Codebase list kodi-pvr-vuplus / 58e1cd0
New upstream version 3.28.9 Balint Reczey 4 years ago
180 changed file(s) with 28130 addition(s) and 4868 deletion(s). Raw diff Collapse all Expand all
2020 .cproject
2121 .project
2222 .settings/
23
24 # VSCode
25 .vscode
22 #
33 # Define the build matrix
44 #
5 # Travis defaults to building on Ubuntu Precise when building on
6 # Linux. We need Trusty in order to get up to date versions of
5 # Travis defaults to building on Ubuntu Trusty when building on
6 # Linux. We need Xenial in order to get up to date versions of
77 # cmake and g++.
88 #
9 env:
10 global:
11 - app_id=pvr.vuplus
12
913 matrix:
1014 include:
1115 - os: linux
12 dist: trusty
16 dist: xenial
1317 sudo: required
1418 compiler: gcc
1519 - os: linux
16 dist: trusty
20 dist: xenial
1721 sudo: required
1822 compiler: clang
1923 - os: osx
20 osx_image: xcode7.3
24 osx_image: xcode9
2125 - os: osx
22 osx_image: xcode6.1
23
24 #
25 # Some of the OS X images don't have cmake, contrary to what people
26 # on the Internet say
27 #
28 before_install:
29 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then which cmake || brew update ; fi
30 - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then which cmake || brew install cmake ; fi
26 osx_image: xcode9.4
3127
3228 #
3329 # The addon source is automatically checked out in $TRAVIS_BUILD_DIR,
3531 #
3632 before_script:
3733 - cd $TRAVIS_BUILD_DIR/..
38 - git clone -b Krypton --depth=1 https://github.com/xbmc/xbmc.git
39 - cd pvr.vuplus && mkdir build && cd build
40 - cmake -DADDONS_TO_BUILD=pvr.vuplus -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/project/cmake/addons
34 - git clone --branch Leia --depth=1 https://github.com/xbmc/xbmc.git
35 - cd ${app_id} && mkdir build && cd build
36 - mkdir -p definition/${app_id}
37 - echo ${app_id} $TRAVIS_BUILD_DIR $TRAVIS_COMMIT > definition/${app_id}/${app_id}.txt
38 - cmake -DADDONS_TO_BUILD=${app_id} -DADDON_SRC_PREFIX=$TRAVIS_BUILD_DIR/.. -DADDONS_DEFINITION_DIR=$TRAVIS_BUILD_DIR/build/definition -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=$TRAVIS_BUILD_DIR/../xbmc/addons -DPACKAGE_ZIP=1 $TRAVIS_BUILD_DIR/../xbmc/cmake/addons
4139
4240 script: make
0 cmake_minimum_required(VERSION 3.5)
01 project(pvr.vuplus)
1
2 cmake_minimum_required(VERSION 2.6)
32
43 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR})
54
6 enable_language(CXX)
7
85 find_package(Kodi REQUIRED)
96 find_package(kodiplatform REQUIRED)
7 find_package(NlohmannJson REQUIRED)
108 find_package(p8-platform REQUIRED)
119 find_package(TinyXML REQUIRED)
1210
1311 include_directories(${kodiplatform_INCLUDE_DIRS}
12 ${NLOHMANNJSON_INCLUDE_DIRS}
1413 ${p8-platform_INCLUDE_DIRS}
1514 ${TINYXML_INCLUDE_DIR}
1615 ${KODI_INCLUDE_DIR})
1716
1817 set(VUPLUS_SOURCES src/client.cpp
19 src/VuData.cpp)
18 src/Enigma2.cpp
19 src/enigma2/Admin.cpp
20 src/enigma2/Channels.cpp
21 src/enigma2/ChannelGroups.cpp
22 src/enigma2/ConnectionManager.cpp
23 src/enigma2/Epg.cpp
24 src/enigma2/RecordingReader.cpp
25 src/enigma2/Recordings.cpp
26 src/enigma2/Settings.cpp
27 src/enigma2/StreamReader.cpp
28 src/enigma2/Timers.cpp
29 src/enigma2/TimeshiftBuffer.cpp
30 src/enigma2/data/AutoTimer.cpp
31 src/enigma2/data/BaseEntry.cpp
32 src/enigma2/data/Channel.cpp
33 src/enigma2/data/ChannelGroup.cpp
34 src/enigma2/data/EpgEntry.cpp
35 src/enigma2/data/RecordingEntry.cpp
36 src/enigma2/data/Timer.cpp
37 src/enigma2/extract/EpgEntryExtractor.cpp
38 src/enigma2/extract/GenreIdMapper.cpp
39 src/enigma2/extract/GenreRytecTextMapper.cpp
40 src/enigma2/extract/ShowInfoExtractor.cpp
41 src/enigma2/utilities/CurlFile.cpp
42 src/enigma2/utilities/FileUtils.cpp
43 src/enigma2/utilities/Logger.cpp
44 src/enigma2/utilities/WebUtils.cpp)
45
46 set(VUPLUS_HEADERS src/client.h
47 src/Enigma2.h
48 src/enigma2/Admin.h
49 src/enigma2/Channels.h
50 src/enigma2/ChannelGroups.h
51 src/enigma2/ConnectionManager.h
52 src/enigma2/Epg.h
53 src/enigma2/IConnectionListener.h
54 src/enigma2/IStreamReader.h
55 src/enigma2/RecordingReader.h
56 src/enigma2/Recordings.h
57 src/enigma2/Settings.h
58 src/enigma2/StreamReader.h
59 src/enigma2/Timers.h
60 src/enigma2/TimeshiftBuffer.h
61 src/enigma2/data/AutoTimer.h
62 src/enigma2/data/BaseChannel.h
63 src/enigma2/data/BaseEntry.h
64 src/enigma2/data/Channel.h
65 src/enigma2/data/ChannelGroup.h
66 src/enigma2/data/EpgEntry.h
67 src/enigma2/data/EpgPartialEntry.h
68 src/enigma2/data/EpgChannel.h
69 src/enigma2/data/RecordingEntry.h
70 src/enigma2/data/Tags.h
71 src/enigma2/data/Timer.h
72 src/enigma2/extract/IExtractor.h
73 src/enigma2/extract/EpgEntryExtractor.h
74 src/enigma2/extract/EpisodeSeasonPattern.h
75 src/enigma2/extract/GenreIdMapper.h
76 src/enigma2/extract/GenreRytecTextMapper.h
77 src/enigma2/extract/ShowInfoExtractor.h
78 src/enigma2/utilities/CurlFile.h
79 src/enigma2/utilities/DeviceInfo.h
80 src/enigma2/utilities/DeviceSettings.h
81 src/enigma2/utilities/LocalizedString.h
82 src/enigma2/utilities/UpdateState.h
83 src/enigma2/utilities/FileUtils.h
84 src/enigma2/utilities/Logger.h
85 src/enigma2/utilities/SignalStatus.h
86 src/enigma2/utilities/StreamStatus.h
87 src/enigma2/utilities/Tuner.h
88 src/enigma2/utilities/WebUtils.h)
2089
2190 set(DEPLIBS ${kodiplatform_LIBRARIES}
2291 ${p8-platform_LIBRARIES}
2392 ${TINYXML_LIBRARIES})
2493
94 addon_version(pvr.vuplus VUPLUS)
95 add_definitions(-DVUPLUS_VERSION=${VUPLUS_VERSION})
96
2597 build_addon(pvr.vuplus VUPLUS DEPLIBS)
2698
2799 include(CPack)
0 # - Find NlohmannJson
1 # Find the native NlohmannJson includes
2 #
3 # NLOHMANNJSON_FOUND - True if NlohmannJson found.
4 # NLOHMANNJSON_INCLUDE_DIRS - where to find nlohmann/json.hpp, etc.
5 #
6
7 find_path(NLOHMANNJSON_INCLUDE_DIR nlohmann/json.hpp)
8
9 include(FindPackageHandleStandardArgs)
10 find_package_handle_standard_args(NlohmannJson DEFAULT_MSG NLOHMANNJSON_INCLUDE_DIR)
11
12 if(NLOHMANNJSON_FOUND)
13 set(NLOHMANNJSON_INCLUDE_DIRS ${NLOHMANNJSON_INCLUDE_DIR})
14 endif()
15
16 mark_as_advanced(NLOHMANNJSON_INCLUDE_DIR)
55 # TINYXML_LIBRARIES - List of libraries when using TinyXML.
66 #
77
8 find_package(PkgConfig)
89 if(PKG_CONFIG_FOUND)
9 pkg_check_modules (TINYXML tinyxml)
10 list(APPEND TINYXML_INCLUDE_DIRS ${TINYXML_INCLUDEDIR})
11 endif()
12 if(NOT TINYXML_FOUND)
13 find_path( TINYXML_INCLUDE_DIRS "tinyxml.h"
14 PATH_SUFFIXES "tinyxml" )
15
16 find_library( TINYXML_LIBRARIES
17 NAMES "tinyxml"
18 PATH_SUFFIXES "tinyxml" )
10 pkg_check_modules(PC_TINYXML tinyxml QUIET)
1911 endif()
2012
21 # handle the QUIETLY and REQUIRED arguments and set TINYXML_FOUND to TRUE if
22 # all listed variables are TRUE
23 include( "FindPackageHandleStandardArgs" )
24 find_package_handle_standard_args(TinyXML DEFAULT_MSG TINYXML_INCLUDE_DIRS TINYXML_LIBRARIES )
13 find_path(TINYXML_INCLUDE_DIRS NAMES tinyxml.h
14 PATHS ${PC_TINYXML_INCLUDEDIR}
15 PATH_SUFFIXES tinyxml)
16 find_library(TINYXML_LIBRARIES NAMES tinyxml
17 PATHS ${PC_TINYXML_LIBDIR}
18 PATH_SUFFIXES tinyxml)
19
20 include("FindPackageHandleStandardArgs")
21 find_package_handle_standard_args(TinyXML REQUIRED_VARS TINYXML_INCLUDE_DIRS TINYXML_LIBRARIES)
2522
2623 mark_as_advanced(TINYXML_INCLUDE_DIRS TINYXML_LIBRARIES)
0 buildPlugin(version: "Leia")
0 [![Build Status](https://travis-ci.org/kodi-pvr/pvr.vuplus.svg?branch=master)](https://travis-ci.org/kodi-pvr/pvr.vuplus)
0 [![Build Status](https://travis-ci.org/kodi-pvr/pvr.vuplus.svg?branch=Leia)](https://travis-ci.org/kodi-pvr/pvr.vuplus/branches)
1 [![Build Status](https://ci.appveyor.com/api/projects/status/github/kodi-pvr/pvr.vuplus?branch=Leia&svg=true)](https://ci.appveyor.com/project/kodi-pvr/pvr-vuplus?branch=Leia)
12 [![Coverity Scan Build Status](https://scan.coverity.com/projects/5120/badge.svg)](https://scan.coverity.com/projects/5120)
23
3 # VuPlus PVR
4 VuPlus PVR client addon for [Kodi] (http://kodi.tv)
4 # Enigma2 PVR
5 Enigma2 PVR client addon for [Kodi](https://kodi.tv)
6
7 ## Overview
8 Enigma2 is a open source TV-receiver/DVR platform which Linux-based firmware (OS images) can be loaded onto many Linux-based set-top boxes (satellite, terrestrial, cable or a combination of these) from different manufacturers.
9
10 This addon leverages the OpenWebIf project to interact with the Enigma2 device via Restful APIs: (https://github.com/E2OpenPlugins/e2openplugin-OpenWebif)
11
12 ### Compatibility
13
14 **Note:** Some images do not use OpenWebIf as the default web interface. In these images some standard functionality may still work but is not guaranteed. Some features that may not function include:
15 * Autotimers
16 * Drive Space Reporting
17 * Embedded EPG Genre IDs
18 * Full Tuner Signal Support (Including Service Providers)
19 * Timer and Recording descriptions: If your provider only uses short description (plot outline) instead of long descrption (plot) then info will not be displayed pertaining to the shows in question. For OpenWebIf clients a JSON API is available to populate the missing data.
20 * Edit recording name, last played position and play count for recordings
21 * Bouquet Backend Channel Numbers
22
23 Some features are only available with at least certain OpenWebIf versions:
24 * 1.3.0
25 * AutoTimers
26 * 1.3.5
27 * Embedded EPG Genres
28 * Tuner Details
29 * Provider Name
30 * Picon URLs
31 * 1.3.6
32 * Editing Recordings
33 * 1.3.7
34 * Backend Channel Numbers
35
36 ### IPTV Streams
37
38 The majority of Enigma2 devices support viewing and recording IPTV streams. They do not however support streaming IPTV from the device. The addon supports IPTV by simply passing the URL used on the device to Kodi PVR. This means that timeshifting cannot be used (and will not be supported in the future). Note that if your IPTV provider restricts the number of active streams each kodi instance viewing it will count as an active stream.
39
40 The option `Enable automatic configuration for live streams` is ignored for channels that are IPTV Streams.
541
642 ## Build instructions
743
844 ### Linux
945
10 1. `git clone https://github.com/xbmc/xbmc.git`
46 1. `git clone --branch Leia https://github.com/xbmc/xbmc.git`
1147 2. `git clone https://github.com/kodi-pvr/pvr.vuplus.git`
1248 3. `cd pvr.vuplus && mkdir build && cd build`
13 4. `cmake -DADDONS_TO_BUILD=pvr.vuplus -DADDON_SRC_PREFIX=../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=../../xbmc/addons -DPACKAGE_ZIP=1 ../../xbmc/project/cmake/addons`
49 4. `cmake -DADDONS_TO_BUILD=pvr.vuplus -DADDON_SRC_PREFIX=../.. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_INSTALL_PREFIX=../../xbmc/build/addons -DPACKAGE_ZIP=1 ../../xbmc/cmake/addons`
1450 5. `make`
1551
16 ##### Useful links
17
18 * [Kodi's PVR user support] (http://forum.kodi.tv/forumdisplay.php?fid=167)
19 * [Kodi's PVR development support] (http://forum.kodi.tv/forumdisplay.php?fid=136)
52 The addon files will be placed in `../../xbmc/build/addons` so if you build Kodi from source and run it directly the addon will be available as a system addon.
53
54 ### Mac OSX
55
56 In order to build the addon on mac the steps are different to Linux and Windows as the cmake command above will not produce an addon that will run in kodi. Instead using make directly as per the supported build steps for kodi on mac we can build the tools and just the addon on it's own. Following this we copy the addon into kodi. Note that we checkout kodi to a separate directory as this repo will only only be used to build the addon and nothing else.
57
58 #### Build tools and initial addon build
59
60 1. Get the repos
61 * `cd $HOME`
62 * `git clone https://github.com/xbmc/xbmc xbmc-addon`
63 * `git clone https://github.com/kodi-pvr/pvr.vuplus`
64 2. Build the kodi tools
65 * `cd $HOME/xbmc-addon/tools/depends`
66 * `./bootstrap`
67 * `./configure --host=x86_64-apple-darwin`
68 * `make -j$(getconf _NPROCESSORS_ONLN)`
69 3. Build the addon
70 * `cd $HOME/xbmc-addon`
71 * `make -j$(getconf _NPROCESSORS_ONLN) -C tools/depends/target/binary-addons ADDONS="pvr.vuplus" ADDON_SRC_PREFIX=$HOME`
72
73 Note that the steps in the following section need to be performed before the addon is installed and you can run it in Kodi.
74
75 #### To rebuild the addon and copy to kodi after changes (after the initial addon build)
76
77 1. `cd $HOME/pvr.vuplus`
78 2. `./build-install-mac.sh ../xbmc-addon`
79
80 If you would prefer to run the rebuild steps manually instead of using the above helper script check the appendix [here](#manual-steps-to-rebuild-the-addon-on-macosx)
81
82 ## Support
83
84 ### Useful links
85
86 * [Kodi's PVR user support forum](https://forum.kodi.tv/forumdisplay.php?fid=167)
87 * [Report an issue on Github](https://github.com/kodi-pvr/pvr.vuplus/issues)
88 * [Kodi's PVR development support forum](https://forum.kodi.tv/forumdisplay.php?fid=136)
89
90 ### Logging
91
92 When reporting issues a debug log should always be supplied. You can use the following guide: [Easy way to submit Kodi debug logs](https://kodi.wiki/view/Log_file/Easy)
93
94 For more detailed info on logging please see the appendix [here](#logging-detailed)
95
96 ## Configuring the addon
97
98 ### Settings Levels
99 In Kodi 18.2 the level of settings shown will correspond to the level set in the main kodi settings UI: `Basic`, `Standard`, `Advanced` and `Expert`. From Kodi 19 it will be possible to change the settingds level from within the addon settings itself.
100
101 ### Connection
102 Within this tab the connection options need to be configured before it can be successfully enabled.
103
104 * **Enigma2 hostname or IP address**: The IP address or hostname of your enigma2 based set-top box.
105 * **Web interface port**: The port used to connect to the web interface.
106 * **Use secure HTTP (https)**: Use https to connect to the web interface.
107 * **Username**: If the webinterface of the set-top box is protected with a username/password combination this needs to be set in this option.
108 * **Password**: If the webinterface of the set-top box is protected with a username/password combination this needs to be set in this option.
109 * **Enable automatic configuration for live streams**: When enabled the stream URL will be read from an M3U8 file. When disabled it is constructed based on the service reference of the channel. This option is rarely required and should not be enbaled unless you have a special use case. If viewing an IPTV Stream this option has no effect on those channels.
110 * **Streaming port**: This option defines the streaming port the set-top box uses to stream live tv. The default is 8001 which should be fine if the user did not define a custom port within the webinterface.
111 * **Use secure HTTP (https) for streams**: Use https to connect to streams.
112 * **Use login for streams**: Use the login username and password for streams.
113 * **Connection check timeout**: The value in seconds to wait for a connection check to complete before failure. Useful for tuning on older Enigma2 devices. Note, this setting should rarely need to be changed. It's more likely the `Connection check interval` setting will have the desired effect. Default is 30 seconds.
114 * **Connection check interval**: The value in seconds to wait between connection checks. Useful for tuning on older Enigma2 devices. Default is 10 seconds.
115
116 ### General
117 Within this tab general options are configured.
118
119 * **Set program id for live channel streams**: Some TV Providers (e.g. Nos - Portugal) using MPTS send extra program stream information. Setting the program id allows kodi to select the correct stream and therefore makes the channel/recording playable. Note that it takes approx 33% longer to open any stream with this option enabled.
120 * **Fetch picons from web interface**: Fetch the picons straight from the Enigma 2 set-top box.
121 * **Use picons.eu file format**: Assume all picons files fetched from the set-top box start with `1_1_1_` and end with `_0_0_0`.
122 * **Use OpenWebIf picon path**: Fetch the picon path from OpenWebIf instead of constructing from ServiceRef. Requires OpenWebIf 1.3.5 or higher. There is no effect if used on a lower version of OpenWebIf.
123 * **Icon path**: In order to have Kodi display channel logos you have to copy the picons from your set-top box onto your OpenELEC machine. You then need to specify this path in this property.
124 * **Update interval**: As the set-top box can also be used to modify timers, delete recordings etc. and the set-top box does not notify the Kodi installation, the addon needs to regularly check for updates (new channels, new/changed/deletes timers, deleted recordings, etc.) This property defines how often the addon checks for updates. Please note that updating the recordings frequently can keep your receiver and it's harddisk from entering standby automatically.
125 * **Update mode**: The mode used when the update interval is reached. Note that if there is any timer change detected a recordings update will always occur regardless of the update mode. Choose from one of the following two modes:
126 - `Timers and Recordings` - Update all timers and recordings.
127 - `Timers only` - Only update the timers. If it's important to not spin up the HDD on your STB use this option. The HDD should then only spin up when a timer event occurs.
128 * **Channel and groups update mode**: The mode used when the hour in the next settings is reached. Choose from one of the following three modes:
129 - `Disabled` - Never check for channel and group changes.
130 - `Notify on UI and Log` - Display a notice in the UI and log the fact that a change was detectetd.
131 - `Reload Channels and Groups` - Disconnect and reconnect with E2 device to reload channels only if a change is detected.
132 * **Channel and group update hour (24h)**: The hour of the day when the check for new channels should occur. Default is 4h as the Auto Bouquet Maker (ABM) on the E2 device defaults to 3AM.
133
134 ### Channels
135 Within this tab options that refer to channel data can be set. When changing bouquets you may need to clear the channel cache to the settings to take effect. You can do this by going to the following in Kodi settings: `Settings->PVR & Live TV->General->Clear cache`.
136
137 Note that channel numbers are set in the addon based on their first occurence when loaded, i.e. if a channel appears in multiple bouqets the channel number will be taken from the first bouquet in which it is loaded, any subsequent channel numbers will be ignored. Therefore if it's desired to keep the same channel numbers across the Enigma2 device and the addon the following guidelines should be adhered to:
138 * If a master bouquet is used it should be the first bouquet loaded assuming it has the channel numbering/order you require.
139 * If not using a master bouquet each channel should only appear in a single bouquet (i.e. do not use channels in multiple bouquets unless they have different service references).
140
141 If Kodi PVR is set to use the channel numbers from the backend the numbers will match those on your STB. If this is not enabled each unique instance of a channel will be given the next free number starting from 1 (i.e. the 17th unique channel will be channel 17). Backend channel numbers will only work for OpenWebIf 1.3.5 and later and they have been tested using ABM (AutoBouquetsMaker).
142
143 * **Zap before channelswitch (i.e. for Single Tuner boxes)**: When using the addon with a single tuner box it may be necessary that the addon needs to be able to zap to another channel on the set-top box. If this option is enabled each channel switch in Kodi will also result in a channel switch on the set-top box. Please note that "allow channel switching" needs to be enabled in the webinterface on the set-top box.
144 * **Use standard channel service reference**: Usually service reference's for the channels are in a standard format like `1:0:1:27F6:806:2:11A0000:0:0:0:`. On occasion depending on provider they can be extended with some text e.g. `1:0:1:27F6:806:2:11A0000:0:0:0::UTV` or `1:0:1:27F6:806:2:11A0000:0:0:0::UTV + 1`. If this option is enabled then all read service reference's will be read as standard. This is default behaviour. Functionality like autotimers will always convert to a standard reference.
145 * **TV bouquet fetch mode**: Choose from one of the following three modes:
146 - `All bouquets` - Fetch all TV bouquets from the set-top box.
147 - `Some bouquets` - Only fetch the bouquet specified in the next option
148 - `Favourites bouquet` - Only fetch the system bouquet for TV favourites.
149 - `Custom bouquets` - Fetch a set of bouquets from the Set-top box whose names are loaded from an XML file.
150 * **Number of TV bouquets**: The number of TV bouquets to load when `Some bouquets` is the selected fetch mode. Up to 5 can be chosen. If more than 5 are required the `Custom bouquets` fetch mode should be used instead.
151 * **TV bouquet 1-5**: If the previous option has been has been set to `Some bouquets` you need to specify a TV bouquet to be fetched from the set-top box. Please not that this is the bouquet-name as shown on the set-top box (i.e. "Favourites (TV)"). This setting is case-sensitive.
152 * **Custom TV Groups file**: The file used to load the custom TV bouquets (groups). If no groups can be matched the channel list will default to 'Last Scanned (TV)'. The default file is `customTVGroups-example.xml`. Details on how to customise can be found in the next section of the README.
153 * **Fetch TV favourites bouquet**: If the fetch mode is `All bouquets` or `Only one bouquet` depending on your Enigma2 image you may need to explicitly fetch favourites if you require them. The options are:
154 - `Disabled` - Don't explicitly fetch TV favourites.
155 - `As first bouquet` - Explicitly fetch them as the first bouquet.
156 - `As last bouquet` - Explicitly fetch them as the last bouquet.
157 * **Exclude last scanned bouquet**: Last scanned is a system bouquet containing all the TV and Radio channels found in the last scan. Any TV channels found in the Last Scanned bouquet can be displayed as a group called ```Last Scanned (TV)``` in Kodi. For TV this group is excluded by default. Disable this option to exclude this group. Note that if no TV groups are loaded the Last Scanned group for TV will be loaded by default regardless of this setting.
158 * **Radio bouquet fetch mode**: Choose from one of the following three modes:
159 - `All bouquets` - Fetch all Radio bouquets from the set-top box.
160 - `Some bouquets` - Only fetch the bouquet specified in the next option
161 - `Favourites bouquet` - Only fetch the system bouquet for Radio favourites.
162 - `Custom bouquets` - Fetch a set of bouquets from the Set-top box whose names are loaded from an XML file.
163 * **Number of radio bouquets**: The number of Radio bouquets to load when `Some bouquets` is the selected fetch mode. Up to 5 can be chosen. If more than 5 are required the `Custom bouquets` fetch mode should be used instead.
164 * **Radio bouquet 1-5**: If the previous option has been has been set to `Some bouquets` you need to specify a Radio bouquet to be fetched from the set-top box. Please not that this is the bouquet-name as shown on the set-top box (i.e. "Favourites (Radio)"). This setting is case-sensitive.
165 * **Custom Radio Groups file**: The file used to load the custom Radio bouquets (groups). If no groups can be matched the channel list will default to 'Last Scanned (Radio)'. The default file is `customRadioGroups-example.xml`. Details on how to customise can be found in the next section of the README.
166 * **Fetch Radio favourites bouquet**: If the fetch mode is `All bouquets` or `Only one bouquet` depending on your Enigma2 image you may need to explicitly fetch favourites if you require them. The options are:
167 - `Disabled` - Don't explicitly fetch Radio favourites.
168 - `As first bouquet` - Explicitly fetch them as the first bouquet.
169 - `As last bouquet` - Explicitly fetch them as the last bouquet.
170 * **Exclude last scanned bouquet**: Last scanned is a system bouquet containing all the TV and Radio channels found in the last scan. Any Radio channels found in the Last Scanned bouquet can be displayed as a group called ```Last Scanned (Radio)``` in Kodi. For Radio this group is excluded by default. Disable this option to show this group.
171
172 ### EPG
173 Within this tab options that refer to EPG data can be set. Excluding logging missing genre text mappings all other options will require clearing the EPG cache to take effect. This can be done by going to `Settings->PVR & Live TV->Guide->Clear cache` in Kodi after the addon restarts.
174
175 Information on customising the extraction and mapper configs can be found in the next section of the README.
176
177 * **Extract season, episode and year info where possible**: Check the description fields in the EPG data and attempt to extract season, episode and year info where possible.
178 * **Extract show info file**: The config used to extract season, episode and year information. The default file is `English-ShowInfo.xml`.
179 * **Enable genre ID mappings**: If the genre IDs sent with EPG data from your set-top box are not using the DVB standard, map from these to the DVB standard IDs. Sky UK for instance uses OpenTV, in that case without this option set the genre colouring and text would be incorrect in Kodi.
180 * **Genre ID mappings file**: The config used to map set-top box EPG genre IDs to DVB standard IDs. The default file is `Sky-UK.xml`.
181 * **Enable Rytec genre text mappings**: If you use Rytec XMLTV EPG data this option can be used to map the text genres to DVB standard IDs.
182 * **Rytec genre text mappings file**: The config used to map Rytec Genre Text to DVB IDs. The default file is `Rytec-UK-Ireland.xml`.
183 * **Log missing genre text mappings**: If you would like missing genre mappings to be logged so you can report them enable this option. Note: any genres found that don't have a mapping will still be extracted and sent to Kodi as strings. Currently genres are extracted by looking for text between square brackets, e.g. [TV Drama], or for major, minor genres using a dot (.) to separate [TV Drama. Soap Opera]
184 * **EPG update delay per channel**: For older Enigma2 devices EPG updates can effect streaming quality (such as buffer timeouts). A delay of between 250ms and 5000ms can be introduced to improve quality. Only recommended for older devices. Choose the lowest value that avoids buffer timeouts.
185 * **Skip intial EPG load**: Ignore the intial EPG load (now and next). Enabled by default to prevent crash issues on LibreElec/CoreElec.
186
187 ### Recordings
188 The following configuration is available on the Recordings tab of the addon settings.
189
190 * **Store last played/play count on the backend**: Store last played position and count on the backend so they can be shared across kodi instances. Only supported on OpenWebIf version 1.3.6+.
191 * **Share last played across**: The options are:
192 - `Kodi instances` - Only use the value in kodi and will not affect last played on the E2 device.
193 - `Kodi/E2 instances` - Use the value across kodi and the E2 device so they stay in sync. Last played will be synced with the E2 device once every 5-10 minutes per recording if the PVR menus are in use. Note that only a single kodi instance is required to have this option enabled.
194 * **Recording folder on receiver**: Per default the addon does not specify the recording folder in newly created timers, so the default set in the set-top box will be used. If you want to specify a different folder (i.e. because you want all recordings scheduled via Kodi to be stored in a separate folder), then you need to set this option.
195 * **Use only the DVB boxes' current recording path**: If this option is not set the addon will fetch all available recordings from all configured paths from the set-top box. If this option is set then it will only list recordings that are stored within the "current recording path" on the set-top box.
196 * **Keep folder structure for records**: If enabled do not specify a recording folder, when disabled (defaut), check if the recording is in it's own folder or in the root of the recording path.
197 * **Enable EDLs support**: EDLs are used to define commericals etc. in recordings. If a tool like [Comskip]() is used to generate EDL files enabling this will allow Kodi PVR to use them. E.g. if there is a file called ```my recording.ts``` the EDL file should be call ```my recording.edl```. Note: enabling this setting has no effect if the files are not present.
198 * **EDL start time padding**: Padding to use at an EDL stop. I.e. use a negative number to start the cut earlier and positive to start the cut later. Default 0.
199 * **EDL stop time padding**: Padding to use at an EDL stop. I.e. use a negative number to stop the cut earlier and positive to stop the cut later. Default 0.
200
201 ### Timers
202
203 **Using Padding for Timers in Kodi PVR**
204
205 Using padding for timers allows you to start a recording some time earlier and finish later in case the actual start and/or run time of a show is incorrect. It's important to note that Enigma2 devices allow you set a padding for all timers, both regular timers and autotimers but it only applies to timers created on the Enigma2 device directly. In the case of autotimers it does not matter if they are created from Kodi or directly on the Enigma2 device as new once off timers are generated on the device so will use this default device padding. It is not possible to set padding for autotimers directly in Kodi PVR at present. You can change these settings on your Enigma2 device as follows:
206 1. Hit `Menu` on the remote and go to `Setup->Recordings, playback & timeshift->Recording & playback`
207 2. Set the following options to your chosen values:
208 * `Margin before recording (minutes)`
209 * `Margin after recording (minutes)`
210
211 If setting padding in Kodi PVR it's only supported on certain timer types, i.e. `Once off time/channel based`, `Repeating time/channel based` and `One time guide-based`. As the Enigma2 device does not support padding per Timer the `tags` field is used to store the padding set in Kodi PVR. If a padding value is not set for these timer types the addon will use the Enigma2 devices default padding value instead. So if you have set a value on the Enigma2 device, this can be overidden in the Kodi UI (note, the default from the Enigma2 device does not display in the Add Timer UI, it won't show until after the timer is created and only if no padding values are set).
212
213 **Timer Types**
214
215 The addon provides the following types of timers and timer rules that the user can create:
216
217 * **Once off time/channel based**: This timer can be created from the add timer UI on the main PVR screen (It cannot be selected from the EPG UI). If running OpenWebIf the timer will be populated with the EPG Entry (if available) at the start time for that channel.
218 * **Repeating time/channel based**: This timer can be created from the add timer UI on the main PVR screen (It cannot be selected from the EPG UI). This type is a timer rule and generates timers. The timers that are generated cannot be edited and will be of the type `Once off timer (set by repeating time/channel based rule)`.
219 * **One time guide-based**: This timer can be created from the EPG UI as well as when playing a channel. It is the timer used when the user selects `Record` when accessing an EPG entry. It will create a timer that starts and ends as per the EPG entry. If playing back a channel it will start from now until the end of the current show. If using OpenWebIf, for providers that only use short description (plot outline) the addon will retrieve the correct description if available and use it in both the timer and resulting recording.
220 * **Auto guide-based**: This is a search based timer rule, using the show name and other factors the Enigma2 device will create timers for EPG entries that satisfy the search. The timers it creates are not editable and will be of the type `Once off timer (set by auto guide-based rule)`.
221
222 In addition there are some timers that can only be created by the addon and are read only:
223
224 * **Once off timer (set by repeating time/channel based rule)**: Timer generated by a `Repeating time/channel based` timer rule. Will contain padding that can't be modified the same as the parent timer rule.
225 * **Once off timer (set by auto guide-based rule)**: Timer created by an `Auto guide-based` timer rule.
226 * **Repeating guide-based**: This type can only be created directly on the Enigma2 device. The type exists to allow users to view the timers in the PVR UI.
227
228 **Timer settings**
229
230 The following are the settings in the Timers tab:
231
232 * **Enable generate repeat timers**: Repeat timers will display as timer rules. Enabling this will make Kodi generate regular timers to match the repeat timer rules so the UI can show what's scheduled and currently recording for each repeat timer.
233 * **Number of repeat timers to generate**: The number of Kodi PVR timers to generate.
234 * **Automatic timerlist cleanup**: If this option is set then the addon will send the command to delete completed timers from the set-top box after each update interval.
235 * **Enable autotimers**: When this is enabled there are some settings required on the set-top box to enable linking of AutoTimers (Timer Rules) to Timers in the Kodi UI. The addon attempts to set these automatically on boot. To set manually on the set-top box enable the following options (note that this feature supports OpenWebIf 1.3.x and higher):
236 1. Hit `Menu` on the remote and go to `Timers->AutoTimers`
237 2. Hit `Menu` again and then select `6 Setup`
238 3. Set the following to option to `yes`
239 * `Include "AutoTimer" in tags`
240 * `Include AutoTimer name in tags`
241 * **Limit 'Any Channel' autotimers to TV or Radio**: If last scanned groups are excluded attempt to limit new autotimers to either TV or Radio (dependent on channel used to create the autotimer). Note that if last scanned groups are enabled this is not possible and the setting will be ignored.
242 * **Limit to groups of original EPG channel**: For the channel used to create the autotimer limit to channel groups that this channel is a member of.
243
244 ### Timeshift
245 Timeshifting allows you to pause live TV as well as move back and forward from your current position similar to playing back a recording. The buffer is deleted each time a channel is changed or stopped.
246
247 * **Enable timeshift**: What timeshift option do you want:
248 - `Disabled` - No timeshifting
249 - `On Pause` - Timeshifting starts when a live stream is paused. E.g. you want to continue from where you were at after pausing.
250 - `On Playback` - Timeshifting starts when a live stream is opened. E.g. You can go to any point in the stream since it was opened.
251 * **Timeshift buffer path**: The path used to store the timeshift buffer. The default is the `addon_data/pvr.vuplus` folder in userdata.
252
253 ### Advanced
254 Within this tab more uncommon and advanced options can be configured.
255
256 * **Put outline (e.g. sub-title) before plot**: By default plot outline (short description on Enigma2) is not displayed in the UI. Can be displayed in EPG, Recordings or both. After changing this option you will need to clear the EPG cache `Settings->PVR & Live TV->Guide->Clear cache` for it to take effect.
257 * **Send powerstate mode on addon exit**: If this option is set to a value other than `DISABLED` then the addon will send a Powerstate command to the set-top box when Kodi will be closed (or the addon will be deactivated).
258 - `Disabled` - No command sent when the addon exits
259 - `Standby` - Send the standby command on exit
260 - `Deep standby` - Send the deep standby command on exit. Note, the set-top box will not respond to Kodi after this command is sent.
261 - `Wakeup, then standby` - Similar to standby but first sends a wakeup command. Can be useful if you want to ensure all streams have stopped. Note: if you use CEC this could cause your TV to wake.
262 * **Custom live TV timeout (0 to use default)**: The timemout to use when trying to read live streams. Default for live streams is 0. Default for timeshifting is 10 seconds.
263 * **Stream read chunk size**: The chunk size used by Kodi for streams. Default 0 to leave it to Kodi to decide.
264 * **Ignore debug logging in debug mode**: Debug log statements will not be displayed for the addon even though debug logging is enabled in Kodi. This can be useful when trying to debug an issue in Kodi which is not addon related.
265 * **Enable debug logging in normal mode**: Debug log statements will display for the addon even though debug logging may not be enabled in Kodi. Note that all debug log statements will display at NOTICE level.
266 * **Enable trace logging in debug mode**: Very detailed and verbose log statements will display in addition to standard debug statements. If enabled along with `Enable debug logging in normal mode` both trace and debug will display without debug logging enabled. In this case both debug and trace log statements will display at NOTICE level.
267
268 ## Customising Config Files
269
270 The various config files have examples allowing users to create their own, making it possible to support custom config, other languages and formats. Each different type of config file is detailed below. Best way to learn about them is to read the config files themselves. Each contains details of how the config file works.
271
272 All of the files listed below are overwritten each time the addon starts. Therefore if you are customising files please create new copies with different file names. Note: that only the files below are overwritten any new files you create will not be touched.
273
274 After adding and selecting new config files you will need to clear the EPG cache `Settings->PVR & Live TV->Guide->Clear cache` for it to take effect in the case of EPG relatd config and for channel related config will need to clear the full cache `Settings->PVR & Live TV->General->Clear cache`.
275
276 If you would like to support other formats/languages please raise an issue at the github project https://github.com/kodi-pvr/pvr.vuplus, where you can either create a PR or request your new configs be shipped with the addon.
277
278 There is one config file located here: `userdata/addon_data/pvr.vuplus/genres/kodiDvbGenres.xml`. This simply contains the DVB genre IDs that Kodi supports. Can be a useful reference if creating your own configs. This file is also overwritten each time the addon restarts.
279
280 ### Custom Channel Groups (Channels)
281
282 Config files are located in the `userdata/addon_data/pvr.vuplus/channelGroups` folder.
283
284 The following files are currently available with the addon:
285 - `customTVGroups-example.xml`
286 - `customRadioGroups-example.xml`
287
288 Note that both these files are provided as examples and are overwritten each time the addon starts. Therefore you should make copies and use those for your custom config.
289
290 The format is quite simple, containing a number of channel group/bouquet names.
291
292 ### Season, Episode and Year Show Info (EPG_)
293
294 Config files are located in the `userdata/addon_data/pvr.vuplus/showInfo` folder.
295
296 The following files are currently available with the addon:
297 - `English-ShowInfo.xml`
298
299 Note: the config file can contain as many pattern matches as are required. So if you need to support multiple languages in a single file that is possible. However there must be at least one <seasonEpisode> pattern and at least one <year> pattern. Proficiency in regular exressions is required!
300
301 ### Genre ID Mappings (EPG)
302
303 Config files are located in the `userdata/addon_data/pvr.vuplus/genres/genreIdMappings` folder.
304
305 The following files are currently available with the addon:
306 - `AU-SAT.xml`
307 - `Sky-IT.xml`
308 - `Sky-NZ.xml`
309 - `Sky-UK.xml`
310
311 Note: that each source genre ID can be mapped to a DVB ID. However multiple source IDs can be mapped to the same DVB ID. Therefore there are exactly 256 <mapping> elements in each file as a genre ID is 8 bits. All values are in Hex. The first fours bits are the genreType in Kodi PVR and the last four bits are the genreSubType.
312
313 ### Rytec Genre Text Mappings (EPG)
314
315 Config files are located in the `userdata/addon_data/pvr.vuplus/genres/genreRytecTextMappings` folder.
316
317 The following files are currently available with the addon:
318 - `Rytec-UK-Ireland.xml`
319
320 Note: the config file can contain as many mappings as is required. Currently genres are extracted by looking for text between square brackets, e.g. [TV Drama], or for major, minor genres using a dot (.) to separate [TV Drama. Soap Opera]. The config file maps the text to a kodi DVB genre ID. If the full text cannot be matched it attempts to match just the major genre, i.e. "TV Drama" in the previous example. If a mapping cannot be found the text between the brackets will be used instead. However there will be no colouring in the Kodi EPG in this case.
321
322 ## Appendix
323
324 ### Manual Steps to rebuild the addon on MacOSX
325
326 The following steps can be followed manually instead of using the `build-install-mac.sh` in the root of the addon repo after the [initial addon build](#build-tools-and-initial-addon-build) has been completed.
327
328 **To rebuild the addon after changes**
329
330 1. `rm tools/depends/target/binary-addons/.installed-macosx*`
331 2. `make -j$(getconf _NPROCESSORS_ONLN) -C tools/depends/target/binary-addons ADDONS="pvr.vuplus" ADDON_SRC_PREFIX=$HOME`
332
333 or
334
335 1. `cd tools/depends/target/binary-addons/macosx*`
336 2. `make`
337
338 **Copy the addon to the Kodi addon directory on Mac**
339
340 1. `rm -rf "$HOME/Library/Application Support/Kodi/addons/pvr.vuplus"`
341 2. `cp -rf $HOME/xbmc-addon/addons/pvr.vuplus "$HOME/Library/Application Support/Kodi/addons"`
342
343 ### Logging detailed
344
345 Some of the most useful information in your log are the details output at the start of the log, both for Kodi and the addon.
346
347 The first 5 lines of the log give details on the exact kodi flavour and version you are running:
348
349 ```
350 01:10:45.744 T:140736264741760 NOTICE: -----------------------------------------------------------------------
351 01:10:45.744 T:140736264741760 NOTICE: Starting Kodi (18.0-BETA2 Git:20180903-5d7e1dbd9c-dirty). Platform: OS X x86 64-bit
352 01:10:45.744 T:140736264741760 NOTICE: Using Debug Kodi x64 build
353 01:10:45.744 T:140736264741760 NOTICE: Kodi compiled Sep 5 2018 by Clang 9.1.0 (clang-902.0.39.2) for OS X x86 64-bit version 10.9.0 (1090)
354 01:10:45.745 T:140736264741760 NOTICE: Running on Apple Inc. MacBook10,1 with OS X 10.13.6, kernel: Darwin x86 64-bit version 17.7.0
355 ```
356
357 Secondly all the information of the Enigma2 image, web interface version etc. is also output:
358
359 ```
360 12:36:55.888 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - Open - VU+ Addon Configuration options
361 12:36:55.888 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - Open - Hostname: '192.168.1.201'
362 12:36:55.888 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - Open - WebPort: '80'
363 12:36:55.888 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - Open - StreamPort: '8001'
364 12:36:55.888 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - Open Use HTTPS: 'false'
365 12:36:56.308 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - LoadDeviceInfo - DeviceInfo
366 12:36:56.308 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - LoadDeviceInfo - E2EnigmaVersion: 2019-01-03
367 12:36:56.308 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - LoadDeviceInfo - E2ImageVersion: 5.2.022
368 12:36:56.309 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - LoadDeviceInfo - E2DistroVersion: openvix
369 12:36:56.309 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - LoadDeviceInfo - E2WebIfVersion: OWIF 1.3.5
370 12:36:56.309 T:123145422725120 NOTICE: AddOnLog: Enigma2 Client: pvr.vuplus - LoadDeviceInfo - E2DeviceName: Ultimo4K
371 ```
372
373 #### Description of Log levels
374
375 * **Error**: Something that will require intervention to resolve
376 * **Notice**: Could be an important piece of information or a warning that something has occurred that might be undesirable but has not affected normal operation
377 * **Info**: Some information on normal operation
378 * **Debug**: More detailed information that can aid in diagnosing issues.
379 * **Trace**: Extremely verbose logging, should rarely be required. Note: can only be enabled from the addon settings in the ```Advanced``` section.
380
381 #### Cleaning up the log
382
383 (If you have a fresh install of version 3.15.0 or later you can ignore this)
384
385 As the addon was upgraded over time some old settings are no longer required. These old settings can create a lot of extra logging on startup. To date there are four of these and they will present like this in your log:
386
387 ```
388 23:17:22.696 T:3990016880 DEBUG: CSettingsManager: requested setting (extracteventinfo) was not found.
389 23:17:22.696 T:3990016880 DEBUG: CAddonSettings[pvr.vuplus]: failed to find definition for setting extracteventinfo. Creating a setting on-the-fly...
390 23:17:22.696 T:3990016880 DEBUG: CSettingsManager: requested setting (onegroup) was not found.
391 23:17:22.696 T:3990016880 DEBUG: CAddonSettings[pvr.vuplus]: failed to find definition for setting onegroup. Creating a setting on-the-fly...
392 23:17:22.696 T:3990016880 DEBUG: CSettingsManager: requested setting (onlyonegroup) was not found.
393 23:17:22.696 T:3990016880 DEBUG: CAddonSettings[pvr.vuplus]: failed to find definition for setting onlyonegroup. Creating a setting on-the-fly...
394 23:17:22.697 T:3990016880 DEBUG: CSettingsManager: requested setting (setpowerstate) was not found.
395 23:17:22.697 T:3990016880 DEBUG: CAddonSettings[pvr.vuplus]: failed to find definition for setting setpowerstate. Creating a setting on-the-fly...
396 ```
397
398 If you see these in debug mode and would like to clean them up you can either:
399
400 1. Remove the offending lines from you settings.xml file OR
401 2. Delete you settings.xml and restart kodi. Note that if you use this option you will need to reconfigure the addon from scratch.
402
403 Your settings.xml file can be found here: ```userdata/addon_data/pvr.vuplus/settings.xml```
0 version: BuildNr.{build}
1
2 image: Visual Studio 2015
3
4 shallow_clone: true
5
6 clone_folder: c:\projects\pvr.vuplus
7
8 environment:
9 app_id: pvr.vuplus
10
11 matrix:
12 - GENERATOR: "Visual Studio 14"
13 CONFIG: Release
14 - GENERATOR: "Visual Studio 14 Win64"
15 CONFIG: Release
16 - GENERATOR: "Visual Studio 14 Win64"
17 CONFIG: Release
18 WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.16299.0"
19 - GENERATOR: "Visual Studio 14 ARM"
20 CONFIG: Release
21 WINSTORE: -DCMAKE_SYSTEM_NAME=WindowsStore -DCMAKE_SYSTEM_VERSION="10.0.16299.0"
22
23 build_script:
24 - cd ..
25 - git clone --branch Leia --depth=1 https://github.com/xbmc/xbmc.git
26 - cd %app_id%
27 - mkdir build
28 - cd build
29 - mkdir -p definition\%app_id%
30 - echo %app_id% %APPVEYOR_BUILD_FOLDER% %APPVEYOR_REPO_COMMIT% > definition\%app_id%\%app_id%.txt
31 - cmake -T host=x64 -G "%GENERATOR%" %WINSTORE% -DADDONS_TO_BUILD=%app_id% -DCMAKE_BUILD_TYPE=%CONFIG% -DADDONS_DEFINITION_DIR=%APPVEYOR_BUILD_FOLDER%/build/definition -DADDON_SRC_PREFIX=../.. -DCMAKE_INSTALL_PREFIX=../../xbmc/addons -DPACKAGE_ZIP=1 ../../xbmc/cmake/addons
32 - cmake --build . --config %CONFIG% --target %app_id%
0 #!/bin/bash
1
2 set -e
3
4 if [ "$#" -ne 1 ] || ! [ -d "$1" ]; then
5 echo "Usage: $0 <XBMC-SRC-DIR>" >&2
6 exit 1
7 fi
8
9 if [[ "$OSTYPE" != "darwin"* ]]; then
10 echo "Error: Script only for use on MacOSX" >&2
11 exit 1
12 fi
13
14 SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
15 if [[ "$1" = /* ]]
16 then
17 #absolute path
18 SCRIPT_DIR=""
19 else
20 #relative
21 SCRIPT_DIR="$SCRIPT_DIR/"
22 fi
23
24 BINARY_ADDONS_TARGET_DIR="$1/tools/depends/target/binary-addons"
25 MACOSX_BINARY_ADDONS_TARGET_DIR=""
26 KODI_ADDONS_DIR="$HOME/Library/Application Support/Kodi/addons"
27 ADDON_NAME=`basename -s .git \`git config --get remote.origin.url\``
28
29 if [ ! -d "$BINARY_ADDONS_TARGET_DIR" ]; then
30 echo "Error: Could not find binary addons directory at: $BINARY_ADDONS_TARGET_DIR" >&2
31 exit 1
32 fi
33
34 for DIR in "$BINARY_ADDONS_TARGET_DIR/"macosx*; do
35 if [ -d "${DIR}" ]; then
36 MACOSX_BINARY_ADDONS_TARGET_DIR="${DIR}"
37 break
38 fi
39 done
40
41 if [ -z "$MACOSX_BINARY_ADDONS_TARGET_DIR" ]; then
42 echo "Error: Could not find binary addons build directory at: $BINARY_ADDONS_TARGET_DIR/macosx*" >&2
43 exit 1
44 fi
45
46 if [ ! -d "$KODI_ADDONS_DIR" ]; then
47 echo "Error: Kodi addons dir does not exist at: $KODI_ADDONS_DIR" >&2
48 exit 1
49 fi
50
51 cd "$MACOSX_BINARY_ADDONS_TARGET_DIR"
52 make
53
54 XBMC_BUILD_ADDON_INSTALL_DIR=$(cd "$SCRIPT_DIR$1/addons/$ADDON_NAME" 2> /dev/null && pwd -P)
55 rm -rf "$KODI_ADDONS_DIR/$ADDON_NAME"
56 echo "Removed previous addon build from: $KODI_ADDONS_DIR"
57 cp -rf "$XBMC_BUILD_ADDON_INSTALL_DIR" "$KODI_ADDONS_DIR"
58 echo "Copied new addon build to: $KODI_ADDONS_DIR"
0 kodi-pvr-vuplus (#PACKAGEVERSION#-#TAGREV#~#DIST#) #DIST#; urgency=low
1
2 [ kodi ]
3 * autogenerated dummy changelog
4
5 -- Cristiano A. Silva <hudokkow@gmail.com> Mon, 23 Feb 2015 15:56:31 +0000
6
0 Source: kodi-pvr-vuplus
1 Priority: extra
2 Maintainer: Cristiano A. Silva <hudokkow@gmail.com>
3 Build-Depends: debhelper (>= 9.0.0), cmake, libtinyxml-dev,
4 libkodiplatform-dev (>= 16.0.0), kodi-addon-dev,
5 nlohmann-json-dev (>= 3.1) | nlohmann-json3-dev (>= 3.1)
6 Standards-Version: 3.9.4
7 Section: libs
8
9 Package: kodi-pvr-vuplus
10 Section: libs
11 Architecture: any
12 Depends: ${shlibs:Depends}, ${misc:Depends}
13 Description: Vu+ PVR for Kodi
14 Vu+ PVR for Kodi
15
16 Package: kodi-pvr-vuplus-dbg
17 Section: debug
18 Architecture: any
19 Depends: ${shlibs:Depends}, ${misc:Depends}
20 Description: debug symbols for Vu+ PVR for Kodi
21 debug symbols for Vu+ PVR for Kodi
0 Format: http://dep.debian.net/deps/dep5
1 Upstream-Name: pvr.vuplus
2
3 Files: *
4 Copyright: 2005-2015 Team XBMC
5 License: GPL-2+
6 This package is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10 .
11 This package is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15 .
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>
18 .
19 On Debian systems, the complete text of the GNU General
20 Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
21
22
23 Files: debian/*
24 Copyright: 2013-2015 Cristiano A. Silva <hudokkow@gmail.com>
25 2013 wsnipex <wsnipex@a1.net>
26 License: GPL-2+
27 This package is free software; you can redistribute it and/or modify
28 it under the terms of the GNU General Public License as published by
29 the Free Software Foundation; either version 2 of the License, or
30 (at your option) any later version.
31 .
32 This package is distributed in the hope that it will be useful,
33 but WITHOUT ANY WARRANTY; without even the implied warranty of
34 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35 GNU General Public License for more details.
36 .
37 You should have received a copy of the GNU General Public License
38 along with this program. If not, see <http://www.gnu.org/licenses/>
39 .
40 On Debian systems, the complete text of the GNU General
41 Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
42
0 usr/lib/*
1 usr/share/*
0 #!/usr/bin/make -f
1 # -*- makefile -*-
2 # Sample debian/rules that uses debhelper.
3 # This file was originally written by Joey Hess and Craig Small.
4 # As a special exception, when this file is copied by dh-make into a
5 # dh-make output file, you may use that output file without restriction.
6 # This special exception was added by Craig Small in version 0.37 of dh-make.
7
8 # Uncomment this to turn on verbose mode.
9 #export DH_VERBOSE=1
10
11 %:
12 dh $@
13
14 override_dh_auto_configure:
15 dh_auto_configure -- -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=1 -DUSE_LTO=1
16
17 override_dh_strip:
18 dh_strip -pkodi-pvr-vuplus --dbg-package=kodi-pvr-vuplus-dbg
19
20 override_dh_installdocs:
21 dh_installdocs --link-doc=kodi-pvr-vuplus
22
0 3.0 (native)
1 ß
0 -DBUILD_TESTING:BOOL=OFF
0 80c45b090e40bf3d7a7f2a6e9f36206d3ff710acfa8d8cc1f8c763bb3075e22e
0 nlohmann-json https://github.com/nlohmann/json/archive/v3.6.1.tar.gz
00 <?xml version="1.0" encoding="UTF-8"?>
11 <addon
22 id="pvr.vuplus"
3 version="2.4.12"
4 name="VU+ / Enigma2 Client"
5 provider-name="Joerg Dembski">
6 <requires>
7 <c-pluff version="0.1"/>
8 <import addon="xbmc.pvr" version="5.2.1"/>
9 </requires>
3 version="3.28.9"
4 name="Enigma2 Client"
5 provider-name="Joerg Dembski and Ross Nicholson">
6 <requires>@ADDON_DEPENDS@</requires>
107 <extension
118 point="xbmc.pvrclient"
129 library_@PLATFORM@="@LIBRARY_FILENAME@"/>
1310 <extension point="xbmc.addon.metadata">
1411 <summary lang="af_ZA">Kodi se voorprogram vir VU+ / Enigma2 gebasseerde 'set-top' bokse</summary>
1512 <summary lang="be_BY">Kodi's frontend for VU+ / Enigma2 based settop boxes</summary>
16 <summary lang="bg_BG">Kodi клиент за тунери базирани на VU+ / Enigma2</summary>
13 <summary lang="bg_BG">Клиент за устройства, базирани на VU+ / Enigma2</summary>
1714 <summary lang="ca_ES">Frontal de Kodi per als descodificadors basats en VU+/Enigma2</summary>
18 <summary lang="cs_CZ">Rozhraní Kodi pro přijímače založené na VU+ nebo Enigma2</summary>
15 <summary lang="cs_CZ">Rozhraní Kodi pro přijímače založené na Enigma2</summary>
1916 <summary lang="cy_GB">Blaen Kodi ar gyfer blychau teledu VU+ / Enigma2</summary>
2017 <summary lang="da_DK">Kodi's frontend til VU+ / Enigma2 baseret på settop bokse</summary>
2118 <summary lang="de_DE">Kodi Oberfläche für VU+ / Enigma2-basierte Settop-Boxen</summary>
2219 <summary lang="el_GR">Frontend του Kodi για αποκωδικοποιητές (settop box) τύπου VU+ / Enigma2</summary>
2320 <summary lang="en_AU">Kodi's frontend for VU+ / Enigma2 based settop boxes</summary>
24 <summary lang="en_GB">Kodi's frontend for VU+ / Enigma2 based settop boxes</summary>
21 <summary lang="en_GB">Kodi's frontend for Enigma2 based set-top boxes</summary>
2522 <summary lang="en_NZ">Kodi's frontend for VU+ / Enigma2 based settop boxes</summary>
2623 <summary lang="en_US">Kodi's frontend for VU+ / Enigma2 based settop boxes</summary>
2724 <summary lang="es_AR">Kodi frontend para decodificadores equipados con VU+/Enigma2</summary>
2926 <summary lang="es_MX">Kodi frontend para cajas fijas basadas en VU + / Enigma2</summary>
3027 <summary lang="et_EE">Kodi liides VU+ / Enigma2 põhistele digiboksidele</summary>
3128 <summary lang="fi_FI">Kodin VU+/ Enigma2-asiakasohjelma</summary>
32 <summary lang="fr_CA">Frontal Kodi pour les boîtiers décodeurs basés sur VU+ / Enigma 2</summary>
29 <summary lang="fr_CA">Frontale Kodi pour les boîtiers décodeurs fondés sur Enigma2</summary>
3330 <summary lang="fr_FR">Interface logicielle pour les enregistreurs VU+/Enigma2</summary>
3431 <summary lang="gl_ES">Interface de Kodi para decodificadores equipados con VU+/Enigma2</summary>
3532 <summary lang="he_IL">לקוח טלוויזיה חיה עבור מכשירי VU+ או מבוססי Enigma2</summary>
5653 <summary lang="sq_AL">Frontend i Kodi'së për Aparate VU+ / Enigma2 </summary>
5754 <summary lang="sr_RS">Kodi-јев интерфејс за VU+ / Enigma2 засноване settop кутије</summary>
5855 <summary lang="sr_RS@latin">Kodijev interfejs za VU+ / Enigma2 zasnovane settop kutije</summary>
59 <summary lang="sv_SE">Kodi Frontend för VU+/Enigma2 baserade dekodrar</summary>
56 <summary lang="sv_SE">Kodi Frontend för Enigma2 baserade digitalboxar</summary>
6057 <summary lang="szl">Klijynt telewizyjny dlŏ dekoderōw VU+ / Enigma2 </summary>
6158 <summary lang="tr_TR">VU+ / Enigma2 alıcı kutuları için Kodi ön ucu</summary>
6259 <summary lang="uk_UA">Накладка VU+ / Enigma2 для Kodi</summary>
6360 <summary lang="vi_VN">Giao tiếp Kodi cho VU+ / Enigma2 dựa trên các bộ Settop Box</summary>
64 <summary lang="zh_CN">基于 VU+/Enigma2 的机顶盒的 Kodi 前端</summary>
61 <summary lang="zh_CN">基于 Enigma2 的机顶盒的 Kodi 前端</summary>
6562 <summary lang="zh_TW">給以VU+ / Enigma2開發的機上盒所使用的Kodi前端</summary>
6663 <description lang="af_ZA">VU+ voorprogram; ondersteun stroom van Lewendige TV &amp; Opnames, EPG, Tydhouers.</description>
6764 <description lang="be_BY">VU+ frontend; supporting streaming of Live TV &amp; Recordings, EPG, Timers.</description>
68 <description lang="bg_BG">VU+ клиент. Поддържа поточна телевизия и записване, електронен програмен справочник и броячи.</description>
65 <description lang="bg_BG">Клиент за „VU+“. Поддържа телевизия на живо и записване, електронен програмен справочник и броячи.</description>
6966 <description lang="ca_ES">Frontal de VU+; és compatible amb les transmissions en línia de TV en directe i enregistraments, guia electrònica de programació (EPG) i temporitzadors.</description>
70 <description lang="cs_CZ">Rozhraní VU+; podporuje streamování živého vysílání a nahrávání, televizní program, časovače.</description>
67 <description lang="cs_CZ">Rozhraní Enigma2 – podporuje streamování živého vysílání a nahrávání, televizní program, časovače, automatické časovače.&#10;&#10;Pro dokumentaci navštivte: https://github.com/kodi-pvr/pvr.vuplus/blob/master/README.md</description>
7168 <description lang="cy_GB">Blaen VU+; cynnal ffrydio Teledu Byw, Recordio, Amserlenni, Amseryddion</description>
7269 <description lang="da_DK">VU+ frontend; understøtter streaming af TV og Optagelser, EPG og Timere.</description>
7370 <description lang="de_DE">VU+ -Oberfläche; Unterstützt Live TV &amp; Aufnahmen, EPG und Timer.</description>
7471 <description lang="el_GR">Frontend για το VU+. Υποστηρίζει ροές Live TV &amp; Εγγραφές, EPG, Χρονοδιακόπτες.</description>
7572 <description lang="en_AU">VU+ frontend; supporting streaming of Live TV &amp; Recordings, EPG, Timers.</description>
76 <description lang="en_GB">VU+ frontend; supporting streaming of Live TV &amp; Recordings, EPG, Timers.</description>
73 <description lang="en_GB">Enigma2 frontend - supporting streaming of Live TV &amp; Recordings, EPG, Timers, Autotimers.&#10; &#10;For documentation visit: https://github.com/kodi-pvr/pvr.vuplus/blob/Leia/README.md&#10; </description>
7774 <description lang="en_NZ">VU+ frontend; supporting streaming of Live TV &amp; Recordings, EPG, Timers.</description>
7875 <description lang="en_US">VU+ frontend; supporting streaming of Live TV &amp; Recordings, EPG, Timers.</description>
7976 <description lang="es_AR">VU+ frontend; soporta TV en vivo, grabaciones, guía de programación (GEP) y temporizadores.</description>
8178 <description lang="es_MX">VU+ frontend; Soportando transmisión de TV en directo y grabaciones, EPG, Temporizadores.</description>
8279 <description lang="et_EE">VU+ liides. Toetab telekanalite striimimist ja salvestamist ning elektroonilist saatekava.</description>
8380 <description lang="fi_FI">VU+-asiakasohjelma. Tukee suorien tv-lähetysten ja tallennusten katsomista, ohjelmaopasta ja ohjelmien ajastamista.</description>
84 <description lang="fr_CA">Frontal VU+, prenant en charge la diffusion en continu des télés en direct &amp; les enregistrements, le GÉP et les minuteries.</description>
81 <description lang="fr_CA">Frontale Enigma2 qui prend en charge la diffusion en continu des télés en direct et des enregistrements, le GÉP et les minuteries&#10;&#10; &#10;Pour consulter la documentation, visitez https://github.com/kodi-pvr/pvr.vuplus/blob/master/README.md (page en anglais)</description>
8582 <description lang="fr_FR">Interface logicielle pour enregistreur VU+. Gère la diffusion et les enregistrements de la TV en direct, le guide électronique des programmes TV et les programmations.</description>
8683 <description lang="gl_ES">Interface VU+; soporta TV en directo, gravacións, Guía de programación e temporizadores.</description>
8784 <description lang="he_IL">לקוח טלוויזיה חיה של VU+. תומך בהזרמת שידורים חיים והקלטות, הצגת לוח שידורים ותזמון הקלטות.</description>
9794 <description lang="mk_MK">VU+ интерфејс;подржува стриминг на Live TV &amp; Recordings, EPG, Timers.</description>
9895 <description lang="ms_MY">Bahagian hadapan VU+; menyokong penstirman Langsung &amp; Rakaman, EPG, Pemasa TV</description>
9996 <description lang="nb_NO">VU+grenseflate; støtter strømming av direkte-TV og opptak, EPG, tidsur.</description>
100 <description lang="nl_NL">VU+ frontend; ondersteunt het streamen van LiveTV &amp; Opnames, EPG, Timers</description>
97 <description lang="nl_NL">VU+ frontend; ondersteunt het streamen van Live-TV &amp; opnames, EPG, timers</description>
10198 <description lang="pl_PL">Klient telewizji dla VU+ obsługuje transmisję kanałów radiowych i telewizyjnych, nagrywanie i harmonogram nagrań oraz funkcje przewodnika telewizyjnego.</description>
10299 <description lang="pt_BR">VU+ frontend; suporta streaming de TV Ao Vivo e Gravações, EPG, agendamentos.</description>
103100 <description lang="pt_PT">Interface VU+ ; suporta transmissão e gravação de TV em direto, EPG e temporizadores.</description>
108105 <description lang="sq_AL">VU+ frontend, përkrahën transmetimin e Live TV's &amp; Regjistrime, EPG, timer.</description>
109106 <description lang="sr_RS">VU+ интерфејс; подржава стримовање ТВ Уживо &amp; Снимака, EPG, Тајмере</description>
110107 <description lang="sr_RS@latin">VU+ interfejs; podržava strimovanje TV Uživo &amp; Snimaka, EPG, Tajmere</description>
111 <description lang="sv_SE">VU+ frontend; stödjer strömning av direktsänd TV &amp; inspelningar, EPG, timers.</description>
108 <description lang="sv_SE">Enigma2 frontend; stödjer strömning av Live-TV &amp; inspelningar, EPG, timers, autotimers.&#10; &#10;För dokumentationen besök https://github.com/kodi-pvr/pvr.vuplus/blob/master/README.md&#10; </description>
112109 <description lang="szl">Klijynt telewizyjny dlŏ VU+ podpiyrŏ szpricowanie kanałōw radyjowych i telewizyjnych, nagrowanie i harmōnogram nagrań aji funkcyje EPG.</description>
113110 <description lang="tr_TR">VU+ ön ucu; Canlı TV akışı ve kayıt yapabilme, EPG ve zamanlayıcıları destekler.</description>
114111 <description lang="uk_UA">Накладка VU+; підтримує потоки Live TV, запис, програму передач, таймери.</description>
115112 <description lang="vi_VN">Giao tiếp cho VU+; hỗ trợ truyền phát và thu chương trình Live TV, hẹn giờ và hiển thị lịch trình chiếu (EPG)</description>
116 <description lang="zh_CN">VU+ 前端,支持直播电视播放和录像、电子节目单、定时器。</description>
113 <description lang="zh_CN">Enigma2 前端 - 支持直播电视播放和录像、电子节目单、定时器、自动定时器。&#10;&#10;文档见:https://github.com/kodi-pvr/pvr.vuplus/blob/master/README.md</description>
117114 <description lang="zh_TW">VU+前端;支援的串流媒體包括有:電視直播和節目錄影,電子節目表,定時器。</description>
118115 <disclaimer lang="af_ZA">Hierdie is onstabiele sagteware! Die outeurs is op geen manier verantwoordelik vir gefaalde opnames, inkorrekte tydhouers, gemorsde ure, of enige ander ongewensde effekte.</disclaimer>
119116 <disclaimer lang="be_BY">This is unstable software! The authors are in no way responsible for failed recordings, incorrect timers, wasted hours, or any other undesirable effects..</disclaimer>
132129 <disclaimer lang="es_ES">¡Este es un software inestable! Los autores no son de ninguna manera responsables de las grabaciones fallidas o incorrectas, las temporizadores perdidas, ni otros efectos no deseables..</disclaimer>
133130 <disclaimer lang="es_MX">¡Esto es software inestable! Los autores no son de ninguna manera responsables por grabaciones fallidas, temporizadores incorrectos, horas perdidas o cualquier otro efecto no deseado...</disclaimer>
134131 <disclaimer lang="et_EE">See on ebastabiilne tarkvara! Autorid ei ole kuidagi moodi vastutavad nurjunud salvestiste, ebaõige aegrelee, raisatud tundide ega muude soovimatute asjade eest.</disclaimer>
135 <disclaimer lang="eu_ES">Software hau beta bertsioan dago! Egilea ez da arduratzen grabaketa erroretaz, kronometro erroreak, hordu galduak edo beste edozein ondorio ezerosotaz</disclaimer>
132 <disclaimer lang="eu_ES">Software hau ezegonkorra da! Egilea ez da arduratzen grabazio-erroreetaz, kronometro-erroreetaz, ordu galduetaz edo beste edozein ondorio ezerosoetaz.</disclaimer>
136133 <disclaimer lang="fi_FI">Tämä on epävakaa ohjelma! Sen tekijät eivät ole millään muotoa vastuussa epäonnistuneista tallennuksista, virheellisistä ajastuksista, haaskatusta ajasta, verenpaineen noususta tai mistään muusta epäsuotuisasta vaikutuksesta.</disclaimer>
137 <disclaimer lang="fr_CA">Ce logiciel est instable! Les auteurs ne sont aucunement responsables des enregistrements défaillants, des minuteries erronées, des heures perdues ou tout autre effet indésirable.</disclaimer>
134 <disclaimer lang="fr_CA">Ce logiciel est instable ! Les auteurs ne sont aucunement responsables des enregistrements défaillants, des minuteries erronées, des heures perdues ou tout autre effet indésirable.</disclaimer>
138135 <disclaimer lang="fr_FR">Logiciel en cours d'élaboration ! Les auteurs ne sont en aucun cas responsables de l'échec des enregistrements, programmations défectueuses, temps perdu ou autres effets indésirables.</disclaimer>
139136 <disclaimer lang="gl_ES">Software non estable, os autores non se fan responsábeis dos erros na gravacións, temporizadores incorrectos, e outros efectos non desexados.</disclaimer>
140137 <disclaimer lang="he_IL">זוהי איננה הרחבה יציבה! המפתחים אינם אחראים על כשלון בניגון, זמנים שגויים במדריך השידורים, שעות מבוזבזות או כל תופעה לא רצויה אחרת.</disclaimer>
176173 <disclaimer lang="zh_CN">这是不稳定版的软件!作者不对录像失败、错误定时造成时间浪费或其它不良影响负责。</disclaimer>
177174 <disclaimer lang="zh_TW">這是測試版軟體!其原創作者並無法對於以下情況負責,包含:錄影失敗,不正確的定時設定,多餘時數,或任何產生的其它不良影響...</disclaimer>
178175 <platform>@PLATFORM@</platform>
176 <news>
177 v3.28.9
178 - Fixed: Add Timer title and fallback entry fix
179
180 v3.28.8
181 - Fixed: Fix time_t format string specifier win32 seg faults
182
183 v3.28.7
184 - Fixed: Logger fix ported from pvr.hts
185
186 v3.28.6
187 - Added: Epg lookup more debug logging on add timer
188
189 v3.28.5
190 - Added: release package bump
191
192 v3.28.4
193 - Added: added new addon icon
194
195 v3.28.3
196 - Added: Epg lookup debug logging - When adding timer
197
198 v3.28.2
199 - Fixed: Use correct start time for EPG lookup when adding timer
200 - Fixed: strncpy fix possible length fault
201
202 v3.28.1
203 - Update: Github README link in addon.xml for Leia
204
205 v3.28.0
206 - Added: Support for IPTV Streams configured on E2 device (no timeshifting)
207 - Added: Reload instead of reconnecting when channel/group changes are detected
208 - Added: Use truly unique IDs for channels so EPG changes are correctly reflected
209 - Fixed: Only get drive space for devices that have an HDD
210 - Fixed: use correct function to lookup group when adding
211 - Added: update README.md to show appveyor/travis badges per branch
212 - Added: Update OSX build script
213 - Added: update badge status for travis/appveyor
214 - Added: add copyright notices to files
215 - Fixed: Fix default path for genre text mapping file
216
217 v3.27.1
218 - Update: Build sytem version
219 - Added: AppVeyor for Windows related build tests
220 - Fixed: Build depends search way
221
222 v3.27.0
223 - Added: Allow creation of epg based repeating timer rules if autotimers are not available
224
225 v3.26.0
226 - Added: Set program id option for streams with superfluous program data
227 - Added: Undelete and trashcan (when configured on backend) for recordings
228 - Added: Use new API for backend channel numbers - openwebif 1.3.7
229 - Fixed: Radio groups parsed from wrong api
230 - Added: Support disabling addon debug logging in debug mode
231
232 v3.25.0
233 - Added: Support backend channel numbers for all channel groups not just the first
234 - Added: Ignore empty channel groups
235 - Added: Readme and help info updates
236 - Fixed: Revert support hidden entries for backend channel numbers
237 - Fixed: Fix hanging on deleting multiple recordings at once
238
239 v3.24.0
240 - Added: Custom Channel Groups, closes #209
241 - Added: Connection manager improvements
242 - Added: Support hidden entries for backend channel numbers
243 - Fixed: Timer descprition for providers who only use long descrption
244
245 v3.23.0
246 - Added: Support settings levels via the current kodi settings level
247 - Added: Fallback EPG Entries for Timers
248 - Added: Support backend channel numbers using Openwebif
249
250 v3.22.0
251 - Added: Help info for addon settings
252 - Added: Delete child timers when deleting autotimers
253 - Added: Set max connection check interval to 60 seconds
254 - Fixed: Incorrect localisation IDs
255 - Fixed: Timers in error state cause crash on delete
256 - Added: Support show info fields for Timers
257
258 v3.21.0
259 - Added: Support Edit Recording name, last played and play count
260 - Fixed: Use v3.6.1 of nlohmann/json to relax cmake version dependency for OSMC, fixes #194
261 - Added: Nightly channel reload check as default
262 - Added: Split out and move openwebif version checking to settings
263
264 v3.20.0
265 - Added: Add options to Tune Async connection for slower E2 devices
266 - Added: Enable option to reload channels and groups once per day if changes are detected
267 - Added: Allow timers generated by autotimers to be deleted
268 - Fixed: Fix for disabling timers
269 - Added: Use genre from kodi for timers instead of lookup where possible
270 - Added: Support recording type fully for TV/Radio/Any channel
271 - Added: By default load Last Scanned group if no TV groups found
272 - Fixed: Channel Service Refs Can sometimes have alphabetic characters appended at the end, fixes #202
273 - Added: For timers and autotimers without a valid channel put in error state instead of omitting
274 - Fixed: IsRunning timer check not checking start time
275
276 v3.19.0
277 - Added: Async Connection - Reconnect if Enigma2 device was or becomes unavailable, closes #154, closes #184
278 - Added: Notify when Channel/ChannelGroups changes are detected, closes #179
279 - Added: Support genres for Recordings and Timers, fixes #186
280 - Fixed: Instant recordings may be missing show info depending on last EPG update, fixes #185
281 - Added: Helper build script for MacOSX
282
283 v3.18.1
284 - Fixed: Crash on addon start, fixes #191
285
286 v3.18.0
287 - Fixed: Ensure only one call to GetEPGForChannel happens at one time, fixes #181
288 - Added: Update/fix server version for pvr addon
289 - Added: Option to skip initial EPG Load
290 - Fixed: Fix for zap on channel change for dreamboxes
291 - Added: Support for padding in certain timer types
292 - Fixed: Change the call web/tunersignal to web/signal so it also works on DreamOS
293
294 v3.17.0
295 - Added: Recording EDL support
296 - Added: Update Timer Types to display correctly in Manual vs EPG UIs
297 - Added: Updated show info regex's
298 - Fixed: Timer Recording not displaying description - Not being stored on STB - AddTimer Call, fixes #174
299 - Fixed: Fix for uncaught type_error for nlohmann/json
300 - Fixed: Include TV Favourites channels by default in settings
301 - Added: Support Last Scanned for both TV and Radio, fixes #178
302 - Fixed: Null pointer check for Genre EPG data processed XML
303
304 v3.16.2
305 - Fixed: Seg fault on shutdown - Timer Updates thread accessing released object, fixes #172
306 - Fixed: Incorrectly used time_t instead int64 in GetStreamTimes, fixes #171
307 - Added: Load Addon Version
308 - Fixed: Clean up/partition addon debug log, fixes #159
309 - Added: Add user defined delay between EPG Channel Updates, fixes #158
310 - Added: Enable Trace Logging in debug mode
311 - Added: Integrate Stream API details with Tuners
312 - Fixed: JSON API requires version 1.3.5+ of OpenWebIf, fixes #169
313 - Added: updated language files from Transifex
314
315 v3.16.1
316 - Fixed: Backend polled too often for Signal Quality, fixes #165
317 - Fixed: SNR and Signal showing as zero in PVR info overlay, fixes #164
318 - Fixed: When playing a current recording duration at end time is wrong, fixes #160
319 - Fixed: Plugin won't load channels after upgrade to 3.16.0, fixes #161
320
321 v3.16.0
322 - Added: Tuners and SignalStatus
323 - Added: Use Picon Path from OpenWebIf
324 - Fixed: Change startup issue log statements from Debug to Error, fixes #157
325
326 v3.15.5
327 - Added: updated language files from Transifex
328
329 v3.15.4
330 - Fixed: In 3.15.2 WebIf that is not OpenWebIf does not support auto timer API - Addon won't load Newnigma2 image, fixes #151
331
332 v3.15.3
333 - Fixed: GetStreamTimes not implemented for Recordings, fixes #148
334 - Fixed: When starting a recording partway through start time is EPG start not recording start, fixes #147
335
336 v3.15.2
337 - Fixed: Only load Season info extractor and genre mappers config when enabled, fixes #136
338 - Fixed: 3.15.1 dont load/work on old DM800se, fixes #139
339 - Fixed: Missing default value from timeshift buffer path, fixes #140
340 - Fixed: Channel Group Member Order not preserved, fixes #141
341
342 v3.15.1
343 - Fixed: since 3.15.0 pvr manager cant start #134
344 - Added: Log Distro Version
345
346 v3.15.0
347 - Added: Support for Radio Groups
348 - Added: Create unique list of channels instead of a copy of each channel per group, fixes #101
349 - Fixed: hdd free space is wrong, fixes #122
350 - Added: Device Settings - AutoTimer and Padding
351 - Added: PowerstateMode on exit, fixes #128
352 - Fixed: Store timer state on update, fixes #131
353 - Fixed: Updates not occuring at specified time and immediate update on timer event, fixes #130
354 - Added: Support different update modes for timers and recordings, fixes #125
355
356 v3.14.0
357 - Added: Externalised season/episode and genre config to allow users support other formats/languages, closes #118
358 - Added: Server OpenWebIf version now reported by addon
359
360 v3.13.0
361 - Added: New setting to enable streaming over HTTPS
362 - Added: New setting to enable authentication for streaming
363
364 v3.12.6
365 - Fixed: Windows build fix
366 - Fixed: tsbuffer.ts never got deleted, fixes #115
367 </news>
179368 </extension>
180369 </addon>
0 v2.4.12
1 - backport: Fixed timer recording margins to Krypton
2
3 v2.4.9
4 - updated language files from Transifex
5
6 v2.4.8
7 - updated language files from Transifex
8
9 v2.4.7
0 v3.28.9
1 - Fixed: Add Timer title and fallback entry fix
2
3 v3.28.8
4 - Fixed: Fix time_t format string specifier win32 seg faults
5
6 v3.28.7
7 - Fixed: Logger fix ported from pvr.hts
8
9 v3.28.6
10 - Added: Epg lookup more debug logging on add timer
11
12 v3.28.5
13 - Added: release package bump
14
15 v3.28.4
16 - Added: added new addon icon
17
18 v3.28.3
19 - Added: Epg lookup debug logging - When adding timer
20
21 v3.28.2
22 - Fixed: Use correct start time for EPG lookup when adding timer
23 - Fixed: strncpy fix possible length fault
24
25 v3.28.1
26 - Update: Github README link in addon.xml for Leia
27
28 v3.28.0
29 - Added: Support for IPTV Streams configured on E2 device (no timeshifting)
30 - Added: Reload instead of reconnecting when channel/group changes are detected
31 - Added: Use truly unique IDs for channels so EPG changes are correctly reflected
32 - Fixed: Only get drive space for devices that have an HDD
33 - Fixed: use correct function to lookup group when adding
34 - Added: update README.md to show appveyor/travis badges per branch
35 - Added: Update OSX build script
36 - Added: update badge status for travis/appveyor
37 - Added: add copyright notices to files
38 - Fixed: Fix default path for genre text mapping file
39
40 v3.27.1
41 - Update: Build sytem version
42 - Added: AppVeyor for Windows related build tests
43 - Fixed: Build depends search way
44
45 v3.27.0
46 - Added: Allow creation of epg based repeating timer rules if autotimers are not available
47
48 v3.26.0
49 - Added: Set program id option for streams with superfluous program data
50 - Added: Undelete and trashcan (when configured on backend) for recordings
51 - Added: Use new API for backend channel numbers - openwebif 1.3.7
52 - Fixed: Radio groups parsed from wrong api
53 - Added: Support disabling addon debug logging in debug mode
54
55 v3.25.0
56 - Added: Support backend channel numbers for all channel groups not just the first
57 - Added: Ignore empty channel groups
58 - Added: Readme and help info updates
59 - Fixed: Revert support hidden entries for backend channel numbers
60 - Fixed: Fix hanging on deleting multiple recordings at once
61
62 v3.24.0
63 - Added: Custom Channel Groups, closes #209
64 - Added: Connection manager improvements
65 - Added: Support hidden entries for backend channel numbers
66 - Fixed: Timer descprition for providers who only use long descrption
67
68 v3.23.0
69 - Added: Support settings levels via the current kodi settings level
70 - Added: Fallback EPG Entries for Timers
71 - Added: Support backend channel numbers using Openwebif
72
73 v3.22.0
74 - Added: Help info for addon settings
75 - Added: Delete child timers when deleting autotimers
76 - Added: Set max connection check interval to 60 seconds
77 - Fixed: Incorrect localisation IDs
78 - Fixed: Timers in error state cause crash on delete
79 - Added: Support show info fields for Timers
80
81 v3.21.0
82 - Added: Support Edit Recording name, last played and play count
83 - Fixed: Use v3.6.1 of nlohmann/json to relax cmake version dependency for OSMC, fixes #194
84 - Added: Nightly channel reload check as default
85 - Added: Split out and move openwebif version checking to settings
86
87 v3.20.0
88 - Added: Add options to Tune Async connection for slower E2 devices
89 - Added: Enable option to reload channels and groups once per day if changes are detected
90 - Added: Allow timers generated by autotimers to be deleted
91 - Fixed: Fix for disabling timers
92 - Added: Use genre from kodi for timers instead of lookup where possible
93 - Added: Support recording type fully for TV/Radio/Any channel
94 - Added: By default load Last Scanned group if no TV groups found
95 - Added: Limit autotimers to TV/Radio or originating channel's groups
96 - Fixed: Channel Service Refs Can sometimes have alphabetic characters appended at the end, fixes #202
97 - Added: For timers and autotimers without a valid channel put in error state instead of omitting
98 - Fixed: IsRunning timer check not checking start time
99
100 v3.19.0
101 - Added: Async Connection - Reconnect if Enigma2 device was or becomes unavailable, closes #154, closes #184
102 - Added: Notify when Channel/ChannelGroups changes are detected, closes #179
103 - Added: Support genres for Recordings and Timers, fixes #186
104 - Fixed: Instant recordings may be missing show info depending on last EPG update, fixes #185
105 - Added: Helper build script for MacOSX
106
107 v3.18.1
108 - Fixed: Crash on addon start, fixes #191
109
110 v3.18.0
111 - Fixed: Ensure only one call to GetEPGForChannel happens at one time, fixes #181
112 - Added: Update/fix server version for pvr addon
113 - Added: Option to skip initial EPG Load
114 - Fixed: Fix for zap on channel change for dreamboxes
115 - Added: Support for padding in certain timer types
116 - Fixed: Change the call web/tunersignal to web/signal so it also works on DreamOS
117
118 v3.17.0
119 - Added: Recording EDL support
120 - Added: Update Timer Types to display correctly in Manual vs EPG UIs
121 - Added: Updated show info regex's
122 - Fixed: Timer Recording not displaying description - Not being stored on STB - AddTimer Call, fixes #174
123 - Fixed: Fix for uncaught type_error for nlohmann/json
124 - Fixed: Include TV Favourites channels by default in settings
125 - Added: Support Last Scanned for both TV and Radio, fixes #178
126 - Fixed: Null pointer check for Genre EPG data from XML
127
128 v3.16.2
129 - Fixed: Seg fault on shutdown - Timer Updates thread accessing released object, fixes #172
130 - Fixed: Incorrectly used time_t instead int64 in GetStreamTimes, fixes #171
131 - Added: Load Addon Version
132 - Fixed: Clean up/partition addon debug log, fixes #159
133 - Added: Add user defined delay between EPG Channel Updates, fixes #158
134 - Added: Enable Trace Logging in debug mode
135 - Added: Integrate Stream API details with Tuners
136 - Fixed: JSON API requires version 1.3.5+ of OpenWebIf, fixes #169
137 - Added: updated language files from Transifex
138
139 v3.16.1
140 - Fixed: Backend polled too often for Signal Quality, fixes #165
141 - Fixed: SNR and Signal showing as zero in PVR info overlay, fixes #164
142 - Fixed: When playing a current recording duration at end time is wrong, fixes #160
143 - Fixed: Plugin won't load channels after upgrade to 3.16.0, fixes #161
144
145 v3.16.0
146 - Added: Tuners and SignalStatus
147 - Added: Use Picon Path from OpenWebIf
148 - Fixed: Change startup issue log statements from Debug to Error, fixes #157
149
150 v3.15.5
151 - Added: updated language files from Transifex
152
153 v3.15.4
154 - Fixed: In 3.15.2 WebIf that is not OpenWebIf does not support auto timer API - Addon won't load Newnigma2 image, fixes #151
155
156 v3.15.3
157 - Fixed: GetStreamTimes not implemented for Recordings, fixes #148
158 - Fixed: When starting a recording partway through start time is EPG start not recording start, fixes #147
159
160 v3.15.2
161 - Fixed: Only load Season info extractor and genre mappers config when enabled, fixes #136
162 - Fixed: 3.15.1 dont load/work on old DM800se, fixes #139
163 - Fixed: Missing default value from timeshift buffer path, fixes #140
164 - Fixed: Channel Group Member Order not preserved, fixes #141
165
166 v3.15.1
167 - Fixed: since 3.15.0 pvr manager cant start #134
168 - Added: Log Distro Version
169
170 v3.15.0
171 - Added: Support for Radio Groups
172 - Added: Create unique list of channels instead of a copy of each channel per group, fixes #101
173 - Fixed: hdd free space is wrong, fixes #122
174 - Added: Device Settings - AutoTimer and Padding
175 - Added: PowerstateMode on exit, fixes #128
176 - Fixed: Store timer state on update, fixes #131
177 - Fixed: Updates not occuring at specified time and immediate update on timer event, fixes #130
178 - Added: Support different update modes for timers and recordings, fixes #125
179
180 v3.14.1
181 - Added: updated language files from Transifex
182
183 v3.14.0
184 - Added: Externalised season/episode and genre config to allow users support other formats/languages, closes #118
185 - Added: Server OpenWebIf version now reported by addon
186
187 v3.13.0
188 - Added: New setting to enable streaming over HTTPS
189 - Added: New setting to enable authentication for streaming
190
191 v3.12.6
192 - Fixed: Windows build fix
193 - Fixed: tsbuffer.ts never got deleted, fixes #115
194
195 v3.12.5
196 - Fixed: Large refactor for code organisation
197 - Fixed: Disk space, only for mounts configured for recordings - Requires OpenWebIf 1.3.5, fixes #112
198
199 v3.12.4
200 - Fixed: Used space instead of free space in GetDriveSpace - fixes #109
201 - Added: Genre id support from OTA feeds - Requires OpenWebIf 1.3.5
202
203 v3.12.3
204 - Fixed: Refactoring - Changed Directory structure, split out classes and added getters/setters #102
205 - Fixed: Updated readme without VU+ entries - Courtesy of Hedda
206 - Fixed: New temporary icon
207
208 v3.12.2
209 - Fixed: Refactoring - Conventions: includes, namesapce naming, public private order in class definition
210 - Fixed: GetInitialEPGForGroup called for each CHANNEL while initial EPG Update - #86
211
212 v3.12.1
213 - Added: New setting for Prepending outline to plot
214 - Added: New setting for stream read chunk size
215 - Fixed: cosmetic error when recordings folder is empty #10
216 - Fixed: Rename "VuPlus" PVR client addon to Enigma2 or something else for Kodi? #28
217
218 v3.12.0
219 - Added: Extracting Genre and Season/Episode numbers for EPG entries and recordings
220 - Added: Updated Readme
221 - Fixed: Minimum version now 1.3.0 to use autotimers
222
223 v3.11.3
224 - Added: New settings to allow feature switches for generating repeating timers and autotimers
225 - Added: Config guide to Readme
226 - Fixed: Missing channel or more than one channel in timers/autotimers
227
228 v3.11.2
229 - Fixed: Previous version picon fix turned into an option to use picons.eu file format
230
231 v3.11.1
232 - Fixed: Not able to select duplicate with titles and all descs
233 - Fixed: Online icons path processing incorrect for some channels
234
235 v3.11.0
236 - Added: Autotimer support
237 - Added: Generate ReadOnly Timers for Repeating Timer Rules
238 - Added: GetDriveSpace
239
240 v3.10.1
241 - Cleaned up settings screen
242 - Fix: Timer tags no longer removed on timer update
243
244 v3.10.0
245 - Added: Recorded Streams support
246 - Added: PVR API 5.0.0: iChannelUid in recordings
247 - Added: PVR API 5.1.0: Support channel type in recordings
248
249 v3.9.0
250 - Added: Timer Types Support, now supports Manual Once, Manual Repeating and EPG Once
251
252 v3.8.0
253 - Added: timeshift support
254 - Signal Status support
255 - Fixed recording duration bug and cleaned up split string code
256
257 v3.7.3
258 - Translation update from Transifex
259
260 v3.7.2
261 - Translation update from Transifex
262
263 v3.7.1
264 - Updated to PVR addon API v5.10.1
265
266 v3.7.0
267 - Updated to PVR addon API v5.10.0
268
269 v3.6.3
270 - Updated to PVR addon API v5.9.0
271
272 v3.6.0
273 - Updated to PVR addon API v5.8.0
274
275 v3.5.6
276 - Fix string replace syntax
277
278 v3.5.5
279 - Remove StdString usage
280
281 v3.5.2
282 - Fixed timer recording margins
283
284 v3.5.1
285 - Updated language files from Transifex
286
287 v3.5.0
288 - Updated to PVR addon API v5.7.0
289
290 v3.4.1
291 - Removed incomplete implementation of channel playback via live input stream. Addon claimed to support it, but actually didn't.
292 - Restored channel playback via stream URL. This is what the addon actually implements.
293
294 v3.4.0
295 - Updated to PVR addon API v5.6.0
296
297 v3.3.2
298 - added option to keep the folder structure from STB
299
300 v3.3.1
301 - added option to request the streaming-URL from openWebif and thus eliminating the need to configure the streaming port
302
303 v3.3.0
304 - Updated to PVR addon API v5.5.0
305
306 v3.2.0
307 - Updated to PVR addon API v5.4.0
308
309 v3.1.0
310 - Updated to PVR addon API v5.3.0
311
312 v3.0.6
313 - remove of never used addon interface function
314
315 v3.0.5
316 - update Debian package control
317 - PVR addon callback way changes
318
319 v3.0.4
320 - removed old no more needed version functions
321
322 v3.0.3
323 - set dependency versions automatic during build
324 - removed never used kodi to addon functions
325
326 v3.0.2
10327 - streaming always use anonymous http connection, regardless of the "Use https" setting
11328
12 v2.4.6
13 - updated language files from Transifex
14
15 v2.4.5
16 - Updated to PVR addon API v5.2.1
329 v3.0.1
330 - updated language files from Transifex
331
332 v3.0.0
333 - Initial Kodi v18 version
17334
18335 v2.4.4
19336 - updated language files from Transifex
184501
185502 0.3.1:
186503 - change: remove XMLParser
187 - change: add enigma2 to the displayname
504 - change: add enigma2 to the displayname
188505
189506 0.3.0:
190507 - change: remove curl dependancy
237554 0.1.14
238555 - change: change .gitignores and copy current changelog into the addon folder. This will enable the user to view the changelog in the addon settings window
239556
240 0.1.13
557 0.1.13
241558 - add: option to set deepstandby powerstate on the DVB box on PVR-addon shutdown
242559 - fix: error in settings.xml, causing crashes on linux
243560
244 0.1.12
561 0.1.12
245562 - add: support to specify the folder for storing recordings
246563
247 0.1.11
564 0.1.11
248565 - fix: some unicode string errors in german language file
249566 - change: add categories to addon settings
250567
251 0.1.10
252 - add: support for using only the recording path currently active on the DVB box
253
254 0.1.9
568 0.1.10
569 - add: support for using only the recording path currently active on the DVB box
570
571 0.1.9
255572 - change: add addon icon (copyied from the openelec guys, thanks!)
256573 - fix: win32 release target (thanks to 'trans' for patch)
257574
258 0.1.8
575 0.1.8
259576 - change: fetch the recording locations and use these locations when querying the recordings
260577 - fix: Stop update thread when destroying the PVR addon - fixes shutdown issues
261578
262 0.1.7
263 - fix: Copy & Paste error
264
265 0.1.6
579 0.1.7
580 - fix: Copy & Paste error
581
582 0.1.6
266583 - fix: Change the logic to determine the picon file name from the service reference.
267584
268 0.1.5
585 0.1.5
269586 - fix: Fix access violation errors on windows (thanks to 'trans' for finding the correct compiler / linker settings)
270587 - fix: do not return out of scope local variable for the streaming URL
271588 - fix: remove the last '_' character from the filename (if applicable). Should finally fix the picon path errors.
272589
273 0.1.4
274 - fix: limit length of the service reference part of the Icon-Path to 30 characters.
590 0.1.4
591 - fix: limit length of the service reference part of the Icon-Path to 30 characters.
275592 - fix: Escape "&", "<" and ">" characters in XML channeldata file.
276 - add: support to disable all bouquet or channel updates
277
278 0.1.3
279 - fix: order of timerlist cleanup and timerlist updates
280
281 0.1.2
593 - add: support to disable all bouquet or channel updates
594
595 0.1.3
596 - fix: order of timerlist cleanup and timerlist updates
597
598 0.1.2
282599 - add: support for storing channel data into a file
283600
284 0.1.1
601 0.1.1
285602 - fix: URLEncode the service reference when fetching EPG
286603
287 0.1.0
604 0.1.0
288605 - Iniital Version
Binary diff not shown
0 <!--
1
2 Custom Channel Groups:
3 - Allows users to create a bespoke list of groups to load.
4 - For each name that matches a group/bouquet name from the set top box include it in the channels loaded
5 - If no names match the addon will load last scanned by default.
6 - channelGroupName is the only value to be set
7
8 If you are creating your own Custom Channel Groups file make a copy of this file in the same directory so it's not overwritten and start from there.
9
10 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
11 -->
12
13 <customChannelGroups>
14 <channelGroupName>FreeSat UK - Radio Channels</channelGroupName>
15 <channelGroupName>Saorview - Radio Channels</channelGroupName>
16 </customChannelGroups>
0 <!--
1
2 Custom Channel Groups:
3 - Allows users to create a bespoke list of groups to load.
4 - For each name that matches a group/bouquet name from the set top box include it in the channels loaded
5 - If no names match the addon will load last scanned by default.
6 - channelGroupName is the only value to be set
7
8 If you are creating your own Custom Channel Groups file make a copy of this file in the same directory so it's not overwritten and start from there.
9
10 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
11 -->
12
13 <customChannelGroups>
14 <channelGroupName>FreeSat UK - All channels</channelGroupName>
15 <channelGroupName>FreeSat UK - Saorview</channelGroupName>
16 <channelGroupName>FreeSat UK - Movies</channelGroupName>
17 </customChannelGroups>
0 <!--
1 Note: the first 4 bits is genre and last is sub genre
2
3 Kodi DVB Genres can be found here: usersdata/genres/kodiDVBGenres.xml
4
5 Mapping ID Genres:
6 - The end result is to map to one of the DVB Genres for Kodi PVR.
7 - This enables Kodi PVR to colour the EPG entries accordingly.
8 - Mapping are done of the Hex value of the genre ID.
9 - SourceId is the genre id from the feed.
10 - Mapping element content is the DVB genre ID
11 - If a mapping can't be found it defaults to 0x00 (Undefined). However all possible 256 values detailed below.
12
13 If you are creating yoru own ID mappings make a copy of this file in the same directory so it's not overwritten and start from there.
14
15 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
16
17 If you have changes either create a PR containing the changes or an issue with details at:
18 https://github.com/kodi-pvr/pvr.vuplus
19 -->
20
21 <genreIdMappings>
22 <mapperName>AU-SAT</mapperName>
23 <mappings>
24 <mapping sourceId="0x01">0x00</mapping> <!-- Undefined -->
25 <mapping sourceId="0x02">0x00</mapping> <!-- Undefined -->
26 <mapping sourceId="0x03">0x00</mapping> <!-- Undefined -->
27 <mapping sourceId="0x04">0x00</mapping> <!-- Undefined -->
28 <mapping sourceId="0x05">0x00</mapping> <!-- Undefined -->
29 <mapping sourceId="0x06">0x00</mapping> <!-- Undefined -->
30 <mapping sourceId="0x07">0x00</mapping> <!-- Undefined -->
31 <mapping sourceId="0x08">0x00</mapping> <!-- Undefined -->
32 <mapping sourceId="0x09">0x00</mapping> <!-- Undefined -->
33 <mapping sourceId="0x0A">0x00</mapping> <!-- Undefined -->
34 <mapping sourceId="0x0B">0x00</mapping> <!-- Undefined -->
35 <mapping sourceId="0x0C">0x00</mapping> <!-- Undefined -->
36 <mapping sourceId="0x0D">0x00</mapping> <!-- Undefined -->
37 <mapping sourceId="0x0E">0x00</mapping> <!-- Undefined -->
38 <mapping sourceId="0x0F">0x00</mapping> <!-- Undefined -->
39 <mapping sourceId="0x10">0x00</mapping> <!-- Undefined -->
40 <mapping sourceId="0x11">0x00</mapping> <!-- Undefined -->
41 <mapping sourceId="0x12">0x00</mapping> <!-- Undefined -->
42 <mapping sourceId="0x13">0x00</mapping> <!-- Undefined -->
43 <mapping sourceId="0x14">0x00</mapping> <!-- Undefined -->
44 <mapping sourceId="0x15">0x00</mapping> <!-- Undefined -->
45 <mapping sourceId="0x16">0x00</mapping> <!-- Undefined -->
46 <mapping sourceId="0x17">0x00</mapping> <!-- Undefined -->
47 <mapping sourceId="0x18">0x00</mapping> <!-- Undefined -->
48 <mapping sourceId="0x19">0x00</mapping> <!-- Undefined -->
49 <mapping sourceId="0x1A">0x00</mapping> <!-- Undefined -->
50 <mapping sourceId="0x1B">0x00</mapping> <!-- Undefined -->
51 <mapping sourceId="0x1C">0x00</mapping> <!-- Undefined -->
52 <mapping sourceId="0x1D">0x00</mapping> <!-- Undefined -->
53 <mapping sourceId="0x1E">0x00</mapping> <!-- Undefined -->
54 <mapping sourceId="0x1F">0x00</mapping> <!-- Undefined -->
55 <mapping sourceId="0x20">0x00</mapping> <!-- Undefined -->
56 <mapping sourceId="0x21">0x00</mapping> <!-- Undefined -->
57 <mapping sourceId="0x22">0x20</mapping> <!-- News/Current Affairs -->
58 <mapping sourceId="0x23">0x20</mapping> <!-- News/Current Affairs -->
59 <mapping sourceId="0x24">0x20</mapping> <!-- News/Current Affairs -->
60 <mapping sourceId="0x25">0x20</mapping> <!-- News/Current Affairs -->
61 <mapping sourceId="0x26">0x20</mapping> <!-- News/Current Affairs -->
62 <mapping sourceId="0x27">0x20</mapping> <!-- News/Current Affairs -->
63 <mapping sourceId="0x28">0x20</mapping> <!-- News/Current Affairs -->
64 <mapping sourceId="0x29">0x20</mapping> <!-- News/Current Affairs -->
65 <mapping sourceId="0x2A">0x00</mapping> <!-- Undefined -->
66 <mapping sourceId="0x2B">0x00</mapping> <!-- Undefined -->
67 <mapping sourceId="0x2C">0x00</mapping> <!-- Undefined -->
68 <mapping sourceId="0x2D">0x00</mapping> <!-- Undefined -->
69 <mapping sourceId="0x2E">0x00</mapping> <!-- Undefined -->
70 <mapping sourceId="0x2F">0x00</mapping> <!-- Undefined -->
71 <mapping sourceId="0x30">0x00</mapping> <!-- Undefined -->
72 <mapping sourceId="0x31">0x00</mapping> <!-- Undefined -->
73 <mapping sourceId="0x32">0x00</mapping> <!-- Undefined -->
74 <mapping sourceId="0x33">0x00</mapping> <!-- Undefined -->
75 <mapping sourceId="0x34">0x00</mapping> <!-- Undefined -->
76 <mapping sourceId="0x35">0x00</mapping> <!-- Undefined -->
77 <mapping sourceId="0x36">0x00</mapping> <!-- Undefined -->
78 <mapping sourceId="0x37">0x00</mapping> <!-- Undefined -->
79 <mapping sourceId="0x38">0x00</mapping> <!-- Undefined -->
80 <mapping sourceId="0x39">0x00</mapping> <!-- Undefined -->
81 <mapping sourceId="0x3A">0x00</mapping> <!-- Undefined -->
82 <mapping sourceId="0x3B">0x00</mapping> <!-- Undefined -->
83 <mapping sourceId="0x3C">0x00</mapping> <!-- Undefined -->
84 <mapping sourceId="0x3D">0x00</mapping> <!-- Undefined -->
85 <mapping sourceId="0x3E">0x00</mapping> <!-- Undefined -->
86 <mapping sourceId="0x3F">0x00</mapping> <!-- Undefined -->
87 <mapping sourceId="0x40">0x00</mapping> <!-- Undefined -->
88 <mapping sourceId="0x41">0x00</mapping> <!-- Undefined -->
89 <mapping sourceId="0x42">0x51</mapping> <!-- Pre-school Children's Programmes -->
90 <mapping sourceId="0x43">0x30</mapping> <!-- Show/Game Show -->
91 <mapping sourceId="0x44">0x30</mapping> <!-- Show/Game Show -->
92 <mapping sourceId="0x45">0x50</mapping> <!-- Children's/Youth Programmes -->
93 <mapping sourceId="0x46">0x33</mapping> <!-- Talk Show -->
94 <mapping sourceId="0x47">0x30</mapping> <!-- Show/Game Show -->
95 <mapping sourceId="0x48">0x50</mapping> <!-- Children's/Youth Programmes -->
96 <mapping sourceId="0x49">0x30</mapping> <!-- Show/Game Show -->
97 <mapping sourceId="0x4A">0x00</mapping> <!-- Undefined -->
98 <mapping sourceId="0x4B">0x30</mapping> <!-- Show/Game Show -->
99 <mapping sourceId="0x4C">0x00</mapping> <!-- Undefined -->
100 <mapping sourceId="0x4D">0x00</mapping> <!-- Undefined -->
101 <mapping sourceId="0x4E">0x00</mapping> <!-- Undefined -->
102 <mapping sourceId="0x4F">0x00</mapping> <!-- Undefined -->
103 <mapping sourceId="0x50">0x00</mapping> <!-- Undefined -->
104 <mapping sourceId="0x51">0x00</mapping> <!-- Undefined -->
105 <mapping sourceId="0x52">0x00</mapping> <!-- Undefined -->
106 <mapping sourceId="0x53">0x00</mapping> <!-- Undefined -->
107 <mapping sourceId="0x54">0x00</mapping> <!-- Undefined -->
108 <mapping sourceId="0x55">0x00</mapping> <!-- Undefined -->
109 <mapping sourceId="0x56">0x00</mapping> <!-- Undefined -->
110 <mapping sourceId="0x57">0x00</mapping> <!-- Undefined -->
111 <mapping sourceId="0x58">0x00</mapping> <!-- Undefined -->
112 <mapping sourceId="0x59">0x00</mapping> <!-- Undefined -->
113 <mapping sourceId="0x5A">0x00</mapping> <!-- Undefined -->
114 <mapping sourceId="0x5B">0x00</mapping> <!-- Undefined -->
115 <mapping sourceId="0x5C">0x00</mapping> <!-- Undefined -->
116 <mapping sourceId="0x5D">0x00</mapping> <!-- Undefined -->
117 <mapping sourceId="0x5E">0x00</mapping> <!-- Undefined -->
118 <mapping sourceId="0x5F">0x00</mapping> <!-- Undefined -->
119 <mapping sourceId="0x60">0x00</mapping> <!-- Undefined -->
120 <mapping sourceId="0x61">0x00</mapping> <!-- Undefined -->
121 <mapping sourceId="0x62">0x00</mapping> <!-- Undefined -->
122 <mapping sourceId="0x63">0x00</mapping> <!-- Undefined -->
123 <mapping sourceId="0x64">0x00</mapping> <!-- Undefined -->
124 <mapping sourceId="0x65">0x00</mapping> <!-- Undefined -->
125 <mapping sourceId="0x66">0x00</mapping> <!-- Undefined -->
126 <mapping sourceId="0x67">0x00</mapping> <!-- Undefined -->
127 <mapping sourceId="0x68">0x00</mapping> <!-- Undefined -->
128 <mapping sourceId="0x69">0x00</mapping> <!-- Undefined -->
129 <mapping sourceId="0x6A">0x00</mapping> <!-- Undefined -->
130 <mapping sourceId="0x6B">0x00</mapping> <!-- Undefined -->
131 <mapping sourceId="0x6C">0x00</mapping> <!-- Undefined -->
132 <mapping sourceId="0x6D">0x00</mapping> <!-- Undefined -->
133 <mapping sourceId="0x6E">0x00</mapping> <!-- Undefined -->
134 <mapping sourceId="0x6F">0x00</mapping> <!-- Undefined -->
135 <mapping sourceId="0x70">0x00</mapping> <!-- Undefined -->
136 <mapping sourceId="0x71">0x00</mapping> <!-- Undefined -->
137 <mapping sourceId="0x72">0x00</mapping> <!-- Undefined -->
138 <mapping sourceId="0x73">0x00</mapping> <!-- Undefined -->
139 <mapping sourceId="0x74">0x00</mapping> <!-- Undefined -->
140 <mapping sourceId="0x75">0x00</mapping> <!-- Undefined -->
141 <mapping sourceId="0x75">0x00</mapping> <!-- Undefined -->
142 <mapping sourceId="0x77">0x00</mapping> <!-- Undefined -->
143 <mapping sourceId="0x78">0x00</mapping> <!-- Undefined -->
144 <mapping sourceId="0x79">0x00</mapping> <!-- Undefined -->
145 <mapping sourceId="0x7A">0x00</mapping> <!-- Undefined -->
146 <mapping sourceId="0x7B">0x00</mapping> <!-- Undefined -->
147 <mapping sourceId="0x7C">0x00</mapping> <!-- Undefined -->
148 <mapping sourceId="0x7D">0x00</mapping> <!-- Undefined -->
149 <mapping sourceId="0x7E">0x00</mapping> <!-- Undefined -->
150 <mapping sourceId="0x7F">0x00</mapping> <!-- Undefined -->
151 <mapping sourceId="0x80">0x00</mapping> <!-- Undefined -->
152 <mapping sourceId="0x81">0x00</mapping> <!-- Undefined -->
153 <mapping sourceId="0x82">0x12</mapping> <!-- Adventure/Western/War -->
154 <mapping sourceId="0x83">0x12</mapping> <!-- Adventure/Western/War -->
155 <mapping sourceId="0x84">0x16</mapping> <!-- Romance -->
156 <mapping sourceId="0x85">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
157 <mapping sourceId="0x86">0x14</mapping> <!-- Comedy -->
158 <mapping sourceId="0x87">0x11</mapping> <!-- Detective/Thriller -->
159 <mapping sourceId="0x88">0x10</mapping> <!-- General Movie/Drama -->
160 <mapping sourceId="0x89">0x10</mapping> <!-- General Movie/Drama -->
161 <mapping sourceId="0x8A">0x60</mapping> <!-- Music/Ballet/Dance -->
162 <mapping sourceId="0x8B">0x00</mapping> <!-- Undefined -->
163 <mapping sourceId="0x8C">0x60</mapping> <!-- Music/Ballet/Dance -->
164 <mapping sourceId="0x8D">0x00</mapping> <!-- Undefined -->
165 <mapping sourceId="0x8E">0x60</mapping> <!-- Music/Ballet/Dance -->
166 <mapping sourceId="0x8F">0x00</mapping> <!-- Undefined -->
167 <mapping sourceId="0x90">0x00</mapping> <!-- Undefined -->
168 <mapping sourceId="0x91">0x00</mapping> <!-- Undefined -->
169 <mapping sourceId="0x92">0x00</mapping> <!-- Undefined -->
170 <mapping sourceId="0x93">0x00</mapping> <!-- Undefined -->
171 <mapping sourceId="0x94">0x00</mapping> <!-- Undefined -->
172 <mapping sourceId="0x95">0x00</mapping> <!-- Undefined -->
173 <mapping sourceId="0x96">0x00</mapping> <!-- Undefined -->
174 <mapping sourceId="0x97">0x00</mapping> <!-- Undefined -->
175 <mapping sourceId="0x98">0x00</mapping> <!-- Undefined -->
176 <mapping sourceId="0x99">0x00</mapping> <!-- Undefined -->
177 <mapping sourceId="0x9A">0x00</mapping> <!-- Undefined -->
178 <mapping sourceId="0x9B">0x00</mapping> <!-- Undefined -->
179 <mapping sourceId="0x9C">0x00</mapping> <!-- Undefined -->
180 <mapping sourceId="0x9D">0x00</mapping> <!-- Undefined -->
181 <mapping sourceId="0x9E">0x00</mapping> <!-- Undefined -->
182 <mapping sourceId="0x9F">0x00</mapping> <!-- Undefined -->
183 <mapping sourceId="0xA0">0x00</mapping> <!-- Undefined -->
184 <mapping sourceId="0xA1">0x00</mapping> <!-- Undefined -->
185 <mapping sourceId="0xA2">0x00</mapping> <!-- Undefined -->
186 <mapping sourceId="0xA3">0x00</mapping> <!-- Undefined -->
187 <mapping sourceId="0xA4">0x00</mapping> <!-- Undefined -->
188 <mapping sourceId="0xA5">0x00</mapping> <!-- Undefined -->
189 <mapping sourceId="0xA6">0x00</mapping> <!-- Undefined -->
190 <mapping sourceId="0xA7">0x00</mapping> <!-- Undefined -->
191 <mapping sourceId="0xA8">0x00</mapping> <!-- Undefined -->
192 <mapping sourceId="0xA9">0x00</mapping> <!-- Undefined -->
193 <mapping sourceId="0xAA">0x00</mapping> <!-- Undefined -->
194 <mapping sourceId="0xAB">0x00</mapping> <!-- Undefined -->
195 <mapping sourceId="0xAC">0x00</mapping> <!-- Undefined -->
196 <mapping sourceId="0xAD">0x00</mapping> <!-- Undefined -->
197 <mapping sourceId="0xAE">0x00</mapping> <!-- Undefined -->
198 <mapping sourceId="0xAF">0x00</mapping> <!-- Undefined -->
199 <mapping sourceId="0xB0">0x00</mapping> <!-- Undefined -->
200 <mapping sourceId="0xB1">0x00</mapping> <!-- Undefined -->
201 <mapping sourceId="0xB2">0x00</mapping> <!-- Undefined -->
202 <mapping sourceId="0xB3">0x00</mapping> <!-- Undefined -->
203 <mapping sourceId="0xB4">0x00</mapping> <!-- Undefined -->
204 <mapping sourceId="0xB5">0x00</mapping> <!-- Undefined -->
205 <mapping sourceId="0xB6">0x00</mapping> <!-- Undefined -->
206 <mapping sourceId="0xB7">0x00</mapping> <!-- Undefined -->
207 <mapping sourceId="0xB8">0x00</mapping> <!-- Undefined -->
208 <mapping sourceId="0xB9">0x00</mapping> <!-- Undefined -->
209 <mapping sourceId="0xBA">0x00</mapping> <!-- Undefined -->
210 <mapping sourceId="0xBB">0x00</mapping> <!-- Undefined -->
211 <mapping sourceId="0xBC">0x00</mapping> <!-- Undefined -->
212 <mapping sourceId="0xBD">0x00</mapping> <!-- Undefined -->
213 <mapping sourceId="0xBE">0x00</mapping> <!-- Undefined -->
214 <mapping sourceId="0xBF">0x00</mapping> <!-- Undefined -->
215 <mapping sourceId="0xC0">0x00</mapping> <!-- Undefined -->
216 <mapping sourceId="0xC1">0x00</mapping> <!-- Undefined -->
217 <mapping sourceId="0xC2">0x40</mapping> <!-- Sports -->
218 <mapping sourceId="0xC3">0x40</mapping> <!-- Sports -->
219 <mapping sourceId="0xC4">0x40</mapping> <!-- Sports -->
220 <mapping sourceId="0xC5">0x43</mapping> <!-- Football -->
221 <mapping sourceId="0xC6">0x40</mapping> <!-- Sports -->
222 <mapping sourceId="0xC7">0x40</mapping> <!-- Sports -->
223 <mapping sourceId="0xC8">0x40</mapping> <!-- Sports -->
224 <mapping sourceId="0xC9">0x40</mapping> <!-- Sports -->
225 <mapping sourceId="0xCA">0x40</mapping> <!-- Sports -->
226 <mapping sourceId="0xCB">0x49</mapping> <!-- Winter Sports -->
227 <mapping sourceId="0xCC">0x40</mapping> <!-- Sports -->
228 <mapping sourceId="0xCD">0x40</mapping> <!-- Sports -->
229 <mapping sourceId="0xCE">0x00</mapping> <!-- Undefined -->
230 <mapping sourceId="0xCF">0x00</mapping> <!-- Undefined -->
231 <mapping sourceId="0xD0">0x00</mapping> <!-- Undefined -->
232 <mapping sourceId="0xD1">0x00</mapping> <!-- Undefined -->
233 <mapping sourceId="0xD2">0x00</mapping> <!-- Undefined -->
234 <mapping sourceId="0xD3">0x00</mapping> <!-- Undefined -->
235 <mapping sourceId="0xD4">0x00</mapping> <!-- Undefined -->
236 <mapping sourceId="0xD5">0x00</mapping> <!-- Undefined -->
237 <mapping sourceId="0xD6">0x00</mapping> <!-- Undefined -->
238 <mapping sourceId="0xD7">0x00</mapping> <!-- Undefined -->
239 <mapping sourceId="0xD8">0x00</mapping> <!-- Undefined -->
240 <mapping sourceId="0xD9">0x00</mapping> <!-- Undefined -->
241 <mapping sourceId="0xDA">0x00</mapping> <!-- Undefined -->
242 <mapping sourceId="0xDB">0x00</mapping> <!-- Undefined -->
243 <mapping sourceId="0xDC">0x00</mapping> <!-- Undefined -->
244 <mapping sourceId="0xDD">0x00</mapping> <!-- Undefined -->
245 <mapping sourceId="0xDE">0x00</mapping> <!-- Undefined -->
246 <mapping sourceId="0xDF">0x00</mapping> <!-- Undefined -->
247 <mapping sourceId="0xE0">0x00</mapping> <!-- Undefined -->
248 <mapping sourceId="0xE1">0x00</mapping> <!-- Undefined -->
249 <mapping sourceId="0xE2">0x00</mapping> <!-- Undefined -->
250 <mapping sourceId="0xE3">0x00</mapping> <!-- Undefined -->
251 <mapping sourceId="0xE4">0x00</mapping> <!-- Undefined -->
252 <mapping sourceId="0xE5">0x00</mapping> <!-- Undefined -->
253 <mapping sourceId="0xE6">0x00</mapping> <!-- Undefined -->
254 <mapping sourceId="0xE7">0x00</mapping> <!-- Undefined -->
255 <mapping sourceId="0xE8">0x00</mapping> <!-- Undefined -->
256 <mapping sourceId="0xE9">0x00</mapping> <!-- Undefined -->
257 <mapping sourceId="0xEA">0x00</mapping> <!-- Undefined -->
258 <mapping sourceId="0xEB">0x00</mapping> <!-- Undefined -->
259 <mapping sourceId="0xEC">0x00</mapping> <!-- Undefined -->
260 <mapping sourceId="0xED">0x00</mapping> <!-- Undefined -->
261 <mapping sourceId="0xEE">0x00</mapping> <!-- Undefined -->
262 <mapping sourceId="0xEF">0x00</mapping> <!-- Undefined -->
263 <mapping sourceId="0xF0">0x00</mapping> <!-- Undefined -->
264 <mapping sourceId="0xF1">0x00</mapping> <!-- Undefined -->
265 <mapping sourceId="0xF2">0x00</mapping> <!-- Undefined -->
266 <mapping sourceId="0xF3">0x00</mapping> <!-- Undefined -->
267 <mapping sourceId="0xF4">0x00</mapping> <!-- Undefined -->
268 <mapping sourceId="0xF5">0x00</mapping> <!-- Undefined -->
269 <mapping sourceId="0xF6">0x00</mapping> <!-- Undefined -->
270 <mapping sourceId="0xF7">0x00</mapping> <!-- Undefined -->
271 <mapping sourceId="0xF8">0x00</mapping> <!-- Undefined -->
272 <mapping sourceId="0xF9">0x00</mapping> <!-- Undefined -->
273 <mapping sourceId="0xFA">0x00</mapping> <!-- Undefined -->
274 <mapping sourceId="0xFB">0x00</mapping> <!-- Undefined -->
275 <mapping sourceId="0xFC">0x00</mapping> <!-- Undefined -->
276 <mapping sourceId="0xFD">0x00</mapping> <!-- Undefined -->
277 <mapping sourceId="0xFD">0x00</mapping> <!-- Undefined -->
278 <mapping sourceId="0xFE">0x00</mapping> <!-- Undefined -->
279 <mapping sourceId="0xFF">0x00</mapping> <!-- Undefined -->
280 </mappings>
281 </genreIdMappings>
0 <!--
1 Note: the first 4 bits is genre and last is sub genre
2
3 Kodi DVB Genres can be found here: usersdata/genres/kodiDVBGenres.xml
4
5 Mapping ID Genres:
6 - The end result is to map to one of the DVB Genres for Kodi PVR.
7 - This enables Kodi PVR to colour the EPG entries accordingly.
8 - Mapping are done of the Hex value of the genre ID.
9 - SourceId is the genre id from the feed.
10 - Mapping element content is the DVB genre ID
11 - If a mapping can't be found it defaults to 0x00 (Undefined). However all possible 256 values detailed below.
12
13 If you are creating yoru own ID mappings make a copy of this file in the same directory so it's not overwritten and start from there.
14
15 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
16
17 If you have changes either create a PR containing the changes or an issue with details at:
18 https://github.com/kodi-pvr/pvr.vuplus
19 -->
20
21 <genreIdMappings>
22 <mapperName>Sky-IT</mapperName>
23 <mappings>
24 <mapping sourceId="0x00">0x00</mapping> <!-- Undefined -->
25 <mapping sourceId="0x01">0x00</mapping> <!-- Undefined -->
26 <mapping sourceId="0x02">0x00</mapping> <!-- Undefined -->
27 <mapping sourceId="0x03">0x00</mapping> <!-- Undefined -->
28 <mapping sourceId="0x04">0x00</mapping> <!-- Undefined -->
29 <mapping sourceId="0x05">0x00</mapping> <!-- Undefined -->
30 <mapping sourceId="0x06">0x00</mapping> <!-- Undefined -->
31 <mapping sourceId="0x07">0x00</mapping> <!-- Undefined -->
32 <mapping sourceId="0x08">0x00</mapping> <!-- Undefined -->
33 <mapping sourceId="0x09">0x00</mapping> <!-- Undefined -->
34 <mapping sourceId="0x0A">0x00</mapping> <!-- Undefined -->
35 <mapping sourceId="0x0B">0x00</mapping> <!-- Undefined -->
36 <mapping sourceId="0x0C">0x00</mapping> <!-- Undefined -->
37 <mapping sourceId="0x0D">0x00</mapping> <!-- Undefined -->
38 <mapping sourceId="0x0E">0x00</mapping> <!-- Undefined -->
39 <mapping sourceId="0x0F">0x00</mapping> <!-- Undefined -->
40 <mapping sourceId="0x10">0x00</mapping> <!-- Undefined -->
41 <mapping sourceId="0x11">0x00</mapping> <!-- Undefined -->
42 <mapping sourceId="0x12">0x00</mapping> <!-- Undefined -->
43 <mapping sourceId="0x13">0x00</mapping> <!-- Undefined -->
44 <mapping sourceId="0x14">0x00</mapping> <!-- Undefined -->
45 <mapping sourceId="0x15">0x00</mapping> <!-- Undefined -->
46 <mapping sourceId="0x16">0x00</mapping> <!-- Undefined -->
47 <mapping sourceId="0x17">0x00</mapping> <!-- Undefined -->
48 <mapping sourceId="0x18">0x00</mapping> <!-- Undefined -->
49 <mapping sourceId="0x19">0x00</mapping> <!-- Undefined -->
50 <mapping sourceId="0x1A">0x00</mapping> <!-- Undefined -->
51 <mapping sourceId="0x1B">0x00</mapping> <!-- Undefined -->
52 <mapping sourceId="0x1C">0x00</mapping> <!-- Undefined -->
53 <mapping sourceId="0x1D">0x00</mapping> <!-- Undefined -->
54 <mapping sourceId="0x1E">0x00</mapping> <!-- Undefined -->
55 <mapping sourceId="0x1F">0x00</mapping> <!-- Undefined -->
56 <mapping sourceId="0x20">0x30</mapping> <!-- Show/Game Show -->
57 <mapping sourceId="0x21">0x30</mapping> <!-- Show/Game Show -->
58 <mapping sourceId="0x22">0x30</mapping> <!-- Show/Game Show -->
59 <mapping sourceId="0x23">0x30</mapping> <!-- Show/Game Show -->
60 <mapping sourceId="0x24">0x30</mapping> <!-- Show/Game Show -->
61 <mapping sourceId="0x25">0x15</mapping> <!-- Soap/Melodrama/Folkloric -->
62 <mapping sourceId="0x26">0x30</mapping> <!-- Show/Game Show -->
63 <mapping sourceId="0x27">0x30</mapping> <!-- Show/Game Show -->
64 <mapping sourceId="0x28">0x30</mapping> <!-- Show/Game Show -->
65 <mapping sourceId="0x29">0x30</mapping> <!-- Show/Game Show -->
66 <mapping sourceId="0x2A">0x30</mapping> <!-- Show/Game Show -->
67 <mapping sourceId="0x2B">0x30</mapping> <!-- Show/Game Show -->
68 <mapping sourceId="0x2C">0x30</mapping> <!-- Show/Game Show -->
69 <mapping sourceId="0x2D">0x30</mapping> <!-- Show/Game Show -->
70 <mapping sourceId="0x2E">0x31</mapping> <!-- Game Show/Quiz/Contest -->
71 <mapping sourceId="0x2F">0x33</mapping> <!-- Talk Show -->
72 <mapping sourceId="0x30">0x30</mapping> <!-- Show/Game Show -->
73 <mapping sourceId="0x31">0x30</mapping> <!-- Show/Game Show -->
74 <mapping sourceId="0x32">0x30</mapping> <!-- Show/Game Show -->
75 <mapping sourceId="0x33">0x30</mapping> <!-- Show/Game Show -->
76 <mapping sourceId="0x34">0x00</mapping> <!-- Undefined -->
77 <mapping sourceId="0x35">0x00</mapping> <!-- Undefined -->
78 <mapping sourceId="0x36">0x00</mapping> <!-- Undefined -->
79 <mapping sourceId="0x37">0x00</mapping> <!-- Undefined -->
80 <mapping sourceId="0x38">0x00</mapping> <!-- Undefined -->
81 <mapping sourceId="0x39">0x00</mapping> <!-- Undefined -->
82 <mapping sourceId="0x3A">0x00</mapping> <!-- Undefined -->
83 <mapping sourceId="0x3B">0x00</mapping> <!-- Undefined -->
84 <mapping sourceId="0x3C">0x00</mapping> <!-- Undefined -->
85 <mapping sourceId="0x3D">0x00</mapping> <!-- Undefined -->
86 <mapping sourceId="0x3E">0x00</mapping> <!-- Undefined -->
87 <mapping sourceId="0x3F">0x00</mapping> <!-- Undefined -->
88 <mapping sourceId="0x40">0x40</mapping> <!-- Sports -->
89 <mapping sourceId="0x41">0x40</mapping> <!-- Sports -->
90 <mapping sourceId="0x42">0x44</mapping> <!-- Tennis/Squash -->
91 <mapping sourceId="0x43">0x47</mapping> <!-- Motor Sport -->
92 <mapping sourceId="0x44">0x40</mapping> <!-- Sports -->
93 <mapping sourceId="0x45">0x40</mapping> <!-- Sports -->
94 <mapping sourceId="0x46">0x40</mapping> <!-- Sports -->
95 <mapping sourceId="0x47">0x40</mapping> <!-- Sports -->
96 <mapping sourceId="0x48">0x40</mapping> <!-- Sports -->
97 <mapping sourceId="0x49">0x40</mapping> <!-- Sports -->
98 <mapping sourceId="0x4A">0x46</mapping> <!-- Athletics -->
99 <mapping sourceId="0x4B">0x40</mapping> <!-- Sports -->
100 <mapping sourceId="0x4C">0x40</mapping> <!-- Sports -->
101 <mapping sourceId="0x4D">0x40</mapping> <!-- Sports -->
102 <mapping sourceId="0x4E">0x4A</mapping> <!-- Equestrian -->
103 <mapping sourceId="0x4F">0x40</mapping> <!-- Sports -->
104 <mapping sourceId="0x50">0x40</mapping> <!-- Sports -->
105 <mapping sourceId="0x51">0x40</mapping> <!-- Sports -->
106 <mapping sourceId="0x52">0x00</mapping> <!-- Undefined -->
107 <mapping sourceId="0x53">0x00</mapping> <!-- Undefined -->
108 <mapping sourceId="0x54">0x00</mapping> <!-- Undefined -->
109 <mapping sourceId="0x55">0x00</mapping> <!-- Undefined -->
110 <mapping sourceId="0x56">0x00</mapping> <!-- Undefined -->
111 <mapping sourceId="0x57">0x00</mapping> <!-- Undefined -->
112 <mapping sourceId="0x58">0x00</mapping> <!-- Undefined -->
113 <mapping sourceId="0x59">0x00</mapping> <!-- Undefined -->
114 <mapping sourceId="0x5A">0x00</mapping> <!-- Undefined -->
115 <mapping sourceId="0x5B">0x00</mapping> <!-- Undefined -->
116 <mapping sourceId="0x5C">0x00</mapping> <!-- Undefined -->
117 <mapping sourceId="0x5D">0x00</mapping> <!-- Undefined -->
118 <mapping sourceId="0x5E">0x00</mapping> <!-- Undefined -->
119 <mapping sourceId="0x5F">0x00</mapping> <!-- Undefined -->
120 <mapping sourceId="0x60">0x10</mapping> <!-- General Movie/Drama -->
121 <mapping sourceId="0x61">0x17</mapping> <!-- Serious/Classical/Religious/Historical Movie/Drama -->
122 <mapping sourceId="0x62">0x14</mapping> <!-- Comedy -->
123 <mapping sourceId="0x63">0x16</mapping> <!-- Romance -->
124 <mapping sourceId="0x64">0x12</mapping> <!-- Adventure/Western/War -->
125 <mapping sourceId="0x65">0x10</mapping> <!-- General Movie/Drama -->
126 <mapping sourceId="0x66">0x12</mapping> <!-- Adventure/Western/War -->
127 <mapping sourceId="0x67">0x14</mapping> <!-- Comedy -->
128 <mapping sourceId="0x68">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
129 <mapping sourceId="0x69">0x12</mapping> <!-- Adventure/Western/War -->
130 <mapping sourceId="0x6A">0x10</mapping> <!-- General Movie/Drama -->
131 <mapping sourceId="0x6B">0x12</mapping> <!-- Adventure/Western/War -->
132 <mapping sourceId="0x6C">0x12</mapping> <!-- Adventure/Western/War -->
133 <mapping sourceId="0x6D">0x10</mapping> <!-- General Movie/Drama -->
134 <mapping sourceId="0x6E">0x11</mapping> <!-- Detective/Thriller -->
135 <mapping sourceId="0x6F">0x10</mapping> <!-- General Movie/Drama -->
136 <mapping sourceId="0x70">0x10</mapping> <!-- General Movie/Drama -->
137 <mapping sourceId="0x71">0x10</mapping> <!-- General Movie/Drama -->
138 <mapping sourceId="0x72">0x00</mapping> <!-- Undefined -->
139 <mapping sourceId="0x73">0x00</mapping> <!-- Undefined -->
140 <mapping sourceId="0x74">0x00</mapping> <!-- Undefined -->
141 <mapping sourceId="0x75">0x00</mapping> <!-- Undefined -->
142 <mapping sourceId="0x76">0x00</mapping> <!-- Undefined -->
143 <mapping sourceId="0x77">0x00</mapping> <!-- Undefined -->
144 <mapping sourceId="0x78">0x00</mapping> <!-- Undefined -->
145 <mapping sourceId="0x79">0x00</mapping> <!-- Undefined -->
146 <mapping sourceId="0x7A">0x00</mapping> <!-- Undefined -->
147 <mapping sourceId="0x7B">0x00</mapping> <!-- Undefined -->
148 <mapping sourceId="0x7C">0x00</mapping> <!-- Undefined -->
149 <mapping sourceId="0x7D">0x00</mapping> <!-- Undefined -->
150 <mapping sourceId="0x7E">0x00</mapping> <!-- Undefined -->
151 <mapping sourceId="0x7F">0x00</mapping> <!-- Undefined -->
152 <mapping sourceId="0x80">0x30</mapping> <!-- Show/Game Show -->
153 <mapping sourceId="0x81">0x30</mapping> <!-- Show/Game Show -->
154 <mapping sourceId="0x82">0x30</mapping> <!-- Show/Game Show -->
155 <mapping sourceId="0x83">0x30</mapping> <!-- Show/Game Show -->
156 <mapping sourceId="0x84">0x30</mapping> <!-- Show/Game Show -->
157 <mapping sourceId="0x85">0x30</mapping> <!-- Show/Game Show -->
158 <mapping sourceId="0x86">0x30</mapping> <!-- Show/Game Show -->
159 <mapping sourceId="0x87">0x30</mapping> <!-- Show/Game Show -->
160 <mapping sourceId="0x88">0x30</mapping> <!-- Show/Game Show -->
161 <mapping sourceId="0x89">0x30</mapping> <!-- Show/Game Show -->
162 <mapping sourceId="0x8A">0x30</mapping> <!-- Show/Game Show -->
163 <mapping sourceId="0x8B">0x30</mapping> <!-- Show/Game Show -->
164 <mapping sourceId="0x8C">0x30</mapping> <!-- Show/Game Show -->
165 <mapping sourceId="0x8D">0x30</mapping> <!-- Show/Game Show -->
166 <mapping sourceId="0x8E">0x30</mapping> <!-- Show/Game Show -->
167 <mapping sourceId="0x8F">0x30</mapping> <!-- Show/Game Show -->
168 <mapping sourceId="0x90">0x30</mapping> <!-- Show/Game Show -->
169 <mapping sourceId="0x91">0x30</mapping> <!-- Show/Game Show -->
170 <mapping sourceId="0x92">0x30</mapping> <!-- Show/Game Show -->
171 <mapping sourceId="0x93">0x30</mapping> <!-- Show/Game Show -->
172 <mapping sourceId="0x94">0x30</mapping> <!-- Show/Game Show -->
173 <mapping sourceId="0x95">0x30</mapping> <!-- Show/Game Show -->
174 <mapping sourceId="0x96">0x30</mapping> <!-- Show/Game Show -->
175 <mapping sourceId="0x97">0x30</mapping> <!-- Show/Game Show -->
176 <mapping sourceId="0x98">0x30</mapping> <!-- Show/Game Show -->
177 <mapping sourceId="0x99">0x30</mapping> <!-- Show/Game Show -->
178 <mapping sourceId="0x9A">0x30</mapping> <!-- Show/Game Show -->
179 <mapping sourceId="0x9B">0x30</mapping> <!-- Show/Game Show -->
180 <mapping sourceId="0x9C">0x30</mapping> <!-- Show/Game Show -->
181 <mapping sourceId="0x9D">0x30</mapping> <!-- Show/Game Show -->
182 <mapping sourceId="0x9E">0x30</mapping> <!-- Show/Game Show -->
183 <mapping sourceId="0x9F">0x30</mapping> <!-- Show/Game Show -->
184 <mapping sourceId="0xA0">0x30</mapping> <!-- Show/Game Show -->
185 <mapping sourceId="0xA1">0x30</mapping> <!-- Show/Game Show -->
186 <mapping sourceId="0xA2">0x30</mapping> <!-- Show/Game Show -->
187 <mapping sourceId="0xA3">0x30</mapping> <!-- Show/Game Show -->
188 <mapping sourceId="0xA4">0x00</mapping> <!-- Undefined -->
189 <mapping sourceId="0xA5">0x00</mapping> <!-- Undefined -->
190 <mapping sourceId="0xA6">0x00</mapping> <!-- Undefined -->
191 <mapping sourceId="0xA7">0x00</mapping> <!-- Undefined -->
192 <mapping sourceId="0xA8">0x00</mapping> <!-- Undefined -->
193 <mapping sourceId="0xA9">0x00</mapping> <!-- Undefined -->
194 <mapping sourceId="0xAA">0x00</mapping> <!-- Undefined -->
195 <mapping sourceId="0xAB">0x00</mapping> <!-- Undefined -->
196 <mapping sourceId="0xAC">0x00</mapping> <!-- Undefined -->
197 <mapping sourceId="0xAD">0x00</mapping> <!-- Undefined -->
198 <mapping sourceId="0xAE">0x00</mapping> <!-- Undefined -->
199 <mapping sourceId="0xAF">0x00</mapping> <!-- Undefined -->
200 <mapping sourceId="0xB0">0x00</mapping> <!-- Undefined -->
201 <mapping sourceId="0xB1">0x00</mapping> <!-- Undefined -->
202 <mapping sourceId="0xB2">0x00</mapping> <!-- Undefined -->
203 <mapping sourceId="0xB3">0x00</mapping> <!-- Undefined -->
204 <mapping sourceId="0xB4">0x00</mapping> <!-- Undefined -->
205 <mapping sourceId="0xB5">0x00</mapping> <!-- Undefined -->
206 <mapping sourceId="0xB6">0x00</mapping> <!-- Undefined -->
207 <mapping sourceId="0xB7">0x00</mapping> <!-- Undefined -->
208 <mapping sourceId="0xB8">0x00</mapping> <!-- Undefined -->
209 <mapping sourceId="0xB9">0x00</mapping> <!-- Undefined -->
210 <mapping sourceId="0xBA">0x00</mapping> <!-- Undefined -->
211 <mapping sourceId="0xBB">0x00</mapping> <!-- Undefined -->
212 <mapping sourceId="0xBC">0x00</mapping> <!-- Undefined -->
213 <mapping sourceId="0xBD">0x00</mapping> <!-- Undefined -->
214 <mapping sourceId="0xBE">0x00</mapping> <!-- Undefined -->
215 <mapping sourceId="0xBF">0x00</mapping> <!-- Undefined -->
216 <mapping sourceId="0xC0">0x60</mapping> <!-- Music/Ballet/Dance -->
217 <mapping sourceId="0xC1">0x60</mapping> <!-- Music/Ballet/Dance -->
218 <mapping sourceId="0xC2">0x60</mapping> <!-- Music/Ballet/Dance -->
219 <mapping sourceId="0xC3">0x60</mapping> <!-- Music/Ballet/Dance -->
220 <mapping sourceId="0xC4">0x60</mapping> <!-- Music/Ballet/Dance -->
221 <mapping sourceId="0xC5">0x60</mapping> <!-- Music/Ballet/Dance -->
222 <mapping sourceId="0xC6">0x60</mapping> <!-- Music/Ballet/Dance -->
223 <mapping sourceId="0xC7">0x60</mapping> <!-- Music/Ballet/Dance -->
224 <mapping sourceId="0xC8">0x60</mapping> <!-- Music/Ballet/Dance -->
225 <mapping sourceId="0xC9">0x00</mapping> <!-- Undefined -->
226 <mapping sourceId="0xCA">0x00</mapping> <!-- Undefined -->
227 <mapping sourceId="0xCB">0x00</mapping> <!-- Undefined -->
228 <mapping sourceId="0xCC">0x00</mapping> <!-- Undefined -->
229 <mapping sourceId="0xCD">0x00</mapping> <!-- Undefined -->
230 <mapping sourceId="0xCE">0x00</mapping> <!-- Undefined -->
231 <mapping sourceId="0xCF">0x00</mapping> <!-- Undefined -->
232 <mapping sourceId="0xD0">0x00</mapping> <!-- Undefined -->
233 <mapping sourceId="0xD1">0x00</mapping> <!-- Undefined -->
234 <mapping sourceId="0xD2">0x00</mapping> <!-- Undefined -->
235 <mapping sourceId="0xD3">0x00</mapping> <!-- Undefined -->
236 <mapping sourceId="0xD4">0x60</mapping> <!-- Music/Ballet/Dance -->
237 <mapping sourceId="0xD5">0x00</mapping> <!-- Undefined -->
238 <mapping sourceId="0xD6">0x00</mapping> <!-- Undefined -->
239 <mapping sourceId="0xD7">0x00</mapping> <!-- Undefined -->
240 <mapping sourceId="0xD8">0x00</mapping> <!-- Undefined -->
241 <mapping sourceId="0xD9">0x00</mapping> <!-- Undefined -->
242 <mapping sourceId="0xDA">0x00</mapping> <!-- Undefined -->
243 <mapping sourceId="0xDB">0x00</mapping> <!-- Undefined -->
244 <mapping sourceId="0xDC">0x00</mapping> <!-- Undefined -->
245 <mapping sourceId="0xDD">0x00</mapping> <!-- Undefined -->
246 <mapping sourceId="0xDE">0x00</mapping> <!-- Undefined -->
247 <mapping sourceId="0xDF">0x00</mapping> <!-- Undefined -->
248 <mapping sourceId="0xE0">0x30</mapping> <!-- Show/Game Show -->
249 <mapping sourceId="0xE1">0x30</mapping> <!-- Show/Game Show -->
250 <mapping sourceId="0xE2">0x30</mapping> <!-- Show/Game Show -->
251 <mapping sourceId="0xE3">0x30</mapping> <!-- Show/Game Show -->
252 <mapping sourceId="0xE4">0x00</mapping> <!-- Undefined -->
253 <mapping sourceId="0xE5">0x30</mapping> <!-- Show/Game Show -->
254 <mapping sourceId="0xE6">0x30</mapping> <!-- Show/Game Show -->
255 <mapping sourceId="0xE7">0x18</mapping> <!-- Adult Movie/Drama -->
256 <mapping sourceId="0xE8">0x00</mapping> <!-- Undefined -->
257 <mapping sourceId="0xE9">0x00</mapping> <!-- Undefined -->
258 <mapping sourceId="0xEA">0x00</mapping> <!-- Undefined -->
259 <mapping sourceId="0xEB">0x00</mapping> <!-- Undefined -->
260 <mapping sourceId="0xEC">0x00</mapping> <!-- Undefined -->
261 <mapping sourceId="0xED">0x00</mapping> <!-- Undefined -->
262 <mapping sourceId="0xEE">0x00</mapping> <!-- Undefined -->
263 <mapping sourceId="0xEF">0x00</mapping> <!-- Undefined -->
264 <mapping sourceId="0xF0">0x00</mapping> <!-- Undefined -->
265 <mapping sourceId="0xF1">0x00</mapping> <!-- Undefined -->
266 <mapping sourceId="0xF2">0x00</mapping> <!-- Undefined -->
267 <mapping sourceId="0xF3">0x00</mapping> <!-- Undefined -->
268 <mapping sourceId="0xF4">0x00</mapping> <!-- Undefined -->
269 <mapping sourceId="0xF5">0x00</mapping> <!-- Undefined -->
270 <mapping sourceId="0xF6">0x00</mapping> <!-- Undefined -->
271 <mapping sourceId="0xF7">0x00</mapping> <!-- Undefined -->
272 <mapping sourceId="0xF8">0x00</mapping> <!-- Undefined -->
273 <mapping sourceId="0xF9">0x00</mapping> <!-- Undefined -->
274 <mapping sourceId="0xFA">0x00</mapping> <!-- Undefined -->
275 <mapping sourceId="0xFB">0x00</mapping> <!-- Undefined -->
276 <mapping sourceId="0xFC">0x00</mapping> <!-- Undefined -->
277 <mapping sourceId="0xFD">0x00</mapping> <!-- Undefined -->
278 <mapping sourceId="0xFE">0x00</mapping> <!-- Undefined -->
279 <mapping sourceId="0xFF">0x00</mapping> <!-- Undefined -->
280 </mappings>
281 </genreIdMappings>
0 <!--
1 Note: the first 4 bits is genre and last is sub genre
2
3 Kodi DVB Genres can be found here: usersdata/genres/kodiDVBGenres.xml
4
5 Mapping ID Genres:
6 - The end result is to map to one of the DVB Genres for Kodi PVR.
7 - This enables Kodi PVR to colour the EPG entries accordingly.
8 - Mapping are done of the Hex value of the genre ID.
9 - SourceId is the genre id from the feed.
10 - Mapping element content is the DVB genre ID
11 - If a mapping can't be found it defaults to 0x00 (Undefined). However all possible 256 values detailed below.
12
13 If you are creating yoru own ID mappings make a copy of this file in the same directory so it's not overwritten and start from there.
14
15 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
16
17 If you have changes either create a PR containing the changes or an issue with details at:
18 https://github.com/kodi-pvr/pvr.vuplus
19 -->
20
21 <genreIdMappings>
22 <mapperName>Sky-NZ</mapperName>
23 <mappings>
24 <mapping sourceId="0x00">0x00</mapping> <!-- Undefined -->
25 <mapping sourceId="0x01">0x00</mapping> <!-- Undefined -->
26 <mapping sourceId="0x02">0x00</mapping> <!-- Undefined -->
27 <mapping sourceId="0x03">0x00</mapping> <!-- Undefined -->
28 <mapping sourceId="0x04">0x00</mapping> <!-- Undefined -->
29 <mapping sourceId="0x05">0x00</mapping> <!-- Undefined -->
30 <mapping sourceId="0x06">0x00</mapping> <!-- Undefined -->
31 <mapping sourceId="0x07">0x00</mapping> <!-- Undefined -->
32 <mapping sourceId="0x08">0x00</mapping> <!-- Undefined -->
33 <mapping sourceId="0x09">0x00</mapping> <!-- Undefined -->
34 <mapping sourceId="0x0A">0x00</mapping> <!-- Undefined -->
35 <mapping sourceId="0x0B">0x00</mapping> <!-- Undefined -->
36 <mapping sourceId="0x0C">0x00</mapping> <!-- Undefined -->
37 <mapping sourceId="0x0D">0x00</mapping> <!-- Undefined -->
38 <mapping sourceId="0x0E">0x00</mapping> <!-- Undefined -->
39 <mapping sourceId="0x0F">0x00</mapping> <!-- Undefined -->
40 <mapping sourceId="0x10">0x00</mapping> <!-- Undefined -->
41 <mapping sourceId="0x11">0x00</mapping> <!-- Undefined -->
42 <mapping sourceId="0x12">0x00</mapping> <!-- Undefined -->
43 <mapping sourceId="0x13">0x00</mapping> <!-- Undefined -->
44 <mapping sourceId="0x14">0x00</mapping> <!-- Undefined -->
45 <mapping sourceId="0x15">0x00</mapping> <!-- Undefined -->
46 <mapping sourceId="0x16">0x00</mapping> <!-- Undefined -->
47 <mapping sourceId="0x17">0x00</mapping> <!-- Undefined -->
48 <mapping sourceId="0x18">0x00</mapping> <!-- Undefined -->
49 <mapping sourceId="0x19">0x00</mapping> <!-- Undefined -->
50 <mapping sourceId="0x1A">0x00</mapping> <!-- Undefined -->
51 <mapping sourceId="0x1B">0x00</mapping> <!-- Undefined -->
52 <mapping sourceId="0x1C">0x00</mapping> <!-- Undefined -->
53 <mapping sourceId="0x1D">0x00</mapping> <!-- Undefined -->
54 <mapping sourceId="0x1E">0x00</mapping> <!-- Undefined -->
55 <mapping sourceId="0x1F">0x00</mapping> <!-- Undefined -->
56 <mapping sourceId="0x20">0x10</mapping> <!-- General Movie/Drama -->
57 <mapping sourceId="0x21">0x11</mapping> <!-- Detective/Thriller -->
58 <mapping sourceId="0x22">0x12</mapping> <!-- Adventure/Western/War -->
59 <mapping sourceId="0x23">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
60 <mapping sourceId="0x24">0x14</mapping> <!-- Comedy -->
61 <mapping sourceId="0x25">0x10</mapping> <!-- General Movie/Drama -->
62 <mapping sourceId="0x26">0x16</mapping> <!-- Romance -->
63 <mapping sourceId="0x27">0x17</mapping> <!-- Serious/Classical/Religious/Historical Movie/Drama -->
64 <mapping sourceId="0x28">0x17</mapping> <!-- Serious/Classical/Religious/Historical Movie/Drama -->
65 <mapping sourceId="0x29">0x10</mapping> <!-- General Movie/Drama -->
66 <mapping sourceId="0x2A">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
67 <mapping sourceId="0x2B">0x17</mapping> <!-- Serious/Classical/Religious/Historical Movie/Drama -->
68 <mapping sourceId="0x2C">0x17</mapping> <!-- Serious/Classical/Religious/Historical Movie/Drama -->
69 <mapping sourceId="0x2D">0x17</mapping> <!-- Serious/Classical/Religious/Historical Movie/Drama -->
70 <mapping sourceId="0x2E">0x12</mapping> <!-- Adventure/Western/War -->
71 <mapping sourceId="0x2F">0x10</mapping> <!-- General Movie/Drama -->
72 <mapping sourceId="0x30">0x00</mapping> <!-- Undefined -->
73 <mapping sourceId="0x31">0x00</mapping> <!-- Undefined -->
74 <mapping sourceId="0x32">0x00</mapping> <!-- Undefined -->
75 <mapping sourceId="0x33">0x00</mapping> <!-- Undefined -->
76 <mapping sourceId="0x34">0x00</mapping> <!-- Undefined -->
77 <mapping sourceId="0x35">0x00</mapping> <!-- Undefined -->
78 <mapping sourceId="0x36">0x00</mapping> <!-- Undefined -->
79 <mapping sourceId="0x37">0x00</mapping> <!-- Undefined -->
80 <mapping sourceId="0x38">0x00</mapping> <!-- Undefined -->
81 <mapping sourceId="0x39">0x00</mapping> <!-- Undefined -->
82 <mapping sourceId="0x3A">0x00</mapping> <!-- Undefined -->
83 <mapping sourceId="0x3B">0x00</mapping> <!-- Undefined -->
84 <mapping sourceId="0x3C">0x00</mapping> <!-- Undefined -->
85 <mapping sourceId="0x3D">0x00</mapping> <!-- Undefined -->
86 <mapping sourceId="0x3E">0x00</mapping> <!-- Undefined -->
87 <mapping sourceId="0x3F">0x00</mapping> <!-- Undefined -->
88 <mapping sourceId="0x40">0x20</mapping> <!-- News/Current Affairs -->
89 <mapping sourceId="0x41">0x21</mapping> <!-- News/Weather Report -->
90 <mapping sourceId="0x42">0x22</mapping> <!-- News Magazine -->
91 <mapping sourceId="0x43">0x23</mapping> <!-- Documentary -->
92 <mapping sourceId="0x44">0x24</mapping> <!-- Discussion/Interview/Debate -->
93 <mapping sourceId="0x45">0x90</mapping> <!-- Education/Science/Factual -->
94 <mapping sourceId="0x46">0x23</mapping> <!-- Documentary -->
95 <mapping sourceId="0x47">0x90</mapping> <!-- Education/Science/Factual -->
96 <mapping sourceId="0x48">0x20</mapping> <!-- News/Current Affairs -->
97 <mapping sourceId="0x49">0x91</mapping> <!-- Nature/Animals/Environment -->
98 <mapping sourceId="0x4A">0x73</mapping> <!-- Religion -->
99 <mapping sourceId="0x4B">0x92</mapping> <!-- Technology/Natural Sciences -->
100 <mapping sourceId="0x4C">0x76</mapping> <!-- Film/Cinema -->
101 <mapping sourceId="0x4D">0x94</mapping> <!-- Foreign Countries/Expeditions -->
102 <mapping sourceId="0x4E">0x90</mapping> <!-- Education/Science/Factual -->
103 <mapping sourceId="0x4F">0x20</mapping> <!-- News/Current Affairs -->
104 <mapping sourceId="0x50">0x00</mapping> <!-- Undefined -->
105 <mapping sourceId="0x51">0x00</mapping> <!-- Undefined -->
106 <mapping sourceId="0x52">0x00</mapping> <!-- Undefined -->
107 <mapping sourceId="0x53">0x00</mapping> <!-- Undefined -->
108 <mapping sourceId="0x54">0x00</mapping> <!-- Undefined -->
109 <mapping sourceId="0x55">0x00</mapping> <!-- Undefined -->
110 <mapping sourceId="0x56">0x00</mapping> <!-- Undefined -->
111 <mapping sourceId="0x57">0x00</mapping> <!-- Undefined -->
112 <mapping sourceId="0x58">0x00</mapping> <!-- Undefined -->
113 <mapping sourceId="0x59">0x00</mapping> <!-- Undefined -->
114 <mapping sourceId="0x5A">0x00</mapping> <!-- Undefined -->
115 <mapping sourceId="0x5B">0x00</mapping> <!-- Undefined -->
116 <mapping sourceId="0x5C">0x00</mapping> <!-- Undefined -->
117 <mapping sourceId="0x5D">0x00</mapping> <!-- Undefined -->
118 <mapping sourceId="0x5E">0x00</mapping> <!-- Undefined -->
119 <mapping sourceId="0x5F">0x00</mapping> <!-- Undefined -->
120 <mapping sourceId="0x60">0x30</mapping> <!-- Show/Game Show -->
121 <mapping sourceId="0x61">0x31</mapping> <!-- Game Show/Quiz/Contest -->
122 <mapping sourceId="0x62">0x33</mapping> <!-- Talk Show -->
123 <mapping sourceId="0x63">0x33</mapping> <!-- Talk Show -->
124 <mapping sourceId="0x64">0x30</mapping> <!-- Show/Game Show -->
125 <mapping sourceId="0x65">0x30</mapping> <!-- Show/Game Show -->
126 <mapping sourceId="0x66">0x30</mapping> <!-- Show/Game Show -->
127 <mapping sourceId="0x67">0x30</mapping> <!-- Show/Game Show -->
128 <mapping sourceId="0x68">0x30</mapping> <!-- Show/Game Show -->
129 <mapping sourceId="0x69">0x30</mapping> <!-- Show/Game Show -->
130 <mapping sourceId="0x6A">0x30</mapping> <!-- Show/Game Show -->
131 <mapping sourceId="0x6B">0x30</mapping> <!-- Show/Game Show -->
132 <mapping sourceId="0x6C">0x31</mapping> <!-- Game Show/Quiz/Contest -->
133 <mapping sourceId="0x6D">0x30</mapping> <!-- Show/Game Show -->
134 <mapping sourceId="0x6E">0x33</mapping> <!-- Talk Show -->
135 <mapping sourceId="0x6F">0x32</mapping> <!-- Variety Show -->
136 <mapping sourceId="0x70">0x00</mapping> <!-- Undefined -->
137 <mapping sourceId="0x71">0x00</mapping> <!-- Undefined -->
138 <mapping sourceId="0x72">0x00</mapping> <!-- Undefined -->
139 <mapping sourceId="0x73">0x00</mapping> <!-- Undefined -->
140 <mapping sourceId="0x74">0x00</mapping> <!-- Undefined -->
141 <mapping sourceId="0x75">0x00</mapping> <!-- Undefined -->
142 <mapping sourceId="0x76">0x00</mapping> <!-- Undefined -->
143 <mapping sourceId="0x77">0x00</mapping> <!-- Undefined -->
144 <mapping sourceId="0x78">0x00</mapping> <!-- Undefined -->
145 <mapping sourceId="0x79">0x00</mapping> <!-- Undefined -->
146 <mapping sourceId="0x7A">0x00</mapping> <!-- Undefined -->
147 <mapping sourceId="0x7B">0x00</mapping> <!-- Undefined -->
148 <mapping sourceId="0x7C">0x00</mapping> <!-- Undefined -->
149 <mapping sourceId="0x7D">0x00</mapping> <!-- Undefined -->
150 <mapping sourceId="0x7E">0x00</mapping> <!-- Undefined -->
151 <mapping sourceId="0x7F">0x00</mapping> <!-- Undefined -->
152 <mapping sourceId="0x80">0x40</mapping> <!-- Sports -->
153 <mapping sourceId="0x81">0x41</mapping> <!-- Special Event -->
154 <mapping sourceId="0x82">0x42</mapping> <!-- Sport Magazine -->
155 <mapping sourceId="0x83">0x43</mapping> <!-- Football -->
156 <mapping sourceId="0x84">0x44</mapping> <!-- Tennis/Squash -->
157 <mapping sourceId="0x85">0x45</mapping> <!-- Team Sports -->
158 <mapping sourceId="0x86">0x46</mapping> <!-- Athletics -->
159 <mapping sourceId="0x87">0x47</mapping> <!-- Motor Sport -->
160 <mapping sourceId="0x88">0x48</mapping> <!-- Water Sport -->
161 <mapping sourceId="0x89">0x49</mapping> <!-- Winter Sports -->
162 <mapping sourceId="0x8A">0x4A</mapping> <!-- Equestrian -->
163 <mapping sourceId="0x8B">0x4B</mapping> <!-- Martial Sports -->
164 <mapping sourceId="0x8C">0x45</mapping> <!-- Team Sports -->
165 <mapping sourceId="0x8D">0x40</mapping> <!-- Sports -->
166 <mapping sourceId="0x8E">0x40</mapping> <!-- Sports -->
167 <mapping sourceId="0x8F">0x40</mapping> <!-- Sports -->
168 <mapping sourceId="0x90">0x00</mapping> <!-- Undefined -->
169 <mapping sourceId="0x91">0x00</mapping> <!-- Undefined -->
170 <mapping sourceId="0x92">0x00</mapping> <!-- Undefined -->
171 <mapping sourceId="0x93">0x00</mapping> <!-- Undefined -->
172 <mapping sourceId="0x94">0x00</mapping> <!-- Undefined -->
173 <mapping sourceId="0x95">0x00</mapping> <!-- Undefined -->
174 <mapping sourceId="0x96">0x00</mapping> <!-- Undefined -->
175 <mapping sourceId="0x97">0x00</mapping> <!-- Undefined -->
176 <mapping sourceId="0x98">0x00</mapping> <!-- Undefined -->
177 <mapping sourceId="0x99">0x00</mapping> <!-- Undefined -->
178 <mapping sourceId="0x9A">0x00</mapping> <!-- Undefined -->
179 <mapping sourceId="0x9B">0x00</mapping> <!-- Undefined -->
180 <mapping sourceId="0x9C">0x00</mapping> <!-- Undefined -->
181 <mapping sourceId="0x9D">0x00</mapping> <!-- Undefined -->
182 <mapping sourceId="0x9E">0x00</mapping> <!-- Undefined -->
183 <mapping sourceId="0x9F">0x00</mapping> <!-- Undefined -->
184 <mapping sourceId="0xA0">0x50</mapping> <!-- Children's/Youth Programmes -->
185 <mapping sourceId="0xA1">0x51</mapping> <!-- Pre-school Children's Programmes -->
186 <mapping sourceId="0xA2">0x52</mapping> <!-- Entertainment Programmes for 6 to 14 -->
187 <mapping sourceId="0xA3">0x53</mapping> <!-- Entertainment Programmes for 10 to 16 -->
188 <mapping sourceId="0xA4">0x54</mapping> <!-- Informational/Educational/School Programme -->
189 <mapping sourceId="0xA5">0x55</mapping> <!-- Cartoons/Puppets -->
190 <mapping sourceId="0xA6">0x50</mapping> <!-- Children's/Youth Programmes -->
191 <mapping sourceId="0xA7">0x50</mapping> <!-- Children's/Youth Programmes -->
192 <mapping sourceId="0xA8">0x54</mapping> <!-- Informational/Educational/School Programme -->
193 <mapping sourceId="0xA9">0x55</mapping> <!-- Cartoons/Puppets -->
194 <mapping sourceId="0xAA">0x50</mapping> <!-- Children's/Youth Programmes -->
195 <mapping sourceId="0xAB">0x50</mapping> <!-- Children's/Youth Programmes -->
196 <mapping sourceId="0xAC">0x50</mapping> <!-- Children's/Youth Programmes -->
197 <mapping sourceId="0xAD">0x50</mapping> <!-- Children's/Youth Programmes -->
198 <mapping sourceId="0xAE">0x50</mapping> <!-- Children's/Youth Programmes -->
199 <mapping sourceId="0xAF">0x50</mapping> <!-- Children's/Youth Programmes -->
200 <mapping sourceId="0xB0">0x00</mapping> <!-- Undefined -->
201 <mapping sourceId="0xB1">0x00</mapping> <!-- Undefined -->
202 <mapping sourceId="0xB2">0x00</mapping> <!-- Undefined -->
203 <mapping sourceId="0xB3">0x00</mapping> <!-- Undefined -->
204 <mapping sourceId="0xB4">0x00</mapping> <!-- Undefined -->
205 <mapping sourceId="0xB5">0x00</mapping> <!-- Undefined -->
206 <mapping sourceId="0xB6">0x00</mapping> <!-- Undefined -->
207 <mapping sourceId="0xB7">0x00</mapping> <!-- Undefined -->
208 <mapping sourceId="0xB8">0x00</mapping> <!-- Undefined -->
209 <mapping sourceId="0xB9">0x00</mapping> <!-- Undefined -->
210 <mapping sourceId="0xBA">0x00</mapping> <!-- Undefined -->
211 <mapping sourceId="0xBB">0x00</mapping> <!-- Undefined -->
212 <mapping sourceId="0xBC">0x00</mapping> <!-- Undefined -->
213 <mapping sourceId="0xBD">0x00</mapping> <!-- Undefined -->
214 <mapping sourceId="0xBE">0x00</mapping> <!-- Undefined -->
215 <mapping sourceId="0xBF">0x00</mapping> <!-- Undefined -->
216 <mapping sourceId="0xC0">0x60</mapping> <!-- Music/Ballet/Dance -->
217 <mapping sourceId="0xC1">0x61</mapping> <!-- Rock/Pop -->
218 <mapping sourceId="0xC2">0x62</mapping> <!-- Serious/Classical Music -->
219 <mapping sourceId="0xC3">0x63</mapping> <!-- Folk/Traditional Music -->
220 <mapping sourceId="0xC4">0x64</mapping> <!-- Jazz -->
221 <mapping sourceId="0xC5">0x65</mapping> <!-- Musical/Opera -->
222 <mapping sourceId="0xC6">0x66</mapping> <!-- Ballet -->
223 <mapping sourceId="0xC7">0x60</mapping> <!-- Music/Ballet/Dance -->
224 <mapping sourceId="0xC8">0x60</mapping> <!-- Music/Ballet/Dance -->
225 <mapping sourceId="0xC9">0x60</mapping> <!-- Music/Ballet/Dance -->
226 <mapping sourceId="0xCA">0x60</mapping> <!-- Music/Ballet/Dance -->
227 <mapping sourceId="0xCB">0x60</mapping> <!-- Music/Ballet/Dance -->
228 <mapping sourceId="0xCC">0x60</mapping> <!-- Music/Ballet/Dance -->
229 <mapping sourceId="0xCD">0x60</mapping> <!-- Music/Ballet/Dance -->
230 <mapping sourceId="0xCE">0x60</mapping> <!-- Music/Ballet/Dance -->
231 <mapping sourceId="0xCF">0x60</mapping> <!-- Music/Ballet/Dance -->
232 <mapping sourceId="0xD0">0x00</mapping> <!-- Undefined -->
233 <mapping sourceId="0xD1">0x00</mapping> <!-- Undefined -->
234 <mapping sourceId="0xD2">0x00</mapping> <!-- Undefined -->
235 <mapping sourceId="0xD3">0x00</mapping> <!-- Undefined -->
236 <mapping sourceId="0xD4">0x00</mapping> <!-- Undefined -->
237 <mapping sourceId="0xD5">0x00</mapping> <!-- Undefined -->
238 <mapping sourceId="0xD6">0x00</mapping> <!-- Undefined -->
239 <mapping sourceId="0xD7">0x00</mapping> <!-- Undefined -->
240 <mapping sourceId="0xD8">0x00</mapping> <!-- Undefined -->
241 <mapping sourceId="0xD9">0x00</mapping> <!-- Undefined -->
242 <mapping sourceId="0xDA">0x00</mapping> <!-- Undefined -->
243 <mapping sourceId="0xDB">0x00</mapping> <!-- Undefined -->
244 <mapping sourceId="0xDC">0x00</mapping> <!-- Undefined -->
245 <mapping sourceId="0xDD">0x00</mapping> <!-- Undefined -->
246 <mapping sourceId="0xDE">0x00</mapping> <!-- Undefined -->
247 <mapping sourceId="0xDF">0x00</mapping> <!-- Undefined -->
248 <mapping sourceId="0xE0">0x70</mapping> <!-- Arts/Culture -->
249 <mapping sourceId="0xE1">0x71</mapping> <!-- Performing Arts -->
250 <mapping sourceId="0xE2">0x72</mapping> <!-- Fine Arts -->
251 <mapping sourceId="0xE3">0x73</mapping> <!-- Religion -->
252 <mapping sourceId="0xE4">0x74</mapping> <!-- Popular Culture/Traditional Arts -->
253 <mapping sourceId="0xE5">0x75</mapping> <!-- Literature -->
254 <mapping sourceId="0xE6">0x76</mapping> <!-- Film/Cinema -->
255 <mapping sourceId="0xE7">0x77</mapping> <!-- Experimental Film/Video -->
256 <mapping sourceId="0xE8">0x78</mapping> <!-- Broadcasting/Press -->
257 <mapping sourceId="0xE9">0x79</mapping> <!-- New Media -->
258 <mapping sourceId="0xEA">0x7A</mapping> <!-- Arts/Culture Magazines -->
259 <mapping sourceId="0xEB">0x7B</mapping> <!-- Fashion -->
260 <mapping sourceId="0xEC">0x00</mapping> <!-- Undefined -->
261 <mapping sourceId="0xED">0x00</mapping> <!-- Undefined -->
262 <mapping sourceId="0xEE">0x00</mapping> <!-- Undefined -->
263 <mapping sourceId="0xEF">0x70</mapping> <!-- Arts/Culture -->
264 <mapping sourceId="0xF0">0x00</mapping> <!-- Undefined -->
265 <mapping sourceId="0xF1">0x00</mapping> <!-- Undefined -->
266 <mapping sourceId="0xF2">0x00</mapping> <!-- Undefined -->
267 <mapping sourceId="0xF3">0x00</mapping> <!-- Undefined -->
268 <mapping sourceId="0xF4">0x00</mapping> <!-- Undefined -->
269 <mapping sourceId="0xF5">0x00</mapping> <!-- Undefined -->
270 <mapping sourceId="0xF6">0x00</mapping> <!-- Undefined -->
271 <mapping sourceId="0xF7">0x00</mapping> <!-- Undefined -->
272 <mapping sourceId="0xF8">0x00</mapping> <!-- Undefined -->
273 <mapping sourceId="0xF9">0x00</mapping> <!-- Undefined -->
274 <mapping sourceId="0xFA">0x00</mapping> <!-- Undefined -->
275 <mapping sourceId="0xFB">0x00</mapping> <!-- Undefined -->
276 <mapping sourceId="0xFC">0x00</mapping> <!-- Undefined -->
277 <mapping sourceId="0xFD">0x00</mapping> <!-- Undefined -->
278 <mapping sourceId="0xFE">0x00</mapping> <!-- Undefined -->
279 <mapping sourceId="0xFF">0x00</mapping> <!-- Undefined -->
280 </mappings>
281 </genreIdMappings>
0 <!--
1 Note: the first 4 bits is genre and last is sub genre
2
3 Kodi DVB Genres can be found here: usersdata/genres/kodiDVBGenres.xml
4
5 Mapping ID Genres:
6 - The end result is to map to one of the DVB Genres for Kodi PVR.
7 - This enables Kodi PVR to colour the EPG entries accordingly.
8 - Mapping are done of the Hex value of the genre ID.
9 - SourceId is the genre id from the feed.
10 - Mapping element content is the DVB genre ID
11 - If a mapping can't be found it defaults to 0x00 (Undefined). However all possible 256 values detailed below.
12
13 If you are creating yoru own ID mappings make a copy of this file in the same directory so it's not overwritten and start from there.
14
15 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
16
17 If you have changes either create a PR containing the changes or an issue with details at:
18 https://github.com/kodi-pvr/pvr.vuplus
19 -->
20
21 <genreIdMappings>
22 <mapperName>Sky-UK</mapperName>
23 <mappings>
24 <mapping sourceId="0x00">0x00</mapping> <!-- Undefined -->
25 <mapping sourceId="0x01">0x00</mapping> <!-- Undefined -->
26 <mapping sourceId="0x02">0x00</mapping> <!-- Undefined -->
27 <mapping sourceId="0x03">0x00</mapping> <!-- Undefined -->
28 <mapping sourceId="0x04">0x00</mapping> <!-- Undefined -->
29 <mapping sourceId="0x05">0x00</mapping> <!-- Undefined -->
30 <mapping sourceId="0x06">0x00</mapping> <!-- Undefined -->
31 <mapping sourceId="0x07">0x00</mapping> <!-- Undefined -->
32 <mapping sourceId="0x08">0x00</mapping> <!-- Undefined -->
33 <mapping sourceId="0x09">0x00</mapping> <!-- Undefined -->
34 <mapping sourceId="0x0A">0x00</mapping> <!-- Undefined -->
35 <mapping sourceId="0x0B">0x00</mapping> <!-- Undefined -->
36 <mapping sourceId="0x0C">0x00</mapping> <!-- Undefined -->
37 <mapping sourceId="0x0D">0x00</mapping> <!-- Undefined -->
38 <mapping sourceId="0x0E">0x00</mapping> <!-- Undefined -->
39 <mapping sourceId="0x0F">0x00</mapping> <!-- Undefined -->
40 <mapping sourceId="0x10">0x00</mapping> <!-- Undefined -->
41 <mapping sourceId="0x11">0x00</mapping> <!-- Undefined -->
42 <mapping sourceId="0x12">0x00</mapping> <!-- Undefined -->
43 <mapping sourceId="0x13">0x00</mapping> <!-- Undefined -->
44 <mapping sourceId="0x14">0x00</mapping> <!-- Undefined -->
45 <mapping sourceId="0x15">0x00</mapping> <!-- Undefined -->
46 <mapping sourceId="0x16">0x00</mapping> <!-- Undefined -->
47 <mapping sourceId="0x17">0x00</mapping> <!-- Undefined -->
48 <mapping sourceId="0x18">0x00</mapping> <!-- Undefined -->
49 <mapping sourceId="0x19">0x00</mapping> <!-- Undefined -->
50 <mapping sourceId="0x1A">0x00</mapping> <!-- Undefined -->
51 <mapping sourceId="0x1B">0x00</mapping> <!-- Undefined -->
52 <mapping sourceId="0x1C">0x00</mapping> <!-- Undefined -->
53 <mapping sourceId="0x1D">0x00</mapping> <!-- Undefined -->
54 <mapping sourceId="0x1E">0x00</mapping> <!-- Undefined -->
55 <mapping sourceId="0x1F">0x00</mapping> <!-- Undefined -->
56 <mapping sourceId="0x20">0x00</mapping> <!-- Undefined -->
57 <mapping sourceId="0x21">0x00</mapping> <!-- Undefined -->
58 <mapping sourceId="0x22">0x00</mapping> <!-- Undefined -->
59 <mapping sourceId="0x23">0xA6</mapping> <!-- Advertisement/Shopping -->
60 <mapping sourceId="0x24">0x00</mapping> <!-- Undefined -->
61 <mapping sourceId="0x25">0x00</mapping> <!-- Undefined -->
62 <mapping sourceId="0x26">0x00</mapping> <!-- Undefined -->
63 <mapping sourceId="0x27">0x00</mapping> <!-- Undefined -->
64 <mapping sourceId="0x28">0x00</mapping> <!-- Undefined -->
65 <mapping sourceId="0x29">0x00</mapping> <!-- Undefined -->
66 <mapping sourceId="0x2A">0x00</mapping> <!-- Undefined -->
67 <mapping sourceId="0x2B">0x00</mapping> <!-- Undefined -->
68 <mapping sourceId="0x2C">0x00</mapping> <!-- Undefined -->
69 <mapping sourceId="0x2D">0x00</mapping> <!-- Undefined -->
70 <mapping sourceId="0x2E">0x00</mapping> <!-- Undefined -->
71 <mapping sourceId="0x2F">0x00</mapping> <!-- Undefined -->
72 <mapping sourceId="0x30">0x00</mapping> <!-- Undefined -->
73 <mapping sourceId="0x31">0x00</mapping> <!-- Undefined -->
74 <mapping sourceId="0x32">0x00</mapping> <!-- Undefined -->
75 <mapping sourceId="0x33">0x00</mapping> <!-- Undefined -->
76 <mapping sourceId="0x34">0x00</mapping> <!-- Undefined -->
77 <mapping sourceId="0x35">0x00</mapping> <!-- Undefined -->
78 <mapping sourceId="0x36">0x00</mapping> <!-- Undefined -->
79 <mapping sourceId="0x37">0x00</mapping> <!-- Undefined -->
80 <mapping sourceId="0x38">0x00</mapping> <!-- Undefined -->
81 <mapping sourceId="0x39">0x00</mapping> <!-- Undefined -->
82 <mapping sourceId="0x3A">0x00</mapping> <!-- Undefined -->
83 <mapping sourceId="0x3B">0x00</mapping> <!-- Undefined -->
84 <mapping sourceId="0x3C">0x00</mapping> <!-- Undefined -->
85 <mapping sourceId="0x3D">0x00</mapping> <!-- Undefined -->
86 <mapping sourceId="0x3E">0x00</mapping> <!-- Undefined -->
87 <mapping sourceId="0x3F">0x00</mapping> <!-- Undefined -->
88 <mapping sourceId="0x40">0x50</mapping> <!-- Children's/Youth Programmes -->
89 <mapping sourceId="0x41">0x55</mapping> <!-- Cartoons/Puppets -->
90 <mapping sourceId="0x42">0x50</mapping> <!-- Children's/Youth Programmes -->
91 <mapping sourceId="0x43">0x50</mapping> <!-- Children's/Youth Programmes -->
92 <mapping sourceId="0x44">0x54</mapping> <!-- Informational/Educational/School Programme -->
93 <mapping sourceId="0x45">0x51</mapping> <!-- Pre-school Children's Programmes -->
94 <mapping sourceId="0x46">0x54</mapping> <!-- Informational/Educational/School Programme -->
95 <mapping sourceId="0x47">0x50</mapping> <!-- Children's/Youth Programmes -->
96 <mapping sourceId="0x48">0x00</mapping> <!-- Undefined -->
97 <mapping sourceId="0x49">0x00</mapping> <!-- Undefined -->
98 <mapping sourceId="0x4A">0x00</mapping> <!-- Undefined -->
99 <mapping sourceId="0x4B">0x00</mapping> <!-- Undefined -->
100 <mapping sourceId="0x4C">0x00</mapping> <!-- Undefined -->
101 <mapping sourceId="0x4D">0x00</mapping> <!-- Undefined -->
102 <mapping sourceId="0x4E">0x00</mapping> <!-- Undefined -->
103 <mapping sourceId="0x4F">0x00</mapping> <!-- Undefined -->
104 <mapping sourceId="0x50">0x00</mapping> <!-- Undefined -->
105 <mapping sourceId="0x51">0x00</mapping> <!-- Undefined -->
106 <mapping sourceId="0x52">0x00</mapping> <!-- Undefined -->
107 <mapping sourceId="0x53">0x00</mapping> <!-- Undefined -->
108 <mapping sourceId="0x54">0x00</mapping> <!-- Undefined -->
109 <mapping sourceId="0x55">0x00</mapping> <!-- Undefined -->
110 <mapping sourceId="0x56">0x00</mapping> <!-- Undefined -->
111 <mapping sourceId="0x57">0x00</mapping> <!-- Undefined -->
112 <mapping sourceId="0x58">0x00</mapping> <!-- Undefined -->
113 <mapping sourceId="0x59">0x00</mapping> <!-- Undefined -->
114 <mapping sourceId="0x5A">0x00</mapping> <!-- Undefined -->
115 <mapping sourceId="0x5B">0x00</mapping> <!-- Undefined -->
116 <mapping sourceId="0x5C">0x00</mapping> <!-- Undefined -->
117 <mapping sourceId="0x5D">0x00</mapping> <!-- Undefined -->
118 <mapping sourceId="0x5E">0x00</mapping> <!-- Undefined -->
119 <mapping sourceId="0x5F">0x00</mapping> <!-- Undefined -->
120 <mapping sourceId="0x60">0x10</mapping> <!-- General Movie/Drama -->
121 <mapping sourceId="0x61">0x12</mapping> <!-- Adventure/Western/War -->
122 <mapping sourceId="0x62">0x14</mapping> <!-- Comedy -->
123 <mapping sourceId="0x63">0x11</mapping> <!-- Detective/Thriller -->
124 <mapping sourceId="0x64">0x10</mapping> <!-- General Movie/Drama -->
125 <mapping sourceId="0x65">0x31</mapping> <!-- Game Show/Quiz/Contest -->
126 <mapping sourceId="0x66">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
127 <mapping sourceId="0x67">0x15</mapping> <!-- Soap/Melodrama/Folkloric -->
128 <mapping sourceId="0x68">0x10</mapping> <!-- General Movie/Drama -->
129 <mapping sourceId="0x69">0x33</mapping> <!-- Talk Show -->
130 <mapping sourceId="0x6A">0xA5</mapping> <!-- Cooking -->
131 <mapping sourceId="0x6B">0x90</mapping> <!-- Education/Science/Factual -->
132 <mapping sourceId="0x6C">0x7B</mapping> <!-- Fashion -->
133 <mapping sourceId="0x6D">0xA7</mapping> <!-- Gardening -->
134 <mapping sourceId="0x6E">0xA1</mapping> <!-- Tourism/Travel -->
135 <mapping sourceId="0x6F">0x10</mapping> <!-- General Movie/Drama -->
136 <mapping sourceId="0x70">0x70</mapping> <!-- Arts/Culture -->
137 <mapping sourceId="0x71">0xA0</mapping> <!-- Leisure/Hobbies -->
138 <mapping sourceId="0x72">0xA0</mapping> <!-- Leisure/Hobbies -->
139 <mapping sourceId="0x73">0x22</mapping> <!-- News Magazine -->
140 <mapping sourceId="0x74">0x10</mapping> <!-- General Movie/Drama -->
141 <mapping sourceId="0x75">0x24</mapping> <!-- Discussion/Interview/Debate -->
142 <mapping sourceId="0x76">0xA0</mapping> <!-- Leisure/Hobbies -->
143 <mapping sourceId="0x77">0xA3</mapping> <!-- Motoring -->
144 <mapping sourceId="0x78">0x75</mapping> <!-- Film/Cinema -->
145 <mapping sourceId="0x79">0x66</mapping> <!-- Ballet -->
146 <mapping sourceId="0x7A">0x65</mapping> <!-- Musical/Opera -->
147 <mapping sourceId="0x7B">0x00</mapping> <!-- Undefined -->
148 <mapping sourceId="0x7C">0x00</mapping> <!-- Undefined -->
149 <mapping sourceId="0x7D">0x00</mapping> <!-- Undefined -->
150 <mapping sourceId="0x7E">0x00</mapping> <!-- Undefined -->
151 <mapping sourceId="0x7F">0x00</mapping> <!-- Undefined -->
152 <mapping sourceId="0x80">0x60</mapping> <!-- Music/Ballet/Dance -->
153 <mapping sourceId="0x81">0x62</mapping> <!-- Serious/Classical Music -->
154 <mapping sourceId="0x82">0x63</mapping> <!-- Folk/Traditional Music -->
155 <mapping sourceId="0x83">0x60</mapping> <!-- Music/Ballet/Dance -->
156 <mapping sourceId="0x84">0x64</mapping> <!-- Jazz -->
157 <mapping sourceId="0x85">0x65</mapping> <!-- Musical/Opera -->
158 <mapping sourceId="0x86">0x61</mapping> <!-- Rock/Pop -->
159 <mapping sourceId="0x87">0x60</mapping> <!-- Music/Ballet/Dance -->
160 <mapping sourceId="0x88">0x60</mapping> <!-- Music/Ballet/Dance -->
161 <mapping sourceId="0x89">0x60</mapping> <!-- Music/Ballet/Dance -->
162 <mapping sourceId="0x8A">0x60</mapping> <!-- Music/Ballet/Dance -->
163 <mapping sourceId="0x8B">0x60</mapping> <!-- Music/Ballet/Dance -->
164 <mapping sourceId="0x8C">0x60</mapping> <!-- Music/Ballet/Dance -->
165 <mapping sourceId="0x8D">0x00</mapping> <!-- Undefined -->
166 <mapping sourceId="0x8E">0x00</mapping> <!-- Undefined -->
167 <mapping sourceId="0x8F">0x00</mapping> <!-- Undefined -->
168 <mapping sourceId="0x90">0x60</mapping> <!-- Music/Ballet/Dance -->
169 <mapping sourceId="0x91">0x00</mapping> <!-- Undefined -->
170 <mapping sourceId="0x92">0x00</mapping> <!-- Undefined -->
171 <mapping sourceId="0x93">0x00</mapping> <!-- Undefined -->
172 <mapping sourceId="0x94">0x00</mapping> <!-- Undefined -->
173 <mapping sourceId="0x95">0x60</mapping> <!-- Music/Ballet/Dance -->
174 <mapping sourceId="0x96">0x60</mapping> <!-- Music/Ballet/Dance -->
175 <mapping sourceId="0x97">0x60</mapping> <!-- Music/Ballet/Dance -->
176 <mapping sourceId="0x98">0x60</mapping> <!-- Music/Ballet/Dance -->
177 <mapping sourceId="0x99">0x60</mapping> <!-- Music/Ballet/Dance -->
178 <mapping sourceId="0x9A">0x60</mapping> <!-- Music/Ballet/Dance -->
179 <mapping sourceId="0x9B">0x00</mapping> <!-- Undefined -->
180 <mapping sourceId="0x9C">0x00</mapping> <!-- Undefined -->
181 <mapping sourceId="0x9D">0x00</mapping> <!-- Undefined -->
182 <mapping sourceId="0x9E">0x00</mapping> <!-- Undefined -->
183 <mapping sourceId="0x9F">0x00</mapping> <!-- Undefined -->
184 <mapping sourceId="0xA0">0x20</mapping> <!-- News/Current Affairs -->
185 <mapping sourceId="0xA1">0x20</mapping> <!-- News/Current Affairs -->
186 <mapping sourceId="0xA2">0x20</mapping> <!-- News/Current Affairs -->
187 <mapping sourceId="0xA3">0x20</mapping> <!-- News/Current Affairs -->
188 <mapping sourceId="0xA4">0x83</mapping> <!-- Remarkable People -->
189 <mapping sourceId="0xA5">0x90</mapping> <!-- Education/Science/Factual -->
190 <mapping sourceId="0xA6">0x20</mapping> <!-- News/Current Affairs -->
191 <mapping sourceId="0xA7">0x80</mapping> <!-- Social/Political/Economics -->
192 <mapping sourceId="0xA8">0x20</mapping> <!-- News/Current Affairs -->
193 <mapping sourceId="0xA9">0x20</mapping> <!-- News/Current Affairs -->
194 <mapping sourceId="0xAA">0x20</mapping> <!-- News/Current Affairs -->
195 <mapping sourceId="0xAB">0x20</mapping> <!-- News/Current Affairs -->
196 <mapping sourceId="0xAC">0x20</mapping> <!-- News/Current Affairs -->
197 <mapping sourceId="0xAD">0x20</mapping> <!-- News/Current Affairs -->
198 <mapping sourceId="0xAE">0x20</mapping> <!-- News/Current Affairs -->
199 <mapping sourceId="0xAF">0x20</mapping> <!-- News/Current Affairs -->
200 <mapping sourceId="0xB0">0x20</mapping> <!-- News/Current Affairs -->
201 <mapping sourceId="0xB1">0x20</mapping> <!-- News/Current Affairs -->
202 <mapping sourceId="0xB2">0x20</mapping> <!-- News/Current Affairs -->
203 <mapping sourceId="0xB3">0x00</mapping> <!-- Undefined -->
204 <mapping sourceId="0xB4">0x00</mapping> <!-- Undefined -->
205 <mapping sourceId="0xB5">0x00</mapping> <!-- Undefined -->
206 <mapping sourceId="0xB6">0x00</mapping> <!-- Undefined -->
207 <mapping sourceId="0xB7">0x00</mapping> <!-- Undefined -->
208 <mapping sourceId="0xB8">0x00</mapping> <!-- Undefined -->
209 <mapping sourceId="0xB9">0x00</mapping> <!-- Undefined -->
210 <mapping sourceId="0xBA">0x00</mapping> <!-- Undefined -->
211 <mapping sourceId="0xBB">0x00</mapping> <!-- Undefined -->
212 <mapping sourceId="0xBC">0x00</mapping> <!-- Undefined -->
213 <mapping sourceId="0xBD">0x00</mapping> <!-- Undefined -->
214 <mapping sourceId="0xBE">0x00</mapping> <!-- Undefined -->
215 <mapping sourceId="0xBF">0x00</mapping> <!-- Undefined -->
216 <mapping sourceId="0xC0">0x10</mapping> <!-- General Movie/Drama -->
217 <mapping sourceId="0xC1">0x12</mapping> <!-- Adventure/Western/War -->
218 <mapping sourceId="0xC2">0x10</mapping> <!-- General Movie/Drama -->
219 <mapping sourceId="0xC3">0x10</mapping> <!-- General Movie/Drama -->
220 <mapping sourceId="0xC4">0x14</mapping> <!-- Comedy -->
221 <mapping sourceId="0xC5">0x10</mapping> <!-- General Movie/Drama -->
222 <mapping sourceId="0xC6">0x10</mapping> <!-- General Movie/Drama -->
223 <mapping sourceId="0xC7">0x10</mapping> <!-- General Movie/Drama -->
224 <mapping sourceId="0xC8">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
225 <mapping sourceId="0xC9">0x11</mapping> <!-- Detective/Thriller -->
226 <mapping sourceId="0xCA">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
227 <mapping sourceId="0xCB">0x16</mapping> <!-- Undefined -->
228 <mapping sourceId="0xCC">0x10</mapping> <!-- General Movie/Drama -->
229 <mapping sourceId="0xCD">0x10</mapping> <!-- General Movie/Drama -->
230 <mapping sourceId="0xCE">0x12</mapping> <!-- Adventure/Western/War -->
231 <mapping sourceId="0xCF">0x17</mapping> <!-- Serious/Classical/Religious/Historical Movie/Drama -->
232 <mapping sourceId="0xD0">0x13</mapping> <!-- Science Fiction/Fantasy/Horror -->
233 <mapping sourceId="0xD1">0x18</mapping> <!-- Adult Movie/Drama -->
234 <mapping sourceId="0xD2">0x12</mapping> <!-- Adventure/Western/War -->
235 <mapping sourceId="0xD3">0x00</mapping> <!-- Undefined -->
236 <mapping sourceId="0xD4">0x00</mapping> <!-- Undefined -->
237 <mapping sourceId="0xD5">0x00</mapping> <!-- Undefined -->
238 <mapping sourceId="0xD6">0x00</mapping> <!-- Undefined -->
239 <mapping sourceId="0xD7">0x00</mapping> <!-- Undefined -->
240 <mapping sourceId="0xD8">0x00</mapping> <!-- Undefined -->
241 <mapping sourceId="0xD9">0x00</mapping> <!-- Undefined -->
242 <mapping sourceId="0xDA">0x00</mapping> <!-- Undefined -->
243 <mapping sourceId="0xDB">0x00</mapping> <!-- Undefined -->
244 <mapping sourceId="0xDC">0x00</mapping> <!-- Undefined -->
245 <mapping sourceId="0xDD">0x00</mapping> <!-- Undefined -->
246 <mapping sourceId="0xDE">0x00</mapping> <!-- Undefined -->
247 <mapping sourceId="0xDF">0x00</mapping> <!-- Undefined -->
248 <mapping sourceId="0xE0">0x40</mapping> <!-- Sports -->
249 <mapping sourceId="0xE1">0x45</mapping> <!-- Team Sports -->
250 <mapping sourceId="0xE2">0x46</mapping> <!-- Athletics -->
251 <mapping sourceId="0xE3">0x45</mapping> <!-- Team Sports -->
252 <mapping sourceId="0xE4">0x45</mapping> <!-- Team Sports -->
253 <mapping sourceId="0xE5">0x40</mapping> <!-- Sports -->
254 <mapping sourceId="0xE6">0x45</mapping> <!-- Team Sports -->
255 <mapping sourceId="0xE7">0x40</mapping> <!-- Sports -->
256 <mapping sourceId="0xE8">0x43</mapping> <!-- Football -->
257 <mapping sourceId="0xE9">0x40</mapping> <!-- Sports -->
258 <mapping sourceId="0xEA">0x45</mapping> <!-- Team Sports -->
259 <mapping sourceId="0xEB">0x47</mapping> <!-- Motor Sport -->
260 <mapping sourceId="0xEC">0x4A</mapping> <!-- Equestrian -->
261 <mapping sourceId="0xED">0x45</mapping> <!-- Team Sports -->
262 <mapping sourceId="0xEE">0x4A</mapping> <!-- Equestrian -->
263 <mapping sourceId="0xEF">0x49</mapping> <!-- Winter Sports -->
264 <mapping sourceId="0xF0">0x40</mapping> <!-- Sports -->
265 <mapping sourceId="0xF1">0x44</mapping> <!-- Tennis/Squash -->
266 <mapping sourceId="0xF2">0x4B</mapping> <!-- Martial Sports -->
267 <mapping sourceId="0xF3">0x40</mapping> <!-- Sports -->
268 <mapping sourceId="0xF4">0x40</mapping> <!-- Sports -->
269 <mapping sourceId="0xF5">0x40</mapping> <!-- Sports -->
270 <mapping sourceId="0xF6">0x00</mapping> <!-- Undefined -->
271 <mapping sourceId="0xF7">0x00</mapping> <!-- Undefined -->
272 <mapping sourceId="0xF8">0x00</mapping> <!-- Undefined -->
273 <mapping sourceId="0xF9">0x00</mapping> <!-- Undefined -->
274 <mapping sourceId="0xFA">0x00</mapping> <!-- Undefined -->
275 <mapping sourceId="0xFB">0x00</mapping> <!-- Undefined -->
276 <mapping sourceId="0xFC">0x00</mapping> <!-- Undefined -->
277 <mapping sourceId="0xFD">0x00</mapping> <!-- Undefined -->
278 <mapping sourceId="0xFE">0x00</mapping> <!-- Undefined -->
279 <mapping sourceId="0xFF">0x00</mapping> <!-- Undefined -->
280 </mappings>
281 </genreIdMappings>
0 <!--
1 Note: the first 4 bits is genre and last is sub genre
2
3 Kodi DVB Genres can be found here: usersdata/genres/kodiDVBGenres.xml
4
5 Mapping Rytec Text Genres:
6 - The end result is to map to one of the DVB Genres for Kodi PVR.
7 - This enables Kodi PVR to colour the EPG entries accordingly.
8 - If a mapping cannot be found the text will be used but there will be no colouring (Genre Description only)
9 - All text will be matched in lowercase
10 - The rytec mapper will look for text between square brackets ([...]) to use for the mapping
11 - The rytec mapper will attempt to match the entire genre string, if that fails it will try to match up to the
12 first dot (this would limit the mapping to 0x10, 0x20, 0x30 etc, but is better than no mapping at all)
13 e.g. if "TV Drama. Melodrama" cannot be found it will look for "TV Drama" and use it's mapping.
14 - If a mapping can't be found it defaults to 0x00 (Undefined)
15
16 If you are creating yoru own text mappings make a copy of this file in the same directory so it's not overwritten and start from there.
17
18 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
19
20 If you have changes either create a PR containing the changes or an issue with details at:
21 https://github.com/kodi-pvr/pvr.vuplus
22 -->
23
24 <genreTextMappings>
25 <mapperName>Rytec UK/Ireland</mapperName>
26 <mappings>
27 <!-- MOVIE/DRAMA -->
28 <mapping targetId="0x10">General Movie/Drama</mapping> <!-- 0x10 Movie/Drama -->
29 <mapping targetId="0x10">Film</mapping> <!-- 0x10 Movie/Drama -->
30 <mapping targetId="0x10">Animated Movie/Drama</mapping> <!-- 0x10 Movie/Drama -->
31 <mapping targetId="0x11">Thriller</mapping> <!-- 0x11 Detective/Thriller -->
32 <mapping targetId="0x11">Detective/Thriller</mapping> <!-- 0x11 Detective/Thriller -->
33 <mapping targetId="0x12">Action</mapping> <!-- 0x12 Adventure/Western/War -->
34 <mapping targetId="0x12">Adventure</mapping> <!-- 0x12 Adventure/Western/War -->
35 <mapping targetId="0x12">Adventure/War</mapping> <!-- 0x12 Adventure/Western/War -->
36 <mapping targetId="0x12">Western</mapping> <!-- 0x12 Adventure/Western/War -->
37 <mapping targetId="0x12">Gangster</mapping> <!-- 0x12 Adventure/Western/War -->
38 <mapping targetId="0x13">Fantasy</mapping> <!-- 0x13 Science Fiction/Fantasy/Horror -->
39 <mapping targetId="0x13">Science Fiction</mapping> <!-- 0x13 Science Fiction/Fantasy/Horror -->
40 <mapping targetId="0x14">Family</mapping> <!-- 0x14 Comedy -->
41 <mapping targetId="0x14">Sitcom</mapping> <!-- 0x14 Comedy -->
42 <mapping targetId="0x14">Comedy</mapping> <!-- 0x14 Comedy -->
43 <mapping targetId="0x14">TV Drama. Comedy</mapping> <!-- 0x14 Comedy -->
44 <mapping targetId="0x15">Drama</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
45 <mapping targetId="0x15">Soap/Melodrama/Folkloric</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
46 <mapping targetId="0x15">TV Drama</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
47 <mapping targetId="0x15">TV Drama. Melodrama</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
48 <mapping targetId="0x15">TV Drama. Factual</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
49 <mapping targetId="0x15">TV Drama. Crime</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
50 <mapping targetId="0x15">TV Drama. Period</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
51 <mapping targetId="0x15">Medical Drama</mapping> <!-- 0x15 Soap/Melodrama/Folkloric -->
52 <mapping targetId="0x16">Romance</mapping> <!-- 0x16 Romance -->
53 <mapping targetId="0x17">Crime drama</mapping> <!-- 0x17 Serious/Classical/Religious/Historical Movie/Drama -->
54 <mapping targetId="0x17">Historical/Period Drama</mapping> <!-- 0x17 Serious/Classical/Religious/Historical Movie/Drama -->
55 <mapping targetId="0x17">Police/Crime Drama</mapping> <!-- 0x17 Serious/Classical/Religious/Historical Movie/Drama -->
56
57 <!-- NEWS/CURRENT AFFAIRS -->
58 <mapping targetId="0x20">News</mapping> <!-- 0x20 News/Current Affairs -->
59 <mapping targetId="0x20">General News/Current Affairs</mapping> <!-- 0x20 News/Current Affairs -->
60 <mapping targetId="0x23">Documentary</mapping> <!-- 0x23 Documentary -->
61 <mapping targetId="0x23">Documentary. News</mapping> <!-- 0x23 Documentary -->
62 <mapping targetId="0x24">Discussion. News</mapping> <!-- 0x24 Discussion/Interview/Debate -->
63
64 <!-- SHOW -->
65 <mapping targetId="0x30">Series</mapping> <!-- 0x30 Show/Game Show -->
66 <mapping targetId="0x30">Show</mapping> <!-- 0x30 Show/Game Show -->
67 <mapping targetId="0x30">Vets/Pets</mapping> <!-- 0x30 Show/Game Show -->
68 <mapping targetId="0x30">Wildlife</mapping> <!-- 0x30 Show/Game Show -->
69 <mapping targetId="0x30">Property</mapping> <!-- 0x30 Show/Game Show -->
70 <mapping targetId="0x31">General Show/Game Show</mapping> <!-- 0x31 Game Show/Quiz/Contest -->
71 <mapping targetId="0x31">Game Show</mapping> <!-- 0x31 Game Show/Quiz/Contest -->
72 <mapping targetId="0x31">Challenge/Reality Show</mapping> <!-- 0x31 Game Show/Quiz/Contest -->
73 <mapping targetId="0x32">Show. Variety Show</mapping> <!-- 0x32 Game Variety Show -->
74 <mapping targetId="0x32">Variety Show</mapping> <!-- 0x32 Variety Show -->
75 <mapping targetId="0x32">Entertainment</mapping> <!-- 0x32 Variety Show -->
76 <mapping targetId="0x32">Miscellaneous</mapping> <!-- 0x32 Variety Show -->
77 <mapping targetId="0x33">Talk Show</mapping> <!-- 0x33 Talk Show -->
78 <mapping targetId="0x34">Show. Talk Show</mapping> <!-- 0x33 Talk Show -->
79
80 <!-- SPORTS -->
81 <mapping targetId="0x40">Sport</mapping> <!-- 0x40 Sports -->
82 <mapping targetId="0x40">Live/Sport</mapping> <!-- 0x40 Sports -->
83 <mapping targetId="0x40">General Sports</mapping> <!-- 0x40 Sports -->
84 <mapping targetId="0x43">Football. Sports</mapping> <!-- 0x43 Football -->
85 <mapping targetId="0x4B">Martial Sports</mapping> <!-- 0x4B Martial Sports -->
86 <mapping targetId="0x4B">Martial Sports. Sports</mapping> <!-- 0x4B Martial Sports -->
87 <mapping targetId="0x4B">Wrestling</mapping> <!-- 0x4B Martial Sports -->
88
89 <!-- CHILDREN/YOUTH -->
90 <mapping targetId="0x50">Children</mapping> <!-- 0x50 Children's/Youth Programmes -->
91 <mapping targetId="0x50">Educational/Schools Programmes</mapping> <!-- 0x50 Children's/Youth Programmes -->
92 <mapping targetId="0x55">Animation</mapping> <!-- 0x55 Cartoons/Puppets -->
93 <mapping targetId="0x55">Cartoons/Puppets</mapping> <!-- 0x55 Cartoons/Puppets -->
94
95 <!-- //MUSIC/BALLET/DANCE -->
96 <mapping targetId="0x60">Music</mapping> <!-- 0x60 Music/Ballet/Dance -->
97 <mapping targetId="0x60">General Music/Ballet/Dance</mapping> <!-- 0x60 Music/Ballet/Dance -->
98 <mapping targetId="0x63">Music. Folk</mapping> <!-- 0x63 Folk/Traditional Music -->
99 <mapping targetId="0x65">Musical</mapping> <!-- 0x65 Musical/Opera -->
100
101 <!-- //ARTS/CULTURE -->
102 <mapping targetId="0x70">General Arts/Culture</mapping> <!-- 0x70 Arts/Culture -->
103 <mapping targetId="0x70">Arts/Culture</mapping> <!-- 0x70 Arts/Culture -->
104 <mapping targetId="0x72">Arts/Culture. Fine Arts</mapping> <!-- 0x72 Fine Arts -->
105 <mapping targetId="0x73">Religion</mapping> <!-- 0x73 Religion -->
106
107 <!-- SOCIAL/POLITICAL/ECONOMICS -->
108 <mapping targetId="0x80">Social/Political</mapping> <!-- 0x80 Social/Political/Economics -->
109 <mapping targetId="0x83">Social/Political. Famous People</mapping> <!-- 0x83 Remarkable People -->
110
111 <!-- EDUCATIONAL/SCIENCE -->
112 <mapping targetId="0x90">Education</mapping> <!-- 0x90 Education/Science/Factual -->
113 <mapping targetId="0x90">Educational</mapping> <!-- 0x90 Education/Science/Factual -->
114 <mapping targetId="0x90">History"</mapping> <!-- 0x90 Education/Science/Factual -->
115 <mapping targetId="0x90">Factual"</mapping> <!-- 0x90 Education/Science/Factual -->
116 <mapping targetId="0x90">General Education/Science/Factual Topics</mapping> <!-- 0x90 Education/Science/Factual -->
117 <mapping targetId="0x90">Science</mapping> <!-- 0x90 Education/Science/Factual -->
118 <mapping targetId="0x91">Educational. Nature</mapping> <!-- 0x91 Nature/Animals/Environment -->
119 <mapping targetId="0x91">Environment</mapping> <!-- 0x91 Nature/Animals/Environment -->
120 <mapping targetId="0x92">Technology</mapping> <!-- 0x92 Technology/Natural Sciences -->
121 <mapping targetId="0x92">Computers/Internet/Gaming</mapping> <!-- 0x92 Technology/Natural Sciences -->
122
123 <!-- LEISURE/HOBBIES -->
124 <mapping targetId="0xA0">Leisure</mapping> <!-- 0xA0 Leisure/Hobbies -->
125 <mapping targetId="0xA0">Leisure. Lifestyle</mapping> <!-- 0xA0 Leisure/Hobbies -->
126 <mapping targetId="0xA1">Travel</mapping> <!-- 0xA1 Tourism/Travel -->
127 <mapping targetId="0xA4">Health</mapping> <!-- 0xA4 Fitness & Health -->
128 <mapping targetId="0xA4">Leisure. Health</mapping> <!-- 0xA4 Fitness & Health -->
129 <mapping targetId="0xA4">Medicine/Health</mapping> <!-- 0xA4 Fitness & Health -->
130 <mapping targetId="0xA5">Cookery</mapping> <!-- 0xA5 Cooking -->
131 <mapping targetId="0xA5">Leisure. Cooking</mapping> <!-- 0xA5 Cooking -->
132 <mapping targetId="0xA6">Leisure. Shopping</mapping> <!-- 0xA6 Advertisement/Shopping -->
133 <mapping targetId="0xA6">Advertisement/Shopping</mapping> <!-- 0xA6 Advertisement/Shopping -->
134 <mapping targetId="0xA6">Consumer</mapping> <!-- 0xA6 Advertisement/Shopping -->
135 <!-- SPECIAL -->
136
137 <!-- USERDEFINED -->
138 <mapping targetId="0xF1">Factual Crime</mapping> <!-- 0xF1 Detective/Thriller -->
139 </mappings>
140 </genreTextMappings>
0 <!--
1 The following are the DVB Genre Id's used for reference
2
3 Source: https://www.etsi.org/deliver/etsi_en/300400_300499/300468/01.11.01_60/en_300468v011101p.pdf
4 Page 40
5
6 Note: the first 4 bits is genre and last is sub genre
7
8 Mapping DVB Genres:
9 - The content below is both a reference for Genre ID mappings and Rytec Text Mappings
10
11 There shoud be no reason to modify this file unless the DVB standard changes.
12
13 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
14
15 If you have changes either create a PR containing the changes or an issue with details at:
16 https://github.com/kodi-pvr/pvr.vuplus
17 -->
18
19 <genreTextMappings>
20 <mapperName>Rytec UK/Ireland</mapperName>
21 <mappings>
22 <!-- UNDEFINED -->
23
24 <mapping targetId="0x00">Undefined</mapping>
25 <!-- MOVIE/DRAMA -->
26 <mapping targetId="0x10">General Movie/Drama</mapping>
27 <mapping targetId="0x11">Detective/Thriller</mapping>
28 <mapping targetId="0x12">Adventure/Western/War</mapping>
29 <mapping targetId="0x13">Science Fiction/Fantasy/Horror</mapping>
30 <mapping targetId="0x14">Comedy</mapping>
31 <mapping targetId="0x15">Soap/Melodrama/Folkloric</mapping>
32 <mapping targetId="0x16">Romance</mapping>
33 <mapping targetId="0x17">Serious/Classical/Religious/Historical Movie/Drama</mapping>
34 <mapping targetId="0x18">Adult Movie/Drama</mapping>
35
36 <!-- NEWS/CURRENT AFFAIRS -->
37 <mapping targetId="0x20">News/Current Affairs</mapping>
38 <mapping targetId="0x21">News/Weather Report</mapping>
39 <mapping targetId="0x22">News Magazine</mapping>
40 <mapping targetId="0x23">Documentary</mapping>
41 <mapping targetId="0x24">Discussion/Interview/Debate</mapping>
42
43 <!-- SHOW -->
44 <mapping targetId="0x30">Show/Game Show</mapping>
45 <mapping targetId="0x31">Game Show/Quiz/Contest</mapping>
46 <mapping targetId="0x32">Variety Show</mapping>
47 <mapping targetId="0x33">Talk Show</mapping>
48
49 <!-- SPORTS -->
50 <mapping targetId="0x40">Sports</mapping>
51 <mapping targetId="0x41">Special Event</mapping>
52 <mapping targetId="0x42">Sport Magazine</mapping>
53 <mapping targetId="0x43">Football</mapping>
54 <mapping targetId="0x44">Tennis/Squash</mapping>
55 <mapping targetId="0x45">Team Sports</mapping>
56 <mapping targetId="0x46">Athletics</mapping>
57 <mapping targetId="0x47">Motor Sport</mapping>
58 <mapping targetId="0x48">Water Sport</mapping>
59 <mapping targetId="0x49">Winter Sports</mapping>
60 <mapping targetId="0x4A">Equestrian</mapping>
61 <mapping targetId="0x4B">Martial Sports</mapping>
62
63 <!-- CHILDREN/YOUTH -->
64 <mapping targetId="0x50">Children's/Youth Programmes</mapping>
65 <mapping targetId="0x51">Pre-school Children's Programmes</mapping>
66 <mapping targetId="0x52">Entertainment Programmes for 6 to 14</mapping>
67 <mapping targetId="0x53">Entertainment Programmes for 10 to 16</mapping>
68 <mapping targetId="0x54">Informational/Educational/School Programme</mapping>
69 <mapping targetId="0x55">Cartoons/Puppets</mapping>
70
71 <!-- MUSIC/BALLET/DANCE -->
72 <mapping targetId="0x60">Music/Ballet/Dance</mapping>
73 <mapping targetId="0x61">Rock/Pop</mapping>
74 <mapping targetId="0x62">Serious/Classical Music</mapping>
75 <mapping targetId="0x63">Folk/Traditional Music</mapping>
76 <mapping targetId="0x64">Jazz</mapping>
77 <mapping targetId="0x65">Musical/Opera</mapping>
78 <mapping targetId="0x66">Ballet</mapping>
79
80 <!-- ARTS/CULTURE -->
81 <mapping targetId="0x70">Arts/Culture</mapping>
82 <mapping targetId="0x71">Performing Arts</mapping>
83 <mapping targetId="0x72">Fine Arts</mapping>
84 <mapping targetId="0x73">Religion</mapping>
85 <mapping targetId="0x74">Popular Culture/Traditional Arts</mapping>
86 <mapping targetId="0x75">Literature</mapping>
87 <mapping targetId="0x76">Film/Cinema</mapping>
88 <mapping targetId="0x77">Experimental Film/Video</mapping>
89 <mapping targetId="0x78">Broadcasting/Press</mapping>
90 <mapping targetId="0x79">New Media</mapping>
91 <mapping targetId="0x7A">Arts/Culture Magazines</mapping>
92 <mapping targetId="0x7B">Fashion</mapping>
93
94 <!-- SOCIAL/POLITICAL/ECONOMICS -->
95 <mapping targetId="0x80">Social/Political/Economics</mapping>
96 <mapping targetId="0x81">Magazines/Reports/Documentary</mapping>
97 <mapping targetId="0x82">Economics/Social Advisory</mapping>
98 <mapping targetId="0x83">Remarkable People</mapping>
99
100 <!-- EDUCATIONAL/SCIENCE -->
101 <mapping targetId="0x90">Education/Science/Factual</mapping>
102 <mapping targetId="0x91">Nature/Animals/Environment</mapping>
103 <mapping targetId="0x92">Technology/Natural Sciences</mapping>
104 <mapping targetId="0x93">Medicine/Physiology/Psychology</mapping>
105 <mapping targetId="0x94">Foreign Countries/Expeditions</mapping>
106 <mapping targetId="0x95">Social/Spiritual Sciences</mapping>
107 <mapping targetId="0x96">Further Education</mapping>
108 <mapping targetId="0x97">Languages</mapping>
109
110 <!-- LEISURE/HOBBIES -->
111 <mapping targetId="0xA0">Leisure/Hobbies</mapping>
112 <mapping targetId="0xA1">Tourism/Travel</mapping>
113 <mapping targetId="0xA2">Handicraft</mapping>
114 <mapping targetId="0xA3">Motoring</mapping>
115 <mapping targetId="0xA4">Fitness &amp; Health</mapping>
116 <mapping targetId="0xA5">Cooking</mapping>
117 <mapping targetId="0xA6">Advertisement/Shopping</mapping>
118 <mapping targetId="0xA7">Gardening</mapping>
119
120 <!-- SPECIAL -->
121 <mapping targetId="0xB0">Special Characteristics</mapping>
122 <mapping targetId="0xB1">Original Language</mapping>
123 <mapping targetId="0xB2">Black &amp; White</mapping>
124 <mapping targetId="0xB3">Unpublished</mapping>
125 <mapping targetId="0xB4">Live Broadcast</mapping>
126
127 <!-- USERDEFINED -->
128 <mapping targetId="0xF0">Drama</mapping>
129 <mapping targetId="0xF1">Detective/Thriller</mapping>
130 <mapping targetId="0xF2">Adventure/Western/War</mapping>
131 <mapping targetId="0xF3">Science Fiction/Fantasy/Horror</mapping>
132 <!-- below currently ignored by XBMC see http://trac.xbmc.org/ticket/13627 -->
133 <mapping targetId="0xF4">Comedy</mapping>
134 <mapping targetId="0xF5">Soap/Melodrama/Folkloric</mapping>
135 <mapping targetId="0xF6">Romance</mapping>
136 <mapping targetId="0xF7">Serious/ClassicalReligion/Historical</mapping>
137 <mapping targetId="0xF8">Adult</mapping>
138 </mappings>
139 </genreTextMappings>
0 <!--
1
2 <name> element
3 - This must exist, and only once
4
5 <seasonEpisode> elements
6 - This element must have a master and episode element, the season element is optional. All elements must have a pattern attribute and cannot be empty
7 - There is no limit to the number of <seasonEpisode> elements but there must be at least one.
8
9 <year> elements
10 - This element must have a pattern attrbute.
11 - There is no limit to the number of <year> elements but there must be at least one.
12
13 If you are creating yoru own patterns make a copy of this file in the same directory so it's not overwritten.
14
15 NOTE: IF YOU MODIFY THIS FILE IT WILL BE OVERWRITTEN NEXT TIME THE ADDON IS STARTED
16
17 If you have changes either create a PR containing the changes or an issue with details at:
18 https://github.com/kodi-pvr/pvr.vuplus
19 -->
20
21 <showInfo>
22 <name>English Show Info</name>
23 <seasonEpisodes>
24 <!-- (S4E37) (S04E37) (S2 Ep3/6) (S2 Ep7) (S2 Ep 3) -->
25 <seasonEpisode>
26 <master pattern="(?:^|.* )\(?([sS]\.?[0-9]+ ?[eE][pP]?\.? ?[0-9]+/?[0-9]*)\)?[^]*$"/>
27 <season pattern="^.*[sS]\.?([0-9][0-9]*).*$"/>
28 <episode pattern="^.*[eE][pP]?\.? ?([0-9][0-9]*).*$"/>
29 </seasonEpisode>
30 <!-- (E130) (Ep10) (E7/9) (Ep7/10) (Ep.25) (Ep 11)-->
31 <seasonEpisode>
32 <master pattern="(?:^|.* )\(?([eE][pP]?\.? ?[0-9]+/?[0-9]*)\)?[^]*$"/>
33 <episode pattern="^.*[eE][pP]?\.? ?([0-9][0-9]*).*$"/>
34 </seasonEpisode>
35 <!-- (2015E22) (2007E3) (2007E3/6) -->
36 <seasonEpisode>
37 <master pattern="(?:^|.* )\(?([12][0-9][0-9][0-9][eE][pP]?\.?[0-9]+\.?/?[0-9]*)\)?[^]*$"/>
38 <episode pattern="^.*[eE][pP]?\.?([0-9][0-9]*).*$"/>
39 </seasonEpisode>
40 <!-- 2/4. 6/6, no prefix -->
41 <seasonEpisode>
42 <master pattern="(?:^|.* )([0-9]+/[0-9]+)(?:(?:\.| )[^]*|$)"/>
43 <episode pattern="^([0-9]+)/[0-9]+"/>
44 </seasonEpisode>
45 </seasonEpisodes>
46 <years>
47 <!-- (2018) -->
48 <year pattern="^.*\(([12][0-9][0-9][0-9])\)[^]*$"/>
49 <!-- (2018E25) -->
50 <year pattern="^.*\(([12][0-9][0-9][0-9])[eE][pP]?\.?[0-9]+/?[0-9]*\)[^]*$"/>
51 </years>
52 </showInfo>
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ gasheernaam of IP adres"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 gasheernaam of IP adres"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Stroom Poort"
23 msgid "Streaming port"
24 msgstr "Stroom poort"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "Wagwoord"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Konneksie"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Ikone"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Reaksie tydverstreke in sekondes"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Ikoon Pad"
47 msgid "Icon path"
48 msgstr "Ikoon pad"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Opdateer Interval"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Opdateer Interval in minute"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatiese Tydhouerlys Skoonmaak"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Automatiese tydhouerlys skoonmaak"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webkoppelvlak Poort"
63 msgid "Web interface port"
64 msgstr "Webkoppelvlak poort"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap voor kanaal verander (d.w.s. vir Enkel Stemmer bokse)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Zap voor kanaal verander (d.w.s. vir enkel stemmer bokse)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Vouer vir kanaal data"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Kyk vir boeket opdaterings"
75 msgid "Update interval"
76 msgstr "Opdateer interval"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Opname vouer op die ontvanger"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Stuur Diep Bystand bevel"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Stuur kragtoestand modus met byvoegsel uit gaan"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Gaan haal slegs een TV boeket"
115 msgid "TV bouquet fetch mode"
116 msgstr "TV boeket gaan haal modus"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Boeket"
119 msgid "TV bouquet"
120 msgstr "TV boeket"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Gaan haal picons vanaf webkoppelvlak"
123 msgid "Fetch picons from web interface"
124 msgstr "Gaan haal picons vanaf web koppelvlak"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Gebruik Secure HTTP (HTTPS)"
127 msgid "Use secure HTTP (https)"
128 msgstr "Gebruik secure HTTP (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Stel outomatiese konfigurasie in staat vir lewendige strome"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Behou gids struktuur vir rekords"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Seisoene en Episodes"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Onttrek seisoen, episode en jaar inligting waar moontlik"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Stel outotydhouers in staat"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Gebruik picons.eu lêer formaat"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Stel genereer herhaal tydhouers in staat"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Log ontbrekende genre teks karterings"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Webkoppelvlak"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Stroom"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Plaas oorsig (bv. onderskrif) voor plot"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Stroom lees stuk grootte"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Nooit"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Slegs in EPG"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Slegs in opnames"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Altyd"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Onttrek vertoning inligting lêer"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Rytec genre teks karterings"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Stel Rytec genre teks karterings in staat"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Rytec genre teks karterings lêer"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Pasgemaakte lewendige TV tydverstreke (0 om verstek te gebruik)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Teken in"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Diverse"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Genre ID Karterings"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Stel genre ID Karterings in staat"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Genre ID karterings lêer"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Radio boeket gaan haal modus"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Radio boeket"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Tydskuif"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Stel tydskuif in staat"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Tydskuif buffer pad"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Af"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Met terugspeel"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Met pouseer"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Gebruik secure HTTP (https) vir strome"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Gebruik inteken vir strome"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Gaan haal TV gunstelinge boeket"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Gaan haal radio gunstelinge boeket"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Opnames & Tydhouers"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Opnames"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Tydhouers"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Hoeveelheid herhaal tydhouers om te genereer"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Alle boekette"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Slegs een boeket"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "As eerste boeket"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "As laaste boeket"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Gunstelinge groep"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Gunstelinge (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Gunstelinge (Radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "onbekend"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Nie gekonnekteer!)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "byvoegsel fout"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Enigma2 Media Bediener"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Agterkant"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Opname Opstop"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Globale begin opstop"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Globale einde opstop"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Toestel Inligting"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "Weblf weergawe"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "OutoTydhouer etiket in tydhouer etikette"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "OutoTydhouer naam in tydhouer etikette"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "NVT"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Waar"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Vals"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Bystand"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Diep bystand"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Waak, dan bystand"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Opdateer modus"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Tydhouers en opnames"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Slegs tydhouers"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Gebruik OpenWeblf picon pad"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Outomaties"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "Een keer (Geskeduleer deur gids-gebaseerde tydhouer reël)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "Een keer (Geskeduleer deur herhalende tydhouer reël)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Nie in staat gestel"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Neem op as EPG titel verskil"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Neem op as EPG titel en kort beskrywing verskil"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Neem op as EPG titel en alle beskrywings verskil"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "Geherkonnekteer aan '%s'"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "Tydskuif buffer pad bestaan nie"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2: Kon nie web koppelvlak bereik nie"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2: Geen kanale groepe gevind nie"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2: Geen kanale gevind nie"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "የመግቢያ ቃል"
2525
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "ግንኙነት "
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "ምልክቶች "
33
2634 msgctxt "#30007"
2735 msgid "Response timeout in seconds"
2836 msgstr "መመለሻ ጊዜ በ ሰከንዶች"
29
30 msgctxt "#30008"
31 msgid "Icon Path"
32 msgstr "የ ምልክት መንገድ"
3337
3438 msgctxt "#30010"
3539 msgid "Update Interval in minutes"
3842 msgctxt "#30014"
3943 msgid "Folder for channeldata"
4044 msgstr "ፎልደር ለ ጣቢያዎች ዳታ "
45
46 msgctxt "#30015"
47 msgid "Update interval"
48 msgstr "የ ማሻሻያ ክፍተት"
4149
4250 msgctxt "#30016"
4351 msgid "Check for channel updates"
6371 msgid "Recordings / Timer"
6472 msgstr "የ መቅረጫ / ሰአት"
6573
74 msgctxt "#30042"
75 msgid "Never"
76 msgstr "በፍጹም "
77
78 msgctxt "#30045"
79 msgid "Always"
80 msgstr "ሁልጊዜ"
81
82 msgctxt "#30051"
83 msgid "Login"
84 msgstr "መግቢያ"
85
86 msgctxt "#30052"
87 msgid "Misc"
88 msgstr "የተለያዩ "
89
90 msgctxt "#30056"
91 msgid "TV"
92 msgstr "ቲቪ "
93
94 msgctxt "#30057"
95 msgid "Radio"
96 msgstr "ራዲዮ "
97
98 msgctxt "#30063"
99 msgid "Off"
100 msgstr "ማጥፊያ "
101
102 msgctxt "#30071"
103 msgid "Recordings"
104 msgstr "መቅረጫ "
105
106 msgctxt "#30072"
107 msgid "Timers"
108 msgstr "መቁጠሪያ"
109
110 msgctxt "#30085"
111 msgid "OK"
112 msgstr "እሺ "
113
114 msgctxt "#30095"
115 msgid "True"
116 msgstr "እውነት"
117
118 msgctxt "#30096"
119 msgid "False"
120 msgstr "ሀሰት"
121
122 msgctxt "#30430"
123 msgid "Disabled"
124 msgstr "ተሰናክሏል "
125
66126 msgctxt "#30500"
67127 msgid "Disconnected from '%s'"
68128 msgstr "ግንኙነት ተቋርጧል ከ '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "كلمة المرور"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "رموز"
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "عام"
3943 msgid "HTTP"
4044 msgstr "HTTP"
4145
46 msgctxt "#30042"
47 msgid "Never"
48 msgstr "أبداً"
49
50 msgctxt "#30045"
51 msgid "Always"
52 msgstr "دائما"
53
54 msgctxt "#30051"
55 msgid "Login"
56 msgstr "تسجيل الدخول"
57
58 msgctxt "#30056"
59 msgid "TV"
60 msgstr "تلفاز"
61
62 msgctxt "#30057"
63 msgid "Radio"
64 msgstr "إذاعة"
65
66 msgctxt "#30063"
67 msgid "Off"
68 msgstr "تعطيل"
69
70 msgctxt "#30071"
71 msgid "Recordings"
72 msgstr "التسجيلات"
73
74 msgctxt "#30085"
75 msgid "OK"
76 msgstr "موافق"
77
78 msgctxt "#30095"
79 msgid "True"
80 msgstr "صحيح"
81
82 msgctxt "#30096"
83 msgid "False"
84 msgstr "خطأ"
85
86 msgctxt "#30430"
87 msgid "Disabled"
88 msgstr "معطلة"
89
4290 msgctxt "#30500"
4391 msgid "Disconnected from '%s'"
4492 msgstr "قطع الاتصال من '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: az_AZ\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
18 msgctxt "#30005"
19 msgid "Connection"
20 msgstr "Qoşulma"
21
22 msgctxt "#30006"
23 msgid "Icons"
24 msgstr "Piktoqramlar"
25
1826 msgctxt "#30018"
1927 msgid "General"
2028 msgstr "Ümumi"
2230 msgctxt "#30019"
2331 msgid "Channels"
2432 msgstr "Kanallar"
33
34 msgctxt "#30045"
35 msgid "Always"
36 msgstr "Həmişə"
37
38 msgctxt "#30056"
39 msgid "TV"
40 msgstr "TV"
41
42 msgctxt "#30085"
43 msgid "OK"
44 msgstr "OK"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: be_BY\n"
1616 "Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname or IP address"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streaming Port"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Username"
3123 msgid "Password"
3224 msgstr "Пароль"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Злучэньне"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Значкі"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Response timeout in seconds"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Icon Path"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Update Interval in minutes"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatic Timerlist Cleanup"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webinterface Port"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap before channelswitch (i.e. for Single Tuner boxes)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Folder for channeldata"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Check for bouquett updates"
47 msgid "Update interval"
48 msgstr "Прамежак паміж абнаўленнямі"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Recording folder on the receiver"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Send DeepStandby-Command"
82 msgctxt "#30042"
83 msgid "Never"
84 msgstr "Ніколі"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Fetch only one TV bouquet"
86 msgctxt "#30045"
87 msgid "Always"
88 msgstr "Заўжды"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30051"
91 msgid "Login"
92 msgstr "Login"
93
94 msgctxt "#30056"
95 msgid "TV"
96 msgstr "ТВ"
97
98 msgctxt "#30057"
99 msgid "Radio"
100 msgstr "Радыё"
101
102 msgctxt "#30063"
103 msgid "Off"
104 msgstr "Не"
105
106 msgctxt "#30071"
107 msgid "Recordings"
108 msgstr "Recordings"
109
110 msgctxt "#30085"
111 msgid "OK"
112 msgstr "Добра"
113
114 msgctxt "#30095"
115 msgid "True"
116 msgstr "True"
117
118 msgctxt "#30096"
119 msgid "False"
120 msgstr "False"
121
122 msgctxt "#30410"
123 msgid "Automatic"
124 msgstr "Аўтаматычна "
125
126 msgctxt "#30430"
127 msgid "Disabled"
128 msgstr "Забаронена"
109129
110130 msgctxt "#30500"
111131 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ хост или IP адрес"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Име на сървър или IP адрес на Enigma2"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Порт за поточно излъчване"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "Парола"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Връзка"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Иконки"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
36 msgstr "Време на изчакване на отговор (секунди)"
44 msgstr "Време на изчакване за отговор (секунди)"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Път до иконите"
47 msgid "Icon path"
48 msgstr "Път до иконките"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Интервал на обновяване"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
44 msgstr "Интервал за обновяване в минути"
56 msgstr "Интервал на обновяване (минути)"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
59 msgid "Automatic timerlist cleanup"
4860 msgstr "Автоматично почистване на броячите"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
63 msgid "Web interface port"
5264 msgstr "Порт на уеб интерфейса"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Нулиране преди превключване на канал (за едно-тунерни устройства)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Нулиране преди превключване на канал (за устройства с един тунер)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
60 msgstr "Папка за данните на канала"
72 msgstr "Папка за данните на каналите"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Провери за обновявания на букетите"
75 msgid "Update interval"
76 msgstr "Интервал на обновление"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
68 msgstr "Проверявай за обновяване на каналите"
80 msgstr "Проверка за промени по каналите"
6981
7082 msgctxt "#30017"
7183 msgid "Use only the DVB boxes' current recording path"
72 msgstr "Ползвай само за запис на зададения в DVB път"
84 msgstr "Използване само на текущия път за запис на устройствата"
7385
7486 msgctxt "#30018"
7587 msgid "General"
96108 msgstr "Папка за записите на приемника"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Изпращай DeepStandby команда"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Изпращане на инф. за режима на захранване при изход на добавката"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Избери само един ТВ букет"
115 msgid "TV bouquet fetch mode"
116 msgstr "Режим на изтегляне на ТВ-букет"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "ТВ букет"
119 msgid "TV bouquet"
120 msgstr "ТВ-букет"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Взимай логото на канала от уеб интерфейса"
123 msgid "Fetch picons from web interface"
124 msgstr "Получаване на логата на каналите от уеб интерфейса"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Ползвай защитена HTTP (https)"
127 msgid "Use secure HTTP (https)"
128 msgstr "Ползване на HTTPS"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Автоматична настройка на потоците на живо"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Запазване на структурата на папките за записите"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Сезони и епизоди"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "Справочник"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Извличане на инф. за сезона, епизода и годината, когато е възможно"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Включване на авт. броячи"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Използване на файловия форма на picons.eu"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Включване на създаването на повтарящи се броячи"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Извеждане на неуспешните текстови съвпадения за липсващи жанрове в журнала"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Уеб интерфейс"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Поточно излъчване"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Показване на резюмето (напр. субтитри) преди сюжета"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Размер на частите на потока за четене"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Никога"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Само в справочника"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Само в записите"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Винаги"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Извличане на файл с инф. за предаването"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Текстови съвпадения на жанровете от Rytec"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Включване на текстовите съвпадения на жанровете от Rytec"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Файл с текстови съвпадения на жанровете от Rytec"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Персонализирано време за изчакване на ТВ на живо (0 = по подразбиране)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Влизане"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Разни"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Съвпадения на ид. на жанровете"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Включване на съвпаденията на ид. на жанровете"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Файл със съвпадения на ид. на жанровете"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "ТЕЛЕВИЗИЯ"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Радио"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Режим на изтегляне на радио-букет"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Радио-букет"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Изместване във времето"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Изместване във времето"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Път до буфера за изместване във времето"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Изкл."
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "При възпроизвеждане"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "На пауза"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Ползване на HTTPS за потоците"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Използване на потребителско име и парола за потоците"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Изтегляне на букет с любими ТВ"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Изтегляне на букет с любими радиа"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Записи и броячи"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Записи"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr " Броячи"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Брой повтарящи се броячи, които да се създадат"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Всички букети"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Само един букет"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "При първия букет"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "При последния букет"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Група от любими"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Любими (ТВ)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Любими (Радио)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "неизвестно"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Няма връзка!)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "грешка в добавката"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Медиен сървър „Enigma2“"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "Добре"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Сървър"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Допълване на записа"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Глобално допълване в началото"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Глобално допълване в края"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Информация за устройството"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "Версия на „WebIf“"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "Етикет за авт. брояч в етикетите на броячите"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "Име на авт. брояч в етикетите на броячите"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "Няма"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Правилно"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Грешно"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Готовност"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Дълбоко състояние на готовност"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Събуждане, след това преминаване в състояние на готовност"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Режим на обновяване"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Броячи и записи"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Само броячи"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Използване на пътя за picon на OpenWebIf"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Автоматично"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "Еднократен (насрочено чрез правило на брояч)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "Еднократен (насрочено чрез правило на повтарящ се брояч)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Изключено"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Запис само, ако заглавието в справочника е различно"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Запис само, ако заглавието и краткото описание в справочника са различни"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Запис само, ако заглавието и всички описания в справочника са различни"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
120 msgstr "Изключен от '%s'"
460 msgstr "Връзката с „%s“ се разпадна"
121461
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124 msgstr "Повторно свързан с '%s'"
464 msgstr "Отново има връзка с „%s“"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "Пътят до буфера за изместване във времето не съществува"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2: Уеб-интерфейсът е недостъпен"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2: Няма намерени групи от канали"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2: Няма намерени канали"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "Lozinka"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Ikone"
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "Opšte"
3438 msgctxt "#30021"
3539 msgid "HTTP"
3640 msgstr "HTTP"
41
42 msgctxt "#30042"
43 msgid "Never"
44 msgstr "Nikada"
45
46 msgctxt "#30045"
47 msgid "Always"
48 msgstr "Uvijek"
49
50 msgctxt "#30056"
51 msgid "TV"
52 msgstr "TV"
53
54 msgctxt "#30057"
55 msgid "Radio"
56 msgstr "Radio"
57
58 msgctxt "#30063"
59 msgid "Off"
60 msgstr "Isklj."
61
62 msgctxt "#30071"
63 msgid "Recordings"
64 msgstr "Snimci"
65
66 msgctxt "#30085"
67 msgid "OK"
68 msgstr "U redu"
69
70 msgctxt "#30095"
71 msgid "True"
72 msgstr "Ispravno"
73
74 msgctxt "#30096"
75 msgid "False"
76 msgstr "Netačno"
77
78 msgctxt "#30430"
79 msgid "Disabled"
80 msgstr "Onemogućeno"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: ca_ES\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nom d'amfitrió o IP de VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Port de la transmissió en línia"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Nom d'usuari"
3123 msgid "Password"
3224 msgstr "Contrasenya"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Connexió"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Icones"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Temps d'expiració de la resposta en segons"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Camí a la icona"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Interval d'actualització en minuts"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Neteja automàtica de Timerlist"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port de la interfície web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap abans de canviar de canal (és a dir, per a les caixes amb solament un sintonitzador)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Carpeta pel canal de dades"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Comprova si hi ha actualitzacions del paquet de TV"
47 msgid "Update interval"
48 msgstr "Interval d'actualització"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Carpeta d'enregistrament en el receptor"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Enviar ordre DeepStandby"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Obté només un paquet de TV"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Mai"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Paquet TV"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "Solament a l'EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Obté els picons des de la interfície web"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Solament als enregistraments"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Utilitza HTTP segur (https)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "Sempre"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Autenticació"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Altres"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "TV"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Ràdio"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Salts en el temps"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Camí a la memòria intermèdia dels salts en el temps"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Apagat"
129
130 msgctxt "#30064"
131 msgid "On playback"
132 msgstr "Amb la reproducció"
133
134 msgctxt "#30065"
135 msgid "On pause"
136 msgstr "Amb la pausa"
137
138 msgctxt "#30071"
139 msgid "Recordings"
140 msgstr "Enregistraments"
141
142 msgctxt "#30072"
143 msgid "Timers"
144 msgstr "Temporitzadors"
145
146 msgctxt "#30085"
147 msgid "OK"
148 msgstr "D'acord"
149
150 msgctxt "#30095"
151 msgid "True"
152 msgstr "Cert"
153
154 msgctxt "#30096"
155 msgid "False"
156 msgstr "Fals"
157
158 msgctxt "#30410"
159 msgid "Automatic"
160 msgstr "Automàtic"
161
162 msgctxt "#30430"
163 msgid "Disabled"
164 msgstr "Inhabilitat"
117165
118166 msgctxt "#30500"
119167 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Název hostitele nebo adresa IP VU+"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Název hostitele nebo IP adresa Enigma2"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Port streamování"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "Heslo"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Spojení"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Ikony"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Časový limit odpovědi v sekundách"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Cesta k ikonám"
47 msgid "Icon path"
48 msgstr "Cesta k ikoně"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Interval aktualizace"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Interval aktualizace v minutách"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
59 msgid "Automatic timerlist cleanup"
4860 msgstr "Automatické čištění seznamu časovačů"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
63 msgid "Web interface port"
5264 msgstr "Port webového rozhraní"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
5668 msgstr "Přepnout před přepnutím kanálu (např. pro jednotunerové přijímače)"
5769
5870 msgctxt "#30014"
6072 msgstr "Složka pro data kanálů"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Kontrolovat aktualizace skupin oblíbených programů"
75 msgid "Update interval"
76 msgstr "Interval aktualizace"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Složka s nahrávkami na přijímači"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Odeslat příkaz úsporného uspání"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Načíst pouze jednu skupinu oblíbených programů"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Při ukončení doplňku poslat režim stavu napájení"
105113
106114 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Skupina oblíbených programů"
115 msgid "TV bouquet"
116 msgstr "TV buket"
109117
110118 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Načíst pikony z webového rozhraní"
119 msgid "Fetch picons from web interface"
120 msgstr "Načíst ikony kanálů z webového rozhraní"
113121
114122 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
123 msgid "Use secure HTTP (https)"
116124 msgstr "Použít zabezpečené HTTP (https)"
125
126 msgctxt "#30029"
127 msgid "Enable automatic configuration for live streams"
128 msgstr "Povolit automatickou konfiguraci pro živé datové proudy"
129
130 msgctxt "#30030"
131 msgid "Keep folder structure for records"
132 msgstr "Zachovat strukturu složky pro nahrávky"
133
134 msgctxt "#30031"
135 msgid "Seasons and Episodes"
136 msgstr "Sezóny a epizody"
137
138 msgctxt "#30032"
139 msgid "EPG"
140 msgstr "Televizní program"
141
142 msgctxt "#30033"
143 msgid "Extract season, episode and year info where possible"
144 msgstr "Extrahovat informaci o sezóně, epizodě a roku, kde je to možné"
145
146 msgctxt "#30034"
147 msgid "Enable autotimers"
148 msgstr "Povolit automatické časovače"
149
150 msgctxt "#30035"
151 msgid "Use picons.eu file format"
152 msgstr "Používat formát souboru picons.eu"
153
154 msgctxt "#30036"
155 msgid "Enable generate repeat timers"
156 msgstr "Povolit generování opakujících se časovačů"
157
158 msgctxt "#30038"
159 msgid "Web Interface"
160 msgstr "Webové rozhraní"
161
162 msgctxt "#30039"
163 msgid "Streaming"
164 msgstr "Streamování"
165
166 msgctxt "#30040"
167 msgid "Put outline (e.g. sub-title) before plot"
168 msgstr "Umístit stručné shrnutí (např. titulky) před obsah děje"
169
170 msgctxt "#30041"
171 msgid "Stream read chunk size"
172 msgstr "Velikost bloku dat čtení streamu"
173
174 msgctxt "#30042"
175 msgid "Never"
176 msgstr "Nikdy"
177
178 msgctxt "#30043"
179 msgid "In EPG only"
180 msgstr "Pouze v televizním programu"
181
182 msgctxt "#30044"
183 msgid "In recordings only"
184 msgstr "Pouze v nahrávkách"
185
186 msgctxt "#30045"
187 msgid "Always"
188 msgstr "Vždy"
189
190 msgctxt "#30050"
191 msgid "Custom live TV timeout (0 to use default)"
192 msgstr "Vlastní časový limit živého vysílání (0 pro použití výchozího)"
193
194 msgctxt "#30051"
195 msgid "Login"
196 msgstr "Přihlášení"
197
198 msgctxt "#30052"
199 msgid "Misc"
200 msgstr "Různé"
201
202 msgctxt "#30053"
203 msgid "Genre ID Mappings"
204 msgstr "Mapování ID žánru"
205
206 msgctxt "#30054"
207 msgid "Enable genre ID Mappings"
208 msgstr "Povolit mapování ID žánru"
209
210 msgctxt "#30055"
211 msgid "Genre ID mappings file"
212 msgstr "Soubor mapování ID žánru"
213
214 msgctxt "#30056"
215 msgid "TV"
216 msgstr "Televize"
217
218 msgctxt "#30057"
219 msgid "Radio"
220 msgstr "Rádio"
221
222 msgctxt "#30059"
223 msgid "Radio bouquet"
224 msgstr "Buket rádií"
225
226 msgctxt "#30060"
227 msgid "Timeshift"
228 msgstr "Časový posun"
229
230 msgctxt "#30061"
231 msgid "Enable timeshift"
232 msgstr "Povolit časový posun"
233
234 msgctxt "#30062"
235 msgid "Timeshift buffer path"
236 msgstr "Cesta k vyrovnávací paměti časového posunu"
237
238 msgctxt "#30063"
239 msgid "Off"
240 msgstr "Vypnout"
241
242 msgctxt "#30064"
243 msgid "On playback"
244 msgstr "Při přehrávání"
245
246 msgctxt "#30065"
247 msgid "On pause"
248 msgstr "Při pozastavení"
249
250 msgctxt "#30066"
251 msgid "Use secure HTTP (https) for streams"
252 msgstr "Použít zabezpečené HTTP (https) pro streamy"
253
254 msgctxt "#30067"
255 msgid "Use login for streams"
256 msgstr "Použít přihlášení pro streamy"
257
258 msgctxt "#30070"
259 msgid "Recordings & Timers"
260 msgstr "Nahrávky a časovače"
261
262 msgctxt "#30071"
263 msgid "Recordings"
264 msgstr "Nahrávky"
265
266 msgctxt "#30072"
267 msgid "Timers"
268 msgstr "Časovače"
269
270 msgctxt "#30073"
271 msgid "Number of repeat timers to generate"
272 msgstr "Počet opakování časovačů ke generování"
273
274 msgctxt "#30074"
275 msgid "All bouquets"
276 msgstr "Všechny bukety"
277
278 msgctxt "#30075"
279 msgid "Only one bouquet"
280 msgstr "Pouze jeden buket"
281
282 msgctxt "#30076"
283 msgid "As first bouquet"
284 msgstr "Jako první buket"
285
286 msgctxt "#30077"
287 msgid "As last bouquet"
288 msgstr "Jako poslední buket"
289
290 msgctxt "#30078"
291 msgid "Favourites group"
292 msgstr "Skupina oblíbených"
293
294 msgctxt "#30079"
295 msgid "Favourites (TV)"
296 msgstr "Oblíbené (TV)"
297
298 msgctxt "#30080"
299 msgid "Favourites (Radio)"
300 msgstr "Oblíbené (rádio)"
301
302 msgctxt "#30081"
303 msgid "unknown"
304 msgstr "neznámé"
305
306 msgctxt "#30082"
307 msgid " (Not connected!)"
308 msgstr "(Nepřipojeno!)"
309
310 msgctxt "#30083"
311 msgid "addon error"
312 msgstr "chyba doplňku"
313
314 msgctxt "#30084"
315 msgid "Enigma2 Media Server"
316 msgstr "Server médií Enigma2"
317
318 msgctxt "#30085"
319 msgid "OK"
320 msgstr "OK"
321
322 msgctxt "#30086"
323 msgid "Backend"
324 msgstr "Podpůrná vrstva"
325
326 msgctxt "#30087"
327 msgid "Recording Padding"
328 msgstr "Zarovnání nahrávání"
329
330 msgctxt "#30088"
331 msgid "Global start padding"
332 msgstr "Globální zarovnání začátku"
333
334 msgctxt "#30089"
335 msgid "Global end padding"
336 msgstr "Globální zarovnání konce"
337
338 msgctxt "#30090"
339 msgid "Device Info"
340 msgstr "Informace o zařízení"
341
342 msgctxt "#30091"
343 msgid "WebIf version"
344 msgstr "Verze WebIf"
345
346 msgctxt "#30092"
347 msgid "AutoTimer tag in timer tags"
348 msgstr "Štítek automatického časovače v štítcích časovačů"
349
350 msgctxt "#30093"
351 msgid "AutoTimer name in timer tags"
352 msgstr "Název automatického časovače v štítcích časovačů"
353
354 msgctxt "#30094"
355 msgid "N/A"
356 msgstr "Nezadáno"
357
358 msgctxt "#30095"
359 msgid "True"
360 msgstr "Pravda"
361
362 msgctxt "#30096"
363 msgid "False"
364 msgstr "Nepravda"
365
366 msgctxt "#30097"
367 msgid "Standby"
368 msgstr "Pohotovostní režim"
369
370 msgctxt "#30098"
371 msgid "Deep standby"
372 msgstr "Pohotovostní režim s nižší spotřebou"
373
374 msgctxt "#30099"
375 msgid "Wakeup, then standby"
376 msgstr "Probudit, pak pohotovostní režim"
377
378 msgctxt "#30100"
379 msgid "Update mode"
380 msgstr "Režim aktualizace"
381
382 msgctxt "#30101"
383 msgid "Timers and recordings"
384 msgstr "Časovače a nahrávání"
385
386 msgctxt "#30102"
387 msgid "Timers only"
388 msgstr "Pouze časovače"
389
390 msgctxt "#30103"
391 msgid "Use OpenWebIf picon path"
392 msgstr "Použij OpenWebIf cestu k pikonám"
393
394 msgctxt "#30410"
395 msgid "Automatic"
396 msgstr "Automatické"
397
398 msgctxt "#30420"
399 msgid "One time (Scheduled by guide-based timer rule)"
400 msgstr "Jednou (Naplánováno pravidlem časovače na základě televizního programu)"
401
402 msgctxt "#30421"
403 msgid "One time (Scheduled by repeating timer rule)"
404 msgstr "Jednou (Naplánováno opakujícím se pravidlem časovače)"
405
406 msgctxt "#30430"
407 msgid "Disabled"
408 msgstr "Zakázáno"
409
410 msgctxt "#30431"
411 msgid "Record if EPG title differs"
412 msgstr "Nahrávat, pokud se liší název televizního programu"
413
414 msgctxt "#30432"
415 msgid "Record if EPG title and short description differs"
416 msgstr "Nahrávat, pokud se liší název a krátký popis televizního programu"
417
418 msgctxt "#30433"
419 msgid "Record if EPG title and all descriptions differ"
420 msgstr "Nahrávat, pokud se liší název a všechny popisy televizního programu"
117421
118422 msgctxt "#30500"
119423 msgid "Disconnected from '%s'"
122426 msgctxt "#30501"
123427 msgid "Reconnected to '%s'"
124428 msgstr "Znovu připojeno k '%s'"
429
430 msgctxt "#30514"
431 msgid "Timeshift buffer path does not exist"
432 msgstr "Cesta k vyrovnávací paměti časového posunu neexistuje"
433
434 msgctxt "#30515"
435 msgid "Enigma2: Could not reach web interface"
436 msgstr "Enigma2: Nemohu se spojit s webovým rozhraním"
437
438 msgctxt "#30516"
439 msgid "Enigma2: No channel groups found"
440 msgstr "Enigma2: Nenalezeny skupiny kanálů"
441
442 msgctxt "#30517"
443 msgid "Enigma2: No channels found"
444 msgstr "Enigma2: Nenalezeny kanály"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: cy_GB\n"
1616 "Plural-Forms: nplurals=4; plural=(n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Enw gwesteiwr neu gyfeiriad IP VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Porth Ffrydio"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Enw defnyddiwr"
3123 msgid "Password"
3224 msgstr "Cyfrinair"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Cysylltiad"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Eiconau"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Ymateb amser allan mewn eiliadau"
37
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Llwybr Eiconau"
4137
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Cyfnod diweddaru mewn munudau"
4541
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Glanhau Amserlen yn Awtomatig"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Porth Rhyngwyneb Gwe"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Sapio cyn newid sianel (h.y. ar gyfer blychau Tiwniwr Unigol)"
57
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Ffolder ar gyfer data sianel"
61
62 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Gwirio am ddiweddariad bouquett"
6545
6646 msgctxt "#30016"
6747 msgid "Check for channel updates"
9575 msgid "Recording folder on the receiver"
9676 msgstr "Ffolder recordio ar y derbynnydd"
9777
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Anfon DeepStandby-Command"
78 msgctxt "#30029"
79 msgid "Enable automatic configuration for live streams"
80 msgstr "Galluogi ffurfweddu awtomatig ar gyfer ffrydio'n fyw"
10181
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Estyn dim ond un bouquet Teledu"
82 msgctxt "#30030"
83 msgid "Keep folder structure for records"
84 msgstr "Cadw strwythur y ffolderi ar gyfer recordiadau"
10585
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Byth"
10989
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Estyn piconau o'r rhyngwyneb gwe"
90 msgctxt "#30045"
91 msgid "Always"
92 msgstr "Bob tro"
11393
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Defnyddiwch HTTP (https) Diogel"
94 msgctxt "#30051"
95 msgid "Login"
96 msgstr "Mewngofnodi"
97
98 msgctxt "#30056"
99 msgid "TV"
100 msgstr "Teledu"
101
102 msgctxt "#30057"
103 msgid "Radio"
104 msgstr "Radio"
105
106 msgctxt "#30062"
107 msgid "Timeshift buffer path"
108 msgstr "Llwybr byffro Symud Amser"
109
110 msgctxt "#30063"
111 msgid "Off"
112 msgstr "Diffodd"
113
114 msgctxt "#30071"
115 msgid "Recordings"
116 msgstr "Recordiadau"
117
118 msgctxt "#30085"
119 msgid "OK"
120 msgstr "Iawn"
121
122 msgctxt "#30094"
123 msgid "N/A"
124 msgstr "Dim ar Gael"
125
126 msgctxt "#30095"
127 msgid "True"
128 msgstr "Gwir"
129
130 msgctxt "#30096"
131 msgid "False"
132 msgstr "Gau"
133
134 msgctxt "#30430"
135 msgid "Disabled"
136 msgstr "Analluogwyd"
117137
118138 msgctxt "#30500"
119139 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: da_DK\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ værtsnavn eller IP-adresse"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streamport"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Brugernavn"
3123 msgid "Password"
3224 msgstr "Adgangskode"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Forbindelse"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikoner"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Tidsfrist for tilbagemelding i sekunder"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Ikon-sti"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Opdateringsinterval i minutter"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatisk oprydning af Timerliste"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Web-grænsefladeport"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap før kanalskift (fx. for enkelttuner-bokse)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Mappe til kanaldata"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Søg efter buketopdateringer"
47 msgid "Update interval"
48 msgstr "Opdateringsinterval"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Optagelsesmappe på modtageren"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Send \"DeepStandby\" kommando"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Hent kun én TV-buket"
86 msgctxt "#30039"
87 msgid "Streaming"
88 msgstr "Streaming"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-buket"
90 msgctxt "#30042"
91 msgid "Never"
92 msgstr "Aldrig"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Hent picons fra webinterfacet"
94 msgctxt "#30043"
95 msgid "In EPG only"
96 msgstr "Kun i EPG"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Brug sikker HTTP (https)"
98 msgctxt "#30044"
99 msgid "In recordings only"
100 msgstr "Kun i optagelser"
101
102 msgctxt "#30045"
103 msgid "Always"
104 msgstr "Altid"
105
106 msgctxt "#30051"
107 msgid "Login"
108 msgstr "Brugernavn"
109
110 msgctxt "#30052"
111 msgid "Misc"
112 msgstr "Diverse"
113
114 msgctxt "#30056"
115 msgid "TV"
116 msgstr "TV"
117
118 msgctxt "#30057"
119 msgid "Radio"
120 msgstr "Radio"
121
122 msgctxt "#30060"
123 msgid "Timeshift"
124 msgstr "Tidsforskydning"
125
126 msgctxt "#30062"
127 msgid "Timeshift buffer path"
128 msgstr "Stien til tidsforskydningsbuffer"
129
130 msgctxt "#30063"
131 msgid "Off"
132 msgstr "Fra"
133
134 msgctxt "#30065"
135 msgid "On pause"
136 msgstr "Sat på pause"
137
138 msgctxt "#30071"
139 msgid "Recordings"
140 msgstr "Optagelser"
141
142 msgctxt "#30072"
143 msgid "Timers"
144 msgstr "Timeroptagelser"
145
146 msgctxt "#30085"
147 msgid "OK"
148 msgstr "OK"
149
150 msgctxt "#30094"
151 msgid "N/A"
152 msgstr "N/A"
153
154 msgctxt "#30095"
155 msgid "True"
156 msgstr "Sandt"
157
158 msgctxt "#30096"
159 msgid "False"
160 msgstr "Falsk"
161
162 msgctxt "#30410"
163 msgid "Automatic"
164 msgstr "Automatisk"
165
166 msgctxt "#30430"
167 msgid "Disabled"
168 msgstr "Deaktiveret"
117169
118170 msgctxt "#30500"
119171 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: de_DE\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ Hostname oder IP-Adresse"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streaming Port"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Benutzername"
3123 msgid "Password"
3224 msgstr "Passwort"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Verbindung"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Symbole"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Antwortzeitüberschreitung in Sekunden"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Icon-Pfad"
38 msgctxt "#30009"
39 msgid "Update Interval"
40 msgstr "Aktualisierungsintervall"
4141
4242 msgctxt "#30010"
4343 msgid "Update Interval in minutes"
4444 msgstr "Aktualisierungsintervall in Minuten"
4545
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Entferne abgeschlossene Timer automatisch"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Weboberfläche Port"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Umschalten auf Receiver (z.B. bei SingleTuner Receivern)"
57
5846 msgctxt "#30014"
5947 msgid "Folder for channeldata"
6048 msgstr "Speicherort für Kanaldaten"
6149
6250 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Überprüfe auf Bouquettaktualisierungen"
51 msgid "Update interval"
52 msgstr "Aktualisierungsintervall"
6553
6654 msgctxt "#30016"
6755 msgid "Check for channel updates"
9583 msgid "Recording folder on the receiver"
9684 msgstr "Aufnahmeverzeichnis auf dem Receiver"
9785
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Sende DeepStandby-Befehl"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Lade nur ein TV-Bouquet"
105
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
109
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Lade Picons aus der Weboberfläche"
113
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Sicheres HTTP (https) verwenden"
86 msgctxt "#30029"
87 msgid "Enable automatic configuration for live streams"
88 msgstr "Aktiviere die Autokonfiguration für Liveübertragungen"
89
90 msgctxt "#30030"
91 msgid "Keep folder structure for records"
92 msgstr "Behalte die Ordnerstruktur für Einträge"
93
94 msgctxt "#30032"
95 msgid "EPG"
96 msgstr "EPG"
97
98 msgctxt "#30035"
99 msgid "Use picons.eu file format"
100 msgstr "Picons.eu Dateiformat verwenden"
101
102 msgctxt "#30039"
103 msgid "Streaming"
104 msgstr "Streaming"
105
106 msgctxt "#30042"
107 msgid "Never"
108 msgstr "Nie"
109
110 msgctxt "#30043"
111 msgid "In EPG only"
112 msgstr "Nur im EPG"
113
114 msgctxt "#30044"
115 msgid "In recordings only"
116 msgstr "Nur in Aufnahmen"
117
118 msgctxt "#30045"
119 msgid "Always"
120 msgstr "Immer"
121
122 msgctxt "#30051"
123 msgid "Login"
124 msgstr "Anmeldung"
125
126 msgctxt "#30052"
127 msgid "Misc"
128 msgstr "verschiedenes"
129
130 msgctxt "#30056"
131 msgid "TV"
132 msgstr "TV"
133
134 msgctxt "#30057"
135 msgid "Radio"
136 msgstr "Radio"
137
138 msgctxt "#30060"
139 msgid "Timeshift"
140 msgstr "Timeshift"
141
142 msgctxt "#30062"
143 msgid "Timeshift buffer path"
144 msgstr "Timeshift Puffer-Pfad"
145
146 msgctxt "#30063"
147 msgid "Off"
148 msgstr "Inaktiv"
149
150 msgctxt "#30064"
151 msgid "On playback"
152 msgstr "Beim Abspielen"
153
154 msgctxt "#30065"
155 msgid "On pause"
156 msgstr "Während der Pause"
157
158 msgctxt "#30070"
159 msgid "Recordings & Timers"
160 msgstr "Aufnahmen & Timer"
161
162 msgctxt "#30071"
163 msgid "Recordings"
164 msgstr "Aufnahmen"
165
166 msgctxt "#30072"
167 msgid "Timers"
168 msgstr "Timer"
169
170 msgctxt "#30085"
171 msgid "OK"
172 msgstr "OK"
173
174 msgctxt "#30094"
175 msgid "N/A"
176 msgstr "N/A"
177
178 msgctxt "#30095"
179 msgid "True"
180 msgstr "Richtig"
181
182 msgctxt "#30096"
183 msgid "False"
184 msgstr "Falsch"
185
186 msgctxt "#30410"
187 msgid "Automatic"
188 msgstr "Automatisch"
189
190 msgctxt "#30420"
191 msgid "One time (Scheduled by guide-based timer rule)"
192 msgstr "Einmalig (geplant nach guide-basierter Zeitregel)"
193
194 msgctxt "#30421"
195 msgid "One time (Scheduled by repeating timer rule)"
196 msgstr "Einmalig (geplant durch Wiederholung der Timerregel)"
197
198 msgctxt "#30430"
199 msgid "Disabled"
200 msgstr "Ausschalten"
201
202 msgctxt "#30431"
203 msgid "Record if EPG title differs"
204 msgstr "Aufnahme bei abweichenden EPG-Titel"
205
206 msgctxt "#30432"
207 msgid "Record if EPG title and short description differs"
208 msgstr "Aufnahme, wenn EPG-Titel und Kurzbeschreibung voneinander abweichen."
209
210 msgctxt "#30433"
211 msgid "Record if EPG title and all descriptions differ"
212 msgstr "Aufnahme, wenn EPG-Titel und alle Beschreibung voneinander abweichen."
117213
118214 msgctxt "#30500"
119215 msgid "Disconnected from '%s'"
122218 msgctxt "#30501"
123219 msgid "Reconnected to '%s'"
124220 msgstr "Verbindung zu '%s' wiederhergestellt"
221
222 msgctxt "#30514"
223 msgid "Timeshift buffer path does not exist"
224 msgstr "Pfad für den Zeitversatz Puffer existiert nicht"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: el_GR\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Όνομα Υπολογιστή ή διεύθυνση IP του VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Θύρα Ροής"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Όνομα χρήστη"
3123 msgid "Password"
3224 msgstr "Κωδικός πρόσβασης"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Σύνδεση"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Εικονίδια"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Χρόνος απόκρισης σε δευτερόλεπτα"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Διαδρομή Εικονιδίου"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Διάστημα Ενημέρωσης σε λεπτά"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Εκκαθάριση Αυτόματης Λίστας Χρονοδιακοπτών"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Θύρα Διεπαφής Ιστού"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap πριν την αλλαγή καναλιού (π.χ. για αποκωδικοποιητές Single Tuner)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Φάκελος για δεδομένα καναλιών"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Έλεγχος για ενημερώσεις μπουκέτων"
47 msgid "Update interval"
48 msgstr "Διάστημα ενημέρωσης "
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Φάκελος εγγραφών στο δέκτη"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Αποστολή Εντολής DeepStandby"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Λήψη μόνο ενός μπουκέτου TV"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Ποτέ"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Μπουκέτο TV"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "Μόνο στο EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Λήψη εικονιδίων από τη διεπαφή ιστού"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Μόνο στις εγγραφές"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Χρήση Ασφαλούς HTTP (https)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "Πάντα"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Σύνδεση"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Διάφορα"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "Τηλεόραση"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Ραδιόφωνο"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Timeshift"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Διαδρομή προσωρινής αποθήκευσης Timeshift"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Ανενεργή"
129
130 msgctxt "#30071"
131 msgid "Recordings"
132 msgstr "Εγγραφές"
133
134 msgctxt "#30072"
135 msgid "Timers"
136 msgstr "Χρονοδιακόπτες"
137
138 msgctxt "#30085"
139 msgid "OK"
140 msgstr "Εντάξει"
141
142 msgctxt "#30094"
143 msgid "N/A"
144 msgstr "Α/Α"
145
146 msgctxt "#30095"
147 msgid "True"
148 msgstr "Αληθές"
149
150 msgctxt "#30096"
151 msgid "False"
152 msgstr "Ψευδές"
153
154 msgctxt "#30430"
155 msgid "Disabled"
156 msgstr "Ανενεργή"
117157
118158 msgctxt "#30500"
119159 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: en_AU\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname or IP address"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streaming Port"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Username"
3123 msgid "Password"
3224 msgstr "Password"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Connection"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Icons"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Response timeout in seconds"
37
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Icon Path"
4137
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Update Interval in minutes"
4541
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatic Timerlist Cleanup"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webinterface Port"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap before channelswitch (i.e. for Single Tuner boxes)"
57
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Folder for channeldata"
61
62 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Check for bouquett updates"
6545
6646 msgctxt "#30016"
6747 msgid "Check for channel updates"
9575 msgid "Recording folder on the receiver"
9676 msgstr "Recording folder on the receiver"
9777
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Send DeepStandby-Command"
78 msgctxt "#30042"
79 msgid "Never"
80 msgstr "Never"
10181
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Fetch only one TV bouquet"
82 msgctxt "#30045"
83 msgid "Always"
84 msgstr "Always"
10585
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
86 msgctxt "#30051"
87 msgid "Login"
88 msgstr "Login"
10989
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Fetch picons from webinterface"
90 msgctxt "#30056"
91 msgid "TV"
92 msgstr "TV"
11393
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Use Secure HTTP (https)"
94 msgctxt "#30057"
95 msgid "Radio"
96 msgstr "Radio"
97
98 msgctxt "#30062"
99 msgid "Timeshift buffer path"
100 msgstr "Timeshift buffer path"
101
102 msgctxt "#30063"
103 msgid "Off"
104 msgstr "Off"
105
106 msgctxt "#30071"
107 msgid "Recordings"
108 msgstr "Recordings"
109
110 msgctxt "#30085"
111 msgid "OK"
112 msgstr "OK"
113
114 msgctxt "#30095"
115 msgid "True"
116 msgstr "True"
117
118 msgctxt "#30096"
119 msgid "False"
120 msgstr "False"
121
122 msgctxt "#30430"
123 msgid "Disabled"
124 msgstr "Disabled"
117125
118126 msgctxt "#30500"
119127 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: en_GB\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 #settings labels
19
18 ###################
19 # settings labels #
20 ###################
21
22 #label: Connection - host
2023 msgctxt "#30000"
21 msgid "VU+ hostname or IP address"
24 msgid "Enigma2 hostname or IP address"
2225 msgstr ""
2326
2427 #empty string with id 30001
2528
29 #label: Connection - streamport
2630 msgctxt "#30002"
27 msgid "Streaming Port"
28 msgstr ""
29
31 msgid "Streaming port"
32 msgstr ""
33
34 #label: Connection - user
3035 msgctxt "#30003"
3136 msgid "Username"
3237 msgstr ""
3338
39 #label: Connection - pass
3440 msgctxt "#30004"
3541 msgid "Password"
3642 msgstr ""
3743
38 #empty strings from id 30005 to 30006
39
44 #label-category: connection
45 msgctxt "#30005"
46 msgid "Connection"
47 msgstr ""
48
49 #label-group: General - Icons
50 msgctxt "#30006"
51 msgid "Icons"
52 msgstr ""
53
54 #label-group: General - Program Streams
4055 msgctxt "#30007"
41 msgid "Response timeout in seconds"
42 msgstr ""
43
56 msgid "Program Streams"
57 msgstr ""
58
59 #label: General - iconpath
4460 msgctxt "#30008"
45 msgid "Icon Path"
46 msgstr ""
47
48 #empty string with id 30009
49
50 msgctxt "#30010"
51 msgid "Update Interval in minutes"
52 msgstr ""
53
61 msgid "Icon path"
62 msgstr ""
63
64 #label-group: General - Update Interval
65 msgctxt "#30009"
66 msgid "Update Interval"
67 msgstr ""
68
69 #empty string with id 30010
70
71 #label: Timers - timerlistcleanup
5472 msgctxt "#30011"
55 msgid "Automatic Timerlist Cleanup"
56 msgstr ""
57
73 msgid "Automatic timerlist cleanup"
74 msgstr ""
75
76 #label: Connection - webport
5877 msgctxt "#30012"
59 msgid "Webinterface Port"
60 msgstr ""
61
78 msgid "Web interface port"
79 msgstr ""
80
81 #label: Channels - zap
6282 msgctxt "#30013"
63 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
64 msgstr ""
65
83 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
84 msgstr ""
85
86 #label: Channels - setprogramid
6687 msgctxt "#30014"
67 msgid "Folder for channeldata"
68 msgstr ""
69
88 msgid "Set program id for live channel or recorded streams"
89 msgstr ""
90
91 #label: General - updateint
7092 msgctxt "#30015"
71 msgid "Check for bouquett updates"
72 msgstr ""
73
74 msgctxt "#30016"
75 msgid "Check for channel updates"
76 msgstr ""
77
93 msgid "Update interval"
94 msgstr ""
95
96 #empty string with id 30016
97
98 #label: Recordings - onlycurrent
7899 msgctxt "#30017"
79100 msgid "Use only the DVB boxes' current recording path"
80101 msgstr ""
81102
103 #label-category: general
104 #label-group: Channels
82105 msgctxt "#30018"
83106 msgid "General"
84107 msgstr ""
85108
109 #label-category: channels
86110 msgctxt "#30019"
87111 msgid "Channels"
88112 msgstr ""
89113
114 #label-category: advanced
115 #label-group: Connection - Advanced
90116 msgctxt "#30020"
91117 msgid "Advanced"
92118 msgstr ""
93119
94 msgctxt "#30021"
95 msgid "HTTP"
96 msgstr ""
97
98 msgctxt "#30022"
99 msgid "Recordings / Timer"
100 msgstr ""
101
120 #empty strings from id 30021 to 30022
121
122 #label: Recordings - recordingpath
102123 msgctxt "#30023"
103124 msgid "Recording folder on the receiver"
104125 msgstr ""
105126
127 #label: Advanced - powerstatemode
106128 msgctxt "#30024"
107 msgid "Send DeepStandby-Command"
108 msgstr ""
109
129 msgid "Send powerstate mode on addon exit"
130 msgstr ""
131
132 #label: Channels - tvgroupmode
110133 msgctxt "#30025"
111 msgid "Fetch only one TV bouquet"
112 msgstr ""
113
134 msgid "TV bouquet fetch mode"
135 msgstr ""
136
137 #label: Channels - onetvgroup
114138 msgctxt "#30026"
115 msgid "TV-Bouquet"
116 msgstr ""
117
139 msgid "TV bouquet 1"
140 msgstr ""
141
142 #label: General - onlinepicons
118143 msgctxt "#30027"
119 msgid "Fetch picons from webinterface"
120 msgstr ""
121
144 msgid "Fetch picons from web interface"
145 msgstr ""
146
147 label: Connection - use_secure
122148 msgctxt "#30028"
123 msgid "Use Secure HTTP (https)"
124 msgstr ""
125
126 #empty strings from id 30029 to 30499
127 #notifications
128
129 msgctxt "#30500"
130 msgid "Disconnected from '%s'"
131 msgstr ""
132
133 msgctxt "#30501"
134 msgid "Reconnected to '%s'"
135 msgstr ""
149 msgid "Use secure HTTP (https)"
150 msgstr ""
151
152 #label: Connection - autoconfig
153 msgctxt "#30029"
154 msgid "Enable automatic configuration for live streams"
155 msgstr ""
156
157 #label: Reordings - keepfolders
158 msgctxt "#30030"
159 msgid "Keep folder structure for records"
160 msgstr ""
161
162 #label-group: EPG - Seasons and Episodes
163 msgctxt "#30031"
164 msgid "Seasons and Episodes"
165 msgstr ""
166
167 #label-category: epg
168 msgctxt "#30032"
169 msgid "EPG"
170 msgstr ""
171
172 #label: EPG - extractshowinfoenabled
173 msgctxt "#30033"
174 msgid "Extract season, episode and year info where possible"
175 msgstr ""
176
177 #label: Timers - enableautotimers
178 msgctxt "#30034"
179 msgid "Enable autotimers"
180 msgstr ""
181
182 #label: General - usepiconseuformat
183 msgctxt "#30035"
184 msgid "Use picons.eu file format"
185 msgstr ""
186
187 #label: Timers - enablegenrepeattimers
188 msgctxt "#30036"
189 msgid "Enable generate repeat timers"
190 msgstr ""
191
192 #label: EPG - logmissinggenremapping
193 msgctxt "#30037"
194 msgid "Log missing genre text mappings"
195 msgstr ""
196
197 #label-group: Connection - Web Interface
198 msgctxt "#30038"
199 msgid "Web Interface"
200 msgstr ""
201
202 #label-group: Connection - Streaming
203 msgctxt "#30039"
204 msgid "Streaming"
205 msgstr ""
206
207 #label: Advanced - prependoutline
208 msgctxt "#30040"
209 msgid "Put outline (e.g. sub-title) before plot"
210 msgstr ""
211
212 #label: Advanced - streamreadchunksize
213 msgctxt "#30041"
214 msgid "Stream read chunk size"
215 msgstr ""
216
217 #label - Advanced - prependoutline
218 msgctxt "#30042"
219 msgid "Never"
220 msgstr ""
221
222 #label - Advanced - prependoutline
223 msgctxt "#30043"
224 msgid "In EPG only"
225 msgstr ""
226
227 #label - Advanced - prependoutline
228 msgctxt "#30044"
229 msgid "In recordings only"
230 msgstr ""
231
232 #label - Advanced - prependoutline
233 msgctxt "#30045"
234 msgid "Always"
235 msgstr ""
236
237 #label: EPG - extractshowinfofile
238 msgctxt "#30046"
239 msgid "Extract show info file"
240 msgstr ""
241
242 #label-group: EPG - Rytec genre text Mappings
243 msgctxt "#30047"
244 msgid "Rytec genre text Mappings"
245 msgstr ""
246
247 #label: EPG - rytecgenretextmapenabled
248 msgctxt "#30048"
249 msgid "Enable Rytec genre text mappings"
250 msgstr ""
251
252 #label: EPG - rytecgenretextmapfile
253 msgctxt "#30049"
254 msgid "Rytec genre text mappings file"
255 msgstr ""
256
257 #label: Advanced - readtimeout
258 msgctxt "#30050"
259 msgid "Custom live TV timeout (0 to use default)"
260 msgstr ""
261
262 #label-group: Connection - Login
263 msgctxt "#30051"
264 msgid "Login"
265 msgstr ""
266
267 #label-group: Advanced - Misc
268 msgctxt "#30052"
269 msgid "Misc"
270 msgstr ""
271
272 #label-group: EPG - Genre ID Mappings
273 msgctxt "#30053"
274 msgid "Genre ID Mappings"
275 msgstr ""
276
277 #label: EPG - genreidmapenabled
278 msgctxt "#30054"
279 msgid "Enable genre ID Mappings"
280 msgstr ""
281
282 #label: EPG - genreidmapfile
283 msgctxt "#30055"
284 msgid "Genre ID mappings file"
285 msgstr ""
286
287 #label-group: Channels - TV
288 msgctxt "#30056"
289 msgid "TV"
290 msgstr ""
291
292 #label-group: Channels - Radio
293 msgctxt "#30057"
294 msgid "Radio"
295 msgstr ""
296
297 #label: Channels - radiogroupmode
298 msgctxt "#30058"
299 msgid "Radio bouquet fetch mode"
300 msgstr ""
301
302 #label: Channels - oneradiogroup
303 msgctxt "#30059"
304 msgid "Radio bouquet 1"
305 msgstr ""
306
307 #label-category: timeshift
308 #label-group: Timeshift - Timeshift
309 msgctxt "#30060"
310 msgid "Timeshift"
311 msgstr ""
312
313 #label: Timeshift - enabletimeshift
314 msgctxt "#30061"
315 msgid "Enable timeshift"
316 msgstr ""
317
318 #label: Timeshift - timeshiftbufferpath
319 msgctxt "#30062"
320 msgid "Timeshift buffer path"
321 msgstr ""
322
323 #label-option: Timeshift - enabletimeshift
324 msgctxt "#30063"
325 msgid "Off"
326 msgstr ""
327
328 #label-option: Timeshift - enabletimeshift
329 msgctxt "#30064"
330 msgid "On playback"
331 msgstr ""
332
333 #label-option: Timeshift - enabletimeshift
334 msgctxt "#30065"
335 msgid "On pause"
336 msgstr ""
337
338 #label: Connection - use_secure_stream
339 msgctxt "#30066"
340 msgid "Use secure HTTP (https) for streams"
341 msgstr ""
342
343 #label: Connection - use_login_stream
344 msgctxt "#30067"
345 msgid "Use login for streams"
346 msgstr ""
347
348 #label: Channels - tvfavouritesmode
349 msgctxt "#30068"
350 msgid "Fetch TV favourites bouquet"
351 msgstr ""
352
353 #label: Channels - radiofavouritesmode
354 msgctxt "#30069"
355 msgid "Fetch radio favourites bouquet"
356 msgstr ""
357
358 #label-category: recordings
359 msgctxt "#30070"
360 msgid "Recordings"
361 msgstr ""
362
363 #label-group: Recordings - Recordings
364 msgctxt "#30071"
365 msgid "Recordings"
366 msgstr ""
367
368 #label-category: timers
369 #label-group: Timers - timers
370 msgctxt "#30072"
371 msgid "Timers"
372 msgstr ""
373
374 #label: Timers - numgenrepeattimers
375 msgctxt "#30073"
376 msgid "Number of repeat timers to generate"
377 msgstr ""
378
379 #label-option: Channels - tvgroupmode
380 #label-option: Channels - radiogroupmode
381 msgctxt "#30074"
382 msgid "All bouquets"
383 msgstr ""
384
385 #label-option: Channels - tvgroupmode
386 #label-option: Channels - radiogroupmode
387 msgctxt "#30075"
388 msgid "Some bouquets"
389 msgstr ""
390
391 #label-option: Channels - tvfavouritesmode
392 #label-option: Channels - radiofavouritesmode
393 msgctxt "#30076"
394 msgid "As first bouquet"
395 msgstr ""
396
397 #label-option: Channels - tvfavouritesmode
398 #label-option: Channels - radiofavouritesmode
399 msgctxt "#30077"
400 msgid "As last bouquet"
401 msgstr ""
402
403 #label-option: Channels - tvgroupmode
404 #label-option: Channels - radiogroupmode
405 msgctxt "#30078"
406 msgid "Favourites bouquet"
407 msgstr ""
408
409 #application: ChannelGroups
410 msgctxt "#30079"
411 msgid "Favourites (TV)"
412 msgstr ""
413
414 #application: ChannelGroups
415 msgctxt "#30080"
416 msgid "Favourites (Radio)"
417 msgstr ""
418
419 #application: Client
420 #application: Admin
421 msgctxt "#30081"
422 msgid "unknown"
423 msgstr ""
424
425 #application: Client
426 msgctxt "#30082"
427 msgid " (Not connected!)"
428 msgstr ""
429
430 #application: Client
431 msgctxt "#30083"
432 msgid "addon error"
433 msgstr ""
434
435 #empty strings from id 30084 to 30085
436
437 #label-category: backend
438 msgctxt "#30086"
439 msgid "Backend"
440 msgstr ""
441
442 #label-group: Backend - Recording Padding
443 msgctxt "#30087"
444 msgid "Recording Padding"
445 msgstr ""
446
447 #label: Backend - globalstartpaddingstb
448 msgctxt "#30088"
449 msgid "Global start padding"
450 msgstr ""
451
452 #label: Backend - globalendpaddingstb
453 msgctxt "#30089"
454 msgid "Global end padding"
455 msgstr ""
456
457 #label-group: Backend - Device Info
458 msgctxt "#30090"
459 msgid "Device Info"
460 msgstr ""
461
462 #label: Backend - webifversion
463 msgctxt "#30091"
464 msgid "WebIf version"
465 msgstr ""
466
467 #label: Backend - autotimertagintags
468 msgctxt "#30092"
469 msgid "AutoTimer tag in timer tags"
470 msgstr ""
471
472 #label: Backend - autotimernameintags
473 msgctxt "#30093"
474 msgid "AutoTimer name in timer tags"
475 msgstr ""
476
477 #application: Admin
478 msgctxt "#30094"
479 msgid "N/A"
480 msgstr ""
481
482 #application: Admin
483 msgctxt "#30095"
484 msgid "True"
485 msgstr ""
486
487 #application: Admin
488 msgctxt "#30096"
489 msgid "False"
490 msgstr ""
491
492 #label-option: Advanced - powerstatemode
493 msgctxt "#30097"
494 msgid "Standby"
495 msgstr ""
496
497 #label-option: Advanced - powerstatemode
498 msgctxt "#30098"
499 msgid "Deep standby"
500 msgstr ""
501
502 #label-option: Advanced - powerstatemode
503 msgctxt "#30099"
504 msgid "Wakeup, then standby"
505 msgstr ""
506
507 #label: General - updatemode
508 msgctxt "#30100"
509 msgid "Update mode"
510 msgstr ""
511
512 #label-option: General - updatemode
513 msgctxt "#30101"
514 msgid "Timers and recordings"
515 msgstr ""
516
517 #label-option: General - updatemode
518 msgctxt "#30102"
519 msgid "Timers only"
520 msgstr ""
521
522 #label: General - useopenwebifpiconpath
523 msgctxt "#30103"
524 msgid "Use OpenWebIf picon path"
525 msgstr ""
526
527 #label: Advanced - tracedebug
528 msgctxt "#30104"
529 msgid "Enable trace logging in debug mode"
530 msgstr ""
531
532 #label-group - EPG - Other
533 msgctxt "#30105"
534 msgid "Other"
535 msgstr ""
536
537 #label: EPG - epgdelayperchannel
538 msgctxt "#30106"
539 msgid "EPG update delay per channel"
540 msgstr ""
541
542 #label-group: Recordings - Recording EDLs (Edit Decision Lists)
543 msgctxt "#30107"
544 msgid "Recording EDLs (Edit Decision Lists)"
545 msgstr ""
546
547 #label: Recordings - enablerecordingedls
548 msgctxt "#30108"
549 msgid "Enable EDLs support"
550 msgstr ""
551
552 #label: Recordings - edlpaddingstart
553 msgctxt "#30109"
554 msgid "EDL start time padding"
555 msgstr ""
556
557 #label: Recordings - edlpaddingstop
558 msgctxt "#30110"
559 msgid "EDL stop time padding"
560 msgstr ""
561
562 #label: Advanced - debugnormal
563 msgctxt "#30111"
564 msgid "Enable debug logging in normal mode"
565 msgstr ""
566
567 #application: ChannelGroups
568 msgctxt "#30112"
569 msgid "Last Scanned (TV)"
570 msgstr ""
571
572 #application: ChannelGroups
573 msgctxt "#30113"
574 msgid "Last Scanned (Radio)"
575 msgstr ""
576
577 #label: Channels - excludelastscannedtv
578 #label: Channels - excludelastscannedradio
579 msgctxt "#30114"
580 msgid "Exclude last scanned bouquet"
581 msgstr ""
582
583 #label: EPG - skipinitialepg
584 msgctxt "#30115"
585 msgid "Skip Initial EPG Load"
586 msgstr ""
587
588 #label: General - channelandgroupupdatemode
589 msgctxt "#30116"
590 msgid "Channels and groups update mode"
591 msgstr ""
592
593 #label-option: General - channelandgroupupdatemode
594 msgctxt "#30117"
595 msgid "Disabled"
596 msgstr ""
597
598 #label-option: General - channelandgroupupdatemode
599 msgctxt "#30118"
600 msgid "Notify on UI and Log"
601 msgstr ""
602
603 #label-option: General - channelandgroupupdatemode
604 msgctxt "#30119"
605 msgid "Reload Channels and Groups"
606 msgstr ""
607
608 #label: General - channelandgroupupdatehour
609 msgctxt "#30120"
610 msgid "Channels and groups update hour (24h)"
611 msgstr ""
612
613 #label: Connection - connectionchecktimeout
614 msgctxt "#30121"
615 msgid "Connection check timeout"
616 msgstr ""
617
618 #label: Connection - connectioncheckinterval
619 msgctxt "#30122"
620 msgid "Connection check interval"
621 msgstr ""
622
623 #label: Timers - Autotimers
624 msgctxt "#30123"
625 msgid "Autotimers"
626 msgstr ""
627
628 #label: Timers - limitanychannelautotimers
629 msgctxt "#30124"
630 msgid "Limit 'Any Channel' autotimers to TV or Radio"
631 msgstr ""
632
633 #label: Timers - limitanychannelautotimerstogroups
634 msgctxt "#30125"
635 msgid "Limit to groups of original EPG channel"
636 msgstr ""
637
638 #label: Channels - usestandardserviceref
639 msgctxt "#30126"
640 msgid "Use standard channel service reference"
641 msgstr ""
642
643 #label: Recordings - storeextrarecordinginfo
644 msgctxt "#30127"
645 msgid "Store last played/play count on the backend"
646 msgstr ""
647
648 #label: Recordings - sharerecordinglastplayed
649 msgctxt "#30128"
650 msgid "Share last played across:"
651 msgstr ""
652
653 #label-option: Recordings - sharerecordinglastplayed
654 msgctxt "#30129"
655 msgid "Kodi instances"
656 msgstr ""
657
658 #label-option: Recordings - sharerecordinglastplayed
659 msgctxt "#30130"
660 msgid "Kodi/E2 instances"
661 msgstr ""
662
663 #label-option: Channels - tvgroupmode
664 #label-option: Channels - radiogroupmode
665 msgctxt "#30131"
666 msgid "Custom bouquets"
667 msgstr ""
668
669 #label: Channels - customtvgroupsfile
670 msgctxt "#30132"
671 msgid "Custom TV bouquets file"
672 msgstr ""
673
674 #label: Channels - customradiogroupsfile
675 msgctxt "#30133"
676 msgid "Custom Radio bouquets file"
677 msgstr ""
678
679 #label: Channels - numtvgroups
680 msgctxt "#30134"
681 msgid "Number of TV bouquets"
682 msgstr ""
683
684 #label: Channels - twotvgroup
685 msgctxt "#30135"
686 msgid "TV bouquet 2"
687 msgstr ""
688
689 #label: Channels - threetvgroup
690 msgctxt "#30136"
691 msgid "TV bouquet 3"
692 msgstr ""
693
694 #label: Channels - fourtvgroup
695 msgctxt "#30137"
696 msgid "TV bouquet 4"
697 msgstr ""
698
699 #label: Channels - fivetvgroup
700 msgctxt "#30138"
701 msgid "TV bouquet 5"
702 msgstr ""
703
704 #label: Channels - numradiogroups
705 msgctxt "#30139"
706 msgid "Number of radio bouquets"
707 msgstr ""
708
709 #label: Channels - tworadiogroup
710 msgctxt "#30140"
711 msgid "Radio bouquet 2"
712 msgstr ""
713
714 #label: Channels - threeradiogroup
715 msgctxt "#30141"
716 msgid "Radio bouquet 3"
717 msgstr ""
718
719 #label: Channels - fourradiogroup
720 msgctxt "#30142"
721 msgid "Radio bouquet 4"
722 msgstr ""
723
724 #label: Channels - fiveradiogroup
725 msgctxt "#30143"
726 msgid "Radio bouquet 5"
727 msgstr ""
728
729 #label: Advanced - ignoredebug
730 msgctxt "#30144"
731 msgid "No addon debug logging in Kodi debug mode"
732 msgstr ""
733
734 #empty strings from id 30145 to 30409
735
736 ###############
737 # application #
738 ###############
739
740 #application: Timers
741 msgctxt "#30410"
742 msgid "Automatic"
743 msgstr ""
744
745 #empty strings from id 30411 to 30419
746
747 #application: Timers
748 msgctxt "#30420"
749 msgid "Once off timer (set by auto guide-based rule)"
750 msgstr ""
751
752 #application: Timers
753 msgctxt "#30421"
754 msgid "Once off timer (set by repeating time/channel based rule)"
755 msgstr ""
756
757 #application: Timers
758 msgctxt "#30422"
759 msgid "Once off time/channel based"
760 msgstr ""
761
762 #application: Timers
763 msgctxt "#30423"
764 msgid "Repeating time/channel based"
765 msgstr ""
766
767 #application: Timers
768 msgctxt "#30424"
769 msgid "One time guide-based"
770 msgstr ""
771
772 #application: Timers
773 msgctxt "#30425"
774 msgid "Repeating guide-based"
775 msgstr ""
776
777 #application: Timers
778 msgctxt "#30426"
779 msgid "Auto guide-based"
780 msgstr ""
781
782 #empty strings from id 30427 to 30429
783
784 #label-option: Channels - tvfavouritesmode
785 #label-option: Channels - radiofavouritesmode
786 #label-option: Advanced - powerstatemode
787 #application: Timers
788 msgctxt "#30430"
789 msgid "Disabled"
790 msgstr ""
791
792 #application: Timers
793 msgctxt "#30431"
794 msgid "Record if EPG title differs"
795 msgstr ""
796
797 #application: Timers
798 msgctxt "#30432"
799 msgid "Record if EPG title and short description differs"
800 msgstr ""
801
802 #application: Timers
803 msgctxt "#30433"
804 msgid "Record if EPG title and all descriptions differ"
805 msgstr ""
806
807 #empty strings from id 30434 to 30499
808
809 #################
810 # notifications #
811 #################
812
813 #empty strings from id 300500 to 30513
814
815 #notification: Client
816 msgctxt "#30514"
817 msgid "Timeshift buffer path does not exist"
818 msgstr ""
819
820 #notification: Enigma2
821 msgctxt "#30515"
822 msgid "Enigma2: Could not reach web interface"
823 msgstr ""
824
825 #notification: Enigma2
826 msgctxt "#30516"
827 msgid "Enigma2: No channel groups found"
828 msgstr ""
829
830 #notification: Enigma2
831 msgctxt "#30517"
832 msgid "Enigma2: No channels found"
833 msgstr ""
834
835 #notification: Enigma2
836 msgctxt "#30518"
837 msgid "Enigma2: Channel group changes detected, please restart to load changes"
838 msgstr ""
839
840 #notification: Enigma2
841 msgctxt "#30519"
842 msgid "Enigma2: Channel changes detected, please restart to load changes"
843 msgstr ""
844
845 #application: AutoTimer
846 #application: Timer
847 msgctxt "#30520"
848 msgid "Invalid Channel"
849 msgstr ""
850
851 #notification: Enigma2
852 msgctxt "#30521"
853 msgid "Enigma2: Channel group changes detected, reloading..."
854 msgstr ""
855
856 #notification: Enigma2
857 msgctxt "#30522"
858 msgid "Enigma2: Channel changes detected, reloading..."
859 msgstr ""
860
861 #empty strings from id 30523 to 30599
862
863 #############
864 # help info #
865 #############
866
867 #help info - Connection
868
869 #help-category: connection
870 msgctxt "#30600"
871 msgid "This category cotains the settings for connecting to the Enigma2 device"
872 msgstr ""
873
874 #help: Connection - host
875 msgctxt "#30601"
876 msgid "The IP address or hostname of your enigma2 based set-top box."
877 msgstr ""
878
879 #help: Connection - webport
880 msgctxt "#30602"
881 msgid "The port used to connect to the web interface."
882 msgstr ""
883
884 #help: Connection - use_secure
885 msgctxt "#30603"
886 msgid "Use https to connect to the web interface."
887 msgstr ""
888
889 #help: Connection - user
890 msgctxt "#30604"
891 msgid "If the webinterface of the set-top box is protected with a username/password combination this needs to be set in this option."
892 msgstr ""
893
894 #help: Connection - pass
895 msgctxt "#30605"
896 msgid "If the webinterface of the set-top box is protected with a username/password combination this needs to be set in this option."
897 msgstr ""
898
899 #help: Connection - autoconfig
900 msgctxt "#30606"
901 msgid "When enabled the stream URL will be read from an M3U8 file. When disabled it is constructed based on the service reference of the channel. This option is rarely required and should not be enbaled unless you have a special use case. If viewing an IPTV Stream this option has no effect on those channels."
902 msgstr ""
903
904 #help: Connection - streamport
905 msgctxt "#30607"
906 msgid "This option defines the streaming port the set-top box uses to stream live tv. The default is 8001 which should be fine if the user did not define a custom port within the webinterface."
907 msgstr ""
908
909 #help: Connection - use_secure_stream
910 msgctxt "#30608"
911 msgid "Use https to connect to streams."
912 msgstr ""
913
914 #help: Connection - use_login_stream
915 msgctxt "#30609"
916 msgid "Use the login username and password for streams."
917 msgstr ""
918
919 #help: Connection - connectionchecktimeout
920 msgctxt "#30610"
921 msgid "The value in seconds to wait for a connection check to complete before failure. Useful for tuning on older Enigma2 devices. Note, this setting should rarely need to be changed. It's more likely the `Connection check interval` setting will have the desired effect. Default is 30 seconds."
922 msgstr ""
923
924 #help: Connection - connectioncheckinterval
925 msgctxt "#30611"
926 msgid "The value in seconds to wait between connection checks. Useful for tuning on older Enigma2 devices. Default is 10 seconds."
927 msgstr ""
928
929 #empty strings from id 30612 to 30619
930
931 #help info - General
932
933 #help-category: general
934 msgctxt "#30620"
935 msgid "This category cotains the settings whivh generally need to be set by the user"
936 msgstr ""
937
938 #help: General - onlinepicons
939 msgctxt "#30621"
940 msgid "Fetch the picons straight from the Enigma 2 set-top box."
941 msgstr ""
942
943 #help: General - useopenwebifpiconpath
944 msgctxt "#30622"
945 msgid "Fetch the picon path from OpenWebIf instead of constructing from ServiceRef. Requires OpenWebIf 1.3.5 or higher. There is no effect if used on a lower version of OpenWebIf."
946 msgstr ""
947
948 #help: General - usepiconseuformat
949 msgctxt "#30623"
950 msgid "Assume all picons files fetched from the set-top box start with '1_1_1_' and end with '_0_0_0'."
951 msgstr ""
952
953 #help: General - iconpath
954 msgctxt "#30624"
955 msgid "In order to have Kodi display channel logos you have to copy the picons from your set-top box onto your OpenELEC machine. You then need to specify this path in this property."
956 msgstr ""
957
958 #help: General - updateint
959 msgctxt "#30625"
960 msgid "As the set-top box can also be used to modify timers, delete recordings etc. and the set-top box does not notify the Kodi installation, the addon needs to regularly check for updates (new channels, new/changed/deletes timers, deleted recordings, etc.) This property defines how often the addon checks for updates. Please note that updating the recordings frequently can keep your receiver and it's harddisk from entering standby automatically."
961 msgstr ""
962
963 #help: General - updatemode
964 msgctxt "#30626"
965 msgid "The mode used when the update interval is reached. Note that if there is any timer change detected a recordings update will always occur regardless of the update mode. Choose from one of the following two modes: [Timers and Recordings] Update all timers and recordings; [Timers only] Only update the timers. If it's important to not spin up the HDD on your STB use this option. The HDD should then only spin up when a timer event occurs."
966 msgstr ""
967
968 #help: General - channelandgroupupdatemode
969 msgctxt "#30627"
970 msgid "The mode used when the hour in the next settings is reached. Choose from one of the following three modes: [Disabled] Never check for channel and group changes; [Notify on UI and Log] Display a notice in the UI and log the fact that a change was detectetd]; [Reload Channels and Groups] Disconnect and reconnect with E2 device to reload channels only if a change is detected."
971 msgstr ""
972
973 #help: General - channelandgroupupdatehour
974 msgctxt "#30628"
975 msgid "The hour of the day when the check for new channels should occur. Default is 4h as the Auto Bouquet Maker (ABM) on the E2 device defaults to 3AM."
976 msgstr ""
977
978 #help: Channels - setprogramid
979 msgctxt "#30629"
980 msgid "Some TV Providers (e.g. Nos - Portugal) using MPTS send extra program stream information. Setting the program id allows kodi to select the correct stream and therefore makes the channel/recording playable. Note that it takes approx 33% longer to open any stream with this option enabled."
981 msgstr ""
982
983 #empty strings from id 30630 to 30639
984
985 #help info - Channels
986
987 #help-category: channels
988 msgctxt "#30640"
989 msgid "This category cotains the settings for channels. When changing bouquets you may need to clear the channel cache to the settings to take effect. You can do this by going to the following in Kodi settings: 'Settings->PVR & Live TV->General->Clear cache'."
990 msgstr ""
991
992 #help: Channels - usestandardserviceref
993 msgctxt "#30641"
994 msgid "Usually service reference's for the channels are in a standard format like '1:0:1:27F6:806:2:11A0000:0:0:0:'. On occasion depending on provider they can be extended with some text e.g. '1:0:1:27F6:806:2:11A0000:0:0:0::UTV' or '1:0:1:27F6:806:2:11A0000:0:0:0::UTV + 1'. If this option is enabled then all read service reference's will be read as standard. This is default behaviour. Functionality like autotimers will always convert to a standard reference."
995 msgstr ""
996
997 #help: Channels - zap
998 msgctxt "#30642"
999 msgid "When using the addon with a single tuner box it may be necessary that the addon needs to be able to zap to another channel on the set-top box. If this option is enabled each channel switch in Kodi will also result in a channel switch on the set-top box. Please note that "allow channel switching" needs to be enabled in the webinterface on the set-top box."
1000 msgstr ""
1001
1002 #help: Channels - tvgroupmode
1003 msgctxt "#30643"
1004 msgid "Choose from one of the following three modes: [All bouquets] Fetch all TV bouquets from the set-top box; [Some bouquets] Only fetch the bouquets specified in the next options; [Favourites group] Only fetch the system bouquet for TV favourites; [Custom groups] Fetch a set of bouquets from the Set-top box whose names are loaded from an XML file."
1005 msgstr ""
1006
1007 #help: Channels - onetvgroup
1008 #help: Channels - twotvgroup
1009 #help: Channels - threetvgroup
1010 #help: Channels - fourtvgroup
1011 #help: Channels - fivetvgroup
1012 msgctxt "#30644"
1013 msgid "If the previous option has been has been set to 'Some bouquets' you need to specify a TV bouquet to be fetched from the set-top box. Please not that this is the bouquet-name as shown on the set-top box (i.e. 'Favourites (TV)'). This setting is case-sensitive."
1014 msgstr ""
1015
1016 #help: Channels - tvfavouritesmode
1017 msgctxt "#30645"
1018 msgid "If the fetch mode is 'All bouquets' or 'Some bouquets' depending on your Enigma2 image you may need to explicitly fetch favourites if you require them. The options are: [Disabled] Don't explicitly fetch TV favourites; [As first bouquet] Explicitly fetch them as the first bouquet; [As last bouquet] Explicitly fetch them as the last bouquet."
1019 msgstr ""
1020
1021 #help: Channels - excludelastscannedtv
1022 msgctxt "#30646"
1023 msgid "Last scanned is a system bouquet containing all the TV and Radio channels found in the last scan. Any TV channels found in the Last Scanned bouquet can be displayed as a group called 'Last Scanned (TV)' in Kodi. For TV this group is excluded by default. Disable this option to exclude this group. Note that if no TV groups are loaded the Last Scanned group for TV will be loaded by default regardless of this setting."
1024 msgstr ""
1025
1026 #help: Channels - radiogroupmode
1027 msgctxt "#30647"
1028 msgid "Choose from one of the following three modes: [All bouquets] Fetch all Radio bouquets from the set-top box]; [Some bouquets] Only fetch the bouquets specified in the next options; [Favourites group] Only fetch the system bouquet for Radio favourites; [Custom groups] Fetch a set of bouquets from the Set-top box whose names are loaded from an XML file."
1029 msgstr ""
1030
1031 #help: Channels - oneradiogroup
1032 #help: Channels - tworadiogroup
1033 #help: Channels - threeradiogroup
1034 #help: Channels - fourradiogroup
1035 #help: Channels - fiveradiogroup
1036 msgctxt "#30648"
1037 msgid "If the previous option has been has been set to 'Some bouquets' you need to specify a Radio bouquet to be fetched from the set-top box. Please not that this is the bouquet-name as shown on the set-top box (i.e. 'Favourites (Radio)'). This setting is case-sensitive."
1038 msgstr ""
1039
1040 #help: Channels - radiofavouritesmode
1041 msgctxt "#30649"
1042 msgid "If the fetch mode is 'All bouquets' or 'Some bouquets' depending on your Enigma2 image you may need to explicitly fetch favourites if you require them. The options are: [Disabled] Don't explicitly fetch Radio favourites; [As first bouquet] Explicitly fetch them as the first bouquet; [As last bouquet] Explicitly fetch them as the last bouquet."
1043 msgstr ""
1044
1045 #help: Channels - excludelastscannedradio
1046 msgctxt "#30650"
1047 msgid "Last scanned is a system bouquet containing all the TV and Radio channels found in the last scan. Any Radio channels found in the Last Scanned bouquet can be displayed as a group called 'Last Scanned (Radio)' in Kodi. For Radio this group is excluded by default. Disable this option to show this group."
1048 msgstr ""
1049
1050 #help: Channels - customtvgroupsfile
1051 msgctxt "#30651"
1052 msgid "The file used to load the custom TV bouquets (groups). If no groups can be matched the channel list will default to 'Last Scanned (TV)'. The default file is `customTVGroups-example.xml`."
1053 msgstr ""
1054
1055 #help: Channels - customradiogroupsfile
1056 msgctxt "#30652"
1057 msgid "The file used to load the custom Radio bouquets (groups). If no groups can be matched the channel list will default to 'Last Scanned (Radio)'. The default file is `customRadioGroups-example.xml`."
1058 msgstr ""
1059
1060 #help: Channels - numtvgroups
1061 msgctxt "#30653"
1062 msgid "The number of TV bouquets to load when `Some bouquets` is the selected fetch mode. Up to 5 can be chosen. If more than 5 are required the 'Custom bouquets' fetch mode should be used instead."
1063 msgstr ""
1064
1065 #help: Channels - numradiogroups
1066 msgctxt "#30654"
1067 msgid "The number of Radio bouquets to load when `Some bouquets` is the selected fetch mode. Up to 5 can be chosen. If more than 5 are required the 'Custom bouquets' fetch mode should be used instead."
1068 msgstr ""
1069
1070 #empty strings from id 30655 to 30659
1071
1072 #help info - EPG
1073
1074 #help-category: epg
1075 msgctxt "#30660"
1076 msgid "This category cotains the settings for EPG (Electronic Programme Guide). Excluding logging missing genre text mappings all other options will require clearing the EPG cache to take effect. This can be done by going to 'Settings->PVR & Live TV->Guide->Clear cache' in Kodi after the addon restarts."
1077 msgstr ""
1078
1079 #help: EPG - extractshowinfoenabled
1080 msgctxt "#30661"
1081 msgid "Check the description fields in the EPG data and attempt to extract season, episode and year info where possible."
1082 msgstr ""
1083
1084 #help: EPG - extractshowinfofile
1085 msgctxt "#30662"
1086 msgid "The config used to extract season, episode and year information. The default file is `English-ShowInfo.xml`."
1087 msgstr ""
1088
1089 #help: EPG - genreidmapenabled
1090 msgctxt "#30663"
1091 msgid "If the genre IDs sent with EPG data from your set-top box are not using the DVB standard, map from these to the DVB standard IDs. Sky UK for instance uses OpenTV, in that case without this option set the genre colouring and text would be incorrect in Kodi."
1092 msgstr ""
1093
1094 #help: EPG - genreidmapfile
1095 msgctxt "#30664"
1096 msgid "The config used to map set-top box EPG genre IDs to DVB standard IDs. The default file is `Sky-UK.xml`."
1097 msgstr ""
1098
1099 #help: EPG - rytecgenretextmapenabled
1100 msgctxt "#30665"
1101 msgid "If you use Rytec XMLTV EPG data this option can be used to map the text genres to DVB standard IDs."
1102 msgstr ""
1103
1104 #help: EPG - rytecgenretextmapfile
1105 msgctxt "#30666"
1106 msgid "The config used to map Rytec Genre Text to DVB IDs. The default file is `Rytec-UK-Ireland.xml`."
1107 msgstr ""
1108
1109 #help: EPG - logmissinggenremapping
1110 msgctxt "#30667"
1111 msgid "If you would like missing genre mappings to be logged so you can report them enable this option. Note: any genres found that don't have a mapping will still be extracted and sent to Kodi as strings. Currently genres are extracted by looking for text between square brackets, e.g. [TV Drama], or for major, minor genres using a dot (.) to separate [TV Drama. Soap Opera]"
1112 msgstr ""
1113
1114 #help: EPG - epgdelayperchannel
1115 msgctxt "#30668"
1116 msgid "For older Enigma2 devices EPG updates can effect streaming quality (such as buffer timeouts). A delay of between 250ms and 5000ms can be introduced to improve quality. Only recommended for older devices. Choose the lowest value that avoids buffer timeouts."
1117 msgstr ""
1118
1119 #help: EPG - skipinitialepg
1120 msgctxt "#30669"
1121 msgid "Ignore the intial EPG load (now and next). Enabled by default to prevent crash issues on LibreElec/CoreElec."
1122 msgstr ""
1123
1124 #empty strings from id 30670 to 30679
1125
1126 #help info - Recordings
1127
1128 #help-category: recordings
1129 msgctxt "#30680"
1130 msgid "This category cotains the settings for recordings"
1131 msgstr ""
1132
1133 #help: Recordings - storeextrarecordinginfo
1134 msgctxt "#30681"
1135 msgid "Store last played position and count on the backend so they can be shared across kodi instances. Only supported on OpenWebIf version 1.3.6+."
1136 msgstr ""
1137
1138 #help: Recordings - sharerecordinglastplayed
1139 msgctxt "#30682"
1140 msgid "The options are: [Kodi instances] Only use the value in kodi and will not affect last played on the E2 device; [Kodi/E2 instances] Use the value across kodi and the E2 device so they stay in sync. Last played will be synced with the E2 device once every 5-10 minutes per recording if the PVR menus are in use. Note that only a single kodi instance is required to have this option enabled."
1141 msgstr ""
1142
1143 #help: Recordings - recordingpath
1144 msgctxt "#30683"
1145 msgid "Per default the addon does not specify the recording folder in newly created timers, so the default set in the set-top box will be used. If you want to specify a different folder (i.e. because you want all recordings scheduled via Kodi to be stored in a separate folder), then you need to set this option."
1146 msgstr ""
1147
1148 #help: Recordings - onlycurrent
1149 msgctxt "#30684"
1150 msgid "If this option is not set the addon will fetch all available recordings from all configured paths from the set-top box. If this option is set then it will only list recordings that are stored within the 'current recording path' on the set-top box."
1151 msgstr ""
1152
1153 #help: Reordings - keepfolders
1154 msgctxt "#30685"
1155 msgid "If enabled do not specify a recording folder, when disabled (defaut), check if the recording is in it's own folder or in the root of the recording path."
1156 msgstr ""
1157
1158 #help: Recordings - enablerecordingedls
1159 msgctxt "#30686"
1160 msgid "EDLs are used to define commericals etc. in recordings. If a tool like Comskip is used to generate EDL files enabling this will allow Kodi PVR to use them. E.g. if there is a file called 'my recording.ts' the EDL file should be call 'my recording.edl'. Note: enabling this setting has no effect if the files are not present."
1161 msgstr ""
1162
1163 #help: Recordings - edlpaddingstart
1164 msgctxt "#30687"
1165 msgid "Padding to use at an EDL stop. I.e. use a negative number to start the cut earlier and positive to start the cut later. Default 0."
1166 msgstr ""
1167
1168 #help: Recordings - edlpaddingstop
1169 msgctxt "#30688"
1170 msgid "Padding to use at an EDL stop. I.e. use a negative number to stop the cut earlier and positive to stop the cut later. Default 0."
1171 msgstr ""
1172
1173 #empty strings from id 30689 to 30699
1174
1175 #help info - Timers
1176
1177 #help-category: timers
1178 msgctxt "#30700"
1179 msgid "This category cotains the settings for timers (regular and auto)"
1180 msgstr ""
1181
1182 #help: Timers - enablegenrepeattimers
1183 msgctxt "#30701"
1184 msgid "Repeat timers will display as timer rules. Enabling this will make Kodi generate regular timers to match the repeat timer rules so the UI can show what's scheduled and currently recording for each repeat timer."
1185 msgstr ""
1186
1187 #help: Timers - numgenrepeattimers
1188 msgctxt "#30702"
1189 msgid "The number of Kodi PVR timers to generate."
1190 msgstr ""
1191
1192 #help: Timers - timerlistcleanup
1193 msgctxt "#30703"
1194 msgid "If this option is set then the addon will send the command to delete completed timers from the set-top box after each update interval."
1195 msgstr ""
1196
1197 #help: Timers - enableautotimers
1198 msgctxt "#30704"
1199 msgid "When this is enabled there are some settings required on the set-top box to enable linking of AutoTimers (Timer Rules) to Timers in the Kodi UI. The addon attempts to set these automatically on boot."
1200 msgstr ""
1201
1202 #help: Timers - limitanychannelautotimers
1203 msgctxt "#30705"
1204 msgid "If last scanned groups are excluded attempt to limit new autotimers to either TV or Radio (dependent on channel used to create the autotimer). Note that if last scanned groups are enabled this is not possible and the setting will be ignored."
1205 msgstr ""
1206
1207 #help: Timers - limitanychannelautotimerstogroups
1208 msgctxt "#30706"
1209 msgid "For the channel used to create the autotimer limit to channel groups that this channel is a member of."
1210 msgstr ""
1211
1212 #empty strings from id 30707 to 30719
1213
1214 #help info - Timeshift
1215
1216 #help-category: timeshift
1217 msgctxt "#30720"
1218 msgid "This category cotains the settings for timeshift. Timeshifting allows you to pause live TV as well as move back and forward from your current position similar to playing back a recording. The buffer is deleted each time a channel is changed or stopped."
1219 msgstr ""
1220
1221 #help: Timeshift - enabletimeshift
1222 msgctxt "#30721"
1223 msgid "What timeshift option do you want: [Disabled] No timeshifting; [On Pause] Timeshifting starts when a live stream is paused. E.g. you want to continue from where you were at after pausing; [On Playback] Timeshifting starts when a live stream is opened. E.g. You can go to any point in the stream since it was opened."
1224 msgstr ""
1225
1226 #help: Timeshift - timeshiftbufferpath
1227 msgctxt "#30722"
1228 msgid "The path used to store the timeshift buffer. The default is the `addon_data/pvr.vuplus` folder in userdata."
1229 msgstr ""
1230
1231 #empty strings from id 30723 to 30739
1232
1233 #help info - Advanced
1234
1235 #help-category: advanced
1236 msgctxt "#30740"
1237 msgid "This category cotains advanced/expert settings"
1238 msgstr ""
1239
1240 #help: Advanced - prependoutline
1241 msgctxt "#30741"
1242 msgid "By default plot outline (short description on Enigma2) is not displayed in the UI. Can be displayed in EPG, Recordings or both. After changing this option you will need to clear the EPG cache `Settings->PVR & Live TV->Guide->Clear cache` for it to take effect."
1243 msgstr ""
1244
1245 #help: Advanced - powerstatemode
1246 msgctxt "#30742"
1247 msgid "If this option is set to a value other than `Disabled` then the addon will send a Powerstate command to the set-top box when Kodi will be closed (or the addon will be deactivated): [Disabled] No command sent when the addon exits; [Standby] Send the standby command on exit; [Deep standby] Send the deep standby command on exit. Note, the set-top box will not respond to Kodi after this command is sent; [Wakeup, then standby] Similar to standby but first sends a wakeup command. Can be useful if you want to ensure all streams have stopped. Note: if you use CEC this could cause your TV to wake."
1248 msgstr ""
1249
1250 #help: Advanced - readtimeout
1251 msgctxt "#30743"
1252 msgid "The timemout to use when trying to read live streams. Default for live streams is 0. Default for for timeshifting is 10 seconds."
1253 msgstr ""
1254
1255 #help: Advanced - streamreadchunksize
1256 msgctxt "#30744"
1257 msgid "The chunk size used by Kodi for streams. Default 0 to leave it to Kodi to decide."
1258 msgstr ""
1259
1260 #help: Advanced - debugnormal
1261 msgctxt "#30745"
1262 msgid "Debug log statements will display for the addon even though debug logging may not be enabled in Kodi. Note that all debug log statements will display at NOTICE level."
1263 msgstr ""
1264
1265 #help: Advanced - tracedebug
1266 msgctxt "#30746"
1267 msgid "Very detailed and verbose log statements will display in addition to standard debug statements. If enabled along with `Enable debug logging in normal mode` both trace and debug will display without debug logging enabled. In this case both debug and trace log statements will display at NOTICE level."
1268 msgstr ""
1269
1270 #help: Advanced - ignoredebug
1271 msgctxt "#30747"
1272 msgid "Debug log statements will not be displayed for the addon even though debug logging is enabled in Kodi. This can be useful when trying to debug an issue in Kodi which is not addon related."
1273 msgstr ""
1274
1275 #empty strings from id 30748 to 30759
1276
1277 #help info - Backend
1278
1279 #help-category: backend
1280 msgctxt "#30760"
1281 msgid "This category cotains advanced/expert settings"
1282 msgstr ""
1283
1284 #help: Backend - webifversion
1285 msgctxt "#30761"
1286 msgid "webifversion"
1287 msgstr ""
1288
1289 #help: Backend - autotimertagintags
1290 msgctxt "#30762"
1291 msgid "autotimertagintags"
1292 msgstr ""
1293
1294 #help: Backend - autotimernameintags
1295 msgctxt "#30763"
1296 msgid "autotimernameintags"
1297 msgstr ""
1298
1299 #help: Backend - globalstartpaddingstb
1300 msgctxt "#30764"
1301 msgid "globalstartpaddingstb"
1302 msgstr ""
1303
1304 #help: Backend - globalendpaddingstb
1305 msgctxt "#30765"
1306 msgid "globalendpaddingstb"
1307 msgstr ""
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: en_NZ\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname or IP address"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streaming Port"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Username"
3123 msgid "Password"
3224 msgstr "Password"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Connection"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Icons"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Response timeout in seconds"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Icon Path"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Update Interval in minutes"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatic Timerlist Cleanup"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webinterface Port"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap before channelswitch (i.e. for Single Tuner boxes)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Folder for channeldata"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Check for bouquet updates"
47 msgid "Update interval"
48 msgstr "Update interval"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Recording folder on the receiver"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Send DeepStandby-Command"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Fetch only one TV bouquet"
86 msgctxt "#30039"
87 msgid "Streaming"
88 msgstr "Streaming"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30042"
91 msgid "Never"
92 msgstr "Never"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Fetch picons from webinterface"
94 msgctxt "#30043"
95 msgid "In EPG only"
96 msgstr "In EPG only"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Use Secure HTTP (https)"
98 msgctxt "#30044"
99 msgid "In recordings only"
100 msgstr "In recordings only"
101
102 msgctxt "#30045"
103 msgid "Always"
104 msgstr "Always"
105
106 msgctxt "#30051"
107 msgid "Login"
108 msgstr "Login"
109
110 msgctxt "#30052"
111 msgid "Misc"
112 msgstr "Misc"
113
114 msgctxt "#30056"
115 msgid "TV"
116 msgstr "TV"
117
118 msgctxt "#30057"
119 msgid "Radio"
120 msgstr "Radio"
121
122 msgctxt "#30060"
123 msgid "Timeshift"
124 msgstr "Timeshift"
125
126 msgctxt "#30062"
127 msgid "Timeshift buffer path"
128 msgstr "Timeshift buffer path"
129
130 msgctxt "#30063"
131 msgid "Off"
132 msgstr "Off"
133
134 msgctxt "#30064"
135 msgid "On playback"
136 msgstr "On playback"
137
138 msgctxt "#30065"
139 msgid "On pause"
140 msgstr "On pause"
141
142 msgctxt "#30071"
143 msgid "Recordings"
144 msgstr "Recordings"
145
146 msgctxt "#30072"
147 msgid "Timers"
148 msgstr "Timers"
149
150 msgctxt "#30085"
151 msgid "OK"
152 msgstr "OK"
153
154 msgctxt "#30094"
155 msgid "N/A"
156 msgstr "N/A"
157
158 msgctxt "#30095"
159 msgid "True"
160 msgstr "True"
161
162 msgctxt "#30096"
163 msgid "False"
164 msgstr "False"
165
166 msgctxt "#30410"
167 msgid "Automatic"
168 msgstr "Automatic"
169
170 msgctxt "#30430"
171 msgid "Disabled"
172 msgstr "Disabled"
117173
118174 msgctxt "#30500"
119175 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname or IP address"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 hostname or IP address"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streaming Port"
23 msgid "Streaming port"
24 msgstr "Streaming port"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "Password"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Connection"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Icons"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Response timeout in seconds"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Icon Path"
47 msgid "Icon path"
48 msgstr "Icon path"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Update Interval"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Update Interval in minutes"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatic Timerlist Cleanup"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Automatic timerlist cleanup"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webinterface Port"
63 msgid "Web interface port"
64 msgstr "Web interface port"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap before channelswitch (i.e. for Single Tuner boxes)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Zap before channelswitch (i.e. for single tuner boxes)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Folder for channeldata"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Check for bouquet updates"
75 msgid "Update interval"
76 msgstr "Update interval"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Recording folder on the receiver"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Send DeepStandby-Command"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Send powerstate mode on addon exit"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Fetch only one TV bouquet"
115 msgid "TV bouquet fetch mode"
116 msgstr "TV bouquet fetch mode"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
119 msgid "TV bouquet"
120 msgstr "TV bouquet"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Fetch picons from webinterface"
123 msgid "Fetch picons from web interface"
124 msgstr "Fetch picons from web interface"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Use Secure HTTP (https)"
127 msgid "Use secure HTTP (https)"
128 msgstr "Use secure HTTP (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Enable automatic configuration for live streams"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Keep folder structure for records"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Seasons and Episodes"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Extract season, episode and year info where possible"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Enable autotimers"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Use picons.eu file format"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Enable generate repeat timers"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Log missing genre text mappings"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Web Interface"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Streaming"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Put outline (e.g. subtitle) before plot"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Stream read chunk size"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Never"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "In EPG only"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "In recordings only"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Always"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Extract show info file"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Rytec genre text Mappings"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Enable Rytec genre text mappings"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Rytec genre text mappings file"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Custom live TV timeout (0 to use default)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Login"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Misc"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Genre ID Mappings"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Enable genre ID Mappings"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Genre ID mappings file"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Radio bouquet fetch mode"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Radio bouquet"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Timeshift"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Enable timeshift"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Timeshift buffer path"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Off"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "On playback"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "On pause"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Use secure HTTP (https) for streams"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Use login for streams"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Fetch TV favorites bouquet"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Fetch radio favorites bouquet"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Recordings & Timers"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Recordings"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Timers"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Number of repeat timers to generate"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "All bouquets"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Only one bouquet"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "As first bouquet"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "As last bouquet"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Favorites group"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Favorites (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Favorites (Radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "unknown"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr " (Not connected!)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "addon error"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Enigma2 Media Server"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Backend"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Recording Padding"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Global start padding"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Global end padding"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Device Info"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "WebIf version"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "AutoTimer tag in timer tags"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "AutoTimer name in timer tags"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "N/A"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "True"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "False"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Standby"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Deep standby"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Wakeup, then standby"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Update mode"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Timers and recordings"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Timers only"
425
426 msgctxt "#30410"
427 msgid "Automatic"
428 msgstr "Automatic"
429
430 msgctxt "#30420"
431 msgid "One time (Scheduled by guide-based timer rule)"
432 msgstr "One time (Scheduled by guide-based timer rule)"
433
434 msgctxt "#30421"
435 msgid "One time (Scheduled by repeating timer rule)"
436 msgstr "One time (Scheduled by repeating timer rule)"
437
438 msgctxt "#30430"
439 msgid "Disabled"
440 msgstr "Disabled"
441
442 msgctxt "#30431"
443 msgid "Record if EPG title differs"
444 msgstr "Record if EPG title differs"
445
446 msgctxt "#30432"
447 msgid "Record if EPG title and short description differs"
448 msgstr "Record if EPG title and short description differs"
449
450 msgctxt "#30433"
451 msgid "Record if EPG title and all descriptions differ"
452 msgstr "Record if EPG title and all descriptions differ"
117453
118454 msgctxt "#30500"
119455 msgid "Disconnected from '%s'"
122458 msgctxt "#30501"
123459 msgid "Reconnected to '%s'"
124460 msgstr "Reconnected to '%s'"
461
462 msgctxt "#30514"
463 msgid "Timeshift buffer path does not exist"
464 msgstr "Timeshift buffer path does not exist"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2626 msgctxt "#30018"
2727 msgid "General"
2828 msgstr "Generalo"
29
30 msgctxt "#30042"
31 msgid "Never"
32 msgstr "Never"
33
34 msgctxt "#30063"
35 msgid "Off"
36 msgstr "Off"
37
38 msgctxt "#30085"
39 msgid "OK"
40 msgstr "Bone"
41
42 msgctxt "#30430"
43 msgid "Disabled"
44 msgstr "Disabled"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: es_AR\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nombre o dirección IP de VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Puerto streaming"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Usuario"
3123 msgid "Password"
3224 msgstr "Contraseña"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Conexión"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Iconos"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Tiempo de espera de respuesta en segundos"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Ruta del icono"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Intervalo de actualización en minutos"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Limpieza automática de Timerlist"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Puerto interface web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap antes de cambiar de canal (es decir, para las cajas de solo un sintonizador)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Carpeta para canales"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Buscar actualizaciones de bouquett"
47 msgid "Update interval"
48 msgstr "Intervalo de actualización"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Carpeta de grabaciones en el receptor"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Envíe el comando DeepStandby"
82 msgctxt "#30042"
83 msgid "Never"
84 msgstr "Nunca"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Buscar sólo TV bouquet"
86 msgctxt "#30043"
87 msgid "In EPG only"
88 msgstr "Sólo en EPG"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30044"
91 msgid "In recordings only"
92 msgstr "Sólo en grabaciones"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Obtener picons de la interfaz web"
94 msgctxt "#30045"
95 msgid "Always"
96 msgstr "Siempre"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Usar HTTP seguro (https)"
98 msgctxt "#30051"
99 msgid "Login"
100 msgstr "Ingresar"
101
102 msgctxt "#30056"
103 msgid "TV"
104 msgstr "TV"
105
106 msgctxt "#30057"
107 msgid "Radio"
108 msgstr "Radio"
109
110 msgctxt "#30060"
111 msgid "Timeshift"
112 msgstr "Timeshift"
113
114 msgctxt "#30062"
115 msgid "Timeshift buffer path"
116 msgstr "Ruta del buffer de Timeshift"
117
118 msgctxt "#30063"
119 msgid "Off"
120 msgstr "Desactivado"
121
122 msgctxt "#30071"
123 msgid "Recordings"
124 msgstr "Grabaciones"
125
126 msgctxt "#30072"
127 msgid "Timers"
128 msgstr "Temporizadores"
129
130 msgctxt "#30085"
131 msgid "OK"
132 msgstr "OK"
133
134 msgctxt "#30095"
135 msgid "True"
136 msgstr "Sí"
137
138 msgctxt "#30096"
139 msgid "False"
140 msgstr "Falso"
141
142 msgctxt "#30410"
143 msgid "Automatic"
144 msgstr "Automático"
145
146 msgctxt "#30430"
147 msgid "Disabled"
148 msgstr "Deshabilitado"
117149
118150 msgctxt "#30500"
119151 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nombre o dirección IP de VU+"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Dirección IP o nombre de equipo Enigma2"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Puerto streaming"
23 msgid "Streaming port"
24 msgstr "Puerto de emisión"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "Contraseña"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Conexión"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Iconos"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Tiempo de espera de respuesta en segundos"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Ruta del icono"
47 msgid "Icon path"
48 msgstr "Ruta de icono"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Intervalo de Actualización"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Intervalo de actualización en minutos"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Limpieza automática de temporizadores"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Limpiar automáticamente la lista de programaciones"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Puerto interface web"
63 msgid "Web interface port"
64 msgstr "Puerto de la interfaz web"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap antes de cambiar de canal (es decir, para las cajas de solo un sintonizador)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Zap antes de cambio de canal (p.e. para sintonizadores únicos)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Carpeta para canales"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Buscar actualizaciones de bouquett"
75 msgid "Update interval"
76 msgstr "Intervalo de actualización"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Carpeta de grabaciones en el receptor"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Enviar comando DeepStandby"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Enviar apagar al salir del add-on"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Buscar sólo un bouquet de TV"
115 msgid "TV bouquet fetch mode"
116 msgstr "Modo de conseguir ramo de TV"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Bouquet de TV"
119 msgid "TV bouquet"
120 msgstr "Ramo TV"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Obtener picons de la interfaz web"
123 msgid "Fetch picons from web interface"
124 msgstr "Conseguir picons de la interfaz web"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Usar HTTP seguro (https)"
127 msgid "Use secure HTTP (https)"
128 msgstr "Usar HTTP Seguro (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Actviar configuración automática para emisiones en directo"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Mantener estructura de carpetas para las grabaciones"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Temporadas y Capítulos"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Extraer información de temporada, episodio y año cuando sea posible"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Activar programaciones automáticas"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Usar formato de archivo picons.eu"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Activar generación de programaciones repetidas"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Registrar cuando género esté vacío"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Interfaz Web"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Streaming"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Poner frase (p.e. subtítulo) antes del argumento"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Tamaño de fragmento de lectura de emisión"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Nunca"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Solo con EPG"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Solo gravaciones"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Siempre"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Extraer fichero de información del programa"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Mapas Rytec para género"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Activa los mapeados de Rytec para el género"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Fichero de mapas Rytec para género"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Apagado de TV en directo personalizado (0 por defecto)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Inicio de sesión"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Otros"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Mapas de ID Género"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Activa los mapeados ID para el género"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Fichero de mapas ID para género"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Modo de conseguir ramo de radio"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Ramo de radio"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Timeshift"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Activar timeshift"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Ruta del buffer de Timeshift"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Desactivado"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Reproduciendo"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Pausado"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Usar HTTP seguro (https) para las emisiones"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Usar usuario para las emisiones"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Conseguir ramo de favoritos de TV"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Conseguir ramo de favoritos de radio"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Grabaciones y Programaciones"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Grabaciones"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Programaciones"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Número de repeticiones de programación a generar"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Todos los ramos"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Solo un ramo"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Como primer ramo"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Como último ramo"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Grupo de favoritos"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Favoritos (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Favoritos (Radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "desconocido"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(¡No conectado!)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "error de add-on"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Servidor de Contenido Enigma2"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Servidor"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Relleno de Grabación"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Relleno global al empezar"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Relleno global al terminar"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Info Dispositivo"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "Version WebIf"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "Etiqueta AutoTimer en etiquetas de programas"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "Nombre AutoTimer en etiquetas de programas"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "N/D"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Sí"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Falso"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Modo de espera"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Modo de espera profundo"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Despertar, después modo de espera"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Modo de actualización"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Programas y grabaciones"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Solo programas"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Usar ruta OpenWebIf"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Automático"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "Una vez (Programado por una regla basada en la guía)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "Una vez (Programada para repetir por regla de tiempo)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Desactivado"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Grabar si el título en EPG difiere"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Grabar aunque el título y la descripción corta en EPG difiera"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Grabar aunque el título y cualquier descripción en EPG difiera"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "Reconectado a '%s'"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "La ruta para el buffer de timeshift no existe"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2: Interfaz web inalcanzable"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2: Ningún grupo de canales encontrado"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2: Ningún canal encontrado"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nombre de host o dirección IP VU+"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Nombre de host o dirección IP de Enigma2"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Puerto de transmisión"
23 msgid "Streaming port"
24 msgstr "Puerto de steaming"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "Contraseña"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Conexión"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Iconos"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Tiempo de respuesta en segundos"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "Ruta del icono"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Intervalo de actualización"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Intervalo de actualización en minutos"
4557
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Limpieza automática de la lista de temporizadores"
49
5058 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Puerto interface web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap antes del conmutador de canales (ej., para las cajas de sintonizador simple)"
59 msgid "Web interface port"
60 msgstr "Puerto para interface web"
5761
5862 msgctxt "#30014"
5963 msgid "Folder for channeldata"
6064 msgstr "Carpeta de datos de canal"
6165
6266 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Revise las actualizaciones de bouquet"
67 msgid "Update interval"
68 msgstr "Intervalo de actualización."
6569
6670 msgctxt "#30016"
6771 msgid "Check for channel updates"
96100 msgstr "Carpeta de grabación en el receptor"
97101
98102 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Enviar comando DeepStandby"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Obtener sólo un ramo de TV"
105
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
109
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Obtener iconos de la interfaz web"
103 msgid "Send powerstate mode on addon exit"
104 msgstr "Envía mode powerstate sobre la salida del complemento"
113105
114106 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Use HTTP seguro (https)"
107 msgid "Use secure HTTP (https)"
108 msgstr "Usa HTTP seguro (https)"
109
110 msgctxt "#30029"
111 msgid "Enable automatic configuration for live streams"
112 msgstr "Activa configuración automática para live streams"
113
114 msgctxt "#30030"
115 msgid "Keep folder structure for records"
116 msgstr "Mantiene estructura de carpetas para grabaciones"
117
118 msgctxt "#30031"
119 msgid "Seasons and Episodes"
120 msgstr "Temporadas y Episodios"
121
122 msgctxt "#30032"
123 msgid "EPG"
124 msgstr "EPG"
125
126 msgctxt "#30033"
127 msgid "Extract season, episode and year info where possible"
128 msgstr "Extrae temporada, episodio e información del año donde sea posible"
129
130 msgctxt "#30035"
131 msgid "Use picons.eu file format"
132 msgstr "Usa formato de archivo picons.eu"
133
134 msgctxt "#30038"
135 msgid "Web Interface"
136 msgstr "Interface web"
137
138 msgctxt "#30039"
139 msgid "Streaming"
140 msgstr "Streaming"
141
142 msgctxt "#30042"
143 msgid "Never"
144 msgstr "Nunca"
145
146 msgctxt "#30043"
147 msgid "In EPG only"
148 msgstr "Sólo en EPG"
149
150 msgctxt "#30044"
151 msgid "In recordings only"
152 msgstr "solo en grabaciones"
153
154 msgctxt "#30045"
155 msgid "Always"
156 msgstr "Siempre"
157
158 msgctxt "#30046"
159 msgid "Extract show info file"
160 msgstr "Extrae información de la serie del archivo"
161
162 msgctxt "#30051"
163 msgid "Login"
164 msgstr "iniciar sesión"
165
166 msgctxt "#30052"
167 msgid "Misc"
168 msgstr "Misc"
169
170 msgctxt "#30056"
171 msgid "TV"
172 msgstr "TV"
173
174 msgctxt "#30057"
175 msgid "Radio"
176 msgstr "Radio"
177
178 msgctxt "#30060"
179 msgid "Timeshift"
180 msgstr "Cambio de hora"
181
182 msgctxt "#30062"
183 msgid "Timeshift buffer path"
184 msgstr "Ruta del buffer de TimeShift"
185
186 msgctxt "#30063"
187 msgid "Off"
188 msgstr "apagado"
189
190 msgctxt "#30064"
191 msgid "On playback"
192 msgstr "En reproducción"
193
194 msgctxt "#30065"
195 msgid "On pause"
196 msgstr "En pausa"
197
198 msgctxt "#30066"
199 msgid "Use secure HTTP (https) for streams"
200 msgstr "Usa HTTPS seguro (https) para streams"
201
202 msgctxt "#30067"
203 msgid "Use login for streams"
204 msgstr "Usa login para streams"
205
206 msgctxt "#30071"
207 msgid "Recordings"
208 msgstr "Grabaciones"
209
210 msgctxt "#30072"
211 msgid "Timers"
212 msgstr "Temporizadores"
213
214 msgctxt "#30078"
215 msgid "Favourites group"
216 msgstr "Grupo de favoritos"
217
218 msgctxt "#30079"
219 msgid "Favourites (TV)"
220 msgstr "Favoritos (TV)"
221
222 msgctxt "#30080"
223 msgid "Favourites (Radio)"
224 msgstr "Favoritos (Radio)"
225
226 msgctxt "#30081"
227 msgid "unknown"
228 msgstr "desconocido"
229
230 msgctxt "#30082"
231 msgid " (Not connected!)"
232 msgstr "(No conectado!)"
233
234 msgctxt "#30083"
235 msgid "addon error"
236 msgstr "Error de complemento"
237
238 msgctxt "#30084"
239 msgid "Enigma2 Media Server"
240 msgstr "Media Server Enigma2"
241
242 msgctxt "#30085"
243 msgid "OK"
244 msgstr "OK"
245
246 msgctxt "#30090"
247 msgid "Device Info"
248 msgstr "Información del dispositivo"
249
250 msgctxt "#30091"
251 msgid "WebIf version"
252 msgstr "Versión Weblf"
253
254 msgctxt "#30094"
255 msgid "N/A"
256 msgstr "N/A"
257
258 msgctxt "#30095"
259 msgid "True"
260 msgstr "Sí"
261
262 msgctxt "#30096"
263 msgid "False"
264 msgstr "Falso"
265
266 msgctxt "#30097"
267 msgid "Standby"
268 msgstr "En espera"
269
270 msgctxt "#30098"
271 msgid "Deep standby"
272 msgstr "Espera profunda"
273
274 msgctxt "#30099"
275 msgid "Wakeup, then standby"
276 msgstr "Despertar, entonces en espera"
277
278 msgctxt "#30100"
279 msgid "Update mode"
280 msgstr "Modo de actualización"
281
282 msgctxt "#30410"
283 msgid "Automatic"
284 msgstr "Automático"
285
286 msgctxt "#30430"
287 msgid "Disabled"
288 msgstr "Deshabilitado"
289
290 msgctxt "#30431"
291 msgid "Record if EPG title differs"
292 msgstr "Graba si los títulos son diferentes"
293
294 msgctxt "#30432"
295 msgid "Record if EPG title and short description differs"
296 msgstr "Graba si el titulo y la descripción corta del EPG son diferentes"
297
298 msgctxt "#30433"
299 msgid "Record if EPG title and all descriptions differ"
300 msgstr "Graba si el título y todas las descripciones del EPG son diferentes"
117301
118302 msgctxt "#30500"
119303 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: et_EE\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hosti nimi või IP aadress"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Voo port"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Kasutajanimi"
3123 msgid "Password"
3224 msgstr "Salasõna"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Ühendus"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikoonid"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Vastuse aegumine sekundites"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Ikooni asukoht"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Uuendamise intervall minutites"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Ajamõõtja loendi automaatne puhastus"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Veebiliidese port"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Enne kanali vahetamist kustutage (nt üksiktuunerite puhul)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Kanali info kaust"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Kontrollige kanalite uuendusi"
47 msgid "Update interval"
48 msgstr "Uuendamise vahemik"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Salvestus kaust vastuvõtjas"
9781
82 msgctxt "#30042"
83 msgid "Never"
84 msgstr "Mitte kunagi"
85
86 msgctxt "#30045"
87 msgid "Always"
88 msgstr "Alati"
89
90 msgctxt "#30051"
91 msgid "Login"
92 msgstr "Logi sisse"
93
94 msgctxt "#30056"
95 msgid "TV"
96 msgstr "TV"
97
98 msgctxt "#30057"
99 msgid "Radio"
100 msgstr "Raadio"
101
102 msgctxt "#30062"
103 msgid "Timeshift buffer path"
104 msgstr "Ajanihke puhverduse rada"
105
106 msgctxt "#30063"
107 msgid "Off"
108 msgstr "Väljas"
109
110 msgctxt "#30071"
111 msgid "Recordings"
112 msgstr "Salvestused"
113
114 msgctxt "#30072"
115 msgid "Timers"
116 msgstr "Taimerid"
117
118 msgctxt "#30085"
119 msgid "OK"
120 msgstr "OK"
121
122 msgctxt "#30095"
123 msgid "True"
124 msgstr "Nüüd saate lõõgastuda"
125
126 msgctxt "#30096"
127 msgid "False"
128 msgstr "Ei ole"
129
130 msgctxt "#30430"
131 msgid "Disabled"
132 msgstr "Keelatud"
133
98134 msgctxt "#30500"
99135 msgid "Disconnected from '%s'"
100136 msgstr "'%s' lahti ühendatud"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "Pasahitza"
2525
26 msgctxt "#30012"
27 msgid "Webinterface Port"
28 msgstr "Webinterface-aren Portua"
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Ikonoak"
29
30 msgctxt "#30015"
31 msgid "Update interval"
32 msgstr "Eguneraketa denbora-tartea"
2933
3034 msgctxt "#30018"
3135 msgid "General"
4246 msgctxt "#30021"
4347 msgid "HTTP"
4448 msgstr "HTTP"
49
50 msgctxt "#30042"
51 msgid "Never"
52 msgstr "Inoiz ez"
53
54 msgctxt "#30045"
55 msgid "Always"
56 msgstr "Beti"
57
58 msgctxt "#30051"
59 msgid "Login"
60 msgstr "Hasi saioa"
61
62 msgctxt "#30056"
63 msgid "TV"
64 msgstr "TB"
65
66 msgctxt "#30057"
67 msgid "Radio"
68 msgstr "Irratia"
69
70 msgctxt "#30060"
71 msgid "Timeshift"
72 msgstr "Denbora aldaketa"
73
74 msgctxt "#30063"
75 msgid "Off"
76 msgstr "Desgaituta"
77
78 msgctxt "#30071"
79 msgid "Recordings"
80 msgstr "Grabazioak"
81
82 msgctxt "#30072"
83 msgid "Timers"
84 msgstr "Programazioak"
85
86 msgctxt "#30085"
87 msgid "OK"
88 msgstr "Ados"
89
90 msgctxt "#30095"
91 msgid "True"
92 msgstr "Egia"
93
94 msgctxt "#30096"
95 msgid "False"
96 msgstr "Gezurra"
97
98 msgctxt "#30410"
99 msgid "Automatic"
100 msgstr "Automatikoa"
101
102 msgctxt "#30430"
103 msgid "Disabled"
104 msgstr "Desgaituta"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "کلمه عبور"
2525
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "اتصال"
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "عمومی"
3034 msgctxt "#30020"
3135 msgid "Advanced"
3236 msgstr "پیشرفته"
37
38 msgctxt "#30042"
39 msgid "Never"
40 msgstr "هرگز"
41
42 msgctxt "#30045"
43 msgid "Always"
44 msgstr "همیشه"
45
46 msgctxt "#30056"
47 msgid "TV"
48 msgstr "تلوزیون"
49
50 msgctxt "#30063"
51 msgid "Off"
52 msgstr "خاموش"
53
54 msgctxt "#30430"
55 msgid "Disabled"
56 msgstr "غیرفعال"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "رمز عبور"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "آیکون"
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "عمومی"
3842 msgctxt "#30021"
3943 msgid "HTTP"
4044 msgstr "HTTP"
45
46 msgctxt "#30042"
47 msgid "Never"
48 msgstr "هرگز"
49
50 msgctxt "#30045"
51 msgid "Always"
52 msgstr "همیشه"
53
54 msgctxt "#30051"
55 msgid "Login"
56 msgstr "ورود"
57
58 msgctxt "#30056"
59 msgid "TV"
60 msgstr "تلویزیون"
61
62 msgctxt "#30057"
63 msgid "Radio"
64 msgstr "رادیو"
65
66 msgctxt "#30063"
67 msgid "Off"
68 msgstr "خاموش"
69
70 msgctxt "#30071"
71 msgid "Recordings"
72 msgstr "ضبط شده ها"
73
74 msgctxt "#30085"
75 msgid "OK"
76 msgstr "تایید"
77
78 msgctxt "#30095"
79 msgid "True"
80 msgstr "درست"
81
82 msgctxt "#30430"
83 msgid "Disabled"
84 msgstr "غیر فعال"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+-isäntänimi tai ip-osoite"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2-palvelimen nimi tai ip-osoite"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Suoratoistoportti"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "Salasana"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Yhteys"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Logot"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Vastauksen aikakatkaisu sekunneissa"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Kanavalogojen polku"
47 msgid "Icon path"
48 msgstr "Kanavalogojen sijainti"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Päivitysväli"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Päivitysväli minuuteissa"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automaattinen ajastuslistan siivous"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Ajastuslistan automaattinen puhdistus"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
63 msgid "Web interface port"
5264 msgstr "Web-käyttöliittymän portti"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Lähetä vaihtokäsky ennen kanavan vaihtamista (yhden virittimen bokseille)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Zap ennen kanavan vaihtoa (yhden virittimen bokseille)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Kanavadatan kansio"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Tarkista kanavaryhmien päivitykset"
75 msgid "Update interval"
76 msgstr "Päivitysväli"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Vastaanottimen tallennuskansio"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Lähetä syväunikomento"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Lähetä virranhallintakäsky, kun lisäosa suljetaan"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Nouda vain yksi kanavaryhmä"
115 msgid "TV bouquet fetch mode"
116 msgstr "Tv-kanavaryhmien (bouquet) noutotapa"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Kanavaryhmän nimi"
119 msgid "TV bouquet"
120 msgstr "Kanavaryhmän nimi (bouquet)"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Nouda kanavalogot web-käyttöliittymästä"
123 msgid "Fetch picons from web interface"
124 msgstr "Nouda kanavalogot (picons) web-käyttöliittymästä"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
127 msgid "Use secure HTTP (https)"
116128 msgstr "Käytä suojattua HTTP:tä (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Käytä tv-lähetysten automaattiasetuksia"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Säilytä tallenteiden kansiorakenne"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Kaudet ja jaksot"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "Ohjelmaopas"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Kerää kausi-, jakso- ja vuositiedot, jos mahdollista"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Käytä automaattiajastuksia"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Käytä picons.eu:n tiedostomuotoa"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Käytä toistuvia ajastuksia"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Kirjaa puuttuvat määritykset lokitiedostoon"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Web-käyttöliittymä"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Suoratoisto"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Laita juonitiivistelmä juonen eteen"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Suoratoiston pakettikoko"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Ei koskaan"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Vain ohjelmaoppaassa"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Vain tallenteissa"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Aina"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Extract show info -tiedosto"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Rytecin genremääritykset"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Käytä Rytecin genremäärityksiä"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Rytecin genremääritysten tiedosto"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Tv-lähetyksen aikakatkaisu (0 on oletusarvo)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Käyttäjätunnus"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Muut"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Genre ID -määritykset"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Käytä genre ID -määrityksiä"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Genre ID -määritysten tiedosto"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "Tv"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Radion kanavaryhmien (bouquet) noutotapa"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Radion kanavaryhmä"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Ajansiirto"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Käytä ajansiirtoa"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Ajansiirtopuskurin polku"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Pois päältä"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Toiston aikana"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Tauon aikana"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Käytä suojattua HTTP:tä (https) suoratoistoon"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Suojaa suoratoisto käyttäjätunnuksilla"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Nouda tv:n suosikkiryhmä"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Nouda radion suosikkiryhmä"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Ajastus ja tallennus"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Tallenteet"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Ajastukset"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Toistuvien ajastusten määrä"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Kaikki"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Yksi"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Aseta ensimmäiseksi"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Aseta viimeiseksi"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Suosikkiryhmä"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Suosikit (Tv)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Suosikit (Radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "tuntematon"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Ei yhteyttä)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "lisäosavirhe"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Enigma2 Media Server"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Taustaosa"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Ajastuksen lisäaika"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Alkuun lisättävä aika"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Loppuun lisättävä aika"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Laitetiedot"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "Web-käyttöliittymän versio"
381
382 msgctxt "#30095"
383 msgid "True"
384 msgstr "On"
385
386 msgctxt "#30096"
387 msgid "False"
388 msgstr "Ei ole"
389
390 msgctxt "#30097"
391 msgid "Standby"
392 msgstr "Valmiustila"
393
394 msgctxt "#30098"
395 msgid "Deep standby"
396 msgstr "Horrostila"
397
398 msgctxt "#30099"
399 msgid "Wakeup, then standby"
400 msgstr "Herätys, jonka jälkeen lepotila"
401
402 msgctxt "#30100"
403 msgid "Update mode"
404 msgstr "Päivitystapa"
405
406 msgctxt "#30101"
407 msgid "Timers and recordings"
408 msgstr "Ajastukset ja tallenteet"
409
410 msgctxt "#30102"
411 msgid "Timers only"
412 msgstr "Vain ajastukset"
413
414 msgctxt "#30103"
415 msgid "Use OpenWebIf picon path"
416 msgstr "Käytä OpenWebIf:n picon-polkua"
417
418 msgctxt "#30410"
419 msgid "Automatic"
420 msgstr "Automaattinen"
421
422 msgctxt "#30420"
423 msgid "One time (Scheduled by guide-based timer rule)"
424 msgstr "Kerran (luotu ajastussäännöllä)"
425
426 msgctxt "#30421"
427 msgid "One time (Scheduled by repeating timer rule)"
428 msgstr "Kerran (luotu ajastussäännöllä)"
429
430 msgctxt "#30430"
431 msgid "Disabled"
432 msgstr "Ei käytössä"
433
434 msgctxt "#30431"
435 msgid "Record if EPG title differs"
436 msgstr "Tallenna, jos on eri ohjelmanimi"
437
438 msgctxt "#30432"
439 msgid "Record if EPG title and short description differs"
440 msgstr "Tallenna, jos ohjelman nimi ja jakso eroavat"
441
442 msgctxt "#30433"
443 msgid "Record if EPG title and all descriptions differ"
444 msgstr "Tallenna, jos ohjelman nimi, jakso ja juoni eroavat"
117445
118446 msgctxt "#30500"
119447 msgid "Disconnected from '%s'"
122450 msgctxt "#30501"
123451 msgid "Reconnected to '%s'"
124452 msgstr "Yhdistetty palvelimeen '%s'"
453
454 msgctxt "#30514"
455 msgid "Timeshift buffer path does not exist"
456 msgstr "Ajansiirtopuskurin polkua ei ole olemassa"
457
458 msgctxt "#30515"
459 msgid "Enigma2: Could not reach web interface"
460 msgstr "Enigma2: Web-käyttöliittymään ei saatu yhteyttä"
461
462 msgctxt "#30516"
463 msgid "Enigma2: No channel groups found"
464 msgstr "Enigma2: Kanavaryhmiä ei löytynyt"
465
466 msgctxt "#30517"
467 msgid "Enigma2: No channels found"
468 msgstr "Enigma2: Kanavia ei löytynyt"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "Loyniorð"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Ímyndir"
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "Vanligt"
3034 msgctxt "#30019"
3135 msgid "Channels"
3236 msgstr "Rás"
37
38 msgctxt "#30042"
39 msgid "Never"
40 msgstr "Ongantíð"
41
42 msgctxt "#30045"
43 msgid "Always"
44 msgstr "Altíð"
45
46 msgctxt "#30056"
47 msgid "TV"
48 msgstr "Sjónvarp"
49
50 msgctxt "#30057"
51 msgid "Radio"
52 msgstr "Útvarp"
53
54 msgctxt "#30063"
55 msgid "Off"
56 msgstr "Sløkk"
57
58 msgctxt "#30071"
59 msgid "Recordings"
60 msgstr "Upptøkur"
61
62 msgctxt "#30085"
63 msgid "OK"
64 msgstr "OK"
65
66 msgctxt "#30095"
67 msgid "True"
68 msgstr "Satt"
69
70 msgctxt "#30096"
71 msgid "False"
72 msgstr "Skeivt"
73
74 msgctxt "#30430"
75 msgid "Disabled"
76 msgstr "Sløkt"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nom d'hôte ou adresse IP de VU+"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Non d’hôte ou adresse IP d’Enigma2"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Port de diffusion en continu"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
28 msgstr "Nom d'utilisateur"
28 msgstr "Nom d’utilisateur"
2929
3030 msgctxt "#30004"
3131 msgid "Password"
3232 msgstr "Mot de passe"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Connexion"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Icônes"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Temporisation de réponse en secondes"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "Chemin des icônes"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Intervalle de mise à jour"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Intervalle de mise à jour en minutes"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
59 msgid "Automatic timerlist cleanup"
4860 msgstr "Nettoyage automatique de la liste des minuteries"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port de l'interface Web"
63 msgid "Web interface port"
64 msgstr "Port de l’interface Web"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
5668 msgstr "Passer les chaînes avant le changement effectif (c.-à-d. pour les boîtiers syntoniseurs simples)"
5769
5870 msgctxt "#30014"
6072 msgstr "Dossier des données de chaînes"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Vérifier les mises à jour du bouquet numérique"
75 msgid "Update interval"
76 msgstr "Intervalle de mise à jour"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
6981
7082 msgctxt "#30017"
7183 msgid "Use only the DVB boxes' current recording path"
72 msgstr "Utiliser seulement le chemin d'enregistrement actuel du boîtier DVB"
84 msgstr "Utiliser seulement le chemin d’enregistrement actuel du boîtier DVB"
7385
7486 msgctxt "#30018"
7587 msgid "General"
93105
94106 msgctxt "#30023"
95107 msgid "Recording folder on the receiver"
96 msgstr "Dossier d'enregistrement du récepteur"
108 msgstr "Dossier d’enregistrement du récepteur"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Envoyer la commande deepstandby"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Envoyer le mode d’alimentation en quittant l’addiciel"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Ne récupérer qu'un bouquet télé"
115 msgid "TV bouquet fetch mode"
116 msgstr "Mode de récupération du bouquet télé"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
119 msgid "TV bouquet"
108120 msgstr "Bouquet télé"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Récupérer les icônes de l'interface Web"
123 msgid "Fetch picons from web interface"
124 msgstr "Récupérer les picônes de l’interface Web"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
127 msgid "Use secure HTTP (https)"
116128 msgstr "Utiliser le HTTP sécurisé (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Activer la configuration automatique des diffusions en direct"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Conserver la structure de dossier pour les enregistrements"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Saisons et épisodes"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "GÉP"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Extraire les renseignements de saison, d’épisode et d’année si possible"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Activer les minuteries automatiques"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Utiliser le format de fichier picons.eu"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Activer la génération de minuteries de répétition"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Les mappages genre texte sont absents du journal"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Interface Web"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Diffusion en continu"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Mettre le contour (p. ex. les sous-titres) avant l’intrigue"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Taille des fragments de lecture du flux"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Jamais"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Dans le GÉP seulement"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Dans les enregistrements seulement"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Toujours"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Extraire le fichier d’informations sur l’émission"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Mappages genre texte de Rytec"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Activer les mappages genre texte de Rytec"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Fichier des mappages genre texte de Rytec"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Temporisation personnalisée de la télé en direct (0 pour la valeur par défaut)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Connexion"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Divers"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Mappages genre ID"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Activer les mappages genre ID"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Fichier des mappages genre ID"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "Télé"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Mode de récupération du bouquet radio"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Bouquet radio"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Décalage temporel"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Activer le décalage temporel"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Chemin du tampon de décalage temporel"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Arrêt"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Lecture"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Pause"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Utiliser le HTTP sécurisé (https) pour les flux"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Utiliser la connexion pour les flux"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Récupérer le bouquet des favoris télé"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Récupérer le bouquet des favoris radio"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Enregistrements et minuteries"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Enregistrements"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Minuteries"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Nombre de minuteries de répétition à générer"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Tous les bouquets"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Un seul bouquet"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Comme premier bouquet"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Comme dernier bouquet"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Groupe de favoris"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Favoris (télé)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Favoris (radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "inconnu"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Non connecté)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "Erreur d’addiciel"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Serveur multimédia Enigma2"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "Valider"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Dorsale"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Début/fin de l’enregistrement avant/après la diffusion prévue"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Global — Début de l’enregistrement avant la diffusion prévue"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Global — Fin de l’enregistrement après la diffusion prévue"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Informations sur le périphérique"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "Version de WebIf"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "Étiquette de la minuterie automatique dans les étiquettes de minuterie"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "Nom de la minuterie automatique dans les étiquettes de minuterie"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "ND"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Vrai"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Faux"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Veille"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Veille prolongée"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Réveil, puis mise en veille"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Mode de mise à jour"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Minuteries et enregistrements"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Minuteries seulement"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Utiliser le chemin des picônes d’OpenWebIf"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Automatiques"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "Une fois (planifiée par une règle de minuterie d’après le guide)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "Une fois (planifiée par la règle de la minuterie de répétition) "
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Désactivées"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Enregistrer si le titre du GÉP diffère"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Enregistrer si le titre et la description courte du GÉP diffèrent"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Enregistrer si le titre et toutes les descriptions du GÉP diffèrent"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "Se reconnecter à « %s »"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "Le chemin du tampon de décalage temporel n’existe pas"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2 : l’interface Web est inaccessible"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2 : aucun groupe de chaînes n’a été trouvé"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2 : aucune chaîne n’a été trouvée"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nom d'hôte VU+ ou adresse IP"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Nom d'hôte Enigma2 ou adresse IP"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Port du flux de diffusion"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "Mot de passe"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Connexion"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Icônes"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Temporisation de réponse en secondes"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "Chemin d'accès de l'icône"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Intervalle de mise à jour"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Intervalle de mise à jour en minutes"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
59 msgid "Automatic timerlist cleanup"
4860 msgstr "Nettoyage automatique de la liste de programmation"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
63 msgid "Web interface port"
5264 msgstr "Port de l'interface Web"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
5668 msgstr "Zapper avant le changement de chaîne (par ex. pour les appareils à tuner unique)"
5769
5870 msgctxt "#30014"
6072 msgstr "Dossier des données de chaîne"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Vérifier les mises à jour des bouquets"
75 msgid "Update interval"
76 msgstr "Intervalle de mise à jour"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Dossier d'enregistrement du récepteur"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Envoyer la commande de mise en veille profonde (DeepStandby)"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Envoyer le mode « powerstate » quand une extension quitte"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Ne rapporter qu'un bouquet TV"
115 msgid "TV bouquet fetch mode"
116 msgstr "Mode de récupération du bouquet TV"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
119 msgid "TV bouquet"
108120 msgstr "Bouquet TV"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Récupérer les icônes de l'interface Web "
123 msgid "Fetch picons from web interface"
124 msgstr "Récupérer les icônes depuis l'interface Web "
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
127 msgid "Use secure HTTP (https)"
116128 msgstr "Utiliser le HTTP sécurisé (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Activer la configuration automatique pour les flux en direct"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Conserver la structure des dossiers pour les enregistrements"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Saisons et épisodes"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "Guide électronique des programmes TV"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Extraire les infos de saison, d'épisode et d'année si possible"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Activer les programmations auto."
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Utiliser le format de fichier picons.eu"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Activer la génération des programmations répétées"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Journaliser les mappages manquant de textes de genres"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Interface Web"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Diffusion par flux"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Placer le résumé (par ex. les sous-titres) avant l'intrigue"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Taille des blocs de flux de lecture diffusé"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Jamais"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Dans le guide des programmes seulement"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Dans les enregistrements seulement"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Toujours"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Extraire les informations de fichier"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Mappage de textes de genres Rytec"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Activer le mappage de textes de genres Rytec"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Fichier de mappage de textes de genres Rytec"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Temporisation personnalisée pour la TV en direct (0 pour la valeur prédéfinie)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Identification"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Divers"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Mappage des ID de genres"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Activer le mappage des ID de genres"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Fichier de mappage des ID de genres"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Mode de récupération du bouquet radio"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Bouquet radio"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Différé"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Activer le différé"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Chemin du tampon pour le différé"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Non"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "En lecture"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "En pause"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Utiliser le HTTP sécurisé (https) pour la diffusion par flux"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Utiliser la connexion pour la diffusion par flux"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Récupérer le bouquet des favoris TV"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Récupérer le bouquet des favoris radio"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Enregistrements et programmation"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Enregistrements"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Programmations"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Nombre de programmations répétées à générer"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Tous les bouquets"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Un seul bouquet"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Comme premier bouquet"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Comme dernier bouquet"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Groupes des favoris"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Favoris (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Favoris (radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "inconnu"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Non connecté)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "erreur de l'extension"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Serveur de média Enigma2"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Serveur"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Remplissage de l'enregistrement"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Remplissage global de début"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Remplissage global de fin"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Infos sur le phériphérique"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "Version WebIf"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "Balise AutoTimer dans les balises de programmation"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "Nom AutoTimer dans les balises de programmation"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "N/D"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Vrai"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Faux"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Mise en attente"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Mise en attente profonde"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Réveil puis mise en attendre"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Mode de mise à jour"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Programmations et enregistrements"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Programmations seules"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Utiliser le chemin des picon OpenWebIf"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Automatique"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "Une fois (planifiée par une règle de programmation du guide)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "Une fois (planifiée par une règle de programmation répétée)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Désactivé"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Enregistrer si le titre du guide (EPG) diffère"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Enregistrer si le titre et la description courte du guide (EPG) diffèrent"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Enregistrer si le titre et toutes les descriptions du guide (EPG) diffèrent"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "Reconnecté à « %s »"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "Le chemin du tampon pour le différé n'existe pas"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2 : interface Web introuvable"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2 : aucun groupe de chaînes trouvé"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2 : aucune chaîne trouvée"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: gl_ES\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nome de host ou enderezo IP de VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Porto de transmisión"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Nome de usuario"
3123 msgid "Password"
3224 msgstr "Contrasinal"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Conexión"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Iconas"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Tempo de espera da resposta en segundos"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Camiño da icona"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Intervalo de actualización en minutos"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Limpeza automática da Timerlist"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Porto da interface web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap antes de trocar de canle (útil para caixas cun só sintonizador)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Cartafol para channeldata"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Verificar actualizacións de bouquett"
47 msgid "Update interval"
48 msgstr "Intervalo de actualización"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Cartafol de gravacións no receptor"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Enviar comando de Standby profundo"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "Guía"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Obter só un TV bouquet"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Nunca"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "Só na Guía"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Obter picons da interface web"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Só nas gravacións"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Usar HTTP Seguro (https)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "Sempre"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Usuario"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Miscelánea"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "TV"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Radio"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Timeshift"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Ruta do búfer do Timeshift"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Apagado"
129
130 msgctxt "#30064"
131 msgid "On playback"
132 msgstr "En reprodución"
133
134 msgctxt "#30065"
135 msgid "On pause"
136 msgstr "En Pausa"
137
138 msgctxt "#30071"
139 msgid "Recordings"
140 msgstr "Gravacións"
141
142 msgctxt "#30072"
143 msgid "Timers"
144 msgstr "Temporizadores"
145
146 msgctxt "#30085"
147 msgid "OK"
148 msgstr "Aceptar"
149
150 msgctxt "#30094"
151 msgid "N/A"
152 msgstr "N/D"
153
154 msgctxt "#30095"
155 msgid "True"
156 msgstr "Verdadeiro"
157
158 msgctxt "#30096"
159 msgid "False"
160 msgstr "Falso"
161
162 msgctxt "#30410"
163 msgid "Automatic"
164 msgstr "Automático"
165
166 msgctxt "#30430"
167 msgid "Disabled"
168 msgstr "Desactivado"
117169
118170 msgctxt "#30500"
119171 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: he_IL\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "שם מארח או כתובת IP"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "פורט הזרמה"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "שם משתמש"
3123 msgid "Password"
3224 msgstr "סיסמה"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "חיבור"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "סמלים"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "זמן המתנה מירבי לתגובה בשניות"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "נתיב סמלי ערוצים"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "מרווח זמני עדכונים בדקות"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "ניקוי רשימת תזמונים אוטומטית"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "פורט ממשק רשת"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "העבר ערוץ במכשיר לפני העברה ב־Kodi (מכשיר בעל מקלט בודד)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "תיקיית נתוני ערוצים"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "חיפוש עדכוני סל ערוצים"
47 msgid "Update interval"
48 msgstr "מרווח זמני עדכונים"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "תיקיית הקלטות בשרת אחורי"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "שלח פקודת שינה עמוקה"
82 msgctxt "#30029"
83 msgid "Enable automatic configuration for live streams"
84 msgstr "הפעל תצורה אוטומטית עבור הזרמת שידורים חיים"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "משוך סל ערוצים יחיד בלבד"
86 msgctxt "#30030"
87 msgid "Keep folder structure for records"
88 msgstr "שמור על מבנה התיקיות עבור הרשומות"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "סל ערוצים"
90 msgctxt "#30032"
91 msgid "EPG"
92 msgstr "לוח שידורים"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "משוך סמלי ערוצים מממשק הדפדפן"
94 msgctxt "#30042"
95 msgid "Never"
96 msgstr "אף פעם"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "השתמש ב־HTTP מאובטח (https)"
98 msgctxt "#30043"
99 msgid "In EPG only"
100 msgstr "בלוח שידורים בלבד"
101
102 msgctxt "#30044"
103 msgid "In recordings only"
104 msgstr "בהקלטות בלבד"
105
106 msgctxt "#30045"
107 msgid "Always"
108 msgstr "תמיד"
109
110 msgctxt "#30051"
111 msgid "Login"
112 msgstr "שם משתמש"
113
114 msgctxt "#30052"
115 msgid "Misc"
116 msgstr "שונות"
117
118 msgctxt "#30056"
119 msgid "TV"
120 msgstr "טלוויזיה"
121
122 msgctxt "#30057"
123 msgid "Radio"
124 msgstr "רדיו"
125
126 msgctxt "#30060"
127 msgid "Timeshift"
128 msgstr "הסט זמן"
129
130 msgctxt "#30062"
131 msgid "Timeshift buffer path"
132 msgstr "נתיב חוצץ טיימשיפט"
133
134 msgctxt "#30063"
135 msgid "Off"
136 msgstr "כבוי"
137
138 msgctxt "#30064"
139 msgid "On playback"
140 msgstr "עם נגינה"
141
142 msgctxt "#30065"
143 msgid "On pause"
144 msgstr "עם השהיה"
145
146 msgctxt "#30071"
147 msgid "Recordings"
148 msgstr "הקלטות"
149
150 msgctxt "#30072"
151 msgid "Timers"
152 msgstr "תזמונים"
153
154 msgctxt "#30085"
155 msgid "OK"
156 msgstr "אישור"
157
158 msgctxt "#30095"
159 msgid "True"
160 msgstr "אמת"
161
162 msgctxt "#30096"
163 msgid "False"
164 msgstr "שקר"
165
166 msgctxt "#30410"
167 msgid "Automatic"
168 msgstr "אוטומטי"
169
170 msgctxt "#30430"
171 msgid "Disabled"
172 msgstr "מנוטרל"
117173
118174 msgctxt "#30500"
119175 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1919 msgid "Username"
2020 msgstr "उपयोगकर्ता नाम"
2121
22 msgctxt "#30006"
23 msgid "Icons"
24 msgstr "प्रतीक"
25
2226 msgctxt "#30018"
2327 msgid "General"
2428 msgstr "सामान्य"
2630 msgctxt "#30020"
2731 msgid "Advanced"
2832 msgstr "उन्नत"
33
34 msgctxt "#30063"
35 msgid "Off"
36 msgstr "से"
37
38 msgctxt "#30085"
39 msgid "OK"
40 msgstr "टेके"
41
42 msgctxt "#30430"
43 msgid "Disabled"
44 msgstr "विकलांग"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: hr_HR\n"
1616 "Plural-Forms: nplurals=3; plural=n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ naziv računala ili IP adresa"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Ulaz stremanja"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Korisničko ime"
3123 msgid "Password"
3224 msgstr "Lozinka"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Povezivanje"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikone"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Vrijeme odaziva u sekundama"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Putanja ikone"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Interval osvježavanja u minutama"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatsko čišćenje popisa zadanih snimanja"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Ulaz web sučelja"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Isključi prije promjene programa (za uređaje s jednim prijemnikom)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Mapa za podatke programa"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Provjeri nadopune buketa"
47 msgid "Update interval"
48 msgstr "Razdoblje nadopune"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Mapa snimanja na prijemniku"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Pošalji naredbu duboke pripravnosti"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG vodič"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Dohvati samo jedan TV buket"
86 msgctxt "#30039"
87 msgid "Streaming"
88 msgstr "Streamanje"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV buket"
90 msgctxt "#30042"
91 msgid "Never"
92 msgstr "Nikada"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Dohvati ikone iz web sučelja"
94 msgctxt "#30043"
95 msgid "In EPG only"
96 msgstr "Samo u EPG-u"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Koristi sigurni HTTP (https)"
98 msgctxt "#30044"
99 msgid "In recordings only"
100 msgstr "Samo u snimkama"
101
102 msgctxt "#30045"
103 msgid "Always"
104 msgstr "Uvijek"
105
106 msgctxt "#30051"
107 msgid "Login"
108 msgstr "Prijava"
109
110 msgctxt "#30052"
111 msgid "Misc"
112 msgstr "Ostalo"
113
114 msgctxt "#30056"
115 msgid "TV"
116 msgstr "Televizija"
117
118 msgctxt "#30057"
119 msgid "Radio"
120 msgstr "Radio"
121
122 msgctxt "#30060"
123 msgid "Timeshift"
124 msgstr "Vremensko premotavanje"
125
126 msgctxt "#30062"
127 msgid "Timeshift buffer path"
128 msgstr "Putanja međuspremnika premotavanja u vremenu"
129
130 msgctxt "#30063"
131 msgid "Off"
132 msgstr "Isključeno"
133
134 msgctxt "#30064"
135 msgid "On playback"
136 msgstr "Pri reprodukciji"
137
138 msgctxt "#30065"
139 msgid "On pause"
140 msgstr "Pri pauzi"
141
142 msgctxt "#30071"
143 msgid "Recordings"
144 msgstr "Snimke"
145
146 msgctxt "#30072"
147 msgid "Timers"
148 msgstr "Snimanja"
149
150 msgctxt "#30085"
151 msgid "OK"
152 msgstr "U redu"
153
154 msgctxt "#30094"
155 msgid "N/A"
156 msgstr "N/A"
157
158 msgctxt "#30095"
159 msgid "True"
160 msgstr "Istina"
161
162 msgctxt "#30096"
163 msgid "False"
164 msgstr "Nesipravan"
165
166 msgctxt "#30410"
167 msgid "Automatic"
168 msgstr "Automatski"
169
170 msgctxt "#30420"
171 msgid "One time (Scheduled by guide-based timer rule)"
172 msgstr "Jednom (zakazano rasporedom EPG vodiča)"
173
174 msgctxt "#30430"
175 msgid "Disabled"
176 msgstr "Onemogućeno"
177
178 msgctxt "#30431"
179 msgid "Record if EPG title differs"
180 msgstr "Snimi ako se EPG naslov razlikuje"
117181
118182 msgctxt "#30500"
119183 msgid "Disconnected from '%s'"
122186 msgctxt "#30501"
123187 msgid "Reconnected to '%s'"
124188 msgstr "Ponovno povezan s '%s'"
189
190 msgctxt "#30514"
191 msgid "Timeshift buffer path does not exist"
192 msgstr "Putanja međuspremnika premotavanja u vremenu ne postoji"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ Kiszolgálónév vagy IP cím"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 gazdanév vagy IP cím"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Sugárzási port"
23 msgid "Streaming port"
24 msgstr "Streaming port"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "Jelszó"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Kapcsolat"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Ikon"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Válasz időkorlát másodpercben"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Csatornaikonok elérési útvonala"
47 msgid "Icon path"
48 msgstr "Ikon útvonal"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Frissítési intervallum"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Frissítési intervallum percben"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Időzítő lista automatikus tisztítása"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Automatikus időzítő lista törlése"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Web-kezelőfelület port"
63 msgid "Web interface port"
64 msgstr "Webes felület port"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Áthangolás csatornaváltás elött (Egytuneres boxoknál)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Törölje csatornaváltás előtt (vagyis egytuneres dobozok esetében)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Csatornaadat mappa"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Csatonalista frissítés keresése"
75 msgid "Update interval"
76 msgstr "Frissítési intervallum"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Felvételi mappa a vevőn"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "DeepStandby parancs küldése"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Energiaellátási mód küldése kiegészítő kilépésekor"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Csak egy csatornalista letöltése"
115 msgid "TV bouquet fetch mode"
116 msgstr "TV-csokor letöltési mód"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-csatorna-csoport"
119 msgid "TV bouquet"
120 msgstr "TV csokor"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Webes ikonok használata"
123 msgid "Fetch picons from web interface"
124 msgstr "Vegye le a piconokat a webes felületről"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Titkosított HTTP haszálata (https)"
127 msgid "Use secure HTTP (https)"
128 msgstr "Használjon biztonságos HTTP-t (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Automatikus konfigurálás engedélyezése élő adásokhoz"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Felvételek mappaszerkezetének megtartása"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Évadok és epizódok"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Másolja ki az évad, epizód és az év adatait, ha lehetséges"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Engedélyezze az automatikus időzítőt"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Használja a picons.eu fájlformátumot"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Engedélyezze az ismétlődő időzítők létrehozását"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Naplózó: hiányzik a műfaj szövegének leképezése"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Webes felület"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Adatfolyam"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Vázlat (pl. sub-title) felvétele a megjelenés előtt"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Stream olvasott darab méret"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Soha"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "csak az EPG-ben"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Csak a felvételekben"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Mindig"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Műsorinfo fájl kimásolása"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Rytec műfaj szöveg leképezések"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Engedélyezze a Rytec műfaj szövegének leképezését"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Rytec műfaj szöveg leképezés fájl"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Egyéni élő TV időtúllépés (0 az alapértelmezett használatához)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Bejelentkezés"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Egyéb"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Műfajazonosító leképezések"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Engedélyezze a műfajazonosító leképezését"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Műfajazonosító leképezés fájl"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Rádió"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Rádió csokor letöltési mód"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Rádió csokor"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Csúsztatott felvétel"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Engedélyezze az időcsúsztatást"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Csúsztatott élőkép tároló útvonala"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Ki"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Lejátszáskor"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Szüneteltetéskor"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Használjon biztonságos HTTP (https) protokollokat"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Jelentkezzen be a streamekhez"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Töltse le a TV-kedvencek csokorát"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Töltse le a rádió kedvencek csokorát"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Felvételek és időzítők"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Felvételek"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Időzítők"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "A létrehozandó ismétlődő időzítők száma"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Összes csokor"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Egyetlen csokor"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Az első csokor"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Utolsó csokor"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Kedvencek csoport"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Kedvencek (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Kedvencek (Rádió)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "ismeretlen"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr " (Nincs csatlakoztatva)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "Kiegészítő hiba"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Enigma2 Média Szerver"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Háttér"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Rögzítés"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Globális kezdeti kitöltés"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Globális végső kitöltés"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Eszköz információ"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "WebIf verzió"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "Automatikus időzítő címke az időzítő címkékben"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "Automatikus időzítő neve időzítő címkékben"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "Nem elérhető"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Igaz"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Hamis"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Készenléti állapot"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Mély készenléti állapot"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Ébrestés, majd készenléti állapot"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Frissítési mód"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Időzítők és felvételek"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Csak időzítők"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Használja az OpenWebIf picon útvonalát"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Automatikus"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "Egyszeri alkalommal (ütemezett útmutató alapú időzítő szabály)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "Egyszeri (az időzített szabály ismétlése szerint ütemezve)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Letiltva"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Felvétel ha az EPG cím eltér"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Felvétel ha az EPG cím és a rövid leírás eltér egymástól"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Felvétel ha az EPG cím és az összes leírás eltér egymástól"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "'%s': Újrakapcsolódva"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "A Timeshift pufferút nem létezik"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2: Nem sikerült elérni a webes felületet"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2: Nincsenek csatornacsoportok"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2: Csatorna nem található"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1919 msgid "Password"
2020 msgstr "Գաղտնաբառ"
2121
22 msgctxt "#30006"
23 msgid "Icons"
24 msgstr "Նշաններ"
25
2226 msgctxt "#30018"
2327 msgid "General"
2428 msgstr "Գլխավոր"
29
30 msgctxt "#30051"
31 msgid "Login"
32 msgstr "Մուտք"
33
34 msgctxt "#30063"
35 msgid "Off"
36 msgstr "Անջատել"
37
38 msgctxt "#30085"
39 msgid "OK"
40 msgstr "Լավ"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: id_ID\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Hostname atau alamat IP VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Port pengaliran"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "NamaPengguna"
3123 msgid "Password"
3224 msgstr "Password"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Koneksi"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikon"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Timeout response dalam deti"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Path Ikon"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Interval update dalam menit"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Pembersihan TImerlist secara otomatis"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port antar-muka web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Matikan sebelum pindah kanal (Contohnya untuk Tuner tunggal)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Folder untuk data kanal"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Cek untuk pemuktahiran buket"
47 msgid "Update interval"
48 msgstr "Interval update"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Folder rekaman di penerima"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Kirim perintah DeepStandby-Command"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG "
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Hanya ambil satu buket TV"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Tidak Pernah"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Buket TV"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "di EPG saja"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Ambil picons dan antarmuka web"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Di perekaman saja"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Gunakan Secure HTTP (https)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "Selalu"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Masuk"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Misc"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "TV"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Radio"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Pergeseran waktu"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Path penyangga Timeshift"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Matikan"
129
130 msgctxt "#30071"
131 msgid "Recordings"
132 msgstr "Perekaman"
133
134 msgctxt "#30085"
135 msgid "OK"
136 msgstr "OK"
137
138 msgctxt "#30095"
139 msgid "True"
140 msgstr "Ya"
141
142 msgctxt "#30096"
143 msgid "False"
144 msgstr "Salah"
145
146 msgctxt "#30430"
147 msgid "Disabled"
148 msgstr "Non Aktif"
117149
118150 msgctxt "#30500"
119151 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nafn eða IP vistfang VU+ hýsingar"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Nafn eða IP-vistfang á Enigma2"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Gátt streymis"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "Lykilorð"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Tenging"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Tákn"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Tímatakmörk svartíma í sekúndum"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "Slóð táknmynda"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Bið milli uppfærslna"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Uppfærslutími í mínútum"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
59 msgid "Automatic timerlist cleanup"
4860 msgstr "Sjálfvirk hreinsun á tímatökulista"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
63 msgid "Web interface port"
5264 msgstr "Gátt vefviðmóts"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
5668 msgstr "Bið á milli rásaskipta (þ.e. fyrir box með einum móttakara)"
5769
5870 msgctxt "#30014"
6072 msgstr "Mappa fyrir rásargögn"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Athuga með uppfærslur knippa"
75 msgid "Update interval"
76 msgstr "Bið milli uppfærslna"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
95107 msgid "Recording folder on the receiver"
96108 msgstr "Upptökumappa á móttakaranum"
97109
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Senda DjúpurSvefn-skipun"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Sækja aðeins eitt sjónvarpsknippi"
105
106110 msgctxt "#30026"
107 msgid "TV-Bouquet"
111 msgid "TV bouquet"
108112 msgstr "Sjónvarps-knippi"
109113
110114 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
115 msgid "Fetch picons from web interface"
112116 msgstr "Sækja 'picon' frá vefviðmóti"
113117
114118 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
119 msgid "Use secure HTTP (https)"
116120 msgstr "Nota öruggara HTTP (https)"
121
122 msgctxt "#30029"
123 msgid "Enable automatic configuration for live streams"
124 msgstr "Virkja sjálfvirka uppsetningu á beinu streymi"
125
126 msgctxt "#30030"
127 msgid "Keep folder structure for records"
128 msgstr "Halda möppuskipulagi fyrir plötur"
129
130 msgctxt "#30031"
131 msgid "Seasons and Episodes"
132 msgstr "Þáttaraðir og þættir"
133
134 msgctxt "#30032"
135 msgid "EPG"
136 msgstr "Rafrænn EPG-sjónvarpsvísir"
137
138 msgctxt "#30038"
139 msgid "Web Interface"
140 msgstr "Vefviðmót"
141
142 msgctxt "#30039"
143 msgid "Streaming"
144 msgstr "Streymi"
145
146 msgctxt "#30040"
147 msgid "Put outline (e.g. sub-title) before plot"
148 msgstr "Setja upplýsingar (t.d. skjátexta) á undan söguþræði"
149
150 msgctxt "#30041"
151 msgid "Stream read chunk size"
152 msgstr "Stærð lesbúts streymis"
153
154 msgctxt "#30042"
155 msgid "Never"
156 msgstr "Aldrei"
157
158 msgctxt "#30043"
159 msgid "In EPG only"
160 msgstr "Aðeins í rafrænum EPG-dagskrárvísum"
161
162 msgctxt "#30044"
163 msgid "In recordings only"
164 msgstr "Aðeins í upptökum"
165
166 msgctxt "#30045"
167 msgid "Always"
168 msgstr "Alltaf"
169
170 msgctxt "#30046"
171 msgid "Extract show info file"
172 msgstr "Veiða upplýsingar um myndskeið úr skrá"
173
174 msgctxt "#30050"
175 msgid "Custom live TV timeout (0 to use default)"
176 msgstr "Sérsniðin tímamörk beinnar sjónvarpsútsendingar (0 til að nota sjálfgefið)"
177
178 msgctxt "#30051"
179 msgid "Login"
180 msgstr "Innskrá"
181
182 msgctxt "#30052"
183 msgid "Misc"
184 msgstr "Ýmislegt"
185
186 msgctxt "#30056"
187 msgid "TV"
188 msgstr "Sjónvarp"
189
190 msgctxt "#30057"
191 msgid "Radio"
192 msgstr "Útvarp"
193
194 msgctxt "#30059"
195 msgid "Radio bouquet"
196 msgstr "Útvarps-knippi"
197
198 msgctxt "#30060"
199 msgid "Timeshift"
200 msgstr "Tímaflakk"
201
202 msgctxt "#30061"
203 msgid "Enable timeshift"
204 msgstr "Virkja tímaflakk"
205
206 msgctxt "#30062"
207 msgid "Timeshift buffer path"
208 msgstr "Slóð á biðminni tímahliðrunar"
209
210 msgctxt "#30063"
211 msgid "Off"
212 msgstr "Slökkt"
213
214 msgctxt "#30064"
215 msgid "On playback"
216 msgstr "Við afspilun"
217
218 msgctxt "#30065"
219 msgid "On pause"
220 msgstr "Við bið"
221
222 msgctxt "#30066"
223 msgid "Use secure HTTP (https) for streams"
224 msgstr "Nota öruggara HTTP (https) fyrir streymi"
225
226 msgctxt "#30067"
227 msgid "Use login for streams"
228 msgstr "Nota innskráningu fyrir streymi"
229
230 msgctxt "#30068"
231 msgid "Fetch TV favourites bouquet"
232 msgstr "Sækja knippi af sjónvarpseftirlætum"
233
234 msgctxt "#30069"
235 msgid "Fetch radio favourites bouquet"
236 msgstr "Sækja knippi af útvarpseftirlætum"
237
238 msgctxt "#30070"
239 msgid "Recordings & Timers"
240 msgstr "Upptökur og tímatökur"
241
242 msgctxt "#30071"
243 msgid "Recordings"
244 msgstr "Upptökur"
245
246 msgctxt "#30072"
247 msgid "Timers"
248 msgstr "Tímatökur"
249
250 msgctxt "#30074"
251 msgid "All bouquets"
252 msgstr "Öll knippi"
253
254 msgctxt "#30075"
255 msgid "Only one bouquet"
256 msgstr "Aðeins eitt knippi"
257
258 msgctxt "#30076"
259 msgid "As first bouquet"
260 msgstr "Sem fyrsta knippi"
261
262 msgctxt "#30077"
263 msgid "As last bouquet"
264 msgstr "Sem síðasta knippi"
265
266 msgctxt "#30078"
267 msgid "Favourites group"
268 msgstr "Eftirlætahópur"
269
270 msgctxt "#30079"
271 msgid "Favourites (TV)"
272 msgstr "Eftirlæti (sjónvarp)"
273
274 msgctxt "#30080"
275 msgid "Favourites (Radio)"
276 msgstr "Eftirlæti (útvarp)"
277
278 msgctxt "#30081"
279 msgid "unknown"
280 msgstr "óþekkt"
281
282 msgctxt "#30082"
283 msgid " (Not connected!)"
284 msgstr "(Engin tenging!)"
285
286 msgctxt "#30083"
287 msgid "addon error"
288 msgstr "villa í viðbót"
289
290 msgctxt "#30085"
291 msgid "OK"
292 msgstr "Í lagi"
293
294 msgctxt "#30086"
295 msgid "Backend"
296 msgstr "Bakendi"
297
298 msgctxt "#30090"
299 msgid "Device Info"
300 msgstr "Upplýsingar um tæki"
301
302 msgctxt "#30091"
303 msgid "WebIf version"
304 msgstr "Útgáfa WebIf"
305
306 msgctxt "#30094"
307 msgid "N/A"
308 msgstr "E/T"
309
310 msgctxt "#30095"
311 msgid "True"
312 msgstr "Satt"
313
314 msgctxt "#30096"
315 msgid "False"
316 msgstr "Ósatt"
317
318 msgctxt "#30097"
319 msgid "Standby"
320 msgstr "Biðstaða"
321
322 msgctxt "#30410"
323 msgid "Automatic"
324 msgstr "Sjálfvirkt"
325
326 msgctxt "#30420"
327 msgid "One time (Scheduled by guide-based timer rule)"
328 msgstr "Eins-skiptis (sett á með tímatökureglu frá dagsrárvísi)"
329
330 msgctxt "#30421"
331 msgid "One time (Scheduled by repeating timer rule)"
332 msgstr "Eins-skiptis (sett á með endurtekinni tímatökureglu)"
333
334 msgctxt "#30430"
335 msgid "Disabled"
336 msgstr "Óvirkt"
337
338 msgctxt "#30431"
339 msgid "Record if EPG title differs"
340 msgstr "Taka upp ef titill í EPG-dagskrárvísi er öðruvísi"
341
342 msgctxt "#30432"
343 msgid "Record if EPG title and short description differs"
344 msgstr "Taka upp ef mismunur er á titli og lýsingu í EPG-dagskrárvísi"
345
346 msgctxt "#30433"
347 msgid "Record if EPG title and all descriptions differ"
348 msgstr "Taka upp ef mismunur er á titli og lýsingum í EPG-dagskrárvísi"
117349
118350 msgctxt "#30500"
119351 msgid "Disconnected from '%s'"
122354 msgctxt "#30501"
123355 msgid "Reconnected to '%s'"
124356 msgstr "Tengdur við '%s'"
357
358 msgctxt "#30514"
359 msgid "Timeshift buffer path does not exist"
360 msgstr "Slóð á biðminni tímahliðrunar er ekki til"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: it_IT\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nome host o indirizzo IP VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Porta per lo streaming"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Nome utente"
3123 msgid "Password"
3224 msgstr "Password"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Connessione"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Icone"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Timeout di risposta in secondi"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Percorso dell'icona"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Intervallo di aggiornamento in minuti"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Pulizia automatica della lista dei timer"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Porta dell'interfaccia web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap prima del cambio canale (ad es: per i dispositivi con sintonizzatore singolo)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Cartella per i dati dei canali"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Controlla aggiornamenti dei bouquet"
47 msgid "Update interval"
48 msgstr "Intervallo aggiornamento"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Cartella per le registrazioni del ricevitore"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Invia comando di DeepStandby"
82 msgctxt "#30029"
83 msgid "Enable automatic configuration for live streams"
84 msgstr "Abilita configurazione automatica per trasmissioni in diretta"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Prendi un solo bouquet TV"
86 msgctxt "#30030"
87 msgid "Keep folder structure for records"
88 msgstr "Mantieni la struttura delle cartelle per i record"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Bouquet TV"
90 msgctxt "#30032"
91 msgid "EPG"
92 msgstr "EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Raccogli picons dall'interfaccia web"
94 msgctxt "#30042"
95 msgid "Never"
96 msgstr "Mai"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Utilizza HTTP Sicuro (https)"
98 msgctxt "#30043"
99 msgid "In EPG only"
100 msgstr "Solo in EPG"
101
102 msgctxt "#30044"
103 msgid "In recordings only"
104 msgstr "Solo in registrazione"
105
106 msgctxt "#30045"
107 msgid "Always"
108 msgstr "Sempre"
109
110 msgctxt "#30051"
111 msgid "Login"
112 msgstr "Login"
113
114 msgctxt "#30052"
115 msgid "Misc"
116 msgstr "Varie"
117
118 msgctxt "#30056"
119 msgid "TV"
120 msgstr "TV"
121
122 msgctxt "#30057"
123 msgid "Radio"
124 msgstr "Radio"
125
126 msgctxt "#30060"
127 msgid "Timeshift"
128 msgstr "Timeshift"
129
130 msgctxt "#30062"
131 msgid "Timeshift buffer path"
132 msgstr "Path per il buffer del timeshift"
133
134 msgctxt "#30063"
135 msgid "Off"
136 msgstr "Off"
137
138 msgctxt "#30064"
139 msgid "On playback"
140 msgstr "In riproduzione"
141
142 msgctxt "#30065"
143 msgid "On pause"
144 msgstr "In pausa"
145
146 msgctxt "#30071"
147 msgid "Recordings"
148 msgstr "Registrazioni"
149
150 msgctxt "#30072"
151 msgid "Timers"
152 msgstr "Timer"
153
154 msgctxt "#30085"
155 msgid "OK"
156 msgstr "OK"
157
158 msgctxt "#30094"
159 msgid "N/A"
160 msgstr "N.D"
161
162 msgctxt "#30095"
163 msgid "True"
164 msgstr "Vero"
165
166 msgctxt "#30096"
167 msgid "False"
168 msgstr "Falso"
169
170 msgctxt "#30410"
171 msgid "Automatic"
172 msgstr "Automatico"
173
174 msgctxt "#30430"
175 msgid "Disabled"
176 msgstr "Disabilitato"
117177
118178 msgctxt "#30500"
119179 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: ja_JP\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ のホスト名または IPアドレス"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "ストリーミングのポート番号"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "ユーザー名"
3123 msgid "Password"
3224 msgstr "パスワード"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "接続"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "アイコン"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "レスポンスのタイムアウト (秒)"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "アイコンのパス"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "更新間隔 (分)"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "タイマーリストの自動クリーンアップ"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Web インターフェースのポート番号"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "チャンネル切り替えの前にザッピングする (つまり、シングルチューナーボックス用)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "チャンネルデータのフォルダー"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "ブーケの更新を確認"
47 msgid "Update interval"
48 msgstr "更新間隔"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "レシーバーの録画フォルダー"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "ディープスタンバイコマンドを送る"
82 msgctxt "#30042"
83 msgid "Never"
84 msgstr "使用しない"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "ひとつのTV ブーケのみ取得"
86 msgctxt "#30045"
87 msgid "Always"
88 msgstr "常に"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-ブーケ"
90 msgctxt "#30051"
91 msgid "Login"
92 msgstr "ログイン"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "ウェブインターフェースからpiconを取得"
94 msgctxt "#30056"
95 msgid "TV"
96 msgstr "テレビ"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Secure HTTP (https) を使用する"
98 msgctxt "#30057"
99 msgid "Radio"
100 msgstr "ラジオ"
101
102 msgctxt "#30062"
103 msgid "Timeshift buffer path"
104 msgstr "タイムシフト用バッファのパス"
105
106 msgctxt "#30063"
107 msgid "Off"
108 msgstr "オフ"
109
110 msgctxt "#30071"
111 msgid "Recordings"
112 msgstr "録音"
113
114 msgctxt "#30072"
115 msgid "Timers"
116 msgstr "タイマー"
117
118 msgctxt "#30085"
119 msgid "OK"
120 msgstr "OK"
121
122 msgctxt "#30095"
123 msgid "True"
124 msgstr "True"
125
126 msgctxt "#30096"
127 msgid "False"
128 msgstr "False"
129
130 msgctxt "#30430"
131 msgid "Disabled"
132 msgstr "無効"
117133
118134 msgctxt "#30500"
119135 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ 호스트네임 또는 IP 주소"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 호스트명이나 IP 주소"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "스트리밍 포트"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "비밀번호"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "연결"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "아이콘"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "응답 제한시간 (초)"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "아이콘 경로"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "간격 업데이트"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "업데이트 주기 (분)"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "타임시프트 자동 정리"
59 msgid "Automatic timerlist cleanup"
60 msgstr "자동 타이머 항목 지움"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "웹인터페이스 포트"
63 msgid "Web interface port"
64 msgstr "웹 인터페이스 포트"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "채널변경전 삭제 (Single Tuner boxes등을 위해)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "채널 변경 전에 빠르게 변경 (하나의 튜너 박스의 경우)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "채널 데이터 폴더"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "묶음 업데이트 확인"
75 msgid "Update interval"
76 msgstr "업데이트 주기"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "리시버 녹화 폴더"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "DeepStandby-Command 보내기"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "애드온을 나갈 때 전원 상태 모드 보내기"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "하나의 TV 묶음만 가져오기"
115 msgid "TV bouquet fetch mode"
116 msgstr "TV 부케 가져오기 모드"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV 묶음"
119 msgid "TV bouquet"
120 msgstr "TV 부케"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "웹인터페이스로 부터 아이콘들을 가져옴"
123 msgid "Fetch picons from web interface"
124 msgstr "웹 인터페이스에서 picons 가져오기"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "암호화된 HTTP (https) 사용"
127 msgid "Use secure HTTP (https)"
128 msgstr "안전한 HTTP (https) 사용"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "라이브 스트림에 자동 설정 사용"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "녹화에 폴더 구조 유지"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "시즌과 에피소드"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "시즌, 에피소드와 가능하면 연도 정보 추출"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "자동 타이머 사용"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "picons.eu 파일 포맷 사용"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "반복 타이머 생성 사용"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "장르 텍스트 매핑 로그 없음"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "웹 인터페이스"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "스트리밍"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "줄거리 앞에 개요 (예. 부제) 넣기"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "스트림 읽기 청크 크기"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "사용 안 함"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "EPG에서만"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "녹화 중에만"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "항상"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "쇼 정보 파일 추출"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Rytec 장르 텍스트 매핑"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Rytec 장르 텍스트 매핑 사용"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Rytec 장르 텍스트 매핑 파일"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "사용자 라이브 TV 마침 (0은 기본 값)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "로그인"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "기타"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "장르 ID 매핑"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "장르 ID 매핑 사용"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "장르 ID 매핑 파일"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "라디오"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "라디오 부케 가져오기 모드"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "라디오 부케"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "타임시프트"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "시간차 시청 사용"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "타임시프트 버퍼 경로"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "끔"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "재생 중"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "중지"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "스트림에 안전한 HTTP (https) 사용"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "스트림에 로그인 사용"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "TV 즐겨찾기 부케 가져오기"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "라디오 즐겨찾기 부케 가져오기"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "녹화와 타이머"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "녹화"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "녹화 예약"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "생성할 반복 타이머 숫자"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "모든 부케"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "한 부케"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "처음 부케로"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "마지막 부케로"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "즐겨찾기 그룹"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "즐겨찾기 (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "즐겨찾기 (라디오)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "알 수 없음"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(연결 안됨!)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "애드온 오류"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Enigma2 미디어 서버"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "확인"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "백엔드"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "녹화 붙이기"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "전체 시작 붙이기"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "전체 종료 붙이기"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "장치 정보"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "WebIf 버전"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "타이머 태그의 자동 타이머 태그"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "타이머 태그의 자동 타이머 이름"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "사용할 수 없음"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "사실"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "없음"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "대기 모드"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "깊은 대기 모드"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "기동하고 대기 모드"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "업데이트 모드"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "타이머와 녹화"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "타이머만"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "OpenWebIf picon 경로 사용"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "자동"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "한 번 (편성표 기반 타이머 규정으로 예약)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "정시 (반복 타이머 규정으로 예약됨)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "사용 안 함"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "EPG 제목이 다르면 녹화"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "EPG 제목과 간략한 개요가 다르면 녹화"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "EPG 제목과 전체 개요가 다르면 녹화"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "'%s'에 다시 연결됨"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "시간차 시청 버퍼 경로가 없습니다"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2: 웹 인터페이스에 연결할 수 없음"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2: 채널 그룹 없음"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2: 채널 없음"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ kompiuterio vardas arba IP adresas"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 kompiuterio vardas arba IP adresas"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Srauto prievadas"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "Slaptažodis"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Prijungimas"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Piktogramos"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Reakcijos laikas, sekundėmis"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "Piktogramos kelias"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Atnaujinimo intervalas"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Naujinimo intervalas minutėmis"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatinis 'Laikmačio Sąrašo' valymas"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Automatinis laikmačio sąrašo išvalymas"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Web sąsajos prievadas"
63 msgid "Web interface port"
64 msgstr "Žiniatinklio sąsajos prievadas"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap before channelswitch (i.e. for Single Tuner boxes)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Uždaryti prieš kanalo perjungimą (pvz., vieno imtuvo priedėliams)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Aplankas kanalo duomenims"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Patikrinkite paketo atnaujinimus"
75 msgid "Update interval"
76 msgstr "Atnaujinimo intervalas"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Įrašymo aplankas į imtuvą"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Siųsti 'Gilus budėjimo režimas' - Komandą"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Siųsti maitinimo būsenos režimą išjungiant priedą"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Išrinkta tik viena TV plokštė"
115 msgid "TV bouquet fetch mode"
116 msgstr "TV puokštės gavimo būdas"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Plokštė"
119 msgid "TV bouquet"
120 msgstr "TV puokštė"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Įkelti 'picons' iš interneto sąsajos"
123 msgid "Fetch picons from web interface"
124 msgstr "Įkelti piktogramas iš žiniatinklio sąsajos"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
127 msgid "Use secure HTTP (https)"
116128 msgstr "Naudoti saugų HTTP (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Įjungti automatinę vaizdo transliacijų konfigūraciją"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Išlaikyti aplanko struktūrą įrašams"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Sezonai ir epizodai"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Išgauti sezono, epizodo ir metų informaciją, jei įmanoma"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Įjungti automatinius laikmačius"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Naudoti picons.eu failo formatą"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Įjungti pakartotinių laikmačių generavimą"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Įrašyti į žurnalą trūkstamų žanrų teksto sužymėjimą"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Žiniatinklio sąsaja"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Transliuojama"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Įdėti pagrindinę informaciją (pvz., subtitrus) prieš siužetą"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Srauto skaitymo dalies dydis"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Niekada"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Tik EPG lange"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Tik įrašymuose"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Visada"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Išgauti laidos informacijos failą"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Rytec žanrų teksto sužymėjimas"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Įjungti Rytec žanrų teksto sužymėjimą"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Rytec žanrų teksto sužymėjimo failas"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Savas televizijos laukimo laikas (0 norint naudoti numatytąjį)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Prisijungimo vardas"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Įvairūs"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Žanrų ID sužymėjimas"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Įjungti žanrų ID sužymėjimą"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Žanrų ID sužymėjimo failas"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radijas"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Radijo puokštės gavimo būdas"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Radijo puokštė"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Laiko poslinkis"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Įjungti laiko poslinkį"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Laiko poslinkio buferio kelias"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Išjungta"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Atkuriant"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Pristabdžius"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Naudoti saugų HTTP (https) srautams"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Naudoti prisijungimą srautams"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Gauti TV mėgstamiausiųjų puokštę"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Gauti radijo mėgstamiausiųjų puokštę"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Įrašai ir laikmačiai"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Įrašai"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Laikmačiai"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Kartojimo laikmačių skaičius generavimui"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Visos puokštės"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Tik viena puokštė"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Kaip pirma puokštė"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Kaip paskutinė puokštė"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Mėgstamiausiųjų grupė"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Mėgstamiausieji (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Mėgstamiausieji (radijas)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "nežinomas"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Neprisijungta!)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "priedo klaida"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Enigma2 medijos serveris"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Posistemė"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Įrašo paraštė"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Globali pradžios paraštė"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Globali pabaigos paraštė"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Įrenginio informacija"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "WebIf versija"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "Automatinio laikmačio žymė laikmačio žymėse"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "Automatinio laikmačio pavadinimas laikmačio žymėse"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "N/A"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Taip"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Ne"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Budėjimo režimas"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Gilus budėjimo režimas"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Pažadinti, tada pereiti į budėjimo režimą"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Atnaujinimo režimas"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Laikmačiai ir įrašai"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Tik laikmačiai"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Naudoti OpenWebIf piktogramos kelią"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Automatiškai"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "Vieną kartą (suplanuota gidu paremtos laikmačio taisyklės)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "Vienkartinis (suplanuotas pasikartojančio laikmačio taisyklės)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Atjungta"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Įrašyti, jei skiriasi EPG pavadinimas"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Įrašyti jei EPG pavadinimas ir trumpas aprašymas skiriasi"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Įrašyti jei EPG pavadinimas ir visi aprašymai skiriasi"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "Prijungtas prie '%s'"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "Laiko poslinkio buferio kelias neegzistuoja"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2: neįmanoma pasiekti žiniatinklio sąsajos"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2: kanalų grupių nerasta"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2: kanalų nerasta"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: lv_LV\n"
1616 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ saimniekvārds vai IP adrese"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Straumēšanas ports"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "LIetotājs"
3123 msgid "Password"
3224 msgstr "Parole"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Pieslēgums"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikonas"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Atbildes noilgums sekundēs"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Ikonu ceļš"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Atjaunināšanas intervāls minūtēs"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automātiska taimersaraksta uzkopšana"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Tīmekļa saskarnes ports"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Pārslēgt pirms kanāla pārslēgšanās (piem., viena uztvērēja pierīcēm)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Mape kanāldatiem"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Pārbaudīt buķetes atjauninājumus"
47 msgid "Update interval"
48 msgstr "Atjauninājuma intervāls"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Ierakstīšanas mape atskaņotājā"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Sūtīt \"dziļas gatavības\" komandu"
82 msgctxt "#30042"
83 msgid "Never"
84 msgstr "Nekad"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Iegūt tikai vienu TV buķeti"
86 msgctxt "#30043"
87 msgid "In EPG only"
88 msgstr "Tikai EPG"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-buķete"
90 msgctxt "#30044"
91 msgid "In recordings only"
92 msgstr "Tikai ierakstos"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Iegūt pikonas no tīmeklā saskarnes"
94 msgctxt "#30045"
95 msgid "Always"
96 msgstr "Vienmēr"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Izmantot drošo HTTP (https)"
98 msgctxt "#30051"
99 msgid "Login"
100 msgstr "Pieteikšanās"
101
102 msgctxt "#30056"
103 msgid "TV"
104 msgstr "TV"
105
106 msgctxt "#30057"
107 msgid "Radio"
108 msgstr "Radio"
109
110 msgctxt "#30062"
111 msgid "Timeshift buffer path"
112 msgstr "Laika nobīdes bufera ceļš"
113
114 msgctxt "#30063"
115 msgid "Off"
116 msgstr "Izslēgts"
117
118 msgctxt "#30071"
119 msgid "Recordings"
120 msgstr "Ieraksti"
121
122 msgctxt "#30085"
123 msgid "OK"
124 msgstr "Skaidrs"
125
126 msgctxt "#30094"
127 msgid "N/A"
128 msgstr "N/P"
129
130 msgctxt "#30095"
131 msgid "True"
132 msgstr "Patiess"
133
134 msgctxt "#30096"
135 msgid "False"
136 msgstr "Nepatiess"
137
138 msgctxt "#30410"
139 msgid "Automatic"
140 msgstr "Automātiski"
141
142 msgctxt "#30430"
143 msgid "Disabled"
144 msgstr "Izslēgts"
117145
118146 msgctxt "#30500"
119147 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "Kupuhipa"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Ata"
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "Āhuawhānui"
3842 msgctxt "#30021"
3943 msgid "HTTP"
4044 msgstr "HTTP"
45
46 msgctxt "#30042"
47 msgid "Never"
48 msgstr "Kore rawa"
49
50 msgctxt "#30045"
51 msgid "Always"
52 msgstr "Tonu"
53
54 msgctxt "#30056"
55 msgid "TV"
56 msgstr "TV"
57
58 msgctxt "#30057"
59 msgid "Radio"
60 msgstr "Radio"
61
62 msgctxt "#30063"
63 msgid "Off"
64 msgstr "Weto"
65
66 msgctxt "#30071"
67 msgid "Recordings"
68 msgstr "Ngā pūhopu"
69
70 msgctxt "#30085"
71 msgid "OK"
72 msgstr "Āna"
73
74 msgctxt "#30095"
75 msgid "True"
76 msgstr "Pono"
77
78 msgctxt "#30096"
79 msgid "False"
80 msgstr "Teka"
81
82 msgctxt "#30430"
83 msgid "Disabled"
84 msgstr "Kua mono"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: mk_MK\n"
1616 "Plural-Forms: nplurals=2; plural=(n % 10 == 1 && n % 100 != 11) ? 0 : 1;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname или IP адреса"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streaming Port"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Корисничко име"
3123 msgid "Password"
3224 msgstr "Лозинка"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Конекција"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Икони"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Response timeout in seconds"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Патека за икони"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Интервал на надградби во минути"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatic Timerlist Cleanup"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webinterface Port"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap before channelswitch (i.e. for Single Tuner boxes)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Папки за channeldata"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Провери дали има нови пакети"
47 msgid "Update interval"
48 msgstr "Период на освежување"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Папка за снимање на ресиверот"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Испрати Наредба за DeepStandby"
82 msgctxt "#30042"
83 msgid "Never"
84 msgstr "Никогаш"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Превземи само еден TV пакет"
86 msgctxt "#30043"
87 msgid "In EPG only"
88 msgstr "Само во EPG"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "ТВ-Пакет"
90 msgctxt "#30044"
91 msgid "In recordings only"
92 msgstr "Само во снимките"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Превземи икони од интернет"
94 msgctxt "#30045"
95 msgid "Always"
96 msgstr "Секогаш"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Користи Secure HTTP (https)"
98 msgctxt "#30051"
99 msgid "Login"
100 msgstr "Најави се"
101
102 msgctxt "#30056"
103 msgid "TV"
104 msgstr "ТВ"
105
106 msgctxt "#30057"
107 msgid "Radio"
108 msgstr "Радио"
109
110 msgctxt "#30062"
111 msgid "Timeshift buffer path"
112 msgstr "Пат за Timeshift buffer-от"
113
114 msgctxt "#30063"
115 msgid "Off"
116 msgstr "Искл."
117
118 msgctxt "#30071"
119 msgid "Recordings"
120 msgstr "Снимки"
121
122 msgctxt "#30072"
123 msgid "Timers"
124 msgstr "Бројачи"
125
126 msgctxt "#30085"
127 msgid "OK"
128 msgstr "Во ред"
129
130 msgctxt "#30095"
131 msgid "True"
132 msgstr "Вистина"
133
134 msgctxt "#30096"
135 msgid "False"
136 msgstr "Неактивно"
137
138 msgctxt "#30430"
139 msgid "Disabled"
140 msgstr "Исклучено"
117141
118142 msgctxt "#30500"
119143 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1818 msgctxt "#30018"
1919 msgid "General"
2020 msgstr "പോതുവായത്"
21
22 msgctxt "#30085"
23 msgid "OK"
24 msgstr "ശരി"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
3939 msgid "HTTP"
4040 msgstr "HTTP"
4141
42 msgctxt "#30056"
43 msgid "TV"
44 msgstr "ТВ"
45
46 msgctxt "#30057"
47 msgid "Radio"
48 msgstr "Радио"
49
50 msgctxt "#30063"
51 msgid "Off"
52 msgstr "Хаах"
53
54 msgctxt "#30071"
55 msgid "Recordings"
56 msgstr "Бичлэгүүд"
57
58 msgctxt "#30072"
59 msgid "Timers"
60 msgstr "Цагалбарууд"
61
62 msgctxt "#30085"
63 msgid "OK"
64 msgstr "OK"
65
66 msgctxt "#30430"
67 msgid "Disabled"
68 msgstr "Идвэхгүй болсон"
69
4270 msgctxt "#30500"
4371 msgid "Disconnected from '%s'"
4472 msgstr "'%s'-с салгагдлаа"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nama hos atau alamat IP VU+"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Namahos atau alamat IP Enigma2 "
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Port Penstriman"
23 msgid "Streaming port"
24 msgstr "Port penstriman"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "Kata Laluan"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Sambungan"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Ikon"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Had masa tamat respons dalam saat"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Laluan Ikon"
47 msgid "Icon path"
48 msgstr "Laluan ikon"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Kemaskini Sela"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Sela kemaskini dalam minit"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Pembersihan Senarai Pemasa Berautomatik"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Pembersihan senarai pemasa berautomatik"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port "
63 msgid "Web interface port"
64 msgstr "Port antaramuka sesawang"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap sebelum tukar saluran (cth. Kotak Penala Tunggal)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Zap sebelum tukar saluran (cth. kotak penala tunggal)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Folder untuk data saluran"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Semak unutk kemaskini bouquett"
75 msgid "Update interval"
76 msgstr "Kemaskini sela"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Folder rakaman pada penerima"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Hantar "
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Hantar mod keadaan kuasa ketika keluar dari tambahan"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Hanya hantar satu TV bouquet"
115 msgid "TV bouquet fetch mode"
116 msgstr "Mod dapatkan jambak TV"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
119 msgid "TV bouquet"
120 msgstr "Jambak TV"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Dapatkan picons dari "
123 msgid "Fetch picons from web interface"
124 msgstr "Dapatkan picon dari antaramuka sesawang"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Guna HTTP Selamat (https)"
127 msgid "Use secure HTTP (https)"
128 msgstr "Guna HTTP selamat (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Benarkan konfigurasi automatik untuk strim langsung"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Kekalkan struktur folder untuk rekod"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Musim dan Episod"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Ekstrak maklumat musim, episod dan tahun jika ada"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Benarkan autopemasa"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Guna format fail picons.eu"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Benarkan jana pemasa berulang"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Log pemetaan teks genre yang hilang"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Antaramuka Sesawang"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Penstriman"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Letak garis-luar (cth. sarikata) sebelum plot"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Saiz cebisan baca strim"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Tidak sesekali"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Dalam EPG sahaja"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Hanya dalam rakaman"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Sentiasa"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Ekstrak fail maklumat rancangan"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Pemetaan teks genre Rytec"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Benarkan pemetaan teks genre Rytec"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Fail pemetaan teks genre Rytec"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Had masa tamat TV langsung suai (0 untuk guna lalai)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Daftar Masuk"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Pelbagai"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Pemetaan ID Genre"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Benarkan Pemetaan ID Genre"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Fail pemetaan ID Genre"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Mod dapatkan jambak radio"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Jambak radio"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Anjak Masa"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Benarkan anjak masa"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Laluan penimbal Anjak Masa"
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Mati"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Ketika main balik"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Ketika dijeda"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Guna HTTP Selamat (https) untuk strim"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Guna daftar masuk untuk strim"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Dapatkan jambak kegemaran TV"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Dapatkan jambak kegemaran radio"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Rakaman & Pemasa"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Rakaman"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Pemasa"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Bilangan pemasa ulang untuk dijana"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Semua jambak"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Hanya satu jambak"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Sebagai jambak pertama"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Sebagai jambak terakhir"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Kumpulan kegemaran"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Kegemaran (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Kegemaran (Radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "tidak diketahui"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Tidak bersambung)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "ralat tambahan"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Pelayan Media Enigma2"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Bahagian belakang"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Pemadatan Rakaman"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Pemadatan mula sejagat"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Pemadatan tamat sejagat"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Maklumat Peranti"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "Versi Webif"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "Tag AutoPemasa dalam tag pemasa"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "Nama AutoPemasa dalam tag pemasa"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "T/A"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Benar"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Palsu"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Sedia"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Sedia mendalam"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Bangun, kemudian sedia"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Mod kemaskini"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Pemasa dan rakaman"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Pemasa sahaja"
425
426 msgctxt "#30410"
427 msgid "Automatic"
428 msgstr "Automatik"
429
430 msgctxt "#30420"
431 msgid "One time (Scheduled by guide-based timer rule)"
432 msgstr "Sekali (Dijadulakan mengikut peraturan pemasa berasaskan-panduan)"
433
434 msgctxt "#30421"
435 msgid "One time (Scheduled by repeating timer rule)"
436 msgstr "Sekali (Dijadualkan mengikut peraturan pemasa ulang)"
437
438 msgctxt "#30430"
439 msgid "Disabled"
440 msgstr "Dilumpuhkan"
441
442 msgctxt "#30431"
443 msgid "Record if EPG title differs"
444 msgstr "Rakam jika tajuk EPG berbeza"
445
446 msgctxt "#30432"
447 msgid "Record if EPG title and short description differs"
448 msgstr "Rakam jika tajuk EPG dan keterangan pendek berlainan"
449
450 msgctxt "#30433"
451 msgid "Record if EPG title and all descriptions differ"
452 msgstr "Rakam jika tajuk EPG dan semua keterangan berlainan"
117453
118454 msgctxt "#30500"
119455 msgid "Disconnected from '%s'"
122458 msgctxt "#30501"
123459 msgid "Reconnected to '%s'"
124460 msgstr "Bersambung semula dengan '%s'"
461
462 msgctxt "#30514"
463 msgid "Timeshift buffer path does not exist"
464 msgstr "Laluan penimbal anjak masa tidak wujud"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "Sigriet"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Ajkons"
29
2630 msgctxt "#30007"
2731 msgid "Response timeout in seconds"
2832 msgstr "Kemm iddum tistenna riposta f'sekondi"
2933
30 msgctxt "#30012"
31 msgid "Webinterface Port"
32 msgstr "Port tal-webinterface"
34 msgctxt "#30015"
35 msgid "Update interval"
36 msgstr "Il-ħin bejn l-aġġornamenti"
3337
3438 msgctxt "#30018"
3539 msgid "General"
4650 msgctxt "#30021"
4751 msgid "HTTP"
4852 msgstr "HTTP"
53
54 msgctxt "#30042"
55 msgid "Never"
56 msgstr "Qatt"
57
58 msgctxt "#30043"
59 msgid "In EPG only"
60 msgstr "Fl-EPG biss"
61
62 msgctxt "#30044"
63 msgid "In recordings only"
64 msgstr "Fir-rekordings biss"
65
66 msgctxt "#30045"
67 msgid "Always"
68 msgstr "Dejjem"
69
70 msgctxt "#30056"
71 msgid "TV"
72 msgstr "Televixin"
73
74 msgctxt "#30057"
75 msgid "Radio"
76 msgstr "Radju"
77
78 msgctxt "#30062"
79 msgid "Timeshift buffer path"
80 msgstr "Il-Buffer path tat-timeshift"
81
82 msgctxt "#30063"
83 msgid "Off"
84 msgstr "Xejn"
85
86 msgctxt "#30071"
87 msgid "Recordings"
88 msgstr "Recordings"
89
90 msgctxt "#30085"
91 msgid "OK"
92 msgstr "OK"
93
94 msgctxt "#30095"
95 msgid "True"
96 msgstr "Veru"
97
98 msgctxt "#30096"
99 msgid "False"
100 msgstr "Falz"
101
102 msgctxt "#30430"
103 msgid "Disabled"
104 msgstr "Mhux attiv"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "စကားဝှက်"
2525
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "ကွန်နက်ရှင်"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Icons"
33
2634 msgctxt "#30018"
2735 msgid "General"
2836 msgstr "ယေဘုယျ"
3442 msgctxt "#30020"
3543 msgid "Advanced"
3644 msgstr "အဆင့်မြင့်သော"
45
46 msgctxt "#30042"
47 msgid "Never"
48 msgstr "ဘယ်တော့မှ"
49
50 msgctxt "#30045"
51 msgid "Always"
52 msgstr "အမြဲတမ်း"
53
54 msgctxt "#30051"
55 msgid "Login"
56 msgstr "ဝင်ရန်"
57
58 msgctxt "#30056"
59 msgid "TV"
60 msgstr "TV"
61
62 msgctxt "#30057"
63 msgid "Radio"
64 msgstr "ရေဒီယို"
65
66 msgctxt "#30063"
67 msgid "Off"
68 msgstr "ပိတ်"
69
70 msgctxt "#30071"
71 msgid "Recordings"
72 msgstr "အသံသွင်းခြင်း"
73
74 msgctxt "#30085"
75 msgid "OK"
76 msgstr "အိုကေ"
77
78 msgctxt "#30095"
79 msgid "True"
80 msgstr "မှန်၏"
81
82 msgctxt "#30430"
83 msgid "Disabled"
84 msgstr "ပိတ်ထားမည်"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: nb_NO\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ vertsnavn eller IP adresse"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Stream Port"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Brukernavn"
3123 msgid "Password"
3224 msgstr "Passord"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Tilkobling"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikoner"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Svar timeout i sekunder"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Sti til ikoner"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Oppdateringsinterval i minutter"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatisk opprydding av tidsursliste"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webgrensesnitt Port"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Bytt før kanalbytte (f.eks. for Single Tuner bokser)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Mappe for kanaldata"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Søk etter bouquett oppdateringer"
47 msgid "Update interval"
48 msgstr "Oppdateringsintervall"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Opptaksmappe på mottaker"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Send kommandoen DeepStandby"
82 msgctxt "#30029"
83 msgid "Enable automatic configuration for live streams"
84 msgstr "Skru på automatisk oppsett for sanntids-strømmer"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Hen kun en TV bouquet"
86 msgctxt "#30030"
87 msgid "Keep folder structure for records"
88 msgstr "Behold mappestruktur for opptak"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30032"
91 msgid "EPG"
92 msgstr "EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Hent piconer fra nettgrensesnittet"
94 msgctxt "#30042"
95 msgid "Never"
96 msgstr "Aldri"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Bruk Sikker HTTP (https)"
98 msgctxt "#30043"
99 msgid "In EPG only"
100 msgstr "Kun i EPG"
101
102 msgctxt "#30044"
103 msgid "In recordings only"
104 msgstr "Kun i opptak"
105
106 msgctxt "#30045"
107 msgid "Always"
108 msgstr "Alltid"
109
110 msgctxt "#30051"
111 msgid "Login"
112 msgstr "Innlogging"
113
114 msgctxt "#30052"
115 msgid "Misc"
116 msgstr "Diverse"
117
118 msgctxt "#30056"
119 msgid "TV"
120 msgstr "TV"
121
122 msgctxt "#30057"
123 msgid "Radio"
124 msgstr "Radio"
125
126 msgctxt "#30060"
127 msgid "Timeshift"
128 msgstr "Tdsforskyvning"
129
130 msgctxt "#30062"
131 msgid "Timeshift buffer path"
132 msgstr "Sti for tidsforskyvningbuffer"
133
134 msgctxt "#30063"
135 msgid "Off"
136 msgstr "Av"
137
138 msgctxt "#30064"
139 msgid "On playback"
140 msgstr "Ved avspilling"
141
142 msgctxt "#30065"
143 msgid "On pause"
144 msgstr "På pause"
145
146 msgctxt "#30071"
147 msgid "Recordings"
148 msgstr "Opptak"
149
150 msgctxt "#30072"
151 msgid "Timers"
152 msgstr "Tidsur"
153
154 msgctxt "#30085"
155 msgid "OK"
156 msgstr "OK"
157
158 msgctxt "#30094"
159 msgid "N/A"
160 msgstr "Ikke Tilgjengelig"
161
162 msgctxt "#30095"
163 msgid "True"
164 msgstr "Sant"
165
166 msgctxt "#30096"
167 msgid "False"
168 msgstr "Usann"
169
170 msgctxt "#30410"
171 msgid "Automatic"
172 msgstr "Automatisk"
173
174 msgctxt "#30430"
175 msgid "Disabled"
176 msgstr "Deaktivert"
117177
118178 msgctxt "#30500"
119179 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostnaam of IP-adres"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 hostnaam of IP-adres"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Streamingpoort"
23 msgid "Streaming port"
24 msgstr "Doorvoerpoort"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "Wachtwoord"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Verbinding"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Iconen"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Antwoordtimeout in seconden"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Icoonpad"
47 msgid "Icon path"
48 msgstr "Iconenpad"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Update-interval"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Update-interval in minuten"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatische opschoning van timers"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Automatisch opschonen van de timerlijst"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webinterfacepoort"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap voor kanaalwisseling (bv. bij enkelvoudige tuners)"
63 msgid "Web interface port"
64 msgstr "Webinterface-poort"
5765
5866 msgctxt "#30014"
5967 msgid "Folder for channeldata"
6068 msgstr "Map voor kanaaldata"
6169
6270 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Controleer bouquetupdates"
71 msgid "Update interval"
72 msgstr "Updatefrequentie"
6573
6674 msgctxt "#30016"
6775 msgid "Check for channel updates"
95103 msgid "Recording folder on the receiver"
96104 msgstr "Opnamemap op de ontvanger"
97105
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Stuur DeepStandby-commando"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Haal slechts 1 TV-bouquet op"
105
106106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-bouquet"
107 msgid "TV bouquet"
108 msgstr "TV bouquet"
109109
110110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Haal picons op van de webinterface"
111 msgid "Fetch picons from web interface"
112 msgstr "Picons ophalen van de web-interface"
113113
114114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Gebruik beveiligde HTTP (https)"
115 msgid "Use secure HTTP (https)"
116 msgstr "Gebruik beveiligd HTTP (https)"
117
118 msgctxt "#30029"
119 msgid "Enable automatic configuration for live streams"
120 msgstr "Activeer automatische configuratie voor live streams"
121
122 msgctxt "#30030"
123 msgid "Keep folder structure for records"
124 msgstr "Behoud folder structuur voor opnamen"
125
126 msgctxt "#30031"
127 msgid "Seasons and Episodes"
128 msgstr "Seizoenen en afleveringen"
129
130 msgctxt "#30032"
131 msgid "EPG"
132 msgstr "EPG"
133
134 msgctxt "#30033"
135 msgid "Extract season, episode and year info where possible"
136 msgstr "Seizoen-, afleverings- en jaarinformatie ophalen wanneer mogelijk"
137
138 msgctxt "#30034"
139 msgid "Enable autotimers"
140 msgstr "Inschakelen van autotimers"
141
142 msgctxt "#30035"
143 msgid "Use picons.eu file format"
144 msgstr "Gebruik picons.eu-bestandsformaat"
145
146 msgctxt "#30036"
147 msgid "Enable generate repeat timers"
148 msgstr "Activeren van gegenereerde herhaaltimers"
149
150 msgctxt "#30037"
151 msgid "Log missing genre text mappings"
152 msgstr "Log de afwezige genre-tekstmappings"
153
154 msgctxt "#30038"
155 msgid "Web Interface"
156 msgstr "Webinterface"
157
158 msgctxt "#30039"
159 msgid "Streaming"
160 msgstr "Streaming"
161
162 msgctxt "#30040"
163 msgid "Put outline (e.g. sub-title) before plot"
164 msgstr "Schets het verhaal (bijv. 2e titel) voor de plot"
165
166 msgctxt "#30042"
167 msgid "Never"
168 msgstr "Nooit"
169
170 msgctxt "#30043"
171 msgid "In EPG only"
172 msgstr "Alleen in EPG"
173
174 msgctxt "#30044"
175 msgid "In recordings only"
176 msgstr "Alleen in opnames"
177
178 msgctxt "#30045"
179 msgid "Always"
180 msgstr "Altijd"
181
182 msgctxt "#30046"
183 msgid "Extract show info file"
184 msgstr "TV-show-informatiebestand ophalen"
185
186 msgctxt "#30051"
187 msgid "Login"
188 msgstr "Gebruikersnaam"
189
190 msgctxt "#30052"
191 msgid "Misc"
192 msgstr " Divers"
193
194 msgctxt "#30056"
195 msgid "TV"
196 msgstr "TV"
197
198 msgctxt "#30057"
199 msgid "Radio"
200 msgstr "Radio"
201
202 msgctxt "#30059"
203 msgid "Radio bouquet"
204 msgstr "Radio-bouquet"
205
206 msgctxt "#30060"
207 msgid "Timeshift"
208 msgstr "Timeshift"
209
210 msgctxt "#30061"
211 msgid "Enable timeshift"
212 msgstr "Timeshift inschakelen"
213
214 msgctxt "#30062"
215 msgid "Timeshift buffer path"
216 msgstr "Tijdsprong bufferlocatie"
217
218 msgctxt "#30063"
219 msgid "Off"
220 msgstr "Uit"
221
222 msgctxt "#30064"
223 msgid "On playback"
224 msgstr "Tijdens afspelen"
225
226 msgctxt "#30065"
227 msgid "On pause"
228 msgstr "tijdens Pauze"
229
230 msgctxt "#30066"
231 msgid "Use secure HTTP (https) for streams"
232 msgstr "Gebruik beveiligde HTTP (https) voor streams"
233
234 msgctxt "#30070"
235 msgid "Recordings & Timers"
236 msgstr "Opnames en timers"
237
238 msgctxt "#30071"
239 msgid "Recordings"
240 msgstr "Opnames"
241
242 msgctxt "#30072"
243 msgid "Timers"
244 msgstr "Timers"
245
246 msgctxt "#30073"
247 msgid "Number of repeat timers to generate"
248 msgstr "Aantal herhaaltimers te genereren"
249
250 msgctxt "#30074"
251 msgid "All bouquets"
252 msgstr "Alle bouquets"
253
254 msgctxt "#30075"
255 msgid "Only one bouquet"
256 msgstr "Slechts één bouquet"
257
258 msgctxt "#30076"
259 msgid "As first bouquet"
260 msgstr "Als eerste bouquet"
261
262 msgctxt "#30077"
263 msgid "As last bouquet"
264 msgstr "Als laatste bouquet"
265
266 msgctxt "#30078"
267 msgid "Favourites group"
268 msgstr "Bladwijzergroep"
269
270 msgctxt "#30079"
271 msgid "Favourites (TV)"
272 msgstr "Bladwijzers (TV)"
273
274 msgctxt "#30080"
275 msgid "Favourites (Radio)"
276 msgstr "Bladwijzers (Radio)"
277
278 msgctxt "#30081"
279 msgid "unknown"
280 msgstr "onbekend"
281
282 msgctxt "#30082"
283 msgid " (Not connected!)"
284 msgstr "(Niet verbonden!)"
285
286 msgctxt "#30083"
287 msgid "addon error"
288 msgstr "Fout in add-on"
289
290 msgctxt "#30084"
291 msgid "Enigma2 Media Server"
292 msgstr "Enigma2 Media Server"
293
294 msgctxt "#30085"
295 msgid "OK"
296 msgstr "OK"
297
298 msgctxt "#30086"
299 msgid "Backend"
300 msgstr "Backend"
301
302 msgctxt "#30087"
303 msgid "Recording Padding"
304 msgstr "Opname-opvulling"
305
306 msgctxt "#30088"
307 msgid "Global start padding"
308 msgstr "Globale startopvulling"
309
310 msgctxt "#30089"
311 msgid "Global end padding"
312 msgstr "Globale eindopvulling"
313
314 msgctxt "#30090"
315 msgid "Device Info"
316 msgstr "Apparaatinformatie"
317
318 msgctxt "#30091"
319 msgid "WebIf version"
320 msgstr "WebIf-versie"
321
322 msgctxt "#30094"
323 msgid "N/A"
324 msgstr "N/B"
325
326 msgctxt "#30095"
327 msgid "True"
328 msgstr "Waar"
329
330 msgctxt "#30096"
331 msgid "False"
332 msgstr "Onwaar"
333
334 msgctxt "#30100"
335 msgid "Update mode"
336 msgstr "Update-modus"
337
338 msgctxt "#30101"
339 msgid "Timers and recordings"
340 msgstr "Timers en opnames"
341
342 msgctxt "#30102"
343 msgid "Timers only"
344 msgstr "Alleen timers"
345
346 msgctxt "#30410"
347 msgid "Automatic"
348 msgstr "Automatisch"
349
350 msgctxt "#30420"
351 msgid "One time (Scheduled by guide-based timer rule)"
352 msgstr "Eenmalig (ingesteld door gidsgebaseerde tijdregel)"
353
354 msgctxt "#30421"
355 msgid "One time (Scheduled by repeating timer rule)"
356 msgstr "Eenmaal (ingepland door herhaalde timerregel)"
357
358 msgctxt "#30430"
359 msgid "Disabled"
360 msgstr "Uitgeschakeld"
361
362 msgctxt "#30431"
363 msgid "Record if EPG title differs"
364 msgstr "Opname indien EPG-titel afwijkt"
365
366 msgctxt "#30432"
367 msgid "Record if EPG title and short description differs"
368 msgstr "Opnemen indien er verschillen in de EPG-titel en de korte omschrijving zijn"
369
370 msgctxt "#30433"
371 msgid "Record if EPG title and all descriptions differ"
372 msgstr "Opnemen indien er verschillen in de EPG-titel en alle korte omschrijvingen zijn"
117373
118374 msgctxt "#30500"
119375 msgid "Disconnected from '%s'"
122378 msgctxt "#30501"
123379 msgid "Reconnected to '%s'"
124380 msgstr "Verbinding met '%s' hersteld"
381
382 msgctxt "#30514"
383 msgid "Timeshift buffer path does not exist"
384 msgstr "Tijdshift-bufferpad bestaat niet"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: pl_PL\n"
1616 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nazwa lub adres serwera"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Port transmisji"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Użytkownik"
3123 msgid "Password"
3224 msgstr "Hasło"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Połączenie"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Plakaty"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Limit czasu odpowiedzi w sekundach"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Folder z ikonami"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Częstotliwość aktualizacji w minutach"
4541
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatyczne czyszczenie harmonogramu nagrań"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port interfejsu webowego"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Przełączaj na dany kanał (np. dla dekoderów z jednym tunerem)"
57
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Folder danych kanałów"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Sprawdzaj aktualizacje bukietów"
47 msgid "Update interval"
48 msgstr "Częstotliwość aktualizacji"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Folder nagrywania na dekoderze"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Wysyłaj polecenie głębokiego czuwania"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Pobieraj tylko jeden bukiet"
105
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Bukiet"
109
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Pobieraj loga kanałów przez interfejs webowy"
113
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Używaj zabezpieczonego HTTP (HTTPS)"
82 msgctxt "#30029"
83 msgid "Enable automatic configuration for live streams"
84 msgstr "Konfiguruj transmisje na żywo automatycznie"
85
86 msgctxt "#30030"
87 msgid "Keep folder structure for records"
88 msgstr "Zachowuj strukturę folderów nagrań"
89
90 msgctxt "#30032"
91 msgid "EPG"
92 msgstr "Przewodnik"
93
94 msgctxt "#30039"
95 msgid "Streaming"
96 msgstr "Strumieniowanie"
97
98 msgctxt "#30042"
99 msgid "Never"
100 msgstr "Nigdy"
101
102 msgctxt "#30043"
103 msgid "In EPG only"
104 msgstr "W przewodniku"
105
106 msgctxt "#30044"
107 msgid "In recordings only"
108 msgstr "W nagraniach"
109
110 msgctxt "#30045"
111 msgid "Always"
112 msgstr "Zawsze"
113
114 msgctxt "#30051"
115 msgid "Login"
116 msgstr "Użytkownik"
117
118 msgctxt "#30052"
119 msgid "Misc"
120 msgstr "Dodatkowe"
121
122 msgctxt "#30056"
123 msgid "TV"
124 msgstr "TELEWIZJA"
125
126 msgctxt "#30057"
127 msgid "Radio"
128 msgstr "Radio"
129
130 msgctxt "#30060"
131 msgid "Timeshift"
132 msgstr "Przesunięcie czasowe"
133
134 msgctxt "#30062"
135 msgid "Timeshift buffer path"
136 msgstr "Folderu bufora przesunięcia czasowego"
137
138 msgctxt "#30063"
139 msgid "Off"
140 msgstr "Nieaktywne"
141
142 msgctxt "#30064"
143 msgid "On playback"
144 msgstr "Po rozpoczęciu odtwarzania"
145
146 msgctxt "#30065"
147 msgid "On pause"
148 msgstr "Po wstrzymaniu odtwarzania"
149
150 msgctxt "#30071"
151 msgid "Recordings"
152 msgstr "Nagrania"
153
154 msgctxt "#30072"
155 msgid "Timers"
156 msgstr "Zadania"
157
158 msgctxt "#30085"
159 msgid "OK"
160 msgstr "OK"
161
162 msgctxt "#30094"
163 msgid "N/A"
164 msgstr "Brak"
165
166 msgctxt "#30095"
167 msgid "True"
168 msgstr "Prawda"
169
170 msgctxt "#30096"
171 msgid "False"
172 msgstr "Fałsz"
173
174 msgctxt "#30410"
175 msgid "Automatic"
176 msgstr "Automat"
177
178 msgctxt "#30420"
179 msgid "One time (Scheduled by guide-based timer rule)"
180 msgstr "Jednorazowo (zaplanowane przez regułę bazująca na przewodniku)"
181
182 msgctxt "#30430"
183 msgid "Disabled"
184 msgstr "Nieaktywny"
185
186 msgctxt "#30431"
187 msgid "Record if EPG title differs"
188 msgstr "Nagrywaj, gdy tytuł w przewodniku się różni"
117189
118190 msgctxt "#30500"
119191 msgid "Disconnected from '%s'"
121193
122194 msgctxt "#30501"
123195 msgid "Reconnected to '%s'"
124 msgstr "Ponownie połączono z '%s'"
196 msgstr "Połączono ponownie z '%s'"
197
198 msgctxt "#30514"
199 msgid "Timeshift buffer path does not exist"
200 msgstr "Folderu bufora przesunięcia czasowego nie istnieje"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: pt_BR\n"
1616 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Hostname VU+ ou endereço IP"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Porta de Streaming"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Nome do usuário"
3123 msgid "Password"
3224 msgstr "Senha"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Conexão"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ícones"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Tempo limite para resposta em segundos"
3737
3838 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Caminho do ícone"
39 msgid "Icon path"
40 msgstr "Caminho para o ícone"
4141
4242 msgctxt "#30010"
4343 msgid "Update Interval in minutes"
4444 msgstr "Intervalo de atualizações em minutos"
4545
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Limpar Timerlist automaticamente"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Porta da Interface Web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zapear antes de trocar canal (isto é, para conversores com sintonizador único)"
57
5846 msgctxt "#30014"
5947 msgid "Folder for channeldata"
6048 msgstr "Pasta para dados dos canais"
6149
6250 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Verificar atualizações de bouquett"
51 msgid "Update interval"
52 msgstr "Intervalo de atualização"
6553
6654 msgctxt "#30016"
6755 msgid "Check for channel updates"
9583 msgid "Recording folder on the receiver"
9684 msgstr "Pasta de gravações no receptor"
9785
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Enviar comando de Standby Profundo"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Buscar apenas um TV bouquet"
105
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
109
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Buscar picons da webinterface"
113
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Usar HTTP com segurança (https)"
86 msgctxt "#30029"
87 msgid "Enable automatic configuration for live streams"
88 msgstr "Ativar configuração automática para streams ao vivo"
89
90 msgctxt "#30030"
91 msgid "Keep folder structure for records"
92 msgstr "Mantenha estrutura da pasta para gravações"
93
94 msgctxt "#30031"
95 msgid "Seasons and Episodes"
96 msgstr "Temporadas e Episódios"
97
98 msgctxt "#30032"
99 msgid "EPG"
100 msgstr "Guia"
101
102 msgctxt "#30039"
103 msgid "Streaming"
104 msgstr "Streaming"
105
106 msgctxt "#30042"
107 msgid "Never"
108 msgstr "Nunca"
109
110 msgctxt "#30043"
111 msgid "In EPG only"
112 msgstr "Somente no EPG"
113
114 msgctxt "#30044"
115 msgid "In recordings only"
116 msgstr "Somente em gravações"
117
118 msgctxt "#30045"
119 msgid "Always"
120 msgstr "Sempre"
121
122 msgctxt "#30051"
123 msgid "Login"
124 msgstr "Login"
125
126 msgctxt "#30052"
127 msgid "Misc"
128 msgstr "Misc"
129
130 msgctxt "#30056"
131 msgid "TV"
132 msgstr "TV"
133
134 msgctxt "#30057"
135 msgid "Radio"
136 msgstr "Rádio"
137
138 msgctxt "#30060"
139 msgid "Timeshift"
140 msgstr "Mudança de horário"
141
142 msgctxt "#30062"
143 msgid "Timeshift buffer path"
144 msgstr "Caminho do buffer de gravação"
145
146 msgctxt "#30063"
147 msgid "Off"
148 msgstr "Desligado"
149
150 msgctxt "#30064"
151 msgid "On playback"
152 msgstr "Na reprodução"
153
154 msgctxt "#30065"
155 msgid "On pause"
156 msgstr "Na pausa"
157
158 msgctxt "#30067"
159 msgid "Use login for streams"
160 msgstr "Usar login para streams"
161
162 msgctxt "#30071"
163 msgid "Recordings"
164 msgstr "Gravações"
165
166 msgctxt "#30072"
167 msgid "Timers"
168 msgstr "Agendamentos"
169
170 msgctxt "#30078"
171 msgid "Favourites group"
172 msgstr "Grupo de favoritos"
173
174 msgctxt "#30079"
175 msgid "Favourites (TV)"
176 msgstr "Favoritos (TV)"
177
178 msgctxt "#30080"
179 msgid "Favourites (Radio)"
180 msgstr "Favoritos (Rádio)"
181
182 msgctxt "#30081"
183 msgid "unknown"
184 msgstr "desconhecido"
185
186 msgctxt "#30082"
187 msgid " (Not connected!)"
188 msgstr "(Não conectado!)"
189
190 msgctxt "#30083"
191 msgid "addon error"
192 msgstr "Erro no add-on"
193
194 msgctxt "#30085"
195 msgid "OK"
196 msgstr "OK"
197
198 msgctxt "#30090"
199 msgid "Device Info"
200 msgstr "Informações do dispositivo"
201
202 msgctxt "#30094"
203 msgid "N/A"
204 msgstr "N/D"
205
206 msgctxt "#30095"
207 msgid "True"
208 msgstr "Verdadeiro"
209
210 msgctxt "#30096"
211 msgid "False"
212 msgstr "Falso"
213
214 msgctxt "#30101"
215 msgid "Timers and recordings"
216 msgstr "Agendamentos e gravações"
217
218 msgctxt "#30102"
219 msgid "Timers only"
220 msgstr "Somente agendamentos"
221
222 msgctxt "#30410"
223 msgid "Automatic"
224 msgstr "Automático"
225
226 msgctxt "#30430"
227 msgid "Disabled"
228 msgstr "Desabilitado"
117229
118230 msgctxt "#30500"
119231 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: pt_PT\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Nome ou endereço IP do servidor VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Porta de transmissão"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Nome de utilizador"
3123 msgid "Password"
3224 msgstr "Palavra-passe"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Ligação"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ícones"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Tempo limite para resposta (segundos)"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Caminho do ícone"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Intervalo de atualização (minutos)"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Limpeza automática da Timerlist"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Porta da interface web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap antes de mudar de canal (útil para caixas só com um sintonizador)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Pasta para dados do canais"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Procurar atualizações do bouquett"
47 msgid "Update interval"
48 msgstr "Intervalo de atualização "
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Pasta de gravação no recetor"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Enviar comando de DeepStandby"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Obter apenas um TV bouquet"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Nunca"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "Apenas em EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Obter ícones da interface web"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Apenas em gravações"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Utilizar HTTP seguro (https)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "Sempre"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Iniciar sessão"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Outras"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "TV"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Rádio"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Ver Mais Tarde"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Localização do buffer para 'Ver Mais Tarde'"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Desligado"
129
130 msgctxt "#30064"
131 msgid "On playback"
132 msgstr "Ao reproduzir"
133
134 msgctxt "#30065"
135 msgid "On pause"
136 msgstr "Ao pausar"
137
138 msgctxt "#30071"
139 msgid "Recordings"
140 msgstr "Gravações"
141
142 msgctxt "#30072"
143 msgid "Timers"
144 msgstr "Temporizadores"
145
146 msgctxt "#30085"
147 msgid "OK"
148 msgstr "CONFIRMAR"
149
150 msgctxt "#30095"
151 msgid "True"
152 msgstr "Verdadeiro"
153
154 msgctxt "#30096"
155 msgid "False"
156 msgstr "Falso"
157
158 msgctxt "#30410"
159 msgid "Automatic"
160 msgstr "Automático"
161
162 msgctxt "#30430"
163 msgid "Disabled"
164 msgstr "Desativado"
117165
118166 msgctxt "#30500"
119167 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: ro_RO\n"
1616 "Plural-Forms: nplurals=3; plural=(n==1?0:(((n%100>19)||((n%100==0)&&(n!=0)))?2:1));\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname sau IP address"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Portul de streaming"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Utilizator"
3123 msgid "Password"
3224 msgstr "Parolă"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Conexiune"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Imagini"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Expirare timp conexiune în secunde"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Adresa pictogramei "
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Intervalul de actualizare în minute"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Ștergere automata a listelor de înregistrare programată"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Portul interfaței web"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zap înainte de schimbarea canalului (ex. pentru decodoarele cu un singur tuner)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Dosarul pentru informațiile canalelor"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Verifică actualizarea buchetului"
47 msgid "Update interval"
48 msgstr "Interval actualizare"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Dosarul de înregistrari în decodor"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Trimite comandă - DeepStandby"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "Ghid program electronic"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Adună date doar pentru un buchet TV"
86 msgctxt "#30039"
87 msgid "Streaming"
88 msgstr "Difuzare în flux"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30042"
91 msgid "Never"
92 msgstr "Niciodată"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Descarcă picons direct din interfața web"
94 msgctxt "#30043"
95 msgid "In EPG only"
96 msgstr "Doar în ghidul tv"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Folosește HTTP sigur (https)"
98 msgctxt "#30044"
99 msgid "In recordings only"
100 msgstr "Doar în înregistrări"
101
102 msgctxt "#30045"
103 msgid "Always"
104 msgstr "Întotdeauna"
105
106 msgctxt "#30051"
107 msgid "Login"
108 msgstr "Autentificare"
109
110 msgctxt "#30052"
111 msgid "Misc"
112 msgstr "Diverse"
113
114 msgctxt "#30056"
115 msgid "TV"
116 msgstr "Televizor"
117
118 msgctxt "#30057"
119 msgid "Radio"
120 msgstr "Radio"
121
122 msgctxt "#30060"
123 msgid "Timeshift"
124 msgstr "Decalaj temporal"
125
126 msgctxt "#30062"
127 msgid "Timeshift buffer path"
128 msgstr "Calea buffer-ului de înregistrare"
129
130 msgctxt "#30063"
131 msgid "Off"
132 msgstr "Oprită"
133
134 msgctxt "#30064"
135 msgid "On playback"
136 msgstr "La redare"
137
138 msgctxt "#30065"
139 msgid "On pause"
140 msgstr "La pauzare"
141
142 msgctxt "#30071"
143 msgid "Recordings"
144 msgstr "Înregistrări"
145
146 msgctxt "#30072"
147 msgid "Timers"
148 msgstr "Cronometre"
149
150 msgctxt "#30085"
151 msgid "OK"
152 msgstr "Bine"
153
154 msgctxt "#30094"
155 msgid "N/A"
156 msgstr "Nedisponibil"
157
158 msgctxt "#30095"
159 msgid "True"
160 msgstr "Adevărat"
161
162 msgctxt "#30096"
163 msgid "False"
164 msgstr "Fals"
165
166 msgctxt "#30410"
167 msgid "Automatic"
168 msgstr "Automat"
169
170 msgctxt "#30430"
171 msgid "Disabled"
172 msgstr "Dezactivat"
117173
118174 msgctxt "#30500"
119175 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: ru_RU\n"
1616 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Имя VU+ хоста или IP-адрес"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Порт видео-потока"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Пользователь"
3123 msgid "Password"
3224 msgstr "Пароль"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Соединение"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Значки"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Тайм-аут отклика в секундах"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Путь к значкам"
38 msgctxt "#30009"
39 msgid "Update Interval"
40 msgstr "Интервал обновления"
4141
4242 msgctxt "#30010"
4343 msgid "Update Interval in minutes"
4444 msgstr "Интервал обновления в минутах"
4545
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Авто-очистка таймеров"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Порт веб-интерфейса"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Сброс перед переключением канала (для одно-тюнерных устройств)"
57
5846 msgctxt "#30014"
5947 msgid "Folder for channeldata"
6048 msgstr "Папка для данных о каналах"
6149
6250 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Проверять обновления букетов"
51 msgid "Update interval"
52 msgstr "Интервал обновления"
6553
6654 msgctxt "#30016"
6755 msgid "Check for channel updates"
9583 msgid "Recording folder on the receiver"
9684 msgstr "Папка для записей на ресивере"
9785
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Послать команду DeepStandby"
101
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Выбрать только один букет"
105
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-букет"
109
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Брать лого каналов из вебинтерфейса"
113
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Использовать защищенный HTTP протокол (https) "
86 msgctxt "#30029"
87 msgid "Enable automatic configuration for live streams"
88 msgstr "Включить автоматическую настройку для прямых трансляций"
89
90 msgctxt "#30030"
91 msgid "Keep folder structure for records"
92 msgstr "Хранить структуру папок для записей"
93
94 msgctxt "#30031"
95 msgid "Seasons and Episodes"
96 msgstr "Сезоны и серии"
97
98 msgctxt "#30032"
99 msgid "EPG"
100 msgstr "EPG"
101
102 msgctxt "#30035"
103 msgid "Use picons.eu file format"
104 msgstr "Использовать файлы в формате picons.eu"
105
106 msgctxt "#30042"
107 msgid "Never"
108 msgstr "Никогда"
109
110 msgctxt "#30043"
111 msgid "In EPG only"
112 msgstr "Только в EPG"
113
114 msgctxt "#30044"
115 msgid "In recordings only"
116 msgstr "Только в записях"
117
118 msgctxt "#30045"
119 msgid "Always"
120 msgstr "Всегда"
121
122 msgctxt "#30051"
123 msgid "Login"
124 msgstr "Логин"
125
126 msgctxt "#30052"
127 msgid "Misc"
128 msgstr "Разное"
129
130 msgctxt "#30056"
131 msgid "TV"
132 msgstr "ТВ"
133
134 msgctxt "#30057"
135 msgid "Radio"
136 msgstr "Радио"
137
138 msgctxt "#30060"
139 msgid "Timeshift"
140 msgstr "Таймшифт"
141
142 msgctxt "#30062"
143 msgid "Timeshift buffer path"
144 msgstr "Путь к буферу таймшифт"
145
146 msgctxt "#30063"
147 msgid "Off"
148 msgstr "Выкл."
149
150 msgctxt "#30064"
151 msgid "On playback"
152 msgstr "Воспроизводится"
153
154 msgctxt "#30065"
155 msgid "On pause"
156 msgstr "На паузе"
157
158 msgctxt "#30070"
159 msgid "Recordings & Timers"
160 msgstr "Запись и планирование"
161
162 msgctxt "#30071"
163 msgid "Recordings"
164 msgstr "Записи"
165
166 msgctxt "#30072"
167 msgid "Timers"
168 msgstr "Таймеры"
169
170 msgctxt "#30083"
171 msgid "addon error"
172 msgstr "ошибка дополнения"
173
174 msgctxt "#30085"
175 msgid "OK"
176 msgstr "ОК"
177
178 msgctxt "#30094"
179 msgid "N/A"
180 msgstr "Не доступно"
181
182 msgctxt "#30095"
183 msgid "True"
184 msgstr "Да"
185
186 msgctxt "#30096"
187 msgid "False"
188 msgstr "Нет"
189
190 msgctxt "#30410"
191 msgid "Automatic"
192 msgstr "Автоматически"
193
194 msgctxt "#30420"
195 msgid "One time (Scheduled by guide-based timer rule)"
196 msgstr "Единоразово (по расписанию планировщика на основе руководства)"
197
198 msgctxt "#30421"
199 msgid "One time (Scheduled by repeating timer rule)"
200 msgstr "Единоразово (по расписанию на основе правил планировщика)"
201
202 msgctxt "#30430"
203 msgid "Disabled"
204 msgstr "Откл."
205
206 msgctxt "#30431"
207 msgid "Record if EPG title differs"
208 msgstr "Записывать, даже если название телепередачи не совпадает"
209
210 msgctxt "#30432"
211 msgid "Record if EPG title and short description differs"
212 msgstr "Записывать, даже если не совпадает название и краткое описание телепередачи"
213
214 msgctxt "#30433"
215 msgid "Record if EPG title and all descriptions differ"
216 msgstr "Записывать, даже если не совпадает название и описание телепередачи"
117217
118218 msgctxt "#30500"
119219 msgid "Disconnected from '%s'"
122222 msgctxt "#30501"
123223 msgid "Reconnected to '%s'"
124224 msgstr "Подключено к '%s'"
225
226 msgctxt "#30514"
227 msgid "Timeshift buffer path does not exist"
228 msgstr "Отсутствует путь для буферизации отложенного просмотра"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "මුරපදය"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "සුරුවම් "
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "සාමාන්‍ය"
3438 msgctxt "#30021"
3539 msgid "HTTP"
3640 msgstr "HTTP"
41
42 msgctxt "#30042"
43 msgid "Never"
44 msgstr "කිසි විටෙකත් නැති "
45
46 msgctxt "#30062"
47 msgid "Timeshift buffer path"
48 msgstr "කාල සාරු අවරෝධක පෙත"
49
50 msgctxt "#30063"
51 msgid "Off"
52 msgstr "වහනවා"
53
54 msgctxt "#30071"
55 msgid "Recordings"
56 msgstr "පටිගතකිරීම්"
57
58 msgctxt "#30085"
59 msgid "OK"
60 msgstr "හරි"
61
62 msgctxt "#30430"
63 msgid "Disabled"
64 msgstr "අක්‍රිය කර ඇත."
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: sk_SK\n"
1616 "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Sieťový názov VU+ zariadenia (názov hostiteľa) alebo IP adresa"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Port pre streamovanie"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Užívateľské meno"
3123 msgid "Password"
3224 msgstr "Heslo"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Pripojenie"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikony"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Časový limit pre odozvu v sekundách"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Cesta k ikonám"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Interval aktualizácie v minútach"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatické čistenie zoznamu časovačov"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port pre webové rozhranie"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Vypnúť zobrazenie aktuálneho kanálu pred prepnutím (napr. pre jednotunerové prijímače)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Priečinok pre dáta kanálov"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Kontrolovať dostupnosť aktualizácií obľúbených skupín programov"
47 msgid "Update interval"
48 msgstr "Doba aktualizácie"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Priečinok pre nahrávky v prijímači"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Posielať príkaz pre uspanie prijímača"
82 msgctxt "#30029"
83 msgid "Enable automatic configuration for live streams"
84 msgstr "Povoliť automatickú konfiguráciu pre živé streamy"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Vyvolať len jednu obľúbenú skupinu TV programov"
86 msgctxt "#30030"
87 msgid "Keep folder structure for records"
88 msgstr "Zachovať pri nahrávkach štruktúru priečinkov"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Obľúbená skupina TV programov"
90 msgctxt "#30032"
91 msgid "EPG"
92 msgstr "EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Získať logá TV staníc z webového rozhrania"
94 msgctxt "#30042"
95 msgid "Never"
96 msgstr "Nikdy"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Použiť Secure HTTP (https)"
98 msgctxt "#30043"
99 msgid "In EPG only"
100 msgstr "Iba v EPG"
101
102 msgctxt "#30044"
103 msgid "In recordings only"
104 msgstr "Iba v nahrávkach"
105
106 msgctxt "#30045"
107 msgid "Always"
108 msgstr "Vždy"
109
110 msgctxt "#30051"
111 msgid "Login"
112 msgstr "Prihlasovavie meno"
113
114 msgctxt "#30052"
115 msgid "Misc"
116 msgstr "Rôzne"
117
118 msgctxt "#30056"
119 msgid "TV"
120 msgstr "TV"
121
122 msgctxt "#30057"
123 msgid "Radio"
124 msgstr "Rádio"
125
126 msgctxt "#30060"
127 msgid "Timeshift"
128 msgstr "Časový posun"
129
130 msgctxt "#30062"
131 msgid "Timeshift buffer path"
132 msgstr "Cesta k zásobníku časového posunu"
133
134 msgctxt "#30063"
135 msgid "Off"
136 msgstr "Vypnuté"
137
138 msgctxt "#30064"
139 msgid "On playback"
140 msgstr "Pri prehrávaní"
141
142 msgctxt "#30065"
143 msgid "On pause"
144 msgstr "Pri pozastavení"
145
146 msgctxt "#30071"
147 msgid "Recordings"
148 msgstr "Nahrávky"
149
150 msgctxt "#30072"
151 msgid "Timers"
152 msgstr "Časovače"
153
154 msgctxt "#30085"
155 msgid "OK"
156 msgstr "OK"
157
158 msgctxt "#30094"
159 msgid "N/A"
160 msgstr "N/A"
161
162 msgctxt "#30095"
163 msgid "True"
164 msgstr "Pravdivé"
165
166 msgctxt "#30096"
167 msgid "False"
168 msgstr "Nepravdivé"
169
170 msgctxt "#30410"
171 msgid "Automatic"
172 msgstr "Automaticky"
173
174 msgctxt "#30420"
175 msgid "One time (Scheduled by guide-based timer rule)"
176 msgstr "Jednorazovo (naplánované pravidlom časovača TV programu)"
177
178 msgctxt "#30430"
179 msgid "Disabled"
180 msgstr "Zakázané"
181
182 msgctxt "#30431"
183 msgid "Record if EPG title differs"
184 msgstr "Nahrávať, ak sa titul v EPG odlišuje"
117185
118186 msgctxt "#30500"
119187 msgid "Disconnected from '%s'"
122190 msgctxt "#30501"
123191 msgid "Reconnected to '%s'"
124192 msgstr "Opätovne pripojený k '%s'"
193
194 msgctxt "#30514"
195 msgid "Timeshift buffer path does not exist"
196 msgstr "Cesta k zásobníku časového posunu neexistuje"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: sl_SI\n"
1616 "Plural-Forms: nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Ime gostitelja ali IP strežnika VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Vrata za pretakanje"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Uporabniško ime"
3123 msgid "Password"
3224 msgstr "Geslo"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Povezava"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikone"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Čas preteka odgovora v sekundah"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Pot ikon"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Interval posodabljanja v minutah"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Samodejno čiščenje seznama časovnikov"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Vrata spletnega vmesnika"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zamenjaj program tudi na sprejemniku"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Mapa za podatke o programih"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Preveri za posodobitve skupin"
47 msgid "Update interval"
48 msgstr "Interval posodabljanja"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Mapa snemanja na sprejemniku"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Pošlji ukaz za prehod v stanje pripravljenosti"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPV"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Prenesi le eno skupino"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Nikoli"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Skupina programov"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "Samo v EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Prenesi ikone s spletnega vmesnika"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Samo v posnetkih"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Uporabi varen HTTP (https)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "Vedno"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Prijava"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Razno"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "TV"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Radio"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Časovni zamik"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Pot medpomnenja časovnega zamika"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Izključeno"
129
130 msgctxt "#30064"
131 msgid "On playback"
132 msgstr "Ob predvajanju"
133
134 msgctxt "#30065"
135 msgid "On pause"
136 msgstr "Ob prekinitvi"
137
138 msgctxt "#30071"
139 msgid "Recordings"
140 msgstr "Posnetki"
141
142 msgctxt "#30085"
143 msgid "OK"
144 msgstr "OK"
145
146 msgctxt "#30095"
147 msgid "True"
148 msgstr "Drži"
149
150 msgctxt "#30096"
151 msgid "False"
152 msgstr "Nepravilno"
153
154 msgctxt "#30410"
155 msgid "Automatic"
156 msgstr "Samodejno"
157
158 msgctxt "#30430"
159 msgid "Disabled"
160 msgstr "Onemogočeno"
117161
118162 msgctxt "#30500"
119163 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: sq_AL\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname ose adresa IP"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Porti i transmetimit"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Emër-përdoruesi"
3123 msgid "Password"
3224 msgstr "Fjalëkalimi"
3325
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Ikona"
29
3430 msgctxt "#30007"
3531 msgid "Response timeout in seconds"
3632 msgstr "Timeout i përgjigjjes në eskonda"
37
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Vendndodhja e ikonave"
4133
4234 msgctxt "#30010"
4335 msgid "Update Interval in minutes"
4436 msgstr "Interval i aktualizimit në minuta"
4537
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Pastrimi i Orarit automatikisht"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webinterface porti"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Parashikimi i kanaleve para ndrimit tëi një kanali (p.sh. për aparate me Single Tuner )"
57
5838 msgctxt "#30014"
5939 msgid "Folder for channeldata"
6040 msgstr "Rregjistri për informacionet të kanaleve"
61
62 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Shikoni për aktualizime të buketit"
6541
6642 msgctxt "#30016"
6743 msgid "Check for channel updates"
9571 msgid "Recording folder on the receiver"
9672 msgstr "Regjistër i regjistrimeve në resiverin"
9773
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Dërgo komand DeepStandby"
74 msgctxt "#30042"
75 msgid "Never"
76 msgstr "Kurrë"
10177
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Shkarko vetëm një TV buket"
78 msgctxt "#30045"
79 msgid "Always"
80 msgstr "Gjithnjë"
10581
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Buket"
82 msgctxt "#30056"
83 msgid "TV"
84 msgstr "TV"
10985
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Tërhiqni pikon'at nga webinterface"
86 msgctxt "#30057"
87 msgid "Radio"
88 msgstr "Radio"
89
90 msgctxt "#30063"
91 msgid "Off"
92 msgstr "Hequr"
93
94 msgctxt "#30071"
95 msgid "Recordings"
96 msgstr "Rregjistrime"
97
98 msgctxt "#30085"
99 msgid "OK"
100 msgstr "N'RREGULL"
101
102 msgctxt "#30095"
103 msgid "True"
104 msgstr "Vërtetë"
105
106 msgctxt "#30096"
107 msgid "False"
108 msgstr "I pavërtetë"
109
110 msgctxt "#30430"
111 msgid "Disabled"
112 msgstr "Deaktivuar"
113113
114114 msgctxt "#30500"
115115 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: sr_RS\n"
1616 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname или IP адреса"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Порт за Стримовање"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Корисничко име"
3123 msgid "Password"
3224 msgstr "Лозинка"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Веза"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Иконе"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Истек времена за одзив у секундама"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Путања Икона"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Интервал ажурирања у минутима"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Аутоматско Чишћење Листе Тајмера"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Порт Web интерфејса"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Искључи пре промене програма (нпр. за кутије са једним пријемником)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Фасцикла за податке канала"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Провери за bouquett новије верзије"
47 msgid "Update interval"
48 msgstr "Интервал ажурирања"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Фасцикла за снимање на пријемнику"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Пошаљи Команду Дубоке Приправности"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Преузми само један ТВ bouquet"
86 msgctxt "#30039"
87 msgid "Streaming"
88 msgstr "Стримовање"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "ТВ-Bouquet"
90 msgctxt "#30042"
91 msgid "Never"
92 msgstr "Никада"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Преузми picons од web интерфејса"
94 msgctxt "#30043"
95 msgid "In EPG only"
96 msgstr "Само у EPG-у"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Користи Сигурни HTTP (https)"
98 msgctxt "#30044"
99 msgid "In recordings only"
100 msgstr "Само у снимцима"
101
102 msgctxt "#30045"
103 msgid "Always"
104 msgstr "Увек"
105
106 msgctxt "#30051"
107 msgid "Login"
108 msgstr "Пријава"
109
110 msgctxt "#30052"
111 msgid "Misc"
112 msgstr "Остало"
113
114 msgctxt "#30056"
115 msgid "TV"
116 msgstr "ТВ"
117
118 msgctxt "#30057"
119 msgid "Radio"
120 msgstr "Радио"
121
122 msgctxt "#30060"
123 msgid "Timeshift"
124 msgstr "Померај времена"
125
126 msgctxt "#30062"
127 msgid "Timeshift buffer path"
128 msgstr "Путања међумеморије помераја времена"
129
130 msgctxt "#30063"
131 msgid "Off"
132 msgstr "Искључено"
133
134 msgctxt "#30064"
135 msgid "On playback"
136 msgstr "При започињању репродукције"
137
138 msgctxt "#30065"
139 msgid "On pause"
140 msgstr "При паузирању"
141
142 msgctxt "#30071"
143 msgid "Recordings"
144 msgstr "Снимци"
145
146 msgctxt "#30072"
147 msgid "Timers"
148 msgstr "Тајмери"
149
150 msgctxt "#30085"
151 msgid "OK"
152 msgstr "У реду"
153
154 msgctxt "#30095"
155 msgid "True"
156 msgstr "Исправно"
157
158 msgctxt "#30096"
159 msgid "False"
160 msgstr "Нетачно"
161
162 msgctxt "#30410"
163 msgid "Automatic"
164 msgstr "Аутоматски"
165
166 msgctxt "#30430"
167 msgid "Disabled"
168 msgstr "Онемогућено"
117169
118170 msgctxt "#30500"
119171 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: sr_RS@latin\n"
1616 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ hostname ili IP adresa"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Port za Strimovanje"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Korisničko ime"
3123 msgid "Password"
3224 msgstr "Lozinka"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Veza"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikone"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Istek vremena za odziv u sekundama"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Putanja Ikona"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Interval ažuriranja u minutima"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatsko Čišćenje Liste Tajmera"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port Web interfejsa"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Isključi pre promene programa (npr. za kutije sa jednim prijemnikom)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Fascikla za podatke kanala"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Proveri za bouquett novije verzije"
47 msgid "Update interval"
48 msgstr "Interval ažuriranja"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Fascikla za snimanje na prijemniku"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Pošalji Komandu Duboke Pripravnosti"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Preuzmi samo jedan TV bouquet"
86 msgctxt "#30039"
87 msgid "Streaming"
88 msgstr "Strimovanje"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30042"
91 msgid "Never"
92 msgstr "Nikada"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Preuzmi picons od web interfejsa"
94 msgctxt "#30043"
95 msgid "In EPG only"
96 msgstr "Samo u EPG-u"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Koristi Sigurni HTTP (https)"
98 msgctxt "#30044"
99 msgid "In recordings only"
100 msgstr "Samo u snimcima"
101
102 msgctxt "#30045"
103 msgid "Always"
104 msgstr "Uvek"
105
106 msgctxt "#30051"
107 msgid "Login"
108 msgstr "Prijava"
109
110 msgctxt "#30052"
111 msgid "Misc"
112 msgstr "Ostalo"
113
114 msgctxt "#30056"
115 msgid "TV"
116 msgstr "TV"
117
118 msgctxt "#30057"
119 msgid "Radio"
120 msgstr "Radio"
121
122 msgctxt "#30060"
123 msgid "Timeshift"
124 msgstr "Pomeraj vremena"
125
126 msgctxt "#30062"
127 msgid "Timeshift buffer path"
128 msgstr "Putanja međumemorije pomeraja vremena"
129
130 msgctxt "#30063"
131 msgid "Off"
132 msgstr "Isključeno"
133
134 msgctxt "#30064"
135 msgid "On playback"
136 msgstr "Pri započinjanju reprodukcije"
137
138 msgctxt "#30065"
139 msgid "On pause"
140 msgstr "Pri pauziranju"
141
142 msgctxt "#30071"
143 msgid "Recordings"
144 msgstr "Snimci"
145
146 msgctxt "#30072"
147 msgid "Timers"
148 msgstr "Tajmeri"
149
150 msgctxt "#30085"
151 msgid "OK"
152 msgstr "U redu"
153
154 msgctxt "#30095"
155 msgid "True"
156 msgstr "Ispravno"
157
158 msgctxt "#30096"
159 msgid "False"
160 msgstr "Netačno"
161
162 msgctxt "#30410"
163 msgid "Automatic"
164 msgstr "Automatski"
165
166 msgctxt "#30430"
167 msgid "Disabled"
168 msgstr "Onemogućeno"
117169
118170 msgctxt "#30500"
119171 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ värdnamn eller IP-adress"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 värdnamn eller IP-adress"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
23 msgid "Streaming port"
2424 msgstr "Strömningsport"
2525
2626 msgctxt "#30003"
3131 msgid "Password"
3232 msgstr "Lösenord"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "Anslutning"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "Ikoner"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "Anslutningstimeout i sekunder"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "Ikonsökväg"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "Uppdateringsintervall"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "Uppdateringsintervall i minuter"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Automatisk timerlistsrensning"
59 msgid "Automatic timerlist cleanup"
60 msgstr "Automatisk upprensning av timerlista"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Webbgränssnittsport"
63 msgid "Web interface port"
64 msgstr "Port för webbgränssnitt"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Zappa före kanalbyte (för enkeltuner boxar)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
68 msgstr "Zappa innan kanalbyte (t.ex. för enskilda mottagarboxar)"
5769
5870 msgctxt "#30014"
5971 msgid "Folder for channeldata"
6072 msgstr "Mapp för kanaldata"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Sök efter bukett-uppdateringar"
75 msgid "Update interval"
76 msgstr "Uppdateringsintervall"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "Inspelningsmapp på mottagaren"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Skicka djupstandby-kommando"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "Sänd energisparläge vid avslutande av tillägget"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Hämta endast en TV-bukett"
115 msgid "TV bouquet fetch mode"
116 msgstr "TV-bukett hämtningsläge"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
119 msgid "TV bouquet"
108120 msgstr "TV-bukett"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Använd picons från webinterfacet"
123 msgid "Fetch picons from web interface"
124 msgstr "Hämta 'picons' från webbgränssnittet"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Använd Säker HTTP (https)"
127 msgid "Use secure HTTP (https)"
128 msgstr "Använd säker HTTP (https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "Aktivera automatisk konfiguration för direktsända strömmar"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "Behåll mappstruktur för inspelningar"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "Säsonger och Avsnitt"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "EPG"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "Extrahera säsonger, avsnitt och årinformation där det är möjligt"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "Aktivera automatisk timer"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "Använd picons.eu filformat"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "Aktivera generera repetitionstimer"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "Logg saknar genre textmappningar"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Webbgränssnitt"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "Strömning"
173
174 msgctxt "#30040"
175 msgid "Put outline (e.g. sub-title) before plot"
176 msgstr "Sätt översikt (t.ex. underrubrik) före handling"
177
178 msgctxt "#30041"
179 msgid "Stream read chunk size"
180 msgstr "Segmentstorlek på strömläsningar"
181
182 msgctxt "#30042"
183 msgid "Never"
184 msgstr "Aldrig"
185
186 msgctxt "#30043"
187 msgid "In EPG only"
188 msgstr "Endast i EPGn"
189
190 msgctxt "#30044"
191 msgid "In recordings only"
192 msgstr "Endast i inspelningar"
193
194 msgctxt "#30045"
195 msgid "Always"
196 msgstr "Alltid"
197
198 msgctxt "#30046"
199 msgid "Extract show info file"
200 msgstr "Extrahera show-infofil"
201
202 msgctxt "#30047"
203 msgid "Rytec genre text Mappings"
204 msgstr "Rytec genre textmappning"
205
206 msgctxt "#30048"
207 msgid "Enable Rytec genre text mappings"
208 msgstr "Aktivera Rytec genre textmappningar"
209
210 msgctxt "#30049"
211 msgid "Rytec genre text mappings file"
212 msgstr "Rytec genre textmappningsfil"
213
214 msgctxt "#30050"
215 msgid "Custom live TV timeout (0 to use default)"
216 msgstr "Anpassad Live-TV-timeout (0 för att använda standard)"
217
218 msgctxt "#30051"
219 msgid "Login"
220 msgstr "Logga in"
221
222 msgctxt "#30052"
223 msgid "Misc"
224 msgstr "Övrigt"
225
226 msgctxt "#30053"
227 msgid "Genre ID Mappings"
228 msgstr "Genre ID-mappningar"
229
230 msgctxt "#30054"
231 msgid "Enable genre ID Mappings"
232 msgstr "Aktivera genre ID-mappningar"
233
234 msgctxt "#30055"
235 msgid "Genre ID mappings file"
236 msgstr "Genre ID-mappningsfil"
237
238 msgctxt "#30056"
239 msgid "TV"
240 msgstr "TV"
241
242 msgctxt "#30057"
243 msgid "Radio"
244 msgstr "Radio"
245
246 msgctxt "#30058"
247 msgid "Radio bouquet fetch mode"
248 msgstr "Radio bukett hämtningsläge"
249
250 msgctxt "#30059"
251 msgid "Radio bouquet"
252 msgstr "Radio bukett"
253
254 msgctxt "#30060"
255 msgid "Timeshift"
256 msgstr "Tidsskifte"
257
258 msgctxt "#30061"
259 msgid "Enable timeshift"
260 msgstr "Aktivera tidsskifte"
261
262 msgctxt "#30062"
263 msgid "Timeshift buffer path"
264 msgstr "Buffertsökväg för Timeshift "
265
266 msgctxt "#30063"
267 msgid "Off"
268 msgstr "Av"
269
270 msgctxt "#30064"
271 msgid "On playback"
272 msgstr "Vid uppspelning"
273
274 msgctxt "#30065"
275 msgid "On pause"
276 msgstr "Vid paus"
277
278 msgctxt "#30066"
279 msgid "Use secure HTTP (https) for streams"
280 msgstr "Använd säker HTTP (https) för strömmar"
281
282 msgctxt "#30067"
283 msgid "Use login for streams"
284 msgstr "Använd inloggning för strömmar"
285
286 msgctxt "#30068"
287 msgid "Fetch TV favourites bouquet"
288 msgstr "Hämta TV-favoriter bukett"
289
290 msgctxt "#30069"
291 msgid "Fetch radio favourites bouquet"
292 msgstr "Hämta radio-favoriter bukett"
293
294 msgctxt "#30070"
295 msgid "Recordings & Timers"
296 msgstr "Inspelningar & Timers"
297
298 msgctxt "#30071"
299 msgid "Recordings"
300 msgstr "Inspelningar"
301
302 msgctxt "#30072"
303 msgid "Timers"
304 msgstr "Timers"
305
306 msgctxt "#30073"
307 msgid "Number of repeat timers to generate"
308 msgstr "Antalet av repetitionstimers att generera"
309
310 msgctxt "#30074"
311 msgid "All bouquets"
312 msgstr "Alla buketter"
313
314 msgctxt "#30075"
315 msgid "Only one bouquet"
316 msgstr "Endast en bukett"
317
318 msgctxt "#30076"
319 msgid "As first bouquet"
320 msgstr "Som första bukett"
321
322 msgctxt "#30077"
323 msgid "As last bouquet"
324 msgstr "Som sista bukett"
325
326 msgctxt "#30078"
327 msgid "Favourites group"
328 msgstr "Favoritgrupp"
329
330 msgctxt "#30079"
331 msgid "Favourites (TV)"
332 msgstr "Favoriter (TV)"
333
334 msgctxt "#30080"
335 msgid "Favourites (Radio)"
336 msgstr "Favoriter (Radio)"
337
338 msgctxt "#30081"
339 msgid "unknown"
340 msgstr "okänd"
341
342 msgctxt "#30082"
343 msgid " (Not connected!)"
344 msgstr "(Ej ansluten!)"
345
346 msgctxt "#30083"
347 msgid "addon error"
348 msgstr "tilläggsfel"
349
350 msgctxt "#30084"
351 msgid "Enigma2 Media Server"
352 msgstr "Enigma2 Media Server"
353
354 msgctxt "#30085"
355 msgid "OK"
356 msgstr "OK"
357
358 msgctxt "#30086"
359 msgid "Backend"
360 msgstr "Backend"
361
362 msgctxt "#30087"
363 msgid "Recording Padding"
364 msgstr "Inspelningsutfyllnad"
365
366 msgctxt "#30088"
367 msgid "Global start padding"
368 msgstr "Global startutfyllnad"
369
370 msgctxt "#30089"
371 msgid "Global end padding"
372 msgstr "Global slututfyllnad"
373
374 msgctxt "#30090"
375 msgid "Device Info"
376 msgstr "Enhetsinfo"
377
378 msgctxt "#30091"
379 msgid "WebIf version"
380 msgstr "WebIf version"
381
382 msgctxt "#30092"
383 msgid "AutoTimer tag in timer tags"
384 msgstr "AutoTimer tagg i timertaggar"
385
386 msgctxt "#30093"
387 msgid "AutoTimer name in timer tags"
388 msgstr "AutoTimer namn i timertaggar"
389
390 msgctxt "#30094"
391 msgid "N/A"
392 msgstr "N/A"
393
394 msgctxt "#30095"
395 msgid "True"
396 msgstr "Sant"
397
398 msgctxt "#30096"
399 msgid "False"
400 msgstr "Falskt"
401
402 msgctxt "#30097"
403 msgid "Standby"
404 msgstr "Standby"
405
406 msgctxt "#30098"
407 msgid "Deep standby"
408 msgstr "Djup standby"
409
410 msgctxt "#30099"
411 msgid "Wakeup, then standby"
412 msgstr "Väck, sedan standby"
413
414 msgctxt "#30100"
415 msgid "Update mode"
416 msgstr "Uppdateringsläge"
417
418 msgctxt "#30101"
419 msgid "Timers and recordings"
420 msgstr "Timers och inspelningar"
421
422 msgctxt "#30102"
423 msgid "Timers only"
424 msgstr "Endast timer"
425
426 msgctxt "#30103"
427 msgid "Use OpenWebIf picon path"
428 msgstr "Använd OpenWebIf picon sökväg"
429
430 msgctxt "#30410"
431 msgid "Automatic"
432 msgstr "Automatisk"
433
434 msgctxt "#30420"
435 msgid "One time (Scheduled by guide-based timer rule)"
436 msgstr "En gång (Schemalags av guide-baserad tidsregel)"
437
438 msgctxt "#30421"
439 msgid "One time (Scheduled by repeating timer rule)"
440 msgstr "En gång (Schemalagd av den upprepade timerregeln)"
441
442 msgctxt "#30430"
443 msgid "Disabled"
444 msgstr "Avaktiverad"
445
446 msgctxt "#30431"
447 msgid "Record if EPG title differs"
448 msgstr "Spela in om EPG-titeln skiljer sig åt"
449
450 msgctxt "#30432"
451 msgid "Record if EPG title and short description differs"
452 msgstr "Spela in om EPG-titeln och den korta beskrivningen skiljer sig åt"
453
454 msgctxt "#30433"
455 msgid "Record if EPG title and all descriptions differ"
456 msgstr "Spela in om EPG-titeln och alla beskrivningar skiljer sig åt"
117457
118458 msgctxt "#30500"
119459 msgid "Disconnected from '%s'"
122462 msgctxt "#30501"
123463 msgid "Reconnected to '%s'"
124464 msgstr "Återansluten till '%s'"
465
466 msgctxt "#30514"
467 msgid "Timeshift buffer path does not exist"
468 msgstr "Sökvägen för Tidsskifte-buffert existerar inte"
469
470 msgctxt "#30515"
471 msgid "Enigma2: Could not reach web interface"
472 msgstr "Enigma2: Kunde inte nå webbgränssnitt"
473
474 msgctxt "#30516"
475 msgid "Enigma2: No channel groups found"
476 msgstr "Enigma2: Inga kanalgrupper funna"
477
478 msgctxt "#30517"
479 msgid "Enigma2: No channels found"
480 msgstr "Enigma2: Inga kanaler funna"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: szl\n"
1616 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Miano lebo adresa ôd serwera"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Port szpricowaniŏ"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Miano ôd używŏcza"
3123 msgid "Password"
3224 msgstr "Hasło"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Skuplowanie"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Ikōny"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Czas na ôdpowiydź w sekundach"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Cesta do folderu z ikōnami"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Frekwyncyjŏ aktualizacyje we minutach"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Autōmatyczne pucowanie harmonogramu nagrań"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Port interfejsu necowygo"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Szaltruj na dany kanał (bp. dlŏ dekoderōw z jednym tunerym)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Folder datōw kanałōw"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Wybaduj aktualizacyje puketōw"
47 msgid "Update interval"
48 msgstr "Interwał ôdnŏwianiŏ"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Folder nagrowaniŏ na dekoderze"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Posyłej nakŏzanie głymbokigo wachowaniŏ"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "EPG"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Sebiyrej ino jedyn puket"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "nigdy"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "Puket"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "Ino w EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Sebiyrej loga kanałōw bez interfejs necowy"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Ino w nagraniach"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Używej bezpieczōnygo HTTP (HTTPS)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "dycki"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Wloguj"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Roztōmajte"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "Telewizyjŏ"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Radio"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Timeshift"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Cesta bufora timeshift"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Zastawiōne"
129
130 msgctxt "#30071"
131 msgid "Recordings"
132 msgstr "Spamiyntania"
133
134 msgctxt "#30072"
135 msgid "Timers"
136 msgstr "Auftragi"
137
138 msgctxt "#30085"
139 msgid "OK"
140 msgstr "OK"
141
142 msgctxt "#30095"
143 msgid "True"
144 msgstr "Prŏwda"
145
146 msgctxt "#30096"
147 msgid "False"
148 msgstr "Fałsz"
149
150 msgctxt "#30410"
151 msgid "Automatic"
152 msgstr "Autōmat"
153
154 msgctxt "#30430"
155 msgid "Disabled"
156 msgstr "Zastawiōne"
117157
118158 msgctxt "#30500"
119159 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "அடையாளச் சொல்"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "சின்னங்கள்"
29
30 msgctxt "#30015"
31 msgid "Update interval"
32 msgstr "இடைவேளையை மெருகேற்று"
33
2634 msgctxt "#30018"
2735 msgid "General"
2836 msgstr "பொதுவானது"
3846 msgctxt "#30021"
3947 msgid "HTTP"
4048 msgstr "HTTP"
49
50 msgctxt "#30042"
51 msgid "Never"
52 msgstr "ஒருபோதும் இல்லை"
53
54 msgctxt "#30045"
55 msgid "Always"
56 msgstr "எப்போதும்"
57
58 msgctxt "#30051"
59 msgid "Login"
60 msgstr "புகுபதிகை"
61
62 msgctxt "#30056"
63 msgid "TV"
64 msgstr "தொலைக்காட்சி"
65
66 msgctxt "#30057"
67 msgid "Radio"
68 msgstr "வானொலி"
69
70 msgctxt "#30063"
71 msgid "Off"
72 msgstr "நிறுத்து"
73
74 msgctxt "#30071"
75 msgid "Recordings"
76 msgstr "பதிவகள்"
77
78 msgctxt "#30085"
79 msgid "OK"
80 msgstr "சரி"
81
82 msgctxt "#30095"
83 msgid "True"
84 msgstr "உண்மை"
85
86 msgctxt "#30096"
87 msgid "False"
88 msgstr "தவறு"
89
90 msgctxt "#30430"
91 msgid "Disabled"
92 msgstr "முடக்கப்பட்டன"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
3030 msgctxt "#30018"
3131 msgid "General"
3232 msgstr "సాధారణం"
33
34 msgctxt "#30085"
35 msgid "OK"
36 msgstr "సరే"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2222 msgctxt "#30004"
2323 msgid "Password"
2424 msgstr "Парол"
25
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Нишонаҳо"
2529
2630 msgctxt "#30007"
2731 msgid "Response timeout in seconds"
4347 msgid "HTTP"
4448 msgstr "HTTP"
4549
50 msgctxt "#30042"
51 msgid "Never"
52 msgstr "Ҳеҷ гоҳ"
53
54 msgctxt "#30045"
55 msgid "Always"
56 msgstr "Ҳамеша"
57
58 msgctxt "#30051"
59 msgid "Login"
60 msgstr "Вуруд"
61
62 msgctxt "#30056"
63 msgid "TV"
64 msgstr "ТВ"
65
66 msgctxt "#30057"
67 msgid "Radio"
68 msgstr "Радио"
69
70 msgctxt "#30063"
71 msgid "Off"
72 msgstr "Хомӯш"
73
74 msgctxt "#30071"
75 msgid "Recordings"
76 msgstr "Сабтҳо"
77
78 msgctxt "#30085"
79 msgid "OK"
80 msgstr "OK"
81
82 msgctxt "#30095"
83 msgid "True"
84 msgstr "Фаъол"
85
86 msgctxt "#30096"
87 msgid "False"
88 msgstr "Ғайрифаъол"
89
90 msgctxt "#30430"
91 msgid "Disabled"
92 msgstr "Ғайрифаъол"
93
4694 msgctxt "#30500"
4795 msgid "Disconnected from '%s'"
4896 msgstr "Пайваст бо '%s' қатъ шудааст"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: th_TH\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
18 msgctxt "#30002"
19 msgid "Streaming Port"
20 msgstr "พอร์ตการสตรีมมิ่ง"
21
2218 msgctxt "#30003"
2319 msgid "Username"
2420 msgstr "ชื่อผู้ใช้"
2723 msgid "Password"
2824 msgstr "รหัสผ่าน"
2925
30 msgctxt "#30012"
31 msgid "Webinterface Port"
32 msgstr "พอร์ต Webinterface"
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "การเชื่อมต่อ"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "ไอคอน"
33
34 msgctxt "#30015"
35 msgid "Update interval"
36 msgstr "ช่วงเวลาการปรับปรุง"
3337
3438 msgctxt "#30018"
3539 msgid "General"
4650 msgctxt "#30021"
4751 msgid "HTTP"
4852 msgstr "HTTP"
53
54 msgctxt "#30042"
55 msgid "Never"
56 msgstr "ไม่เลย"
57
58 msgctxt "#30043"
59 msgid "In EPG only"
60 msgstr "ใน EPG เท่านั้น"
61
62 msgctxt "#30044"
63 msgid "In recordings only"
64 msgstr "ในการบันทึกเท่านั้น"
65
66 msgctxt "#30045"
67 msgid "Always"
68 msgstr "เสมอ"
69
70 msgctxt "#30051"
71 msgid "Login"
72 msgstr "ลงชื่อเข้าใช้"
73
74 msgctxt "#30056"
75 msgid "TV"
76 msgstr "ทีวี"
77
78 msgctxt "#30057"
79 msgid "Radio"
80 msgstr "วิทยุ"
81
82 msgctxt "#30062"
83 msgid "Timeshift buffer path"
84 msgstr "เส้นทางบัฟเฟอร์ของ Timeshift"
85
86 msgctxt "#30063"
87 msgid "Off"
88 msgstr "ปิด"
89
90 msgctxt "#30071"
91 msgid "Recordings"
92 msgstr "กำลังบันทึก"
93
94 msgctxt "#30072"
95 msgid "Timers"
96 msgstr "ตั้งเวลา"
97
98 msgctxt "#30085"
99 msgid "OK"
100 msgstr "ตกลง"
101
102 msgctxt "#30095"
103 msgid "True"
104 msgstr "จริง"
105
106 msgctxt "#30096"
107 msgid "False"
108 msgstr "ไม่จริง"
109
110 msgctxt "#30410"
111 msgid "Automatic"
112 msgstr "อัตโนมัติ"
113
114 msgctxt "#30430"
115 msgid "Disabled"
116 msgstr "ปิดการใช้งาน"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: tr_TR\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ ana bilgisayar adı veya IP adresi"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Yayın Portu"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Kullanıcı adı"
3123 msgid "Password"
3224 msgstr "Parola"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Bağlantı"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Simgeler"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Saniye cinsinden yanıt zaman aşımı süresi"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Simge Yolu"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Güncelleme aralığı dakikası"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Otomatik Zamanlayıcı Listesi Temizleme"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Web arayüzü Portu"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Kanal değişiminden önce değiştir (örn. Tek Alıcılı kutular)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Kanal verisi için klasör"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "bouquett güncellemelerini denetle"
47 msgid "Update interval"
48 msgstr "Güncelleme aralığı"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Alıcıdaki kayıt klasörü"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Derin Hazırda Beklet komutu yolla"
82 msgctxt "#30032"
83 msgid "EPG"
84 msgstr "Elektronik Program Rehberi"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Sadece tek TV destesi getir"
86 msgctxt "#30042"
87 msgid "Never"
88 msgstr "Asla"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV Destesi"
90 msgctxt "#30043"
91 msgid "In EPG only"
92 msgstr "Sadece EPG içinde"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Picon'ları web arayüzünden getir"
94 msgctxt "#30044"
95 msgid "In recordings only"
96 msgstr "Sadece kayıtlarda"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Güvenli HTTP kullan (https)"
98 msgctxt "#30045"
99 msgid "Always"
100 msgstr "Her zaman"
101
102 msgctxt "#30051"
103 msgid "Login"
104 msgstr "Oturum Aç"
105
106 msgctxt "#30052"
107 msgid "Misc"
108 msgstr "Çeşitli"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "TV"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Radyo"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Zaman Kaydırma"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Zaman kaydırma arabellek yolu"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Kapalı"
129
130 msgctxt "#30071"
131 msgid "Recordings"
132 msgstr "Kayıtlar"
133
134 msgctxt "#30072"
135 msgid "Timers"
136 msgstr "Zamanlayıcılar"
137
138 msgctxt "#30085"
139 msgid "OK"
140 msgstr "Tamam"
141
142 msgctxt "#30095"
143 msgid "True"
144 msgstr "Doğru"
145
146 msgctxt "#30096"
147 msgid "False"
148 msgstr "Yanlış"
149
150 msgctxt "#30410"
151 msgid "Automatic"
152 msgstr "Otomatik"
153
154 msgctxt "#30430"
155 msgid "Disabled"
156 msgstr "Devre dışı"
117157
118158 msgctxt "#30500"
119159 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: uk_UA\n"
1616 "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Сервер VU+ або адреса IP"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Порт потоку"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Ім'я користувача"
3123 msgid "Password"
3224 msgstr "Пароль"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Зв’язок"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Піктограми"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Затримка відклику в секундах"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Шлях до іконки"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Інтервал оновлення в хвилинах"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Автоматичне очищення списку таймерів"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Порт веб-інтерфейсу"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Схопити сигнал перед переключенням каналу (тобто для одного тюнера)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Тека для даних каналів"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Перевірка на букетне оновлення "
47 msgid "Update interval"
48 msgstr "Інтервал оновлень"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "Тека записів на ресівері"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Вислати команду глибокої зупинки"
82 msgctxt "#30029"
83 msgid "Enable automatic configuration for live streams"
84 msgstr "Увімкнути автоматичну конфігурацію для прямих трансляцій"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Отримати тільки один TV bouquet"
86 msgctxt "#30030"
87 msgid "Keep folder structure for records"
88 msgstr "Зберігати структуру папок для записів"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
90 msgctxt "#30032"
91 msgid "EPG"
92 msgstr "EPG"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Отримати пікони з веб-інтерфейсу"
94 msgctxt "#30042"
95 msgid "Never"
96 msgstr "Ніколи"
97
98 msgctxt "#30043"
99 msgid "In EPG only"
100 msgstr "Тільки в EPG"
101
102 msgctxt "#30045"
103 msgid "Always"
104 msgstr "Завжди"
105
106 msgctxt "#30051"
107 msgid "Login"
108 msgstr " Логін"
109
110 msgctxt "#30056"
111 msgid "TV"
112 msgstr "ТБ"
113
114 msgctxt "#30057"
115 msgid "Radio"
116 msgstr "Радіо"
117
118 msgctxt "#30060"
119 msgid "Timeshift"
120 msgstr "Зрушення в часі"
121
122 msgctxt "#30062"
123 msgid "Timeshift buffer path"
124 msgstr "Шлях до буферу зсуву у часі"
125
126 msgctxt "#30063"
127 msgid "Off"
128 msgstr "Вимкн."
129
130 msgctxt "#30064"
131 msgid "On playback"
132 msgstr "Під час відтворення"
133
134 msgctxt "#30071"
135 msgid "Recordings"
136 msgstr "Записи"
137
138 msgctxt "#30072"
139 msgid "Timers"
140 msgstr "Таймери"
141
142 msgctxt "#30085"
143 msgid "OK"
144 msgstr "ОК"
145
146 msgctxt "#30094"
147 msgid "N/A"
148 msgstr "Н/Д"
149
150 msgctxt "#30095"
151 msgid "True"
152 msgstr "Так"
153
154 msgctxt "#30096"
155 msgid "False"
156 msgstr "Ні"
157
158 msgctxt "#30410"
159 msgid "Automatic"
160 msgstr "Автоматично"
161
162 msgctxt "#30430"
163 msgid "Disabled"
164 msgstr "Вимкн."
113165
114166 msgctxt "#30500"
115167 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
2323 msgid "Password"
2424 msgstr "Maxfiy so'z"
2525
26 msgctxt "#30006"
27 msgid "Icons"
28 msgstr "Nishonchalar"
29
2630 msgctxt "#30018"
2731 msgid "General"
2832 msgstr "Umumiy"
3438 msgctxt "#30021"
3539 msgid "HTTP"
3640 msgstr "HTTP"
41
42 msgctxt "#30042"
43 msgid "Never"
44 msgstr "Hech qachon"
45
46 msgctxt "#30045"
47 msgid "Always"
48 msgstr "Doim"
49
50 msgctxt "#30051"
51 msgid "Login"
52 msgstr "Kirish"
53
54 msgctxt "#30056"
55 msgid "TV"
56 msgstr "TV"
57
58 msgctxt "#30057"
59 msgid "Radio"
60 msgstr "Radio"
61
62 msgctxt "#30063"
63 msgid "Off"
64 msgstr "O'chirilgan"
65
66 msgctxt "#30085"
67 msgid "OK"
68 msgstr "OK"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: vi_VN\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "Tên miền hoặc địa chỉ IP của VU+"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "Cổng Streaming"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "Tên truy cập"
3123 msgid "Password"
3224 msgstr "Mật khẩu"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "Kết nối"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "Biểu tượng"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "Số giây tự ngắt chờ kết nối"
37
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "Đường dẫn biểu tượng"
4137
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "Số phút tự cập nhật lại"
4541
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "Tự động xoá danh sách hẹn giờ"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Cổng Webinterface"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "Tắt trước khi chuyển kênh (ví dụ cho các Single Tuner box)"
57
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "Thư mục đặt dữ liệu cho kênh"
61
62 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "Kiểm tra cập nhật bouquett"
6545
6646 msgctxt "#30016"
6747 msgid "Check for channel updates"
9575 msgid "Recording folder on the receiver"
9676 msgstr "Thư mục lưu trên thiết bị"
9777
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "Gửi lệnh Chế Độ Chờ"
78 msgctxt "#30042"
79 msgid "Never"
80 msgstr "Không bao giờ"
10181
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "Chỉ lấy một TV bouquet"
82 msgctxt "#30045"
83 msgid "Always"
84 msgstr "Luôn luôn"
10585
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "TV-Bouquet"
86 msgctxt "#30051"
87 msgid "Login"
88 msgstr "Đăng nhập"
10989
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "Lấy các hình icon từ mạng"
90 msgctxt "#30056"
91 msgid "TV"
92 msgstr "TV"
11393
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "Sử dụng an toàn HTTP (https)"
94 msgctxt "#30057"
95 msgid "Radio"
96 msgstr "Radio"
97
98 msgctxt "#30062"
99 msgid "Timeshift buffer path"
100 msgstr "Đường dẫn bộ đệm Timeshift"
101
102 msgctxt "#30063"
103 msgid "Off"
104 msgstr "Tắt"
105
106 msgctxt "#30071"
107 msgid "Recordings"
108 msgstr "Các bản ghi"
109
110 msgctxt "#30085"
111 msgid "OK"
112 msgstr "OK"
113
114 msgctxt "#30095"
115 msgid "True"
116 msgstr "Đúng"
117
118 msgctxt "#30430"
119 msgid "Disabled"
120 msgstr "Đã tắt"
117121
118122 msgctxt "#30500"
119123 msgid "Disconnected from '%s'"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
1818 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+ 主机名或 IP 地址"
19 msgid "Enigma2 hostname or IP address"
20 msgstr "Enigma2 机器名或 IP 地址"
2121
2222 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "流媒体端口"
23 msgid "Streaming port"
24 msgstr "流端口"
2525
2626 msgctxt "#30003"
2727 msgid "Username"
3131 msgid "Password"
3232 msgstr "密码"
3333
34 msgctxt "#30005"
35 msgid "Connection"
36 msgstr "连接"
37
38 msgctxt "#30006"
39 msgid "Icons"
40 msgstr "图标"
41
3442 msgctxt "#30007"
3543 msgid "Response timeout in seconds"
3644 msgstr "响应超时(秒)"
3745
3846 msgctxt "#30008"
39 msgid "Icon Path"
47 msgid "Icon path"
4048 msgstr "图标路径"
49
50 msgctxt "#30009"
51 msgid "Update Interval"
52 msgstr "更新间隔"
4153
4254 msgctxt "#30010"
4355 msgid "Update Interval in minutes"
4456 msgstr "更新间隔(分)"
4557
4658 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
59 msgid "Automatic timerlist cleanup"
4860 msgstr "自动清除定时器列表"
4961
5062 msgctxt "#30012"
51 msgid "Webinterface Port"
63 msgid "Web interface port"
5264 msgstr "Web 界面端口"
5365
5466 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
67 msgid "Zap before channelswitch (i.e. for single tuner boxes)"
5668 msgstr "频道切换前清屏(如单调谐器机顶盒)"
5769
5870 msgctxt "#30014"
6072 msgstr "频道数据文件夹"
6173
6274 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "检查频道组更新"
75 msgid "Update interval"
76 msgstr "更新间隔"
6577
6678 msgctxt "#30016"
6779 msgid "Check for channel updates"
96108 msgstr "接收器上的录像文件夹"
97109
98110 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "发送 DeepStandby 命令"
111 msgid "Send powerstate mode on addon exit"
112 msgstr "在插件退出时发送电源状态模式"
101113
102114 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "仅获取一个电视频道组"
115 msgid "TV bouquet fetch mode"
116 msgstr "电视频道组获取模式"
105117
106118 msgctxt "#30026"
107 msgid "TV-Bouquet"
119 msgid "TV bouquet"
108120 msgstr "电视频道组"
109121
110122 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
123 msgid "Fetch picons from web interface"
112124 msgstr "从 Web 界面获取 picons"
113125
114126 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
127 msgid "Use secure HTTP (https)"
116128 msgstr "使用安全连接(https)"
129
130 msgctxt "#30029"
131 msgid "Enable automatic configuration for live streams"
132 msgstr "启用直播流自动设置"
133
134 msgctxt "#30030"
135 msgid "Keep folder structure for records"
136 msgstr "保留录像文件夹结构"
137
138 msgctxt "#30031"
139 msgid "Seasons and Episodes"
140 msgstr "季和集"
141
142 msgctxt "#30032"
143 msgid "EPG"
144 msgstr "电子节目单"
145
146 msgctxt "#30033"
147 msgid "Extract season, episode and year info where possible"
148 msgstr "可能的情况下提取季、集和年信息"
149
150 msgctxt "#30034"
151 msgid "Enable autotimers"
152 msgstr "启用自动定时器"
153
154 msgctxt "#30035"
155 msgid "Use picons.eu file format"
156 msgstr "使用 picons.eu 文件格式"
157
158 msgctxt "#30036"
159 msgid "Enable generate repeat timers"
160 msgstr "启用生成重复定时器"
161
162 msgctxt "#30037"
163 msgid "Log missing genre text mappings"
164 msgstr "记录缺少的类型文本映射"
165
166 msgctxt "#30038"
167 msgid "Web Interface"
168 msgstr "Web 界面"
169
170 msgctxt "#30039"
171 msgid "Streaming"
172 msgstr "串流中"
173
174 msgctxt "#30041"
175 msgid "Stream read chunk size"
176 msgstr "流读取块大小"
177
178 msgctxt "#30042"
179 msgid "Never"
180 msgstr "从不"
181
182 msgctxt "#30043"
183 msgid "In EPG only"
184 msgstr "仅电子节目单中"
185
186 msgctxt "#30044"
187 msgid "In recordings only"
188 msgstr "仅录像中"
189
190 msgctxt "#30045"
191 msgid "Always"
192 msgstr "总是"
193
194 msgctxt "#30046"
195 msgid "Extract show info file"
196 msgstr "提取显示信息"
197
198 msgctxt "#30047"
199 msgid "Rytec genre text Mappings"
200 msgstr "Rytec 类型文本映射"
201
202 msgctxt "#30048"
203 msgid "Enable Rytec genre text mappings"
204 msgstr "启用 Rytec 类型文本映射"
205
206 msgctxt "#30049"
207 msgid "Rytec genre text mappings file"
208 msgstr "Rytec 类型文本映射文件"
209
210 msgctxt "#30050"
211 msgid "Custom live TV timeout (0 to use default)"
212 msgstr "自定义直播电视超时(0为默认值)"
213
214 msgctxt "#30051"
215 msgid "Login"
216 msgstr "登录"
217
218 msgctxt "#30052"
219 msgid "Misc"
220 msgstr "杂项"
221
222 msgctxt "#30053"
223 msgid "Genre ID Mappings"
224 msgstr "类型ID映射"
225
226 msgctxt "#30054"
227 msgid "Enable genre ID Mappings"
228 msgstr "启用类型ID映射"
229
230 msgctxt "#30055"
231 msgid "Genre ID mappings file"
232 msgstr "类型 ID 映射文件"
233
234 msgctxt "#30056"
235 msgid "TV"
236 msgstr "电视"
237
238 msgctxt "#30057"
239 msgid "Radio"
240 msgstr "电台"
241
242 msgctxt "#30058"
243 msgid "Radio bouquet fetch mode"
244 msgstr "电台列表获取模式"
245
246 msgctxt "#30059"
247 msgid "Radio bouquet"
248 msgstr "电台频道组"
249
250 msgctxt "#30060"
251 msgid "Timeshift"
252 msgstr "时光平移"
253
254 msgctxt "#30061"
255 msgid "Enable timeshift"
256 msgstr "启用时光平移"
257
258 msgctxt "#30062"
259 msgid "Timeshift buffer path"
260 msgstr "时光平移缓存路径"
261
262 msgctxt "#30063"
263 msgid "Off"
264 msgstr "关"
265
266 msgctxt "#30064"
267 msgid "On playback"
268 msgstr "播放中"
269
270 msgctxt "#30065"
271 msgid "On pause"
272 msgstr "暂停中"
273
274 msgctxt "#30066"
275 msgid "Use secure HTTP (https) for streams"
276 msgstr "为流使用安全连接(https)"
277
278 msgctxt "#30067"
279 msgid "Use login for streams"
280 msgstr "登录使用流"
281
282 msgctxt "#30068"
283 msgid "Fetch TV favourites bouquet"
284 msgstr "获取电视收藏列表"
285
286 msgctxt "#30069"
287 msgid "Fetch radio favourites bouquet"
288 msgstr "获取电台收藏列表"
289
290 msgctxt "#30070"
291 msgid "Recordings & Timers"
292 msgstr "录像和定时器"
293
294 msgctxt "#30071"
295 msgid "Recordings"
296 msgstr "录像"
297
298 msgctxt "#30072"
299 msgid "Timers"
300 msgstr "定时器"
301
302 msgctxt "#30073"
303 msgid "Number of repeat timers to generate"
304 msgstr "生成的重复定时器数目"
305
306 msgctxt "#30074"
307 msgid "All bouquets"
308 msgstr "全部频道组"
309
310 msgctxt "#30075"
311 msgid "Only one bouquet"
312 msgstr "仅一个列表"
313
314 msgctxt "#30076"
315 msgid "As first bouquet"
316 msgstr "作为第一个列表"
317
318 msgctxt "#30077"
319 msgid "As last bouquet"
320 msgstr "作为最后一个列表"
321
322 msgctxt "#30078"
323 msgid "Favourites group"
324 msgstr "收藏夹组"
325
326 msgctxt "#30079"
327 msgid "Favourites (TV)"
328 msgstr "收藏夹(电视)"
329
330 msgctxt "#30080"
331 msgid "Favourites (Radio)"
332 msgstr "收藏夹(电台)"
333
334 msgctxt "#30081"
335 msgid "unknown"
336 msgstr "未知"
337
338 msgctxt "#30082"
339 msgid " (Not connected!)"
340 msgstr "(未连接!)"
341
342 msgctxt "#30083"
343 msgid "addon error"
344 msgstr "插件错误"
345
346 msgctxt "#30084"
347 msgid "Enigma2 Media Server"
348 msgstr "Enigma2 媒体服务器"
349
350 msgctxt "#30085"
351 msgid "OK"
352 msgstr "确定"
353
354 msgctxt "#30086"
355 msgid "Backend"
356 msgstr "后端"
357
358 msgctxt "#30088"
359 msgid "Global start padding"
360 msgstr "全局开始填充"
361
362 msgctxt "#30089"
363 msgid "Global end padding"
364 msgstr "全局结束填充"
365
366 msgctxt "#30090"
367 msgid "Device Info"
368 msgstr "设备信息"
369
370 msgctxt "#30091"
371 msgid "WebIf version"
372 msgstr "WebIf 版本"
373
374 msgctxt "#30092"
375 msgid "AutoTimer tag in timer tags"
376 msgstr "定时器标签中的自动定时器标签"
377
378 msgctxt "#30093"
379 msgid "AutoTimer name in timer tags"
380 msgstr "定时器标签中的自动定时器名称"
381
382 msgctxt "#30094"
383 msgid "N/A"
384 msgstr "不可用"
385
386 msgctxt "#30095"
387 msgid "True"
388 msgstr "真"
389
390 msgctxt "#30096"
391 msgid "False"
392 msgstr "假"
393
394 msgctxt "#30097"
395 msgid "Standby"
396 msgstr "待机"
397
398 msgctxt "#30098"
399 msgid "Deep standby"
400 msgstr "深度待机"
401
402 msgctxt "#30099"
403 msgid "Wakeup, then standby"
404 msgstr "唤醒,然后待机"
405
406 msgctxt "#30100"
407 msgid "Update mode"
408 msgstr "更新模式"
409
410 msgctxt "#30101"
411 msgid "Timers and recordings"
412 msgstr "定时器和录像"
413
414 msgctxt "#30102"
415 msgid "Timers only"
416 msgstr "仅限定时器"
417
418 msgctxt "#30410"
419 msgid "Automatic"
420 msgstr "自动"
421
422 msgctxt "#30420"
423 msgid "One time (Scheduled by guide-based timer rule)"
424 msgstr "单次(由基于指南的定时器规则计划)"
425
426 msgctxt "#30421"
427 msgid "One time (Scheduled by repeating timer rule)"
428 msgstr "单次(由重复定时器计划)"
429
430 msgctxt "#30430"
431 msgid "Disabled"
432 msgstr "已禁用"
433
434 msgctxt "#30431"
435 msgid "Record if EPG title differs"
436 msgstr "录制电子节目单标题不同的"
437
438 msgctxt "#30432"
439 msgid "Record if EPG title and short description differs"
440 msgstr "录制电子节目单标题和简介不同的"
441
442 msgctxt "#30433"
443 msgid "Record if EPG title and all descriptions differ"
444 msgstr "录制电子节目单标题和全面介绍不同的"
117445
118446 msgctxt "#30500"
119447 msgid "Disconnected from '%s'"
122450 msgctxt "#30501"
123451 msgid "Reconnected to '%s'"
124452 msgstr "重新连接到“%s”"
453
454 msgctxt "#30514"
455 msgid "Timeshift buffer path does not exist"
456 msgstr "时光平移缓存路径不存在"
00 # Kodi Media Center language file
1 # Addon Name: VU+ / Enigma2 Client
1 # Addon Name: Enigma2 Client
22 # Addon id: pvr.vuplus
3 # Addon Provider: Joerg Dembski
3 # Addon Provider: Joerg Dembski and Ross Nicholson
44 msgid ""
55 msgstr ""
66 "Project-Id-Version: KODI Main\n"
7 "Report-Msgid-Bugs-To: http://trac.kodi.tv/\n"
7 "Report-Msgid-Bugs-To: https://github.com/xbmc/xbmc/issues/\n"
88 "POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE\n"
99 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1010 "Last-Translator: Kodi Translation Team\n"
1515 "Language: zh_TW\n"
1616 "Plural-Forms: nplurals=1; plural=0;\n"
1717
18 msgctxt "#30000"
19 msgid "VU+ hostname or IP address"
20 msgstr "VU+主機名稱或IP位址"
21
22 msgctxt "#30002"
23 msgid "Streaming Port"
24 msgstr "串流連接埠"
25
2618 msgctxt "#30003"
2719 msgid "Username"
2820 msgstr "帳號"
3123 msgid "Password"
3224 msgstr "密碼"
3325
26 msgctxt "#30005"
27 msgid "Connection"
28 msgstr "連接"
29
30 msgctxt "#30006"
31 msgid "Icons"
32 msgstr "圖示"
33
3434 msgctxt "#30007"
3535 msgid "Response timeout in seconds"
3636 msgstr "回應逾時 (秒)"
3737
38 msgctxt "#30008"
39 msgid "Icon Path"
40 msgstr "圖示路徑"
41
4238 msgctxt "#30010"
4339 msgid "Update Interval in minutes"
4440 msgstr "更新頻率 (分)"
45
46 msgctxt "#30011"
47 msgid "Automatic Timerlist Cleanup"
48 msgstr "自動清除定時器清單"
49
50 msgctxt "#30012"
51 msgid "Webinterface Port"
52 msgstr "Web介面端口"
53
54 msgctxt "#30013"
55 msgid "Zap before channelswitch (i.e. for Single Tuner boxes)"
56 msgstr "頻道切換前修正 (i.e.針對單頻電視盒)"
5741
5842 msgctxt "#30014"
5943 msgid "Folder for channeldata"
6044 msgstr "channeldata的資料夾"
6145
6246 msgctxt "#30015"
63 msgid "Check for bouquett updates"
64 msgstr "檢查節目群組更新"
47 msgid "Update interval"
48 msgstr "更新間隔"
6549
6650 msgctxt "#30016"
6751 msgid "Check for channel updates"
9579 msgid "Recording folder on the receiver"
9680 msgstr "接收器上的錄影資料夾"
9781
98 msgctxt "#30024"
99 msgid "Send DeepStandby-Command"
100 msgstr "傳送 DeepStandby-Command"
82 msgctxt "#30029"
83 msgid "Enable automatic configuration for live streams"
84 msgstr "開啟即時串流的自動配置"
10185
102 msgctxt "#30025"
103 msgid "Fetch only one TV bouquet"
104 msgstr "只取單一電視節目群組"
86 msgctxt "#30030"
87 msgid "Keep folder structure for records"
88 msgstr "保留錄影的資料夾架構"
10589
106 msgctxt "#30026"
107 msgid "TV-Bouquet"
108 msgstr "電視節目群組"
90 msgctxt "#30032"
91 msgid "EPG"
92 msgstr "電子節目表"
10993
110 msgctxt "#30027"
111 msgid "Fetch picons from webinterface"
112 msgstr "從Web界面獲取picons"
94 msgctxt "#30042"
95 msgid "Never"
96 msgstr "永不"
11397
114 msgctxt "#30028"
115 msgid "Use Secure HTTP (https)"
116 msgstr "使用安全協定 (https)"
98 msgctxt "#30043"
99 msgid "In EPG only"
100 msgstr "僅限有在電子節目表中的"
101
102 msgctxt "#30044"
103 msgid "In recordings only"
104 msgstr "僅限有在錄影檔中的"
105
106 msgctxt "#30045"
107 msgid "Always"
108 msgstr "總是"
109
110 msgctxt "#30051"
111 msgid "Login"
112 msgstr "登入"
113
114 msgctxt "#30052"
115 msgid "Misc"
116 msgstr "雜項"
117
118 msgctxt "#30056"
119 msgid "TV"
120 msgstr "電視"
121
122 msgctxt "#30057"
123 msgid "Radio"
124 msgstr "無線電廣播"
125
126 msgctxt "#30060"
127 msgid "Timeshift"
128 msgstr "時間平移"
129
130 msgctxt "#30062"
131 msgid "Timeshift buffer path"
132 msgstr "時間平移緩衝路徑"
133
134 msgctxt "#30063"
135 msgid "Off"
136 msgstr "關閉"
137
138 msgctxt "#30064"
139 msgid "On playback"
140 msgstr "當播放中"
141
142 msgctxt "#30065"
143 msgid "On pause"
144 msgstr "當暫停中"
145
146 msgctxt "#30071"
147 msgid "Recordings"
148 msgstr "錄影檔"
149
150 msgctxt "#30072"
151 msgid "Timers"
152 msgstr "定時"
153
154 msgctxt "#30085"
155 msgid "OK"
156 msgstr "確定"
157
158 msgctxt "#30094"
159 msgid "N/A"
160 msgstr "N/A"
161
162 msgctxt "#30095"
163 msgid "True"
164 msgstr "真實"
165
166 msgctxt "#30096"
167 msgid "False"
168 msgstr "錯誤"
169
170 msgctxt "#30410"
171 msgid "Automatic"
172 msgstr "自動"
173
174 msgctxt "#30430"
175 msgid "Disabled"
176 msgstr "關閉"
117177
118178 msgctxt "#30500"
119179 msgid "Disconnected from '%s'"
0 <?xml version="1.0" encoding="utf-8" standalone="yes"?>
1 <settings>
2 <!-- SYSTEM -->
3 <category label="30018">
4 <setting id="host" type="text" label="30000" default="127.0.0.1" />
5 <setting id="onlinepicons" type="bool" default="true" label="30027" />
6 <setting id="iconpath" type="folder" label="30008" enable="eq(-1,false)" default="" />
7 <setting id="updateint" type="number" label="30010" default="2" />
8 </category>
9
10 <!-- Channels -->
11 <category label="30019">
12 <setting label="30025" type="bool" id="onlyonegroup" default="false"/>
13 <setting label="30026" type="text" id="onegroup" default="" enable="eq(-1,true)" />
14 <setting label="30013" type="bool" id="zap" default="false"/>
15 </category>
16
17 <!-- Advanced -->
18 <category label="30020">
19 <setting id="streamport" type="number" label="30002" default="8001" />
20 <setting id="webport" type="number" label="30012" default="80" />
21 <setting label="30028" type="bool" id="use_secure" default="false"/>
22 <setting id="user" type="text" label="30003" default="" />
23 <setting id="pass" type="text" label="30004" option="hidden" default="" />
24 <setting id="recordingpath" type="text" label="30023" default="" />
25 <setting label="30017" type="bool" id="onlycurrent" default="false"/>
26 <setting label="30011" type="bool" id="timerlistcleanup" default="false"/>
27 <setting label="30024" type="bool" id="setpowerstate" default="false" />
28 </category>
0 <?xml version="1.0" encoding="utf-8" ?>
1 <settings version="1">
2 <section id="pvr.vuplus">
3
4 <!-- Connection -->
5 <category id="connection" label="30005" help="30600">
6 <group id="1" label="30038">
7 <setting id="host" type="string" label="30000" help="30601">
8 <level>0</level>
9 <default>127.0.0.1</default>
10 <control type="edit" format="string" />
11 </setting>
12 <setting id="webport" type="integer" label="30012" help="30602">
13 <level>0</level>
14 <default>80</default>
15 <constraints>
16 <minimum>1</minimum>
17 <step>1</step>
18 <maximum>65535</maximum>
19 </constraints>
20 <control type="edit" format="integer" />
21 </setting>
22 <setting id="use_secure" type="boolean" label="30028" help="30603">
23 <level>1</level>
24 <default>false</default>
25 <control type="toggle" />
26 </setting>
27 </group>
28 <group id="2" label="30051">
29 <setting id="user" type="string" label="30003" help="30604">
30 <level>1</level>
31 <default></default>
32 <constraints>
33 <allowempty>true</allowempty>
34 </constraints>
35 <control type="edit" format="string" />
36 </setting>
37 <setting id="pass" type="string" label="30004" help="30605">
38 <level>1</level>
39 <default></default>
40 <constraints>
41 <allowempty>true</allowempty>
42 </constraints>
43 <control type="edit" format="string">
44 <hidden>true</hidden>
45 </control>
46 </setting>
47 </group>
48 <group id="3" label="30039">
49 <setting id="autoconfig" type="boolean" label="30029" help="30606">
50 <level>2</level>
51 <default>false</default>
52 <control type="toggle" />
53 </setting>
54 <setting id="streamport" type="integer" label="30002" help="30607">
55 <level>2</level>
56 <default>8001</default>
57 <constraints>
58 <minimum>1</minimum>
59 <step>1</step>
60 <maximum>65535</maximum>
61 </constraints>
62 <dependencies>
63 <dependency type="enable" setting="autoconfig">false</dependency>
64 </dependencies>
65 <control type="edit" format="integer" />
66 </setting>
67 <setting id="use_secure_stream" type="boolean" label="30066" help="30608">
68 <level>2</level>
69 <default>false</default>
70 <dependencies>
71 <dependency type="enable" setting="autoconfig">false</dependency>
72 </dependencies>
73 <control type="toggle" />
74 </setting>
75 <setting id="use_login_stream" type="boolean" label="30067" help="30609">
76 <level>2</level>
77 <default>false</default>
78 <dependencies>
79 <dependency type="enable" setting="autoconfig">false</dependency>
80 </dependencies>
81 <control type="toggle" />
82 </setting>
83 </group>
84 <group id="4" label="30020">
85 <setting id="connectionchecktimeout" type="integer" label="30121" help="30610">
86 <level>3</level>
87 <default>30</default>
88 <constraints>
89 <minimum>10</minimum>
90 <step>10</step>
91 <maximum>60</maximum>
92 </constraints>
93 <control type="slider" format="integer">
94 <popup>true</popup>
95 <formatlabel>14045</formatlabel>
96 </control>
97 </setting>
98 <setting id="connectioncheckinterval" type="integer" label="30122" help="30611">
99 <level>3</level>
100 <default>10</default>
101 <constraints>
102 <minimum>1</minimum>
103 <step>1</step>
104 <maximum>60</maximum>
105 </constraints>
106 <control type="slider" format="integer">
107 <popup>true</popup>
108 <formatlabel>14045</formatlabel>
109 </control>
110 </setting>
111 </group>
112 </category>
113
114 <!-- General -->
115 <category id="general" label="30018" help="30620">
116 <group id="1" label="30007">
117 <setting id="setprogramid" type="boolean" label="30014" help="30629">
118 <level>0</level>
119 <default>false</default>
120 <control type="toggle" />
121 </setting>
122 </group>
123
124 <group id="2" label="30006">
125 <setting id="onlinepicons" type="boolean" label="30027" help="30621">
126 <level>0</level>
127 <default>true</default>
128 <control type="toggle" />
129 </setting>
130 <setting id="useopenwebifpiconpath" type="boolean" parent="onlinepicons" label="30103" help="30622">
131 <level>1</level>
132 <default>false</default>
133 <dependencies>
134 <dependency type="enable" setting="onlinepicons">true</dependency>
135 </dependencies>
136 <control type="toggle" />
137 </setting>
138 <setting id="usepiconseuformat" type="boolean" label="30035" help="30623">
139 <level>0</level>
140 <default>false</default>
141 <control type="toggle" />
142 </setting>
143 <setting id="iconpath" type="path" label="30008" help="30624">
144 <level>1</level>
145 <default></default>
146 <constraints>
147 <allowempty>true</allowempty>
148 <writable>true</writable>
149 </constraints>
150 <dependencies>
151 <dependency type="enable" setting="onlinepicons">false</dependency>
152 </dependencies>
153 <control type="button" format="path">
154 <heading>657</heading>
155 </control>
156 </setting>
157 </group>
158
159 <group id="3" label="30009">
160 <setting id="updateint" type="integer" label="30015" help="30625">
161 <level>1</level>
162 <default>2</default>
163 <constraints>
164 <minimum>1</minimum>
165 <step>1</step>
166 <maximum>1440</maximum>
167 </constraints>
168 <control type="slider" format="integer">
169 <popup>true</popup>
170 <formatlabel>14044</formatlabel>
171 </control>
172 </setting>
173 <setting id="updatemode" type="integer" label="30100" help="30626">
174 <level>1</level>
175 <default>0</default>
176 <constraints>
177 <options>
178 <option label="30101">0</option> <!-- TIMERS_AND_RECORDINGS -->
179 <option label="30102">1</option> <!-- TIMERS_ONLY -->
180 </options>
181 </constraints>
182 <control type="list" format="integer" />
183 </setting>
184 <setting id="channelandgroupupdatemode" type="integer" label="30116" help="30627">
185 <level>2</level>
186 <default>2</default>
187 <constraints>
188 <options>
189 <option label="30117">0</option> <!-- DISABLED -->
190 <option label="30118">1</option> <!-- NOTIFY_AND_LOG -->
191 <option label="30119">2</option> <!-- RELOAD_CHANNELS_AND_GROUPS -->
192 </options>
193 </constraints>
194 <control type="list" format="integer" />
195 </setting>
196 <setting id="channelandgroupupdatehour" type="integer" label="30120" help="30628">
197 <level>2</level>
198 <default>4</default>
199 <constraints>
200 <minimum>0</minimum>
201 <step>1</step>
202 <maximum>23</maximum>
203 </constraints>
204 <dependencies>
205 <dependency type="visible">
206 <or>
207 <condition setting="channelandgroupupdatemode" operator="is">1</condition>
208 <condition setting="channelandgroupupdatemode" operator="is">2</condition>
209 </or>
210 </dependency>
211 </dependencies>
212 <control type="slider" format="integer">
213 <popup>true</popup>
214 <formatlabel>17998</formatlabel>
215 </control>
216 </setting>
217 </group>
218 </category>
219
220 <!-- Channels -->
221 <category id="channels" label="30019" help="30640">
222 <group id="1" label="30018">
223 <setting id="zap" type="boolean" label="30013" help="30642">
224 <level>0</level>
225 <default>false</default>
226 <control type="toggle" />
227 </setting>
228 <setting id="usestandardserviceref" type="boolean" label="30126" help="30641">
229 <level>3</level>
230 <default>true</default>
231 <control type="toggle" />
232 </setting>
233 </group>
234 <group id="2" label="30056">
235 <setting id="tvgroupmode" type="integer" label="30025" help="30643">
236 <level>0</level>
237 <default>0</default>
238 <constraints>
239 <options>
240 <option label="30074">0</option> <!-- ALL_GROUPS -->
241 <option label="30075">1</option> <!-- SOME_GROUPS -->
242 <option label="30078">2</option> <!-- FAVOURITES_GROUP -->
243 <option label="30131">3</option> <!-- CUSTOM_GROUPS -->
244 </options>
245 </constraints>
246 <control type="spinner" format="integer" />
247 </setting>
248
249 <setting id="numtvgroups" type="integer" parent="tvgroupmode" label="30134" help="30653">
250 <level>0</level>
251 <default>1</default>
252 <constraints>
253 <minimum>1</minimum>
254 <step>1</step>
255 <maximum>5</maximum>
256 </constraints>
257 <dependencies>
258 <dependency type="visible" setting="tvgroupmode" operator="is">1</dependency>
259 </dependencies>
260 <control type="spinner" format="integer" />
261 </setting>
262 <setting id="onetvgroup" type="string" parent="tvgroupmode" label="30026" help="30644">
263 <level>0</level>
264 <default></default>
265 <constraints>
266 <allowempty>true</allowempty>
267 </constraints>
268 <dependencies>
269 <dependency type="visible" setting="tvgroupmode" operator="is">1</dependency>
270 </dependencies>
271 <control type="edit" format="string" />
272 </setting>
273 <setting id="twotvgroup" type="string" parent="tvgroupmode" label="30135" help="30644">
274 <level>0</level>
275 <default></default>
276 <constraints>
277 <allowempty>true</allowempty>
278 </constraints>
279 <dependencies>
280 <dependency type="visible">
281 <and>
282 <condition setting="tvgroupmode" operator="is">1</condition>
283 <condition setting="numtvgroups" operator="gt">1</condition>
284 </and>
285 </dependency>
286 </dependencies>
287 <control type="edit" format="string" />
288 </setting>
289 <setting id="threetvgroup" type="string" parent="tvgroupmode" label="30136" help="30644">
290 <level>0</level>
291 <default></default>
292 <constraints>
293 <allowempty>true</allowempty>
294 </constraints>
295 <dependencies>
296 <dependency type="visible">
297 <and>
298 <condition setting="tvgroupmode" operator="is">1</condition>
299 <condition setting="numtvgroups" operator="gt">2</condition>
300 </and>
301 </dependency>
302 </dependencies>
303 <control type="edit" format="string" />
304 </setting>
305 <setting id="fourtvgroup" type="string" parent="tvgroupmode" label="30137" help="30644">
306 <level>0</level>
307 <default></default>
308 <constraints>
309 <allowempty>true</allowempty>
310 </constraints>
311 <dependencies>
312 <dependency type="visible">
313 <and>
314 <condition setting="tvgroupmode" operator="is">1</condition>
315 <condition setting="numtvgroups" operator="gt">3</condition>
316 </and>
317 </dependency>
318 </dependencies>
319 <control type="edit" format="string" />
320 </setting>
321 <setting id="fivetvgroup" type="string" parent="tvgroupmode" label="30138" help="30644">
322 <level>0</level>
323 <default></default>
324 <constraints>
325 <allowempty>true</allowempty>
326 </constraints>
327 <dependencies>
328 <dependency type="visible">
329 <and>
330 <condition setting="tvgroupmode" operator="is">1</condition>
331 <condition setting="numtvgroups" operator="gt">4</condition>
332 </and>
333 </dependency>
334 </dependencies>
335 <control type="edit" format="string" />
336 </setting>
337
338 <setting id="customtvgroupsfile" type="path" parent="tvgroupmode" label="30132" help="30651">
339 <level>0</level>
340 <default>special://userdata/addon_data/pvr.vuplus/channelGroups/customTVGroups-example.xml</default>
341 <constraints>
342 <allowempty>false</allowempty>
343 <writable>false</writable>
344 </constraints>
345 <dependencies>
346 <dependency type="visible" setting="tvgroupmode" operator="is">3</dependency>
347 </dependencies>
348 <control type="button" format="file">
349 <heading>1033</heading>
350 </control>
351 </setting>
352 <setting id="tvfavouritesmode" type="integer" label="30068" help="30645">
353 <level>2</level>
354 <default>0</default>
355 <constraints>
356 <options>
357 <option label="30430">0</option> <!-- DISABLED -->
358 <option label="30076">1</option> <!-- AS_FIRST_GROUP -->
359 <option label="30077">2</option> <!-- AS_LAST_GROUP -->
360 </options>
361 </constraints>
362 <dependencies>
363 <dependency type="visible">
364 <or>
365 <condition setting="tvgroupmode" operator="is">0</condition>
366 <condition setting="tvgroupmode" operator="is">1</condition>
367 </or>
368 </dependency>
369 </dependencies>
370 <control type="spinner" format="integer" />
371 </setting>
372 <setting id="excludelastscannedtv" type="boolean" label="30114" help="30646">
373 <level>3</level>
374 <default>true</default>
375 <dependencies>
376 <dependency type="visible" setting="tvgroupmode" operator="is">0</dependency>
377 </dependencies>
378 <control type="toggle" />
379 </setting>
380 </group>
381 <group id="3" label="30057">
382 <setting id="radiogroupmode" type="integer" label="30058" help="30647">
383 <level>0</level>
384 <default>0</default>
385 <constraints>
386 <options>
387 <option label="30074">0</option> <!-- ALL_GROUPS -->
388 <option label="30075">1</option> <!-- SOME_GROUPS -->
389 <option label="30078">2</option> <!-- FAVOURITES_GROUP -->
390 <option label="30131">3</option> <!-- CUSTOM_GROUPS -->
391 </options>
392 </constraints>
393 <control type="spinner" format="integer" />
394 </setting>
395
396 <setting id="numradiogroups" type="integer" parent="tvgroupmode" label="30139" help="30654">
397 <level>0</level>
398 <default>1</default>
399 <constraints>
400 <minimum>1</minimum>
401 <step>1</step>
402 <maximum>5</maximum>
403 </constraints>
404 <dependencies>
405 <dependency type="visible" setting="radiogroupmode" operator="is">1</dependency>
406 </dependencies>
407 <control type="spinner" format="integer" />
408 </setting>
409 <setting id="oneradiogroup" type="string" parent="radiogroupmode" label="30059" help="30648">
410 <level>0</level>
411 <default></default>
412 <constraints>
413 <allowempty>true</allowempty>
414 </constraints>
415 <dependencies>
416 <dependency type="visible" setting="radiogroupmode" operator="is">1</dependency>
417 </dependencies>
418 <control type="edit" format="string" />
419 </setting>
420 <setting id="tworadiogroup" type="string" parent="radiogroupmode" label="30140" help="30648">
421 <level>0</level>
422 <default></default>
423 <constraints>
424 <allowempty>true</allowempty>
425 </constraints>
426 <dependencies>
427 <dependency type="visible">
428 <and>
429 <condition setting="radiogroupmode" operator="is">1</condition>
430 <condition setting="numradiogroups" operator="gt">1</condition>
431 </and>
432 </dependency>
433 </dependencies>
434 <control type="edit" format="string" />
435 </setting>
436 <setting id="threeradiogroup" type="string" parent="radiogroupmode" label="30141" help="30648">
437 <level>0</level>
438 <default></default>
439 <constraints>
440 <allowempty>true</allowempty>
441 </constraints>
442 <dependencies>
443 <dependency type="visible">
444 <and>
445 <condition setting="radiogroupmode" operator="is">1</condition>
446 <condition setting="numradiogroups" operator="gt">2</condition>
447 </and>
448 </dependency>
449 </dependencies>
450 <control type="edit" format="string" />
451 </setting>
452 <setting id="fourradiogroup" type="string" parent="radiogroupmode" label="30142" help="30648">
453 <level>0</level>
454 <default></default>
455 <constraints>
456 <allowempty>true</allowempty>
457 </constraints>
458 <dependencies>
459 <dependency type="visible">
460 <and>
461 <condition setting="radiogroupmode" operator="is">1</condition>
462 <condition setting="numradiogroups" operator="gt">3</condition>
463 </and>
464 </dependency>
465 </dependencies>
466 <control type="edit" format="string" />
467 </setting>
468 <setting id="fiveradiogroup" type="string" parent="radiogroupmode" label="30143" help="30648">
469 <level>0</level>
470 <default></default>
471 <constraints>
472 <allowempty>true</allowempty>
473 </constraints>
474 <dependencies>
475 <dependency type="visible">
476 <and>
477 <condition setting="radiogroupmode" operator="is">1</condition>
478 <condition setting="numradiogroups" operator="gt">4</condition>
479 </and>
480 </dependency>
481 </dependencies>
482 <control type="edit" format="string" />
483 </setting>
484
485 <setting id="customradiogroupsfile" type="path" parent="radiogroupmode" label="30133" help="30652">
486 <level>0</level>
487 <default>special://userdata/addon_data/pvr.vuplus/channelGroups/customRadioGroups-example.xml</default>
488 <constraints>
489 <allowempty>false</allowempty>
490 <writable>false</writable>
491 </constraints>
492 <dependencies>
493 <dependency type="visible" setting="radiogroupmode" operator="is">3</dependency>
494 </dependencies>
495 <control type="button" format="file">
496 <heading>1033</heading>
497 </control>
498 </setting>
499 <setting id="radiofavouritesmode" type="integer" label="30069" help="30649">
500 <level>2</level>
501 <default>0</default>
502 <constraints>
503 <options>
504 <option label="30430">0</option> <!-- DISABLED -->
505 <option label="30076">1</option> <!-- AS_FIRST_GROUP -->
506 <option label="30077">2</option> <!-- AS_LAST_GROUP -->
507 </options>
508 </constraints>
509 <dependencies>
510 <dependency type="visible">
511 <or>
512 <condition setting="radiogroupmode" operator="is">0</condition>
513 <condition setting="radiogroupmode" operator="is">1</condition>
514 </or>
515 </dependency>
516 </dependencies>
517 <control type="spinner" format="integer" />
518 </setting>
519 <setting id="excludelastscannedradio" type="boolean" label="30114" help="30650">
520 <level>3</level>
521 <default>true</default>
522 <dependencies>
523 <dependency type="visible" setting="radiogroupmode" operator="is">0</dependency>
524 </dependencies>
525 <control type="toggle" />
526 </setting>
527 </group>
528 </category>
529
530 <!-- EPG -->
531 <category id="epg" label="30032" help="30660">
532 <group id="1" label="30031">
533 <setting id="extractshowinfoenabled" type="boolean" label="30033" help="30661">
534 <level>0</level>
535 <default>false</default>
536 <control type="toggle" />
537 </setting>
538 <setting id="extractshowinfofile" type="path" parent="extractshowinfoenabled" label="30046" help="30662">
539 <level>0</level>
540 <default>special://userdata/addon_data/pvr.vuplus/showInfo/English-ShowInfo.xml</default>
541 <constraints>
542 <allowempty>false</allowempty>
543 <writable>false</writable>
544 </constraints>
545 <dependencies>
546 <dependency type="visible" setting="extractshowinfoenabled" operator="is">true</dependency>
547 </dependencies>
548 <control type="button" format="file">
549 <heading>1033</heading>
550 </control>
551 </setting>
552 </group>
553 <group id="2" label="30053">
554 <setting id="genreidmapenabled" type="boolean" label="30054" help="30663">
555 <level>2</level>
556 <default>false</default>
557 <control type="toggle" />
558 </setting>
559 <setting id="genreidmapfile" type="path" parent="genreidmapenabled" label="30055" help="30664">
560 <level>2</level>
561 <default>special://userdata/addon_data/pvr.vuplus/genres/genreIdMappings/Sky-UK.xml</default>
562 <constraints>
563 <allowempty>false</allowempty>
564 <writable>false</writable>
565 </constraints>
566 <dependencies>
567 <dependency type="visible" setting="genreidmapenabled" operator="is">true</dependency>
568 </dependencies>
569 <control type="button" format="file">
570 <heading>1033</heading>
571 </control>
572 </setting>
573 </group>
574 <group id="3" label="30047">
575 <setting id="rytecgenretextmapenabled" type="boolean" label="30048" help="30665">
576 <level>2</level>
577 <default>false</default>
578 <control type="toggle" />
579 </setting>
580 <setting id="rytecgenretextmapfile" type="path" parent="rytecgenretextmapenabled" label="30049" help="30666">
581 <level>2</level>
582 <default>special://userdata/addon_data/pvr.vuplus/genres/genreRytecTextMappings/Rytec-UK-Ireland.xml</default>
583 <constraints>
584 <allowempty>false</allowempty>
585 <writable>false</writable>
586 </constraints>
587 <dependencies>
588 <dependency type="visible" setting="rytecgenretextmapenabled" operator="is">true</dependency>
589 </dependencies>
590 <control type="button" format="file">
591 <heading>1033</heading>
592 </control>
593 </setting>
594 <setting id="logmissinggenremapping" type="boolean" parent="rytecgenretextmapenabled" label="30037" help="30667">
595 <level>2</level>
596 <default>false</default>
597 <dependencies>
598 <dependency type="visible" setting="rytecgenretextmapenabled" operator="is">true</dependency>
599 </dependencies>
600 <control type="toggle" />
601 </setting>
602 </group>
603 <group id="4" label="30105">
604 <setting id="epgdelayperchannel" type="integer" label="30106" help="30668">
605 <level>2</level>
606 <default>0</default>
607 <constraints>
608 <minimum>0</minimum>
609 <step>250</step>
610 <maximum>5000</maximum>
611 </constraints>
612 <control type="slider" format="integer">
613 <popup>true</popup>
614 <formatlabel>14046</formatlabel>
615 </control>
616 </setting>
617 <setting id="skipinitialepg" type="boolean" label="30115" help="30669">
618 <level>2</level>
619 <default>true</default>
620 <control type="toggle" />
621 </setting>
622 </group>
623 </category>
624
625 <!-- Recordings -->
626 <category id="recordings" label="30070" help="30680">
627 <group id="1" label="30071">
628 <setting id="storeextrarecordinginfo" type="boolean" label="30127" help="30681">
629 <level>0</level>
630 <default>true</default>
631 <control type="toggle" />
632 </setting>
633 <setting id="sharerecordinglastplayed" type="integer" parent="storeextrarecordinginfo" label="30128" help="30682">
634 <level>0</level>
635 <default>0</default>
636 <dependencies>
637 <dependency type="enable" setting="storeextrarecordinginfo" operator="is">true</dependency>
638 </dependencies>
639 <constraints>
640 <options>
641 <option label="30129">0</option> <!-- ACROSS_KODI_INSTANCES -->
642 <option label="30130">1</option> <!-- ACROSS_KODI_AND_E2_INSTANCES -->
643 </options>
644 </constraints>
645 <control type="spinner" format="integer" />
646 </setting>
647 <setting id="recordingpath" type="string" label="30023" help="30683">
648 <level>2</level>
649 <default></default>
650 <constraints>
651 <allowempty>true</allowempty>
652 </constraints>
653 <control type="edit" format="string" />
654 </setting>
655 <setting id="onlycurrent" type="boolean" label="30017" help="30684">
656 <level>2</level>
657 <default>false</default>
658 <control type="toggle" />
659 </setting>
660 <setting id="keepfolders" type="boolean" label="30030" help="30685">
661 <level>2</level>
662 <default>false</default>
663 <control type="toggle" />
664 </setting>
665 </group>
666
667 <group id="2" label="30107">
668 <setting id="enablerecordingedls" type="boolean" label="30108" help="30686">
669 <level>0</level>
670 <default>false</default>
671 <control type="toggle" />
672 </setting>
673 <setting id="edlpaddingstart" type="integer" parent="enablerecordingedls" label="30109" help="30687">
674 <level>0</level>
675 <default>0</default>
676 <constraints>
677 <minimum>-10000</minimum>
678 <step>500</step>
679 <maximum>10000</maximum>
680 </constraints>
681 <dependencies>
682 <dependency type="visible" setting="enablerecordingedls">true</dependency>
683 </dependencies>
684 <control type="slider" format="integer">
685 <popup>true</popup>
686 <formatlabel>14046</formatlabel>
687 </control>
688 </setting>
689 <setting id="edlpaddingstop" type="integer" parent="enablerecordingedls" label="30110" help="30688">
690 <level>0</level>
691 <default>0</default>
692 <constraints>
693 <minimum>-10000</minimum>
694 <step>500</step>
695 <maximum>10000</maximum>
696 </constraints>
697 <dependencies>
698 <dependency type="visible" setting="enablerecordingedls">true</dependency>
699 </dependencies>
700 <control type="slider" format="integer">
701 <popup>true</popup>
702 <formatlabel>14046</formatlabel>
703 </control>
704 </setting>
705 </group>
706 </category>
707
708 <!-- Timers-->
709 <category id="timers" label="30072" help="30700">
710 <group id="1" label="30072">
711 <setting id="enablegenrepeattimers" type="boolean" label="30036" help="30701">
712 <level>1</level>
713 <default>true</default>
714 <control type="toggle" />
715 </setting>
716 <setting id="numgenrepeattimers" type="integer" parent="enablegenrepeattimers" label="30073" help="30702">
717 <level>1</level>
718 <default>1</default>
719 <constraints>
720 <minimum>1</minimum>
721 <step>1</step>
722 <maximum>10</maximum>
723 </constraints>
724 <dependencies>
725 <dependency type="enable" setting="enablegenrepeattimers">true</dependency>
726 </dependencies>
727 <control type="edit" format="integer" />
728 </setting>
729 <setting id="timerlistcleanup" type="boolean" label="30011" help="30703">
730 <level>0</level>
731 <default>false</default>
732 <control type="toggle" />
733 </setting>
734 </group>
735 <group id="2" label="30123">
736 <setting id="enableautotimers" type="boolean" label="30034" help="30704">
737 <level>0</level>
738 <default>true</default>
739 <control type="toggle" />
740 </setting>
741 <setting id="limitanychannelautotimers" type="boolean" label="30124" help="30705">
742 <level>2</level>
743 <default>true</default>
744 <dependencies>
745 <dependency type="visible" setting="enableautotimers" operator="is">true</dependency>
746 </dependencies>
747 <control type="toggle" />
748 </setting>
749 <setting id="limitanychannelautotimerstogroups" type="boolean" parent="limitanychannelautotimers" label="30125" help="30706">
750 <level>2</level>
751 <default>true</default>
752 <dependencies>
753 <dependency type="visible" setting="enableautotimers" operator="is">true</dependency>
754 <dependency type="enable" setting="limitanychannelautotimers">true</dependency>
755 </dependencies>
756 <control type="toggle" />
757 </setting>
758 </group>
759 </category>
760
761 <!-- Timeshift -->
762 <category id="timeshift" label="30060" help="30720">
763 <group id="1" label="30060">
764 <setting id="enabletimeshift" type="integer" label="30061" help="30721">
765 <level>0</level>
766 <default>0</default>
767 <constraints>
768 <options>
769 <option label="30063">0</option> <!-- OFF -->
770 <option label="30064">1</option> <!-- ON_PLAYBACK -->
771 <option label="30065">2</option> <!-- ON_PAUSE -->
772 </options>
773 </constraints>
774 <control type="spinner" format="integer" />
775 </setting>
776 <setting id="timeshiftbufferpath" type="path" parent="enabletimeshift" label="30062" help="30722">
777 <level>0</level>
778 <default>special://userdata/addon_data/pvr.vuplus</default>
779 <constraints>
780 <allowempty>true</allowempty>
781 <writable>true</writable>
782 </constraints>
783 <dependencies>
784 <dependency type="enable" setting="enabletimeshift" operator="gt">0</dependency>
785 </dependencies>
786 <control type="button" format="path">
787 <heading>657</heading>
788 </control>
789 </setting>
790 </group>
791 </category>
792
793 <!-- Advanced -->
794 <category id="advanced" label="30020" help="30740">
795 <group id="1" label="30052">
796 <setting id="prependoutline" type="integer" label="30040" help="30741">
797 <level>1</level>
798 <default>0</default>
799 <constraints>
800 <options>
801 <option label="30042">0</option> <!-- NEVER -->
802 <option label="30043">1</option> <!-- IN_EPG -->
803 <option label="30044">2</option> <!-- IN_RECORDINGS -->
804 <option label="30045">3</option> <!-- ALWAYS -->
805 </options>
806 </constraints>
807 <control type="list" format="integer" />
808 </setting>
809 <setting id="powerstatemode" type="integer" label="30024" help="30742">
810 <level>1</level>
811 <default>0</default>
812 <constraints>
813 <options>
814 <option label="30430">0</option> <!-- DISABLED -->
815 <option label="30097">1</option> <!-- STANDBY -->
816 <option label="30098">2</option> <!-- DEEP_STANDBY -->
817 <option label="30099">3</option> <!-- WAKEUP_THEN_STANDBY -->
818 </options>
819 </constraints>
820 <control type="list" format="integer" />
821 </setting>
822 <setting id="readtimeout" type="integer" label="30050" help="30743">
823 <level>3</level>
824 <default>0</default>
825 <constraints>
826 <minimum>0</minimum>
827 <step>1</step>
828 <maximum>60</maximum>
829 </constraints>
830 <control type="slider" format="integer">
831 <popup>true</popup>
832 <formatlabel>14045</formatlabel>
833 </control>
834 </setting>
835 <setting id="streamreadchunksize" type="integer" label="30041" help="30744">
836 <level>3</level>
837 <default>0</default>
838 <constraints>
839 <minimum>0</minimum>
840 <step>4</step>
841 <maximum>128</maximum>
842 </constraints>
843 <control type="slider" format="integer">
844 <popup>true</popup>
845 <formatlabel>14049</formatlabel>
846 </control>
847 </setting>
848 <setting id="nodebug" type="boolean" label="30144" help="30747">
849 <level>1</level>
850 <default>false</default>
851 <control type="toggle" />
852 </setting>
853 <setting id="debugnormal" type="boolean" parent="nodebug" label="30111" help="30745">
854 <level>1</level>
855 <default>false</default>
856 <dependencies>
857 <dependency type="enable" setting="nodebug">false</dependency>
858 </dependencies>
859 <control type="toggle" />
860 </setting>
861 <setting id="tracedebug" type="boolean" parent="nodebug" label="30104" help="30746">
862 <level>1</level>
863 <default>false</default>
864 <dependencies>
865 <dependency type="enable" setting="nodebug">false</dependency>
866 </dependencies>
867 <control type="toggle" />
868 </setting>
869 </group>
870 </category>
871
872 <!-- Backend -->
873 <!-- Add again one new addon API is supported -->
874 <!--
875 <category id="backend" label="30086" help="30760">
876 <group id="1" label="30090">
877 <setting id="webifversion" type="string" label="30091" help="30761">
878 <level>0</level>
879 <default>N/A</default>
880 <dependencies>
881 <dependency type="enable" setting="timeshiftbufferpath" operator="is">AnyTextThatDoesNotMatch</dependency>
882 </dependencies>
883 <control type="edit" format="string" />
884 </setting>
885 <setting id="autotimertagintags" type="string" label="30092" help="30762">
886 <level>0</level>
887 <default>N/A</default>
888 <dependencies>
889 <dependency type="enable" setting="timeshiftbufferpath" operator="is">AnyTextThatDoesNotMatch</dependency>
890 </dependencies>
891 <control type="edit" format="string" />
892 </setting>
893 <setting id="autotimernameintags" type="string" label="30093" help="30763">
894 <level>0</level>
895 <default>N/A</default>
896 <dependencies>
897 <dependency type="enable" setting="timeshiftbufferpath" operator="is">AnyTextThatDoesNotMatch</dependency>
898 </dependencies>
899 <control type="edit" format="string" />
900 </setting>
901 </group>
902
903 <group id="2" label="30087">
904 <setting id="globalstartpaddingstb" type="integer" label="30088" help="30764">
905 <level>0</level>
906 <default>0</default>
907 <constraints>
908 <minimum>0</minimum>
909 <step>1</step>
910 <maximum>120</maximum>
911 </constraints>
912 <control type="slider" format="integer">
913 <popup>true</popup>
914 <formatlabel>14044</formatlabel>
915 </control>
916 </setting>
917 <setting id="globalendpaddingstb" type="integer" label="30089" help="30765">
918 <level>0</level>
919 <default>0</default>
920 <constraints>
921 <minimum>0</minimum>
922 <step>1</step>
923 <maximum>120</maximum>
924 </constraints>
925 <control type="slider" format="integer">
926 <popup>true</popup>
927 <formatlabel>14044</formatlabel>
928 </control>
929 </setting>
930 </group>
931 </category>
932 -->
933
934 </section>
29935 </settings>
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Enigma2.h"
23
24 #include "client.h"
25 #include "enigma2/utilities/CurlFile.h"
26 #include "enigma2/utilities/LocalizedString.h"
27 #include "enigma2/utilities/Logger.h"
28 #include "enigma2/utilities/WebUtils.h"
29 #include "util/XMLUtils.h"
30
31 #include <algorithm>
32 #include <fstream>
33 #include <iostream>
34 #include <regex>
35 #include <stdlib.h>
36 #include <string>
37
38 #include <p8-platform/util/StringUtils.h>
39
40 using namespace ADDON;
41 using namespace P8PLATFORM;
42 using namespace enigma2;
43 using namespace enigma2::data;
44 using namespace enigma2::extract;
45 using namespace enigma2::utilities;
46
47 Enigma2::Enigma2(PVR_PROPERTIES* pvrProps) : m_epgMaxDays(pvrProps->iEpgMaxDays)
48 {
49 m_timers.AddTimerChangeWatcher(&m_dueRecordingUpdate);
50
51 connectionManager = new ConnectionManager(*this);
52 }
53
54 Enigma2::~Enigma2()
55 {
56 if (connectionManager)
57 connectionManager->Stop();
58 delete connectionManager;
59 }
60
61 /* **************************************************************************
62 * Connection
63 * *************************************************************************/
64
65 void Enigma2::ConnectionLost()
66 {
67 CLockObject lock(m_mutex);
68
69 Logger::Log(LEVEL_NOTICE, "%s Lost connection with Enigma2 device...", __FUNCTION__);
70
71 Logger::Log(LEVEL_DEBUG, "%s Stopping update thread...", __FUNCTION__);
72 StopThread();
73
74 m_currentChannel = -1;
75 m_isConnected = false;
76 }
77
78
79 void Enigma2::ConnectionEstablished()
80 {
81 CLockObject lock(m_mutex);
82
83 Logger::Log(LEVEL_DEBUG, "%s Removing internal channels and groups lists...", __FUNCTION__);
84 m_channels.ClearChannels();
85 m_channelGroups.ClearChannelGroups();
86
87 Logger::Log(LEVEL_NOTICE, "%s Connection Established with Enigma2 device...", __FUNCTION__);
88
89 Logger::Log(LEVEL_NOTICE, "%s - VU+ Addon Configuration options", __FUNCTION__);
90 Logger::Log(LEVEL_NOTICE, "%s - Hostname: '%s'", __FUNCTION__, m_settings.GetHostname().c_str());
91 Logger::Log(LEVEL_NOTICE, "%s - WebPort: '%d'", __FUNCTION__, m_settings.GetWebPortNum());
92 Logger::Log(LEVEL_NOTICE, "%s - StreamPort: '%d'", __FUNCTION__, m_settings.GetStreamPortNum());
93 if (!m_settings.GetUseSecureConnection())
94 Logger::Log(LEVEL_NOTICE, "%s Use HTTPS: 'false'", __FUNCTION__);
95 else
96 Logger::Log(LEVEL_NOTICE, "%s Use HTTPS: 'true'", __FUNCTION__);
97
98 if ((m_settings.GetUsername().length() > 0) && (m_settings.GetPassword().length() > 0))
99 {
100 if ((m_settings.GetUsername().find("@") != std::string::npos) || (m_settings.GetPassword().find("@") != std::string::npos))
101 {
102 Logger::Log(LEVEL_ERROR, "%s - You cannot use the '@' character in either the username or the password with this addon. Please change your configuraton!", __FUNCTION__);
103 return;
104 }
105 }
106 m_isConnected = m_admin.Initialise();
107
108 if (!m_isConnected)
109 {
110 Logger::Log(LEVEL_ERROR, "%s It seem's that the webinterface cannot be reached. Make sure that you set the correct configuration options in the addon settings!", __FUNCTION__);
111 XBMC->QueueNotification(QUEUE_ERROR, LocalizedString(30515).c_str());
112 return;
113 }
114
115 m_settings.ReadFromAddon();
116
117 m_recordings.ClearLocations();
118 m_recordings.LoadLocations();
119
120 if (m_channels.GetNumChannels() == 0)
121 {
122 // Load the TV channels - close connection if no channels are found
123 if (!m_channelGroups.LoadChannelGroups())
124 {
125 Logger::Log(LEVEL_ERROR, "%s No channel groups (bouquets) found, please check the addon channel settings, exiting", __FUNCTION__);
126 XBMC->QueueNotification(QUEUE_ERROR, LocalizedString(30516).c_str());
127
128 return;
129 }
130
131 if (!m_channels.LoadChannels(m_channelGroups))
132 {
133 Logger::Log(LEVEL_ERROR, "%s No channels found, please check the addon channel settings, exiting", __FUNCTION__);
134 XBMC->QueueNotification(QUEUE_ERROR, LocalizedString(30517).c_str());
135
136 return;
137 }
138 }
139
140 m_skipInitialEpgLoad = m_settings.SkipInitialEpgLoad();
141
142 m_epg.Initialise(m_channels, m_channelGroups);
143
144 m_timers.TimerUpdates();
145
146 Logger::Log(LEVEL_INFO, "%s Starting separate client update thread...", __FUNCTION__);
147 CreateThread();
148 }
149
150 /* **************************************************************************
151 * Connection
152 * *************************************************************************/
153
154 void Enigma2::OnSleep()
155 {
156 connectionManager->OnSleep();
157 }
158
159 void Enigma2::OnWake()
160 {
161 connectionManager->OnWake();
162 }
163
164 /***************************************************************************
165 * Device and helpers
166 **************************************************************************/
167
168 bool Enigma2::Start()
169 {
170 CLockObject lock(m_mutex);
171
172 connectionManager->Start();
173
174 return true;
175 }
176
177 void* Enigma2::Process()
178 {
179 Logger::Log(LEVEL_DEBUG, "%s - starting", __FUNCTION__);
180
181 // Wait for the initial EPG update to complete
182 int totalWaitSecs = 0;
183 while (totalWaitSecs < INITIAL_EPG_WAIT_SECS)
184 {
185 totalWaitSecs += INITIAL_EPG_STEP_SECS;
186
187 if (!m_epg.IsInitialEpgCompleted())
188 Sleep(INITIAL_EPG_STEP_SECS * 1000);
189 }
190
191 m_skipInitialEpgLoad = false;
192
193 // Whether or not initial EPG updates occurred now Trigger "Real" EPG updates
194 // This will regard Initial EPG as completed anyway.
195 m_epg.TriggerEpgUpdatesForChannels();
196
197 unsigned int updateTimer = 0;
198 time_t lastUpdateTimeSeconds = time(nullptr);
199 int lastUpdateHour = m_settings.GetChannelAndGroupUpdateHour(); //ignore if we start during same hour
200
201 while (!IsStopped() && m_isConnected)
202 {
203 Sleep(PROCESS_LOOP_WAIT_SECS * 1000);
204
205 time_t currentUpdateTimeSeconds = time(nullptr);
206 std::tm timeInfo = *std::localtime(&currentUpdateTimeSeconds);
207 updateTimer += static_cast<unsigned int>(currentUpdateTimeSeconds - lastUpdateTimeSeconds);
208 lastUpdateTimeSeconds = currentUpdateTimeSeconds;
209
210 if (m_dueRecordingUpdate || updateTimer >= (m_settings.GetUpdateIntervalMins() * 60))
211 {
212 updateTimer = 0;
213
214 // Trigger Timer and Recording updates according to the addon settings
215 CLockObject lock(m_mutex);
216 // We need to check this again in case StopThread is called (in destroying Enigma2) during the sleep, otherwise TimerUpdates could be called after the object is released
217 if (!IsStopped() && m_isConnected)
218 {
219 Logger::Log(LEVEL_INFO, "%s Perform Updates!", __FUNCTION__);
220
221 if (m_settings.GetAutoTimerListCleanupEnabled())
222 {
223 m_timers.RunAutoTimerListCleanup();
224 }
225 m_timers.TimerUpdates();
226
227 if (m_dueRecordingUpdate || m_settings.GetUpdateMode() == UpdateMode::TIMERS_AND_RECORDINGS)
228 {
229 m_dueRecordingUpdate = false;
230 PVR->TriggerRecordingUpdate();
231 }
232 }
233 }
234
235 if (lastUpdateHour != timeInfo.tm_hour && timeInfo.tm_hour == m_settings.GetChannelAndGroupUpdateHour())
236 {
237 // Trigger Channel and Group updates according to the addon settings
238 CLockObject lock(m_mutex);
239 // We need to check this again in case StopThread is called (in destroying Enigma2) during the sleep, otherwise TimerUpdates could be called after the object is released
240 if (!IsStopped() && m_isConnected)
241 {
242 if (CheckForChannelAndGroupChanges() != ChannelsChangeState::NO_CHANGE &&
243 m_settings.GetChannelAndGroupUpdateMode() == ChannelAndGroupUpdateMode::RELOAD_CHANNELS_AND_GROUPS)
244 {
245 ReloadChannelsGroupsAndEPG();
246 }
247 }
248 }
249 lastUpdateHour = timeInfo.tm_hour;
250 }
251
252 //CLockObject lock(m_mutex);
253 m_started.Broadcast();
254
255 return nullptr;
256 }
257
258 ChannelsChangeState Enigma2::CheckForChannelAndGroupChanges()
259 {
260 ChannelsChangeState changeType = ChannelsChangeState::NO_CHANGE;
261
262 if (m_settings.GetChannelAndGroupUpdateMode() != ChannelAndGroupUpdateMode::DISABLED)
263 {
264 Logger::Log(LEVEL_INFO, "%s Checking for Channel and Group Changes!", __FUNCTION__);
265
266 //Now check for any channel or group changes
267 ChannelGroups latestChannelGroups;
268 Channels latestChannels;
269
270 // Load the TV channels - close connection if no channels are found
271 if (latestChannelGroups.LoadChannelGroups())
272 {
273 if (latestChannels.LoadChannels(latestChannelGroups))
274 {
275 changeType = m_channels.CheckForChannelAndGroupChanges(latestChannelGroups, latestChannels);
276
277 if (m_settings.GetChannelAndGroupUpdateMode() == ChannelAndGroupUpdateMode::NOTIFY_AND_LOG)
278 {
279 if (changeType == ChannelsChangeState::CHANNEL_GROUPS_CHANGED)
280 {
281 Logger::Log(LEVEL_NOTICE, "%s Channel group (bouquet) changes detected, please restart to load changes", __FUNCTION__);
282 XBMC->QueueNotification(QUEUE_INFO, LocalizedString(30518).c_str());
283 }
284 else if (changeType == ChannelsChangeState::CHANNELS_CHANGED)
285 {
286 Logger::Log(LEVEL_NOTICE, "%s Channel changes detected, please restart to load changes", __FUNCTION__);
287 XBMC->QueueNotification(QUEUE_INFO, LocalizedString(30519).c_str());
288 }
289 }
290 else // RELOAD_CHANNELS_AND_GROUPS
291 {
292 if (changeType == ChannelsChangeState::CHANNEL_GROUPS_CHANGED)
293 {
294 Logger::Log(LEVEL_NOTICE, "%s Channel group (bouquet) changes detected, reloading channels, groups and EPG now", __FUNCTION__);
295 XBMC->QueueNotification(QUEUE_INFO, LocalizedString(30521).c_str());
296 }
297 else if (changeType == ChannelsChangeState::CHANNELS_CHANGED)
298 {
299 Logger::Log(LEVEL_NOTICE, "%s Channel changes detected, reloading channels, groups and EPG now", __FUNCTION__);
300 XBMC->QueueNotification(QUEUE_INFO, LocalizedString(30522).c_str());
301 }
302 }
303 }
304 }
305 }
306
307 return changeType;
308 }
309
310 void Enigma2::ReloadChannelsGroupsAndEPG()
311 {
312 Logger::Log(LEVEL_DEBUG, "%s Removing internal channels list...", __FUNCTION__);
313 m_channels.ClearChannels();
314 m_channelGroups.ClearChannelGroups();
315
316 m_recordings.ClearLocations();
317 m_recordings.LoadLocations();
318
319 m_channelGroups.LoadChannelGroups();
320 m_channels.LoadChannels(m_channelGroups);
321
322 PVR->TriggerChannelGroupsUpdate();
323 PVR->TriggerChannelUpdate();
324
325 m_skipInitialEpgLoad = true;
326
327 m_epg.Initialise(m_channels, m_channelGroups);
328
329 m_timers.TimerUpdates();
330
331 for (const auto& myChannel : m_channels.GetChannelsList())
332 PVR->TriggerEpgUpdate(myChannel->GetUniqueId());
333
334 PVR->TriggerRecordingUpdate();
335 }
336
337 void Enigma2::SendPowerstate()
338 {
339 CLockObject lock(m_mutex);
340
341 m_admin.SendPowerstate();
342 }
343
344 const char* Enigma2::GetServerName() const
345 {
346 return m_admin.GetServerName();
347 }
348
349 const char* Enigma2::GetServerVersion() const
350 {
351 return m_admin.GetServerVersion();
352 }
353
354 bool Enigma2::IsConnected() const
355 {
356 return m_isConnected;
357 }
358
359 /***************************************************************************
360 * Channel Groups
361 **************************************************************************/
362
363 unsigned int Enigma2::GetNumChannelGroups() const
364 {
365 return m_channelGroups.GetNumChannelGroups();
366 }
367
368 PVR_ERROR Enigma2::GetChannelGroups(ADDON_HANDLE handle, bool radio)
369 {
370 std::vector<PVR_CHANNEL_GROUP> channelGroups;
371 {
372 CLockObject lock(m_mutex);
373 m_channelGroups.GetChannelGroups(channelGroups, radio);
374 }
375
376 Logger::Log(LEVEL_DEBUG, "%s - channel groups available '%d'", __FUNCTION__, channelGroups.size());
377
378 for (const auto& channelGroup : channelGroups)
379 PVR->TransferChannelGroup(handle, &channelGroup);
380
381 return PVR_ERROR_NO_ERROR;
382 }
383
384 PVR_ERROR Enigma2::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group)
385 {
386 std::vector<PVR_CHANNEL_GROUP_MEMBER> channelGroupMembers;
387 {
388 CLockObject lock(m_mutex);
389 m_channelGroups.GetChannelGroupMembers(channelGroupMembers, group.strGroupName);
390 }
391
392 Logger::Log(LEVEL_DEBUG, "%s - group '%s' members available '%d'", __FUNCTION__, group.strGroupName, channelGroupMembers.size());
393
394 for (const auto& channelGroupMember : channelGroupMembers)
395 PVR->TransferChannelGroupMember(handle, &channelGroupMember);
396
397 return PVR_ERROR_NO_ERROR;
398 }
399
400 /***************************************************************************
401 * Channels
402 **************************************************************************/
403
404 int Enigma2::GetChannelsAmount() const
405 {
406 return m_channels.GetNumChannels();
407 }
408
409 PVR_ERROR Enigma2::GetChannels(ADDON_HANDLE handle, bool bRadio)
410 {
411 std::vector<PVR_CHANNEL> channels;
412 {
413 CLockObject lock(m_mutex);
414 m_channels.GetChannels(channels, bRadio);
415 }
416
417 Logger::Log(LEVEL_DEBUG, "%s - channels available '%d', radio = %d", __FUNCTION__, channels.size(), bRadio);
418
419 for (auto& channel : channels)
420 PVR->TransferChannelEntry(handle, &channel);
421
422 return PVR_ERROR_NO_ERROR;
423 }
424
425 /***************************************************************************
426 * EPG
427 **************************************************************************/
428
429 PVR_ERROR Enigma2::GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL& channel, time_t iStart, time_t iEnd)
430 {
431 if (m_epg.IsInitialEpgCompleted() && m_settings.GetEPGDelayPerChannelDelay() != 0)
432 Sleep(m_settings.GetEPGDelayPerChannelDelay());
433
434 //Have a lock while getting the channel. Then we don't have to worry about a disconnection while retrieving the EPG data.
435 std::shared_ptr<Channel> myChannel;
436 {
437 CLockObject lock(m_mutex);
438
439 if (!m_channels.IsValid(channel.iUniqueId))
440 {
441 Logger::Log(LEVEL_ERROR, "%s Could not fetch channel object - not fetching EPG for channel with UniqueID '%d'", __FUNCTION__, channel.iUniqueId);
442 return PVR_ERROR_SERVER_ERROR;
443 }
444
445 myChannel = m_channels.GetChannel(channel.iUniqueId);
446 }
447
448 if (m_skipInitialEpgLoad)
449 {
450 Logger::Log(LEVEL_DEBUG, "%s Skipping Initial EPG for channel: %s", __FUNCTION__, myChannel->GetChannelName().c_str());
451 m_epg.MarkChannelAsInitialEpgRead(myChannel->GetServiceReference());
452 return PVR_ERROR_NO_ERROR;
453 }
454
455 return m_epg.GetEPGForChannel(handle, myChannel->GetServiceReference(), iStart, iEnd);
456 }
457
458 void Enigma2::SetEPGTimeFrame(int epgMaxDays)
459 {
460 m_epg.SetEPGTimeFrame(epgMaxDays);
461 }
462
463 /***************************************************************************
464 * Livestream
465 **************************************************************************/
466 bool Enigma2::OpenLiveStream(const PVR_CHANNEL& channelinfo)
467 {
468 Logger::Log(LEVEL_DEBUG, "%s: channel=%u", __FUNCTION__, channelinfo.iUniqueId);
469 CLockObject lock(m_mutex);
470
471 if (channelinfo.iUniqueId != m_currentChannel)
472 {
473 m_currentChannel = channelinfo.iUniqueId;
474 m_lastSignalStatusUpdateSeconds = 0;
475
476 if (m_settings.GetZapBeforeChannelSwitch())
477 {
478 // Zapping is set to true, so send the zapping command to the PVR box
479 const std::string strServiceReference = m_channels.GetChannel(channelinfo.iUniqueId)->GetServiceReference().c_str();
480
481 const std::string strCmd = StringUtils::Format("web/zap?sRef=%s", WebUtils::URLEncodeInline(strServiceReference).c_str());
482
483 std::string strResult;
484 if (!WebUtils::SendSimpleCommand(strCmd, strResult, true))
485 return false;
486 }
487 }
488 return true;
489 }
490
491 void Enigma2::CloseLiveStream(void)
492 {
493 CLockObject lock(m_mutex);
494 m_currentChannel = -1;
495 }
496
497 const std::string Enigma2::GetLiveStreamURL(const PVR_CHANNEL& channelinfo)
498 {
499 if (m_settings.GetAutoConfigLiveStreamsEnabled())
500 {
501 // we need to download the M3U file that contains the URL for the stream...
502 // we do it here for 2 reasons:
503 // 1. This is faster than doing it during initialization
504 // 2. The URL can change, so this is more up-to-date.
505 return GetStreamURL(m_channels.GetChannel(channelinfo.iUniqueId)->GetM3uURL());
506 }
507
508 return m_channels.GetChannel(channelinfo.iUniqueId)->GetStreamURL();
509 }
510
511 bool Enigma2::IsIptvStream(const PVR_CHANNEL& channelinfo) const
512 {
513 return m_channels.GetChannel(channelinfo.iUniqueId)->IsIptvStream();
514 }
515
516 int Enigma2::GetChannelStreamProgramNumber(const PVR_CHANNEL& channelinfo)
517 {
518 return m_channels.GetChannel(channelinfo.iUniqueId)->GetStreamProgramNumber();
519 }
520
521 /**
522 * GetStreamURL() reads out a stream-URL from a M3U-file.
523 *
524 * This method downloads a M3U-file from the address that is given by strM3uURL.
525 * It returns the first line that starts with "http".
526 * If no line starts with "http" the last line is returned.
527 */
528 std::string Enigma2::GetStreamURL(const std::string& strM3uURL)
529 {
530 const std::string strM3U = WebUtils::GetHttpXML(strM3uURL);
531 std::istringstream streamM3U(strM3U);
532 std::string strURL = "";
533 while (std::getline(streamM3U, strURL))
534 {
535 if (strURL.compare(0, 4, "http", 4) == 0)
536 break;
537 };
538 return strURL;
539 }
540
541 /***************************************************************************
542 * Recordings
543 **************************************************************************/
544
545 unsigned int Enigma2::GetRecordingsAmount(bool deleted)
546 {
547 return m_recordings.GetNumRecordings(deleted);
548 }
549
550 PVR_ERROR Enigma2::GetRecordings(ADDON_HANDLE handle, bool deleted)
551 {
552 m_recordings.LoadRecordings(deleted);
553
554 std::vector<PVR_RECORDING> recordings;
555 {
556 CLockObject lock(m_mutex);
557 m_recordings.GetRecordings(recordings, deleted);
558 }
559
560 Logger::Log(LEVEL_DEBUG, "%s - recordings available '%d'", __FUNCTION__, recordings.size());
561
562 for (const auto& recording : recordings)
563 PVR->TransferRecordingEntry(handle, &recording);
564
565 return PVR_ERROR_NO_ERROR;
566 }
567
568 PVR_ERROR Enigma2::DeleteRecording(const PVR_RECORDING& recinfo)
569 {
570 return m_recordings.DeleteRecording(recinfo);
571 }
572
573 PVR_ERROR Enigma2::UndeleteRecording(const PVR_RECORDING& recording)
574 {
575 return m_recordings.UndeleteRecording(recording);
576 }
577
578 PVR_ERROR Enigma2::DeleteAllRecordingsFromTrash()
579 {
580 return m_recordings.DeleteAllRecordingsFromTrash();
581 }
582
583 PVR_ERROR Enigma2::GetRecordingEdl(const PVR_RECORDING& recinfo, PVR_EDL_ENTRY edl[], int* size)
584 {
585 std::vector<PVR_EDL_ENTRY> edlEntries;
586 {
587 CLockObject lock(m_mutex);
588 m_recordings.GetRecordingEdl(recinfo.strRecordingId, edlEntries);
589 }
590
591 Logger::Log(LEVEL_DEBUG, "%s - recording '%s' has '%d' EDL entries available", __FUNCTION__, recinfo.strTitle, edlEntries.size());
592
593 int index = 0;
594 int maxSize = *size;
595 for (auto& edlEntry : edlEntries)
596 {
597 if (index >= maxSize)
598 break;
599
600 edl[index].start = edlEntry.start;
601 edl[index].end = edlEntry.end;
602 edl[index].type = edlEntry.type;
603
604 index++;
605 }
606 *size = edlEntries.size();
607
608 return PVR_ERROR_NO_ERROR;
609 }
610
611 RecordingReader* Enigma2::OpenRecordedStream(const PVR_RECORDING& recinfo)
612 {
613 CLockObject lock(m_mutex);
614 std::time_t now = std::time(nullptr), start = 0, end = 0;
615 std::string channelName = recinfo.strChannelName;
616 auto timer = m_timers.GetTimer([&](const Timer &timer)
617 {
618 return timer.IsRunning(&now, &channelName, recinfo.recordingTime);
619 });
620 if (timer)
621 {
622 start = timer->GetRealStartTime();
623 end = timer->GetRealEndTime();
624 }
625
626 return new RecordingReader(m_recordings.GetRecordingURL(recinfo).c_str(), start, end, recinfo.iDuration);
627 }
628
629 bool Enigma2::HasRecordingStreamProgramNumber(const PVR_RECORDING& recording)
630 {
631 return m_recordings.HasRecordingStreamProgramNumber(recording);
632 }
633
634 int Enigma2::GetRecordingStreamProgramNumber(const PVR_RECORDING& recording)
635 {
636 return m_recordings.GetRecordingStreamProgramNumber(recording);
637 }
638
639 PVR_ERROR Enigma2::RenameRecording(const PVR_RECORDING& recording)
640 {
641 CLockObject lock(m_mutex);
642 return m_recordings.RenameRecording(recording);
643 }
644
645 PVR_ERROR Enigma2::SetRecordingPlayCount(const PVR_RECORDING& recording, int count)
646 {
647 CLockObject lock(m_mutex);
648 return m_recordings.SetRecordingPlayCount(recording, count);
649 }
650
651 PVR_ERROR Enigma2::SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastPlayedPosition)
652 {
653 CLockObject lock(m_mutex);
654 return m_recordings.SetRecordingLastPlayedPosition(recording, lastPlayedPosition);
655 }
656
657 int Enigma2::GetRecordingLastPlayedPosition(const PVR_RECORDING& recording)
658 {
659 CLockObject lock(m_mutex);
660 return m_recordings.GetRecordingLastPlayedPosition(recording);
661 }
662
663 /***************************************************************************
664 * Timers
665 **************************************************************************/
666
667 void Enigma2::GetTimerTypes(PVR_TIMER_TYPE types[], int* size)
668 {
669 std::vector<PVR_TIMER_TYPE> timerTypes;
670 {
671 CLockObject lock(m_mutex);
672 m_timers.GetTimerTypes(timerTypes);
673 }
674
675 int i = 0;
676 for (auto& timerType : timerTypes)
677 types[i++] = timerType;
678 *size = timerTypes.size();
679 Logger::Log(LEVEL_NOTICE, "%s Transfered %u timer types", __FUNCTION__, *size);
680 }
681
682 int Enigma2::GetTimersAmount()
683 {
684 CLockObject lock(m_mutex);
685 return m_timers.GetTimerCount();
686 }
687
688 PVR_ERROR Enigma2::GetTimers(ADDON_HANDLE handle)
689 {
690 std::vector<PVR_TIMER> timers;
691 {
692 CLockObject lock(m_mutex);
693 m_timers.GetTimers(timers);
694 m_timers.GetAutoTimers(timers);
695 }
696
697 Logger::Log(LEVEL_DEBUG, "%s - timers available '%d'", __FUNCTION__, timers.size());
698
699 for (auto& timer : timers)
700 PVR->TransferTimerEntry(handle, &timer);
701
702 return PVR_ERROR_NO_ERROR;
703 }
704
705 PVR_ERROR Enigma2::AddTimer(const PVR_TIMER& timer)
706 {
707 return m_timers.AddTimer(timer);
708 }
709
710 PVR_ERROR Enigma2::UpdateTimer(const PVR_TIMER& timer)
711 {
712 return m_timers.UpdateTimer(timer);
713 }
714
715 PVR_ERROR Enigma2::DeleteTimer(const PVR_TIMER& timer)
716 {
717 return m_timers.DeleteTimer(timer);
718 }
719
720 /***************************************************************************
721 * Misc
722 **************************************************************************/
723
724 PVR_ERROR Enigma2::GetDriveSpace(long long* iTotal, long long* iUsed)
725 {
726 if (m_admin.GetDeviceHasHDD())
727 return m_admin.GetDriveSpace(iTotal, iUsed, m_locations);
728
729 return PVR_ERROR_NOT_IMPLEMENTED;
730 }
731
732 PVR_ERROR Enigma2::GetTunerSignal(PVR_SIGNAL_STATUS& signalStatus)
733 {
734 if (m_currentChannel >= 0)
735 {
736 const std::shared_ptr<Channel> channel = m_channels.GetChannel(m_currentChannel);
737
738 strncpy(signalStatus.strServiceName, channel->GetChannelName().c_str(), sizeof(signalStatus.strServiceName) - 1);
739 strncpy(signalStatus.strProviderName, channel->GetProviderName().c_str(), sizeof(signalStatus.strProviderName) - 1);
740
741 time_t now = time(nullptr);
742 if ((now - m_lastSignalStatusUpdateSeconds) >= POLL_INTERVAL_SECONDS)
743 {
744 Logger::Log(LEVEL_DEBUG, "%s - Calling backend for Signal Status after interval of %d seconds", __FUNCTION__, POLL_INTERVAL_SECONDS);
745
746 if (!m_admin.GetTunerSignal(m_signalStatus, channel))
747 {
748 return PVR_ERROR_SERVER_ERROR;
749 }
750 m_lastSignalStatusUpdateSeconds = now;
751 }
752 }
753
754 signalStatus.iSNR = m_signalStatus.m_snrPercentage;
755 signalStatus.iBER = m_signalStatus.m_ber;
756 signalStatus.iSignal = m_signalStatus.m_signalStrength;
757 strncpy(signalStatus.strAdapterName, m_signalStatus.m_adapterName.c_str(), sizeof(signalStatus.strAdapterName) - 1);
758 strncpy(signalStatus.strAdapterStatus, m_signalStatus.m_adapterStatus.c_str(), sizeof(signalStatus.strAdapterStatus) - 1);
759
760 return PVR_ERROR_NO_ERROR;
761 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "client.h"
24 #include "enigma2/Admin.h"
25 #include "enigma2/ChannelGroups.h"
26 #include "enigma2/Channels.h"
27 #include "enigma2/ConnectionManager.h"
28 #include "enigma2/Epg.h"
29 #include "enigma2/IConnectionListener.h"
30 #include "enigma2/RecordingReader.h"
31 #include "enigma2/Recordings.h"
32 #include "enigma2/Settings.h"
33 #include "enigma2/Timers.h"
34 #include "enigma2/data/BaseEntry.h"
35 #include "enigma2/data/Channel.h"
36 #include "enigma2/data/ChannelGroup.h"
37 #include "enigma2/data/EpgEntry.h"
38 #include "enigma2/data/RecordingEntry.h"
39 #include "enigma2/extract/EpgEntryExtractor.h"
40 #include "enigma2/utilities/SignalStatus.h"
41 #include "p8-platform/threads/threads.h"
42 #include "tinyxml.h"
43
44 #include <atomic>
45 #include <time.h>
46
47 // The windows build defines this but it breaks nlohmann/json.hpp's reference to std::snprintf
48 #if defined(snprintf)
49 #undef snprintf
50 #endif
51
52 class Enigma2 : public P8PLATFORM::CThread, public enigma2::IConnectionListener
53 {
54 public:
55 Enigma2(PVR_PROPERTIES* pvrProps);
56 ~Enigma2();
57
58 // IConnectionListener implementation
59 void ConnectionLost() override;
60 void ConnectionEstablished() override;
61
62 void OnSleep();
63 void OnWake();
64
65 //device and helper functions
66 bool Start();
67 void SendPowerstate();
68 const char* GetServerName() const;
69 const char* GetServerVersion() const;
70 bool IsConnected() const;
71
72 //groups, channels and EPG
73 unsigned int GetNumChannelGroups(void) const;
74 PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool radio);
75 PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group);
76 int GetChannelsAmount(void) const;
77 PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio);
78 PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL& channel, time_t iStart, time_t iEnd);
79 void SetEPGTimeFrame(int epgMaxDays);
80
81 //live streams, recordings and Timers
82 bool OpenLiveStream(const PVR_CHANNEL& channelinfo);
83 void CloseLiveStream();
84 const std::string GetLiveStreamURL(const PVR_CHANNEL& channelinfo);
85 bool IsIptvStream(const PVR_CHANNEL& channelinfo) const;
86 int GetChannelStreamProgramNumber(const PVR_CHANNEL& channelinfo);
87 unsigned int GetRecordingsAmount(bool deleted);
88 PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted);
89 PVR_ERROR DeleteRecording(const PVR_RECORDING& recinfo);
90 PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording);
91 PVR_ERROR DeleteAllRecordingsFromTrash();
92 bool GetRecordingsFromLocation(std::string strRecordingFolder);
93 PVR_ERROR GetRecordingEdl(const PVR_RECORDING& recinfo, PVR_EDL_ENTRY edl[], int* size);
94 PVR_ERROR RenameRecording(const PVR_RECORDING& recording);
95 PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING& recording, int count);
96 PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastplayedposition);
97 int GetRecordingLastPlayedPosition(const PVR_RECORDING& recording);
98 bool HasRecordingStreamProgramNumber(const PVR_RECORDING& recording);
99 int GetRecordingStreamProgramNumber(const PVR_RECORDING& recording);
100 enigma2::RecordingReader* OpenRecordedStream(const PVR_RECORDING& recinfo);
101 void GetTimerTypes(PVR_TIMER_TYPE types[], int* size);
102 int GetTimersAmount(void);
103 PVR_ERROR GetTimers(ADDON_HANDLE handle);
104 PVR_ERROR AddTimer(const PVR_TIMER& timer);
105 PVR_ERROR UpdateTimer(const PVR_TIMER& timer);
106 PVR_ERROR DeleteTimer(const PVR_TIMER& timer);
107 PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed);
108 PVR_ERROR GetTunerSignal(PVR_SIGNAL_STATUS& signalStatus);
109
110 protected:
111 void* Process() override;
112
113 private:
114 static const int INITIAL_EPG_WAIT_SECS = 60;
115 static const int INITIAL_EPG_STEP_SECS = 5;
116 static const int PROCESS_LOOP_WAIT_SECS = 5;
117
118 // helper functions
119 std::string GetStreamURL(const std::string& strM3uURL);
120 enigma2::ChannelsChangeState CheckForChannelAndGroupChanges();
121 void ReloadChannelsGroupsAndEPG();
122
123 // members
124 bool m_isConnected = false;
125 int m_currentChannel = -1;
126 std::atomic_bool m_dueRecordingUpdate{true};
127 time_t m_lastSignalStatusUpdateSeconds;
128 bool m_skipInitialEpgLoad;
129 int m_epgMaxDays;
130
131 mutable enigma2::Channels m_channels;
132 enigma2::ChannelGroups m_channelGroups;
133 enigma2::Recordings m_recordings{m_channels, m_entryExtractor};
134 std::vector<std::string>& m_locations = m_recordings.GetLocations();
135 enigma2::Epg m_epg{m_entryExtractor, m_epgMaxDays};
136 enigma2::Timers m_timers{m_channels, m_channelGroups, m_locations, m_epg, m_entryExtractor};
137 enigma2::Settings& m_settings = enigma2::Settings::GetInstance();
138 enigma2::Admin m_admin;
139 enigma2::extract::EpgEntryExtractor m_entryExtractor;
140 enigma2::utilities::SignalStatus m_signalStatus;
141 enigma2::ConnectionManager* connectionManager;
142
143 mutable P8PLATFORM::CMutex m_mutex;
144 P8PLATFORM::CCondition<bool> m_started;
145 };
+0
-1885
src/VuData.cpp less more
0 /*
1 * Copyright (C) 2005-2015 Team XBMC
2 * http://xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "VuData.h"
23 #include "client.h"
24 #include <iostream>
25 #include <fstream>
26 #include <string>
27 #include "util/XMLUtils.h"
28
29
30 using namespace ADDON;
31 using namespace P8PLATFORM;
32
33 bool CCurlFile::Get(const std::string &strURL, std::string &strResult)
34 {
35 void* fileHandle = XBMC->OpenFile(strURL.c_str(), 0);
36 if (fileHandle)
37 {
38 char buffer[1024];
39 while (XBMC->ReadFileString(fileHandle, buffer, 1024))
40 strResult.append(buffer);
41 XBMC->CloseFile(fileHandle);
42 return true;
43 }
44 return false;
45 }
46
47 std::string& Vu::Escape(std::string &s, std::string from, std::string to)
48 {
49 std::string::size_type pos = -1;
50 while ( (pos = s.find(from, pos+1) ) != std::string::npos)
51 s.erase(pos, from.length()).insert(pos, to);
52
53 return s;
54 }
55
56 bool Vu::LoadLocations()
57 {
58 CStdString url;
59 if (g_bOnlyCurrentLocation)
60 url.Format("%s%s", m_strURL.c_str(), "web/getcurrlocation");
61 else
62 url.Format("%s%s", m_strURL.c_str(), "web/getlocations");
63
64 CStdString strXML;
65 strXML = GetHttpXML(url);
66
67 int iNumLocations = 0;
68
69 TiXmlDocument xmlDoc;
70 if (!xmlDoc.Parse(strXML.c_str()))
71 {
72 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
73 return false;
74 }
75
76 TiXmlHandle hDoc(&xmlDoc);
77 TiXmlElement* pElem;
78 TiXmlHandle hRoot(0);
79
80 pElem = hDoc.FirstChildElement("e2locations").Element();
81
82 if (!pElem)
83 {
84 XBMC->Log(LOG_DEBUG, "Could not find <e2locations> element");
85 return false;
86 }
87
88 hRoot=TiXmlHandle(pElem);
89
90 TiXmlElement* pNode = hRoot.FirstChildElement("e2location").Element();
91
92 if (!pNode)
93 {
94 XBMC->Log(LOG_DEBUG, "Could not find <e2location> element");
95 return false;
96 }
97
98 for (; pNode != NULL; pNode = pNode->NextSiblingElement("e2location"))
99 {
100 CStdString strTmp;
101 strTmp = pNode->GetText();
102
103 m_locations.push_back(strTmp);
104 iNumLocations++;
105
106 XBMC->Log(LOG_DEBUG, "%s Added '%s' as a recording location", __FUNCTION__, strTmp.c_str());
107 }
108
109 XBMC->Log(LOG_INFO, "%s Loded '%d' recording locations", __FUNCTION__, iNumLocations);
110
111 return true;
112 }
113
114 void Vu::TimerUpdates()
115 {
116 std::vector<VuTimer> newtimer = LoadTimers();
117
118 for (unsigned int i=0; i<m_timers.size(); i++)
119 {
120 m_timers[i].iUpdateState = VU_UPDATE_STATE_NONE;
121 }
122
123 unsigned int iUpdated=0;
124 unsigned int iUnchanged=0;
125
126 for (unsigned int j=0;j<newtimer.size(); j++)
127 {
128 for (unsigned int i=0; i<m_timers.size(); i++)
129 {
130 if (m_timers[i].like(newtimer[j]))
131 {
132 if(m_timers[i] == newtimer[j])
133 {
134 m_timers[i].iUpdateState = VU_UPDATE_STATE_FOUND;
135 newtimer[j].iUpdateState = VU_UPDATE_STATE_FOUND;
136 iUnchanged++;
137 }
138 else
139 {
140 newtimer[j].iUpdateState = VU_UPDATE_STATE_UPDATED;
141 m_timers[i].iUpdateState = VU_UPDATE_STATE_UPDATED;
142 m_timers[i].strTitle = newtimer[j].strTitle;
143 m_timers[i].strPlot = newtimer[j].strPlot;
144 m_timers[i].iChannelId = newtimer[j].iChannelId;
145 m_timers[i].startTime = newtimer[j].startTime;
146 m_timers[i].endTime = newtimer[j].endTime;
147 m_timers[i].iWeekdays = newtimer[j].iWeekdays;
148 m_timers[i].iEpgID = newtimer[j].iEpgID;
149
150 iUpdated++;
151 }
152 }
153 }
154 }
155
156 unsigned int iRemoved = 0;
157
158 for (unsigned int i=0; i<m_timers.size(); i++)
159 {
160 if (m_timers.at(i).iUpdateState == VU_UPDATE_STATE_NONE)
161 {
162 XBMC->Log(LOG_INFO, "%s Removed timer: '%s', ClientIndex: '%d'", __FUNCTION__, m_timers.at(i).strTitle.c_str(), m_timers.at(i).iClientIndex);
163 m_timers.erase(m_timers.begin()+i);
164 i=0;
165 iRemoved++;
166 }
167 }
168 unsigned int iNew=0;
169
170 for (unsigned int i=0; i<newtimer.size();i++)
171 {
172 if(newtimer.at(i).iUpdateState == VU_UPDATE_STATE_NEW)
173 {
174 VuTimer &timer = newtimer.at(i);
175 timer.iClientIndex = m_iClientIndexCounter;
176 XBMC->Log(LOG_INFO, "%s New timer: '%s', ClientIndex: '%d'", __FUNCTION__, timer.strTitle.c_str(), m_iClientIndexCounter);
177 m_timers.push_back(timer);
178 m_iClientIndexCounter++;
179 iNew++;
180 }
181 }
182
183 XBMC->Log(LOG_INFO, "%s No of timers: removed [%d], untouched [%d], updated '%d', new '%d'", __FUNCTION__, iRemoved, iUnchanged, iUpdated, iNew);
184
185 if (iRemoved != 0 || iUpdated != 0 || iNew != 0)
186 {
187 XBMC->Log(LOG_INFO, "%s Changes in timerlist detected, trigger an update!", __FUNCTION__);
188 PVR->TriggerTimerUpdate();
189 }
190 }
191
192 Vu::Vu()
193 {
194 m_bIsConnected = false;
195 m_strServerName = "Vu";
196 CStdString strURL = "";
197
198 // simply add user@pass in front of the URL if username/password is set
199 if ((g_strUsername.length() > 0) && (g_strPassword.length() > 0))
200 {
201 strURL.Format("%s:%s@", g_strUsername.c_str(), g_strPassword.c_str());
202 }
203
204 if (!g_bUseSecureHTTP)
205 strURL.Format("http://%s%s:%u/", strURL.c_str(), g_strHostname.c_str(), g_iPortWeb);
206 else
207 strURL.Format("https://%s%s:%u/", strURL.c_str(), g_strHostname.c_str(), g_iPortWeb);
208
209 m_strURL = strURL.c_str();
210
211 m_iNumRecordings = 0;
212 m_iNumChannelGroups = 0;
213 m_iCurrentChannel = -1;
214 m_iClientIndexCounter = 1;
215
216 m_bUpdating = false;
217 m_iUpdateTimer = 0;
218 m_bInitialEPG = true;
219
220 std::string initialEPGReady = "special://userdata/addon_data/pvr.vuplus/initialEPGReady";
221 m_writeHandle = XBMC->OpenFileForWrite(initialEPGReady.c_str(), true);
222 XBMC->WriteFile(m_writeHandle, "Y", 1);
223 XBMC->CloseFile(m_writeHandle);
224
225 }
226
227 bool Vu::Open()
228 {
229 CLockObject lock(m_mutex);
230
231 XBMC->Log(LOG_NOTICE, "%s - VU+ Addon Configuration options", __FUNCTION__);
232 XBMC->Log(LOG_NOTICE, "%s - Hostname: '%s'", __FUNCTION__, g_strHostname.c_str());
233 XBMC->Log(LOG_NOTICE, "%s - WebPort: '%d'", __FUNCTION__, g_iPortWeb);
234 XBMC->Log(LOG_NOTICE, "%s - StreamPort: '%d'", __FUNCTION__, g_iPortStream);
235 if (!g_bUseSecureHTTP)
236 XBMC->Log(LOG_NOTICE, "%s Use HTTPS: 'false'", __FUNCTION__);
237 else
238 XBMC->Log(LOG_NOTICE, "%s Use HTTPS: 'true'", __FUNCTION__);
239
240 if ((g_strUsername.length() > 0) && (g_strPassword.length() > 0))
241 {
242 if ((g_strUsername.find("@") != std::string::npos) || (g_strPassword.find("@") != std::string::npos))
243 {
244 XBMC->Log(LOG_ERROR, "%s - You cannot use the '@' character in either the username or the password with this addon. Please change your configuraton!", __FUNCTION__);
245 return false;
246 }
247 }
248 m_bIsConnected = GetDeviceInfo();
249
250 if (!m_bIsConnected)
251 {
252 XBMC->Log(LOG_ERROR, "%s It seem's that the webinterface cannot be reached. Make sure that you set the correct configuration options in the addon settings!", __FUNCTION__);
253 return false;
254 }
255
256 LoadLocations();
257
258 if (m_channels.size() == 0)
259 {
260 // Load the TV channels - close connection if no channels are found
261 if (!LoadChannelGroups())
262 return false;
263
264 if (!LoadChannels())
265 return false;
266
267 }
268 TimerUpdates();
269
270 XBMC->Log(LOG_INFO, "%s Starting separate client update thread...", __FUNCTION__);
271 CreateThread();
272
273 return IsRunning();
274 }
275
276 void *Vu::Process()
277 {
278 XBMC->Log(LOG_DEBUG, "%s - starting", __FUNCTION__);
279
280 // Wait for the initial EPG update to complete
281 bool bwait = true;
282 int cycles = 0;
283
284 while (bwait)
285 {
286 if (cycles == 30)
287 bwait = false;
288
289 cycles++;
290 std::string initialEPGReady = "special://userdata/addon_data/pvr.vuplus/initialEPGReady";
291 m_readHandle = XBMC->OpenFile(initialEPGReady.c_str(), 0);
292 byte buf[1];
293 XBMC->ReadFile(m_readHandle, buf, 1);
294 XBMC->CloseFile(m_readHandle);
295 char buf2[] = { "N" };
296 if (buf[0] == buf2[0])
297 {
298 XBMC->Log(LOG_DEBUG, "%s - Intial EPG update COMPLETE!", __FUNCTION__);
299 }
300 else
301 {
302 XBMC->Log(LOG_DEBUG, "%s - Intial EPG update not completed yet.", __FUNCTION__);
303 Sleep(5 * 1000);
304 }
305 }
306
307 // Trigger "Real" EPG updates
308 for (unsigned int iChannelPtr = 0; iChannelPtr < m_channels.size(); iChannelPtr++)
309 {
310 XBMC->Log(LOG_DEBUG, "%s - Trigger EPG update for channel '%d'", __FUNCTION__, iChannelPtr);
311 PVR->TriggerEpgUpdate(m_channels.at(iChannelPtr).iUniqueId);
312 }
313
314 while(!IsStopped())
315 {
316 Sleep(5 * 1000);
317 m_iUpdateTimer += 5;
318
319 if ((int)m_iUpdateTimer > (g_iUpdateInterval * 60))
320 {
321 m_iUpdateTimer = 0;
322
323 // Trigger Timer and Recording updates acording to the addon settings
324 CLockObject lock(m_mutex);
325 XBMC->Log(LOG_INFO, "%s Perform Updates!", __FUNCTION__);
326
327 if (g_bAutomaticTimerlistCleanup)
328 {
329 CStdString strTmp;
330 strTmp.Format("web/timercleanup?cleanup=true");
331 CStdString strResult;
332 if(!SendSimpleCommand(strTmp, strResult))
333 XBMC->Log(LOG_ERROR, "%s - AutomaticTimerlistCleanup failed!", __FUNCTION__);
334 }
335 TimerUpdates();
336 PVR->TriggerRecordingUpdate();
337 }
338
339 }
340
341 //CLockObject lock(m_mutex);
342 m_started.Broadcast();
343
344 return NULL;
345 }
346
347 bool Vu::LoadChannels()
348 {
349 bool bOk = false;
350
351 m_channels.clear();
352 // Load Channels
353 for (int i = 0;i<m_iNumChannelGroups; i++)
354 {
355 VuChannelGroup &myGroup = m_groups.at(i);
356 if (LoadChannels(myGroup.strServiceReference, myGroup.strGroupName))
357 bOk = true;
358 }
359
360 // Load the radio channels - continue if no channels are found
361 CStdString strTmp;
362 strTmp.Format("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.favourites.radio\" ORDER BY bouquet");
363 LoadChannels(strTmp, "radio");
364
365 return bOk;
366 }
367
368 bool Vu::LoadChannelGroups()
369 {
370 CStdString strTmp;
371
372 strTmp.Format("%sweb/getservices", m_strURL.c_str());
373
374 CStdString strXML = GetHttpXML(strTmp);
375
376 TiXmlDocument xmlDoc;
377 if (!xmlDoc.Parse(strXML.c_str()))
378 {
379 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
380 return false;
381 }
382
383 TiXmlHandle hDoc(&xmlDoc);
384 TiXmlElement* pElem;
385 TiXmlHandle hRoot(0);
386
387 pElem = hDoc.FirstChildElement("e2servicelist").Element();
388
389 if (!pElem)
390 {
391 XBMC->Log(LOG_DEBUG, "%s Could not find <e2servicelist> element!", __FUNCTION__);
392 return false;
393 }
394
395 hRoot=TiXmlHandle(pElem);
396
397 TiXmlElement* pNode = hRoot.FirstChildElement("e2service").Element();
398
399 if (!pNode)
400 {
401 XBMC->Log(LOG_DEBUG, "%s Could not find <e2service> element", __FUNCTION__);
402 return false;
403 }
404
405 m_groups.clear();
406 m_iNumChannelGroups = 0;
407
408 for (; pNode != NULL; pNode = pNode->NextSiblingElement("e2service"))
409 {
410 CStdString strTmp;
411
412 if (!XMLUtils::GetString(pNode, "e2servicereference", strTmp))
413 continue;
414
415 // Check whether the current element is not just a label
416 if (strTmp.compare(0,5,"1:64:") == 0)
417 continue;
418
419 VuChannelGroup newGroup;
420 newGroup.strServiceReference = strTmp;
421
422 if (!XMLUtils::GetString(pNode, "e2servicename", strTmp))
423 continue;
424
425 newGroup.strGroupName = strTmp;
426
427 if (g_bOnlyOneGroup && g_strOneGroup.compare(strTmp.c_str())) {
428 XBMC->Log(LOG_INFO, "%s Only one group is set, but current e2servicename '%s' does not match requested name '%s'", __FUNCTION__, strTmp.c_str(), g_strOneGroup.c_str());
429 continue;
430 }
431
432 m_groups.push_back(newGroup);
433
434 XBMC->Log(LOG_INFO, "%s Loaded channelgroup: %s", __FUNCTION__, newGroup.strGroupName.c_str());
435 m_iNumChannelGroups++;
436 }
437
438 XBMC->Log(LOG_INFO, "%s Loaded %d Channelsgroups", __FUNCTION__, m_iNumChannelGroups);
439 return true;
440 }
441
442 bool Vu::LoadChannels(CStdString strServiceReference, CStdString strGroupName)
443 {
444 XBMC->Log(LOG_INFO, "%s loading channel group: '%s'", __FUNCTION__, strGroupName.c_str());
445
446 CStdString strTmp;
447 strTmp.Format("%sweb/getservices?sRef=%s", m_strURL.c_str(), URLEncodeInline(strServiceReference.c_str()));
448
449 CStdString strXML = GetHttpXML(strTmp);
450
451 TiXmlDocument xmlDoc;
452 if (!xmlDoc.Parse(strXML.c_str()))
453 {
454 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
455 return false;
456 }
457
458 TiXmlHandle hDoc(&xmlDoc);
459 TiXmlElement* pElem;
460 TiXmlHandle hRoot(0);
461
462 pElem = hDoc.FirstChildElement("e2servicelist").Element();
463
464 if (!pElem)
465 {
466 XBMC->Log(LOG_DEBUG, "%s Could not find <e2servicelist> element!", __FUNCTION__);
467 return false;
468 }
469
470 hRoot=TiXmlHandle(pElem);
471
472 TiXmlElement* pNode = hRoot.FirstChildElement("e2service").Element();
473
474 if (!pNode)
475 {
476 XBMC->Log(LOG_DEBUG, "Could not find <e2service> element");
477 return false;
478 }
479
480 bool bRadio;
481
482 bRadio = !strGroupName.compare("radio");
483
484 for (; pNode != NULL; pNode = pNode->NextSiblingElement("e2service"))
485 {
486 CStdString strTmp;
487
488 if (!XMLUtils::GetString(pNode, "e2servicereference", strTmp))
489 continue;
490
491 // Check whether the current element is not just a label
492 if (strTmp.compare(0,5,"1:64:") == 0)
493 continue;
494
495 VuChannel newChannel;
496 newChannel.bRadio = bRadio;
497 newChannel.bInitialEPG = true;
498 newChannel.strGroupName = strGroupName;
499 newChannel.iUniqueId = m_channels.size()+1;
500 newChannel.iChannelNumber = m_channels.size()+1;
501 newChannel.strServiceReference = strTmp;
502
503 if (!XMLUtils::GetString(pNode, "e2servicename", strTmp))
504 continue;
505
506 newChannel.strChannelName = strTmp;
507
508 std::string strIcon;
509 strIcon = newChannel.strServiceReference.c_str();
510
511 int j = 0;
512 std::string::iterator it = strIcon.begin();
513
514 while (j<10 && it != strIcon.end())
515 {
516 if (*it == ':')
517 j++;
518
519 it++;
520 }
521 std::string::size_type index = it-strIcon.begin();
522
523 strIcon = strIcon.substr(0,index);
524
525 it = strIcon.end() - 1;
526 if (*it == ':')
527 {
528 strIcon.erase(it);
529 }
530
531 CStdString strTmp2;
532
533 strTmp2.Format("%s", strIcon.c_str());
534
535 std::replace(strIcon.begin(), strIcon.end(), ':', '_');
536 strIcon = g_strIconPath.c_str() + strIcon + ".png";
537
538 newChannel.strIconPath = strIcon;
539
540 strTmp.Format("");
541
542 strTmp.Format("http://%s:%d/%s", g_strHostname, g_iPortStream, strTmp2.c_str());
543
544 newChannel.strStreamURL = strTmp;
545
546 if (g_bOnlinePicons == true)
547 {
548 std::replace(strTmp2.begin(), strTmp2.end(), ':', '_');
549 strTmp.Format("%spicon/%s.png", m_strURL.c_str(), strTmp2.c_str());
550 newChannel.strIconPath = strTmp;
551 }
552
553 m_channels.push_back(newChannel);
554 XBMC->Log(LOG_INFO, "%s Loaded channel: %s, Icon: %s", __FUNCTION__, newChannel.strChannelName.c_str(), newChannel.strIconPath.c_str());
555 }
556
557 XBMC->Log(LOG_INFO, "%s Loaded %d Channels", __FUNCTION__, m_channels.size());
558 return true;
559 }
560
561 bool Vu::IsConnected()
562 {
563 return m_bIsConnected;
564 }
565
566 CStdString Vu::GetHttpXML(CStdString& url)
567 {
568 // CLockObject lock(m_mutex);
569
570 XBMC->Log(LOG_INFO, "%s Open webAPI with URL: '%s'", __FUNCTION__, url.c_str());
571
572 CStdString strTmp;
573
574 CCurlFile http;
575 if(!http.Get(url, strTmp))
576 {
577 XBMC->Log(LOG_DEBUG, "%s - Could not open webAPI.", __FUNCTION__);
578 return "";
579 }
580
581 XBMC->Log(LOG_INFO, "%s Got result. Length: %u", __FUNCTION__, strTmp.length());
582
583
584 return strTmp;
585 }
586
587 const char * Vu::GetServerName()
588 {
589 return m_strServerName.c_str();
590 }
591
592 int Vu::GetChannelsAmount()
593 {
594 return m_channels.size();
595 }
596
597 int Vu::GetTimersAmount()
598 {
599 return m_timers.size();
600 }
601
602 unsigned int Vu::GetRecordingsAmount() {
603 return m_iNumRecordings;
604 }
605
606 PVR_ERROR Vu::GetChannels(ADDON_HANDLE handle, bool bRadio)
607 {
608 // is the addon is currently updating the channels, then delay the call
609 unsigned int iTimer = 0;
610 while(m_bUpdating == true && iTimer < 120)
611 {
612 Sleep(1000);
613 iTimer++;
614 }
615
616 for (unsigned int iChannelPtr = 0; iChannelPtr < m_channels.size(); iChannelPtr++)
617 {
618 VuChannel &channel = m_channels.at(iChannelPtr);
619 if (channel.bRadio == bRadio)
620 {
621 PVR_CHANNEL xbmcChannel;
622 memset(&xbmcChannel, 0, sizeof(PVR_CHANNEL));
623
624 xbmcChannel.iUniqueId = channel.iUniqueId;
625 xbmcChannel.bIsRadio = channel.bRadio;
626 xbmcChannel.iChannelNumber = channel.iChannelNumber;
627 strncpy(xbmcChannel.strChannelName, channel.strChannelName.c_str(), sizeof(xbmcChannel.strChannelName));
628 strncpy(xbmcChannel.strInputFormat, "", 0); // unused
629 xbmcChannel.iEncryptionSystem = 0;
630 xbmcChannel.bIsHidden = false;
631 strncpy(xbmcChannel.strIconPath, channel.strIconPath.c_str(), sizeof(xbmcChannel.strIconPath));
632
633 CStdString strStream;
634 strStream.Format("pvr://stream/tv/%i.ts", channel.iUniqueId);
635 strncpy(xbmcChannel.strStreamURL, strStream.c_str(), sizeof(xbmcChannel.strStreamURL));
636
637 PVR->TransferChannelEntry(handle, &xbmcChannel);
638 }
639 }
640
641 return PVR_ERROR_NO_ERROR;
642 }
643
644 Vu::~Vu()
645 {
646 CLockObject lock(m_mutex);
647 XBMC->Log(LOG_DEBUG, "%s Stopping update thread...", __FUNCTION__);
648 StopThread();
649
650 XBMC->Log(LOG_DEBUG, "%s Removing internal channels list...", __FUNCTION__);
651 m_channels.clear();
652
653 XBMC->Log(LOG_DEBUG, "%s Removing internal timers list...", __FUNCTION__);
654 m_timers.clear();
655
656 XBMC->Log(LOG_DEBUG, "%s Removing internal recordings list...", __FUNCTION__);
657 m_recordings.clear();
658
659 XBMC->Log(LOG_DEBUG, "%s Removing internal group list...", __FUNCTION__);
660 m_groups.clear();
661 m_bIsConnected = false;
662 }
663
664 bool Vu::GetInitialEPGForGroup(VuChannelGroup &group)
665 {
666 // is the addon is currently updating the channels, then delay the call
667 unsigned int iTimer = 0;
668 while(m_bUpdating == true && iTimer < 120)
669 {
670 Sleep(1000);
671 iTimer++;
672 }
673
674 CStdString url;
675 url.Format("%s%s%s", m_strURL.c_str(), "web/epgnownext?bRef=", URLEncodeInline(group.strServiceReference.c_str()));
676
677 CStdString strXML;
678 strXML = GetHttpXML(url);
679
680 int iNumEPG = 0;
681
682 TiXmlDocument xmlDoc;
683 if (!xmlDoc.Parse(strXML.c_str()))
684 {
685 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
686 return false;
687 }
688
689 TiXmlHandle hDoc(&xmlDoc);
690 TiXmlElement* pElem;
691 TiXmlHandle hRoot(0);
692
693 pElem = hDoc.FirstChildElement("e2eventlist").Element();
694
695 if (!pElem)
696 {
697 XBMC->Log(LOG_DEBUG, "%s could not find <e2eventlist> element!", __FUNCTION__);
698 // Return "NO_ERROR" as the EPG could be empty for this channel
699 return false;
700 }
701
702 hRoot=TiXmlHandle(pElem);
703
704 TiXmlElement* pNode = hRoot.FirstChildElement("e2event").Element();
705
706 if (!pNode)
707 {
708 XBMC->Log(LOG_DEBUG, "Could not find <e2event> element");
709 // RETURN "NO_ERROR" as the EPG could be empty for this channel
710 return false;
711 }
712
713 for (; pNode != NULL; pNode = pNode->NextSiblingElement("e2event"))
714 {
715 CStdString strTmp;
716
717 int iTmpStart;
718 int iTmp;
719
720 // check and set event starttime and endtimes
721 if (!XMLUtils::GetInt(pNode, "e2eventstart", iTmpStart))
722 continue;
723
724 if (!XMLUtils::GetInt(pNode, "e2eventduration", iTmp))
725 continue;
726
727 VuEPGEntry entry;
728 entry.startTime = iTmpStart;
729 entry.endTime = iTmpStart + iTmp;
730
731 if (!XMLUtils::GetInt(pNode, "e2eventid", entry.iEventId))
732 continue;
733
734
735 if(!XMLUtils::GetString(pNode, "e2eventtitle", strTmp))
736 continue;
737
738 entry.strTitle = strTmp;
739
740 if(!XMLUtils::GetString(pNode, "e2eventservicereference", strTmp))
741 continue;
742
743 entry.strServiceReference = strTmp;
744
745 entry.iChannelId = GetChannelNumber(entry.strServiceReference.c_str());
746
747 if (XMLUtils::GetString(pNode, "e2eventdescriptionextended", strTmp))
748 entry.strPlot = strTmp;
749
750 if (XMLUtils::GetString(pNode, "e2eventdescription", strTmp))
751 entry.strPlotOutline = strTmp;
752
753 iNumEPG++;
754
755 group.initialEPG.push_back(entry);
756 }
757
758 XBMC->Log(LOG_INFO, "%s Loaded %u EPG Entries for group '%s'", __FUNCTION__, iNumEPG, group.strGroupName.c_str());
759 return true;
760 }
761
762 PVR_ERROR Vu::GetInitialEPGForChannel(ADDON_HANDLE handle, const VuChannel &channel, time_t iStart, time_t iEnd)
763 {
764 if (m_iNumChannelGroups < 1)
765 return PVR_ERROR_SERVER_ERROR;
766
767 XBMC->Log(LOG_DEBUG, "%s Fetch information for group '%s'", __FUNCTION__, channel.strGroupName.c_str());
768
769 VuChannelGroup &myGroup = m_groups.at(0);
770 for (int i = 0;i<m_iNumChannelGroups; i++)
771 {
772 myGroup = m_groups.at(i);
773 if (!myGroup.strGroupName.compare(channel.strGroupName))
774 if (myGroup.initialEPG.size() == 0)
775 {
776 GetInitialEPGForGroup(myGroup);
777 break;
778 }
779 }
780
781 XBMC->Log(LOG_DEBUG, "%s initialEPG size is now '%d'", __FUNCTION__, myGroup.initialEPG.size());
782
783 for (unsigned int i = 0;i<myGroup.initialEPG.size(); i++)
784 {
785 VuEPGEntry &entry = myGroup.initialEPG.at(i);
786 if (!channel.strServiceReference.compare(entry.strServiceReference))
787 {
788 EPG_TAG broadcast;
789 memset(&broadcast, 0, sizeof(EPG_TAG));
790
791 broadcast.iUniqueBroadcastId = entry.iEventId;
792 broadcast.strTitle = entry.strTitle.c_str();
793 broadcast.iChannelNumber = channel.iChannelNumber;
794 broadcast.startTime = entry.startTime;
795 broadcast.endTime = entry.endTime;
796 broadcast.strPlotOutline = entry.strPlotOutline.c_str();
797 broadcast.strPlot = entry.strPlot.c_str();
798 broadcast.strOriginalTitle = NULL; // unused
799 broadcast.strCast = NULL; // unused
800 broadcast.strDirector = NULL; // unused
801 broadcast.strWriter = NULL; // unused
802 broadcast.iYear = 0; // unused
803 broadcast.strIMDBNumber = NULL; // unused
804 broadcast.strIconPath = ""; // unused
805 broadcast.iGenreType = 0; // unused
806 broadcast.iGenreSubType = 0; // unused
807 broadcast.strGenreDescription = "";
808 broadcast.firstAired = 0; // unused
809 broadcast.iParentalRating = 0; // unused
810 broadcast.iStarRating = 0; // unused
811 broadcast.bNotify = false;
812 broadcast.iSeriesNumber = 0; // unused
813 broadcast.iEpisodeNumber = 0; // unused
814 broadcast.iEpisodePartNumber = 0; // unused
815 broadcast.strEpisodeName = ""; // unused
816 broadcast.iFlags = EPG_TAG_FLAG_UNDEFINED;
817
818 PVR->TransferEpgEntry(handle, &broadcast);
819 }
820 }
821 return PVR_ERROR_NO_ERROR;
822 }
823
824 PVR_ERROR Vu::GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd)
825 {
826 // is the addon is currently updating the channels, then delay the call
827 unsigned int iTimer = 0;
828 while(m_bUpdating == true && iTimer < 120)
829 {
830 Sleep(1000);
831 iTimer++;
832 }
833
834 if (channel.iUniqueId-1 > m_channels.size())
835 {
836 XBMC->Log(LOG_ERROR, "%s Could not fetch cannel object - not fetching EPG for channel with UniqueID '%d'", __FUNCTION__, channel.iUniqueId);
837 return PVR_ERROR_NO_ERROR;
838 }
839
840 VuChannel myChannel;
841 myChannel = m_channels.at(channel.iUniqueId-1);
842
843 // Check if the initial short import has already been done for this channel
844 if (m_channels.at(channel.iUniqueId-1).bInitialEPG == true)
845 {
846 m_channels.at(channel.iUniqueId-1).bInitialEPG = false;
847
848 // Check if all channels have completed the initial EPG import
849 m_bInitialEPG = false;
850 for (unsigned int iChannelPtr = 0; iChannelPtr < m_channels.size(); iChannelPtr++)
851 {
852 if (m_channels.at(iChannelPtr).bInitialEPG == true)
853 {
854 m_bInitialEPG = true;
855 }
856 }
857
858 if (!m_bInitialEPG)
859 {
860 std::string initialEPGReady = "special://userdata/addon_data/pvr.vuplus/initialEPGReady";
861 m_writeHandle = XBMC->OpenFileForWrite(initialEPGReady.c_str(), true);
862 XBMC->WriteFile(m_writeHandle, "N", 1);
863 XBMC->CloseFile(m_writeHandle);
864 }
865 return GetInitialEPGForChannel(handle, myChannel, iStart, iEnd);
866 }
867
868 CStdString url;
869 url.Format("%s%s%s", m_strURL.c_str(), "web/epgservice?sRef=", URLEncodeInline(myChannel.strServiceReference.c_str()));
870
871 CStdString strXML;
872 strXML = GetHttpXML(url);
873
874 int iNumEPG = 0;
875
876 TiXmlDocument xmlDoc;
877 if (!xmlDoc.Parse(strXML.c_str()))
878 {
879 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
880 return PVR_ERROR_SERVER_ERROR;
881 }
882
883 TiXmlHandle hDoc(&xmlDoc);
884 TiXmlElement* pElem;
885 TiXmlHandle hRoot(0);
886
887 pElem = hDoc.FirstChildElement("e2eventlist").Element();
888
889 if (!pElem)
890 {
891 XBMC->Log(LOG_DEBUG, "%s could not find <e2eventlist> element!", __FUNCTION__);
892 // Return "NO_ERROR" as the EPG could be empty for this channel
893 return PVR_ERROR_NO_ERROR;
894 }
895
896 hRoot=TiXmlHandle(pElem);
897
898 TiXmlElement* pNode = hRoot.FirstChildElement("e2event").Element();
899
900 if (!pNode)
901 {
902 XBMC->Log(LOG_DEBUG, "Could not find <e2event> element");
903 // RETURN "NO_ERROR" as the EPG could be empty for this channel
904 return PVR_ERROR_SERVER_ERROR;
905 }
906
907 for (; pNode != NULL; pNode = pNode->NextSiblingElement("e2event"))
908 {
909 CStdString strTmp;
910
911 int iTmpStart;
912 int iTmp;
913
914 // check and set event starttime and endtimes
915 if (!XMLUtils::GetInt(pNode, "e2eventstart", iTmpStart))
916 continue;
917
918 // Skip unneccessary events
919 if (iStart > iTmpStart)
920 continue;
921
922 if (!XMLUtils::GetInt(pNode, "e2eventduration", iTmp))
923 continue;
924
925 if ((iEnd > 1) && (iEnd < (iTmpStart + iTmp)))
926 continue;
927
928 VuEPGEntry entry;
929 entry.startTime = iTmpStart;
930 entry.endTime = iTmpStart + iTmp;
931
932 if (!XMLUtils::GetInt(pNode, "e2eventid", entry.iEventId))
933 continue;
934
935 entry.iChannelId = channel.iUniqueId;
936
937 if(!XMLUtils::GetString(pNode, "e2eventtitle", strTmp))
938 continue;
939
940 entry.strTitle = strTmp;
941
942 entry.strServiceReference = myChannel.strServiceReference.c_str();
943
944 if (XMLUtils::GetString(pNode, "e2eventdescriptionextended", strTmp))
945 entry.strPlot = strTmp;
946
947 if (XMLUtils::GetString(pNode, "e2eventdescription", strTmp))
948 entry.strPlotOutline = strTmp;
949
950 EPG_TAG broadcast;
951 memset(&broadcast, 0, sizeof(EPG_TAG));
952
953 broadcast.iUniqueBroadcastId = entry.iEventId;
954 broadcast.strTitle = entry.strTitle.c_str();
955 broadcast.iChannelNumber = channel.iChannelNumber;
956 broadcast.startTime = entry.startTime;
957 broadcast.endTime = entry.endTime;
958 broadcast.strPlotOutline = entry.strPlotOutline.c_str();
959 broadcast.strPlot = entry.strPlot.c_str();
960 broadcast.strOriginalTitle = NULL; // unused
961 broadcast.strCast = NULL; // unused
962 broadcast.strDirector = NULL; // unused
963 broadcast.strWriter = NULL; // unused
964 broadcast.iYear = 0; // unused
965 broadcast.strIMDBNumber = NULL; // unused
966 broadcast.strIconPath = ""; // unused
967 broadcast.iGenreType = 0; // unused
968 broadcast.iGenreSubType = 0; // unused
969 broadcast.strGenreDescription = "";
970 broadcast.firstAired = 0; // unused
971 broadcast.iParentalRating = 0; // unused
972 broadcast.iStarRating = 0; // unused
973 broadcast.bNotify = false;
974 broadcast.iSeriesNumber = 0; // unused
975 broadcast.iEpisodeNumber = 0; // unused
976 broadcast.iEpisodePartNumber = 0; // unused
977 broadcast.strEpisodeName = ""; // unused
978 broadcast.iFlags = EPG_TAG_FLAG_UNDEFINED;
979
980 PVR->TransferEpgEntry(handle, &broadcast);
981
982 iNumEPG++;
983
984 XBMC->Log(LOG_DEBUG, "%s loaded EPG entry '%d:%s' channel '%d' start '%d' end '%d'", __FUNCTION__, broadcast.iUniqueBroadcastId, broadcast.strTitle, entry.iChannelId, entry.startTime, entry.endTime);
985 }
986
987 XBMC->Log(LOG_INFO, "%s Loaded %u EPG Entries for channel '%s'", __FUNCTION__, iNumEPG, channel.strChannelName);
988 return PVR_ERROR_NO_ERROR;
989 }
990
991 int Vu::GetChannelNumber(CStdString strServiceReference)
992 {
993 for (unsigned int i = 0;i<m_channels.size(); i++)
994 {
995 if (!strServiceReference.compare(m_channels[i].strServiceReference))
996 return i+1;
997 }
998 return -1;
999 }
1000
1001 CStdString Vu::GetChannelIconPath(CStdString strChannelName)
1002 {
1003 for (unsigned int i = 0;i<m_channels.size(); i++)
1004 {
1005 if (!strChannelName.compare(m_channels[i].strChannelName))
1006 return m_channels[i].strIconPath;
1007 }
1008 return "";
1009 }
1010
1011 PVR_ERROR Vu::GetTimers(ADDON_HANDLE handle)
1012 {
1013 // is the addon is currently updating the channels, then delay the call
1014 unsigned int iTimer = 0;
1015 while(m_bUpdating == true && iTimer < 120)
1016 {
1017 Sleep(1000);
1018 iTimer++;
1019 }
1020
1021 XBMC->Log(LOG_INFO, "%s - timers available '%d'", __FUNCTION__, m_timers.size());
1022 for (unsigned int i=0; i<m_timers.size(); i++)
1023 {
1024 VuTimer &timer = m_timers.at(i);
1025 XBMC->Log(LOG_DEBUG, "%s - Transfer timer '%s', ClientIndex '%d'", __FUNCTION__, timer.strTitle.c_str(), timer.iClientIndex);
1026 PVR_TIMER tag;
1027 memset(&tag, 0, sizeof(PVR_TIMER));
1028
1029 /* TODO: Implement own timer types to get support for the timer features introduced with PVR API 1.9.7 */
1030 tag.iTimerType = PVR_TIMER_TYPE_NONE;
1031
1032 tag.iClientChannelUid = timer.iChannelId;
1033 tag.startTime = timer.startTime;
1034 tag.endTime = timer.endTime;
1035 strncpy(tag.strTitle, timer.strTitle.c_str(), sizeof(tag.strTitle));
1036 strncpy(tag.strDirectory, "/", sizeof(tag.strDirectory)); // unused
1037 strncpy(tag.strSummary, timer.strPlot.c_str(), sizeof(tag.strSummary));
1038 tag.state = timer.state;
1039 tag.iPriority = 0; // unused
1040 tag.iLifetime = 0; // unused
1041 tag.firstDay = 0; // unused
1042 tag.iWeekdays = timer.iWeekdays;
1043 tag.iEpgUid = timer.iEpgID;
1044 tag.iMarginStart = 0; // unused
1045 tag.iMarginEnd = 0; // unused
1046 tag.iGenreType = 0; // unused
1047 tag.iGenreSubType = 0; // unused
1048 tag.iClientIndex = timer.iClientIndex;
1049
1050 PVR->TransferTimerEntry(handle, &tag);
1051 }
1052
1053 return PVR_ERROR_NO_ERROR;
1054 }
1055
1056 std::vector<VuTimer> Vu::LoadTimers()
1057 {
1058 std::vector<VuTimer> timers;
1059
1060 CStdString url;
1061 url.Format("%s%s", m_strURL.c_str(), "web/timerlist");
1062
1063 CStdString strXML;
1064 strXML = GetHttpXML(url);
1065
1066 TiXmlDocument xmlDoc;
1067 if (!xmlDoc.Parse(strXML.c_str()))
1068 {
1069 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
1070 return timers;
1071 }
1072
1073 TiXmlHandle hDoc(&xmlDoc);
1074 TiXmlElement* pElem;
1075 TiXmlHandle hRoot(0);
1076
1077 pElem = hDoc.FirstChildElement("e2timerlist").Element();
1078
1079 if (!pElem)
1080 {
1081 XBMC->Log(LOG_DEBUG, "%s Could not find <e2timerlist> element!", __FUNCTION__);
1082 return timers;
1083 }
1084
1085 hRoot=TiXmlHandle(pElem);
1086
1087 TiXmlElement* pNode = hRoot.FirstChildElement("e2timer").Element();
1088
1089 if (!pNode)
1090 {
1091 XBMC->Log(LOG_DEBUG, "Could not find <e2timer> element");
1092 return timers;
1093 }
1094
1095 for (; pNode != NULL; pNode = pNode->NextSiblingElement("e2timer"))
1096 {
1097 CStdString strTmp;
1098
1099 int iTmp;
1100 bool bTmp;
1101 int iDisabled;
1102
1103 if (XMLUtils::GetString(pNode, "e2name", strTmp))
1104 XBMC->Log(LOG_DEBUG, "%s Processing timer '%s'", __FUNCTION__, strTmp.c_str());
1105
1106 if (!XMLUtils::GetInt(pNode, "e2state", iTmp))
1107 continue;
1108
1109 if (!XMLUtils::GetInt(pNode, "e2disabled", iDisabled))
1110 continue;
1111
1112 VuTimer timer;
1113
1114 timer.strTitle = strTmp;
1115
1116 if (XMLUtils::GetString(pNode, "e2servicereference", strTmp))
1117 timer.iChannelId = GetChannelNumber(strTmp.c_str());
1118
1119 if (!XMLUtils::GetInt(pNode, "e2timebegin", iTmp))
1120 continue;
1121
1122 timer.startTime = iTmp;
1123
1124 if (!XMLUtils::GetInt(pNode, "e2timeend", iTmp))
1125 continue;
1126
1127 timer.endTime = iTmp;
1128
1129 if (XMLUtils::GetString(pNode, "e2description", strTmp))
1130 timer.strPlot = strTmp.c_str();
1131
1132 if (XMLUtils::GetInt(pNode, "e2repeated", iTmp))
1133 timer.iWeekdays = iTmp;
1134 else
1135 timer.iWeekdays = 0;
1136
1137 if (XMLUtils::GetInt(pNode, "e2eit", iTmp))
1138 timer.iEpgID = iTmp;
1139 else
1140 timer.iEpgID = 0;
1141
1142 timer.state = PVR_TIMER_STATE_NEW;
1143
1144 if (!XMLUtils::GetInt(pNode, "e2state", iTmp))
1145 continue;
1146
1147 XBMC->Log(LOG_DEBUG, "%s e2state is: %d ", __FUNCTION__, iTmp);
1148
1149 if (iTmp == 0)
1150 {
1151 timer.state = PVR_TIMER_STATE_SCHEDULED;
1152 XBMC->Log(LOG_DEBUG, "%s Timer state is: SCHEDULED", __FUNCTION__);
1153 }
1154
1155 if (iTmp == 2)
1156 {
1157 timer.state = PVR_TIMER_STATE_RECORDING;
1158 XBMC->Log(LOG_DEBUG, "%s Timer state is: RECORDING", __FUNCTION__);
1159 }
1160
1161 if (iTmp == 3 && iDisabled == 0)
1162 {
1163 timer.state = PVR_TIMER_STATE_COMPLETED;
1164 XBMC->Log(LOG_DEBUG, "%s Timer state is: COMPLETED", __FUNCTION__);
1165 }
1166
1167 if (XMLUtils::GetBoolean(pNode, "e2cancled", bTmp))
1168 {
1169 if (bTmp)
1170 {
1171 timer.state = PVR_TIMER_STATE_ABORTED;
1172 XBMC->Log(LOG_DEBUG, "%s Timer state is: ABORTED", __FUNCTION__);
1173 }
1174 }
1175
1176 if (iDisabled == 1)
1177 {
1178 timer.state = PVR_TIMER_STATE_CANCELLED;
1179 XBMC->Log(LOG_DEBUG, "%s Timer state is: Cancelled", __FUNCTION__);
1180 }
1181
1182 if (timer.state == PVR_TIMER_STATE_NEW)
1183 XBMC->Log(LOG_DEBUG, "%s Timer state is: NEW", __FUNCTION__);
1184
1185 timers.push_back(timer);
1186
1187 XBMC->Log(LOG_INFO, "%s fetched Timer entry '%s', begin '%d', end '%d'", __FUNCTION__, timer.strTitle.c_str(), timer.startTime, timer.endTime);
1188 }
1189
1190 XBMC->Log(LOG_INFO, "%s fetched %u Timer Entries", __FUNCTION__, timers.size());
1191 return timers;
1192 }
1193
1194 bool Vu::SendSimpleCommand(const CStdString& strCommandURL, CStdString& strResultText, bool bIgnoreResult)
1195 {
1196 CStdString url;
1197 url.Format("%s%s", m_strURL.c_str(), strCommandURL.c_str());
1198
1199 CStdString strXML;
1200 strXML = GetHttpXML(url);
1201
1202 if (!bIgnoreResult)
1203 {
1204 TiXmlDocument xmlDoc;
1205 if (!xmlDoc.Parse(strXML.c_str()))
1206 {
1207 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
1208 return false;
1209 }
1210
1211 TiXmlHandle hDoc(&xmlDoc);
1212 TiXmlElement* pElem;
1213 TiXmlHandle hRoot(0);
1214
1215 pElem = hDoc.FirstChildElement("e2simplexmlresult").Element();
1216
1217 if (!pElem)
1218 {
1219 XBMC->Log(LOG_DEBUG, "%s Could not find <e2simplexmlresult> element!", __FUNCTION__);
1220 return false;
1221 }
1222
1223 bool bTmp;
1224
1225 if (!XMLUtils::GetBoolean(pElem, "e2state", bTmp))
1226 {
1227 XBMC->Log(LOG_ERROR, "%s Could not parse e2state from result!", __FUNCTION__);
1228 strResultText.Format("Could not parse e2state!");
1229 return false;
1230 }
1231
1232 if (!XMLUtils::GetString(pElem, "e2statetext", strResultText))
1233 {
1234 XBMC->Log(LOG_ERROR, "%s Could not parse e2state from result!", __FUNCTION__);
1235 return false;
1236 }
1237
1238 if (!bTmp)
1239 XBMC->Log(LOG_ERROR, "%s Error message from backend: '%s'", __FUNCTION__, strResultText.c_str());
1240
1241 return bTmp;
1242 }
1243 return true;
1244 }
1245
1246
1247 PVR_ERROR Vu::AddTimer(const PVR_TIMER &timer)
1248 {
1249 XBMC->Log(LOG_DEBUG, "%s - channelUid=%d title=%s epgid=%d", __FUNCTION__, timer.iClientChannelUid, timer.strTitle, timer.iEpgUid);
1250
1251 CStdString strTmp;
1252 CStdString strServiceReference = m_channels.at(timer.iClientChannelUid-1).strServiceReference.c_str();
1253
1254 time_t startTime, endTime;
1255 startTime = timer.startTime - (timer.iMarginStart * 60);
1256 endTime = timer.endTime + (timer.iMarginEnd * 60);
1257
1258 if (!g_strRecordingPath.compare(""))
1259 strTmp.Format("web/timeradd?sRef=%s&repeated=%d&begin=%d&end=%d&name=%s&description=%s&eit=%d&dirname=&s", URLEncodeInline(strServiceReference), timer.iWeekdays, startTime, endTime, URLEncodeInline(timer.strTitle), URLEncodeInline(timer.strSummary),timer.iEpgUid, URLEncodeInline(g_strRecordingPath));
1260 else
1261 strTmp.Format("web/timeradd?sRef=%s&repeated=%d&begin=%d&end=%d&name=%s&description=%s&eit=%d", URLEncodeInline(strServiceReference), timer.iWeekdays, startTime, endTime, URLEncodeInline(timer.strTitle), URLEncodeInline(timer.strSummary),timer.iEpgUid);
1262
1263 CStdString strResult;
1264 if(!SendSimpleCommand(strTmp, strResult))
1265 return PVR_ERROR_SERVER_ERROR;
1266
1267 TimerUpdates();
1268
1269 return PVR_ERROR_NO_ERROR;
1270 }
1271
1272 PVR_ERROR Vu::DeleteTimer(const PVR_TIMER &timer)
1273 {
1274 CStdString strTmp;
1275 CStdString strServiceReference = m_channels.at(timer.iClientChannelUid-1).strServiceReference.c_str();
1276
1277 time_t startTime, endTime;
1278 startTime = timer.startTime - (timer.iMarginStart * 60);
1279 endTime = timer.endTime + (timer.iMarginEnd * 60);
1280
1281 strTmp.Format("web/timerdelete?sRef=%s&begin=%d&end=%d", URLEncodeInline(strServiceReference.c_str()), startTime, endTime);
1282
1283 CStdString strResult;
1284 if(!SendSimpleCommand(strTmp, strResult))
1285 return PVR_ERROR_SERVER_ERROR;
1286
1287 if (timer.state == PVR_TIMER_STATE_RECORDING)
1288 PVR->TriggerRecordingUpdate();
1289
1290 TimerUpdates();
1291
1292 return PVR_ERROR_NO_ERROR;
1293 }
1294
1295 PVR_ERROR Vu::GetRecordings(ADDON_HANDLE handle)
1296 {
1297 // is the addon is currently updating the channels, then delay the call
1298 unsigned int iTimer = 0;
1299 while(m_bUpdating == true && iTimer < 120)
1300 {
1301 Sleep(1000);
1302 iTimer++;
1303 }
1304
1305 m_iNumRecordings = 0;
1306 m_recordings.clear();
1307
1308 for (unsigned int i=0; i<m_locations.size(); i++)
1309 {
1310 if (!GetRecordingFromLocation(m_locations[i]))
1311 {
1312 XBMC->Log(LOG_ERROR, "%s Error fetching lists for folder: '%s'", __FUNCTION__, m_locations[i].c_str());
1313 }
1314 }
1315
1316 TransferRecordings(handle);
1317
1318 return PVR_ERROR_NO_ERROR;
1319 }
1320
1321 bool Vu::IsInRecordingFolder(CStdString strRecordingFolder)
1322 {
1323 int iMatches = 0;
1324 for (unsigned int i = 0; i < m_recordings.size(); i++)
1325 {
1326 if (strRecordingFolder.compare(m_recordings.at(i).strTitle) == 0)
1327 {
1328 iMatches++;
1329 XBMC->Log(LOG_DEBUG, "%s Found Recording title '%s' in recordings vector!", __FUNCTION__, strRecordingFolder.c_str());
1330 if (iMatches > 1)
1331 {
1332 XBMC->Log(LOG_DEBUG, "%s Found Recording title twice '%s' in recordings vector!", __FUNCTION__, strRecordingFolder.c_str());
1333 return true;
1334 }
1335 }
1336 }
1337
1338 return false;
1339 }
1340
1341 void Vu::TransferRecordings(ADDON_HANDLE handle)
1342 {
1343 for (unsigned int i=0; i<m_recordings.size(); i++)
1344 {
1345 CStdString strTmp;
1346 VuRecording &recording = m_recordings.at(i);
1347 PVR_RECORDING tag;
1348 memset(&tag, 0, sizeof(PVR_RECORDING));
1349 strncpy(tag.strRecordingId, recording.strRecordingId.c_str(), sizeof(tag.strRecordingId));
1350 strncpy(tag.strTitle, recording.strTitle.c_str(), sizeof(tag.strTitle));
1351 strncpy(tag.strStreamURL, recording.strStreamURL.c_str(), sizeof(tag.strStreamURL));
1352 strncpy(tag.strPlotOutline, recording.strPlotOutline.c_str(), sizeof(tag.strPlotOutline));
1353 strncpy(tag.strPlot, recording.strPlot.c_str(), sizeof(tag.strPlot));
1354 strncpy(tag.strChannelName, recording.strChannelName.c_str(), sizeof(tag.strChannelName));
1355 strncpy(tag.strIconPath, recording.strIconPath.c_str(), sizeof(tag.strIconPath));
1356
1357 if(IsInRecordingFolder(recording.strTitle))
1358 strTmp.Format("/%s/", recording.strTitle.c_str());
1359 else
1360 strTmp.Format("/");
1361
1362 recording.strDirectory = strTmp;
1363 strncpy(tag.strDirectory, recording.strDirectory.c_str(), sizeof(tag.strDirectory));
1364 tag.recordingTime = recording.startTime;
1365 tag.iDuration = recording.iDuration;
1366
1367 /* TODO: PVR API 5.0.0: Implement this */
1368 tag.iChannelUid = PVR_CHANNEL_INVALID_UID;
1369
1370 /* TODO: PVR API 5.1.0: Implement this */
1371 tag.channelType = PVR_RECORDING_CHANNEL_TYPE_UNKNOWN;
1372
1373 PVR->TransferRecordingEntry(handle, &tag);
1374 }
1375 }
1376
1377 bool Vu::GetRecordingFromLocation(CStdString strRecordingFolder)
1378 {
1379 CStdString url;
1380
1381 if (!strRecordingFolder.compare("default"))
1382 url.Format("%s%s", m_strURL.c_str(), "web/movielist");
1383 else
1384 url.Format("%s%s?dirname=%s", m_strURL.c_str(), "web/movielist", URLEncodeInline(strRecordingFolder.c_str()));
1385
1386 CStdString strXML;
1387 strXML = GetHttpXML(url);
1388
1389 TiXmlDocument xmlDoc;
1390 if (!xmlDoc.Parse(strXML.c_str()))
1391 {
1392 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
1393 return false;
1394 }
1395
1396 TiXmlHandle hDoc(&xmlDoc);
1397 TiXmlElement* pElem;
1398 TiXmlHandle hRoot(0);
1399
1400 pElem = hDoc.FirstChildElement("e2movielist").Element();
1401
1402 if (!pElem)
1403 {
1404 XBMC->Log(LOG_DEBUG, "%s Could not find <e2movielist> element!", __FUNCTION__);
1405 return false;
1406 }
1407
1408 hRoot=TiXmlHandle(pElem);
1409
1410 TiXmlElement* pNode = hRoot.FirstChildElement("e2movie").Element();
1411
1412 if (!pNode)
1413 {
1414 XBMC->Log(LOG_DEBUG, "Could not find <e2movie> element");
1415 return false;
1416 }
1417
1418 int iNumRecording = 0;
1419
1420 for (; pNode != NULL; pNode = pNode->NextSiblingElement("e2movie"))
1421 {
1422 CStdString strTmp;
1423 int iTmp;
1424
1425 VuRecording recording;
1426
1427 recording.iLastPlayedPosition = 0;
1428 if (XMLUtils::GetString(pNode, "e2servicereference", strTmp))
1429 recording.strRecordingId = strTmp;
1430
1431 if (XMLUtils::GetString(pNode, "e2title", strTmp))
1432 recording.strTitle = strTmp;
1433
1434 if (XMLUtils::GetString(pNode, "e2description", strTmp))
1435 recording.strPlotOutline = strTmp;
1436
1437 if (XMLUtils::GetString(pNode, "e2descriptionextended", strTmp))
1438 recording.strPlot = strTmp;
1439
1440 if (XMLUtils::GetString(pNode, "e2servicename", strTmp))
1441 recording.strChannelName = strTmp;
1442
1443 recording.strIconPath = GetChannelIconPath(strTmp.c_str());
1444
1445 if (XMLUtils::GetInt(pNode, "e2time", iTmp))
1446 recording.startTime = iTmp;
1447
1448 if (XMLUtils::GetString(pNode, "e2length", strTmp))
1449 {
1450 iTmp = TimeStringToSeconds(strTmp.c_str());
1451 recording.iDuration = iTmp;
1452 }
1453 else
1454 recording.iDuration = 0;
1455
1456 if (XMLUtils::GetString(pNode, "e2filename", strTmp))
1457 {
1458 strTmp.Format("%sfile?file=%s", m_strURL.c_str(), URLEncodeInline(strTmp.c_str()));
1459 recording.strStreamURL = strTmp;
1460 }
1461
1462 m_iNumRecordings++;
1463 iNumRecording++;
1464
1465 m_recordings.push_back(recording);
1466
1467 XBMC->Log(LOG_DEBUG, "%s loaded Recording entry '%s', start '%d', length '%d'", __FUNCTION__, recording.strTitle.c_str(), recording.startTime, recording.iDuration);
1468 }
1469
1470 XBMC->Log(LOG_INFO, "%s Loaded %u Recording Entries from folder '%s'", __FUNCTION__, iNumRecording, strRecordingFolder.c_str());
1471
1472 return true;
1473 }
1474
1475 PVR_ERROR Vu::DeleteRecording(const PVR_RECORDING &recinfo)
1476 {
1477 CStdString strTmp;
1478
1479 strTmp.Format("web/moviedelete?sRef=%s", URLEncodeInline(recinfo.strRecordingId));
1480
1481 CStdString strResult;
1482 if(!SendSimpleCommand(strTmp, strResult))
1483 return PVR_ERROR_FAILED;
1484
1485 PVR->TriggerRecordingUpdate();
1486
1487 return PVR_ERROR_NO_ERROR;
1488 }
1489
1490 PVR_ERROR Vu::UpdateTimer(const PVR_TIMER &timer)
1491 {
1492
1493 XBMC->Log(LOG_DEBUG, "%s timer channelid '%d'", __FUNCTION__, timer.iClientChannelUid);
1494
1495 CStdString strTmp;
1496 CStdString strServiceReference = m_channels.at(timer.iClientChannelUid-1).strServiceReference.c_str();
1497
1498 unsigned int i=0;
1499
1500 while (i<m_timers.size())
1501 {
1502 if (m_timers.at(i).iClientIndex == timer.iClientIndex)
1503 break;
1504 else
1505 i++;
1506 }
1507
1508 VuTimer &oldTimer = m_timers.at(i);
1509 CStdString strOldServiceReference = m_channels.at(oldTimer.iChannelId-1).strServiceReference.c_str();
1510 XBMC->Log(LOG_DEBUG, "%s old timer channelid '%d'", __FUNCTION__, oldTimer.iChannelId);
1511
1512 int iDisabled = 0;
1513 if (timer.state == PVR_TIMER_STATE_CANCELLED)
1514 iDisabled = 1;
1515
1516 strTmp.Format("web/timerchange?sRef=%s&begin=%d&end=%d&name=%s&eventID=&description=%s&tags=&afterevent=3&eit=0&disabled=%d&justplay=0&repeated=%d&channelOld=%s&beginOld=%d&endOld=%d&deleteOldOnSave=1", URLEncodeInline(strServiceReference.c_str()), timer.startTime, timer.endTime, URLEncodeInline(timer.strTitle), URLEncodeInline(timer.strSummary), iDisabled, timer.iWeekdays, URLEncodeInline(strOldServiceReference.c_str()), oldTimer.startTime, oldTimer.endTime );
1517
1518 CStdString strResult;
1519 if(!SendSimpleCommand(strTmp, strResult))
1520 return PVR_ERROR_SERVER_ERROR;
1521
1522 TimerUpdates();
1523
1524 return PVR_ERROR_NO_ERROR;
1525 }
1526
1527 long Vu::TimeStringToSeconds(const CStdString &timeString)
1528 {
1529 CStdStringArray secs;
1530 SplitString(timeString, ":", secs);
1531 int timeInSecs = 0;
1532 for (unsigned int i = 0; i < secs.size(); i++)
1533 {
1534 timeInSecs *= 60;
1535 timeInSecs += atoi(secs[i]);
1536 }
1537 return timeInSecs;
1538 }
1539
1540 int Vu::SplitString(const CStdString& input, const CStdString& delimiter, CStdStringArray &results, unsigned int iMaxStrings)
1541 {
1542 int iPos = -1;
1543 int newPos = -1;
1544 int sizeS2 = delimiter.GetLength();
1545 int isize = input.GetLength();
1546
1547 results.clear();
1548 std::vector<unsigned int> positions;
1549
1550 newPos = input.Find (delimiter, 0);
1551
1552 if ( newPos < 0 )
1553 {
1554 results.push_back(input);
1555 return 1;
1556 }
1557
1558 while ( newPos > iPos )
1559 {
1560 positions.push_back(newPos);
1561 iPos = newPos;
1562 newPos = input.Find (delimiter, iPos + sizeS2);
1563 }
1564
1565 // numFound is the number of delimeters which is one less
1566 // than the number of substrings
1567 unsigned int numFound = positions.size();
1568 if (iMaxStrings > 0 && numFound >= iMaxStrings)
1569 numFound = iMaxStrings - 1;
1570
1571 for ( unsigned int i = 0; i <= numFound; i++ )
1572 {
1573 CStdString s;
1574 if ( i == 0 )
1575 {
1576 if ( i == numFound )
1577 s = input;
1578 else
1579 s = input.Mid( i, positions[i] );
1580 }
1581 else
1582 {
1583 int offset = positions[i - 1] + sizeS2;
1584 if ( offset < isize )
1585 {
1586 if ( i == numFound )
1587 s = input.Mid(offset);
1588 else if ( i > 0 )
1589 s = input.Mid( positions[i - 1] + sizeS2,
1590 positions[i] - positions[i - 1] - sizeS2 );
1591 }
1592 }
1593 results.push_back(s);
1594 }
1595 // return the number of substrings
1596 return results.size();
1597 }
1598
1599 PVR_ERROR Vu::GetChannelGroups(ADDON_HANDLE handle)
1600 {
1601 // is the addon is currently updating the channels, then delay the call
1602 unsigned int iTimer = 0;
1603 while(m_bUpdating == true && iTimer < 120)
1604 {
1605 Sleep(1000);
1606 iTimer++;
1607 }
1608
1609 for(unsigned int iTagPtr = 0; iTagPtr < m_groups.size(); iTagPtr++)
1610 {
1611 PVR_CHANNEL_GROUP tag;
1612 memset(&tag, 0 , sizeof(PVR_CHANNEL_GROUP));
1613
1614 tag.bIsRadio = false;
1615 tag.iPosition = 0; // groups default order, unused
1616 strncpy(tag.strGroupName, m_groups[iTagPtr].strGroupName.c_str(), sizeof(tag.strGroupName));
1617
1618 PVR->TransferChannelGroup(handle, &tag);
1619 }
1620
1621 return PVR_ERROR_NO_ERROR;
1622 }
1623
1624 unsigned int Vu::GetNumChannelGroups()
1625 {
1626 return m_iNumChannelGroups;
1627 }
1628
1629 CStdString Vu::GetGroupServiceReference(CStdString strGroupName)
1630 {
1631 for (int i = 0;i<m_iNumChannelGroups; i++)
1632 {
1633 VuChannelGroup &myGroup = m_groups.at(i);
1634 if (!strGroupName.compare(myGroup.strGroupName))
1635 return myGroup.strServiceReference;
1636 }
1637 return "error";
1638 }
1639
1640 PVR_ERROR Vu::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group)
1641 {
1642 // is the addon is currently updating the channels, then delay the call
1643 unsigned int iTimer = 0;
1644 while(m_bUpdating == true && iTimer < 120)
1645 {
1646 Sleep(1000);
1647 iTimer++;
1648 }
1649
1650 XBMC->Log(LOG_DEBUG, "%s - group '%s'", __FUNCTION__, group.strGroupName);
1651 CStdString strTmp = group.strGroupName;
1652 for (unsigned int i = 0;i<m_channels.size(); i++)
1653 {
1654 VuChannel &myChannel = m_channels.at(i);
1655 if (!strTmp.compare(myChannel.strGroupName))
1656 {
1657 PVR_CHANNEL_GROUP_MEMBER tag;
1658 memset(&tag,0 , sizeof(PVR_CHANNEL_GROUP_MEMBER));
1659
1660 strncpy(tag.strGroupName, group.strGroupName, sizeof(tag.strGroupName));
1661 tag.iChannelUniqueId = myChannel.iUniqueId;
1662 tag.iChannelNumber = myChannel.iChannelNumber;
1663
1664 XBMC->Log(LOG_DEBUG, "%s - add channel %s (%d) to group '%s' channel number %d",
1665 __FUNCTION__, myChannel.strChannelName.c_str(), tag.iChannelUniqueId, group.strGroupName, myChannel.iChannelNumber);
1666
1667 PVR->TransferChannelGroupMember(handle, &tag);
1668 }
1669 }
1670 return PVR_ERROR_NO_ERROR;
1671 }
1672
1673 const char* Vu::GetLiveStreamURL(const PVR_CHANNEL &channelinfo)
1674 {
1675 SwitchChannel(channelinfo);
1676
1677 return m_channels.at(channelinfo.iUniqueId-1).strStreamURL.c_str();
1678 }
1679
1680 bool Vu::OpenLiveStream(const PVR_CHANNEL &channelinfo)
1681 {
1682 XBMC->Log(LOG_INFO, "%s channel '%u'", __FUNCTION__, channelinfo.iUniqueId);
1683
1684 if ((int)channelinfo.iUniqueId == m_iCurrentChannel)
1685 return true;
1686
1687 return SwitchChannel(channelinfo);
1688 }
1689
1690 void Vu::CloseLiveStream(void)
1691 {
1692 m_iCurrentChannel = -1;
1693 }
1694
1695 int Vu::ReadLiveStream(unsigned char *pBuffer, unsigned int iBufferSize)
1696 {
1697 return 0;
1698 }
1699
1700 long long Vu::SeekLiveStream(long long iPosition, int iWhence /* = SEEK_SET */)
1701 {
1702 return 0;
1703 }
1704
1705 long long Vu::PositionLiveStream(void)
1706 {
1707 return 0;
1708 }
1709
1710 long long Vu::LengthLiveStream(void)
1711 {
1712 return 0;
1713 }
1714
1715 bool Vu::SwitchChannel(const PVR_CHANNEL &channel)
1716 {
1717 XBMC->Log(LOG_DEBUG, "%s Switching channels", __FUNCTION__);
1718
1719 if ((int)channel.iUniqueId == m_iCurrentChannel)
1720 return true;
1721
1722 m_iCurrentChannel = (int)channel.iUniqueId;
1723
1724 if (g_bZap)
1725 {
1726 // Zapping is set to true, so send the zapping command to the PVR box
1727 CStdString strServiceReference = m_channels.at(channel.iUniqueId-1).strServiceReference.c_str();
1728
1729 CStdString strTmp;
1730 strTmp.Format("web/zap?sRef=%s", URLEncodeInline(strServiceReference));
1731
1732 CStdString strResult;
1733 if(!SendSimpleCommand(strTmp, strResult))
1734 return false;
1735
1736 }
1737 return true;
1738 }
1739
1740 void Vu::SendPowerstate()
1741 {
1742 if (!g_bSetPowerstate)
1743 return;
1744
1745 CLockObject lock(m_mutex);
1746 CStdString strTmp;
1747 strTmp.Format("web/powerstate?newstate=1");
1748
1749 CStdString strResult;
1750 SendSimpleCommand(strTmp, strResult, true);
1751 }
1752
1753 bool Vu::GetDeviceInfo()
1754 {
1755 CStdString url;
1756 url.Format("%s%s", m_strURL.c_str(), "web/deviceinfo");
1757
1758 CStdString strXML;
1759 strXML = GetHttpXML(url);
1760
1761 TiXmlDocument xmlDoc;
1762 if (!xmlDoc.Parse(strXML))
1763 {
1764 XBMC->Log(LOG_DEBUG, "Unable to parse XML: %s at line %d", xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
1765 return false;
1766 }
1767
1768 TiXmlHandle hDoc(&xmlDoc);
1769 TiXmlElement* pElem;
1770 TiXmlHandle hRoot(0);
1771
1772 pElem = hDoc.FirstChildElement("e2deviceinfo").Element();
1773
1774 if (!pElem)
1775 {
1776 XBMC->Log(LOG_ERROR, "%s Could not find <e2deviceinfo> element!", __FUNCTION__);
1777 return false;
1778 }
1779
1780 CStdString strTmp;;
1781
1782 XBMC->Log(LOG_NOTICE, "%s - DeviceInfo", __FUNCTION__);
1783
1784 // Get EnigmaVersion
1785 if (!XMLUtils::GetString(pElem, "e2enigmaversion", strTmp))
1786 {
1787 XBMC->Log(LOG_ERROR, "%s Could not parse e2enigmaversion from result!", __FUNCTION__);
1788 return false;
1789 }
1790 m_strEnigmaVersion = strTmp.c_str();
1791 XBMC->Log(LOG_NOTICE, "%s - E2EnigmaVersion: %s", __FUNCTION__, m_strEnigmaVersion.c_str());
1792
1793 // Get ImageVersion
1794 if (!XMLUtils::GetString(pElem, "e2imageversion", strTmp))
1795 {
1796 XBMC->Log(LOG_ERROR, "%s Could not parse e2imageversion from result!", __FUNCTION__);
1797 return false;
1798 }
1799 m_strImageVersion = strTmp.c_str();
1800 XBMC->Log(LOG_NOTICE, "%s - E2ImageVersion: %s", __FUNCTION__, m_strImageVersion.c_str());
1801
1802 // Get WebIfVersion
1803 if (!XMLUtils::GetString(pElem, "e2webifversion", strTmp))
1804 {
1805 XBMC->Log(LOG_ERROR, "%s Could not parse e2webifversion from result!", __FUNCTION__);
1806 return false;
1807 }
1808 m_strWebIfVersion = strTmp.c_str();
1809 XBMC->Log(LOG_NOTICE, "%s - E2WebIfVersion: %s", __FUNCTION__, m_strWebIfVersion.c_str());
1810
1811 // Get DeviceName
1812 if (!XMLUtils::GetString(pElem, "e2devicename", strTmp))
1813 {
1814 XBMC->Log(LOG_ERROR, "%s Could not parse e2devicename from result!", __FUNCTION__);
1815 return false;
1816 }
1817 m_strServerName = strTmp.c_str();
1818 XBMC->Log(LOG_NOTICE, "%s - E2DeviceName: %s", __FUNCTION__, m_strServerName.c_str());
1819
1820 return true;
1821 }
1822
1823 const char SAFE[256] =
1824 {
1825 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
1826 /* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1827 /* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1828 /* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1829 /* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
1830
1831 /* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
1832 /* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
1833 /* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
1834 /* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
1835
1836 /* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1837 /* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1838 /* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1839 /* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1840
1841 /* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1842 /* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1843 /* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
1844 /* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
1845 };
1846
1847
1848 CStdString Vu::URLEncodeInline(const CStdString& sSrc)
1849 {
1850 const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
1851 const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
1852 const int SRC_LEN = sSrc.length();
1853 unsigned char * const pStart = new unsigned char[SRC_LEN * 3];
1854 unsigned char * pEnd = pStart;
1855 const unsigned char * const SRC_END = pSrc + SRC_LEN;
1856
1857 for (; pSrc < SRC_END; ++pSrc)
1858 {
1859 if (SAFE[*pSrc])
1860 *pEnd++ = *pSrc;
1861 else
1862 {
1863 // escape this char
1864 *pEnd++ = '%';
1865 *pEnd++ = DEC2HEX[*pSrc >> 4];
1866 *pEnd++ = DEC2HEX[*pSrc & 0x0F];
1867 }
1868 }
1869
1870 std::string sResult((char *)pStart, (char *)pEnd);
1871 delete [] pStart;
1872 return sResult;
1873 }
1874
1875 int Vu::GetRecordingIndex(CStdString strStreamURL)
1876 {
1877 for (unsigned int i = 0;i<m_recordings.size(); i++)
1878 {
1879 if (!strStreamURL.compare(m_recordings[i].strStreamURL))
1880 return i;
1881 }
1882 return -1;
1883 }
1884
+0
-236
src/VuData.h less more
0 #pragma once
1 /*
2 * Copyright (C) 2005-2015 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "p8-platform/util/StdString.h"
24 #include "client.h"
25 #include "p8-platform/threads/threads.h"
26 #include "tinyxml.h"
27
28 #define CHANNELDATAVERSION 2
29
30 class CCurlFile
31 {
32 public:
33 CCurlFile(void) {};
34 ~CCurlFile(void) {};
35
36 bool Get(const std::string &strURL, std::string &strResult);
37 };
38
39
40 typedef enum VU_UPDATE_STATE
41 {
42 VU_UPDATE_STATE_NONE,
43 VU_UPDATE_STATE_FOUND,
44 VU_UPDATE_STATE_UPDATED,
45 VU_UPDATE_STATE_NEW
46 } VU_UPDATE_STATE;
47
48 struct VuEPGEntry
49 {
50 int iEventId;
51 std::string strServiceReference;
52 std::string strTitle;
53 int iChannelId;
54 time_t startTime;
55 time_t endTime;
56 std::string strPlotOutline;
57 std::string strPlot;
58 };
59
60 struct VuChannelGroup
61 {
62 std::string strServiceReference;
63 std::string strGroupName;
64 int iGroupState;
65 std::vector<VuEPGEntry> initialEPG;
66 };
67
68 struct VuChannel
69 {
70 bool bRadio;
71 bool bInitialEPG;
72 int iUniqueId;
73 int iChannelNumber;
74 std::string strGroupName;
75 std::string strChannelName;
76 std::string strServiceReference;
77 std::string strStreamURL;
78 std::string strIconPath;
79 };
80
81 struct VuTimer
82 {
83 std::string strTitle;
84 std::string strPlot;
85 int iChannelId;
86 time_t startTime;
87 time_t endTime;
88 int iWeekdays;
89 unsigned int iEpgID;
90 PVR_TIMER_STATE state;
91 int iUpdateState;
92 unsigned int iClientIndex;
93
94 VuTimer()
95 {
96 iUpdateState = VU_UPDATE_STATE_NEW;
97 }
98
99 bool like(const VuTimer &right) const
100 {
101 bool bChanged = true;
102 bChanged = bChanged && (startTime == right.startTime);
103 bChanged = bChanged && (endTime == right.endTime);
104 bChanged = bChanged && (iChannelId == right.iChannelId);
105 bChanged = bChanged && (iWeekdays == right.iWeekdays);
106 bChanged = bChanged && (iEpgID == right.iEpgID);
107
108 return bChanged;
109 }
110
111 bool operator==(const VuTimer &right) const
112 {
113 bool bChanged = true;
114 bChanged = bChanged && (startTime == right.startTime);
115 bChanged = bChanged && (endTime == right.endTime);
116 bChanged = bChanged && (iChannelId == right.iChannelId);
117 bChanged = bChanged && (iWeekdays == right.iWeekdays);
118 bChanged = bChanged && (iEpgID == right.iEpgID);
119 bChanged = bChanged && (state == right.state);
120 bChanged = bChanged && (! strTitle.compare(right.strTitle));
121 bChanged = bChanged && (! strPlot.compare(right.strPlot));
122
123 return bChanged;
124 }
125 };
126
127 struct VuRecording
128 {
129 std::string strRecordingId;
130 time_t startTime;
131 int iDuration;
132 int iLastPlayedPosition;
133 std::string strTitle;
134 std::string strStreamURL;
135 std::string strPlot;
136 std::string strPlotOutline;
137 std::string strChannelName;
138 std::string strDirectory;
139 std::string strIconPath;
140 };
141
142 class Vu : public P8PLATFORM::CThread
143 {
144 private:
145
146 // members
147 void *m_writeHandle;
148 void *m_readHandle;
149 std::string m_strEnigmaVersion;
150 std::string m_strImageVersion;
151 std::string m_strWebIfVersion;
152 bool m_bIsConnected;
153 std::string m_strServerName;
154 std::string m_strURL;
155 int m_iNumRecordings;
156 int m_iNumChannelGroups;
157 int m_iCurrentChannel;
158 unsigned int m_iUpdateTimer;
159 std::vector<VuChannel> m_channels;
160 std::vector<VuTimer> m_timers;
161 std::vector<VuRecording> m_recordings;
162 std::vector<VuChannelGroup> m_groups;
163 std::vector<std::string> m_locations;
164 unsigned int m_iClientIndexCounter;
165
166 P8PLATFORM::CMutex m_mutex;
167 P8PLATFORM::CCondition<bool> m_started;
168
169 bool m_bUpdating;
170
171 // functions
172 CStdString GetHttpXML(CStdString& url);
173 int GetChannelNumber(CStdString strServiceReference);
174 CStdString GetChannelIconPath(CStdString strChannelName);
175 bool SendSimpleCommand(const CStdString& strCommandURL, CStdString& strResult, bool bIgnoreResult = false);
176 CStdString GetGroupServiceReference(CStdString strGroupName);
177 bool LoadChannels(CStdString strServerReference, CStdString strGroupName);
178 bool LoadChannels();
179 bool LoadChannelGroups();
180 bool LoadLocations();
181 std::vector<VuTimer> LoadTimers();
182 void TimerUpdates();
183 bool GetDeviceInfo();
184 int GetRecordingIndex(CStdString);
185
186 // helper functions
187 static long TimeStringToSeconds(const CStdString &timeString);
188 static int SplitString(const CStdString& input, const CStdString& delimiter, CStdStringArray &results, unsigned int iMaxStrings = 0);
189 bool CheckForGroupUpdate();
190 bool CheckForChannelUpdate();
191 std::string& Escape(std::string &s, std::string from, std::string to);
192 CStdString URLEncodeInline(const CStdString& sSrc);
193 bool IsInRecordingFolder(CStdString);
194 void TransferRecordings(ADDON_HANDLE handle);
195
196 protected:
197 virtual void *Process(void);
198
199 public:
200 Vu(void);
201 ~Vu();
202
203 const char * GetServerName();
204 bool IsConnected();
205 int GetChannelsAmount(void);
206 PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio);
207 PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd);
208 PVR_ERROR GetInitialEPGForChannel(ADDON_HANDLE handle, const VuChannel &channel, time_t iStart, time_t iEnd);
209 bool GetInitialEPGForGroup(VuChannelGroup &group);
210 int GetTimersAmount(void);
211 PVR_ERROR GetTimers(ADDON_HANDLE handle);
212 PVR_ERROR AddTimer(const PVR_TIMER &timer);
213 PVR_ERROR UpdateTimer(const PVR_TIMER &timer);
214 PVR_ERROR DeleteTimer(const PVR_TIMER &timer);
215 bool GetRecordingFromLocation(CStdString strRecordingFolder);
216 unsigned int GetRecordingsAmount();
217 PVR_ERROR GetRecordings(ADDON_HANDLE handle);
218 PVR_ERROR DeleteRecording(const PVR_RECORDING &recinfo);
219 unsigned int GetNumChannelGroups(void);
220 PVR_ERROR GetChannelGroups(ADDON_HANDLE handle);
221 PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group);
222 const char* GetLiveStreamURL(const PVR_CHANNEL &channelinfo);
223 bool OpenLiveStream(const PVR_CHANNEL &channelinfo);
224 void CloseLiveStream();
225 void SendPowerstate();
226 bool SwitchChannel(const PVR_CHANNEL &channel);
227 bool Open();
228 void Action();
229 int ReadLiveStream(unsigned char *pBuffer, unsigned int iBufferSize);
230 long long SeekLiveStream(long long iPosition, int iWhence /* = SEEK_SET */);
231 long long PositionLiveStream(void);
232 long long LengthLiveStream(void);
233 bool m_bInitialEPG;
234 };
235
00 /*
1 * Copyright (C) 2005-2015 Team XBMC
1 * Copyright (C) 2005-2019 Team XBMC
22 * http://xbmc.org
33 *
44 * This Program is free software; you can redistribute it and/or modify
2020 */
2121
2222 #include "client.h"
23 #include "xbmc_pvr_dll.h"
23
24 #include "Enigma2.h"
25 #include "enigma2/RecordingReader.h"
26 #include "enigma2/Settings.h"
27 #include "enigma2/StreamReader.h"
28 #include "enigma2/TimeshiftBuffer.h"
29 #include "enigma2/utilities/LocalizedString.h"
30 #include "enigma2/utilities/Logger.h"
31 #include "kodi/xbmc_pvr_dll.h"
32 #include "p8-platform/util/util.h"
33
2434 #include <stdlib.h>
25 #include "VuData.h"
26 #include "p8-platform/util/util.h"
27
28 using namespace std;
35
36 #include <p8-platform/util/StringUtils.h>
37
2938 using namespace ADDON;
30
31 bool m_bCreated = false;
32 ADDON_STATUS m_CurStatus = ADDON_STATUS_UNKNOWN;
33 //int g_iClientId = -1;
34
35 /* User adjustable settings are saved here.
36 * Default values are defined inside client.h
37 * and exported to the other source files.
38 */
39 std::string g_strHostname = DEFAULT_HOST;
40 int g_iConnectTimeout = DEFAULT_CONNECT_TIMEOUT;
41 int g_iPortStream = DEFAULT_STREAM_PORT;
42 int g_iPortWeb = DEFAULT_WEB_PORT;
43 int g_iUpdateInterval = DEFAULT_UPDATE_INTERVAL;
44 std::string g_strUsername = "";
45 std::string g_strRecordingPath = "";
46 std::string g_strPassword = "";
47 std::string g_szUserPath = "";
48 std::string g_strIconPath = "";
49 bool g_bAutomaticTimerlistCleanup = false;
50 bool g_bZap = false;
51 bool g_bOnlyCurrentLocation = false;
52 bool g_bSetPowerstate = false;
53 bool g_bOnlyOneGroup = false;
54 bool g_bOnlinePicons = true;
55 bool g_bUseSecureHTTP = false;
56 std::string g_strOneGroup = "";
57 std::string g_szClientPath = "";
58
59 CHelper_libXBMC_addon *XBMC = NULL;
60 CHelper_libXBMC_pvr *PVR = NULL;
61 Vu *VuData = NULL;
62
63 extern "C" {
64
65 void ADDON_ReadSettings(void)
66 {
67 /* read setting "host" from settings.xml */
68 char * buffer;
69 buffer = (char*) malloc (1024);
70 buffer[0] = 0; /* Set the end of string */
71
72 if (XBMC->GetSetting("host", buffer))
73 g_strHostname = buffer;
74 else
75 g_strHostname = DEFAULT_HOST;
76 buffer[0] = 0; /* Set the end of string */
77
78 /* read setting "user" from settings.xml */
79 if (XBMC->GetSetting("user", buffer))
80 g_strUsername = buffer;
81 else
82 g_strUsername = "";
83 buffer[0] = 0; /* Set the end of string */
84
85 /* read setting "recordingpath" from settings.xml */
86 if (XBMC->GetSetting("recordingpath", buffer))
87 g_strRecordingPath = buffer;
88 else
89 g_strRecordingPath = "";
90 buffer[0] = 0; /* Set the end of string */
91
92 /* read setting "pass" from settings.xml */
93 if (XBMC->GetSetting("pass", buffer))
94 g_strPassword = buffer;
95 else
96 g_strPassword = "";
97
98 /* read setting "use_secure" from settings.xml */
99 if (!XBMC->GetSetting("use_secure", &g_bUseSecureHTTP))
100 g_bUseSecureHTTP = false;
101
102 /* read setting "streamport" from settings.xml */
103 if (!XBMC->GetSetting("streamport", &g_iPortStream))
104 g_iPortStream = DEFAULT_STREAM_PORT;
105
106 /* read setting "webport" from settings.xml */
107 if (!XBMC->GetSetting("webport", &g_iPortWeb))
108 g_iPortWeb = DEFAULT_WEB_PORT;
109
110 /* read setting "onlinepicons" from settings.xml */
111 if (!XBMC->GetSetting("onlinepicons", &g_bOnlinePicons))
112 g_bOnlinePicons = true;
113
114 /* read setting "onlycurrent" from settings.xml */
115 if (!XBMC->GetSetting("onlycurrent", &g_bOnlyCurrentLocation))
116 g_bOnlyCurrentLocation = false;
117
118 /* read setting "setpowerstate" from settings.xml */
119 if (!XBMC->GetSetting("setpowerstate", &g_bSetPowerstate))
120 g_bSetPowerstate = false;
121
122 /* read setting "zap" from settings.xml */
123 if (!XBMC->GetSetting("zap", &g_bZap))
124 g_bZap = false;
125
126 /* read setting "onlyonegroup" from settings.xml */
127 if (!XBMC->GetSetting("onlyonegroup", &g_bOnlyOneGroup))
128 g_bOnlyOneGroup = false;
129
130 /* read setting "onegroup" from settings.xml */
131 if (XBMC->GetSetting("onegroup", buffer))
132 g_strOneGroup = buffer;
133 else
134 g_strOneGroup = "";
135
136 /* read setting "timerlistcleanup" from settings.xml */
137 if (!XBMC->GetSetting("timerlistcleanup", &g_bAutomaticTimerlistCleanup))
138 g_bAutomaticTimerlistCleanup = false;
139
140 /* read setting "updateint" from settings.xml */
141 if (!XBMC->GetSetting("updateint", &g_iUpdateInterval))
142 g_iConnectTimeout = DEFAULT_UPDATE_INTERVAL;
143
144 /* read setting "iconpath" from settings.xml */
145 if (XBMC->GetSetting("iconpath", buffer))
146 g_strIconPath = buffer;
147 else
148 g_strIconPath = "";
149
150 free (buffer);
151 }
39 using namespace enigma2;
40 using namespace enigma2::data;
41 using namespace enigma2::utilities;
42
43 bool m_created = false;
44 ADDON_STATUS m_currentStatus = ADDON_STATUS_UNKNOWN;
45 IStreamReader* streamReader = nullptr;
46 int m_streamReadChunkSize = 64;
47 RecordingReader* recordingReader = nullptr;
48 Settings& settings = Settings::GetInstance();
49
50 CHelper_libXBMC_addon* XBMC = nullptr;
51 CHelper_libXBMC_pvr* PVR = nullptr;
52 Enigma2* enigma = nullptr;
53
54 extern "C"
55 {
56
57 /***************************************************************************
58 * Addon Calls
59 **************************************************************************/
15260
15361 ADDON_STATUS ADDON_Create(void* hdl, void* props)
15462 {
15563 if (!hdl || !props)
156 return ADDON_STATUS_UNKNOWN;
157
158 PVR_PROPERTIES* pvrprops = (PVR_PROPERTIES*)props;
64 return m_currentStatus;
65
66 PVR_PROPERTIES* pvrProps = reinterpret_cast<PVR_PROPERTIES*>(props);
15967
16068 XBMC = new CHelper_libXBMC_addon;
16169 if (!XBMC->RegisterMe(hdl))
16270 {
16371 SAFE_DELETE(XBMC);
164 return ADDON_STATUS_PERMANENT_FAILURE;
72 m_currentStatus = ADDON_STATUS_PERMANENT_FAILURE;
73 return m_currentStatus;
16574 }
16675
16776 PVR = new CHelper_libXBMC_pvr;
16978 {
17079 SAFE_DELETE(PVR);
17180 SAFE_DELETE(XBMC);
172 return ADDON_STATUS_PERMANENT_FAILURE;
173 }
174
175 XBMC->Log(LOG_DEBUG, "%s - Creating VU+ PVR-Client", __FUNCTION__);
176
177 m_CurStatus = ADDON_STATUS_UNKNOWN;
178 //g_iClientId = pvrprops->iClientId; //removed from Frodo PVR API
179 g_szUserPath = pvrprops->strUserPath;
180 g_szClientPath = pvrprops->strClientPath;
181
182 ADDON_ReadSettings();
183
184 VuData = new Vu;
185 if (!VuData->Open())
186 {
187 SAFE_DELETE(VuData);
188 SAFE_DELETE(PVR);
189 SAFE_DELETE(XBMC);
190 m_CurStatus = ADDON_STATUS_LOST_CONNECTION;
191 return m_CurStatus;
192 }
193
194 m_CurStatus = ADDON_STATUS_OK;
195 m_bCreated = true;
196 return m_CurStatus;
81 m_currentStatus = ADDON_STATUS_PERMANENT_FAILURE;
82 return m_currentStatus;
83 }
84
85 Logger::Log(LEVEL_DEBUG, "%s - Creating VU+ PVR-Client", __FUNCTION__);
86
87 m_currentStatus = ADDON_STATUS_UNKNOWN;
88
89 /* Configure the logger */
90 Logger::GetInstance().SetImplementation([](LogLevel level, const char* message)
91 {
92 /* Don't log trace messages unless told so */
93 if (level == LogLevel::LEVEL_TRACE && !Settings::GetInstance().GetTraceDebug())
94 return;
95
96 /* Convert the log level */
97 addon_log_t addonLevel;
98
99 switch (level)
100 {
101 case LogLevel::LEVEL_ERROR:
102 addonLevel = addon_log_t::LOG_ERROR;
103 break;
104 case LogLevel::LEVEL_INFO:
105 addonLevel = addon_log_t::LOG_INFO;
106 break;
107 case LogLevel::LEVEL_NOTICE:
108 addonLevel = addon_log_t::LOG_NOTICE;
109 break;
110 default:
111 addonLevel = addon_log_t::LOG_DEBUG;
112 }
113
114 if (addonLevel == addon_log_t::LOG_DEBUG && Settings::GetInstance().GetNoDebug())
115 return;
116
117 if (addonLevel == addon_log_t::LOG_DEBUG && Settings::GetInstance().GetDebugNormal())
118 addonLevel = addon_log_t::LOG_NOTICE;
119
120 XBMC->Log(addonLevel, "%s", message);
121 });
122
123 Logger::GetInstance().SetPrefix("pvr.vuplus");
124
125 Logger::Log(LogLevel::LEVEL_INFO, "%s starting PVR client...", __FUNCTION__);
126
127 settings.ReadFromAddon();
128
129 enigma = new Enigma2(pvrProps);
130 enigma->Start();
131
132 m_currentStatus = ADDON_STATUS_OK;
133 m_created = true;
134 return m_currentStatus;
197135 }
198136
199137 ADDON_STATUS ADDON_GetStatus()
200138 {
201 /* check whether we're still connected */
202 if (m_CurStatus == ADDON_STATUS_OK && !VuData->IsConnected())
203 m_CurStatus = ADDON_STATUS_LOST_CONNECTION;
204
205 return m_CurStatus;
139 return m_currentStatus;
206140 }
207141
208142 void ADDON_Destroy()
209143 {
210 if (m_bCreated)
211 {
212 m_bCreated = false;
213 }
214
215 if (VuData)
216 {
217 VuData->SendPowerstate();
218 }
219
220 SAFE_DELETE(VuData);
144 if (m_created)
145 {
146 m_created = false;
147 }
148
149 if (enigma)
150 {
151 enigma->SendPowerstate();
152 }
153
154 SAFE_DELETE(enigma);
221155 SAFE_DELETE(PVR);
222156 SAFE_DELETE(XBMC);
223157
224 m_CurStatus = ADDON_STATUS_UNKNOWN;
225 }
226
227 bool ADDON_HasSettings()
228 {
229 return true;
230 }
231
232 unsigned int ADDON_GetSettings(ADDON_StructSetting ***sSet)
233 {
234 return 0;
235 }
236
237 ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue)
238 {
239 string str = settingName;
240 if (str == "host")
241 {
242 string tmp_sHostname;
243 XBMC->Log(LOG_INFO, "%s - Changed Setting 'host' from %s to %s", __FUNCTION__, g_strHostname.c_str(), (const char*) settingValue);
244 tmp_sHostname = g_strHostname;
245 g_strHostname = (const char*) settingValue;
246 if (tmp_sHostname != g_strHostname)
247 return ADDON_STATUS_NEED_RESTART;
248 }
249 else if (str == "user")
250 {
251 string tmp_sUsername = g_strUsername;
252 g_strUsername = (const char*) settingValue;
253 if (tmp_sUsername != g_strUsername)
254 {
255 XBMC->Log(LOG_INFO, "%s - Changed Setting 'user'", __FUNCTION__);
256 return ADDON_STATUS_NEED_RESTART;
257 }
258 }
259 else if (str == "pass")
260 {
261 string tmp_sPassword = g_strPassword;
262 g_strPassword = (const char*) settingValue;
263 if (tmp_sPassword != g_strPassword)
264 {
265 XBMC->Log(LOG_INFO, "%s - Changed Setting 'pass'", __FUNCTION__);
266 return ADDON_STATUS_NEED_RESTART;
267 }
268 }
269 else if (str == "streamport")
270 {
271 int iNewValue = *(int*) settingValue + 1;
272 if (g_iPortStream != iNewValue)
273 {
274 XBMC->Log(LOG_INFO, "%s - Changed Setting 'streamport' from %u to %u", __FUNCTION__, g_iPortStream, iNewValue);
275 g_iPortStream = iNewValue;
276 return ADDON_STATUS_OK;
277 }
278 }
279 else if (str == "webport")
280 {
281 int iNewValue = *(int*) settingValue + 1;
282 if (g_iPortWeb != iNewValue)
283 {
284 XBMC->Log(LOG_INFO, "%s - Changed Setting 'webport' from %u to %u", __FUNCTION__, g_iPortWeb, iNewValue);
285 g_iPortWeb = iNewValue;
286 return ADDON_STATUS_OK;
287 }
288 }
289 return ADDON_STATUS_OK;
290 }
291
292 void ADDON_Stop()
293 {
294 }
295
296 void ADDON_FreeSettings()
297 {
158 m_currentStatus = ADDON_STATUS_UNKNOWN;
159 }
160
161 ADDON_STATUS ADDON_SetSetting(const char* settingName, const void* settingValue)
162 {
163 if (!XBMC || !enigma)
164 return ADDON_STATUS_OK;
165
166 return settings.SetValue(settingName, settingValue);
298167 }
299168
300169 /***********************************************************
303172
304173 void OnSystemSleep()
305174 {
175 if (!enigma || !enigma->IsConnected())
176 return;
177
178 if (enigma)
179 enigma->OnSleep();
306180 }
307181
308182 void OnSystemWake()
309183 {
310 }
311
312 void OnPowerSavingActivated()
313 {
314 }
315
316 void OnPowerSavingDeactivated()
317 {
318 }
319
320 const char* GetPVRAPIVersion(void)
321 {
322 static const char *strApiVersion = XBMC_PVR_API_VERSION;
323 return strApiVersion;
324 }
325
326 const char* GetMininumPVRAPIVersion(void)
327 {
328 static const char *strMinApiVersion = XBMC_PVR_MIN_API_VERSION;
329 return strMinApiVersion;
330 }
331
332 const char* GetGUIAPIVersion(void)
333 {
334 return ""; // GUI API not used
335 }
336
337 const char* GetMininumGUIAPIVersion(void)
338 {
339 return ""; // GUI API not used
340 }
184 if (!enigma || !enigma->IsConnected())
185 return;
186
187 if (enigma)
188 enigma->OnWake();
189 }
190
191 void OnPowerSavingActivated() {}
192
193 void OnPowerSavingDeactivated() {}
341194
342195 PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES* pCapabilities)
343196 {
344197 pCapabilities->bSupportsEPG = true;
198 pCapabilities->bSupportsEPGEdl = false;
345199 pCapabilities->bSupportsTV = true;
346200 pCapabilities->bSupportsRadio = true;
347201 pCapabilities->bSupportsRecordings = true;
348 pCapabilities->bSupportsRecordingsUndelete = false;
202 pCapabilities->bSupportsRecordingsUndelete = true;
349203 pCapabilities->bSupportsTimers = true;
350204 pCapabilities->bSupportsChannelGroups = true;
351205 pCapabilities->bSupportsChannelScan = false;
206 pCapabilities->bSupportsChannelSettings = false;
352207 pCapabilities->bHandlesInputStream = true;
353208 pCapabilities->bHandlesDemuxing = false;
354 pCapabilities->bSupportsLastPlayedPosition = false;
209 pCapabilities->bSupportsRecordingPlayCount = settings.SupportsEditingRecordings() && settings.GetStoreRecordingLastPlayedAndCount();
210 pCapabilities->bSupportsLastPlayedPosition = settings.SupportsEditingRecordings() && settings.GetStoreRecordingLastPlayedAndCount();
211 pCapabilities->bSupportsRecordingEdl = true;
212 pCapabilities->bSupportsRecordingsRename = settings.SupportsEditingRecordings();
213 pCapabilities->bSupportsRecordingsLifetimeChange = false;
214 pCapabilities->bSupportsDescrambleInfo = false;
215 pCapabilities->bSupportsAsyncEPGTransfer = false;
355216
356217 return PVR_ERROR_NO_ERROR;
357218 }
358219
359 const char *GetBackendName(void)
360 {
361 static const char *strBackendName = VuData ? VuData->GetServerName() : "unknown";
362 return strBackendName;
363 }
364
365 const char *GetBackendVersion(void)
366 {
367 static const char *strBackendVersion = "UNKNOWN";
368 return strBackendVersion;
369 }
370
371 static CStdString strConnectionString;
372
373 const char *GetConnectionString(void)
374 {
375 if (VuData)
376 strConnectionString.Format("%s%s", g_strHostname.c_str(), VuData->IsConnected() ? "" : " (Not connected!)");
220 const char* GetBackendName(void)
221 {
222 static const char* backendName = enigma ? enigma->GetServerName() : LocalizedString(30081).c_str(); //unknown
223 return backendName;
224 }
225
226 const char* GetBackendVersion(void)
227 {
228 static const char* backendVersion = enigma ? enigma->GetServerVersion() : LocalizedString(30081).c_str(); //unknown
229 return backendVersion;
230 }
231
232 static std::string connectionString;
233
234 const char* GetConnectionString(void)
235 {
236 if (enigma)
237 connectionString = StringUtils::Format("%s%s", settings.GetHostname().c_str(), enigma->IsConnected() ? "" : LocalizedString(30082).c_str()); // (Not connected!)
377238 else
378 strConnectionString.Format("%s (addon error!)", g_strHostname.c_str());
379 return strConnectionString.c_str();
380 }
381
382 const char *GetBackendHostname(void)
383 {
384 return g_strHostname.c_str();
385 }
386
387 PVR_ERROR GetDriveSpace(long long *iTotal, long long *iUsed)
388 {
389 return PVR_ERROR_SERVER_ERROR;
390 }
391
392 PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL &channel, time_t iStart, time_t iEnd)
393 {
394 if (!VuData || !VuData->IsConnected())
395 return PVR_ERROR_SERVER_ERROR;
396
397 return VuData->GetEPGForChannel(handle, channel, iStart, iEnd);
239 connectionString = StringUtils::Format("%s (%s!)", settings.GetHostname().c_str(), LocalizedString(30083).c_str()); //addon error
240 return connectionString.c_str();
241 }
242
243 const char* GetBackendHostname(void)
244 {
245 return settings.GetHostname().c_str();
246 }
247
248 PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed)
249 {
250 if (!enigma || !enigma->IsConnected())
251 return PVR_ERROR_SERVER_ERROR;
252
253 return enigma->GetDriveSpace(iTotal, iUsed);
254 }
255
256
257 PVR_ERROR SignalStatus(PVR_SIGNAL_STATUS& signalStatus)
258 {
259 // SNR = Signal to Noise Ratio - which means signal quality
260 // AGC = Automatic Gain Control - which means signal strength
261 // BER = Bit Error Rate - which shows the error rate of the signal.
262 // UNC = There is not notion of UNC on enigma devices
263
264 // So, SNR and AGC should be as high as possible.
265 // BER should be as low as possible, like 0. It can be higher, if your other values are higher.
266
267 enigma->GetTunerSignal(signalStatus);
268
269 Logger::Log(LEVEL_DEBUG, "%s Tuner Details - name: %s, status: %s", __FUNCTION__, signalStatus.strAdapterName, signalStatus.strAdapterStatus);
270 Logger::Log(LEVEL_DEBUG, "%s Service Details - service: %s, provider: %s", __FUNCTION__, signalStatus.strServiceName, signalStatus.strProviderName);
271 // For some reason the iSNR and iSignal values need to multiplied by 655!
272 Logger::Log(LEVEL_DEBUG, "%s Signal - snrPercent: %d, ber: %u, signal strength: %d", __FUNCTION__, signalStatus.iSNR / 655, signalStatus.iBER, signalStatus.iSignal / 655);
273
274 return PVR_ERROR_NO_ERROR;
275 }
276
277 /***************************************************************************
278 * ChannelGroups
279 **************************************************************************/
280
281 int GetChannelGroupsAmount(void)
282 {
283 if (!enigma || !enigma->IsConnected())
284 return 0;
285
286 return enigma->GetNumChannelGroups();
287 }
288
289 PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio)
290 {
291 if (!enigma || !enigma->IsConnected())
292 return PVR_ERROR_SERVER_ERROR;
293
294 return enigma->GetChannelGroups(handle, bRadio);
295 }
296
297 PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP& group)
298 {
299 if (!enigma || !enigma->IsConnected())
300 return PVR_ERROR_SERVER_ERROR;
301
302 return enigma->GetChannelGroupMembers(handle, group);
303 }
304
305 /***************************************************************************
306 * EPG and Channels
307 **************************************************************************/
308
309 PVR_ERROR SetEPGTimeFrame(int epgMaxDays)
310 {
311 if (!enigma || !enigma->IsConnected())
312 return PVR_ERROR_SERVER_ERROR;
313
314 enigma->SetEPGTimeFrame(epgMaxDays);
315
316 return PVR_ERROR_NO_ERROR;
317 }
318
319 PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL& channel, time_t iStart, time_t iEnd)
320 {
321 if (!enigma || !enigma->IsConnected())
322 return PVR_ERROR_SERVER_ERROR;
323
324 return enigma->GetEPGForChannel(handle, channel, iStart, iEnd);
398325 }
399326
400327 int GetChannelsAmount(void)
401328 {
402 if (!VuData || !VuData->IsConnected())
329 if (!enigma || !enigma->IsConnected())
403330 return 0;
404331
405 return VuData->GetChannelsAmount();
332 return enigma->GetChannelsAmount();
406333 }
407334
408335 PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio)
409336 {
410 if (!VuData || !VuData->IsConnected())
411 return PVR_ERROR_SERVER_ERROR;
412
413 return VuData->GetChannels(handle, bRadio);
414 }
337 if (!enigma || !enigma->IsConnected())
338 return PVR_ERROR_SERVER_ERROR;
339
340 return enigma->GetChannels(handle, bRadio);
341 }
342
343 /***************************************************************************
344 * Live Streams
345 **************************************************************************/
346
347 PVR_ERROR GetChannelStreamProperties(const PVR_CHANNEL* channel, PVR_NAMED_VALUE* properties, unsigned int* iPropertiesCount)
348 {
349 if (!settings.SetStreamProgramID() && !enigma->IsIptvStream(*channel))
350 return PVR_ERROR_NOT_IMPLEMENTED;
351
352 //
353 // We only use this function to set the program number which comes with every Enigma2 channel. For providers that
354 // use MPTS it allows the FFMPEG Demux to identify the correct Program/PID.
355 //
356
357 if (!channel || !properties || !iPropertiesCount)
358 return PVR_ERROR_SERVER_ERROR;
359
360 if (*iPropertiesCount < 1)
361 return PVR_ERROR_INVALID_PARAMETERS;
362
363 if (!enigma || !enigma->IsConnected())
364 return PVR_ERROR_SERVER_ERROR;
365
366 *iPropertiesCount = 0;
367
368 if (enigma->IsIptvStream(*channel))
369 {
370 strncpy(properties[0].strName, PVR_STREAM_PROPERTY_STREAMURL, sizeof(properties[0].strName) - 1);
371 strncpy(properties[0].strValue, enigma->GetLiveStreamURL(*channel).c_str(), sizeof(properties[0].strValue) - 1);
372 (*iPropertiesCount)++;
373 }
374
375 if (settings.SetStreamProgramID())
376 {
377 const std::string strStreamProgramNumber = std::to_string(enigma->GetChannelStreamProgramNumber(*channel));
378
379 Logger::Log(LEVEL_NOTICE, "%s - for channel: %s, set Stream Program Number to %s - %s", __FUNCTION__, channel->strChannelName, strStreamProgramNumber.c_str(), enigma->GetLiveStreamURL(*channel).c_str());
380
381 strncpy(properties[0].strName, "program", sizeof(properties[0].strName) - 1);
382 strncpy(properties[0].strValue, strStreamProgramNumber.c_str(), sizeof(properties[0].strValue) - 1);
383 (*iPropertiesCount)++;
384 }
385
386 return PVR_ERROR_NO_ERROR;
387 }
388
389 PVR_ERROR GetStreamReadChunkSize(int* chunksize)
390 {
391 if (!chunksize)
392 return PVR_ERROR_INVALID_PARAMETERS;
393 int size = settings.GetStreamReadChunkSizeKb();
394 if (!size)
395 return PVR_ERROR_NOT_IMPLEMENTED;
396 *chunksize = settings.GetStreamReadChunkSizeKb() * 1024;
397 return PVR_ERROR_NO_ERROR;
398 }
399
400 /* live stream functions */
401 bool OpenLiveStream(const PVR_CHANNEL& channel)
402 {
403 if (!enigma || !enigma->IsConnected())
404 return false;
405
406 if (!enigma->OpenLiveStream(channel))
407 return false;
408
409 /* queue a warning if the timeshift buffer path does not exist */
410 if (settings.GetTimeshift() != Timeshift::OFF && !settings.IsTimeshiftBufferPathValid())
411 XBMC->QueueNotification(QUEUE_ERROR, LocalizedString(30514).c_str());
412
413 const std::string streamURL = enigma->GetLiveStreamURL(channel);
414 streamReader = new StreamReader(streamURL, settings.GetReadTimeoutSecs());
415 if (settings.GetTimeshift() == Timeshift::ON_PLAYBACK)
416 streamReader = new TimeshiftBuffer(streamReader, settings.GetTimeshiftBufferPath(), settings.GetReadTimeoutSecs());
417
418 return streamReader->Start();
419 }
420
421 void CloseLiveStream(void)
422 {
423 if (enigma)
424 enigma->CloseLiveStream();
425 SAFE_DELETE(streamReader);
426 }
427
428 bool IsRealTimeStream()
429 {
430 return (streamReader) ? streamReader->IsRealTime() : false;
431 }
432
433 bool CanPauseStream(void)
434 {
435 if (!enigma || !enigma->IsConnected())
436 return false;
437
438 if (settings.GetTimeshift() != Timeshift::OFF && streamReader)
439 return (streamReader->IsTimeshifting() || settings.IsTimeshiftBufferPathValid());
440
441 return false;
442 }
443
444 bool CanSeekStream(void)
445 {
446 if (!enigma || !enigma->IsConnected())
447 return false;
448
449 return (settings.GetTimeshift() != Timeshift::OFF);
450 }
451
452 int ReadLiveStream(unsigned char* buffer, unsigned int size)
453 {
454 return (streamReader) ? streamReader->ReadData(buffer, size) : 0;
455 }
456
457 long long SeekLiveStream(long long position, int whence)
458 {
459 return (streamReader) ? streamReader->Seek(position, whence) : -1;
460 }
461
462 long long LengthLiveStream(void)
463 {
464 return (streamReader) ? streamReader->Length() : -1;
465 }
466
467 bool IsTimeshifting(void)
468 {
469 return (streamReader && streamReader->IsTimeshifting());
470 }
471
472 PVR_ERROR GetStreamTimes(PVR_STREAM_TIMES* times)
473 {
474 if (!times)
475 return PVR_ERROR_INVALID_PARAMETERS;
476
477 if (streamReader)
478 {
479 times->startTime = streamReader->TimeStart();
480 times->ptsStart = 0;
481 times->ptsBegin = 0;
482 times->ptsEnd = (!streamReader->IsTimeshifting()) ? 0
483 : (streamReader->TimeEnd() - streamReader->TimeStart()) * DVD_TIME_BASE;
484
485 return PVR_ERROR_NO_ERROR;
486 }
487 else if (recordingReader)
488 {
489 times->startTime = 0;
490 times->ptsStart = 0;
491 times->ptsBegin = 0;
492 times->ptsEnd = static_cast<int64_t>(recordingReader->CurrentDuration()) * DVD_TIME_BASE;
493
494 return PVR_ERROR_NO_ERROR;
495 }
496
497 return PVR_ERROR_NOT_IMPLEMENTED;
498 }
499
500 void PauseStream(bool paused)
501 {
502 if (!enigma || !enigma->IsConnected())
503 return;
504
505 /* start timeshift on pause */
506 if (paused && settings.GetTimeshift() == Timeshift::ON_PAUSE &&
507 streamReader && !streamReader->IsTimeshifting() &&
508 settings.IsTimeshiftBufferPathValid())
509 {
510 streamReader = new TimeshiftBuffer(streamReader, settings.GetTimeshiftBufferPath(), settings.GetReadTimeoutSecs());
511 (void)streamReader->Start();
512 }
513 }
514
515 /***************************************************************************
516 * Recordings
517 **************************************************************************/
415518
416519 int GetRecordingsAmount(bool deleted)
417520 {
418 if (!VuData || !VuData->IsConnected())
419 return PVR_ERROR_SERVER_ERROR;
420
421 return VuData->GetRecordingsAmount();
521 if (!enigma || !enigma->IsConnected())
522 return 0;
523
524 return enigma->GetRecordingsAmount(deleted);
422525 }
423526
424527 PVR_ERROR GetRecordings(ADDON_HANDLE handle, bool deleted)
425528 {
426 if (!VuData || !VuData->IsConnected())
427 return PVR_ERROR_SERVER_ERROR;
428
429 return VuData->GetRecordings(handle);
430 }
431
432 PVR_ERROR DeleteRecording(const PVR_RECORDING &recording)
433 {
434 if (!VuData || !VuData->IsConnected())
435 return PVR_ERROR_SERVER_ERROR;
436
437 return VuData->DeleteRecording(recording);
438 }
439
440 PVR_ERROR RenameRecording(const PVR_RECORDING &recording)
441 {
442 return PVR_ERROR_NOT_IMPLEMENTED;
443 }
444
445 PVR_ERROR GetTimerTypes(PVR_TIMER_TYPE types[], int *size)
446 {
447 /* TODO: Implement this to get support for the timer features introduced with PVR API 1.9.7 */
448 return PVR_ERROR_NOT_IMPLEMENTED;
529 if (!enigma || !enigma->IsConnected())
530 return PVR_ERROR_SERVER_ERROR;
531
532 return enigma->GetRecordings(handle, deleted);
533 }
534
535 PVR_ERROR DeleteRecording(const PVR_RECORDING& recording)
536 {
537 if (!enigma || !enigma->IsConnected())
538 return PVR_ERROR_SERVER_ERROR;
539
540 return enigma->DeleteRecording(recording);
541 }
542
543 PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording)
544 {
545 if (!enigma || !enigma->IsConnected())
546 return PVR_ERROR_SERVER_ERROR;
547
548 return enigma->UndeleteRecording(recording);
549 }
550
551 PVR_ERROR DeleteAllRecordingsFromTrash()
552 {
553 if (!enigma || !enigma->IsConnected())
554 return PVR_ERROR_SERVER_ERROR;
555
556 return enigma->DeleteAllRecordingsFromTrash();
557 }
558
559 PVR_ERROR GetRecordingEdl(const PVR_RECORDING& recinfo, PVR_EDL_ENTRY edl[], int* size)
560 {
561 if (!enigma || !enigma->IsConnected())
562 return PVR_ERROR_SERVER_ERROR;
563
564 if (!settings.GetRecordingEDLsEnabled())
565 {
566 *size = 0;
567 return PVR_ERROR_NO_ERROR;
568 }
569
570 return enigma->GetRecordingEdl(recinfo, edl, size);
571 }
572
573 PVR_ERROR RenameRecording(const PVR_RECORDING& recording)
574 {
575 if (!enigma || !enigma->IsConnected())
576 return PVR_ERROR_SERVER_ERROR;
577
578 return enigma->RenameRecording(recording);
579 }
580
581 PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING& recording, int count)
582 {
583 if (!enigma || !enigma->IsConnected())
584 return PVR_ERROR_SERVER_ERROR;
585
586 return enigma->SetRecordingPlayCount(recording, count);
587 }
588
589 PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastPlayedPosition)
590 {
591 if (!enigma || !enigma->IsConnected())
592 return PVR_ERROR_SERVER_ERROR;
593
594 return enigma->SetRecordingLastPlayedPosition(recording, lastPlayedPosition);
595 }
596
597 int GetRecordingLastPlayedPosition(const PVR_RECORDING& recording)
598 {
599 if (!enigma || !enigma->IsConnected())
600 return PVR_ERROR_SERVER_ERROR;
601
602 return enigma->GetRecordingLastPlayedPosition(recording);
603 }
604
605 /***************************************************************************
606 * Recording Streams
607 **************************************************************************/
608
609 PVR_ERROR GetRecordingStreamProperties(const PVR_RECORDING* recording, PVR_NAMED_VALUE* properties, unsigned int* iPropertiesCount)
610 {
611 if (!settings.SetStreamProgramID())
612 return PVR_ERROR_NOT_IMPLEMENTED;
613
614 //
615 // We only use this function to set the program number which may comes with every Enigma2 recording. For providers that
616 // use MPTS it allows the FFMPEG Demux to identify the correct Program/PID.
617 //
618
619 if (!recording || !properties || !iPropertiesCount)
620 return PVR_ERROR_SERVER_ERROR;
621
622 if (*iPropertiesCount < 1)
623 return PVR_ERROR_INVALID_PARAMETERS;
624
625 if (!enigma || !enigma->IsConnected())
626 return PVR_ERROR_SERVER_ERROR;
627
628 if (enigma->HasRecordingStreamProgramNumber(*recording))
629 {
630 const std::string strStreamProgramNumber = std::to_string(enigma->GetRecordingStreamProgramNumber(*recording));
631
632 Logger::Log(LEVEL_NOTICE, "%s - for recording for channel: %s, set Stream Program Number to %s - %s", __FUNCTION__, recording->strChannelName, strStreamProgramNumber.c_str(), recording->strRecordingId);
633
634 strncpy(properties[0].strName, "program", sizeof(properties[0].strName) - 1);
635 strncpy(properties[0].strValue, strStreamProgramNumber.c_str(), sizeof(properties[0].strValue) - 1);
636 *iPropertiesCount = 1;
637 }
638
639 return PVR_ERROR_NO_ERROR;
640 }
641
642 bool OpenRecordedStream(const PVR_RECORDING& recording)
643 {
644 if (recordingReader)
645 SAFE_DELETE(recordingReader);
646
647 if (!enigma || !enigma->IsConnected())
648 return false;
649
650 recordingReader = enigma->OpenRecordedStream(recording);
651 return recordingReader->Start();
652 }
653
654 void CloseRecordedStream(void)
655 {
656 if (recordingReader)
657 SAFE_DELETE(recordingReader);
658 }
659
660 int ReadRecordedStream(unsigned char* buffer, unsigned int size)
661 {
662 if (!recordingReader)
663 return 0;
664
665 return recordingReader->ReadData(buffer, size);
666 }
667
668 long long SeekRecordedStream(long long position, int whence)
669 {
670 if (!recordingReader)
671 return 0;
672
673 return recordingReader->Seek(position, whence);
674 }
675
676 long long LengthRecordedStream(void)
677 {
678 if (!recordingReader)
679 return -1;
680
681 return recordingReader->Length();
682 }
683
684 /***************************************************************************
685 * Timers
686 **************************************************************************/
687
688 PVR_ERROR GetTimerTypes(PVR_TIMER_TYPE types[], int* size)
689 {
690 *size = 0;
691 if (enigma && enigma->IsConnected())
692 enigma->GetTimerTypes(types, size);
693 return PVR_ERROR_NO_ERROR;
449694 }
450695
451696 int GetTimersAmount(void)
452697 {
453 if (!VuData || !VuData->IsConnected())
698 if (!enigma || !enigma->IsConnected())
454699 return 0;
455700
456 return VuData->GetTimersAmount();
701 return enigma->GetTimersAmount();
457702 }
458703
459704 PVR_ERROR GetTimers(ADDON_HANDLE handle)
460705 {
461 if (!VuData || !VuData->IsConnected())
462 return PVR_ERROR_SERVER_ERROR;
463
464 /* TODO: Change implementation to get support for the timer features introduced with PVR API 1.9.7 */
465 return VuData->GetTimers(handle);
466 }
467
468 PVR_ERROR AddTimer(const PVR_TIMER &timer)
469 {
470 if (!VuData || !VuData->IsConnected())
471 return PVR_ERROR_SERVER_ERROR;
472
473 return VuData->AddTimer(timer);
474 }
475
476 PVR_ERROR DeleteTimer(const PVR_TIMER &timer, bool bForceDelete)
477 {
478 if (!VuData || !VuData->IsConnected())
479 return PVR_ERROR_SERVER_ERROR;
480
481 return VuData->DeleteTimer(timer);
482 }
483
484 PVR_ERROR UpdateTimer(const PVR_TIMER &timer)
485 {
486 if (!VuData || !VuData->IsConnected())
487 return PVR_ERROR_SERVER_ERROR;
488
489 return VuData->UpdateTimer(timer);
490 }
491
492 bool SwitchChannel(const PVR_CHANNEL &channel)
493 {
494 if (!VuData || !VuData->IsConnected())
495 return false;
496
497 return VuData->SwitchChannel(channel);
498 }
499
500 int GetChannelGroupsAmount(void)
501 {
502 if (!VuData || !VuData->IsConnected())
503 return PVR_ERROR_SERVER_ERROR;
504
505 return VuData->GetNumChannelGroups();
506 }
507
508 PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio)
509 {
510 if (bRadio)
511 return PVR_ERROR_NO_ERROR;
512
513 if (!VuData || !VuData->IsConnected())
514 return PVR_ERROR_SERVER_ERROR;
515
516 return VuData->GetChannelGroups(handle);
517 }
518
519 PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group)
520 {
521 if (group.bIsRadio)
522 return PVR_ERROR_NO_ERROR;
523
524 if (!VuData || !VuData->IsConnected())
525 return PVR_ERROR_SERVER_ERROR;
526
527 return VuData->GetChannelGroupMembers(handle, group);
528 }
529
530 void CloseLiveStream(void)
531 {
532 VuData->CloseLiveStream();
533 };
534
535 bool OpenLiveStream(const PVR_CHANNEL &channel)
536 {
537 if (!VuData || !VuData->IsConnected())
538 return false;
539
540 return VuData->OpenLiveStream(channel);
541 }
542
543 const char * GetLiveStreamURL(const PVR_CHANNEL &channel)
544 {
545 if (!VuData || !VuData->IsConnected())
546 return "";
547
548 return VuData->GetLiveStreamURL(channel);
549 }
550 PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING &recording, int lastplayedposition)
551 {
552 return PVR_ERROR_NOT_IMPLEMENTED;
553 }
554
555 int GetRecordingLastPlayedPosition(const PVR_RECORDING &recording)
556 {
557 return PVR_ERROR_NOT_IMPLEMENTED;
706 if (!enigma || !enigma->IsConnected())
707 return PVR_ERROR_SERVER_ERROR;
708
709 return enigma->GetTimers(handle);
710 }
711
712 PVR_ERROR AddTimer(const PVR_TIMER& timer)
713 {
714 if (!enigma || !enigma->IsConnected())
715 return PVR_ERROR_SERVER_ERROR;
716
717 return enigma->AddTimer(timer);
718 }
719
720 PVR_ERROR DeleteTimer(const PVR_TIMER& timer, bool bForceDelete)
721 {
722 if (!enigma || !enigma->IsConnected())
723 return PVR_ERROR_SERVER_ERROR;
724
725 return enigma->DeleteTimer(timer);
726 }
727
728 PVR_ERROR UpdateTimer(const PVR_TIMER& timer)
729 {
730 if (!enigma || !enigma->IsConnected())
731 return PVR_ERROR_SERVER_ERROR;
732
733 return enigma->UpdateTimer(timer);
558734 }
559735
560736 /** UNUSED API FUNCTIONS */
561 PVR_ERROR SignalStatus(PVR_SIGNAL_STATUS &signalStatus) { return PVR_ERROR_NO_ERROR; }
562 PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES* pProperties) { return PVR_ERROR_NOT_IMPLEMENTED; }
737 PVR_ERROR GetStreamProperties(PVR_STREAM_PROPERTIES* pProperties) { return PVR_ERROR_NOT_IMPLEMENTED; }
563738 void DemuxAbort(void) { return; }
564 DemuxPacket* DemuxRead(void) { return NULL; }
739 DemuxPacket* DemuxRead(void) { return nullptr; }
565740 PVR_ERROR OpenDialogChannelScan(void) { return PVR_ERROR_NOT_IMPLEMENTED; }
566 PVR_ERROR CallMenuHook(const PVR_MENUHOOK &menuhook, const PVR_MENUHOOK_DATA &item) { return PVR_ERROR_NOT_IMPLEMENTED; }
567 PVR_ERROR DeleteChannel(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
568 PVR_ERROR RenameChannel(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
569 PVR_ERROR MoveChannel(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
570 PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
571 PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL &channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
572 bool OpenRecordedStream(const PVR_RECORDING &recording) { return false; }
573 void CloseRecordedStream(void) {}
574 int ReadRecordedStream(unsigned char *pBuffer, unsigned int iBufferSize) { return 0; }
575 long long SeekRecordedStream(long long iPosition, int iWhence /* = SEEK_SET */) { return 0; }
576 long long PositionRecordedStream(void) { return -1; }
577 long long LengthRecordedStream(void) { return 0; }
741 PVR_ERROR CallMenuHook(const PVR_MENUHOOK& menuhook, const PVR_MENUHOOK_DATA& item) { return PVR_ERROR_NOT_IMPLEMENTED; }
742 PVR_ERROR DeleteChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
743 PVR_ERROR RenameChannel(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
744 PVR_ERROR OpenDialogChannelSettings(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
745 PVR_ERROR OpenDialogChannelAdd(const PVR_CHANNEL& channel) { return PVR_ERROR_NOT_IMPLEMENTED; }
578746 void DemuxReset(void) {}
579747 void DemuxFlush(void) {}
580 int ReadLiveStream(unsigned char *pBuffer, unsigned int iBufferSize) { return 0; }
581 long long SeekLiveStream(long long iPosition, int iWhence /* = SEEK_SET */) { return -1; }
582 long long PositionLiveStream(void) { return -1; }
583 long long LengthLiveStream(void) { return -1; }
584 PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING &recording, int count) { return PVR_ERROR_NOT_IMPLEMENTED; }
585 PVR_ERROR GetRecordingEdl(const PVR_RECORDING&, PVR_EDL_ENTRY[], int*) { return PVR_ERROR_NOT_IMPLEMENTED; };
586 unsigned int GetChannelSwitchDelay(void) { return 0; }
587 void PauseStream(bool bPaused) {}
588 bool CanPauseStream(void) { return false; }
589 bool CanSeekStream(void) { return false; }
590 bool SeekTime(double,bool,double*) { return false; }
591 void SetSpeed(int) {};
592 bool IsTimeshifting(void) { return false; }
593 time_t GetPlayingTime() { return 0; }
594 time_t GetBufferTimeStart() { return 0; }
595 time_t GetBufferTimeEnd() { return 0; }
596 bool IsRealTimeStream() { return true; }
597 PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording) { return PVR_ERROR_NOT_IMPLEMENTED; }
598 PVR_ERROR DeleteAllRecordingsFromTrash() { return PVR_ERROR_NOT_IMPLEMENTED; }
599 PVR_ERROR SetEPGTimeFrame(int) { return PVR_ERROR_NOT_IMPLEMENTED; }
600 }
748 bool SeekTime(double, bool, double*) { return false; }
749 void SetSpeed(int){};
750 PVR_ERROR GetDescrambleInfo(PVR_DESCRAMBLE_INFO*) { return PVR_ERROR_NOT_IMPLEMENTED; }
751 PVR_ERROR SetRecordingLifetime(const PVR_RECORDING*) { return PVR_ERROR_NOT_IMPLEMENTED; }
752 PVR_ERROR IsEPGTagRecordable(const EPG_TAG*, bool*) { return PVR_ERROR_NOT_IMPLEMENTED; }
753 PVR_ERROR IsEPGTagPlayable(const EPG_TAG*, bool*) { return PVR_ERROR_NOT_IMPLEMENTED; }
754 PVR_ERROR GetEPGTagStreamProperties(const EPG_TAG*, PVR_NAMED_VALUE*, unsigned int*) { return PVR_ERROR_NOT_IMPLEMENTED; }
755 PVR_ERROR GetEPGTagEdl(const EPG_TAG* epgTag, PVR_EDL_ENTRY edl[], int* size) { return PVR_ERROR_NOT_IMPLEMENTED; }
756 }
00 #pragma once
11 /*
2 * Copyright (C) 2005-2015 Team XBMC
2 * Copyright (C) 2005-2019 Team XBMC
33 * http://www.xbmc.org
44 *
55 * This Program is free software; you can redistribute it and/or modify
2020 *
2121 */
2222
23 #include "libXBMC_addon.h"
24 #include "libXBMC_pvr.h"
23 #include "kodi/libXBMC_addon.h"
24 #include "kodi/libXBMC_pvr.h"
2525
26 #define DEFAULT_HOST "127.0.0.1"
27 #define DEFAULT_CONNECT_TIMEOUT 30
28 #define DEFAULT_STREAM_PORT 8001
29 #define DEFAULT_WEB_PORT 80
30 #define DEFAULT_UPDATE_INTERVAL 2
31
32 extern bool m_bCreated;
33 extern std::string g_strHostname;
34 extern int g_iPortStream;
35 extern int g_iPortWeb;
36 extern std::string g_strUsername;
37 extern std::string g_strPassword;
38 extern std::string g_strIconPath;
39 extern std::string g_strRecordingPath;
40 extern int g_iUpdateInterval;
41 //extern int g_iClientId;
42 extern unsigned int g_iPacketSequence;
43 extern bool g_bShowTimerNotifications;
44 extern bool g_bZap;
45 extern bool g_bAutomaticTimerlistCleanup;
46 extern bool g_bUseSecureHTTP;
47 extern bool g_bOnlyCurrentLocation;
48 extern bool g_bSetPowerstate;
49 extern bool g_bOnlyOneGroup;
50 extern bool g_bOnlinePicons;
51 extern std::string g_strOneGroup;
52 extern std::string g_szUserPath;
53 extern std::string g_szClientPath;
54 extern std::string g_strChannelDataPath;
55 extern ADDON::CHelper_libXBMC_addon * XBMC;
56 extern CHelper_libXBMC_pvr * PVR;
26 extern ADDON::CHelper_libXBMC_addon* XBMC;
27 extern CHelper_libXBMC_pvr* PVR;
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Admin.h"
23
24 #include "../Enigma2.h"
25 #include "../client.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "util/XMLUtils.h"
28 #include "utilities/FileUtils.h"
29 #include "utilities/LocalizedString.h"
30 #include "utilities/Logger.h"
31 #include "utilities/WebUtils.h"
32
33 #include <cstdlib>
34 #include <regex>
35
36 #include <nlohmann/json.hpp>
37
38 using namespace enigma2;
39 using namespace enigma2::data;
40 using namespace enigma2::extract;
41 using namespace enigma2::utilities;
42 using json = nlohmann::json;
43
44 Admin::Admin() : m_addonVersion(STR(VUPLUS_VERSION))
45 {
46 m_serverName[0] = '\0';
47 m_serverVersion[0] = '\0';
48 };
49
50 void Admin::SendPowerstate()
51 {
52 if (Settings::GetInstance().GetPowerstateModeOnAddonExit() != PowerstateMode::DISABLED)
53 {
54 if (Settings::GetInstance().GetPowerstateModeOnAddonExit() == PowerstateMode::WAKEUP_THEN_STANDBY)
55 {
56 const std::string strCmd = StringUtils::Format("web/powerstate?newstate=4"); //Wakeup
57
58 std::string strResult;
59 WebUtils::SendSimpleCommand(strCmd, strResult, true);
60 }
61
62 if (Settings::GetInstance().GetPowerstateModeOnAddonExit() == PowerstateMode::STANDBY ||
63 Settings::GetInstance().GetPowerstateModeOnAddonExit() == PowerstateMode::WAKEUP_THEN_STANDBY)
64 {
65 const std::string strCmd = StringUtils::Format("web/powerstate?newstate=5"); //Standby
66
67 std::string strResult;
68 WebUtils::SendSimpleCommand(strCmd, strResult, true);
69 }
70
71 if (Settings::GetInstance().GetPowerstateModeOnAddonExit() == PowerstateMode::DEEP_STANDBY)
72 {
73 const std::string strCmd = StringUtils::Format("web/powerstate?newstate=1"); //Deep Standby
74
75 std::string strResult;
76 WebUtils::SendSimpleCommand(strCmd, strResult, true);
77 }
78 }
79 }
80
81 bool Admin::Initialise()
82 {
83 std::string unknown = LocalizedString(30081).c_str();
84 SetCharString(m_serverName, unknown);
85 SetCharString(m_serverVersion, unknown);
86
87 Settings::GetInstance().SetAdmin(this);
88
89 bool deviceInfoLoaded = LoadDeviceInfo();
90
91 if (deviceInfoLoaded)
92 {
93 Settings::GetInstance().SetDeviceInfo(&m_deviceInfo);
94
95 bool deviceSettingsLoaded = LoadDeviceSettings();
96 Settings::GetInstance().SetDeviceSettings(&m_deviceSettings);
97
98 if (deviceSettingsLoaded)
99 {
100 //If OpenWebVersion is new enough to allow the setting of AutoTimer setttings
101 if (Settings::GetInstance().SupportsAutoTimers())
102 SendAutoTimerSettings();
103 }
104 }
105
106 return deviceInfoLoaded;
107 }
108
109 bool Admin::LoadDeviceInfo()
110 {
111 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/deviceinfo");
112
113 const std::string strXML = WebUtils::GetHttpXML(url);
114
115 TiXmlDocument xmlDoc;
116 if (!xmlDoc.Parse(strXML.c_str()))
117 {
118 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
119 return false;
120 }
121
122 std::string enigmaVersion;
123 std::string imageVersion;
124 std::string distroName;
125 std::string webIfVersion;
126 std::string deviceName = "Enigma2";
127 unsigned int webIfVersionAsNum;
128
129 TiXmlHandle hDoc(&xmlDoc);
130 TiXmlElement* pElem;
131 TiXmlHandle hRoot(0);
132
133 pElem = hDoc.FirstChildElement("e2deviceinfo").Element();
134
135 if (!pElem)
136 {
137 Logger::Log(LEVEL_ERROR, "%s Could not find <e2deviceinfo> element!", __FUNCTION__);
138 return false;
139 }
140
141 std::string strTmp;
142
143 Logger::Log(LEVEL_NOTICE, "%s - DeviceInfo", __FUNCTION__);
144
145 // Get EnigmaVersion
146 if (!XMLUtils::GetString(pElem, "e2enigmaversion", strTmp))
147 {
148 Logger::Log(LEVEL_ERROR, "%s Could not parse e2enigmaversion from result!", __FUNCTION__);
149 return false;
150 }
151 enigmaVersion = strTmp.c_str();
152 Logger::Log(LEVEL_NOTICE, "%s - E2EnigmaVersion: %s", __FUNCTION__, enigmaVersion.c_str());
153
154 // Get ImageVersion
155 if (!XMLUtils::GetString(pElem, "e2imageversion", strTmp))
156 {
157 Logger::Log(LEVEL_ERROR, "%s Could not parse e2imageversion from result!", __FUNCTION__);
158 return false;
159 }
160 imageVersion = strTmp.c_str();
161 Logger::Log(LEVEL_NOTICE, "%s - E2ImageVersion: %s", __FUNCTION__, imageVersion.c_str());
162
163 // Get distroName
164 if (!XMLUtils::GetString(pElem, "e2distroversion", strTmp))
165 {
166 Logger::Log(LEVEL_NOTICE, "%s Could not parse e2distroversion from result, continuing as not available in all images!", __FUNCTION__);
167 strTmp = LocalizedString(30081); //unknown
168 }
169 else
170 {
171 distroName = strTmp.c_str();
172 }
173 Logger::Log(LEVEL_NOTICE, "%s - E2DistroName: %s", __FUNCTION__, distroName.c_str());
174
175 // Get WebIfVersion
176 if (!XMLUtils::GetString(pElem, "e2webifversion", strTmp))
177 {
178 Logger::Log(LEVEL_ERROR, "%s Could not parse e2webifversion from result!", __FUNCTION__);
179 return false;
180 }
181 webIfVersion = strTmp.c_str();
182 webIfVersionAsNum = ParseWebIfVersion(webIfVersion);
183
184 Logger::Log(LEVEL_NOTICE, "%s - E2WebIfVersion: %s", __FUNCTION__, webIfVersion.c_str());
185
186 // Get DeviceName
187 if (!XMLUtils::GetString(pElem, "e2devicename", strTmp))
188 {
189 Logger::Log(LEVEL_ERROR, "%s Could not parse e2devicename from result!", __FUNCTION__);
190 return false;
191 }
192 deviceName = strTmp.c_str();
193 Logger::Log(LEVEL_NOTICE, "%s - E2DeviceName: %s", __FUNCTION__, deviceName.c_str());
194
195 m_deviceInfo = DeviceInfo(deviceName, enigmaVersion, imageVersion, distroName, webIfVersion, webIfVersionAsNum);
196
197 std::string version = webIfVersion + " - " + distroName + " (" + imageVersion + "/" + enigmaVersion + ")";
198 SetCharString(m_serverName, deviceName);
199 SetCharString(m_serverVersion, version);
200
201 Logger::Log(LEVEL_NOTICE, "%s - ServerVersion: %s", __FUNCTION__, m_serverVersion);
202
203 Logger::Log(LEVEL_NOTICE, "%s - AddonVersion: %s", __FUNCTION__, m_addonVersion.c_str());
204
205 hRoot = TiXmlHandle(pElem);
206
207 TiXmlElement* pNode = hRoot.FirstChildElement("e2frontends").Element();
208
209 if (pNode)
210 {
211 TiXmlElement* tunerNode = pNode->FirstChildElement("e2frontend");
212
213 if (tunerNode)
214 {
215 int tunerNumber = 0;
216
217 for (; tunerNode != nullptr; tunerNode = tunerNode->NextSiblingElement("e2frontend"))
218 {
219 std::string tunerName;
220 std::string tunerModel;
221
222 XMLUtils::GetString(tunerNode, "e2name", tunerName);
223 XMLUtils::GetString(tunerNode, "e2model", tunerModel);
224
225 m_tuners.emplace_back(Tuner(tunerNumber, tunerName, tunerModel));
226
227 Logger::Log(LEVEL_DEBUG, "%s Tuner Info Loaded - Tuner Number: %d, Tuner Name:%s Tuner Model: %s", __FUNCTION__, tunerNumber, tunerName.c_str(), tunerModel.c_str());
228
229 tunerNumber++;
230 }
231 }
232 else
233 {
234 Logger::Log(LEVEL_DEBUG, "%s Could not find <e2frontend> element", __FUNCTION__);
235 }
236 }
237 else
238 {
239 Logger::Log(LEVEL_DEBUG, "%s Could not find <e2frontends> element", __FUNCTION__);
240 }
241
242 return true;
243 }
244
245 unsigned int Admin::ParseWebIfVersion(const std::string& webIfVersion)
246 {
247 unsigned int webIfVersionAsNum = 0;
248
249 std::regex regex("^.*[0-9]+\\.[0-9]+\\.[0-9].*$");
250 if (std::regex_match(webIfVersion, regex))
251 {
252 int count = 0;
253 unsigned int versionPart = 0;
254 std::regex pattern("([0-9]+)");
255 for (auto i = std::sregex_iterator(webIfVersion.begin(), webIfVersion.end(), pattern); i != std::sregex_iterator(); ++i)
256 {
257 switch (count)
258 {
259 case 0:
260 versionPart = std::atoi(i->str().c_str());
261 webIfVersionAsNum = versionPart << 16;
262 break;
263 case 1:
264 versionPart = std::atoi(i->str().c_str());
265 webIfVersionAsNum |= versionPart << 8;
266 break;
267 case 2:
268 versionPart = std::atoi(i->str().c_str());
269 webIfVersionAsNum |= versionPart;
270 break;
271 }
272
273 count++;
274 }
275 }
276
277 return webIfVersionAsNum;
278 }
279
280 bool Admin::LoadDeviceSettings()
281 {
282 //TODO: Include once addon starts to use new API
283 //kodi::SetSettingString("webifversion", m_deviceInfo.GetWebIfVersion());
284
285 std::string autoTimerTagInTags = LocalizedString(30094); // N/A
286 std::string autoTimerNameInTags = LocalizedString(30094); // N/A
287
288 //If OpenWebVersion is new enough to allow the setting of AutoTimer setttings
289 if (Settings::GetInstance().SupportsAutoTimers())
290 {
291 if (LoadAutoTimerSettings())
292 {
293 if (m_deviceSettings.IsAddTagAutoTimerToTagsEnabled())
294 autoTimerTagInTags = LocalizedString(30095); // True
295 else
296 autoTimerTagInTags = LocalizedString(30096); // False
297 if (m_deviceSettings.IsAddAutoTimerNameToTagsEnabled())
298 autoTimerNameInTags = LocalizedString(30095); // True
299 else
300 autoTimerNameInTags = LocalizedString(30096); //False
301 }
302 }
303
304 //TODO: Include once addon starts to use new API
305 //kodi::SetSettingString("autotimertagintags", autoTimerTagInTags);
306 //kodi::SetSettingString("autotimernameintags", autoTimerNameInTags);
307
308 if (!LoadRecordingMarginSettings())
309 {
310 return false;
311 }
312 else
313 {
314 //TODO: Include once addon starts to use new API
315 //kodi::SetSettingInt("globalstartpaddingstb", m_deviceSettings.GetGlobalRecordingStartMargin());
316 //kodi::SetSettingInt("globalendpaddingstb", m_deviceSettings.GetGlobalRecordingEndMargin());
317 }
318
319 return true;
320 }
321
322 bool Admin::LoadAutoTimerSettings()
323 {
324 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "autotimer/get");
325
326 const std::string strXML = WebUtils::GetHttpXML(url);
327
328 TiXmlDocument xmlDoc;
329 if (!xmlDoc.Parse(strXML.c_str()))
330 {
331 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
332 return false;
333 }
334
335 TiXmlHandle hDoc(&xmlDoc);
336
337 TiXmlElement* pElem = hDoc.FirstChildElement("e2settings").Element();
338
339 if (!pElem)
340 {
341 Logger::Log(LEVEL_ERROR, "%s Could not find <e2settings> element!", __FUNCTION__);
342 return false;
343 }
344
345 TiXmlHandle hRoot = TiXmlHandle(pElem);
346
347 TiXmlElement* pNode = hRoot.FirstChildElement("e2setting").Element();
348
349 if (!pNode)
350 {
351 Logger::Log(LEVEL_ERROR, "%s Could not find <e2setting> element", __FUNCTION__);
352 return false;
353 }
354
355 std::string settingName;
356 std::string settingValue;
357 bool setAutoTimerToTags = false;
358 bool setAutoTimerNameToTags = false;
359 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2setting"))
360 {
361 if (!XMLUtils::GetString(pNode, "e2settingname", settingName))
362 return false;
363
364 if (!XMLUtils::GetString(pNode, "e2settingvalue", settingValue))
365 return false;
366
367 if (settingName == "config.plugins.autotimer.add_autotimer_to_tags")
368 {
369 m_deviceSettings.SetAddTagAutoTimerToTagsEnabled(settingValue == "True");
370 setAutoTimerToTags = true;
371 }
372 else if (settingName == "config.plugins.autotimer.add_name_to_tags")
373 {
374 m_deviceSettings.SetAddAutoTimerNameToTagsEnabled(settingValue == "True");
375 setAutoTimerNameToTags = true;
376 }
377
378 if (setAutoTimerNameToTags && setAutoTimerToTags)
379 break;
380 }
381
382 Logger::Log(LEVEL_DEBUG, "%s Add Tag AutoTimer to Tags: %d, Add AutoTimer Name to tags: %d", __FUNCTION__, m_deviceSettings.IsAddTagAutoTimerToTagsEnabled(), m_deviceSettings.IsAddAutoTimerNameToTagsEnabled());
383
384 return true;
385 }
386
387 bool Admin::LoadRecordingMarginSettings()
388 {
389 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/settings");
390
391 const std::string strXML = WebUtils::GetHttpXML(url);
392
393 TiXmlDocument xmlDoc;
394 if (!xmlDoc.Parse(strXML.c_str()))
395 {
396 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
397 return false;
398 }
399
400 TiXmlHandle hDoc(&xmlDoc);
401
402 TiXmlElement* pElem = hDoc.FirstChildElement("e2settings").Element();
403
404 if (!pElem)
405 {
406 Logger::Log(LEVEL_ERROR, "%s Could not find <e2settings> element!", __FUNCTION__);
407 return false;
408 }
409
410 TiXmlHandle hRoot = TiXmlHandle(pElem);
411
412 TiXmlElement* pNode = hRoot.FirstChildElement("e2setting").Element();
413
414 if (!pNode)
415 {
416 Logger::Log(LEVEL_ERROR, "%s Could not find <e2setting> element", __FUNCTION__);
417 return false;
418 }
419
420 std::string settingName;
421 std::string settingValue;
422 bool readMarginBefore = false;
423 bool readMarginAfter = false;
424 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2setting"))
425 {
426 if (!XMLUtils::GetString(pNode, "e2settingname", settingName))
427 continue;
428
429 if (!XMLUtils::GetString(pNode, "e2settingvalue", settingValue))
430 continue;
431
432 if (settingName == "config.recording.margin_before")
433 {
434 m_deviceSettings.SetGlobalRecordingStartMargin(std::atoi(settingValue.c_str()));
435 readMarginBefore = true;
436 }
437 else if (settingName == "config.recording.margin_after")
438 {
439 m_deviceSettings.SetGlobalRecordingEndMargin(std::atoi(settingValue.c_str()));
440 readMarginAfter = true;
441 }
442
443 if (readMarginBefore && readMarginAfter)
444 break;
445 }
446
447 Logger::Log(LEVEL_DEBUG, "%s Margin Before: %d, Margin After: %d", __FUNCTION__, m_deviceSettings.GetGlobalRecordingStartMargin(), m_deviceSettings.GetGlobalRecordingEndMargin());
448
449 return true;
450 }
451
452 bool Admin::SendAutoTimerSettings()
453 {
454 if (!(m_deviceSettings.IsAddTagAutoTimerToTagsEnabled() && m_deviceSettings.IsAddAutoTimerNameToTagsEnabled()))
455 {
456 Logger::Log(LEVEL_DEBUG, "%s Setting AutoTimer Settings on Backend", __FUNCTION__);
457 const std::string url = StringUtils::Format("%s", "autotimer/set?add_name_to_tags=true&add_autotimer_to_tags=true");
458 std::string strResult;
459
460 if (!WebUtils::SendSimpleCommand(url, strResult))
461 return false;
462 }
463
464 return true;
465 }
466
467 bool Admin::SendGlobalRecordingStartMarginSetting(int newValue)
468 {
469 if (m_deviceSettings.GetGlobalRecordingStartMargin() != newValue)
470 {
471 Logger::Log(LEVEL_NOTICE, "%s Setting Global Recording Start Margin Backend, from: %d, to: %d", __FUNCTION__, m_deviceSettings.GetGlobalRecordingStartMargin(), newValue);
472 const std::string url = StringUtils::Format("%s%d", "api/saveconfig?key=config.recording.margin_before&value=", newValue);
473 std::string strResult;
474
475 if (!WebUtils::SendSimpleJsonPostCommand(url, strResult))
476 return false;
477 else
478 m_deviceSettings.SetGlobalRecordingStartMargin(newValue);
479 }
480
481 return true;
482 }
483
484 bool Admin::SendGlobalRecordingEndMarginSetting(int newValue)
485 {
486 if (m_deviceSettings.GetGlobalRecordingEndMargin() != newValue)
487 {
488 Logger::Log(LEVEL_NOTICE, "%s Setting Global Recording End Margin Backend, from: %d, to: %d", __FUNCTION__, m_deviceSettings.GetGlobalRecordingEndMargin(), newValue);
489 const std::string url = StringUtils::Format("%s%d", "api/saveconfig?key=config.recording.margin_after&value=", newValue);
490 std::string strResult;
491
492 if (!WebUtils::SendSimpleJsonPostCommand(url, strResult))
493 return false;
494 else
495 m_deviceSettings.SetGlobalRecordingEndMargin(newValue);
496 }
497
498 return true;
499 }
500
501 PVR_ERROR Admin::GetDriveSpace(long long* iTotal, long long* iUsed, std::vector<std::string>& locations)
502 {
503 long long totalKb = 0;
504 long long freeKb = 0;
505
506 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/deviceinfo");
507
508 const std::string strXML = WebUtils::GetHttpXML(url);
509
510 TiXmlDocument xmlDoc;
511 if (!xmlDoc.Parse(strXML.c_str()))
512 {
513 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
514 return PVR_ERROR_SERVER_ERROR;
515 }
516
517 TiXmlHandle hDoc(&xmlDoc);
518
519 TiXmlElement* pElem = hDoc.FirstChildElement("e2deviceinfo").Element();
520
521 if (!pElem)
522 {
523 Logger::Log(LEVEL_ERROR, "%s Could not find <e2deviceinfo> element!", __FUNCTION__);
524 return PVR_ERROR_SERVER_ERROR;
525 }
526
527 TiXmlHandle hRoot = TiXmlHandle(pElem);
528
529 TiXmlElement* pNode = hRoot.FirstChildElement("e2hdds").Element();
530
531 if (!pNode)
532 {
533 Logger::Log(LEVEL_ERROR, "%s Could not find <e2hdds> element", __FUNCTION__);
534 return PVR_ERROR_SERVER_ERROR;
535 }
536
537 TiXmlElement* hddNode = pNode->FirstChildElement("e2hdd");
538
539 if (!hddNode)
540 {
541 m_deviceHasHDD = false;
542 Logger::Log(LEVEL_ERROR, "%s Could not find <e2hdd> element", __FUNCTION__);
543 return PVR_ERROR_SERVER_ERROR;
544 }
545
546 for (; hddNode != nullptr; hddNode = hddNode->NextSiblingElement("e2hdd"))
547 {
548 std::string capacity;
549 std::string freeSpace;
550 std::string mount;
551
552 XMLUtils::GetString(hddNode, "e2capacity", capacity);
553 XMLUtils::GetString(hddNode, "e2free", freeSpace);
554 XMLUtils::GetString(hddNode, "e2mount", mount);
555
556 if (!mount.empty())
557 {
558 auto it = std::find_if(locations.begin(), locations.end(),
559 [&mount](std::string& location) { return location.find(mount) != std::string::npos; });
560
561 if (it == locations.end())
562 continue; // no valid mount point
563 }
564
565 totalKb += GetKbFromString(capacity);
566 freeKb += GetKbFromString(freeSpace);
567 }
568
569 *iTotal = totalKb;
570 *iUsed = totalKb - freeKb;
571
572 Logger::Log(LEVEL_INFO, "%s Space Total: %lld, Used %lld", __FUNCTION__, *iTotal, *iUsed);
573
574 return PVR_ERROR_NO_ERROR;
575 }
576
577 long long Admin::GetKbFromString(const std::string& stringInMbGbTb) const
578 {
579 long long sizeInKb = 0;
580
581 static const std::vector<std::string> sizes = {"MB", "GB", "TB"};
582 long multiplier = 1024;
583 std::string replaceWith = "";
584 for (const std::string& size : sizes)
585 {
586 std::regex regexSize("^.* " + size);
587 std::regex regexReplaceSize(" " + size);
588
589 if (std::regex_match(stringInMbGbTb, regexSize))
590 {
591 double sizeValue = std::atof(std::regex_replace(stringInMbGbTb, regexReplaceSize, replaceWith).c_str());
592
593 sizeInKb += static_cast<long long>(sizeValue * multiplier);
594
595 break;
596 }
597
598 multiplier = multiplier * 1024;
599 }
600
601 return sizeInKb;
602 }
603
604 bool Admin::GetTunerSignal(SignalStatus& signalStatus, const std::shared_ptr<data::Channel>& channel)
605 {
606 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/signal");
607
608 const std::string strXML = WebUtils::GetHttpXML(url);
609
610 TiXmlDocument xmlDoc;
611 if (!xmlDoc.Parse(strXML.c_str()))
612 {
613 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
614 return false;
615 }
616
617 std::string snrDb;
618 std::string snrPercentage;
619 std::string ber;
620 std::string signalStrength;
621
622 TiXmlHandle hDoc(&xmlDoc);
623
624 TiXmlElement* pElem = hDoc.FirstChildElement("e2frontendstatus").Element();
625
626 if (!pElem)
627 {
628 Logger::Log(LEVEL_ERROR, "%s Could not find <e2frontendstatus> element!", __FUNCTION__);
629 return false;
630 }
631
632 if (!XMLUtils::GetString(pElem, "e2snrdb", snrDb))
633 {
634 Logger::Log(LEVEL_ERROR, "%s Could not parse e2snrdb from result!", __FUNCTION__);
635 return false;
636 }
637
638 if (!XMLUtils::GetString(pElem, "e2snr", snrPercentage))
639 {
640 Logger::Log(LEVEL_ERROR, "%s Could not parse e2snr from result!", __FUNCTION__);
641 return false;
642 }
643
644 if (!XMLUtils::GetString(pElem, "e2ber", ber))
645 {
646 Logger::Log(LEVEL_ERROR, "%s Could not parse e2ber from result!", __FUNCTION__);
647 return false;
648 }
649
650 if (!XMLUtils::GetString(pElem, "e2acg", signalStrength))
651 {
652 Logger::Log(LEVEL_ERROR, "%s Could not parse e2acg from result!", __FUNCTION__);
653 return false;
654 }
655
656 std::regex regexReplacePercent(" %");
657 std::string regexReplace = "";
658
659 // For some reason the iSNR and iSignal values need to multiplied by 655!
660 signalStatus.m_snrPercentage = std::atoi(std::regex_replace(snrPercentage, regexReplacePercent, regexReplace).c_str()) * 655;
661 signalStatus.m_ber = std::atol(ber.c_str());
662 signalStatus.m_signalStrength = std::atoi(std::regex_replace(signalStrength, regexReplacePercent, regexReplace).c_str()) * 655;
663
664 if (Settings::GetInstance().SupportsTunerDetails())
665 {
666 //TODO: Cross reference against tuners once OpenWebIf API is updated.
667 //StreamStatus streamStatus = GetStreamDetails(channel);
668 GetTunerDetails(signalStatus, channel);
669 }
670
671 return true;
672 }
673
674 StreamStatus Admin::GetStreamDetails(const std::shared_ptr<data::Channel>& channel)
675 {
676 StreamStatus streamStatus;
677
678 const std::string jsonUrl = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "api/deviceinfo");
679
680 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
681
682 try
683 {
684 auto jsonDoc = json::parse(strJson);
685
686 if (!jsonDoc["streams"].empty())
687 {
688 for (const auto& it : jsonDoc["streams"].items())
689 {
690 auto jsonStream = it.value();
691
692 if (jsonStream["ref"].get<std::string>() == channel->GetGenericServiceReference() &&
693 !jsonStream["ip"].get<std::string>().empty()) //TODO: Find out Kodi IP and compare
694 {
695 streamStatus.m_ipAddress = jsonStream["ip"].get<std::string>();
696 streamStatus.m_serviceReference = channel->GetServiceReference();
697 streamStatus.m_channelName = channel->GetChannelName(); //Use our channel name as from JSON is unreliable
698
699 if (jsonStream["type"].get<std::string>() == "S")
700 streamStatus.m_streamType = StreamType::DIRECTLY_STREAMED;
701 else
702 streamStatus.m_streamType = StreamType::TRANSCODED;
703
704 break;
705 }
706
707 Logger::Log(LEVEL_DEBUG, "%s Active Stream IP: %s, ref: %s, name: %s", __FUNCTION__, jsonStream["ip"].get<std::string>().c_str(), jsonStream["ref"].get<std::string>().c_str(), jsonStream["name"].get<std::string>().c_str());
708 }
709 }
710
711 if (!streamStatus.m_channelName.empty())
712 {
713 if (!jsonDoc["tuners"].empty())
714 {
715 int tunerNumber = 0;
716
717 for (const auto& it : jsonDoc["tuners"].items())
718 {
719 auto jsonTuner = it.value();
720
721 if (jsonTuner["name"].get<std::string>() == streamStatus.m_channelName)
722 {
723 //TODO: Complete once API is available
724
725 break;
726 }
727
728 tunerNumber++;
729 }
730 }
731 }
732 }
733 catch (nlohmann::detail::parse_error& e)
734 {
735 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot load extra stream details from OpenWebIf - JSON parse error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
736 }
737 catch (nlohmann::detail::type_error& e)
738 {
739 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
740 }
741
742 return streamStatus;
743 }
744
745 void Admin::GetTunerDetails(SignalStatus& signalStatus, const std::shared_ptr<data::Channel>& channel)
746 {
747 const std::string jsonUrl = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "api/tunersignal");
748
749 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
750
751 try
752 {
753 auto jsonDoc = json::parse(strJson);
754
755 for (const auto& element : jsonDoc.items())
756 {
757 if (element.key() == "tunernumber")
758 {
759 Logger::Log(LEVEL_DEBUG, "%s Json API - %s : %d", __FUNCTION__, element.key().c_str(), element.value().get<int>());
760
761 int tunerNumber = element.value().get<int>();
762
763 if (m_tuners.size() > tunerNumber)
764 {
765 Tuner& tuner = m_tuners.at(tunerNumber);
766
767 signalStatus.m_adapterName = tuner.m_tunerName + " - " + tuner.m_tunerModel;
768 }
769 }
770 else if (element.key() == "tunertype")
771 {
772 Logger::Log(LEVEL_DEBUG, "%s Json API - %s : %s", __FUNCTION__, element.key().c_str(), element.value().get<std::string>().c_str());
773
774 signalStatus.m_adapterStatus = element.value().get<std::string>();
775 }
776 }
777 }
778 catch (nlohmann::detail::parse_error& e)
779 {
780 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot load extra tuner details from OpenWebIf - JSON parse error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
781 }
782 catch (nlohmann::detail::type_error& e)
783 {
784 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
785 }
786 }
787
788 void Admin::SetCharString(char* target, const std::string value)
789 {
790 std::copy(value.begin(), value.end(), target);
791 target[value.size()] = '\0';
792 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "data/Channel.h"
24 #include "utilities/DeviceInfo.h"
25 #include "utilities/DeviceSettings.h"
26 #include "utilities/SignalStatus.h"
27 #include "utilities/StreamStatus.h"
28 #include "utilities/Tuner.h"
29 #include "kodi/libXBMC_pvr.h"
30
31 #include <string>
32 #include <vector>
33
34 namespace enigma2
35 {
36 class Admin
37 {
38 public:
39 Admin();
40
41 void SendPowerstate();
42 bool Initialise();
43 bool LoadDeviceSettings();
44 bool SendAutoTimerSettings();
45 bool SendGlobalRecordingStartMarginSetting(int newValue);
46 bool SendGlobalRecordingEndMarginSetting(int newValue);
47 const utilities::DeviceInfo& GetDeviceInfo() const { return m_deviceInfo; }
48 PVR_ERROR GetDriveSpace(long long* iTotal, long long* iUsed, std::vector<std::string>& locations);
49 const char* GetServerName() const { return m_serverName; }
50 const char* GetServerVersion() const { return m_serverVersion; }
51 const std::string& GetDeviceName() const { return m_deviceInfo.GetServerName(); }
52 const std::string& GetDistroName() const { return m_deviceInfo.GetDistroName(); }
53 const std::string& GetEnigmaVersion() const { return m_deviceInfo.GetEnigmaVersion(); }
54 const std::string& GetImageVersion() const { return m_deviceInfo.GetImageVersion(); }
55 const std::string& GetWebIfVersion() const { return m_deviceInfo.GetWebIfVersion(); }
56 unsigned int GetWebIfVersionAsNum() const { return m_deviceInfo.GetWebIfVersionAsNum(); }
57 const std::string& GetAddonVersion() const { return m_addonVersion; }
58 bool GetTunerSignal(utilities::SignalStatus& signalStatus, const std::shared_ptr<data::Channel>& channel);
59 bool GetDeviceHasHDD() const { return m_deviceHasHDD; };
60
61 private:
62 static void SetCharString(char* target, const std::string value);
63 bool LoadDeviceInfo();
64 bool LoadAutoTimerSettings();
65 bool LoadRecordingMarginSettings();
66 unsigned int ParseWebIfVersion(const std::string& webIfVersion);
67 long long GetKbFromString(const std::string& stringInMbGbTb) const;
68 utilities::StreamStatus GetStreamDetails(const std::shared_ptr<data::Channel>& channel);
69 void GetTunerDetails(utilities::SignalStatus& signalStatus, const std::shared_ptr<data::Channel>& channel);
70
71 char m_serverName[256];
72 char m_serverVersion[256];
73 bool m_deviceHasHDD = true;
74 const std::string m_addonVersion;
75 enigma2::utilities::DeviceInfo m_deviceInfo;
76 enigma2::utilities::DeviceSettings m_deviceSettings;
77 std::vector<enigma2::utilities::Tuner> m_tuners;
78 };
79 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "ChannelGroups.h"
23
24 #include "../Enigma2.h"
25 #include "../client.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "util/XMLUtils.h"
28 #include "utilities/FileUtils.h"
29 #include "utilities/LocalizedString.h"
30 #include "utilities/Logger.h"
31 #include "utilities/WebUtils.h"
32
33 #include <regex>
34
35 #include <nlohmann/json.hpp>
36
37 using namespace enigma2;
38 using namespace enigma2::data;
39 using namespace enigma2::utilities;
40 using json = nlohmann::json;
41
42 void ChannelGroups::GetChannelGroups(std::vector<PVR_CHANNEL_GROUP>& kodiChannelGroups, bool radio) const
43 {
44 Logger::Log(LEVEL_DEBUG, "%s - Starting to get ChannelGroups for PVR", __FUNCTION__);
45
46 for (const auto& channelGroup : m_channelGroups)
47 {
48 Logger::Log(LEVEL_DEBUG, "%s - Transfer channelGroup '%s', ChannelGroupIndex '%d'", __FUNCTION__, channelGroup->GetGroupName().c_str(), channelGroup->GetUniqueId());
49
50 if (channelGroup->IsRadio() == radio && !channelGroup->IsEmptyGroup())
51 {
52 PVR_CHANNEL_GROUP kodiChannelGroup = {0};
53
54 channelGroup->UpdateTo(kodiChannelGroup);
55
56 kodiChannelGroups.emplace_back(kodiChannelGroup);
57 }
58 }
59
60 Logger::Log(LEVEL_DEBUG, "%s - Finished getting ChannelGroups for PVR", __FUNCTION__);
61 }
62
63 PVR_ERROR ChannelGroups::GetChannelGroupMembers(std::vector<PVR_CHANNEL_GROUP_MEMBER>& channelGroupMembers, const std::string& groupName)
64 {
65 std::shared_ptr<ChannelGroup> channelGroup = GetChannelGroupUsingName(groupName);
66
67 if (!channelGroup)
68 {
69 Logger::Log(LEVEL_NOTICE, "%s - Channel Group not found, could not get ChannelGroupsMembers for PVR for group: %s", __FUNCTION__, groupName.c_str());
70
71 return PVR_ERROR_NO_ERROR;
72 }
73 else
74 {
75 Logger::Log(LEVEL_DEBUG, "%s - Starting to get ChannelGroupsMembers for PVR for group: %s", __FUNCTION__, groupName.c_str());
76 }
77
78 int channelNumberInGroup = 1;
79
80 for (const auto& channel : channelGroup->GetChannelList())
81 {
82 PVR_CHANNEL_GROUP_MEMBER tag = {0};
83
84 strncpy(tag.strGroupName, groupName.c_str(), sizeof(tag.strGroupName) - 1);
85 tag.iChannelUniqueId = channel->GetUniqueId();
86 tag.iChannelNumber = channelNumberInGroup; //Keep the channels in list order as per the groups on the STB
87
88 Logger::Log(LEVEL_DEBUG, "%s - add channel %s (%d) to group '%s' channel number %d", __FUNCTION__, channel->GetChannelName().c_str(), tag.iChannelUniqueId, groupName.c_str(), channel->GetChannelNumber());
89
90 channelGroupMembers.emplace_back(tag);
91
92 channelNumberInGroup++;
93 }
94
95 Logger::Log(LEVEL_DEBUG, "%s - Finished getting ChannelGroupsMembers for PVR for group: %s", __FUNCTION__, groupName.c_str());
96
97 return PVR_ERROR_NO_ERROR;
98 }
99
100 std::string ChannelGroups::GetChannelGroupServiceReference(const std::string& groupName)
101 {
102 for (const auto& channelGroup : m_channelGroups)
103 {
104 if (groupName == channelGroup->GetGroupName())
105 return channelGroup->GetServiceReference();
106 }
107 return "error";
108 }
109
110 std::shared_ptr<ChannelGroup> ChannelGroups::GetChannelGroup(const std::string& groupServiceReference)
111 {
112 const auto channelGroupPair = m_channelGroupsServiceReferenceMap.find(groupServiceReference);
113 if (channelGroupPair != m_channelGroupsServiceReferenceMap.end())
114 return channelGroupPair->second;
115
116 return {};
117 }
118
119 std::shared_ptr<ChannelGroup> ChannelGroups::GetChannelGroupUsingName(const std::string& groupName)
120 {
121 std::shared_ptr<ChannelGroup> channelGroup;
122
123 auto channelGroupPair = m_channelGroupsNameMap.find(groupName);
124 if (channelGroupPair != m_channelGroupsNameMap.end())
125 {
126 channelGroup = channelGroupPair->second;
127 }
128
129 return channelGroup;
130 }
131
132 bool ChannelGroups::IsValid(std::string groupName)
133 {
134 return GetChannelGroupUsingName(groupName) != nullptr;
135 }
136
137 int ChannelGroups::GetNumChannelGroups() const
138 {
139 return m_channelGroups.size();
140 }
141
142 void ChannelGroups::ClearChannelGroups()
143 {
144 m_channelGroups.clear();
145 m_channelGroupsNameMap.clear();
146 m_channelGroupsServiceReferenceMap.clear();
147
148 Settings::GetInstance().SetUsesLastScannedChannelGroup(false);
149 }
150
151 void ChannelGroups::AddChannelGroup(ChannelGroup& newChannelGroup)
152 {
153 std::shared_ptr<ChannelGroup> foundChannelGroup = GetChannelGroupUsingName(newChannelGroup.GetGroupName());
154
155 if (!foundChannelGroup)
156 {
157 newChannelGroup.SetUniqueId(m_channelGroups.size() + 1);
158
159 m_channelGroups.emplace_back(new ChannelGroup(newChannelGroup));
160
161 std::shared_ptr<ChannelGroup> channelGroup = m_channelGroups.back();
162 m_channelGroupsNameMap.insert({channelGroup->GetGroupName(), channelGroup});
163 m_channelGroupsServiceReferenceMap.insert({channelGroup->GetServiceReference(), channelGroup});
164 }
165 }
166
167 std::vector<std::shared_ptr<ChannelGroup>>& ChannelGroups::GetChannelGroupsList()
168 {
169 return m_channelGroups;
170 }
171
172 bool ChannelGroups::LoadChannelGroups()
173 {
174 ClearChannelGroups();
175
176 bool successful = LoadTVChannelGroups();
177
178 if (successful)
179 LoadRadioChannelGroups();
180
181 return successful;
182 }
183
184 bool ChannelGroups::LoadTVChannelGroups()
185 {
186 int tempNumChannelGroups = m_channelGroups.size();
187
188 if ((Settings::GetInstance().GetTVFavouritesMode() == FavouritesGroupMode::AS_FIRST_GROUP &&
189 Settings::GetInstance().GetTVChannelGroupMode() != ChannelGroupMode::FAVOURITES_GROUP) ||
190 Settings::GetInstance().GetTVChannelGroupMode() == ChannelGroupMode::FAVOURITES_GROUP)
191 {
192 AddTVFavouritesChannelGroup();
193 }
194
195 if (Settings::GetInstance().GetTVChannelGroupMode() != ChannelGroupMode::FAVOURITES_GROUP)
196 {
197 const std::string strTmp = StringUtils::Format("%sweb/getservices", Settings::GetInstance().GetConnectionURL().c_str());
198
199 const std::string strXML = WebUtils::GetHttpXML(strTmp);
200
201 TiXmlDocument xmlDoc;
202 if (!xmlDoc.Parse(strXML.c_str()))
203 {
204 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
205 return false;
206 }
207
208 TiXmlHandle hDoc(&xmlDoc);
209
210 TiXmlElement* pElem = hDoc.FirstChildElement("e2servicelist").Element();
211
212 if (!pElem)
213 {
214 Logger::Log(LEVEL_ERROR, "%s Could not find <e2servicelist> element!", __FUNCTION__);
215 return false;
216 }
217
218 TiXmlHandle hRoot = TiXmlHandle(pElem);
219
220 TiXmlElement* pNode = hRoot.FirstChildElement("e2service").Element();
221
222 if (!pNode)
223 {
224 Logger::Log(LEVEL_ERROR, "%s Could not find <e2service> element", __FUNCTION__);
225 return false;
226 }
227
228 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2service"))
229 {
230 ChannelGroup newChannelGroup;
231
232 if (!newChannelGroup.UpdateFrom(pNode, false))
233 continue;
234
235 AddChannelGroup(newChannelGroup);
236
237 Logger::Log(LEVEL_INFO, "%s Loaded channelgroup: %s", __FUNCTION__, newChannelGroup.GetGroupName().c_str());
238 }
239 }
240
241 LoadChannelGroupsStartPosition(false);
242
243 if (Settings::GetInstance().GetTVFavouritesMode() == FavouritesGroupMode::AS_LAST_GROUP &&
244 Settings::GetInstance().GetTVChannelGroupMode() != ChannelGroupMode::FAVOURITES_GROUP)
245 {
246 AddTVFavouritesChannelGroup();
247 }
248
249 if ((!Settings::GetInstance().ExcludeLastScannedTVGroup() && Settings::GetInstance().GetTVChannelGroupMode() == ChannelGroupMode::ALL_GROUPS) ||
250 m_channelGroups.empty()) //If there are no channel groups default to including the last scanned group for TV Only
251 AddTVLastScannedChannelGroup();
252
253 Logger::Log(LEVEL_INFO, "%s Loaded %d TV Channelgroups", __FUNCTION__, m_channelGroups.size() - tempNumChannelGroups);
254 return true;
255 }
256
257 bool ChannelGroups::LoadRadioChannelGroups()
258 {
259 int tempNumChannelGroups = m_channelGroups.size();
260
261 if ((Settings::GetInstance().GetRadioFavouritesMode() == FavouritesGroupMode::AS_FIRST_GROUP &&
262 Settings::GetInstance().GetRadioChannelGroupMode() != ChannelGroupMode::FAVOURITES_GROUP) ||
263 Settings::GetInstance().GetRadioChannelGroupMode() == ChannelGroupMode::FAVOURITES_GROUP)
264 {
265 AddRadioFavouritesChannelGroup();
266 }
267
268 if (Settings::GetInstance().GetRadioChannelGroupMode() != ChannelGroupMode::FAVOURITES_GROUP)
269 {
270 const std::string strTmp = StringUtils::Format("%sweb/getservices?sRef=%s", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"bouquets.radio\" ORDER BY bouquet").c_str());
271
272 const std::string strXML = WebUtils::GetHttpXML(strTmp);
273
274 TiXmlDocument xmlDoc;
275 if (!xmlDoc.Parse(strXML.c_str()))
276 {
277 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
278 return false;
279 }
280
281 TiXmlHandle hDoc(&xmlDoc);
282
283 TiXmlElement* pElem = hDoc.FirstChildElement("e2servicelist").Element();
284
285 if (!pElem)
286 {
287 Logger::Log(LEVEL_ERROR, "%s Could not find <e2servicelist> element!", __FUNCTION__);
288 return false;
289 }
290
291 TiXmlHandle hRoot = TiXmlHandle(pElem);
292
293 TiXmlElement* pNode = hRoot.FirstChildElement("e2service").Element();
294
295 if (!pNode)
296 {
297 Logger::Log(LEVEL_ERROR, "%s Could not find <e2service> element", __FUNCTION__);
298 return false;
299 }
300
301 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2service"))
302 {
303 ChannelGroup newChannelGroup;
304
305 if (!newChannelGroup.UpdateFrom(pNode, true))
306 continue;
307
308 AddChannelGroup(newChannelGroup);
309
310 Logger::Log(LEVEL_INFO, "%s Loaded channelgroup: %s", __FUNCTION__, newChannelGroup.GetGroupName().c_str());
311 }
312 }
313
314 LoadChannelGroupsStartPosition(true);
315
316 if (Settings::GetInstance().GetRadioFavouritesMode() == FavouritesGroupMode::AS_LAST_GROUP &&
317 Settings::GetInstance().GetRadioChannelGroupMode() != ChannelGroupMode::FAVOURITES_GROUP)
318 {
319 AddRadioFavouritesChannelGroup();
320 }
321
322 if (!Settings::GetInstance().ExcludeLastScannedRadioGroup() && Settings::GetInstance().GetRadioChannelGroupMode() == ChannelGroupMode::ALL_GROUPS)
323 AddRadioLastScannedChannelGroup();
324
325 Logger::Log(LEVEL_INFO, "%s Loaded %d Radio Channelgroups", __FUNCTION__, m_channelGroups.size() - tempNumChannelGroups);
326 return true;
327 }
328
329 void ChannelGroups::AddTVFavouritesChannelGroup()
330 {
331 ChannelGroup newChannelGroup;
332 newChannelGroup.SetRadio(false);
333 newChannelGroup.SetGroupName(LocalizedString(30079)); //Favourites (TV)
334 newChannelGroup.SetServiceReference("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.favourites.tv\" ORDER BY bouquet");
335 AddChannelGroup(newChannelGroup);
336 Logger::Log(LEVEL_INFO, "%s Loaded channelgroup: %s", __FUNCTION__, newChannelGroup.GetGroupName().c_str());
337 }
338
339 void ChannelGroups::AddRadioFavouritesChannelGroup()
340 {
341 ChannelGroup newChannelGroup;
342 newChannelGroup.SetRadio(true);
343 newChannelGroup.SetGroupName(LocalizedString(30080)); //Favourites (Radio)
344 newChannelGroup.SetServiceReference("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.favourites.radio\" ORDER BY bouquet");
345 AddChannelGroup(newChannelGroup);
346 Logger::Log(LEVEL_INFO, "%s Loaded channelgroup: %s", __FUNCTION__, newChannelGroup.GetGroupName().c_str());
347 }
348
349 void ChannelGroups::AddTVLastScannedChannelGroup()
350 {
351 ChannelGroup newChannelGroup;
352 newChannelGroup.SetRadio(false);
353 newChannelGroup.SetGroupName(LocalizedString(30112)); //Last Scanned (TV)
354 newChannelGroup.SetServiceReference("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.LastScanned.tv\" ORDER BY bouquet");
355 newChannelGroup.SetLastScannedGroup(true);
356 AddChannelGroup(newChannelGroup);
357 Settings::GetInstance().SetUsesLastScannedChannelGroup(true);
358 Logger::Log(LEVEL_INFO, "%s Loaded channelgroup: %s", __FUNCTION__, newChannelGroup.GetGroupName().c_str());
359 }
360
361 void ChannelGroups::AddRadioLastScannedChannelGroup()
362 {
363 ChannelGroup newChannelGroup;
364 newChannelGroup.SetRadio(true);
365 newChannelGroup.SetGroupName(LocalizedString(30113)); //Last Scanned (Radio)
366 //Hack used here, extra space in service reference so we can spearate TV and Radio, it must be unique
367 newChannelGroup.SetServiceReference("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.LastScanned.tv\" ORDER BY bouquet");
368 newChannelGroup.SetLastScannedGroup(true);
369 AddChannelGroup(newChannelGroup);
370 Settings::GetInstance().SetUsesLastScannedChannelGroup(true);
371 Logger::Log(LEVEL_INFO, "%s Loaded channelgroup: %s", __FUNCTION__, newChannelGroup.GetGroupName().c_str());
372 }
373
374 void ChannelGroups::LoadChannelGroupsStartPosition(bool radio)
375 {
376 if (Settings::GetInstance().SupportsChannelNumberGroupStartPos())
377 {
378 //We can use the JSON API so let's supplement the existing groups with start channel numbers
379 std::string jsonURL;
380
381 if (!radio)
382 {
383 Logger::Log(LEVEL_INFO, "%s loading channel group start channel number for all TV groups", __FUNCTION__);
384 jsonURL = StringUtils::Format("%sapi/getservices", Settings::GetInstance().GetConnectionURL().c_str());
385 }
386 else
387 {
388 Logger::Log(LEVEL_INFO, "%s loading channel group start channel number for all Radio groups", __FUNCTION__);
389 jsonURL = StringUtils::Format("%sapi/getservices?sRef=%s", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"bouquets.radio\" ORDER BY bouquet").c_str());
390 }
391
392 const std::string strJson = WebUtils::GetHttpXML(jsonURL);
393
394 try
395 {
396 auto jsonDoc = json::parse(strJson);
397
398 if (!jsonDoc["services"].empty())
399 {
400 for (const auto& it : jsonDoc["services"].items())
401 {
402 auto jsonGroup = it.value();
403
404 std::string serviceReference = jsonGroup["servicereference"].get<std::string>();
405
406 // Check whether the current element is not just a label or that it's not a hidden entry
407 if (serviceReference.compare(0, 5, "1:64:") == 0 || serviceReference.compare(0, 6, "1:320:") == 0)
408 continue;
409
410 auto group = GetChannelGroup(serviceReference);
411
412 if (group)
413 {
414 if (!jsonGroup["startpos"].empty())
415 {
416 Logger::Log(LEVEL_DEBUG, "%s For Group %s, set start pos for channel number is %d", __FUNCTION__, jsonGroup["servicename"].get<std::string>().c_str(), jsonGroup["startpos"].get<int>());
417 group->SetStartChannelNumber(jsonGroup["startpos"].get<int>());
418 }
419 }
420 }
421 }
422 }
423 catch (nlohmann::detail::parse_error& e)
424 {
425 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot load start channel number for group from OpenWebIf - JSON parse error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
426 }
427 catch (nlohmann::detail::type_error& e)
428 {
429 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
430 }
431 }
432 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "data/Channel.h"
24 #include "data/ChannelGroup.h"
25 #include "kodi/libXBMC_pvr.h"
26
27 #include <memory>
28 #include <string>
29 #include <unordered_map>
30 #include <vector>
31
32 namespace enigma2
33 {
34 class ChannelGroups
35 {
36 public:
37 void GetChannelGroups(std::vector<PVR_CHANNEL_GROUP>& channelGroups, bool radio) const;
38 PVR_ERROR GetChannelGroupMembers(std::vector<PVR_CHANNEL_GROUP_MEMBER>& channelGroupMembers, const std::string& groupName);
39
40 std::string GetChannelGroupServiceReference(const std::string& groupName);
41 std::shared_ptr<enigma2::data::ChannelGroup> GetChannelGroup(const std::string& groupServiceReference);
42 std::shared_ptr<enigma2::data::ChannelGroup> GetChannelGroupUsingName(const std::string& groupName);
43 bool IsValid(std::string groupName);
44 int GetNumChannelGroups() const;
45 void ClearChannelGroups();
46 std::vector<std::shared_ptr<enigma2::data::ChannelGroup>>& GetChannelGroupsList();
47 bool LoadChannelGroups();
48
49 private:
50 bool LoadTVChannelGroups();
51 bool LoadRadioChannelGroups();
52 void AddTVFavouritesChannelGroup();
53 void AddRadioFavouritesChannelGroup();
54 void AddTVLastScannedChannelGroup();
55 void AddRadioLastScannedChannelGroup();
56 void AddChannelGroup(enigma2::data::ChannelGroup& channelGroup);
57 void LoadChannelGroupsStartPosition(bool radio);
58
59 std::vector<std::shared_ptr<enigma2::data::ChannelGroup>> m_channelGroups;
60 std::unordered_map<std::string, std::shared_ptr<enigma2::data::ChannelGroup>> m_channelGroupsNameMap;
61 std::unordered_map<std::string, std::shared_ptr<enigma2::data::ChannelGroup>> m_channelGroupsServiceReferenceMap;
62 };
63 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Channels.h"
23
24 #include "../Enigma2.h"
25 #include "../client.h"
26 #include "Admin.h"
27 #include "ChannelGroups.h"
28 #include "p8-platform/util/StringUtils.h"
29 #include "util/XMLUtils.h"
30 #include "utilities/Logger.h"
31 #include "utilities/WebUtils.h"
32
33 #include <regex>
34
35 #include <nlohmann/json.hpp>
36
37 using namespace enigma2;
38 using namespace enigma2::data;
39 using namespace enigma2::utilities;
40 using json = nlohmann::json;
41
42 namespace
43 {
44
45 int GenerateChannelUniqueId(const std::string& channelName, const std::string& extendedServiceReference)
46 {
47 std::string concat(channelName);
48 concat.append(extendedServiceReference);
49
50 const char* calcString = concat.c_str();
51 int uniqueId = 0;
52 int c;
53 while ((c = *calcString++))
54 uniqueId = ((uniqueId << 5) + uniqueId) + c; /* iId * 33 + c */
55
56 return abs(uniqueId);
57 }
58
59 } // unnamed namespace
60
61 void Channels::GetChannels(std::vector<PVR_CHANNEL>& kodiChannels, bool bRadio) const
62 {
63 for (const auto& channel : m_channels)
64 {
65 if (channel->IsRadio() == bRadio)
66 {
67 Logger::Log(LEVEL_DEBUG, "%s - Transfer channel '%s', ChannelIndex '%d'", __FUNCTION__, channel->GetChannelName().c_str(),
68 channel->GetUniqueId());
69 PVR_CHANNEL kodiChannel = {0};
70
71 channel->UpdateTo(kodiChannel);
72
73 kodiChannels.emplace_back(kodiChannel);
74 }
75 }
76 }
77
78 int Channels::GetChannelUniqueId(const std::string& channelServiceReference)
79 {
80 std::shared_ptr<Channel> channel = GetChannel(channelServiceReference);
81 int uniqueId = PVR_CHANNEL_INVALID_UID;
82
83 if (channel)
84 uniqueId = channel->GetUniqueId();
85
86 return uniqueId;
87 }
88
89 std::shared_ptr<Channel> Channels::GetChannel(int uniqueId)
90 {
91 auto channelPair = m_channelsUniqueIdMap.find(uniqueId);
92 if (channelPair != m_channelsUniqueIdMap.end())
93 return channelPair->second;
94
95 return {};
96 }
97
98 std::shared_ptr<Channel> Channels::GetChannel(const std::string& channelServiceReference)
99 {
100 auto channelPair = m_channelsServiceReferenceMap.find(channelServiceReference);
101 if (channelPair != m_channelsServiceReferenceMap.end())
102 return channelPair->second;
103
104 return {};
105 }
106
107 std::shared_ptr<Channel> Channels::GetChannel(const std::string& channelName, bool isRadio)
108 {
109 for (const auto& channel : m_channels)
110 {
111 if (channelName == channel->GetChannelName() && isRadio == channel->IsRadio())
112 return channel;
113 }
114
115 return nullptr;
116 }
117
118 bool Channels::IsValid(int uniqueId)
119 {
120 return GetChannel(uniqueId) != nullptr;
121 }
122
123 bool Channels::IsValid(const std::string &channelServiceReference)
124 {
125 return GetChannel(channelServiceReference) != nullptr;
126 }
127
128 int Channels::GetNumChannels() const
129 {
130 return m_channels.size();
131 }
132
133 void Channels::ClearChannels()
134 {
135 m_channels.clear();
136 m_channelsUniqueIdMap.clear();
137 m_channelsServiceReferenceMap.clear();
138 }
139
140 void Channels::AddChannel(Channel& newChannel, std::shared_ptr<ChannelGroup>& channelGroup)
141 {
142 std::shared_ptr<Channel> foundChannel = GetChannel(newChannel.GetServiceReference());
143
144 if (!foundChannel)
145 {
146 newChannel.SetUniqueId(GenerateChannelUniqueId(newChannel.GetChannelName(), newChannel.GetExtendedServiceReference()));
147 newChannel.SetChannelNumber(m_channels.size() + 1);
148
149 m_channels.emplace_back(new Channel(newChannel));
150
151 std::shared_ptr<Channel> channel = m_channels.back();
152 channel->AddChannelGroup(channelGroup);
153 channelGroup->AddChannel(channel);
154
155 m_channelsUniqueIdMap.insert({channel->GetUniqueId(), channel});
156 m_channelsServiceReferenceMap.insert({channel->GetServiceReference(), channel});
157 }
158 else
159 {
160 foundChannel->AddChannelGroup(channelGroup);
161 channelGroup->AddChannel(foundChannel);
162 }
163 }
164
165 std::vector<std::shared_ptr<Channel>>& Channels::GetChannelsList()
166 {
167 return m_channels;
168 }
169
170 std::string Channels::GetChannelIconPath(std::string& channelName)
171 {
172 for (const auto& channel : m_channels)
173 {
174 if (channelName == channel->GetChannelName())
175 return channel->GetIconPath();
176 }
177 return "";
178 }
179
180 bool Channels::LoadChannels(ChannelGroups& channelGroups)
181 {
182 m_channelGroups = channelGroups;
183
184 bool bOk = false;
185
186 ClearChannels();
187 // Load Channels
188 for (auto& group : channelGroups.GetChannelGroupsList())
189 {
190 if (LoadChannels(group->GetServiceReference(), group->GetGroupName(), group))
191 bOk = true;
192 }
193
194 // Load Channels extra data for groups
195 int tvChannelNumberOffset = 0;
196 int radioChannelNumberOffset = 0;
197 for (const auto& group : channelGroups.GetChannelGroupsList())
198 {
199 if (group->IsRadio())
200 radioChannelNumberOffset = LoadChannelsExtraData(group, radioChannelNumberOffset);
201 else
202 tvChannelNumberOffset = LoadChannelsExtraData(group, tvChannelNumberOffset);
203 }
204
205 return bOk;
206 }
207
208 bool Channels::LoadChannels(const std::string groupServiceReference, const std::string groupName, std::shared_ptr<ChannelGroup>& channelGroup)
209 {
210 Logger::Log(LEVEL_INFO, "%s loading channel group: '%s'", __FUNCTION__, groupName.c_str());
211
212 const std::string strTmp = StringUtils::Format("%sweb/getservices?sRef=%s", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline(groupServiceReference).c_str());
213
214 const std::string strXML = WebUtils::GetHttpXML(strTmp);
215
216 TiXmlDocument xmlDoc;
217 if (!xmlDoc.Parse(strXML.c_str()))
218 {
219 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
220 return false;
221 }
222
223 TiXmlHandle hDoc(&xmlDoc);
224
225 TiXmlElement* pElem = hDoc.FirstChildElement("e2servicelist").Element();
226
227 if (!pElem)
228 {
229 Logger::Log(LEVEL_ERROR, "%s Could not find <e2servicelist> element!", __FUNCTION__);
230 return false;
231 }
232
233 TiXmlHandle hRoot = TiXmlHandle(pElem);
234
235 TiXmlElement* pNode = hRoot.FirstChildElement("e2service").Element();
236
237 if (!pNode)
238 {
239 Logger::Log(LEVEL_ERROR, "%s Could not find <e2service> element", __FUNCTION__);
240 return false;
241 }
242
243 bool emptyGroup = true;
244
245 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2service"))
246 {
247 Channel newChannel;
248 newChannel.SetRadio(channelGroup->IsRadio());
249
250 if (!newChannel.UpdateFrom(pNode))
251 continue;
252 else
253 emptyGroup = false;
254
255 AddChannel(newChannel, channelGroup);
256 Logger::Log(LEVEL_DEBUG, "%s Loaded channel: %s, Group: %s, Icon: %s, ID: %d", __FUNCTION__, newChannel.GetChannelName().c_str(), groupName.c_str(), newChannel.GetIconPath().c_str(), newChannel.GetUniqueId());
257 }
258
259 channelGroup->SetEmptyGroup(emptyGroup);
260
261 Logger::Log(LEVEL_INFO, "%s Loaded %d Channels", __FUNCTION__, GetNumChannels());
262
263 return true;
264 }
265
266 int Channels::LoadChannelsExtraData(const std::shared_ptr<enigma2::data::ChannelGroup> channelGroup, int lastGroupLatestChannelPosition)
267 {
268 int newChannelPositionOffset = channelGroup->GetStartChannelNumber();
269
270 // In case we don't have a start channel number for this group just use the latest
271 if (!channelGroup->HasStartChannelNumber())
272 newChannelPositionOffset = lastGroupLatestChannelPosition;
273
274 if (Settings::GetInstance().SupportsProviderNumberAndPiconForChannels())
275 {
276 Logger::Log(LEVEL_INFO, "%s loading channel group extra data: '%s'", __FUNCTION__, channelGroup->GetGroupName().c_str());
277
278 //We can use the JSON API so let's supplement the data with extra information
279
280 const std::string jsonURL = StringUtils::Format("%sapi/getservices?provider=1&picon=1&sRef=%s", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline(channelGroup->GetServiceReference()).c_str());
281 const std::string strJson = WebUtils::GetHttpXML(jsonURL);
282
283 try
284 {
285 auto jsonDoc = json::parse(strJson);
286
287 if (!jsonDoc["services"].empty())
288 {
289 for (const auto& it : jsonDoc["services"].items())
290 {
291 auto jsonChannel = it.value();
292
293 std::string serviceReference = jsonChannel["servicereference"].get<std::string>();
294
295 // Check whether the current element is not just a label or that it's not a hidden entry
296 if (serviceReference.compare(0, 5, "1:64:") == 0 || serviceReference.compare(0, 6, "1:320:") == 0)
297 continue;
298
299 if (Settings::GetInstance().UseStandardServiceReference())
300 {
301 serviceReference = Channel::CreateStandardServiceReference(serviceReference);
302 }
303
304 auto channel = GetChannel(serviceReference);
305
306 if (channel)
307 {
308 if (!jsonChannel["provider"].empty())
309 {
310 Logger::Log(LEVEL_DEBUG, "%s For Channel %s, set provider name to %s", __FUNCTION__, jsonChannel["servicename"].get<std::string>().c_str(), jsonChannel["provider"].get<std::string>().c_str());
311 channel->SetProviderlName(jsonChannel["provider"].get<std::string>());
312 }
313
314 if (!jsonChannel["pos"].empty() && channel->UsingDefaultChannelNumber() && Settings::GetInstance().SupportsChannelNumberGroupStartPos())
315 {
316 Logger::Log(LEVEL_DEBUG, "%s For Channel %s, set backend channel number to %d", __FUNCTION__, jsonChannel["servicename"].get<std::string>().c_str(), jsonChannel["pos"].get<int>());
317 channel->SetChannelNumber(jsonChannel["pos"].get<int>() + lastGroupLatestChannelPosition);
318 channel->SetUsingDefaultChannelNumber(false);
319 }
320
321 if (Settings::GetInstance().UseOpenWebIfPiconPath())
322 {
323 if (!jsonChannel["picon"].empty())
324 {
325 std::string connectionURL = Settings::GetInstance().GetConnectionURL();
326 connectionURL = connectionURL.substr(0, connectionURL.size() - 1);
327 channel->SetIconPath(StringUtils::Format("%s%s", connectionURL.c_str(), jsonChannel["picon"].get<std::string>().c_str()));
328
329 Logger::Log(LEVEL_DEBUG, "%s For Channel %s, using OpenWebPiconPath: %s", __FUNCTION__, jsonChannel["servicename"].get<std::string>().c_str(), channel->GetIconPath().c_str());
330 }
331 }
332 }
333 }
334 }
335
336 if (!jsonDoc["pos"].empty())
337 {
338 newChannelPositionOffset += jsonDoc["pos"].get<int>();
339
340 Logger::Log(LEVEL_DEBUG, "%s For groupName %s, highest backend channel number offset is %d", __FUNCTION__, channelGroup->GetGroupName().c_str(), newChannelPositionOffset);
341 }
342 }
343 catch (nlohmann::detail::parse_error& e)
344 {
345 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot load provider or picon paths from OpenWebIf - JSON parse error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
346 }
347 catch (nlohmann::detail::type_error& e)
348 {
349 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
350 }
351 }
352
353 return newChannelPositionOffset;
354 }
355
356 ChannelsChangeState Channels::CheckForChannelAndGroupChanges(enigma2::ChannelGroups& latestChannelGroups, enigma2::Channels& latestChannels)
357 {
358 if (GetNumChannels() != latestChannels.GetNumChannels())
359 return ChannelsChangeState::CHANNELS_CHANGED;
360
361 int foundCount = 0;
362 for (const auto& channel : m_channels)
363 {
364 const std::shared_ptr<Channel> channelPtr = latestChannels.GetChannel(channel->GetServiceReference());
365
366 if (channelPtr)
367 {
368 foundCount++;
369
370 if (*channelPtr != *channel)
371 {
372 return ChannelsChangeState::CHANNELS_CHANGED;
373 }
374 }
375 }
376
377 if (foundCount != GetNumChannels())
378 return ChannelsChangeState::CHANNELS_CHANGED;
379
380 // Now check the groups
381 if (m_channelGroups.GetNumChannelGroups() != latestChannelGroups.GetNumChannelGroups())
382 return ChannelsChangeState::CHANNEL_GROUPS_CHANGED;
383
384 foundCount = 0;
385 for (const auto& group : m_channelGroups.GetChannelGroupsList())
386 {
387 const std::shared_ptr<ChannelGroup> channelGroupPtr = latestChannelGroups.GetChannelGroupUsingName(group->GetGroupName());
388
389 if (channelGroupPtr)
390 {
391 foundCount++;
392
393 if (*channelGroupPtr != *group)
394 {
395 return ChannelsChangeState::CHANNEL_GROUPS_CHANGED;
396 }
397 }
398 }
399
400 if (foundCount != m_channelGroups.GetNumChannelGroups())
401 return ChannelsChangeState::CHANNEL_GROUPS_CHANGED;
402
403 return ChannelsChangeState::NO_CHANGE;
404 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "ChannelGroups.h"
24 #include "data/Channel.h"
25 #include "kodi/libXBMC_pvr.h"
26
27 #include <memory>
28 #include <string>
29 #include <unordered_map>
30 #include <vector>
31
32 namespace enigma2
33 {
34 class ChannelGroups;
35
36 namespace data
37 {
38 class ChannelGroup;
39 }
40
41 enum class ChannelsChangeState : int // same type as addon settings
42 {
43 NO_CHANGE = 0,
44 CHANNEL_GROUPS_CHANGED,
45 CHANNELS_CHANGED
46 };
47
48 class Channels
49 {
50 public:
51 void GetChannels(std::vector<PVR_CHANNEL>& timers, bool bRadio) const;
52
53 int GetChannelUniqueId(const std::string& channelServiceReference);
54 std::shared_ptr<enigma2::data::Channel> GetChannel(int uniqueId);
55 std::shared_ptr<enigma2::data::Channel> GetChannel(const std::string& channelServiceReference);
56 std::shared_ptr<enigma2::data::Channel> GetChannel(const std::string& channelName, bool isRadio);
57 bool IsValid(int uniqueId);
58 bool IsValid(const std::string& channelServiceReference);
59 int GetNumChannels() const;
60 void ClearChannels();
61 std::vector<std::shared_ptr<enigma2::data::Channel>>& GetChannelsList();
62 std::string GetChannelIconPath(std::string& channelName);
63 bool LoadChannels(enigma2::ChannelGroups& channelGroups);
64
65 ChannelsChangeState CheckForChannelAndGroupChanges(enigma2::ChannelGroups& latestChannelGroups, enigma2::Channels& latestChannels);
66
67 private:
68 void AddChannel(enigma2::data::Channel& channel, std::shared_ptr<enigma2::data::ChannelGroup>& channelGroup);
69 bool LoadChannels(const std::string groupServiceReference,
70 const std::string groupName,
71 std::shared_ptr<enigma2::data::ChannelGroup>& channelGroup);
72 int LoadChannelsExtraData(const std::shared_ptr<enigma2::data::ChannelGroup> channelGroup, int lastGroupLatestChannelPosition);
73
74 std::vector<std::shared_ptr<enigma2::data::Channel>> m_channels;
75 std::unordered_map<int, std::shared_ptr<enigma2::data::Channel>> m_channelsUniqueIdMap;
76 std::unordered_map<std::string, std::shared_ptr<enigma2::data::Channel>> m_channelsServiceReferenceMap;
77
78 ChannelGroups m_channelGroups;
79 };
80 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 * http://www.gnu.org/copyleft/gpl.html
18 *
19 */
20
21 #include "ConnectionManager.h"
22
23 #include "../client.h"
24 #include "IConnectionListener.h"
25 #include "Settings.h"
26 #include "p8-platform/os.h"
27 #include "p8-platform/util/StringUtils.h"
28 #include "utilities/Logger.h"
29 #include "utilities/WebUtils.h"
30
31 using namespace P8PLATFORM;
32 using namespace enigma2;
33 using namespace enigma2::utilities;
34
35 /*
36 * Enigma2 Connection handler
37 */
38
39 ConnectionManager::ConnectionManager(IConnectionListener& connectionListener)
40 : m_connectionListener(connectionListener), m_suspended(false), m_state(PVR_CONNECTION_STATE_UNKNOWN)
41 {
42 }
43
44 ConnectionManager::~ConnectionManager()
45 {
46 StopThread(-1);
47 Disconnect();
48 StopThread(0);
49 }
50
51 void ConnectionManager::Start()
52 {
53 // Note: "connecting" must only be set one time, before the very first connection attempt, not on every reconnect.
54 SetState(PVR_CONNECTION_STATE_CONNECTING);
55 CreateThread();
56 }
57
58 void ConnectionManager::Stop()
59 {
60 StopThread(-1);
61 Disconnect();
62 }
63
64 void ConnectionManager::OnSleep()
65 {
66 CLockObject lock(m_mutex);
67
68 Logger::Log(LogLevel::LEVEL_DEBUG, "%s going to sleep", __FUNCTION__);
69
70 m_suspended = true;
71 }
72
73 void ConnectionManager::OnWake()
74 {
75 CLockObject lock(m_mutex);
76
77 Logger::Log(LogLevel::LEVEL_DEBUG, "%s Waking up", __FUNCTION__);
78
79 m_suspended = false;
80 }
81
82 void ConnectionManager::SetState(PVR_CONNECTION_STATE state)
83 {
84 PVR_CONNECTION_STATE prevState(PVR_CONNECTION_STATE_UNKNOWN);
85 PVR_CONNECTION_STATE newState(PVR_CONNECTION_STATE_UNKNOWN);
86
87 {
88 CLockObject lock(m_mutex);
89
90 /* No notification if no state change or while suspended. */
91 if (m_state != state && !m_suspended)
92 {
93 prevState = m_state;
94 newState = state;
95 m_state = newState;
96
97 Logger::Log(LogLevel::LEVEL_DEBUG, "connection state change (%d -> %d)", prevState, newState);
98 }
99 }
100
101 if (prevState != newState)
102 {
103 static std::string serverString;
104
105 if (newState == PVR_CONNECTION_STATE_SERVER_UNREACHABLE)
106 {
107 m_connectionListener.ConnectionLost();
108 }
109 else if (newState == PVR_CONNECTION_STATE_CONNECTED)
110 {
111 m_connectionListener.ConnectionEstablished();
112 }
113
114 /* Notify connection state change (callback!) */
115 PVR->ConnectionStateChange(Settings::GetInstance().GetConnectionURL().c_str(), newState, NULL);
116 }
117 }
118
119 void ConnectionManager::Disconnect()
120 {
121 CLockObject lock(m_mutex);
122
123 m_connectionListener.ConnectionLost();
124 }
125
126 void ConnectionManager::Reconnect()
127 {
128 // Setting this state will cause Enigma2 to receive a connetionLost event
129 // The connection manager will then connect again causeing a reload of all state
130 SetState(PVR_CONNECTION_STATE_SERVER_UNREACHABLE);
131 }
132
133 void* ConnectionManager::Process()
134 {
135 static bool log = false;
136 static unsigned int retryAttempt = 0;
137 int fastReconnectIntervalMs = (Settings::GetInstance().GetConnectioncCheckIntervalSecs() * 1000) / 2;
138 int intervalMs = Settings::GetInstance().GetConnectioncCheckIntervalSecs() * 1000;
139
140 while (!IsStopped())
141 {
142 while (m_suspended)
143 {
144 Logger::Log(LogLevel::LEVEL_DEBUG, "%s - suspended, waiting for wakeup...", __FUNCTION__);
145
146 /* Wait for wakeup */
147 SteppedSleep(intervalMs);
148 }
149
150 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/currenttime");
151
152 /* Connect */
153 if (!WebUtils::CheckHttp(url))
154 {
155 /* Unable to connect */
156 if (retryAttempt == 0)
157 Logger::Log(LogLevel::LEVEL_ERROR, "%s - unable to connect to: %s", __FUNCTION__, url.c_str());
158 SetState(PVR_CONNECTION_STATE_SERVER_UNREACHABLE);
159
160 // Retry a few times with a short interval, after that with the default timeout
161 if (++retryAttempt <= FAST_RECONNECT_ATTEMPTS)
162 SteppedSleep(fastReconnectIntervalMs);
163 else
164 SteppedSleep(intervalMs);
165
166 continue;
167 }
168
169 SetState(PVR_CONNECTION_STATE_CONNECTED);
170 retryAttempt = 0;
171
172 SteppedSleep(intervalMs);
173 }
174
175 return nullptr;
176 }
177
178 void ConnectionManager::SteppedSleep(int intervalMs)
179 {
180 int sleepCountMs = 0;
181
182 while (sleepCountMs <= intervalMs)
183 {
184 if (!IsStopped())
185 Sleep(SLEEP_INTERVAL_STEP_MS);
186
187 sleepCountMs += SLEEP_INTERVAL_STEP_MS;
188 }
189 }
0 #pragma once
1
2 /*
3 * Copyright (C) 2005-2019 Team XBMC
4 * http://www.xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, write to
18 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1335, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 *
22 */
23
24 #include "kodi/libXBMC_pvr.h"
25 #include "p8-platform/threads/mutex.h"
26 #include "p8-platform/threads/threads.h"
27
28 #include <string>
29
30 namespace enigma2
31 {
32 static const int FAST_RECONNECT_ATTEMPTS = 5;
33 static const int SLEEP_INTERVAL_STEP_MS = 500;
34
35 class IConnectionListener;
36
37 class ConnectionManager : public P8PLATFORM::CThread
38 {
39 public:
40 ConnectionManager(IConnectionListener& connectionListener);
41 ~ConnectionManager() override;
42
43 void Start();
44 void Stop();
45 void Disconnect();
46 void Reconnect();
47
48 void OnSleep();
49 void OnWake();
50
51 private:
52 void* Process() override;
53 void SetState(PVR_CONNECTION_STATE state);
54 void SteppedSleep(int intervalMs);
55
56 IConnectionListener& m_connectionListener;
57 mutable P8PLATFORM::CMutex m_mutex;
58 bool m_suspended;
59 PVR_CONNECTION_STATE m_state;
60 };
61 } // namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Epg.h"
23
24 #include "../Enigma2.h"
25 #include "../client.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "util/XMLUtils.h"
28 #include "utilities/Logger.h"
29 #include "utilities/WebUtils.h"
30
31 #include <chrono>
32 #include <cmath>
33 #include <regex>
34
35 #include <nlohmann/json.hpp>
36
37 using namespace enigma2;
38 using namespace enigma2::data;
39 using namespace enigma2::extract;
40 using namespace enigma2::utilities;
41 using namespace P8PLATFORM;
42 using json = nlohmann::json;
43
44 Epg::Epg(enigma2::extract::EpgEntryExtractor& entryExtractor, int epgMaxDays)
45 : m_entryExtractor(entryExtractor), m_epgMaxDays(epgMaxDays) {}
46
47 Epg::Epg(const Epg& epg) : m_entryExtractor(epg.m_entryExtractor) {}
48
49 bool Epg::Initialise(enigma2::Channels& channels, enigma2::ChannelGroups& channelGroups)
50 {
51 SetEPGTimeFrame(m_epgMaxDays);
52
53 auto started = std::chrono::high_resolution_clock::now();
54 Logger::Log(LEVEL_DEBUG, "%s Initial EPG Load Start", __FUNCTION__);
55
56 //clear current data structures
57 m_epgChannels.clear();
58 m_epgChannelsMap.clear();
59 m_readInitialEpgChannelsMap.clear();
60 m_needsInitialEpgChannelsMap.clear();
61 m_initialEpgReady = false;
62
63 //add an initial EPG data per channel uId, sref and initial EPG
64 for (auto& channel : channels.GetChannelsList())
65 {
66 std::shared_ptr<data::EpgChannel> newEpgChannel = std::make_shared<EpgChannel>();
67
68 newEpgChannel->SetRadio(channel->IsRadio());
69 newEpgChannel->SetUniqueId(channel->GetUniqueId());
70 newEpgChannel->SetChannelName(channel->GetChannelName());
71 newEpgChannel->SetServiceReference(channel->GetServiceReference());
72
73 m_epgChannels.emplace_back(newEpgChannel);
74
75 m_epgChannelsMap.insert({newEpgChannel->GetServiceReference(), newEpgChannel});
76 m_readInitialEpgChannelsMap.insert({newEpgChannel->GetServiceReference(), newEpgChannel});
77 m_needsInitialEpgChannelsMap.insert({newEpgChannel->GetServiceReference(), newEpgChannel});
78 }
79
80 int lastScannedIgnoreSuccessCount = std::round((1 - LAST_SCANNED_INITIAL_EPG_SUCCESS_PERCENT) * m_epgChannels.size());
81
82 std::vector<std::shared_ptr<ChannelGroup>> groupList;
83
84 std::shared_ptr<ChannelGroup> newChannelGroup = std::make_shared<ChannelGroup>();
85 newChannelGroup->SetRadio(false);
86 newChannelGroup->SetGroupName("Last Scanned"); //Name not important
87 newChannelGroup->SetServiceReference("1:7:1:0:0:0:0:0:0:0:FROM BOUQUET \"userbouquet.LastScanned.tv\" ORDER BY bouquet");
88 newChannelGroup->SetLastScannedGroup(true);
89
90 groupList.emplace_back(newChannelGroup);
91 for (auto& group : channelGroups.GetChannelGroupsList())
92 {
93 if (!group->IsLastScannedGroup())
94 groupList.emplace_back(group);
95 }
96
97 //load each group and if we don't already have it's intial EPG then load those entries
98 for (auto& group : groupList)
99 {
100 LoadInitialEPGForGroup(group);
101
102 //Remove channels that now have an initial EPG
103 for (auto& epgChannel : m_epgChannels)
104 {
105 if (epgChannel->GetInitialEPG().size() > 0)
106 InitialEpgLoadedForChannel(epgChannel->GetServiceReference());
107 }
108
109 Logger::Log(LEVEL_DEBUG, "%s Initial EPG Progress - Remaining channels %d, Min Channels for completion %d", __FUNCTION__, m_needsInitialEpgChannelsMap.size(), lastScannedIgnoreSuccessCount);
110
111 for (auto pair : m_needsInitialEpgChannelsMap)
112 Logger::Log(LEVEL_DEBUG, "%s - Initial EPG Progress - Remaining channel: %s - sref: %s", __FUNCTION__, pair.second->GetChannelName().c_str(), pair.first.c_str());
113
114 if (group->IsLastScannedGroup() && m_needsInitialEpgChannelsMap.size() <= lastScannedIgnoreSuccessCount)
115 break;
116 }
117
118 int milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - started).count();
119
120 Logger::Log(LEVEL_NOTICE, "%s Initial EPG Loaded - %d (ms)", __FUNCTION__, milliseconds);
121
122 m_initialEpgReady = true;
123
124 return true;
125 }
126
127 std::shared_ptr<data::EpgChannel> Epg::GetEpgChannel(const std::string& serviceReference)
128 {
129 std::shared_ptr<data::EpgChannel> epgChannel = std::make_shared<data::EpgChannel>();
130
131 auto epgChannelSearch = m_epgChannelsMap.find(serviceReference);
132 if (epgChannelSearch != m_epgChannelsMap.end())
133 epgChannel = epgChannelSearch->second;
134
135 return epgChannel;
136 }
137
138 std::shared_ptr<data::EpgChannel> Epg::GetEpgChannelNeedingInitialEpg(const std::string& serviceReference)
139 {
140 std::shared_ptr<data::EpgChannel> epgChannel = std::make_shared<data::EpgChannel>();
141
142 auto initialEpgChannelSearch = m_needsInitialEpgChannelsMap.find(serviceReference);
143 if (initialEpgChannelSearch != m_needsInitialEpgChannelsMap.end())
144 epgChannel = initialEpgChannelSearch->second;
145
146 return epgChannel;
147 }
148
149 bool Epg::ChannelNeedsInitialEpg(const std::string& serviceReference)
150 {
151 auto needsInitialEpgSearch = m_needsInitialEpgChannelsMap.find(serviceReference);
152
153 return needsInitialEpgSearch != m_needsInitialEpgChannelsMap.end();
154 }
155
156 bool Epg::InitialEpgLoadedForChannel(const std::string& serviceReference)
157 {
158 return m_needsInitialEpgChannelsMap.erase(serviceReference) == 1;
159 }
160
161 bool Epg::IsInitialEpgCompleted()
162 {
163 Logger::Log(LEVEL_DEBUG, "%s Waiting to Get Initial EPG for %d remaining channels", __FUNCTION__, m_readInitialEpgChannelsMap.size());
164
165 return m_readInitialEpgChannelsMap.size() == 0;
166 }
167
168 void Epg::TriggerEpgUpdatesForChannels()
169 {
170 for (auto& epgChannel : m_epgChannels)
171 {
172 //We want to trigger full updates only so let's make sure it's not an initialEpg
173 if (epgChannel->RequiresInitialEpg())
174 {
175 epgChannel->SetRequiresInitialEpg(false);
176 epgChannel->GetInitialEPG().clear();
177 m_readInitialEpgChannelsMap.erase(epgChannel->GetServiceReference());
178 }
179
180 Logger::Log(LEVEL_DEBUG, "%s - Trigger EPG update for channel: %s (%d)", __FUNCTION__, epgChannel->GetChannelName().c_str(), epgChannel->GetUniqueId());
181 PVR->TriggerEpgUpdate(epgChannel->GetUniqueId());
182 }
183 }
184
185 void Epg::MarkChannelAsInitialEpgRead(const std::string& serviceReference)
186 {
187 std::shared_ptr<data::EpgChannel> epgChannel = GetEpgChannel(serviceReference);
188
189 if (epgChannel->RequiresInitialEpg())
190 {
191 epgChannel->SetRequiresInitialEpg(false);
192 epgChannel->GetInitialEPG().clear();
193 m_readInitialEpgChannelsMap.erase(epgChannel->GetServiceReference());
194 }
195 }
196
197 PVR_ERROR Epg::GetEPGForChannel(ADDON_HANDLE handle, const std::string& serviceReference, time_t iStart, time_t iEnd)
198 {
199 std::shared_ptr<data::EpgChannel> epgChannel = GetEpgChannel(serviceReference);
200
201 if (epgChannel)
202 {
203 Logger::Log(LEVEL_DEBUG, "%s Getting EPG for channel '%s'", __FUNCTION__, epgChannel->GetChannelName().c_str());
204
205 if (epgChannel->RequiresInitialEpg())
206 {
207 epgChannel->SetRequiresInitialEpg(false);
208
209 return TransferInitialEPGForChannel(handle, epgChannel, iStart, iEnd);
210 }
211
212 const std::string url = StringUtils::Format("%s%s%s", Settings::GetInstance().GetConnectionURL().c_str(),
213 "web/epgservice?sRef=", WebUtils::URLEncodeInline(serviceReference).c_str());
214
215 const std::string strXML = WebUtils::GetHttpXML(url);
216
217 int iNumEPG = 0;
218
219 TiXmlDocument xmlDoc;
220 if (!xmlDoc.Parse(strXML.c_str()))
221 {
222 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
223 return PVR_ERROR_SERVER_ERROR;
224 }
225
226 TiXmlHandle hDoc(&xmlDoc);
227
228 TiXmlElement* pElem = hDoc.FirstChildElement("e2eventlist").Element();
229
230 if (!pElem)
231 {
232 Logger::Log(LEVEL_NOTICE, "%s could not find <e2eventlist> element!", __FUNCTION__);
233 // Return "NO_ERROR" as the EPG could be empty for this channel
234 return PVR_ERROR_NO_ERROR;
235 }
236
237 TiXmlHandle hRoot = TiXmlHandle(pElem);
238
239 TiXmlElement* pNode = hRoot.FirstChildElement("e2event").Element();
240
241 if (!pNode)
242 {
243 Logger::Log(LEVEL_NOTICE, "%s Could not find <e2event> element", __FUNCTION__);
244 // RETURN "NO_ERROR" as the EPG could be empty for this channel
245 return PVR_ERROR_NO_ERROR;
246 }
247
248 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2event"))
249 {
250 EpgEntry entry;
251
252 if (!entry.UpdateFrom(pNode, epgChannel, iStart, iEnd))
253 continue;
254
255 if (m_entryExtractor.IsEnabled())
256 m_entryExtractor.ExtractFromEntry(entry);
257
258 EPG_TAG broadcast = {0};
259
260 entry.UpdateTo(broadcast);
261
262 PVR->TransferEpgEntry(handle, &broadcast);
263
264 iNumEPG++;
265
266 Logger::Log(LEVEL_TRACE, "%s loaded EPG entry '%d:%s' channel '%d' start '%d' end '%d'", __FUNCTION__, broadcast.iUniqueBroadcastId, broadcast.strTitle, entry.GetChannelId(), entry.GetStartTime(), entry.GetEndTime());
267 }
268
269 iNumEPG += TransferTimerBasedEntries(handle, epgChannel->GetUniqueId());
270
271 Logger::Log(LEVEL_INFO, "%s Loaded %u EPG Entries for channel '%s'", __FUNCTION__, iNumEPG, epgChannel->GetChannelName().c_str());
272 }
273 else
274 {
275 Logger::Log(LEVEL_NOTICE, "%s EPG requested for unknown channel reference: '%s'", __FUNCTION__, serviceReference.c_str());
276 }
277
278
279 return PVR_ERROR_NO_ERROR;
280 }
281
282 void Epg::SetEPGTimeFrame(int epgMaxDays)
283 {
284 CLockObject lock(m_mutex);
285
286 m_epgMaxDays = epgMaxDays;
287
288 if (m_epgMaxDays > 0)
289 m_epgMaxDaysSeconds = m_epgMaxDays * 24 * 60 * 60;
290 else
291 m_epgMaxDaysSeconds = DEFAULT_EPG_MAX_DAYS * 24 * 60 * 60;
292 }
293
294 PVR_ERROR Epg::TransferInitialEPGForChannel(ADDON_HANDLE handle, const std::shared_ptr<EpgChannel>& epgChannel, time_t iStart, time_t iEnd)
295 {
296 for (const auto& entry : epgChannel->GetInitialEPG())
297 {
298 EPG_TAG broadcast = {0};
299
300 entry.UpdateTo(broadcast);
301
302 PVR->TransferEpgEntry(handle, &broadcast);
303 }
304
305 epgChannel->GetInitialEPG().clear();
306 m_readInitialEpgChannelsMap.erase(epgChannel->GetServiceReference());
307
308 TransferTimerBasedEntries(handle, epgChannel->GetUniqueId());
309
310 return PVR_ERROR_NO_ERROR;
311 }
312
313 std::string Epg::LoadEPGEntryShortDescription(const std::string& serviceReference, unsigned int epgUid)
314 {
315 std::string shortDescription;
316
317 const std::string jsonUrl = StringUtils::Format("%sapi/event?sref=%s&idev=%u", Settings::GetInstance().GetConnectionURL().c_str(),
318 WebUtils::URLEncodeInline(serviceReference).c_str(), epgUid);
319
320 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
321
322 try
323 {
324 auto jsonDoc = json::parse(strJson);
325
326 if (!jsonDoc["event"].empty())
327 {
328 for (const auto& element : jsonDoc["event"].items())
329 {
330 if (element.key() == "shortdesc")
331 {
332 Logger::Log(LEVEL_DEBUG, "%s Loaded EPG event short description for sref: %s, epgId: %u - '%s'", __FUNCTION__, serviceReference.c_str(), epgUid, element.value().get<std::string>().c_str());
333 shortDescription = element.value().get<std::string>();
334 }
335 }
336 }
337 }
338 catch (nlohmann::detail::parse_error& e)
339 {
340 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot load short descrption from OpenWebIf for sref: %s, epgId: %u - JSON parse error - message: %s, exception id: %d", __FUNCTION__, serviceReference.c_str(), epgUid, e.what(), e.id);
341 }
342 catch (nlohmann::detail::type_error& e)
343 {
344 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
345 }
346
347 return shortDescription;
348 }
349
350 EpgPartialEntry Epg::LoadEPGEntryPartialDetails(const std::string& serviceReference, unsigned int epgUid)
351 {
352 EpgPartialEntry partialEntry;
353
354 Logger::Log(LEVEL_DEBUG, "%s Looking for EPG event partial details for sref: %s, epgUid: %u", __FUNCTION__, serviceReference.c_str(), epgUid);
355
356 const std::string jsonUrl = StringUtils::Format("%sapi/event?sref=%s&idev=%u", Settings::GetInstance().GetConnectionURL().c_str(),
357 WebUtils::URLEncodeInline(serviceReference).c_str(), epgUid);
358
359 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
360
361 try
362 {
363 auto jsonDoc = json::parse(strJson);
364
365 if (!jsonDoc["event"].empty())
366 {
367 for (const auto& element : jsonDoc["event"].items())
368 {
369 if (element.key() == "shortdesc")
370 partialEntry.SetPlotOutline(element.value().get<std::string>());
371 if (element.key() == "longdesc")
372 partialEntry.SetPlot(element.value().get<std::string>());
373 else if (element.key() == "title")
374 partialEntry.SetTitle(element.value().get<std::string>());
375 else if (element.key() == "id")
376 partialEntry.SetEpgUid(element.value().get<unsigned int>());
377 else if (element.key() == "genreid")
378 {
379 int genreId = element.value().get<int>();
380 partialEntry.SetGenreType(genreId & 0xF0);
381 partialEntry.SetGenreSubType(genreId & 0x0F);
382 }
383 }
384
385 if (partialEntry.EntryFound())
386 {
387 Logger::Log(LEVEL_DEBUG, "%s Loaded EPG event partial details for sref: %s, epgId: %u - title: %s - '%s'", __FUNCTION__, serviceReference.c_str(), epgUid, partialEntry.GetTitle().c_str(), partialEntry.GetPlotOutline().c_str());
388 }
389 }
390 }
391 catch (nlohmann::detail::parse_error& e)
392 {
393 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot event details from OpenWebIf for sref: %s, epgId: %u - JSON parse error - message: %s, exception id: %d", __FUNCTION__, serviceReference.c_str(), epgUid, e.what(), e.id);
394 }
395 catch (nlohmann::detail::type_error& e)
396 {
397 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
398 }
399
400 return partialEntry;
401 }
402
403 EpgPartialEntry Epg::LoadEPGEntryPartialDetails(const std::string& serviceReference, time_t startTime)
404 {
405 EpgPartialEntry partialEntry;
406
407 Logger::Log(LEVEL_DEBUG, "%s Looking for EPG event partial details for sref: %s, time: %lld", __FUNCTION__, serviceReference.c_str(), static_cast<long long>(startTime));
408
409 const std::string jsonUrl = StringUtils::Format("%sapi/epgservice?sRef=%s&time=%lld&endTime=1", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline(serviceReference).c_str(), static_cast<long long>(startTime));
410
411 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
412
413 try
414 {
415 auto jsonDoc = json::parse(strJson);
416
417 if (!jsonDoc["events"].empty())
418 {
419 for (const auto& event : jsonDoc["events"].items())
420 {
421 for (const auto& element : event.value().items())
422 {
423 if (element.key() == "shortdesc")
424 partialEntry.SetPlotOutline(element.value().get<std::string>());
425 if (element.key() == "longdesc")
426 partialEntry.SetPlot(element.value().get<std::string>());
427 else if (element.key() == "title")
428 partialEntry.SetTitle(element.value().get<std::string>());
429 else if (element.key() == "id")
430 partialEntry.SetEpgUid(element.value().get<unsigned int>());
431 else if (element.key() == "genreid")
432 {
433 int genreId = element.value().get<int>();
434 partialEntry.SetGenreType(genreId & 0xF0);
435 partialEntry.SetGenreSubType(genreId & 0x0F);
436 }
437 }
438
439 if (partialEntry.EntryFound())
440 Logger::Log(LEVEL_DEBUG, "%s Loaded EPG event partial details for sref: %s, time: %lld - title: %s, epgId: %u - '%s'", __FUNCTION__, serviceReference.c_str(), static_cast<long long>(startTime), partialEntry.GetTitle().c_str(), partialEntry.GetEpgUid(), partialEntry.GetPlotOutline().c_str());
441
442 break; //We only want first event
443 }
444 }
445 }
446 catch (nlohmann::detail::parse_error& e)
447 {
448 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot event details from OpenWebIf for sref: %s, time: %lld - JSON parse error - message: %s, exception id: %d", __FUNCTION__, serviceReference.c_str(), static_cast<long long>(startTime), e.what(), e.id);
449 }
450 catch (nlohmann::detail::type_error& e)
451 {
452 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
453 }
454
455 return partialEntry;
456 }
457
458 std::string Epg::FindServiceReference(const std::string& title, int epgUid, time_t startTime, time_t endTime) const
459 {
460 std::string serviceReference;
461
462 const auto started = std::chrono::high_resolution_clock::now();
463
464 const std::string jsonUrl = StringUtils::Format("%sapi/epgsearch?search=%s&endtime=%lld", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline(title).c_str(), static_cast<long long>(endTime));
465
466 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
467
468 try
469 {
470 auto jsonDoc = json::parse(strJson);
471
472 if (!jsonDoc["events"].empty())
473 {
474 for (const auto& event : jsonDoc["events"].items())
475 {
476 if (event.value()["title"].get<std::string>() == title &&
477 event.value()["id"].get<int>() == epgUid &&
478 event.value()["begin_timestamp"].get<time_t>() == startTime &&
479 event.value()["duration_sec"].get<int>() == (endTime - startTime))
480 {
481 serviceReference = Channel::NormaliseServiceReference(event.value()["sref"].get<std::string>());
482
483 break; //We only want first event
484 }
485 }
486 }
487 }
488 catch (nlohmann::detail::parse_error& e)
489 {
490 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot retrieve service reference from OpenWebIf for: %s, epgUid: %d, start time: %lld, end time: %lld - JSON parse error - message: %s, exception id: %d", __FUNCTION__, title.c_str(), epgUid, static_cast<long long>(startTime), static_cast<long long>(endTime), e.what(), e.id);
491 }
492 catch (nlohmann::detail::type_error& e)
493 {
494 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
495 }
496
497 int milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - started).count();
498
499 Logger::Log(LEVEL_DEBUG, "%s Service reference search time - %d (ms)", __FUNCTION__, milliseconds);
500
501 return serviceReference;
502 }
503
504 bool Epg::LoadInitialEPGForGroup(const std::shared_ptr<ChannelGroup> group)
505 {
506 const std::string url = StringUtils::Format("%s%s%s", Settings::GetInstance().GetConnectionURL().c_str(),
507 "web/epgnownext?bRef=", WebUtils::URLEncodeInline(group->GetServiceReference()).c_str());
508
509 const std::string strXML = WebUtils::GetHttpXML(url);
510
511 int iNumEPG = 0;
512
513 TiXmlDocument xmlDoc;
514 if (!xmlDoc.Parse(strXML.c_str()))
515 {
516 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
517 return false;
518 }
519
520 TiXmlHandle hDoc(&xmlDoc);
521
522 TiXmlElement* pElem = hDoc.FirstChildElement("e2eventlist").Element();
523
524 if (!pElem)
525 {
526 Logger::Log(LEVEL_NOTICE, "%s could not find <e2eventlist> element!", __FUNCTION__);
527 // Return "NO_ERROR" as the EPG could be empty for this channel
528 return false;
529 }
530
531 TiXmlHandle hRoot = TiXmlHandle(pElem);
532
533 TiXmlElement* pNode = hRoot.FirstChildElement("e2event").Element();
534
535 if (!pNode)
536 {
537 Logger::Log(LEVEL_DEBUG, "%s Could not find <e2event> element", __FUNCTION__);
538 // RETURN "NO_ERROR" as the EPG could be empty for this channel
539 return false;
540 }
541
542 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2event"))
543 {
544 EpgEntry entry;
545
546 if (!entry.UpdateFrom(pNode, m_needsInitialEpgChannelsMap))
547 continue;
548
549 std::shared_ptr<data::EpgChannel> epgChannel = GetEpgChannelNeedingInitialEpg(entry.GetServiceReference());
550
551 if (m_entryExtractor.IsEnabled())
552 m_entryExtractor.ExtractFromEntry(entry);
553
554 iNumEPG++;
555
556 epgChannel->GetInitialEPG().emplace_back(entry);
557 Logger::Log(LEVEL_TRACE, "%s Added Initial EPG Entry for: %s, %d, %s", __FUNCTION__, epgChannel->GetChannelName().c_str(), epgChannel->GetUniqueId(), epgChannel->GetServiceReference().c_str());
558 }
559
560 Logger::Log(LEVEL_INFO, "%s Loaded %u EPG Entries for group '%s'", __FUNCTION__, iNumEPG, group->GetGroupName().c_str());
561 return true;
562 }
563
564 void Epg::UpdateTimerEPGFallbackEntries(const std::vector<enigma2::data::EpgEntry>& timerBasedEntries)
565 {
566 CLockObject lock(m_mutex);
567 time_t now = time(nullptr);
568 time_t until = now + m_epgMaxDaysSeconds;
569
570 m_timerBasedEntries.clear();
571
572 for (auto& timerBasedEntry : timerBasedEntries)
573 {
574 if (timerBasedEntry.GetEndTime() < now || timerBasedEntry.GetEndTime() > until)
575 m_timerBasedEntries.emplace_back(timerBasedEntry);
576 }
577 }
578
579 int Epg::TransferTimerBasedEntries(ADDON_HANDLE handle, int epgChannelId)
580 {
581 int numTransferred = 0;
582
583 CLockObject lock(m_mutex);
584 for (auto& timerBasedEntry : m_timerBasedEntries)
585 {
586 if (epgChannelId == timerBasedEntry.GetChannelId())
587 {
588 EPG_TAG broadcast = {0};
589
590 timerBasedEntry.UpdateTo(broadcast);
591
592 PVR->TransferEpgEntry(handle, &broadcast);
593
594 numTransferred++;
595 }
596 }
597
598 return numTransferred;
599 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "ChannelGroups.h"
24 #include "Channels.h"
25 #include "data/EpgChannel.h"
26 #include "data/EpgPartialEntry.h"
27 #include "extract/EpgEntryExtractor.h"
28 #include "kodi/libXBMC_pvr.h"
29 #include "p8-platform/threads/threads.h"
30
31 #include <map>
32 #include <memory>
33 #include <string>
34 #include <vector>
35
36 namespace enigma2
37 {
38 static const float LAST_SCANNED_INITIAL_EPG_SUCCESS_PERCENT = 0.99f;
39 static const int DEFAULT_EPG_MAX_DAYS = 3;
40
41 class Epg
42 {
43 public:
44 Epg(enigma2::extract::EpgEntryExtractor& entryExtractor, int epgMaxDays);
45 Epg(const enigma2::Epg& epg);
46
47 bool Initialise(enigma2::Channels& channels, enigma2::ChannelGroups& channelGroups);
48 bool IsInitialEpgCompleted();
49 void TriggerEpgUpdatesForChannels();
50 void MarkChannelAsInitialEpgRead(const std::string& serviceReference);
51 PVR_ERROR GetEPGForChannel(ADDON_HANDLE handle, const std::string& serviceReference, time_t iStart, time_t iEnd);
52 void SetEPGTimeFrame(int epgMaxDays);
53 std::string LoadEPGEntryShortDescription(const std::string& serviceReference, unsigned int epgUid);
54 data::EpgPartialEntry LoadEPGEntryPartialDetails(const std::string& serviceReference, time_t startTime);
55 data::EpgPartialEntry LoadEPGEntryPartialDetails(const std::string& serviceReference, unsigned int epgUid);
56 std::string FindServiceReference(const std::string& title, int epgUid, time_t startTime, time_t endTime) const;
57 void UpdateTimerEPGFallbackEntries(const std::vector<enigma2::data::EpgEntry>& timerBasedEntries);
58
59 private:
60 PVR_ERROR TransferInitialEPGForChannel(ADDON_HANDLE handle, const std::shared_ptr<data::EpgChannel>& epgChannel, time_t iStart, time_t iEnd);
61 std::shared_ptr<data::EpgChannel> GetEpgChannel(const std::string& serviceReference);
62 bool LoadInitialEPGForGroup(const std::shared_ptr<enigma2::data::ChannelGroup> group);
63 bool ChannelNeedsInitialEpg(const std::string& serviceReference);
64 bool InitialEpgLoadedForChannel(const std::string& serviceReference);
65 bool InitialEpgReadForChannel(const std::string& serviceReference);
66 std::shared_ptr<data::EpgChannel> GetEpgChannelNeedingInitialEpg(const std::string& serviceReference);
67 int TransferTimerBasedEntries(ADDON_HANDLE handle, int epgChannelId);
68
69 enigma2::extract::EpgEntryExtractor& m_entryExtractor;
70
71 bool m_initialEpgReady = false;
72 int m_epgMaxDays;
73 long m_epgMaxDaysSeconds;
74
75 std::vector<std::shared_ptr<data::EpgChannel>> m_epgChannels;
76 std::map<std::string, std::shared_ptr<data::EpgChannel>> m_epgChannelsMap;
77 std::map<std::string, std::shared_ptr<data::EpgChannel>> m_readInitialEpgChannelsMap;
78 std::map<std::string, std::shared_ptr<data::EpgChannel>> m_needsInitialEpgChannelsMap;
79
80 std::vector<data::EpgEntry> m_timerBasedEntries;
81
82 mutable P8PLATFORM::CMutex m_mutex;
83 };
84 } //namespace enigma2
0 #pragma once
1
2 /*
3 * Copyright (C) 2005-2019 Team XBMC
4 * http://www.xbmc.org
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, write to
18 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
19 * MA 02110-1335, USA.
20 * http://www.gnu.org/copyleft/gpl.html
21 *
22 */
23
24 namespace enigma2
25 {
26 class IConnectionListener
27 {
28 public:
29 virtual ~IConnectionListener() = default;
30
31 virtual void ConnectionLost() = 0;
32 virtual void ConnectionEstablished() = 0;
33 };
34 } // namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "kodi/libXBMC_addon.h"
24
25 #include <ctime>
26
27 namespace enigma2
28 {
29 class IStreamReader
30 {
31 public:
32 virtual ~IStreamReader(void) = default;
33 virtual bool Start() = 0;
34 virtual ssize_t ReadData(unsigned char* buffer, unsigned int size) = 0;
35 virtual int64_t Seek(long long position, int whence) = 0;
36 virtual int64_t Position() = 0;
37 virtual int64_t Length() = 0;
38 virtual std::time_t TimeStart() = 0;
39 virtual std::time_t TimeEnd() = 0;
40 virtual bool IsRealTime() = 0;
41 virtual bool IsTimeshifting() = 0;
42 };
43 } // namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "client.h"
24
25 #include <string>
26
27 namespace enigma2
28 {
29 class LocalizedString
30 {
31 public:
32 explicit LocalizedString(int id)
33 {
34 Load(id);
35 }
36
37 bool Load(int id)
38 {
39 char* str;
40 if ((str = XBMC->GetLocalizedString(id)))
41 {
42 m_localizedString = str;
43 XBMC->FreeString(str);
44 return true;
45 }
46
47 m_localizedString = "";
48 return false;
49 }
50
51 std::string Get()
52 {
53 return m_localizedString;
54 }
55
56 operator std::string()
57 {
58 return Get();
59 }
60
61 const char* c_str()
62 {
63 return m_localizedString.c_str();
64 }
65
66 private:
67 LocalizedString() = delete;
68 LocalizedString(const LocalizedString&) = delete;
69 LocalizedString& operator=(const LocalizedString&) = delete;
70
71 std::string m_localizedString;
72 };
73 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "RecordingReader.h"
23
24 #include "../client.h"
25 #include "p8-platform/threads/mutex.h"
26 #include "utilities/Logger.h"
27
28 #include <algorithm>
29
30 using namespace ADDON;
31 using namespace enigma2;
32 using namespace enigma2::utilities;
33
34 RecordingReader::RecordingReader(const std::string& streamURL, std::time_t start, std::time_t end, int duration)
35 : m_streamURL(streamURL), m_start(start), m_end(end), m_duration(duration)
36 {
37 m_readHandle = XBMC->CURLCreate(m_streamURL.c_str());
38 (void)XBMC->CURLOpen(m_readHandle, XFILE::READ_NO_CACHE);
39 m_len = XBMC->GetFileLength(m_readHandle);
40 m_nextReopen = time(nullptr) + REOPEN_INTERVAL;
41
42 //If this is an ongoing recording set the duration to the eventual length of the recording
43 if (start > 0 && end > 0)
44 {
45 m_duration = static_cast<int>(end - start);
46 }
47
48 Logger::Log(LEVEL_DEBUG, "%s RecordingReader: Started - url=%s, start=%u, end=%u, duration=%d", __FUNCTION__, m_streamURL.c_str(),
49 m_start, m_end, m_duration);
50 }
51
52 RecordingReader::~RecordingReader(void)
53 {
54 if (m_readHandle)
55 XBMC->CloseFile(m_readHandle);
56 Logger::Log(LEVEL_DEBUG, "%s RecordingReader: Stopped", __FUNCTION__);
57 }
58
59 bool RecordingReader::Start()
60 {
61 return (m_readHandle != nullptr);
62 }
63
64 ssize_t RecordingReader::ReadData(unsigned char* buffer, unsigned int size)
65 {
66 /* check for playback of ongoing recording */
67 if (m_end)
68 {
69 std::time_t now = std::time(nullptr);
70 if (m_pos == m_len || now > m_nextReopen)
71 {
72 /* reopen stream */
73 Logger::Log(LEVEL_DEBUG, "%s RecordingReader: Reopening stream...", __FUNCTION__);
74 (void)XBMC->CURLOpen(m_readHandle, XFILE::READ_REOPEN | XFILE::READ_NO_CACHE);
75 m_len = XBMC->GetFileLength(m_readHandle);
76 XBMC->SeekFile(m_readHandle, m_pos, SEEK_SET);
77
78 // random value (10 MiB) we choose to switch to fast reopen interval
79 bool nearEnd = m_len - m_pos <= 10 * 1024 * 1024;
80 m_nextReopen = now + (nearEnd ? REOPEN_INTERVAL_FAST : REOPEN_INTERVAL);
81
82 /* recording has finished */
83 if (now > m_end)
84 m_end = 0;
85 }
86 }
87
88 ssize_t read = XBMC->ReadFile(m_readHandle, buffer, size);
89 m_pos += read;
90 return read;
91 }
92
93 int64_t RecordingReader::Seek(long long position, int whence)
94 {
95 int64_t ret = XBMC->SeekFile(m_readHandle, position, whence);
96 // for unknown reason seek sometimes doesn't return the correct position
97 // so let's sync with the underlaying implementation
98 m_pos = XBMC->GetFilePosition(m_readHandle);
99 m_len = XBMC->GetFileLength(m_readHandle);
100 return ret;
101 }
102
103 int64_t RecordingReader::Position()
104 {
105 return m_pos;
106 }
107
108 int64_t RecordingReader::Length()
109 {
110 return m_len;
111 }
112
113 int RecordingReader::CurrentDuration()
114 {
115 if (m_end != 0)
116 {
117 time_t now = std::time(nullptr);
118
119 if (now < m_end)
120 {
121 Logger::Log(LEVEL_DEBUG, "%s RecordingReader - Partial: %d", __FUNCTION__, static_cast<int>(now - m_start));
122 return now - m_start;
123 }
124 }
125
126 Logger::Log(LEVEL_DEBUG, "%s RecordingReader - Full: %d", __FUNCTION__, m_duration);
127 return m_duration;
128 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "kodi/libXBMC_addon.h"
24
25 #include <ctime>
26 #include <string>
27
28 namespace enigma2
29 {
30 class RecordingReader
31 {
32 public:
33 RecordingReader(const std::string& streamURL, std::time_t start, std::time_t end, int duration);
34 ~RecordingReader(void);
35
36 bool Start();
37 ssize_t ReadData(unsigned char* buffer, unsigned int size);
38 int64_t Seek(long long position, int whence);
39 int64_t Position();
40 int64_t Length();
41 int CurrentDuration();
42
43
44 private:
45 static const int REOPEN_INTERVAL = 30;
46 static const int REOPEN_INTERVAL_FAST = 10;
47
48 const std::string& m_streamURL;
49 void* m_readHandle;
50
51 int m_duration;
52
53 /*!< @brief start and end time of the recording set only in case this an ongoing recording */
54 std::time_t m_start;
55 std::time_t m_end;
56
57 std::time_t m_nextReopen;
58 uint64_t m_pos = {0};
59 uint64_t m_len;
60 };
61 } // namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Recordings.h"
23
24 #include "../Enigma2.h"
25 #include "../client.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "util/XMLUtils.h"
28 #include "utilities/Logger.h"
29 #include "utilities/WebUtils.h"
30
31 #include <iostream>
32 #include <regex>
33 #include <sstream>
34
35 #include <nlohmann/json.hpp>
36
37 using namespace enigma2;
38 using namespace enigma2::data;
39 using namespace enigma2::extract;
40 using namespace enigma2::utilities;
41 using json = nlohmann::json;
42
43 const std::string Recordings::FILE_NOT_FOUND_RESPONSE_SUFFIX = "not found";
44
45 Recordings::Recordings(Channels& channels, enigma2::extract::EpgEntryExtractor& entryExtractor)
46 : m_channels(channels), m_entryExtractor(entryExtractor)
47 {
48 std::random_device randomDevice; //Will be used to obtain a seed for the random number engine
49 m_randomGenerator = std::mt19937(randomDevice()); //Standard mersenne_twister_engine seeded with randomDevice()
50 m_randomDistribution = std::uniform_int_distribution<>(E2_DEVICE_LAST_PLAYED_SYNC_INTERVAL_MIN, E2_DEVICE_LAST_PLAYED_SYNC_INTERVAL_MAX);
51 }
52
53 void Recordings::GetRecordings(std::vector<PVR_RECORDING>& kodiRecordings, bool deleted)
54 {
55 auto& recordings = (!deleted) ? m_recordings : m_deletedRecordings;
56
57 for (auto& recording : recordings)
58 {
59 Logger::Log(LEVEL_DEBUG, "%s - Transfer recording '%s', Recording Id '%s'", __FUNCTION__, recording.GetTitle().c_str(), recording.GetRecordingId().c_str());
60 PVR_RECORDING kodiRecording = {0};
61
62 recording.UpdateTo(kodiRecording, m_channels, IsInRecordingFolder(recording.GetTitle(), deleted));
63
64 kodiRecordings.emplace_back(kodiRecording);
65 }
66 }
67
68 int Recordings::GetNumRecordings(bool deleted) const
69 {
70 const auto& recordings = (!deleted) ? m_recordings : m_deletedRecordings;
71
72 return recordings.size();
73 }
74
75 void Recordings::ClearRecordings(bool deleted)
76 {
77 auto& recordings = (!deleted) ? m_recordings : m_deletedRecordings;
78
79 recordings.clear();
80
81 for (auto it = m_recordingsIdMap.begin(); it != m_recordingsIdMap.end();)
82 {
83 if (it->second.IsDeleted() == deleted)
84 it = m_recordingsIdMap.erase(it);
85 else
86 ++it;
87 }
88 }
89
90 void Recordings::GetRecordingEdl(const std::string& recordingId, std::vector<PVR_EDL_ENTRY>& edlEntries) const
91 {
92 const RecordingEntry recordingEntry = GetRecording(recordingId);
93
94 if (!recordingEntry.GetEdlURL().empty())
95 {
96 const std::string edlFile = WebUtils::GetHttp(recordingEntry.GetEdlURL());
97
98 if (!StringUtils::EndsWith(edlFile, FILE_NOT_FOUND_RESPONSE_SUFFIX))
99 {
100 std::istringstream stream(edlFile);
101 std::string line;
102 int lineNumber = 0;
103 while (std::getline(stream, line))
104 {
105 float start = 0.0f, stop = 0.0f;
106 unsigned int type = PVR_EDL_TYPE_CUT;
107 lineNumber++;
108 if (std::sscanf(line.c_str(), "%f %f %u", &start, &stop, &type) < 2 || type > PVR_EDL_TYPE_COMBREAK)
109 {
110 Logger::Log(LEVEL_NOTICE, "%s Unable to parse EDL entry for recording '%s' at line %d. Skipping.", __FUNCTION__,
111 recordingEntry.GetTitle().c_str(), lineNumber);
112 continue;
113 }
114
115 start += static_cast<float>(Settings::GetInstance().GetEDLStartTimePadding()) / 1000.0f;
116 stop += static_cast<float>(Settings::GetInstance().GetEDLStopTimePadding()) / 1000.0f;
117
118 start = std::max(start, 0.0f);
119 stop = std::max(stop, 0.0f);
120 start = std::min(start, stop);
121 stop = std::max(start, stop);
122
123 Logger::Log(LEVEL_NOTICE, "%s EDL for '%s', line %d - start: %f stop: %f type: %d", __FUNCTION__, recordingEntry.GetTitle().c_str(), lineNumber, start, stop, type);
124
125 PVR_EDL_ENTRY edlEntry;
126 edlEntry.start = static_cast<int64_t>(start * 1000.0f);
127 edlEntry.end = static_cast<int64_t>(stop * 1000.0f);
128 edlEntry.type = static_cast<PVR_EDL_TYPE>(type);
129
130 edlEntries.emplace_back(edlEntry);
131 }
132 }
133 }
134 }
135
136 RecordingEntry Recordings::GetRecording(const std::string& recordingId) const
137 {
138 RecordingEntry entry;
139
140 auto recordingPair = m_recordingsIdMap.find(recordingId);
141 if (recordingPair != m_recordingsIdMap.end())
142 {
143 entry = recordingPair->second;
144 }
145
146 return entry;
147 }
148
149 bool Recordings::IsInRecordingFolder(const std::string& recordingFolder, bool deleted) const
150 {
151 const auto& recordings = (!deleted) ? m_recordings : m_deletedRecordings;
152
153 int iMatches = 0;
154 for (const auto& recording : recordings)
155 {
156 if (recordingFolder == recording.GetTitle())
157 {
158 iMatches++;
159 Logger::Log(LEVEL_DEBUG, "%s Found Recording title '%s' in recordings vector!", __FUNCTION__, recordingFolder.c_str());
160 if (iMatches > 1)
161 {
162 Logger::Log(LEVEL_DEBUG, "%s Found Recording title twice '%s' in recordings vector!", __FUNCTION__, recordingFolder.c_str());
163 return true;
164 }
165 }
166 }
167
168 return false;
169 }
170
171 PVR_ERROR Recordings::RenameRecording(const PVR_RECORDING& recording)
172 {
173 auto recordingEntry = GetRecording(recording.strRecordingId);
174
175 if (!recordingEntry.GetRecordingId().empty())
176 {
177 Logger::Log(LEVEL_DEBUG, "%s Sending rename command for recording '%s' to '%s'", __FUNCTION__, recordingEntry.GetTitle().c_str(), recording.strTitle);
178 const std::string jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s&title=%s", Settings::GetInstance().GetConnectionURL().c_str(),
179 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str(),
180 WebUtils::URLEncodeInline(recording.strTitle).c_str());
181 std::string strResult;
182
183 if (WebUtils::SendSimpleJsonCommand(jsonUrl, strResult))
184 {
185 PVR->TriggerRecordingUpdate();
186 return PVR_ERROR_NO_ERROR;
187 }
188 }
189
190 PVR->TriggerRecordingUpdate();
191
192 return PVR_ERROR_SERVER_ERROR;
193 }
194
195 PVR_ERROR Recordings::SetRecordingPlayCount(const PVR_RECORDING& recording, int count)
196 {
197 auto recordingEntry = GetRecording(recording.strRecordingId);
198
199 if (!recordingEntry.GetRecordingId().empty())
200 {
201 if (recording.iPlayCount == count)
202 return PVR_ERROR_NO_ERROR;
203
204 std::vector<std::string> oldTags;
205 ReadExtraRecordingPlayCountInfo(recordingEntry, oldTags);
206
207 std::string addTagsArg = TAG_FOR_PLAY_COUNT + "=" + std::to_string(count);
208
209 std::string deleteTagsArg;
210 for (std::string& oldTag : oldTags)
211 {
212 if (oldTag != addTagsArg)
213 {
214 if (!deleteTagsArg.empty())
215 deleteTagsArg += ",";
216
217 deleteTagsArg += oldTag;
218 }
219 }
220
221 Logger::Log(LEVEL_DEBUG, "%s Setting playcount for recording '%s' to '%d'", __FUNCTION__, recordingEntry.GetTitle().c_str(), count);
222 const std::string jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s&deltag=%s&addtag=%s",
223 Settings::GetInstance().GetConnectionURL().c_str(),
224 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str(),
225 WebUtils::URLEncodeInline(deleteTagsArg).c_str(),
226 WebUtils::URLEncodeInline(addTagsArg).c_str());
227 std::string strResult;
228
229 if (WebUtils::SendSimpleJsonCommand(jsonUrl, strResult))
230 {
231 PVR->TriggerRecordingUpdate();
232 return PVR_ERROR_NO_ERROR;
233 }
234 }
235
236 PVR->TriggerRecordingUpdate();
237
238 return PVR_ERROR_SERVER_ERROR;
239 }
240
241 PVR_ERROR Recordings::SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastPlayedPosition)
242 {
243 auto recordingEntry = GetRecording(recording.strRecordingId);
244
245 if (!recordingEntry.GetRecordingId().empty())
246 {
247 if (recording.iLastPlayedPosition == lastPlayedPosition)
248 return PVR_ERROR_NO_ERROR;
249
250 std::vector<std::pair<int, int64_t>> cuts;
251 std::vector<std::string> oldTags;
252
253 bool readExtraCutsInfo = ReadExtaRecordingCutsInfo(recordingEntry, cuts, oldTags);
254 std::string cutsArg;
255 bool cutsLastPlayedSet = false;
256 if (readExtraCutsInfo && Settings::GetInstance().GetRecordingLastPlayedMode() == RecordingLastPlayedMode::ACROSS_KODI_AND_E2_INSTANCES)
257 {
258 for (auto cut : cuts)
259 {
260 if (!cutsArg.empty())
261 cutsArg += ",";
262
263 if (cut.first == CUTS_LAST_PLAYED_TYPE)
264 {
265 if (!cutsLastPlayedSet)
266 {
267 cutsArg += std::to_string(CUTS_LAST_PLAYED_TYPE) + ":" + std::to_string(PTS_PER_SECOND * lastPlayedPosition);
268 cutsLastPlayedSet = true;
269 }
270 }
271 else
272 {
273 cutsArg += std::to_string(cut.first) + ":" + std::to_string(cut.second);
274 }
275 }
276
277 if (!cutsLastPlayedSet)
278 {
279 if (!cutsArg.empty())
280 cutsArg += ",";
281
282 cutsArg += std::to_string(CUTS_LAST_PLAYED_TYPE) + ":" + std::to_string(PTS_PER_SECOND * lastPlayedPosition);
283 cutsLastPlayedSet = true;
284 }
285 }
286
287 std::string addTagsArg = TAG_FOR_LAST_PLAYED + "=" + std::to_string(lastPlayedPosition);
288
289 std::string deleteTagsArg;
290 for (std::string& oldTag : oldTags)
291 {
292 if (oldTag != addTagsArg)
293 {
294 if (!deleteTagsArg.empty())
295 deleteTagsArg += ",";
296
297 deleteTagsArg += oldTag;
298 }
299 }
300
301 addTagsArg += "," + TAG_FOR_NEXT_SYNC_TIME + "=" + std::to_string(std::time(nullptr) + m_randomDistribution(m_randomGenerator));
302
303 Logger::Log(LEVEL_DEBUG, "%s Setting last played position for recording '%s' to '%d'", __FUNCTION__, recordingEntry.GetTitle().c_str(), lastPlayedPosition);
304
305 std::string jsonUrl;
306 if (Settings::GetInstance().GetRecordingLastPlayedMode() == RecordingLastPlayedMode::ACROSS_KODI_INSTANCES || !cutsLastPlayedSet)
307 {
308 jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s&deltag=%s&addtag=%s",
309 Settings::GetInstance().GetConnectionURL().c_str(),
310 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str(),
311 WebUtils::URLEncodeInline(deleteTagsArg).c_str(),
312 WebUtils::URLEncodeInline(addTagsArg).c_str());
313 }
314 else
315 {
316 jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s&deltag=%s&addtag=%s&cuts=%s",
317 Settings::GetInstance().GetConnectionURL().c_str(),
318 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str(),
319 WebUtils::URLEncodeInline(deleteTagsArg).c_str(),
320 WebUtils::URLEncodeInline(addTagsArg).c_str(),
321 WebUtils::URLEncodeInline(cutsArg).c_str());
322 }
323 std::string strResult;
324
325 if (WebUtils::SendSimpleJsonCommand(jsonUrl, strResult))
326 {
327 PVR->TriggerRecordingUpdate();
328 return PVR_ERROR_NO_ERROR;
329 }
330 }
331
332 PVR->TriggerRecordingUpdate();
333
334 return PVR_ERROR_SERVER_ERROR;
335 }
336
337 int Recordings::GetRecordingLastPlayedPosition(const PVR_RECORDING& recording)
338 {
339 auto recordingEntry = GetRecording(recording.strRecordingId);
340
341 time_t now = std::time(nullptr);
342 time_t newNextSyncTime = now + m_randomDistribution(m_randomGenerator);
343
344 Logger::Log(LEVEL_DEBUG, "%s Recording: %s - Checking if Next Sync Time: %lld < Now: %lld ", __FUNCTION__, recordingEntry.GetTitle().c_str(), static_cast<long long>(recordingEntry.GetNextSyncTime()), static_cast<long long>(now));
345
346 if (Settings::GetInstance().GetRecordingLastPlayedMode() == RecordingLastPlayedMode::ACROSS_KODI_AND_E2_INSTANCES &&
347 recordingEntry.GetNextSyncTime() < now)
348 {
349 //We need to get this value separately as it's not returned by the movielist api
350 //We don't want to call for it everytime as large movie directories would make a lot of calls.
351 //Instead we'll only call out every five to ten mins and store the value so it can be returned by the movielist api.
352
353 std::vector<std::pair<int, int64_t>> cuts;
354 std::vector<std::string> oldTags;
355 bool readExtraCutsInfo = ReadExtaRecordingCutsInfo(recordingEntry, cuts, oldTags);
356 int lastPlayedPosition = -1;
357 if (readExtraCutsInfo)
358 {
359 for (auto cut : cuts)
360 {
361 if (cut.first == CUTS_LAST_PLAYED_TYPE)
362 {
363 lastPlayedPosition = cut.second / PTS_PER_SECOND;
364 break;
365 }
366 }
367 }
368
369 if (readExtraCutsInfo && lastPlayedPosition >= 0 && lastPlayedPosition != recordingEntry.GetLastPlayedPosition())
370 {
371 std::string addTagsArg = TAG_FOR_LAST_PLAYED + "=" + std::to_string(lastPlayedPosition);
372
373 //then we update it in the tags using movieinfo
374 std::string deleteTagsArg;
375 for (std::string& oldTag : oldTags)
376 {
377 if (oldTag != addTagsArg)
378 {
379 if (!deleteTagsArg.empty())
380 deleteTagsArg += ",";
381
382 deleteTagsArg += oldTag;
383 }
384 }
385
386 addTagsArg += "," + TAG_FOR_NEXT_SYNC_TIME + "=" + std::to_string(newNextSyncTime);
387
388 Logger::Log(LEVEL_DEBUG, "%s Setting last played position from E2 cuts file to tags for recording '%s' to '%d'", __FUNCTION__, recordingEntry.GetTitle().c_str(), lastPlayedPosition);
389
390 std::string jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s&deltag=%s&addtag=%s",
391 Settings::GetInstance().GetConnectionURL().c_str(),
392 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str(),
393 WebUtils::URLEncodeInline(deleteTagsArg).c_str(),
394 WebUtils::URLEncodeInline(addTagsArg).c_str());
395 std::string strResult;
396
397 if (WebUtils::SendSimpleJsonCommand(jsonUrl, strResult))
398 {
399 recordingEntry.SetLastPlayedPosition(lastPlayedPosition);
400 recordingEntry.SetNextSyncTime(newNextSyncTime);
401 }
402 }
403 else
404 {
405 //just update the tag for next sync.
406 SetRecordingNextSyncTime(recordingEntry, newNextSyncTime, oldTags);
407
408 lastPlayedPosition = recordingEntry.GetLastPlayedPosition();
409 }
410
411 return lastPlayedPosition;
412 }
413 else
414 {
415 return recordingEntry.GetLastPlayedPosition();
416 }
417 }
418
419 void Recordings::SetRecordingNextSyncTime(RecordingEntry& recordingEntry, time_t nextSyncTime, std::vector<std::string>& oldTags)
420 {
421 Logger::Log(LEVEL_DEBUG, "%s Setting next sync time in tags for recording '%s' to '%lld'", __FUNCTION__, recordingEntry.GetTitle().c_str(), static_cast<long long>(nextSyncTime));
422
423 std::string addTagsArg = TAG_FOR_NEXT_SYNC_TIME + "=" + std::to_string(nextSyncTime);
424
425 //then we update it in the tags using movieinfo api
426 std::string deleteTagsArg;
427 for (std::string& oldTag : oldTags)
428 {
429 if (oldTag != addTagsArg && StringUtils::StartsWith(oldTag, TAG_FOR_NEXT_SYNC_TIME + "="))
430 {
431 if (!deleteTagsArg.empty())
432 deleteTagsArg += ",";
433
434 deleteTagsArg += oldTag;
435 }
436 }
437
438 const std::string jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s&deltag=%s&addtag=%s",
439 Settings::GetInstance().GetConnectionURL().c_str(),
440 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str(),
441 WebUtils::URLEncodeInline(deleteTagsArg).c_str(),
442 WebUtils::URLEncodeInline(addTagsArg).c_str());
443 std::string strResult;
444
445 if (!WebUtils::SendSimpleJsonCommand(jsonUrl, strResult))
446 {
447 recordingEntry.SetNextSyncTime(nextSyncTime);
448 Logger::Log(LEVEL_ERROR, "%s Error setting next sync time for recording '%s' to '%lld'", __FUNCTION__, recordingEntry.GetTitle().c_str(), static_cast<long long>(nextSyncTime));
449 }
450 }
451
452 PVR_ERROR Recordings::DeleteRecording(const PVR_RECORDING& recinfo)
453 {
454 const std::string strTmp = StringUtils::Format("web/moviedelete?sRef=%s", WebUtils::URLEncodeInline(recinfo.strRecordingId).c_str());
455
456 std::string strResult;
457 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
458 return PVR_ERROR_FAILED;
459
460 // No need to call PVR->TriggerRecordingUpdate() as it is handled by kodi PVR.
461 // In fact when multiple recordings are removed at once, calling it here can cause hanging issues
462
463 return PVR_ERROR_NO_ERROR;
464 }
465
466 PVR_ERROR Recordings::UndeleteRecording(const PVR_RECORDING& recording)
467 {
468 auto recordingEntry = GetRecording(recording.strRecordingId);
469
470 std::regex regex(TRASH_FOLDER);
471
472 const std::string newRecordingDirectory = std::regex_replace(recordingEntry.GetDirectory(), regex, "");
473
474 const std::string strTmp = StringUtils::Format("web/moviemove?sRef=%s&dirname=%s", WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str(), WebUtils::URLEncodeInline(newRecordingDirectory).c_str());
475
476 std::string strResult;
477 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
478 return PVR_ERROR_FAILED;
479
480 return PVR_ERROR_NO_ERROR;
481 }
482
483 PVR_ERROR Recordings::DeleteAllRecordingsFromTrash()
484 {
485 for (const auto& deletedRecording : m_deletedRecordings)
486 {
487 const std::string strTmp =
488 StringUtils::Format("web/moviedelete?sRef=%s", WebUtils::URLEncodeInline(deletedRecording.GetRecordingId()).c_str());
489
490 std::string strResult;
491 WebUtils::SendSimpleCommand(strTmp, strResult, true);
492 }
493
494 return PVR_ERROR_NO_ERROR;
495 }
496
497 bool Recordings::HasRecordingStreamProgramNumber(const PVR_RECORDING& recording)
498 {
499 return GetRecording(recording.strRecordingId).HasStreamProgramNumber();
500 }
501
502 int Recordings::GetRecordingStreamProgramNumber(const PVR_RECORDING& recording)
503 {
504 return GetRecording(recording.strRecordingId).GetStreamProgramNumber();
505 }
506
507 const std::string Recordings::GetRecordingURL(const PVR_RECORDING& recinfo)
508 {
509 for (const auto& recording : m_recordings)
510 {
511 if (recinfo.strRecordingId == recording.GetRecordingId())
512 return recording.GetStreamURL();
513 }
514 return "";
515 }
516
517 bool Recordings::ReadExtaRecordingCutsInfo(const data::RecordingEntry& recordingEntry, std::vector<std::pair<int, int64_t>>& cuts, std::vector<std::string>& tags)
518 {
519 const std::string jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s", Settings::GetInstance().GetConnectionURL().c_str(),
520 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str());
521
522 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
523
524 try
525 {
526 auto jsonDoc = json::parse(strJson);
527
528 if (jsonDoc["result"].empty() || !jsonDoc["result"].get<bool>())
529 return false;
530
531 if (!jsonDoc["cuts"].empty())
532 {
533 int type;
534 uint64_t position;
535
536 for (const auto& cut : jsonDoc["cuts"].items())
537 {
538 for (const auto& element : cut.value().items())
539 {
540 if (element.key() == "type")
541 type = element.value().get<int>();
542 if (element.key() == "pos")
543 position = element.value().get<int64_t>();
544 }
545
546 cuts.emplace_back(std::make_pair(type, position));
547 }
548 }
549
550 if (!jsonDoc["tags"].empty())
551 {
552 for (const auto& tag : jsonDoc["tags"].items())
553 {
554 std::string tempTag = tag.value().get<std::string>();
555
556 if (StringUtils::StartsWith(tempTag, TAG_FOR_LAST_PLAYED) || StringUtils::StartsWith(tempTag, TAG_FOR_NEXT_SYNC_TIME))
557 tags.emplace_back(tempTag);
558 }
559 }
560
561 return true;
562 }
563 catch (nlohmann::detail::parse_error& e)
564 {
565 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot find extra recording cuts info from OpenWebIf for recording: %s, ID: %s - JSON parse error - message: %s, exception id: %d", __FUNCTION__, recordingEntry.GetTitle().c_str(), recordingEntry.GetRecordingId().c_str(), e.what(), e.id);
566 }
567 catch (nlohmann::detail::type_error& e)
568 {
569 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
570 }
571
572 return false;
573 }
574
575 bool Recordings::ReadExtraRecordingPlayCountInfo(const data::RecordingEntry& recordingEntry, std::vector<std::string>& tags)
576 {
577 const std::string jsonUrl = StringUtils::Format("%sapi/movieinfo?sref=%s", Settings::GetInstance().GetConnectionURL().c_str(),
578 WebUtils::URLEncodeInline(recordingEntry.GetRecordingId()).c_str());
579
580 const std::string strJson = WebUtils::GetHttpXML(jsonUrl);
581
582 try
583 {
584 auto jsonDoc = json::parse(strJson);
585
586 if (jsonDoc["result"].empty() || !jsonDoc["result"].get<bool>())
587 return false;
588
589 if (!jsonDoc["tags"].empty())
590 {
591 for (const auto& tag : jsonDoc["tags"].items())
592 {
593 std::string tempTag = tag.value().get<std::string>();
594
595 if (StringUtils::StartsWith(tempTag, TAG_FOR_PLAY_COUNT))
596 tags.emplace_back(tempTag);
597 }
598 }
599
600 return true;
601 }
602 catch (nlohmann::detail::parse_error& e)
603 {
604 Logger::Log(LEVEL_ERROR, "%s Invalid JSON received, cannot find extra recording play count info from OpenWebIf for recording: %s, ID: %s - JSON parse error - message: %s, exception id: %d", __FUNCTION__, recordingEntry.GetTitle().c_str(), recordingEntry.GetRecordingId().c_str(), e.what(), e.id);
605 }
606 catch (nlohmann::detail::type_error& e)
607 {
608 Logger::Log(LEVEL_ERROR, "%s JSON type error - message: %s, exception id: %d", __FUNCTION__, e.what(), e.id);
609 }
610
611 return false;
612 }
613
614 std::vector<std::string>& Recordings::GetLocations()
615 {
616 return m_locations;
617 }
618
619 void Recordings::ClearLocations()
620 {
621 m_locations.clear();
622 }
623
624 bool Recordings::LoadLocations()
625 {
626 std::string url;
627 if (Settings::GetInstance().GetRecordingsFromCurrentLocationOnly())
628 url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/getcurrlocation");
629 else
630 url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/getlocations");
631
632 const std::string strXML = WebUtils::GetHttpXML(url);
633
634 TiXmlDocument xmlDoc;
635 if (!xmlDoc.Parse(strXML.c_str()))
636 {
637 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
638 return false;
639 }
640
641 TiXmlHandle hDoc(&xmlDoc);
642
643 TiXmlElement* pElem = hDoc.FirstChildElement("e2locations").Element();
644
645 if (!pElem)
646 {
647 Logger::Log(LEVEL_ERROR, "%s Could not find <e2locations> element", __FUNCTION__);
648 return false;
649 }
650
651 TiXmlHandle hRoot = TiXmlHandle(pElem);
652
653 TiXmlElement* pNode = hRoot.FirstChildElement("e2location").Element();
654
655 if (!pNode)
656 {
657 Logger::Log(LEVEL_ERROR, "%s Could not find <e2location> element", __FUNCTION__);
658 return false;
659 }
660
661 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2location"))
662 {
663 const std::string strTmp = pNode->GetText();
664
665 m_locations.emplace_back(strTmp);
666
667 Logger::Log(LEVEL_DEBUG, "%s Added '%s' as a recording location", __FUNCTION__, strTmp.c_str());
668 }
669
670 Logger::Log(LEVEL_INFO, "%s Loaded '%d' recording locations", __FUNCTION__, m_locations.size());
671
672 return true;
673 }
674
675 void Recordings::LoadRecordings(bool deleted)
676 {
677 ClearRecordings(deleted);
678
679 for (std::string location : m_locations)
680 {
681 if (deleted)
682 location += TRASH_FOLDER;
683
684 if (!GetRecordingsFromLocation(location, deleted))
685 {
686 Logger::Log(LEVEL_ERROR, "%s Error fetching lists for folder: '%s'", __FUNCTION__, location.c_str());
687 }
688 }
689 }
690
691 bool Recordings::GetRecordingsFromLocation(const std::string recordingLocation, bool deleted)
692 {
693 auto& recordings = (!deleted) ? m_recordings : m_deletedRecordings;
694
695 std::string url;
696 std::string directory;
697
698 if (recordingLocation == "default")
699 {
700 url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/movielist");
701 directory = StringUtils::Format("/");
702 }
703 else
704 {
705 url = StringUtils::Format("%s%s?dirname=%s", Settings::GetInstance().GetConnectionURL().c_str(), "web/movielist",
706 WebUtils::URLEncodeInline(recordingLocation).c_str());
707 directory = recordingLocation;
708 }
709
710 const std::string strXML = WebUtils::GetHttpXML(url);
711
712 TiXmlDocument xmlDoc;
713 if (!xmlDoc.Parse(strXML.c_str()))
714 {
715 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
716 return false;
717 }
718
719 TiXmlHandle hDoc(&xmlDoc);
720
721 TiXmlElement* pElem = hDoc.FirstChildElement("e2movielist").Element();
722
723 if (!pElem)
724 {
725 Logger::Log(LEVEL_ERROR, "%s Could not find <e2movielist> element!", __FUNCTION__);
726 return false;
727 }
728
729 TiXmlHandle hRoot = TiXmlHandle(pElem);
730
731 TiXmlElement* pNode = hRoot.FirstChildElement("e2movie").Element();
732
733 int iNumRecordings = 0;
734
735 if (!pNode)
736 {
737 Logger::Log(LEVEL_DEBUG, "%s Could not find <e2movie> element, no movies at location: %s", directory.c_str(), __FUNCTION__);
738 }
739 else
740 {
741 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2movie"))
742 {
743
744 RecordingEntry recordingEntry;
745
746 if (!recordingEntry.UpdateFrom(pNode, directory, deleted, m_channels))
747 continue;
748
749 if (m_entryExtractor.IsEnabled())
750 m_entryExtractor.ExtractFromEntry(recordingEntry);
751
752 iNumRecordings++;
753
754 recordings.emplace_back(recordingEntry);
755 m_recordingsIdMap.insert({recordingEntry.GetRecordingId(), recordingEntry});
756
757 Logger::Log(LEVEL_DEBUG, "%s loaded Recording entry '%s', start '%d', length '%d'", __FUNCTION__, recordingEntry.GetTitle().c_str(), recordingEntry.GetStartTime(), recordingEntry.GetDuration());
758 }
759
760 Logger::Log(LEVEL_INFO, "%s Loaded %u Recording Entries from folder '%s'", __FUNCTION__, iNumRecordings, recordingLocation.c_str());
761 }
762 return true;
763 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "Channels.h"
24 #include "data/RecordingEntry.h"
25 #include "extract/EpgEntryExtractor.h"
26 #include "kodi/libXBMC_pvr.h"
27
28 #include <random>
29 #include <string>
30 #include <unordered_map>
31 #include <vector>
32
33 namespace enigma2
34 {
35 static int64_t PTS_PER_SECOND = 90000;
36 static int CUTS_LAST_PLAYED_TYPE = 3;
37 static int E2_DEVICE_LAST_PLAYED_SYNC_INTERVAL_MIN = 300;
38 static int E2_DEVICE_LAST_PLAYED_SYNC_INTERVAL_MAX = 600;
39 static constexpr const char* TRASH_FOLDER = ".Trash";
40
41 class Recordings
42 {
43 public:
44 Recordings(Channels& channels, enigma2::extract::EpgEntryExtractor& entryExtractor);
45 void GetRecordings(std::vector<PVR_RECORDING>& recordings, bool deleted);
46 int GetNumRecordings(bool deleted) const;
47 void ClearRecordings(bool deleted);
48 void GetRecordingEdl(const std::string& recordingId, std::vector<PVR_EDL_ENTRY>& edlEntries) const;
49 PVR_ERROR RenameRecording(const PVR_RECORDING& recording);
50 PVR_ERROR SetRecordingPlayCount(const PVR_RECORDING& recording, int count);
51 PVR_ERROR SetRecordingLastPlayedPosition(const PVR_RECORDING& recording, int lastplayedposition);
52 int GetRecordingLastPlayedPosition(const PVR_RECORDING& recording);
53 const std::string GetRecordingURL(const PVR_RECORDING& recinfo);
54 PVR_ERROR DeleteRecording(const PVR_RECORDING& recinfo);
55 PVR_ERROR UndeleteRecording(const PVR_RECORDING& recording);
56 PVR_ERROR DeleteAllRecordingsFromTrash();
57 bool HasRecordingStreamProgramNumber(const PVR_RECORDING& recording);
58 int GetRecordingStreamProgramNumber(const PVR_RECORDING& recording);
59
60 std::vector<std::string>& GetLocations();
61 void ClearLocations();
62
63 bool LoadLocations();
64 void LoadRecordings(bool deleted);
65
66 private:
67 static const std::string FILE_NOT_FOUND_RESPONSE_SUFFIX;
68
69 bool GetRecordingsFromLocation(const std::string recordingFolder, bool deleted);
70 data::RecordingEntry GetRecording(const std::string& recordingId) const;
71 bool ReadExtaRecordingCutsInfo(const data::RecordingEntry& recordingEntry, std::vector<std::pair<int, int64_t>>& cuts, std::vector<std::string>& tags);
72 bool ReadExtraRecordingPlayCountInfo(const data::RecordingEntry& recordingEntry, std::vector<std::string>& tags);
73 void SetRecordingNextSyncTime(data::RecordingEntry& recordingEntry, time_t nextSyncTime, std::vector<std::string>& oldTags);
74 bool IsInRecordingFolder(const std::string& strRecordingFolder, bool deleted) const;
75
76 std::mt19937 m_randomGenerator;
77 std::uniform_int_distribution<> m_randomDistribution;
78
79 std::vector<enigma2::data::RecordingEntry> m_recordings;
80 std::vector<enigma2::data::RecordingEntry> m_deletedRecordings;
81 std::unordered_map<std::string, enigma2::data::RecordingEntry> m_recordingsIdMap;
82 std::vector<std::string> m_locations;
83
84 Channels& m_channels;
85 enigma2::extract::EpgEntryExtractor& m_entryExtractor;
86 };
87 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Settings.h"
23
24 #include "../client.h"
25 #include "p8-platform/util/StringUtils.h"
26 #include "tinyxml.h"
27 #include "util/XMLUtils.h"
28 #include "utilities/FileUtils.h"
29 #include "utilities/LocalizedString.h"
30
31 using namespace ADDON;
32 using namespace enigma2;
33 using namespace enigma2::utilities;
34
35 /***************************************************************************
36 * PVR settings
37 **************************************************************************/
38 void Settings::ReadFromAddon()
39 {
40 FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + CHANNEL_GROUPS_DIR, CHANNEL_GROUPS_ADDON_DATA_BASE_DIR, true);
41
42 char buffer[1024];
43 buffer[0] = 0;
44
45 //Connection
46 if (XBMC->GetSetting("host", buffer))
47 m_hostname = buffer;
48 else
49 m_hostname = DEFAULT_HOST;
50 buffer[0] = 0;
51
52 if (!XBMC->GetSetting("webport", &m_portWeb))
53 m_portWeb = DEFAULT_WEB_PORT;
54
55 if (!XBMC->GetSetting("use_secure", &m_useSecureHTTP))
56 m_useSecureHTTP = false;
57
58 if (XBMC->GetSetting("user", buffer))
59 m_username = buffer;
60 else
61 m_username = "";
62 buffer[0] = 0;
63
64 if (XBMC->GetSetting("pass", buffer))
65 m_password = buffer;
66 else
67 m_password = "";
68 buffer[0] = 0;
69
70 if (!XBMC->GetSetting("autoconfig", &m_autoConfig))
71 m_autoConfig = false;
72
73 if (!XBMC->GetSetting("streamport", &m_portStream))
74 m_portStream = DEFAULT_STREAM_PORT;
75
76 if (!XBMC->GetSetting("use_secure_stream", &m_useSecureHTTPStream))
77 m_useSecureHTTPStream = false;
78
79 if (!XBMC->GetSetting("use_login_stream", &m_useLoginStream))
80 m_useLoginStream = false;
81
82 if (!XBMC->GetSetting("connectionchecktimeout", &m_connectioncCheckTimeoutSecs))
83 m_connectioncCheckTimeoutSecs = DEFAULT_CONNECTION_CHECK_TIMEOUT_SECS;
84
85 if (!XBMC->GetSetting("connectioncheckinterval", &m_connectioncCheckIntervalSecs))
86 m_connectioncCheckIntervalSecs = DEFAULT_CONNECTION_CHECK_INTERVAL_SECS;
87
88 //General
89 if (!XBMC->GetSetting("setprogramid", &m_setStreamProgramId))
90 m_setStreamProgramId = false;
91
92 if (!XBMC->GetSetting("onlinepicons", &m_onlinePicons))
93 m_onlinePicons = true;
94
95 if (!XBMC->GetSetting("usepiconseuformat", &m_usePiconsEuFormat))
96 m_usePiconsEuFormat = false;
97
98 if (!XBMC->GetSetting("useopenwebifpiconpath", &m_useOpenWebIfPiconPath))
99 m_useOpenWebIfPiconPath = false;
100
101 if (XBMC->GetSetting("iconpath", buffer))
102 m_iconPath = buffer;
103 else
104 m_iconPath = "";
105 buffer[0] = 0;
106
107 if (!XBMC->GetSetting("updateint", &m_updateInterval))
108 m_updateInterval = DEFAULT_UPDATE_INTERVAL;
109
110 if (!XBMC->GetSetting("updatemode", &m_updateMode))
111 m_updateMode = UpdateMode::TIMERS_AND_RECORDINGS;
112
113 if (!XBMC->GetSetting("channelandgroupupdatemode", &m_channelAndGroupUpdateMode))
114 m_channelAndGroupUpdateMode = ChannelAndGroupUpdateMode::RELOAD_CHANNELS_AND_GROUPS;
115
116 if (!XBMC->GetSetting("channelandgroupupdatehour", &m_channelAndGroupUpdateHour))
117 m_channelAndGroupUpdateHour = DEFAULT_CHANNEL_AND_GROUP_UPDATE_HOUR;
118
119 //Channels
120 if (!XBMC->GetSetting("zap", &m_zap))
121 m_zap = false;
122
123 if (!XBMC->GetSetting("usestandardserviceref", &m_useStandardServiceReference))
124 m_useStandardServiceReference = true;
125
126 if (!XBMC->GetSetting("tvgroupmode", &m_tvChannelGroupMode))
127 m_tvChannelGroupMode = ChannelGroupMode::ALL_GROUPS;
128
129 if (!XBMC->GetSetting("numtvgroups", &m_numTVGroups))
130 m_numTVGroups = DEFAULT_NUM_GROUPS;
131
132 if (XBMC->GetSetting("onetvgroup", buffer))
133 m_oneTVGroup = buffer;
134 else
135 m_oneTVGroup = "";
136 buffer[0] = 0;
137
138 if (XBMC->GetSetting("twotvgroup", buffer))
139 m_twoTVGroup = buffer;
140 else
141 m_twoTVGroup = "";
142 buffer[0] = 0;
143
144 if (XBMC->GetSetting("threetvgroup", buffer))
145 m_threeTVGroup = buffer;
146 else
147 m_threeTVGroup = "";
148 buffer[0] = 0;
149
150 if (XBMC->GetSetting("fourtvgroup", buffer))
151 m_fourTVGroup = buffer;
152 else
153 m_fourTVGroup = "";
154 buffer[0] = 0;
155
156 if (XBMC->GetSetting("fivetvgroup", buffer))
157 m_fiveTVGroup = buffer;
158 else
159 m_fiveTVGroup = "";
160 buffer[0] = 0;
161
162 if (m_tvChannelGroupMode == ChannelGroupMode::SOME_GROUPS)
163 {
164 m_customTVChannelGroupNameList.clear();
165
166 if (!m_oneTVGroup.empty() && m_numTVGroups >= 1)
167 m_customTVChannelGroupNameList.emplace_back(m_oneTVGroup);
168 if (!m_twoTVGroup.empty() && m_numTVGroups >= 2)
169 m_customTVChannelGroupNameList.emplace_back(m_twoTVGroup);
170 if (!m_threeTVGroup.empty() && m_numTVGroups >= 3)
171 m_customTVChannelGroupNameList.emplace_back(m_threeTVGroup);
172 if (!m_fourTVGroup.empty() && m_numTVGroups >= 4)
173 m_customTVChannelGroupNameList.emplace_back(m_fourTVGroup);
174 if (!m_fiveTVGroup.empty() && m_numTVGroups >= 5)
175 m_customTVChannelGroupNameList.emplace_back(m_fiveTVGroup);
176 }
177
178 if (XBMC->GetSetting("customtvgroupsfile", buffer))
179 m_customTVGroupsFile = buffer;
180 else
181 m_customTVGroupsFile = DEFAULT_CUSTOM_TV_GROUPS_FILE;
182 buffer[0] = 0;
183 if (m_tvChannelGroupMode == ChannelGroupMode::CUSTOM_GROUPS)
184 LoadCustomChannelGroupFile(m_customTVGroupsFile, m_customTVChannelGroupNameList);
185
186 if (!XBMC->GetSetting("tvfavouritesmode", &m_tvFavouritesMode))
187 m_tvFavouritesMode = FavouritesGroupMode::DISABLED;
188
189 if (!XBMC->GetSetting("excludelastscannedtv", &m_excludeLastScannedTVGroup))
190 m_excludeLastScannedTVGroup = true;
191
192 if (!XBMC->GetSetting("radiogroupmode", &m_radioChannelGroupMode))
193 m_radioChannelGroupMode = ChannelGroupMode::ALL_GROUPS;
194
195 if (!XBMC->GetSetting("numradiogroups", &m_numRadioGroups))
196 m_numRadioGroups = DEFAULT_NUM_GROUPS;
197
198 if (XBMC->GetSetting("oneradiogroup", buffer))
199 m_oneRadioGroup = buffer;
200 else
201 m_oneRadioGroup = "";
202 buffer[0] = 0;
203
204 if (XBMC->GetSetting("tworadiogroup", buffer))
205 m_twoRadioGroup = buffer;
206 else
207 m_twoRadioGroup = "";
208 buffer[0] = 0;
209
210 if (XBMC->GetSetting("threeradiogroup", buffer))
211 m_threeRadioGroup = buffer;
212 else
213 m_threeRadioGroup = "";
214 buffer[0] = 0;
215
216 if (XBMC->GetSetting("fourradiogroup", buffer))
217 m_fourRadioGroup = buffer;
218 else
219 m_fourRadioGroup = "";
220 buffer[0] = 0;
221
222 if (XBMC->GetSetting("fiveradiogroup", buffer))
223 m_fiveRadioGroup = buffer;
224 else
225 m_fiveRadioGroup = "";
226 buffer[0] = 0;
227
228 if (m_radioChannelGroupMode == ChannelGroupMode::SOME_GROUPS)
229 {
230 m_customRadioChannelGroupNameList.clear();
231
232 if (!m_oneRadioGroup.empty() && m_numRadioGroups >= 1)
233 m_customRadioChannelGroupNameList.emplace_back(m_oneRadioGroup);
234 if (!m_twoRadioGroup.empty() && m_numRadioGroups >= 2)
235 m_customRadioChannelGroupNameList.emplace_back(m_twoRadioGroup);
236 if (!m_threeRadioGroup.empty() && m_numRadioGroups >= 3)
237 m_customRadioChannelGroupNameList.emplace_back(m_threeRadioGroup);
238 if (!m_fourRadioGroup.empty() && m_numRadioGroups >= 4)
239 m_customRadioChannelGroupNameList.emplace_back(m_fourRadioGroup);
240 if (!m_fiveRadioGroup.empty() && m_numRadioGroups >= 5)
241 m_customRadioChannelGroupNameList.emplace_back(m_fiveRadioGroup);
242 }
243
244 if (XBMC->GetSetting("customradiogroupsfile", buffer))
245 m_customRadioGroupsFile = buffer;
246 else
247 m_customRadioGroupsFile = DEFAULT_CUSTOM_RADIO_GROUPS_FILE;
248 buffer[0] = 0;
249 if (m_radioChannelGroupMode == ChannelGroupMode::CUSTOM_GROUPS)
250 LoadCustomChannelGroupFile(m_customRadioGroupsFile, m_customRadioChannelGroupNameList);
251
252 if (!XBMC->GetSetting("radiofavouritesmode", &m_radioFavouritesMode))
253 m_radioFavouritesMode = FavouritesGroupMode::DISABLED;
254
255 if (!XBMC->GetSetting("excludelastscannedradio", &m_excludeLastScannedRadioGroup))
256 m_excludeLastScannedRadioGroup = true;
257
258 //EPG
259 if (!XBMC->GetSetting("extractshowinfoenabled", &m_extractShowInfo))
260 m_extractShowInfo = false;
261
262 if (XBMC->GetSetting("extractshowinfofile", buffer))
263 m_extractShowInfoFile = buffer;
264 else
265 m_extractShowInfoFile = DEFAULT_SHOW_INFO_FILE;
266 buffer[0] = 0;
267
268 if (!XBMC->GetSetting("genreidmapenabled", &m_mapGenreIds))
269 m_mapGenreIds = false;
270
271 if (XBMC->GetSetting("genreidmapfile", buffer))
272 m_mapGenreIdsFile = buffer;
273 else
274 m_mapGenreIdsFile = DEFAULT_GENRE_ID_MAP_FILE;
275 buffer[0] = 0;
276
277 if (!XBMC->GetSetting("rytecgenretextmapenabled", &m_mapRytecTextGenres))
278 m_mapRytecTextGenres = false;
279
280 if (XBMC->GetSetting("rytecgenretextmapfile", buffer))
281 m_mapRytecTextGenresFile = buffer;
282 else
283 m_mapRytecTextGenresFile = DEFAULT_GENRE_ID_MAP_FILE;
284 buffer[0] = 0;
285
286 if (!XBMC->GetSetting("logmissinggenremapping", &m_logMissingGenreMappings))
287 m_logMissingGenreMappings = false;
288
289 if (!XBMC->GetSetting("epgdelayperchannel", &m_epgDelayPerChannel))
290 m_epgDelayPerChannel = 0;
291
292 if (!XBMC->GetSetting("skipinitialepg", &m_skipInitialEpgLoad))
293 m_skipInitialEpgLoad = true;
294
295 //Recording
296 if (!XBMC->GetSetting("storeextrarecordinginfo", &m_storeLastPlayedAndCount))
297 m_storeLastPlayedAndCount = false;
298
299 if (!XBMC->GetSetting("sharerecordinglastplayed", &m_recordingLastPlayedMode))
300 m_recordingLastPlayedMode = RecordingLastPlayedMode::ACROSS_KODI_INSTANCES;
301
302 if (XBMC->GetSetting("recordingpath", buffer))
303 m_recordingPath = buffer;
304 else
305 m_recordingPath = "";
306 buffer[0] = 0;
307
308 if (!XBMC->GetSetting("onlycurrent", &m_onlyCurrentLocation))
309 m_onlyCurrentLocation = false;
310
311 if (!XBMC->GetSetting("keepfolders", &m_keepFolders))
312 m_keepFolders = false;
313
314 if (!XBMC->GetSetting("enablerecordingedls", &m_enableRecordingEDLs))
315 m_enableRecordingEDLs = false;
316
317 if (!XBMC->GetSetting("edlpaddingstart", &m_edlStartTimePadding))
318 m_edlStartTimePadding = 0;
319
320 if (!XBMC->GetSetting("edlpaddingstop", &m_edlStopTimePadding))
321 m_edlStopTimePadding = 0;
322
323 //Timers
324 if (!XBMC->GetSetting("enablegenrepeattimers", &m_enableGenRepeatTimers))
325 m_enableGenRepeatTimers = true;
326
327 if (!XBMC->GetSetting("numgenrepeattimers", &m_numGenRepeatTimers))
328 m_numGenRepeatTimers = DEFAULT_NUM_GEN_REPEAT_TIMERS;
329
330 if (!XBMC->GetSetting("timerlistcleanup", &m_automaticTimerlistCleanup))
331 m_automaticTimerlistCleanup = false;
332
333 if (!XBMC->GetSetting("enableautotimers", &m_enableAutoTimers))
334 m_enableAutoTimers = true;
335
336 if (!XBMC->GetSetting("limitanychannelautotimers", &m_limitAnyChannelAutoTimers))
337 m_limitAnyChannelAutoTimers = true;
338
339 if (!XBMC->GetSetting("limitanychannelautotimerstogroups", &m_limitAnyChannelAutoTimersToChannelGroups))
340 m_limitAnyChannelAutoTimersToChannelGroups = true;
341
342 //Timeshift
343 if (!XBMC->GetSetting("enabletimeshift", &m_timeshift))
344 m_timeshift = Timeshift::OFF;
345
346 if (XBMC->GetSetting("timeshiftbufferpath", buffer) && !std::string(buffer).empty())
347 m_timeshiftBufferPath = buffer;
348 else
349 m_timeshiftBufferPath = ADDON_DATA_BASE_DIR;
350 buffer[0] = 0;
351
352 //Advanced
353 if (!XBMC->GetSetting("prependoutline", &m_prependOutline))
354 m_prependOutline = PrependOutline::IN_EPG;
355
356 if (!XBMC->GetSetting("powerstatemode", &m_powerstateMode))
357 m_powerstateMode = PowerstateMode::DISABLED;
358
359 if (!XBMC->GetSetting("readtimeout", &m_readTimeout))
360 m_readTimeout = 0;
361
362 if (!XBMC->GetSetting("streamreadchunksize", &m_streamReadChunkSize))
363 m_streamReadChunkSize = 0;
364
365 if (!XBMC->GetSetting("nodebug", &m_noDebug))
366 m_noDebug = false;
367
368 if (!XBMC->GetSetting("debugnormal", &m_debugNormal))
369 m_debugNormal = false;
370
371 if (!XBMC->GetSetting("tracedebug", &m_traceDebug))
372 m_traceDebug = false;
373
374 // Now that we've read all the settings construct the connection URL
375
376 m_connectionURL.clear();
377 // simply add user@pass in front of the URL if username/password is set
378 if ((m_username.length() > 0) && (m_password.length() > 0))
379 m_connectionURL = StringUtils::Format("%s:%s@", m_username.c_str(), m_password.c_str());
380 if (!m_useSecureHTTP)
381 m_connectionURL = StringUtils::Format("http://%s%s:%u/", m_connectionURL.c_str(), m_hostname.c_str(), m_portWeb);
382 else
383 m_connectionURL = StringUtils::Format("https://%s%s:%u/", m_connectionURL.c_str(), m_hostname.c_str(), m_portWeb);
384 }
385
386 ADDON_STATUS Settings::SetValue(const std::string& settingName, const void* settingValue)
387 {
388 //Connection
389 if (settingName == "host")
390 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_hostname, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
391 else if (settingName == "webport")
392 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_portWeb, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
393 else if (settingName == "use_secure")
394 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_useSecureHTTP, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
395 else if (settingName == "user")
396 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_username, ADDON_STATUS_OK, ADDON_STATUS_OK);
397 else if (settingName == "pass")
398 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_password, ADDON_STATUS_OK, ADDON_STATUS_OK);
399 else if (settingName == "autoconfig")
400 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_autoConfig, ADDON_STATUS_OK, ADDON_STATUS_OK);
401 else if (settingName == "streamport")
402 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_portStream, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
403 else if (settingName == "use_secure_stream")
404 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_useSecureHTTPStream, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
405 else if (settingName == "use_login_stream")
406 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_useLoginStream, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
407 else if (settingName == "connectionchecktimeout")
408 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_connectioncCheckTimeoutSecs, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
409 else if (settingName == "connectioncheckinterval")
410 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_connectioncCheckIntervalSecs, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
411 //General
412 else if (settingName == "setprogramid")
413 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_setStreamProgramId, ADDON_STATUS_OK, ADDON_STATUS_OK);
414 else if (settingName == "onlinepicons")
415 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_onlinePicons, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
416 else if (settingName == "usepiconseuformat")
417 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_usePiconsEuFormat, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
418 else if (settingName == "useopenwebifpiconpath")
419 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_useOpenWebIfPiconPath, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
420 else if (settingName == "iconpath")
421 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_iconPath, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
422 else if (settingName == "updateint")
423 return SetSetting<unsigned int, ADDON_STATUS>(settingName, settingValue, m_updateInterval, ADDON_STATUS_OK, ADDON_STATUS_OK);
424 else if (settingName == "updatemode")
425 return SetSetting<UpdateMode, ADDON_STATUS>(settingName, settingValue, m_updateMode, ADDON_STATUS_OK, ADDON_STATUS_OK);
426 else if (settingName == "channelandgroupupdatemode")
427 return SetSetting<ChannelAndGroupUpdateMode, ADDON_STATUS>(settingName, settingValue, m_channelAndGroupUpdateMode, ADDON_STATUS_OK, ADDON_STATUS_OK);
428 else if (settingName == "channelandgroupupdatehour")
429 return SetSetting<unsigned int, ADDON_STATUS>(settingName, settingValue, m_channelAndGroupUpdateHour, ADDON_STATUS_OK, ADDON_STATUS_OK);
430 //Channels
431 else if (settingName == "zap")
432 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_zap, ADDON_STATUS_OK, ADDON_STATUS_OK);
433 else if (settingName == "usestandardserviceref")
434 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_useStandardServiceReference, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
435 else if (settingName == "tvgroupmode")
436 return SetSetting<ChannelGroupMode, ADDON_STATUS>(settingName, settingValue, m_tvChannelGroupMode, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
437 else if (settingName == "numtvgroups")
438 return SetSetting<unsigned int, ADDON_STATUS>(settingName, settingValue, m_numTVGroups, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
439 else if (settingName == "onetvgroup")
440 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_oneTVGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
441 else if (settingName == "twotvgroup")
442 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_twoTVGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
443 else if (settingName == "threetvgroup")
444 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_threeTVGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
445 else if (settingName == "twotvgroup")
446 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_fourTVGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
447 else if (settingName == "fivetvgroup")
448 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_fiveTVGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
449 else if (settingName == "customtvgroupsfile")
450 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_customTVGroupsFile, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
451 else if (settingName == "tvfavouritesmode")
452 return SetSetting<FavouritesGroupMode, ADDON_STATUS>(settingName, settingValue, m_tvFavouritesMode, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
453 else if (settingName == "excludelastscannedtv")
454 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_excludeLastScannedTVGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
455 else if (settingName == "radiogroupmode")
456 return SetSetting<ChannelGroupMode, ADDON_STATUS>(settingName, settingValue, m_radioChannelGroupMode, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
457 else if (settingName == "numradiogroups")
458 return SetSetting<unsigned int, ADDON_STATUS>(settingName, settingValue, m_numRadioGroups, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
459 else if (settingName == "oneradiogroup")
460 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_oneRadioGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
461 else if (settingName == "tworadiogroup")
462 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_twoRadioGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
463 else if (settingName == "threeradiogroup")
464 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_threeRadioGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
465 else if (settingName == "fourradiogroup")
466 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_fourRadioGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
467 else if (settingName == "fiveradiogroup")
468 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_fiveRadioGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
469 else if (settingName == "customradiogroupsfile")
470 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_customRadioGroupsFile, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
471 else if (settingName == "radiofavouritesmode")
472 return SetSetting<FavouritesGroupMode, ADDON_STATUS>(settingName, settingValue, m_radioFavouritesMode, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
473 else if (settingName == "excludelastscannedradio")
474 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_excludeLastScannedRadioGroup, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
475 //EPG
476 else if (settingName == "extractepginfoenabled")
477 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_extractShowInfo, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
478 else if (settingName == "extractepginfofile")
479 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_extractShowInfoFile, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
480 else if (settingName == "genreidmapenabled")
481 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_mapGenreIds, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
482 else if (settingName == "genreidmapfile")
483 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_mapGenreIdsFile, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
484 else if (settingName == "rytecgenretextmapenabled")
485 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_mapRytecTextGenres, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
486 else if (settingName == "rytecgenretextmapfile")
487 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_mapRytecTextGenresFile, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
488 else if (settingName == "logmissinggenremapping")
489 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_logMissingGenreMappings, ADDON_STATUS_OK, ADDON_STATUS_OK);
490 else if (settingName == "epgdelayperchannel")
491 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_epgDelayPerChannel, ADDON_STATUS_OK, ADDON_STATUS_OK);
492 else if (settingName == "skipinitialepg")
493 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_skipInitialEpgLoad, ADDON_STATUS_OK, ADDON_STATUS_OK);
494 //Recordings
495 else if (settingName == "storeextrarecordinginfo")
496 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_storeLastPlayedAndCount, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
497 else if (settingName == "sharerecordinglastplayed")
498 return SetSetting<RecordingLastPlayedMode, ADDON_STATUS>(settingName, settingValue, m_recordingLastPlayedMode, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
499 else if (settingName == "recordingpath")
500 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_recordingPath, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
501 else if (settingName == "onlycurrent")
502 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_onlyCurrentLocation, ADDON_STATUS_OK, ADDON_STATUS_OK);
503 else if (settingName == "keepfolders")
504 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_keepFolders, ADDON_STATUS_OK, ADDON_STATUS_OK);
505 else if (settingName == "enablerecordingedls")
506 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_enableRecordingEDLs, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
507 else if (settingName == "edlpaddingstart")
508 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_edlStartTimePadding, ADDON_STATUS_OK, ADDON_STATUS_OK);
509 else if (settingName == "edlpaddingstop")
510 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_edlStopTimePadding, ADDON_STATUS_OK, ADDON_STATUS_OK);
511 //Timers
512 else if (settingName == "enablegenrepeattimers")
513 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_enableAutoTimers, ADDON_STATUS_OK, ADDON_STATUS_OK);
514 else if (settingName == "numgenrepeattimers")
515 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_numGenRepeatTimers, ADDON_STATUS_OK, ADDON_STATUS_OK);
516 else if (settingName == "timerlistcleanup")
517 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_automaticTimerlistCleanup, ADDON_STATUS_OK, ADDON_STATUS_OK);
518 else if (settingName == "enableautotimers")
519 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_enableAutoTimers, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
520 else if (settingName == "limitanychannelautotimers")
521 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_limitAnyChannelAutoTimers, ADDON_STATUS_OK, ADDON_STATUS_OK);
522 else if (settingName == "limitanychannelautotimerstogroups")
523 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_limitAnyChannelAutoTimersToChannelGroups, ADDON_STATUS_OK, ADDON_STATUS_OK);
524 //Timeshift
525 else if (settingName == "enabletimeshift")
526 return SetSetting<Timeshift, ADDON_STATUS>(settingName, settingValue, m_timeshift, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
527 else if (settingName == "timeshiftbufferpath")
528 return SetStringSetting<ADDON_STATUS>(settingName, settingValue, m_timeshiftBufferPath, ADDON_STATUS_OK, ADDON_STATUS_OK);
529 //Advanced
530 else if (settingName == "prependoutline")
531 return SetSetting<PrependOutline, ADDON_STATUS>(settingName, settingValue, m_prependOutline, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
532 else if (settingName == "powerstatemode")
533 return SetSetting<PowerstateMode, ADDON_STATUS>(settingName, settingValue, m_powerstateMode, ADDON_STATUS_OK, ADDON_STATUS_OK);
534 else if (settingName == "readtimeout")
535 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_readTimeout, ADDON_STATUS_NEED_RESTART, ADDON_STATUS_OK);
536 else if (settingName == "streamreadchunksize")
537 return SetSetting<int, ADDON_STATUS>(settingName, settingValue, m_streamReadChunkSize, ADDON_STATUS_OK, ADDON_STATUS_OK);
538 else if (settingName == "nodebug")
539 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_noDebug, ADDON_STATUS_OK, ADDON_STATUS_OK);
540 else if (settingName == "debugnormal")
541 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_debugNormal, ADDON_STATUS_OK, ADDON_STATUS_OK);
542 else if (settingName == "tracedebug")
543 return SetSetting<bool, ADDON_STATUS>(settingName, settingValue, m_traceDebug, ADDON_STATUS_OK, ADDON_STATUS_OK);
544 //Backend
545 else if (settingName == "globalstartpaddingstb")
546 {
547 if (SetSetting<int, bool>(settingName, settingValue, m_globalStartPaddingStb, true, false))
548 m_admin->SendGlobalRecordingStartMarginSetting(m_globalStartPaddingStb);
549 }
550 else if (settingName == "globalendpaddingstb")
551 {
552 if (SetSetting<int, bool>(settingName, settingValue, m_globalEndPaddingStb, true, false))
553 m_admin->SendGlobalRecordingEndMarginSetting(m_globalEndPaddingStb);
554 }
555
556 return ADDON_STATUS_OK;
557 }
558
559 bool Settings::IsTimeshiftBufferPathValid() const
560 {
561 return XBMC->DirectoryExists(m_timeshiftBufferPath.c_str());
562 }
563
564 bool Settings::LoadCustomChannelGroupFile(std::string& xmlFile, std::vector<std::string>& channelGroupNameList)
565 {
566 channelGroupNameList.clear();
567
568 if (!FileUtils::FileExists(xmlFile.c_str()))
569 {
570 Logger::Log(LEVEL_ERROR, "%s No XML file found: %s", __FUNCTION__, xmlFile.c_str());
571 return false;
572 }
573
574 Logger::Log(LEVEL_DEBUG, "%s Loading XML File: %s", __FUNCTION__, xmlFile.c_str());
575
576 const std::string fileContents = FileUtils::ReadXmlFileToString(xmlFile);
577
578 if (fileContents.empty())
579 {
580 Logger::Log(LEVEL_ERROR, "%s No Content in XML file: %s", __FUNCTION__, xmlFile.c_str());
581 return false;
582 }
583
584 TiXmlDocument xmlDoc;
585 if (!xmlDoc.Parse(fileContents.c_str()))
586 {
587 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
588 return false;
589 }
590
591 TiXmlHandle hDoc(&xmlDoc);
592
593 TiXmlElement* pElem = hDoc.FirstChildElement("customChannelGroups").Element();
594
595 if (!pElem)
596 {
597 Logger::Log(LEVEL_ERROR, "%s Could not find <customChannelGroups> element!", __FUNCTION__);
598 return false;
599 }
600
601 TiXmlHandle hRoot = TiXmlHandle(pElem);
602
603 TiXmlElement* pNode = hRoot.FirstChildElement("channelGroupName").Element();
604
605 if (!pNode)
606 {
607 Logger::Log(LEVEL_ERROR, "%s Could not find <channelGroupName> element", __FUNCTION__);
608 return false;
609 }
610
611 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("channelGroupName"))
612 {
613 const std::string channelGroupName = pNode->GetText();
614
615 channelGroupNameList.emplace_back(channelGroupName);
616
617 Logger::Log(LEVEL_TRACE, "%s Read Custom ChannelGroup Name: %s, from file: %s", __FUNCTION__, channelGroupName.c_str(), xmlFile.c_str());
618 }
619
620 return true;
621 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "Admin.h"
24 #include "utilities/DeviceInfo.h"
25 #include "utilities/DeviceSettings.h"
26 #include "utilities/Logger.h"
27 #include "kodi/xbmc_addon_types.h"
28
29 #include <string>
30
31 #include <p8-platform/util/StringUtils.h>
32
33 class Vu;
34
35 namespace enigma2
36 {
37 static const std::string DEFAULT_HOST = "127.0.0.1";
38 static const int DEFAULT_CONNECT_TIMEOUT = 30;
39 static const int DEFAULT_STREAM_PORT = 8001;
40 static const int DEFAULT_WEB_PORT = 80;
41 static const int DEFAULT_CONNECTION_CHECK_TIMEOUT_SECS = 10;
42 static const int DEFAULT_CONNECTION_CHECK_INTERVAL_SECS = 1;
43 static const int DEFAULT_UPDATE_INTERVAL = 2;
44 static const int DEFAULT_CHANNEL_AND_GROUP_UPDATE_HOUR = 4;
45 static const int DEFAULT_NUM_GROUPS = 1;
46 static const std::string ADDON_DATA_BASE_DIR = "special://userdata/addon_data/pvr.vuplus";
47 static const std::string DEFAULT_SHOW_INFO_FILE = ADDON_DATA_BASE_DIR + "/showInfo/English-ShowInfo.xml";
48 static const std::string DEFAULT_GENRE_ID_MAP_FILE = ADDON_DATA_BASE_DIR + "/genres/genreIdMappings/Sky-UK.xml";
49 static const std::string DEFAULT_GENRE_TEXT_MAP_FILE = ADDON_DATA_BASE_DIR + "/genres/genreRytecTextMappings/Rytec-UK-Ireland.xml";
50 static const std::string DEFAULT_CUSTOM_TV_GROUPS_FILE = ADDON_DATA_BASE_DIR + "/channelGroups/customRadioGroups-example.xml";
51 static const std::string DEFAULT_CUSTOM_RADIO_GROUPS_FILE = ADDON_DATA_BASE_DIR + "/channelGroups/customRadioGroups-example.xml";
52 static const int DEFAULT_NUM_GEN_REPEAT_TIMERS = 1;
53
54 static const std::string CHANNEL_GROUPS_DIR = "/channelGroups";
55 static const std::string CHANNEL_GROUPS_ADDON_DATA_BASE_DIR = ADDON_DATA_BASE_DIR + CHANNEL_GROUPS_DIR;
56
57 enum class UpdateMode
58 : int // same type as addon settings
59 {
60 TIMERS_AND_RECORDINGS = 0,
61 TIMERS_ONLY
62 };
63
64 enum class ChannelAndGroupUpdateMode
65 : int // same type as addon settings
66 {
67 DISABLED = 0,
68 NOTIFY_AND_LOG,
69 RELOAD_CHANNELS_AND_GROUPS
70 };
71
72 enum class ChannelGroupMode
73 : int // same type as addon settings
74 {
75 ALL_GROUPS = 0,
76 SOME_GROUPS,
77 FAVOURITES_GROUP,
78 CUSTOM_GROUPS
79 };
80
81 enum class FavouritesGroupMode
82 : int // same type as addon settings
83 {
84 DISABLED = 0,
85 AS_FIRST_GROUP,
86 AS_LAST_GROUP
87 };
88
89 enum class RecordingLastPlayedMode
90 : int // same type as addon settings
91 {
92 ACROSS_KODI_INSTANCES = 0,
93 ACROSS_KODI_AND_E2_INSTANCES
94 };
95
96 enum class Timeshift
97 : int // same type as addon settings
98 {
99 OFF = 0,
100 ON_PLAYBACK,
101 ON_PAUSE
102 };
103
104 enum class PrependOutline
105 : int // same type as addon settings
106 {
107 NEVER = 0,
108 IN_EPG,
109 IN_RECORDINGS,
110 ALWAYS
111 };
112
113 enum class PowerstateMode
114 : int // same type as addon settings
115 {
116 DISABLED = 0,
117 STANDBY,
118 DEEP_STANDBY,
119 WAKEUP_THEN_STANDBY
120 };
121
122 class Settings
123 {
124 public:
125 /**
126 * Singleton getter for the instance
127 */
128 static Settings& GetInstance()
129 {
130 static Settings settings;
131 return settings;
132 }
133
134 void ReadFromAddon();
135 ADDON_STATUS SetValue(const std::string& settingName, const void* settingValue);
136
137 //Connection
138 const std::string& GetHostname() const { return m_hostname; }
139 int GetWebPortNum() const { return m_portWeb; }
140 bool GetUseSecureConnection() const { return m_useSecureHTTP; }
141 const std::string& GetUsername() const { return m_username; }
142 const std::string& GetPassword() const { return m_password; }
143 bool GetAutoConfigLiveStreamsEnabled() const { return m_autoConfig; }
144 int GetStreamPortNum() const { return m_portStream; }
145 bool UseSecureConnectionStream() const { return m_useSecureHTTPStream; }
146 bool UseLoginStream() const { return m_useLoginStream; }
147 int GetConnectioncCheckTimeoutSecs() const { return m_connectioncCheckTimeoutSecs; }
148 int GetConnectioncCheckIntervalSecs() const { return m_connectioncCheckIntervalSecs; }
149
150 //General
151 bool SetStreamProgramID() const { return m_setStreamProgramId; }
152 bool UseOnlinePicons() const { return m_onlinePicons; }
153 bool UsePiconsEuFormat() const { return m_usePiconsEuFormat; }
154 bool UseOpenWebIfPiconPath() const { return m_useOpenWebIfPiconPath; }
155 const std::string& GetIconPath() const { return m_iconPath; }
156 unsigned int GetUpdateIntervalMins() const { return m_updateInterval; }
157 UpdateMode GetUpdateMode() const { return m_updateMode; }
158 unsigned int GetChannelAndGroupUpdateHour() const { return m_channelAndGroupUpdateHour; }
159 ChannelAndGroupUpdateMode GetChannelAndGroupUpdateMode() const { return m_channelAndGroupUpdateMode; }
160
161 //Channel
162 bool GetZapBeforeChannelSwitch() const { return m_zap; }
163 bool UseStandardServiceReference() const { return m_useStandardServiceReference; }
164 const ChannelGroupMode& GetTVChannelGroupMode() const { return m_tvChannelGroupMode; }
165 const std::string& GetCustomTVGroupsFile() const { return m_customTVGroupsFile; }
166 const FavouritesGroupMode& GetTVFavouritesMode() const { return m_tvFavouritesMode; }
167 bool ExcludeLastScannedTVGroup() const { return m_excludeLastScannedTVGroup; }
168 const ChannelGroupMode& GetRadioChannelGroupMode() const { return m_radioChannelGroupMode; }
169 const std::string& GetCustomRadioGroupsFile() const { return m_customRadioGroupsFile; }
170 const FavouritesGroupMode& GetRadioFavouritesMode() const { return m_radioFavouritesMode; }
171 bool ExcludeLastScannedRadioGroup() const { return m_excludeLastScannedRadioGroup; }
172
173 //EPG
174 bool GetExtractShowInfo() const { return m_extractShowInfo; }
175 const std::string& GetExtractShowInfoFile() const { return m_extractShowInfoFile; }
176 bool GetMapGenreIds() const { return m_mapGenreIds; }
177 const std::string& GetMapGenreIdsFile() const { return m_mapGenreIdsFile; }
178 bool GetMapRytecTextGenres() const { return m_mapRytecTextGenres; }
179 const std::string& GetMapRytecTextGenresFile() const { return m_mapRytecTextGenresFile; }
180 bool GetLogMissingGenreMappings() const { return m_logMissingGenreMappings; }
181 int GetEPGDelayPerChannelDelay() const { return m_epgDelayPerChannel; }
182 bool SkipInitialEpgLoad() const { return m_skipInitialEpgLoad; }
183
184 //Recordings
185 bool GetStoreRecordingLastPlayedAndCount() const { return m_storeLastPlayedAndCount; }
186 const RecordingLastPlayedMode& GetRecordingLastPlayedMode() const { return m_recordingLastPlayedMode; }
187 const std::string& GetRecordingPath() const { return m_recordingPath; }
188 bool GetRecordingsFromCurrentLocationOnly() const { return m_onlyCurrentLocation; }
189 bool GetKeepRecordingsFolders() const { return m_keepFolders; }
190 bool GetRecordingEDLsEnabled() const { return m_enableRecordingEDLs; }
191 int GetEDLStartTimePadding() const { return m_edlStartTimePadding; }
192 int GetEDLStopTimePadding() const { return m_edlStopTimePadding; }
193
194 //Timers
195 bool GetGenRepeatTimersEnabled() const { return m_enableGenRepeatTimers; }
196 int GetNumGenRepeatTimers() const { return m_numGenRepeatTimers; }
197 bool GetAutoTimerListCleanupEnabled() const { return m_automaticTimerlistCleanup; }
198 bool GetAutoTimersEnabled() const { return m_enableAutoTimers; }
199 bool GetLimitAnyChannelAutoTimers() const { return m_limitAnyChannelAutoTimers; }
200 bool GetLimitAnyChannelAutoTimersToChannelGroups() const { return m_limitAnyChannelAutoTimersToChannelGroups; }
201
202 //Timeshift
203 const Timeshift& GetTimeshift() const { return m_timeshift; }
204 const std::string& GetTimeshiftBufferPath() const { return m_timeshiftBufferPath; }
205 bool IsTimeshiftBufferPathValid() const;
206
207 //Advanced
208 const PrependOutline& GetPrependOutline() const { return m_prependOutline; }
209 PowerstateMode GetPowerstateModeOnAddonExit() const { return m_powerstateMode; }
210 int GetReadTimeoutSecs() const { return m_readTimeout; }
211 int GetStreamReadChunkSizeKb() const { return m_streamReadChunkSize; }
212 bool GetNoDebug() const { return m_noDebug; };
213 bool GetDebugNormal() const { return m_debugNormal; };
214 bool GetTraceDebug() const { return m_traceDebug; };
215
216 const std::string& GetConnectionURL() const { return m_connectionURL; }
217
218 unsigned int GetWebIfVersionAsNum() const { return m_deviceInfo->GetWebIfVersionAsNum(); }
219 const std::string& GetWebIfVersion() const { return m_deviceInfo->GetWebIfVersion(); }
220
221 const enigma2::utilities::DeviceInfo* GetDeviceInfo() const { return m_deviceInfo; }
222 void SetDeviceInfo(enigma2::utilities::DeviceInfo* deviceInfo) { m_deviceInfo = deviceInfo; }
223
224 const enigma2::utilities::DeviceSettings* GetDeviceSettings() const { return m_deviceSettings; }
225 void SetDeviceSettings(enigma2::utilities::DeviceSettings* deviceSettings)
226 {
227 m_deviceSettings = deviceSettings;
228 m_globalStartPaddingStb = deviceSettings->GetGlobalRecordingStartMargin();
229 m_globalEndPaddingStb = deviceSettings->GetGlobalRecordingEndMargin();
230 m_deviceSettingsSet = true;
231 }
232
233 void SetAdmin(enigma2::Admin* admin) { m_admin = admin; }
234
235 inline unsigned int GenerateWebIfVersionAsNum(unsigned int major, unsigned int minor, unsigned int patch) const
236 {
237 return (major << 16 | minor << 8 | patch);
238 };
239
240 bool CheckOpenWebIfVersion(unsigned int major, unsigned int minor, unsigned int patch) const
241 {
242 return m_deviceSettingsSet ? GetWebIfVersionAsNum() >= GenerateWebIfVersionAsNum(major, minor, patch) && StringUtils::StartsWith(GetWebIfVersion(), "OWIF") : m_deviceSettingsSet;
243 }
244
245 bool IsOpenWebIf() const { return StringUtils::StartsWith(GetWebIfVersion(), "OWIF"); }
246 bool SupportsEditingRecordings() const { return CheckOpenWebIfVersion(1, 3, 6); }
247 bool SupportsAutoTimers() const { return CheckOpenWebIfVersion(1, 3, 0); }
248 bool SupportsTunerDetails() const { return CheckOpenWebIfVersion(1, 3, 5); }
249 bool SupportsProviderNumberAndPiconForChannels() const { return CheckOpenWebIfVersion(1, 3, 5); }
250 bool SupportsChannelNumberGroupStartPos() const { return CheckOpenWebIfVersion(1, 3, 7); }
251
252 bool UsesLastScannedChannelGroup() const { return m_usesLastScannedChannelGroup; }
253 void SetUsesLastScannedChannelGroup(bool value) { m_usesLastScannedChannelGroup = value; }
254
255 std::vector<std::string>& GetCustomTVChannelGroupNameList() { return m_customTVChannelGroupNameList; }
256 std::vector<std::string>& GetCustomRadioChannelGroupNameList() { return m_customRadioChannelGroupNameList; }
257
258 private:
259 Settings() = default;
260
261 Settings(Settings const&) = delete;
262 void operator=(Settings const&) = delete;
263
264 template<typename T, typename V>
265 V SetSetting(const std::string& settingName, const void* settingValue, T& currentValue, V returnValueIfChanged, V defaultReturnValue)
266 {
267 T newValue = *static_cast<const T*>(settingValue);
268 if (newValue != currentValue)
269 {
270 utilities::Logger::Log(utilities::LogLevel::LEVEL_NOTICE, "%s - Changed Setting '%s' from %d to %d", __FUNCTION__, settingName.c_str(), currentValue, newValue);
271 currentValue = newValue;
272 return returnValueIfChanged;
273 }
274
275 return defaultReturnValue;
276 };
277
278 template<typename V>
279 V SetStringSetting(const std::string& settingName, const void* settingValue, std::string& currentValue, V returnValueIfChanged, V defaultReturnValue)
280 {
281 const std::string strSettingValue = static_cast<const char*>(settingValue);
282
283 if (strSettingValue != currentValue)
284 {
285 utilities::Logger::Log(utilities::LogLevel::LEVEL_NOTICE, "%s - Changed Setting '%s' from '%s' to '%s'", __FUNCTION__, settingName.c_str(), currentValue.c_str(), strSettingValue.c_str());
286 currentValue = strSettingValue;
287 return returnValueIfChanged;
288 }
289
290 return defaultReturnValue;
291 }
292
293 static bool LoadCustomChannelGroupFile(std::string& file, std::vector<std::string>& channelGroupNameList);
294
295 //Connection
296 std::string m_hostname = DEFAULT_HOST;
297 int m_portWeb = DEFAULT_WEB_PORT;
298 bool m_useSecureHTTP = false;
299 std::string m_username = "";
300 std::string m_password = "";
301 bool m_autoConfig = false;
302 int m_portStream = DEFAULT_STREAM_PORT;
303 bool m_useSecureHTTPStream = false;
304 bool m_useLoginStream = false;
305 int m_connectioncCheckTimeoutSecs = DEFAULT_CONNECTION_CHECK_TIMEOUT_SECS;
306 int m_connectioncCheckIntervalSecs = DEFAULT_CONNECTION_CHECK_INTERVAL_SECS;
307
308 //General
309 bool m_setStreamProgramId = false;
310 bool m_onlinePicons = true;
311 bool m_usePiconsEuFormat = false;
312 bool m_useOpenWebIfPiconPath = false;
313 std::string m_iconPath = "";
314 unsigned int m_updateInterval = DEFAULT_UPDATE_INTERVAL;
315 UpdateMode m_updateMode = UpdateMode::TIMERS_AND_RECORDINGS;
316 ChannelAndGroupUpdateMode m_channelAndGroupUpdateMode = ChannelAndGroupUpdateMode::RELOAD_CHANNELS_AND_GROUPS;
317 unsigned int m_channelAndGroupUpdateHour = DEFAULT_CHANNEL_AND_GROUP_UPDATE_HOUR;
318
319 //Channel
320 bool m_zap = false;
321 bool m_useStandardServiceReference = true;
322 ChannelGroupMode m_tvChannelGroupMode = ChannelGroupMode::ALL_GROUPS;
323 unsigned int m_numTVGroups = DEFAULT_NUM_GROUPS;
324 std::string m_oneTVGroup = "";
325 std::string m_twoTVGroup = "";
326 std::string m_threeTVGroup = "";
327 std::string m_fourTVGroup = "";
328 std::string m_fiveTVGroup = "";
329 std::string m_customTVGroupsFile;
330 FavouritesGroupMode m_tvFavouritesMode = FavouritesGroupMode::DISABLED;
331 bool m_excludeLastScannedTVGroup = true;
332 ChannelGroupMode m_radioChannelGroupMode = ChannelGroupMode::ALL_GROUPS;
333 unsigned int m_numRadioGroups = DEFAULT_NUM_GROUPS;
334 std::string m_oneRadioGroup = "";
335 std::string m_twoRadioGroup = "";
336 std::string m_threeRadioGroup = "";
337 std::string m_fourRadioGroup = "";
338 std::string m_fiveRadioGroup = "";
339 std::string m_customRadioGroupsFile;
340 FavouritesGroupMode m_radioFavouritesMode = FavouritesGroupMode::DISABLED;
341 bool m_excludeLastScannedRadioGroup = true;
342
343 //EPG
344 bool m_extractShowInfo = true;
345 std::string m_extractShowInfoFile;
346 bool m_mapGenreIds = true;
347 std::string m_mapGenreIdsFile;
348 bool m_mapRytecTextGenres = true;
349 std::string m_mapRytecTextGenresFile;
350 bool m_logMissingGenreMappings = true;
351 int m_epgDelayPerChannel;
352 bool m_skipInitialEpgLoad = true;
353
354 //Recordings
355 bool m_storeLastPlayedAndCount = true;
356 RecordingLastPlayedMode m_recordingLastPlayedMode = RecordingLastPlayedMode::ACROSS_KODI_INSTANCES;
357 std::string m_recordingPath = "";
358 bool m_onlyCurrentLocation = false;
359 bool m_keepFolders = false;
360 bool m_enableRecordingEDLs = false;
361 int m_edlStartTimePadding = 0;
362 int m_edlStopTimePadding = 0;
363
364 //Timers
365 bool m_enableGenRepeatTimers = true;
366 int m_numGenRepeatTimers = DEFAULT_NUM_GEN_REPEAT_TIMERS;
367 bool m_automaticTimerlistCleanup = false;
368 bool m_enableAutoTimers = true;
369 bool m_limitAnyChannelAutoTimers = true;
370 bool m_limitAnyChannelAutoTimersToChannelGroups = false;
371
372 //Timeshift
373 Timeshift m_timeshift = Timeshift::OFF;
374 std::string m_timeshiftBufferPath = ADDON_DATA_BASE_DIR;
375
376 //Advanced
377 PrependOutline m_prependOutline = PrependOutline::IN_EPG;
378 PowerstateMode m_powerstateMode = PowerstateMode::DISABLED;
379 int m_readTimeout = 0;
380 int m_streamReadChunkSize = 0;
381 bool m_noDebug = false;
382 bool m_debugNormal = false;
383 bool m_traceDebug = false;
384
385 //Backend
386 int m_globalStartPaddingStb = 0;
387 int m_globalEndPaddingStb = 0;
388
389 //Last Scanned
390 bool m_usesLastScannedChannelGroup = false;
391
392 std::string m_connectionURL;
393 enigma2::utilities::DeviceInfo* m_deviceInfo;
394 enigma2::utilities::DeviceSettings* m_deviceSettings;
395 enigma2::Admin* m_admin;
396 bool m_deviceSettingsSet = false;
397
398 std::vector<std::string> m_customTVChannelGroupNameList;
399 std::vector<std::string> m_customRadioChannelGroupNameList;
400
401 //PVR Props
402 std::string m_szUserPath = "";
403 std::string m_szClientPath = "";
404 };
405 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "StreamReader.h"
23
24 #include "../client.h"
25 #include "utilities/Logger.h"
26
27 using namespace ADDON;
28 using namespace enigma2;
29 using namespace enigma2::utilities;
30
31 StreamReader::StreamReader(const std::string& streamURL, const unsigned int readTimeout)
32 {
33 m_streamHandle = XBMC->CURLCreate(streamURL.c_str());
34 if (readTimeout > 0)
35 XBMC->CURLAddOption(m_streamHandle, XFILE::CURL_OPTION_PROTOCOL, "connection-timeout", std::to_string(readTimeout).c_str());
36
37 Logger::Log(LEVEL_DEBUG, "%s StreamReader: Started; url=%s", __FUNCTION__, streamURL.c_str());
38 }
39
40 StreamReader::~StreamReader(void)
41 {
42 if (m_streamHandle)
43 XBMC->CloseFile(m_streamHandle);
44 Logger::Log(LEVEL_DEBUG, "%s StreamReader: Stopped", __FUNCTION__);
45 }
46
47 bool StreamReader::Start()
48 {
49 return XBMC->CURLOpen(m_streamHandle, XFILE::READ_NO_CACHE);
50 }
51
52 ssize_t StreamReader::ReadData(unsigned char* buffer, unsigned int size)
53 {
54 return XBMC->ReadFile(m_streamHandle, buffer, size);
55 }
56
57 int64_t StreamReader::Seek(long long position, int whence)
58 {
59 return XBMC->SeekFile(m_streamHandle, position, whence);
60 }
61
62 int64_t StreamReader::Position()
63 {
64 return XBMC->GetFilePosition(m_streamHandle);
65 }
66
67 int64_t StreamReader::Length()
68 {
69 return XBMC->GetFileLength(m_streamHandle);
70 }
71
72 std::time_t StreamReader::TimeStart()
73 {
74 return m_start;
75 }
76
77 std::time_t StreamReader::TimeEnd()
78 {
79 return std::time(nullptr);
80 }
81
82 bool StreamReader::IsRealTime()
83 {
84 return true;
85 }
86
87 bool StreamReader::IsTimeshifting()
88 {
89 return false;
90 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "IStreamReader.h"
24
25 #include <string>
26
27 namespace enigma2
28 {
29 class StreamReader : public IStreamReader
30 {
31 public:
32 StreamReader(const std::string& streamURL, const unsigned int m_readTimeout);
33 ~StreamReader(void);
34
35 bool Start() override;
36 ssize_t ReadData(unsigned char* buffer, unsigned int size) override;
37 int64_t Seek(long long position, int whence) override;
38 int64_t Position() override;
39 int64_t Length() override;
40 std::time_t TimeStart() override;
41 std::time_t TimeEnd() override;
42 bool IsRealTime() override;
43 bool IsTimeshifting() override;
44
45 private:
46 void* m_streamHandle;
47 std::time_t m_start = time(nullptr);
48 };
49 } // namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Timers.h"
23
24 #include "../Enigma2.h"
25 #include "../client.h"
26 #include "inttypes.h"
27 #include "p8-platform/util/StringUtils.h"
28 #include "util/XMLUtils.h"
29 #include "utilities/LocalizedString.h"
30 #include "utilities/Logger.h"
31 #include "utilities/UpdateState.h"
32 #include "utilities/WebUtils.h"
33
34 #include <algorithm>
35 #include <cstdlib>
36 #include <regex>
37
38 using namespace ADDON;
39 using namespace enigma2;
40 using namespace enigma2::data;
41 using namespace enigma2::utilities;
42
43 template<typename T>
44 T* Timers::GetTimer(std::function<bool(const T&)> func, std::vector<T>& timerlist)
45 {
46 for (auto& timer : timerlist)
47 {
48 if (func(timer))
49 return &timer;
50 }
51 return nullptr;
52 }
53
54 std::vector<Timer> Timers::LoadTimers() const
55 {
56 std::vector<Timer> timers;
57
58 const std::string url = StringUtils::Format("%s%s", m_settings.GetConnectionURL().c_str(), "web/timerlist");
59
60 const std::string strXML = WebUtils::GetHttpXML(url);
61
62 TiXmlDocument xmlDoc;
63 if (!xmlDoc.Parse(strXML.c_str()))
64 {
65 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
66 return timers;
67 }
68
69 TiXmlHandle hDoc(&xmlDoc);
70
71 TiXmlElement* pElem = hDoc.FirstChildElement("e2timerlist").Element();
72
73 if (!pElem)
74 {
75 Logger::Log(LEVEL_ERROR, "%s Could not find <e2timerlist> element!", __FUNCTION__);
76 return timers;
77 }
78
79 TiXmlHandle hRoot = TiXmlHandle(pElem);
80
81 TiXmlElement* pNode = hRoot.FirstChildElement("e2timer").Element();
82
83 if (!pNode)
84 {
85 Logger::Log(LEVEL_ERROR, "%s Could not find <e2timer> element", __FUNCTION__);
86 return timers;
87 }
88
89 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("e2timer"))
90 {
91 Timer newTimer;
92
93 if (!newTimer.UpdateFrom(pNode, m_channels))
94 continue;
95
96 if (m_entryExtractor.IsEnabled())
97 m_entryExtractor.ExtractFromEntry(newTimer);
98
99 timers.emplace_back(newTimer);
100
101 if ((newTimer.GetType() == Timer::MANUAL_REPEATING || newTimer.GetType() == Timer::EPG_REPEATING) &&
102 m_settings.GetGenRepeatTimersEnabled() && m_settings.GetNumGenRepeatTimers() > 0)
103 {
104 GenerateChildManualRepeatingTimers(&timers, &newTimer);
105 }
106
107 Logger::Log(LEVEL_INFO, "%s fetched Timer entry '%s', begin '%lld', end '%lld', start padding mins '%u', end padding mins '%u'",
108 __FUNCTION__, newTimer.GetTitle().c_str(), static_cast<long long>(newTimer.GetStartTime()), static_cast<long long>(newTimer.GetEndTime()), newTimer.GetPaddingStartMins(), newTimer.GetPaddingEndMins());
109 }
110
111 Logger::Log(LEVEL_INFO, "%s fetched %u Timer Entries", __FUNCTION__, timers.size());
112 return timers;
113 }
114
115 void Timers::GenerateChildManualRepeatingTimers(std::vector<Timer>* timers, Timer* timer) const
116 {
117 int genTimerCount = 0;
118 int weekdays = timer->GetWeekdays();
119 const time_t ONE_DAY = 24 * 60 * 60;
120
121 if (m_settings.GetNumGenRepeatTimers() && weekdays != PVR_WEEKDAY_NONE)
122 {
123 time_t nextStartTime = timer->GetStartTime();
124 time_t nextEndTime = timer->GetEndTime();
125
126 for (int i = 0; i < m_settings.GetNumGenRepeatTimers(); i++)
127 {
128 //Even if one day a week the max we can hit is 3 weeks
129 for (int i = 0; i < DAYS_IN_WEEK; i++)
130 {
131 std::tm nextTimeInfo = *std::localtime(&nextStartTime);
132
133 // Get the weekday and convert to PVR day of week
134 int pvrWeekday = nextTimeInfo.tm_wday - 1;
135 if (pvrWeekday < 0)
136 pvrWeekday = 6;
137
138 if (timer->GetWeekdays() & (1 << pvrWeekday))
139 {
140 //Create a timer
141 Timer newTimer;
142 newTimer.SetType(Timer::READONLY_REPEATING_ONCE);
143 newTimer.SetTitle(timer->GetTitle());
144 newTimer.SetChannelId(timer->GetChannelId());
145 newTimer.SetChannelName(timer->GetChannelName());
146 newTimer.SetStartTime(nextStartTime);
147 newTimer.SetEndTime(nextEndTime);
148 newTimer.SetPlot(timer->GetPlot());
149 newTimer.SetWeekdays(0);
150 newTimer.SetState(PVR_TIMER_STATE_NEW);
151 newTimer.SetEpgId(timer->GetEpgId());
152 newTimer.SetPaddingStartMins(timer->GetPaddingStartMins());
153 newTimer.SetPaddingEndMins(timer->GetPaddingEndMins());
154
155 time_t now = std::time(nullptr);
156 if (now < nextStartTime)
157 newTimer.SetState(PVR_TIMER_STATE_SCHEDULED);
158 else if (nextStartTime <= now && now <= nextEndTime)
159 newTimer.SetState(PVR_TIMER_STATE_RECORDING);
160 else
161 newTimer.SetState(PVR_TIMER_STATE_COMPLETED);
162
163 timers->emplace_back(newTimer);
164
165 genTimerCount++;
166
167 if (genTimerCount >= m_settings.GetNumGenRepeatTimers())
168 break;
169 }
170
171 nextStartTime += ONE_DAY;
172 nextEndTime += ONE_DAY;
173 }
174
175 if (genTimerCount >= m_settings.GetNumGenRepeatTimers())
176 break;
177 }
178 }
179 }
180
181 std::string Timers::ConvertToAutoTimerTag(std::string tag)
182 {
183 std::regex regex(" ");
184 std::string replaceWith = "_";
185
186 return std::regex_replace(tag, regex, replaceWith);
187 }
188
189 std::vector<AutoTimer> Timers::LoadAutoTimers() const
190 {
191 std::vector<AutoTimer> autoTimers;
192
193 const std::string url = StringUtils::Format("%s%s", m_settings.GetConnectionURL().c_str(), "autotimer");
194
195 const std::string strXML = WebUtils::GetHttpXML(url);
196
197 TiXmlDocument xmlDoc;
198 if (!xmlDoc.Parse(strXML.c_str()))
199 {
200 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
201 return autoTimers;
202 }
203
204 TiXmlHandle hDoc(&xmlDoc);
205
206 TiXmlElement* pElem = hDoc.FirstChildElement("autotimer").Element();
207
208 if (!pElem)
209 {
210 Logger::Log(LEVEL_ERROR, "%s Could not find <autotimer> element!", __FUNCTION__);
211 return autoTimers;
212 }
213
214 TiXmlHandle hRoot = TiXmlHandle(pElem);
215
216 TiXmlElement* pNode = hRoot.FirstChildElement("timer").Element();
217
218 if (!pNode)
219 {
220 Logger::Log(LEVEL_ERROR, "%s Could not find <timer> element", __FUNCTION__);
221 return autoTimers;
222 }
223
224 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("timer"))
225 {
226 AutoTimer newAutoTimer;
227
228 if (!newAutoTimer.UpdateFrom(pNode, m_channels))
229 continue;
230
231 autoTimers.emplace_back(newAutoTimer);
232
233 Logger::Log(LEVEL_INFO, "%s fetched AutoTimer entry '%s', begin '%lld', end '%lld'", __FUNCTION__, newAutoTimer.GetTitle().c_str(), static_cast<long long>(newAutoTimer.GetStartTime()), static_cast<long long>(newAutoTimer.GetEndTime()));
234 }
235
236 Logger::Log(LEVEL_INFO, "%s fetched %u AutoTimer Entries", __FUNCTION__, autoTimers.size());
237 return autoTimers;
238 }
239
240 bool Timers::IsAutoTimer(const PVR_TIMER& timer) const
241 {
242 return timer.iTimerType == Timer::Type::EPG_AUTO_SEARCH;
243 }
244
245 void Timers::GetTimerTypes(std::vector<PVR_TIMER_TYPE>& types) const
246 {
247 struct TimerType : PVR_TIMER_TYPE
248 {
249 TimerType(unsigned int id,
250 unsigned int attributes,
251 const std::string& description = std::string(),
252 const std::vector<std::pair<int, std::string>>& groupValues = std::vector<std::pair<int, std::string>>(),
253 const std::vector<std::pair<int, std::string>>& deDupValues = std::vector<std::pair<int, std::string>>(),
254 int preventDuplicateEpisodesDefault = AutoTimer::DeDup::DISABLED)
255 {
256 int i;
257 memset(this, 0, sizeof(PVR_TIMER_TYPE));
258
259 iId = id;
260 iAttributes = attributes;
261 strncpy(strDescription, description.c_str(), sizeof(strDescription) - 1);
262
263 if ((iRecordingGroupSize = groupValues.size()))
264 iRecordingGroupDefault = groupValues[0].first;
265 i = 0;
266 for (const auto& group : groupValues)
267 {
268 recordingGroup[i].iValue = group.first;
269 strncpy(recordingGroup[i].strDescription, group.second.c_str(), sizeof(recordingGroup[i].strDescription) - 1);
270 i++;
271 }
272
273 if ((iPreventDuplicateEpisodesSize = deDupValues.size()))
274 iPreventDuplicateEpisodesDefault = preventDuplicateEpisodesDefault;
275 i = 0;
276 for (const auto& deDup : deDupValues)
277 {
278 preventDuplicateEpisodes[i].iValue = deDup.first;
279 strncpy(preventDuplicateEpisodes[i].strDescription, deDup.second.c_str(), sizeof(preventDuplicateEpisodes[i].strDescription) - 1);
280 i++;
281 }
282 }
283 };
284
285 /* PVR_Timer.iRecordingGroup values and presentation.*/
286 std::vector<std::pair<int, std::string>> groupValues = {
287 {0, LocalizedString(30410)}, //automatic
288 };
289 for (const auto& recf : m_locations)
290 groupValues.emplace_back(groupValues.size(), recf);
291
292 /* One-shot manual (time and channel based) */
293 TimerType* t = new TimerType(
294 Timer::Type::MANUAL_ONCE,
295 PVR_TIMER_TYPE_IS_MANUAL |
296 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
297 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
298 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
299 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
300 PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN |
301 PVR_TIMER_TYPE_SUPPORTS_RECORDING_GROUP |
302 PVR_TIMER_TYPE_FORBIDS_EPG_TAG_ON_CREATE,
303 LocalizedString(30422), // Once off time/channel based
304 groupValues);
305 types.emplace_back(*t);
306 delete t;
307
308 /* One-shot generated by manual repeating timer - note these are completely read only and cannot be edited */
309 t = new TimerType(
310 Timer::Type::READONLY_REPEATING_ONCE,
311 PVR_TIMER_TYPE_IS_MANUAL |
312 PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES |
313 PVR_TIMER_TYPE_IS_READONLY |
314 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
315 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
316 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
317 PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN |
318 PVR_TIMER_TYPE_SUPPORTS_RECORDING_GROUP,
319 LocalizedString(30421), // Once off timer (set by repeating time/channel based rule)
320 groupValues);
321 types.emplace_back(*t);
322 delete t;
323
324 /* Repeating manual (time and channel based) */
325 t = new TimerType(
326 Timer::Type::MANUAL_REPEATING,
327 PVR_TIMER_TYPE_IS_MANUAL |
328 PVR_TIMER_TYPE_IS_REPEATING |
329 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
330 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
331 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
332 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
333 PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS |
334 PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN |
335 PVR_TIMER_TYPE_SUPPORTS_RECORDING_GROUP |
336 PVR_TIMER_TYPE_FORBIDS_EPG_TAG_ON_CREATE,
337 LocalizedString(30423), // Repeating time/channel based
338 groupValues);
339 types.emplace_back(*t);
340 delete t;
341
342 /* One-shot epg based */
343 t = new TimerType(
344 Timer::Type::EPG_ONCE,
345 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
346 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
347 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
348 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
349 PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN |
350 PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE,
351 LocalizedString(30424)); // One time guide-based
352 types.emplace_back(*t);
353 delete t;
354
355 if (!Settings::GetInstance().SupportsAutoTimers() || !m_settings.GetAutoTimersEnabled())
356 {
357 // Allow this type of timer to be created from kodi if autotimers are not available
358 // as otherwise there is no way to create a repeating EPG timer rule
359 /* Repeating epg based */
360 t = new TimerType(
361 Timer::Type::EPG_REPEATING,
362 PVR_TIMER_TYPE_IS_REPEATING |
363 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
364 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
365 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
366 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
367 PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS,
368 LocalizedString(30425)); // Repeating guide-based
369 types.emplace_back(*t);
370 delete t;
371 }
372 else
373 {
374 // This type can only be created on the Enigma2 device (i.e. not via kodi PVR) if autotimers are used.
375 // In this case this type is superflous and just clutters the UI on creation.
376 /* Repeating epg based */
377 t = new TimerType(
378 Timer::Type::EPG_REPEATING,
379 PVR_TIMER_TYPE_IS_REPEATING |
380 PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES |
381 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
382 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
383 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
384 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
385 PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS,
386 LocalizedString(30425)); // Repeating guide-based
387 types.emplace_back(*t);
388 delete t;
389
390 /* PVR_Timer.iPreventDuplicateEpisodes values and presentation.*/
391 static std::vector<std::pair<int, std::string>> deDupValues =
392 {
393 { AutoTimer::DeDup::DISABLED, LocalizedString(30430) },
394 { AutoTimer::DeDup::CHECK_TITLE, LocalizedString(30431) },
395 { AutoTimer::DeDup::CHECK_TITLE_AND_SHORT_DESC, LocalizedString(30432) },
396 { AutoTimer::DeDup::CHECK_TITLE_AND_ALL_DESCS, LocalizedString(30433) },
397 };
398
399 /* epg auto search */
400 t = new TimerType(
401 Timer::Type::EPG_AUTO_SEARCH,
402 PVR_TIMER_TYPE_IS_REPEATING |
403 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
404 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
405 PVR_TIMER_TYPE_SUPPORTS_ANY_CHANNEL |
406 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
407 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
408 PVR_TIMER_TYPE_SUPPORTS_START_ANYTIME |
409 PVR_TIMER_TYPE_SUPPORTS_END_ANYTIME |
410 PVR_TIMER_TYPE_SUPPORTS_WEEKDAYS |
411 PVR_TIMER_TYPE_SUPPORTS_TITLE_EPG_MATCH |
412 PVR_TIMER_TYPE_SUPPORTS_FULLTEXT_EPG_MATCH |
413 PVR_TIMER_TYPE_SUPPORTS_RECORDING_GROUP |
414 PVR_TIMER_TYPE_SUPPORTS_RECORD_ONLY_NEW_EPISODES |
415 PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE,
416 LocalizedString(30426), // Auto guide-based
417 groupValues, deDupValues, AutoTimer::DeDup::CHECK_TITLE_AND_ALL_DESCS);
418 types.emplace_back(*t);
419 delete t;
420
421 /* One-shot created by epg auto search */
422 t = new TimerType(
423 Timer::Type::EPG_AUTO_ONCE,
424 PVR_TIMER_TYPE_IS_MANUAL |
425 PVR_TIMER_TYPE_FORBIDS_NEW_INSTANCES |
426 PVR_TIMER_TYPE_IS_READONLY |
427 PVR_TIMER_TYPE_SUPPORTS_READONLY_DELETE |
428 PVR_TIMER_TYPE_SUPPORTS_ENABLE_DISABLE |
429 PVR_TIMER_TYPE_SUPPORTS_CHANNELS |
430 PVR_TIMER_TYPE_SUPPORTS_START_TIME |
431 PVR_TIMER_TYPE_SUPPORTS_END_TIME |
432 PVR_TIMER_TYPE_SUPPORTS_START_END_MARGIN |
433 PVR_TIMER_TYPE_SUPPORTS_RECORDING_GROUP |
434 PVR_TIMER_TYPE_REQUIRES_EPG_TAG_ON_CREATE,
435 LocalizedString(30420), // Once off timer (set by auto guide-based rule)
436 groupValues);
437 types.emplace_back(*t);
438 delete t;
439 }
440 }
441
442 int Timers::GetTimerCount() const
443 {
444 return m_timers.size();
445 }
446
447 int Timers::GetAutoTimerCount() const
448 {
449 return m_autotimers.size();
450 }
451
452 void Timers::GetTimers(std::vector<PVR_TIMER>& timers) const
453 {
454 for (const auto& timer : m_timers)
455 {
456 Logger::Log(LEVEL_DEBUG, "%s - Transfer timer '%s', ClientIndex '%d'", __FUNCTION__, timer.GetTitle().c_str(), timer.GetClientIndex());
457 PVR_TIMER tag = {0};
458
459 timer.UpdateTo(tag);
460
461 timers.emplace_back(tag);
462 }
463 }
464
465 void Timers::GetAutoTimers(std::vector<PVR_TIMER>& timers) const
466 {
467 for (const auto& autoTimer : m_autotimers)
468 {
469 Logger::Log(LEVEL_DEBUG, "%s - Transfer timer '%s', ClientIndex '%d'", __FUNCTION__, autoTimer.GetTitle().c_str(),
470 autoTimer.GetClientIndex());
471 PVR_TIMER tag = {0};
472
473 autoTimer.UpdateTo(tag);
474
475 timers.emplace_back(tag);
476 }
477 }
478
479 Timer* Timers::GetTimer(std::function<bool(const Timer&)> func)
480 {
481 return GetTimer<Timer>(func, m_timers);
482 }
483
484 AutoTimer* Timers::GetAutoTimer(std::function<bool(const AutoTimer&)> func)
485 {
486 return GetTimer<AutoTimer>(func, m_autotimers);
487 }
488
489 PVR_ERROR Timers::AddTimer(const PVR_TIMER& timer)
490 {
491 if (IsAutoTimer(timer))
492 return AddAutoTimer(timer);
493
494 Logger::Log(LEVEL_DEBUG, "%s - Start", __FUNCTION__);
495
496 const std::string serviceReference = m_channels.GetChannel(timer.iClientChannelUid)->GetServiceReference().c_str();
497 Tags tags;
498
499 if (timer.iTimerType == Timer::MANUAL_ONCE || timer.iTimerType == Timer::MANUAL_REPEATING)
500 tags.AddTag(TAG_FOR_MANUAL_TIMER);
501 else
502 tags.AddTag(TAG_FOR_EPG_TIMER);
503
504 if (m_channels.GetChannel(timer.iClientChannelUid)->IsRadio())
505 tags.AddTag(TAG_FOR_CHANNEL_TYPE, VALUE_FOR_CHANNEL_TYPE_RADIO);
506 else
507 tags.AddTag(TAG_FOR_CHANNEL_TYPE, VALUE_FOR_CHANNEL_TYPE_TV);
508
509 tags.AddTag(TAG_FOR_CHANNEL_REFERENCE, serviceReference, true);
510
511 unsigned int startPadding = timer.iMarginStart;
512 unsigned int endPadding = timer.iMarginEnd;
513
514 if (startPadding == 0 && endPadding == 0)
515 {
516 startPadding = Settings::GetInstance().GetDeviceSettings()->GetGlobalRecordingStartMargin();
517 endPadding = Settings::GetInstance().GetDeviceSettings()->GetGlobalRecordingEndMargin();
518 }
519
520 bool alreadyStarted = false;
521 time_t startTime, endTime;
522 time_t now = std::time(nullptr);
523 if ((timer.startTime - (startPadding * 60)) < now)
524 {
525 alreadyStarted = true;
526 startTime = now;
527 if (timer.startTime < now)
528 startPadding = 0;
529 else
530 startPadding = (timer.startTime - now) / 60;
531 }
532 else
533 {
534 startTime = timer.startTime - (startPadding * 60);
535 }
536 endTime = timer.endTime + (endPadding * 60);
537
538 tags.AddTag(TAG_FOR_PADDING, StringUtils::Format("%u,%u", startPadding, endPadding));
539
540 std::string title = timer.strTitle;
541 std::string description = timer.strSummary;
542 unsigned int epgUid = timer.iEpgUid;
543 bool foundEntry = false;
544
545 if (Settings::GetInstance().IsOpenWebIf() && (timer.iTimerType == Timer::EPG_ONCE || timer.iTimerType == Timer::MANUAL_ONCE))
546 {
547 // We try to find the EPG Entry and use it's details
548 EpgPartialEntry partialEntry = m_epg.LoadEPGEntryPartialDetails(serviceReference, timer.startTime < now ? now : timer.startTime);
549
550 if (partialEntry.EntryFound())
551 {
552 foundEntry = true;
553
554 /* Note that plot (long desc) is automatically written to a timer entry by the backend
555 therefore we only need to send outline as description to preserve both.
556 Once a timer completes, long description will be cleared so if description
557 is not populated we set it to the value of long description
558 */
559 title = partialEntry.GetTitle();
560 description = partialEntry.GetPlotOutline();
561 epgUid = partialEntry.GetEpgUid();
562
563 // Very important for providers that only use the plot field.
564 if (description.empty())
565 description = partialEntry.GetPlot();
566
567 tags.AddTag(TAG_FOR_GENRE_ID, StringUtils::Format("0x%02X", partialEntry.GetGenreType() | partialEntry.GetGenreSubType()));
568 }
569 }
570
571 if (!foundEntry)
572 tags.AddTag(TAG_FOR_GENRE_ID, StringUtils::Format("0x%02X", timer.iGenreType | timer.iGenreSubType));
573
574 std::string strTmp;
575 if (!m_settings.GetRecordingPath().empty())
576 strTmp = StringUtils::Format("web/timeradd?sRef=%s&repeated=%d&begin=%lld&end=%lld&name=%s&description=%s&eit=%d&tags=%s&dirname=&s",
577 WebUtils::URLEncodeInline(serviceReference).c_str(), timer.iWeekdays, static_cast<long long>(startTime), static_cast<long long>(endTime),
578 WebUtils::URLEncodeInline(title).c_str(), WebUtils::URLEncodeInline(description).c_str(), epgUid,
579 WebUtils::URLEncodeInline(tags.GetTags()).c_str(), WebUtils::URLEncodeInline(m_settings.GetRecordingPath()).c_str());
580 else
581 strTmp = StringUtils::Format("web/timeradd?sRef=%s&repeated=%d&begin=%lld&end=%lld&name=%s&description=%s&eit=%d&tags=%s",
582 WebUtils::URLEncodeInline(serviceReference).c_str(), timer.iWeekdays, static_cast<long long>(startTime), static_cast<long long>(endTime),
583 WebUtils::URLEncodeInline(title).c_str(), WebUtils::URLEncodeInline(description).c_str(), epgUid,
584 WebUtils::URLEncodeInline(tags.GetTags()).c_str());
585
586 Logger::Log(LEVEL_DEBUG, "%s - Command: %s", __FUNCTION__, strTmp.c_str());
587
588 std::string strResult;
589 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
590 return PVR_ERROR_SERVER_ERROR;
591
592 Logger::Log(LEVEL_DEBUG, "%s - Updating timers", __FUNCTION__);
593
594 TimerUpdates();
595
596 if (alreadyStarted)
597 {
598 Logger::Log(LEVEL_DEBUG, "%s - Timer started, triggering recording update", __FUNCTION__);
599 PVR->TriggerRecordingUpdate();
600 }
601
602 return PVR_ERROR_NO_ERROR;
603 }
604
605 PVR_ERROR Timers::AddAutoTimer(const PVR_TIMER& timer)
606 {
607 Logger::Log(LEVEL_DEBUG, "%s - Start", __FUNCTION__);
608
609 std::string strTmp = StringUtils::Format("autotimer/edit?");
610
611 strTmp += StringUtils::Format("name=%s", WebUtils::URLEncodeInline(timer.strTitle).c_str());
612 strTmp += StringUtils::Format("&match=%s", WebUtils::URLEncodeInline(timer.strEpgSearchString).c_str());
613
614 if (timer.state != PVR_TIMER_STATE_DISABLED)
615 strTmp += StringUtils::Format("&enabled=%s", WebUtils::URLEncodeInline(AUTOTIMER_ENABLED_YES).c_str());
616 else
617 strTmp += StringUtils::Format("&enabled=%s", WebUtils::URLEncodeInline(AUTOTIMER_ENABLED_NO).c_str());
618
619 if (!timer.bStartAnyTime)
620 {
621 time_t startTime = timer.startTime;
622 std::tm timeinfo = *std::localtime(&startTime);
623 strTmp += StringUtils::Format("&timespanFrom=%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
624 }
625
626 if (!timer.bEndAnyTime)
627 {
628 time_t endTime = timer.endTime;
629 std::tm timeinfo = *std::localtime(&endTime);
630 strTmp += StringUtils::Format("&timespanTo=%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
631 }
632
633 strTmp += StringUtils::Format("&encoding=%s", WebUtils::URLEncodeInline(AUTOTIMER_ENCODING).c_str());
634 strTmp += StringUtils::Format("&searchCase=%s", WebUtils::URLEncodeInline(AUTOTIMER_SEARCH_CASE_SENSITIVE).c_str());
635 if (timer.bFullTextEpgSearch)
636 strTmp += StringUtils::Format("&searchType=%s", WebUtils::URLEncodeInline(AUTOTIMER_SEARCH_TYPE_DESCRIPTION).c_str());
637 else
638 strTmp += StringUtils::Format("&searchType=%s", WebUtils::URLEncodeInline(AUTOTIMER_SEARCH_TYPE_EXACT).c_str());
639
640 std::underlying_type<AutoTimer::DeDup>::type deDup = static_cast<AutoTimer::DeDup>(timer.iPreventDuplicateEpisodes);
641 if (deDup == AutoTimer::DeDup::DISABLED)
642 {
643 strTmp += StringUtils::Format("&avoidDuplicateDescription=0");
644 }
645 else
646 {
647 strTmp += StringUtils::Format("&avoidDuplicateDescription=%s", AUTOTIMER_AVOID_DUPLICATE_ANY_SERVICE_OR_RECORDING.c_str());
648 switch (deDup)
649 {
650 case AutoTimer::DeDup::CHECK_TITLE:
651 strTmp += StringUtils::Format("&searchForDuplicateDescription=%s", AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE.c_str());
652 break;
653 case AutoTimer::DeDup::CHECK_TITLE_AND_SHORT_DESC:
654 strTmp += StringUtils::Format("&searchForDuplicateDescription=%s", AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_SHORT_DESC.c_str());
655 break;
656 case AutoTimer::DeDup::CHECK_TITLE_AND_ALL_DESCS:
657 strTmp += StringUtils::Format("&searchForDuplicateDescription=%s", AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_ALL_DESCS.c_str());
658 break;
659 }
660 }
661
662 if (timer.iClientChannelUid != PVR_TIMER_ANY_CHANNEL)
663 {
664 const std::string serviceReference = m_channels.GetChannel(timer.iClientChannelUid)->GetServiceReference();
665
666 //single channel
667 strTmp += StringUtils::Format("&services=%s", WebUtils::URLEncodeInline(serviceReference).c_str());
668
669 if (m_channels.GetChannel(timer.iClientChannelUid)->IsRadio())
670 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_TYPE.c_str(), VALUE_FOR_CHANNEL_TYPE_RADIO.c_str())).c_str());
671 else
672 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_TYPE.c_str(), VALUE_FOR_CHANNEL_TYPE_TV.c_str())).c_str());
673
674 std::string tagValue = serviceReference;
675 std::replace(tagValue.begin(), tagValue.end(), ' ', '_');
676 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_REFERENCE.c_str(), tagValue.c_str())).c_str());
677 }
678 else
679 {
680 const std::string serviceReference = m_epg.FindServiceReference(timer.strTitle, timer.iEpgUid, timer.startTime, timer.endTime);
681 if (!serviceReference.empty())
682 {
683 const auto channel = m_channels.GetChannel(serviceReference);
684
685 if (channel)
686 {
687 bool isRadio = channel->IsRadio();
688
689 if (isRadio)
690 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_TYPE.c_str(), VALUE_FOR_CHANNEL_TYPE_RADIO.c_str())).c_str());
691 else
692 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_TYPE.c_str(), VALUE_FOR_CHANNEL_TYPE_TV.c_str())).c_str());
693
694 std::string tagValue = serviceReference;
695 std::replace(tagValue.begin(), tagValue.end(), ' ', '_');
696 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_REFERENCE.c_str(), tagValue.c_str())).c_str());
697
698 if (!m_settings.UsesLastScannedChannelGroup())
699 strTmp += BuildAddUpdateAutoTimerLimitGroupsParams(channel);
700 }
701 }
702
703 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s", TAG_FOR_ANY_CHANNEL.c_str())).c_str());
704 }
705
706 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("GenreId=0x%02X", timer.iGenreType | timer.iGenreSubType)).c_str());
707
708 strTmp += Timers::BuildAddUpdateAutoTimerIncludeParams(timer.iWeekdays);
709
710 Logger::Log(LEVEL_DEBUG, "%s - Command: %s", __FUNCTION__, strTmp.c_str());
711
712 std::string strResult;
713 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
714 return PVR_ERROR_SERVER_ERROR;
715
716 if (timer.state == PVR_TIMER_STATE_RECORDING)
717 {
718 Logger::Log(LEVEL_DEBUG, "%s - Timer started, triggering recording update", __FUNCTION__);
719 PVR->TriggerRecordingUpdate();
720 }
721
722 Logger::Log(LEVEL_DEBUG, "%s - Updating timers", __FUNCTION__);
723
724 TimerUpdates();
725
726 return PVR_ERROR_NO_ERROR;
727 }
728
729 PVR_ERROR Timers::UpdateTimer(const PVR_TIMER& timer)
730 {
731 if (IsAutoTimer(timer))
732 return UpdateAutoTimer(timer);
733
734 Logger::Log(LEVEL_DEBUG, "%s timer channelid '%d'", __FUNCTION__, timer.iClientChannelUid);
735
736 const std::string strServiceReference = m_channels.GetChannel(timer.iClientChannelUid)->GetServiceReference().c_str();
737
738 const auto it = std::find_if(m_timers.cbegin(), m_timers.cend(), [&timer](const Timer& myTimer)
739 {
740 return myTimer.GetClientIndex() == timer.iClientIndex;
741 });
742
743 if (it != m_timers.cend())
744 {
745 Timer oldTimer = *it;
746
747 Logger::Log(LEVEL_DEBUG, "%s old timer channelid '%d'", __FUNCTION__, oldTimer.GetChannelId());
748
749 Tags tags(oldTimer.GetTags());
750 tags.AddTag(TAG_FOR_CHANNEL_REFERENCE, strServiceReference, true);
751
752 int iDisabled = 0;
753 if (timer.state == PVR_TIMER_STATE_DISABLED)
754 iDisabled = 1;
755
756 unsigned int startPadding = timer.iMarginStart;
757 unsigned int endPadding = timer.iMarginEnd;
758
759 if (startPadding == 0 && endPadding == 0)
760 {
761 startPadding = Settings::GetInstance().GetDeviceSettings()->GetGlobalRecordingStartMargin();
762 endPadding = Settings::GetInstance().GetDeviceSettings()->GetGlobalRecordingEndMargin();
763 }
764
765 bool alreadyStarted = false;
766 time_t startTime, endTime;
767 time_t now = std::time(nullptr);
768 if ((timer.startTime - (startPadding * 60)) < now)
769 {
770 alreadyStarted = true;
771 startTime = now;
772 if (timer.startTime < now)
773 startPadding = 0;
774 else
775 startPadding = (timer.startTime - now) / 60;
776 }
777 else
778 {
779 startTime = timer.startTime - (startPadding * 60);
780 }
781 endTime = timer.endTime + (endPadding * 60);
782
783 tags.AddTag(TAG_FOR_PADDING, StringUtils::Format("%u,%u", startPadding, endPadding));
784
785 /* Note that plot (long desc) is automatically written to a timer entry by the backend
786 therefore we only need to send outline as description to preserve both.
787 Once a timer completes, long description will be cleared so if description
788 is not populated we set it to the value of long description.
789 Very important for providers that only use the plot field.
790 */
791 const std::string& description = !oldTimer.GetPlotOutline().empty() ? oldTimer.GetPlotOutline() : oldTimer.GetPlot();
792
793 const std::string strTmp = StringUtils::Format("web/timerchange?sRef=%s&begin=%lld&end=%lld&name=%s&eventID=&description=%s&tags=%s&afterevent=3&eit=0&disabled=%d&justplay=0&repeated=%d&channelOld=%s&beginOld=%lld&endOld=%lld&deleteOldOnSave=1",
794 WebUtils::URLEncodeInline(strServiceReference).c_str(), static_cast<long long>(startTime), static_cast<long long>(endTime),
795 WebUtils::URLEncodeInline(timer.strTitle).c_str(), WebUtils::URLEncodeInline(description).c_str(),
796 WebUtils::URLEncodeInline(tags.GetTags()).c_str(), iDisabled, timer.iWeekdays,
797 WebUtils::URLEncodeInline(oldTimer.GetServiceReference()).c_str(),
798 static_cast<long long>(oldTimer.GetRealStartTime()),
799 static_cast<long long>(oldTimer.GetRealEndTime()));
800
801 std::string strResult;
802 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
803 return PVR_ERROR_SERVER_ERROR;
804
805 TimerUpdates();
806
807 if (alreadyStarted)
808 PVR->TriggerRecordingUpdate();
809
810 return PVR_ERROR_NO_ERROR;
811 }
812
813 return PVR_ERROR_SERVER_ERROR;
814 }
815
816 std::string Timers::RemovePaddingTag(std::string tag)
817 {
818 std::regex regex(" Padding=[0-9]+,[0-9]+ *");
819 std::string replaceWith = "";
820
821 return std::regex_replace(tag, regex, replaceWith);
822 }
823
824 PVR_ERROR Timers::UpdateAutoTimer(const PVR_TIMER& timer)
825 {
826 const auto it = std::find_if(m_autotimers.cbegin(), m_autotimers.cend(), [&timer](const AutoTimer& autoTimer)
827 {
828 return autoTimer.GetClientIndex() == timer.iClientIndex;
829 });
830
831 if (it != m_autotimers.cend())
832 {
833 AutoTimer timerToUpdate = *it;
834
835 std::string strTmp = StringUtils::Format("autotimer/edit?id=%d", timerToUpdate.GetBackendId());
836
837 strTmp += StringUtils::Format("&name=%s", WebUtils::URLEncodeInline(timer.strTitle).c_str());
838 strTmp += StringUtils::Format("&match=%s", WebUtils::URLEncodeInline(timer.strEpgSearchString).c_str());
839
840 if (timer.state != PVR_TIMER_STATE_DISABLED)
841 strTmp += StringUtils::Format("&enabled=%s", WebUtils::URLEncodeInline(AUTOTIMER_ENABLED_YES).c_str());
842 else
843 strTmp += StringUtils::Format("&enabled=%s", WebUtils::URLEncodeInline(AUTOTIMER_ENABLED_NO).c_str());
844
845 if (!timer.bStartAnyTime)
846 {
847 time_t startTime = timer.startTime;
848 std::tm timeinfo = *std::localtime(&startTime);
849 strTmp += StringUtils::Format("&timespanFrom=%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
850 }
851
852 if (!timer.bEndAnyTime)
853 {
854 time_t endTime = timer.endTime;
855 std::tm timeinfo = *std::localtime(&endTime);
856 strTmp += StringUtils::Format("&timespanTo=%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
857 }
858
859 strTmp += StringUtils::Format("&encoding=%s", WebUtils::URLEncodeInline(AUTOTIMER_ENCODING).c_str());
860
861 if (timer.bFullTextEpgSearch)
862 strTmp += StringUtils::Format("&searchType=%s", WebUtils::URLEncodeInline(AUTOTIMER_SEARCH_TYPE_DESCRIPTION).c_str());
863 else
864 strTmp += StringUtils::Format("&searchType=%s", WebUtils::URLEncodeInline(AUTOTIMER_SEARCH_TYPE_EXACT).c_str());
865
866 if (!timerToUpdate.GetSearchCase().empty())
867 strTmp += StringUtils::Format("&searchCase=%s", WebUtils::URLEncodeInline(AUTOTIMER_SEARCH_CASE_SENSITIVE).c_str());
868
869 std::underlying_type<AutoTimer::DeDup>::type deDup = static_cast<AutoTimer::DeDup>(timer.iPreventDuplicateEpisodes);
870 if (deDup == AutoTimer::DeDup::DISABLED)
871 {
872 strTmp += StringUtils::Format("&avoidDuplicateDescription=0");
873 }
874 else
875 {
876 strTmp += StringUtils::Format("&avoidDuplicateDescription=%s", AUTOTIMER_AVOID_DUPLICATE_ANY_SERVICE_OR_RECORDING.c_str());
877 switch (deDup)
878 {
879 case AutoTimer::DeDup::CHECK_TITLE:
880 strTmp += StringUtils::Format("&searchForDuplicateDescription=%s", AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE.c_str());
881 break;
882 case AutoTimer::DeDup::CHECK_TITLE_AND_SHORT_DESC:
883 strTmp += StringUtils::Format("&searchForDuplicateDescription=%s", AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_SHORT_DESC.c_str());
884 break;
885 case AutoTimer::DeDup::CHECK_TITLE_AND_ALL_DESCS:
886 strTmp += StringUtils::Format("&searchForDuplicateDescription=%s", AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_ALL_DESCS.c_str());
887 break;
888 }
889 }
890
891 if (timer.iClientChannelUid != PVR_TIMER_ANY_CHANNEL &&
892 (timerToUpdate.GetAnyChannel() || (!timerToUpdate.GetAnyChannel() && timer.iClientChannelUid != timerToUpdate.GetChannelId())))
893 {
894 const std::string serviceReference = m_channels.GetChannel(timer.iClientChannelUid)->GetServiceReference();
895
896 //move to single channel
897 strTmp += StringUtils::Format("&services=%s", WebUtils::URLEncodeInline(serviceReference).c_str());
898
899 //Update tags
900 strTmp += StringUtils::Format("&tag=");
901
902 if (m_channels.GetChannel(timer.iClientChannelUid)->IsRadio())
903 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_TYPE.c_str(), VALUE_FOR_CHANNEL_TYPE_RADIO.c_str())).c_str());
904 else
905 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_TYPE.c_str(), VALUE_FOR_CHANNEL_TYPE_TV.c_str())).c_str());
906
907 std::string tagValue = serviceReference;
908 std::replace(tagValue.begin(), tagValue.end(), ' ', '_');
909 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_REFERENCE.c_str(), tagValue.c_str())).c_str());
910
911 if (timerToUpdate.ContainsTag(TAG_FOR_GENRE_ID))
912 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_GENRE_ID.c_str(), timerToUpdate.ReadTagValue(TAG_FOR_GENRE_ID).c_str())).c_str());
913
914 //Clear bouquets
915 strTmp += "&bouquets=";
916 }
917 else if (!timerToUpdate.GetAnyChannel() && timer.iClientChannelUid == PVR_TIMER_ANY_CHANNEL)
918 {
919 const auto& channel = m_channels.GetChannel(timerToUpdate.GetChannelId());
920
921 //Move to any channel
922 strTmp += StringUtils::Format("&services=");
923
924 //Update tags
925 strTmp += StringUtils::Format("&tag=");
926
927 if (timerToUpdate.ContainsTag(TAG_FOR_CHANNEL_TYPE))
928 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_TYPE.c_str(), timerToUpdate.ReadTagValue(TAG_FOR_CHANNEL_TYPE).c_str())).c_str());
929
930 std::string tagValue = channel->GetServiceReference();
931 std::replace(tagValue.begin(), tagValue.end(), ' ', '_');
932 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_CHANNEL_REFERENCE.c_str(), tagValue.c_str())).c_str());
933
934 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s", TAG_FOR_ANY_CHANNEL.c_str())).c_str());
935
936 if (timerToUpdate.ContainsTag(TAG_FOR_GENRE_ID))
937 strTmp += StringUtils::Format("&tag=%s", WebUtils::URLEncodeInline(StringUtils::Format("%s=%s", TAG_FOR_GENRE_ID.c_str(), timerToUpdate.ReadTagValue(TAG_FOR_GENRE_ID).c_str())).c_str());
938
939 //Limit Channel Groups
940 if (!m_settings.UsesLastScannedChannelGroup())
941 strTmp += BuildAddUpdateAutoTimerLimitGroupsParams(channel);
942 }
943
944 strTmp += Timers::BuildAddUpdateAutoTimerIncludeParams(timer.iWeekdays);
945
946 std::string strResult;
947 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
948 return PVR_ERROR_SERVER_ERROR;
949
950 if (timer.state == PVR_TIMER_STATE_RECORDING)
951 PVR->TriggerRecordingUpdate();
952
953 TimerUpdates();
954
955 return PVR_ERROR_NO_ERROR;
956 }
957 return PVR_ERROR_SERVER_ERROR;
958 }
959
960 std::string Timers::BuildAddUpdateAutoTimerLimitGroupsParams(const std::shared_ptr<Channel>& channel)
961 {
962 std::string limitGroupParams;
963
964 if (m_settings.GetLimitAnyChannelAutoTimers() && channel)
965 {
966 if (m_settings.GetLimitAnyChannelAutoTimersToChannelGroups())
967 {
968 for (const auto& group : channel->GetChannelGroupList())
969 limitGroupParams += StringUtils::Format("%s,", group->GetServiceReference().c_str());
970 }
971 else
972 {
973 for (const auto& group : m_channelGroups.GetChannelGroupsList())
974 {
975 if (group->IsRadio() == channel->IsRadio())
976 limitGroupParams += StringUtils::Format("%s,", group->GetServiceReference().c_str());
977 }
978 }
979 }
980
981 return StringUtils::Format("&bouquets=%s", WebUtils::URLEncodeInline(limitGroupParams).c_str());
982 }
983
984 std::string Timers::BuildAddUpdateAutoTimerIncludeParams(int weekdays)
985 {
986 bool everyday = true;
987 std::string includeParams;
988 if (weekdays != PVR_WEEKDAY_NONE)
989 {
990 for (int i = 0; i < DAYS_IN_WEEK; i++)
991 {
992 if (1 & (weekdays >> i))
993 {
994 includeParams += StringUtils::Format("&dayofweek=%d", i);
995 }
996 else
997 {
998 everyday = false;
999 }
1000 }
1001
1002 if (everyday)
1003 includeParams = "&dayofweek=";
1004 }
1005 else
1006 {
1007 includeParams = "&dayofweek=";
1008 }
1009
1010 return includeParams;
1011 }
1012
1013 PVR_ERROR Timers::DeleteTimer(const PVR_TIMER& timer)
1014 {
1015 if (IsAutoTimer(timer))
1016 return DeleteAutoTimer(timer);
1017
1018 const auto it = std::find_if(m_timers.cbegin(), m_timers.cend(), [&timer](const Timer& myTimer)
1019 {
1020 return myTimer.GetClientIndex() == timer.iClientIndex;
1021 });
1022
1023 if (it != m_timers.cend())
1024 {
1025 Timer timerToDelete = *it;
1026
1027 const std::string strTmp = StringUtils::Format("web/timerdelete?sRef=%s&begin=%lld&end=%lld",
1028 WebUtils::URLEncodeInline(timerToDelete.GetServiceReference()).c_str(),
1029 static_cast<long long>(timerToDelete.GetRealStartTime()),
1030 static_cast<long long>(timerToDelete.GetRealEndTime()));
1031
1032 std::string strResult;
1033 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
1034 return PVR_ERROR_SERVER_ERROR;
1035
1036 if (timer.state == PVR_TIMER_STATE_RECORDING)
1037 PVR->TriggerRecordingUpdate();
1038
1039 TimerUpdates();
1040
1041 return PVR_ERROR_NO_ERROR;
1042 }
1043
1044 return PVR_ERROR_SERVER_ERROR;
1045 }
1046
1047 PVR_ERROR Timers::DeleteAutoTimer(const PVR_TIMER &timer)
1048 {
1049 const auto it = std::find_if(m_autotimers.cbegin(), m_autotimers.cend(), [&timer](const AutoTimer& autoTimer)
1050 {
1051 return autoTimer.GetClientIndex() == timer.iClientIndex;
1052 });
1053
1054 if (it != m_autotimers.cend())
1055 {
1056 AutoTimer timerToDelete = *it;
1057
1058 //remove any child timers
1059 bool childTimerIsRecording = false;
1060 for (const auto& childTimer : m_timers)
1061 {
1062 if (childTimer.GetParentClientIndex() == timerToDelete.GetClientIndex())
1063 {
1064 const std::string strTmp = StringUtils::Format("web/timerdelete?sRef=%s&begin=%lld&end=%lld",
1065 WebUtils::URLEncodeInline(childTimer.GetServiceReference()).c_str(),
1066 static_cast<long long>(childTimer.GetRealStartTime()),
1067 static_cast<long long>(childTimer.GetRealEndTime()));
1068
1069 std::string strResult;
1070 WebUtils::SendSimpleCommand(strTmp, strResult, true);
1071
1072 if (childTimer.GetState() == PVR_TIMER_STATE_RECORDING)
1073 childTimerIsRecording = true;
1074 }
1075 }
1076
1077 const std::string strTmp = StringUtils::Format("autotimer/remove?id=%u", timerToDelete.GetBackendId());
1078
1079 std::string strResult;
1080 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
1081 return PVR_ERROR_SERVER_ERROR;
1082
1083 if (timer.state == PVR_TIMER_STATE_RECORDING || childTimerIsRecording)
1084 PVR->TriggerRecordingUpdate();
1085
1086 TimerUpdates();
1087
1088 return PVR_ERROR_NO_ERROR;
1089 }
1090
1091 return PVR_ERROR_SERVER_ERROR;
1092 }
1093
1094 void Timers::ClearTimers()
1095 {
1096 m_timers.clear();
1097 m_autotimers.clear();
1098 m_timerChangeWatchers.clear();
1099 }
1100
1101 void Timers::AddTimerChangeWatcher(std::atomic_bool* watcher)
1102 {
1103 m_timerChangeWatchers.emplace_back(watcher);
1104 }
1105
1106 bool Timers::TimerUpdates()
1107 {
1108 bool regularTimersChanged = TimerUpdatesRegular();
1109 bool autoTimersChanged = false;
1110
1111 if (Settings::GetInstance().SupportsAutoTimers() && m_settings.GetAutoTimersEnabled())
1112 autoTimersChanged = TimerUpdatesAuto();
1113
1114 if (regularTimersChanged || autoTimersChanged)
1115 {
1116 Logger::Log(LEVEL_INFO, "%s Changes in timerlist detected, trigger an update!", __FUNCTION__);
1117 PVR->TriggerTimerUpdate();
1118
1119 for (auto watcher : m_timerChangeWatchers)
1120 watcher->store(true);
1121
1122 return true;
1123 }
1124
1125 return false;
1126 }
1127
1128 bool Timers::TimerUpdatesRegular()
1129 {
1130 std::vector<Timer> newtimers = LoadTimers();
1131
1132 for (auto& timer : m_timers)
1133 {
1134 timer.SetUpdateState(UPDATE_STATE_NONE);
1135 }
1136
1137 //Update any timers
1138 unsigned int iUpdated = 0;
1139 unsigned int iUnchanged = 0;
1140
1141 for (auto& newTimer : newtimers)
1142 {
1143 for (auto& existingTimer : m_timers)
1144 {
1145 if (existingTimer.Like(newTimer))
1146 {
1147 if (existingTimer == newTimer)
1148 {
1149 existingTimer.SetUpdateState(UPDATE_STATE_FOUND);
1150 newTimer.SetUpdateState(UPDATE_STATE_FOUND);
1151 iUnchanged++;
1152 }
1153 else
1154 {
1155 newTimer.SetUpdateState(UPDATE_STATE_UPDATED);
1156 existingTimer.SetUpdateState(UPDATE_STATE_UPDATED);
1157
1158 existingTimer.UpdateFrom(newTimer);
1159
1160 iUpdated++;
1161 }
1162 }
1163 }
1164 }
1165
1166 //Remove any timers that are no longer valid
1167 unsigned int iRemoved = m_timers.size();
1168
1169 m_timers.erase(
1170 std::remove_if(m_timers.begin(), m_timers.end(),
1171 [](const Timer& timer) { return timer.GetUpdateState() == UPDATE_STATE_NONE; }),
1172 m_timers.end());
1173
1174 iRemoved -= m_timers.size();
1175
1176 //Add any new autotimers
1177 unsigned int iNew = 0;
1178
1179 for (auto& newTimer : newtimers)
1180 {
1181 if (newTimer.GetUpdateState() == UPDATE_STATE_NEW)
1182 {
1183 newTimer.SetClientIndex(m_clientIndexCounter);
1184 Logger::Log(LEVEL_DEBUG, "%s New timer: '%s', ClientIndex: '%d'", __FUNCTION__, newTimer.GetTitle().c_str(), m_clientIndexCounter);
1185 m_timers.emplace_back(newTimer);
1186 m_clientIndexCounter++;
1187 iNew++;
1188 }
1189 }
1190
1191 //Link any Readonly timers to Repeating Timers
1192 for (const auto& repeatingTimer : m_timers)
1193 {
1194 for (auto& readonlyRepeatingOnceTimer : m_timers)
1195 {
1196 if ((repeatingTimer.GetType() == Timer::MANUAL_REPEATING || repeatingTimer.GetType() == Timer::EPG_REPEATING) &&
1197 readonlyRepeatingOnceTimer.GetType() == Timer::READONLY_REPEATING_ONCE &&
1198 readonlyRepeatingOnceTimer.IsChildOfParent(repeatingTimer))
1199 {
1200 readonlyRepeatingOnceTimer.SetParentClientIndex(repeatingTimer.GetClientIndex());
1201 continue;
1202 }
1203 }
1204 }
1205
1206 Logger::Log(LEVEL_DEBUG, "%s No of timers: removed [%d], untouched [%d], updated '%d', new '%d'", __FUNCTION__, iRemoved, iUnchanged, iUpdated, iNew);
1207
1208 std::vector<EpgEntry> timerBaseEntries;
1209 for (auto& timer : m_timers)
1210 {
1211 EpgEntry entry = timer;
1212 entry.SetStartTime(timer.GetRealStartTime());
1213 entry.SetEndTime(timer.GetRealEndTime());
1214 timerBaseEntries.emplace_back(entry);
1215 }
1216 m_epg.UpdateTimerEPGFallbackEntries(timerBaseEntries);
1217
1218 return (iRemoved != 0 || iUpdated != 0 || iNew != 0);
1219 }
1220
1221 bool Timers::TimerUpdatesAuto()
1222 {
1223 std::vector<AutoTimer> newautotimers = LoadAutoTimers();
1224
1225 for (auto& autoTimer : m_autotimers)
1226 {
1227 autoTimer.SetUpdateState(UPDATE_STATE_NONE);
1228 }
1229
1230 //Update any autotimers
1231 unsigned int iUpdated = 0;
1232 unsigned int iUnchanged = 0;
1233
1234 for (auto& newAutoTimer : newautotimers)
1235 {
1236 for (auto& existingAutoTimer : m_autotimers)
1237 {
1238 if (existingAutoTimer.Like(newAutoTimer))
1239 {
1240 if (existingAutoTimer == newAutoTimer)
1241 {
1242 existingAutoTimer.SetUpdateState(UPDATE_STATE_FOUND);
1243 newAutoTimer.SetUpdateState(UPDATE_STATE_FOUND);
1244 iUnchanged++;
1245 }
1246 else
1247 {
1248 newAutoTimer.SetUpdateState(UPDATE_STATE_UPDATED);
1249 existingAutoTimer.SetUpdateState(UPDATE_STATE_UPDATED);
1250
1251 existingAutoTimer.UpdateFrom(newAutoTimer);
1252
1253 iUpdated++;
1254 }
1255 }
1256 }
1257 }
1258
1259 //Remove any autotimers that are no longer valid
1260 unsigned int iRemoved = m_autotimers.size();
1261
1262 m_autotimers.erase(
1263 std::remove_if(m_autotimers.begin(), m_autotimers.end(),
1264 [](const AutoTimer& autoTimer) { return autoTimer.GetUpdateState() == UPDATE_STATE_NONE; }),
1265 m_autotimers.end());
1266
1267 iRemoved -= m_autotimers.size();
1268
1269 //Add any new autotimers
1270 unsigned int iNew = 0;
1271
1272 for (auto& newAutoTimer : newautotimers)
1273 {
1274 if (newAutoTimer.GetUpdateState() == UPDATE_STATE_NEW)
1275 {
1276 newAutoTimer.SetClientIndex(m_clientIndexCounter);
1277
1278 if ((newAutoTimer.GetChannelId()) == PVR_TIMER_ANY_CHANNEL)
1279 newAutoTimer.SetAnyChannel(true);
1280 Logger::Log(LEVEL_INFO, "%s New auto timer: '%s', ClientIndex: '%d'", __FUNCTION__, newAutoTimer.GetTitle().c_str(), m_clientIndexCounter);
1281 m_autotimers.emplace_back(newAutoTimer);
1282 m_clientIndexCounter++;
1283 iNew++;
1284 }
1285 }
1286
1287 //Link Any child timers to autotimers
1288 for (const auto& autoTimer : m_autotimers)
1289 {
1290 for (auto& timer : m_timers)
1291 {
1292 const std::string autotimerTag = ConvertToAutoTimerTag(autoTimer.GetTitle());
1293
1294 if (timer.GetType() == Timer::EPG_AUTO_ONCE && timer.ContainsTag(TAG_FOR_AUTOTIMER) && timer.ContainsTag(autotimerTag))
1295 {
1296 timer.SetParentClientIndex(autoTimer.GetClientIndex());
1297 continue;
1298 }
1299 }
1300 }
1301
1302 Logger::Log(LEVEL_INFO, "%s No of autotimers: removed [%d], untouched [%d], updated '%d', new '%d'", __FUNCTION__, iRemoved, iUnchanged, iUpdated, iNew);
1303
1304 return (iRemoved != 0 || iUpdated != 0 || iNew != 0);
1305 }
1306
1307 void Timers::RunAutoTimerListCleanup()
1308 {
1309 const std::string strTmp = StringUtils::Format("web/timercleanup?cleanup=true");
1310 std::string strResult;
1311 if (!WebUtils::SendSimpleCommand(strTmp, strResult))
1312 Logger::Log(LEVEL_ERROR, "%s - AutomaticTimerlistCleanup failed!", __FUNCTION__);
1313 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "Epg.h"
24 #include "data/AutoTimer.h"
25 #include "data/Timer.h"
26 #include "extract/EpgEntryExtractor.h"
27 #include "tinyxml.h"
28 #include "kodi/libXBMC_pvr.h"
29
30 #include <atomic>
31 #include <ctime>
32 #include <functional>
33 #include <memory>
34 #include <string>
35 #include <type_traits>
36
37 namespace enigma2
38 {
39 class Timers
40 {
41 public:
42 Timers(Channels& channels, ChannelGroups& channelGroups, std::vector<std::string>& locations, Epg& epg, enigma2::extract::EpgEntryExtractor& entryExtractor)
43 : m_channels(channels), m_channelGroups(channelGroups), m_locations(locations), m_epg(epg), m_entryExtractor(entryExtractor)
44 {
45 m_clientIndexCounter = 1;
46 };
47
48 void GetTimerTypes(std::vector<PVR_TIMER_TYPE>& types) const;
49
50 int GetTimerCount() const;
51 int GetAutoTimerCount() const;
52
53 void GetTimers(std::vector<PVR_TIMER>& timers) const;
54 void GetAutoTimers(std::vector<PVR_TIMER>& timers) const;
55
56 enigma2::data::Timer* GetTimer(std::function<bool(const enigma2::data::Timer&)> func);
57 enigma2::data::AutoTimer* GetAutoTimer(std::function<bool(const enigma2::data::AutoTimer&)> func);
58
59 PVR_ERROR AddTimer(const PVR_TIMER& timer);
60 PVR_ERROR AddAutoTimer(const PVR_TIMER& timer);
61
62 PVR_ERROR UpdateTimer(const PVR_TIMER& timer);
63 PVR_ERROR UpdateAutoTimer(const PVR_TIMER& timer);
64
65 PVR_ERROR DeleteTimer(const PVR_TIMER& timer);
66 PVR_ERROR DeleteAutoTimer(const PVR_TIMER& timer);
67
68 void ClearTimers();
69 bool TimerUpdates();
70 void RunAutoTimerListCleanup();
71 void AddTimerChangeWatcher(std::atomic_bool* watcher);
72
73 private:
74 //templates
75 template<typename T>
76 T* GetTimer(std::function<bool(const T&)> func, std::vector<T>& timerlist);
77
78 // functions
79 std::vector<enigma2::data::Timer> LoadTimers() const;
80 void GenerateChildManualRepeatingTimers(std::vector<enigma2::data::Timer>* timers, enigma2::data::Timer* timer) const;
81 static std::string ConvertToAutoTimerTag(std::string tag);
82 static std::string RemovePaddingTag(std::string tag);
83 std::vector<enigma2::data::AutoTimer> LoadAutoTimers() const;
84 bool IsAutoTimer(const PVR_TIMER& timer) const;
85 bool TimerUpdatesRegular();
86 bool TimerUpdatesAuto();
87 std::string BuildAddUpdateAutoTimerLimitGroupsParams(const std::shared_ptr<data::Channel>& channel);
88 static std::string BuildAddUpdateAutoTimerIncludeParams(int weekdays);
89
90 // members
91 unsigned int m_clientIndexCounter;
92 std::vector<std::atomic_bool*> m_timerChangeWatchers;
93
94 enigma2::extract::EpgEntryExtractor& m_entryExtractor;
95
96 enigma2::Settings& m_settings = enigma2::Settings::GetInstance();
97 std::vector<enigma2::data::Timer> m_timers;
98 std::vector<enigma2::data::AutoTimer> m_autotimers;
99
100 Channels& m_channels;
101 ChannelGroups& m_channelGroups;
102 std::vector<std::string>& m_locations;
103 Epg& m_epg;
104 };
105 } // namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "TimeshiftBuffer.h"
23
24 #include "../client.h"
25 #include "StreamReader.h"
26 #include "p8-platform/util/util.h"
27 #include "utilities/Logger.h"
28
29 using namespace ADDON;
30 using namespace enigma2;
31 using namespace enigma2::utilities;
32
33 TimeshiftBuffer::TimeshiftBuffer(IStreamReader* m_streamReader, const std::string& timeshiftBufferPath, const unsigned int readTimeout)
34 : m_streamReader(m_streamReader)
35 {
36 m_bufferPath = timeshiftBufferPath + "/tsbuffer.ts";
37 m_readTimeout = (readTimeout) ? readTimeout : DEFAULT_READ_TIMEOUT;
38
39 m_filebufferWriteHandle = XBMC->OpenFileForWrite(m_bufferPath.c_str(), true);
40 std::this_thread::sleep_for(std::chrono::milliseconds(100));
41 m_filebufferReadHandle = XBMC->OpenFile(m_bufferPath.c_str(), XFILE::READ_NO_CACHE);
42 }
43
44 TimeshiftBuffer::~TimeshiftBuffer(void)
45 {
46 m_running = false;
47 if (m_inputThread.joinable())
48 m_inputThread.join();
49
50 if (m_filebufferWriteHandle)
51 {
52 // XBMC->TruncateFile doesn't work for unknown reasons
53 XBMC->CloseFile(m_filebufferWriteHandle);
54 void* tmp;
55 if ((tmp = XBMC->OpenFileForWrite(m_bufferPath.c_str(), true)) != nullptr)
56 XBMC->CloseFile(tmp);
57 }
58 if (m_filebufferReadHandle)
59 XBMC->CloseFile(m_filebufferReadHandle);
60
61 if (!XBMC->DeleteFile(m_bufferPath.c_str()))
62 Logger::Log(LEVEL_ERROR, "%s Unable to delete file when timeshift buffer is deleted: %s", __FUNCTION__, m_bufferPath.c_str());
63
64 SAFE_DELETE(m_streamReader);
65 Logger::Log(LEVEL_DEBUG, "%s Timeshift: Stopped", __FUNCTION__);
66 }
67
68 bool TimeshiftBuffer::Start()
69 {
70 if (m_streamReader == nullptr || m_filebufferWriteHandle == nullptr || m_filebufferReadHandle == nullptr)
71 return false;
72 if (m_running)
73 return true;
74
75 Logger::Log(LEVEL_INFO, "%s Timeshift: Started", __FUNCTION__);
76 m_start = time(nullptr);
77 m_running = true;
78 m_inputThread = std::thread([&] { DoReadWrite(); });
79
80 return true;
81 }
82
83 void TimeshiftBuffer::DoReadWrite()
84 {
85 Logger::Log(LEVEL_DEBUG, "%s Timeshift: Thread started", __FUNCTION__);
86 uint8_t buffer[BUFFER_SIZE];
87
88 m_streamReader->Start();
89 while (m_running)
90 {
91 ssize_t read = m_streamReader->ReadData(buffer, sizeof(buffer));
92
93 // don't handle any errors here, assume write fully succeeds
94 ssize_t write = XBMC->WriteFile(m_filebufferWriteHandle, buffer, read);
95
96 std::lock_guard<std::mutex> lock(m_mutex);
97 m_writePos += write;
98
99 m_condition.notify_one();
100 }
101 Logger::Log(LEVEL_DEBUG, "%s Timeshift: Thread stopped", __FUNCTION__);
102 return;
103 }
104
105 int64_t TimeshiftBuffer::Seek(long long position, int whence)
106 {
107 return XBMC->SeekFile(m_filebufferReadHandle, position, whence);
108 }
109
110 int64_t TimeshiftBuffer::Position()
111 {
112 return XBMC->GetFilePosition(m_filebufferReadHandle);
113 }
114
115 int64_t TimeshiftBuffer::Length()
116 {
117 return m_writePos;
118 }
119
120 ssize_t TimeshiftBuffer::ReadData(unsigned char* buffer, unsigned int size)
121 {
122 int64_t requiredLength = Position() + size;
123
124 /* make sure we never read above the current write position */
125 std::unique_lock<std::mutex> lock(m_mutex);
126 bool available = m_condition.wait_for(lock, std::chrono::seconds(m_readTimeout), [&] { return Length() >= requiredLength; });
127
128 if (!available)
129 {
130 Logger::Log(LEVEL_DEBUG, "%s Timeshift: Read timed out; waited %d", __FUNCTION__, m_readTimeout);
131 return -1;
132 }
133
134 return XBMC->ReadFile(m_filebufferReadHandle, buffer, size);
135 }
136
137 std::time_t TimeshiftBuffer::TimeStart()
138 {
139 return m_start;
140 }
141
142 std::time_t TimeshiftBuffer::TimeEnd()
143 {
144 return std::time(nullptr);
145 }
146
147 bool TimeshiftBuffer::IsRealTime()
148 {
149 // other PVRs use 10 seconds here, but we aren't doing any demuxing
150 // we'll therefore just asume 1 secs needs about 1mb
151 return Length() - Position() <= 10 * 1048576;
152 }
153
154 bool TimeshiftBuffer::IsTimeshifting()
155 {
156 return true;
157 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "IStreamReader.h"
24
25 #include <atomic>
26 #include <condition_variable>
27 #include <mutex>
28 #include <thread>
29
30 namespace enigma2
31 {
32 class TimeshiftBuffer : public IStreamReader
33 {
34 public:
35 TimeshiftBuffer(IStreamReader* strReader, const std::string& m_timeshiftBufferPath, const unsigned int m_readTimeoutX);
36 ~TimeshiftBuffer(void);
37
38 bool Start() override;
39 ssize_t ReadData(unsigned char* buffer, unsigned int size) override;
40 int64_t Seek(long long position, int whence) override;
41 int64_t Position() override;
42 int64_t Length() override;
43 std::time_t TimeStart() override;
44 std::time_t TimeEnd() override;
45 bool IsRealTime() override;
46 bool IsTimeshifting() override;
47
48 private:
49 void DoReadWrite();
50
51 static const int BUFFER_SIZE = 32 * 1024;
52 static const int DEFAULT_READ_TIMEOUT = 10;
53 static const int READ_WAITTIME = 50;
54
55 std::string m_bufferPath;
56 IStreamReader* m_streamReader;
57 void* m_filebufferReadHandle;
58 void* m_filebufferWriteHandle;
59 int m_readTimeout;
60 std::time_t m_start = 0;
61 std::atomic<uint64_t> m_writePos = {0};
62
63 std::atomic<bool> m_running = {false};
64 std::thread m_inputThread;
65 std::condition_variable m_condition;
66 std::mutex m_mutex;
67 };
68 } // namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "AutoTimer.h"
23
24 #include "../utilities/LocalizedString.h"
25 #include "inttypes.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "util/XMLUtils.h"
28
29 #include <cstdlib>
30
31 using namespace enigma2;
32 using namespace enigma2::data;
33 using namespace enigma2::utilities;
34
35 bool AutoTimer::Like(const AutoTimer& right) const
36 {
37 return m_backendId == right.m_backendId;
38 }
39
40 bool AutoTimer::operator==(const AutoTimer& right) const
41 {
42 bool isEqual = (!m_title.compare(right.m_title));
43 isEqual &= (m_startTime == right.m_startTime);
44 isEqual &= (m_endTime == right.m_endTime);
45 isEqual &= (m_channelId == right.m_channelId);
46 isEqual &= (m_weekdays == right.m_weekdays);
47
48 isEqual &= (m_searchPhrase == right.m_searchPhrase);
49 isEqual &= (m_searchType == right.m_searchType);
50 isEqual &= (m_searchCase == right.m_searchCase);
51 isEqual &= (m_state == right.m_state);
52 isEqual &= (m_searchFulltext == right.m_searchFulltext);
53 isEqual &= (m_startAnyTime == right.m_startAnyTime);
54 isEqual &= (m_endAnyTime == right.m_endAnyTime);
55 isEqual &= (m_anyChannel == right.m_anyChannel);
56 isEqual &= (m_deDup == right.m_deDup);
57 isEqual &= (m_tags == right.m_tags);
58
59 return isEqual;
60 }
61
62 void AutoTimer::UpdateFrom(const AutoTimer& right)
63 {
64 Timer::UpdateFrom(right);
65
66 m_searchPhrase = right.m_searchPhrase;
67 m_encoding = right.m_encoding;
68 m_searchCase = right.m_searchCase;
69 m_searchType = right.m_searchType;
70 m_searchFulltext = right.m_searchFulltext;
71 m_startAnyTime = right.m_startAnyTime;
72 m_endAnyTime = right.m_endAnyTime;
73 m_anyChannel = right.m_anyChannel;
74 m_deDup = right.m_deDup;
75 m_tags = right.m_tags;
76 }
77
78 void AutoTimer::UpdateTo(PVR_TIMER& left) const
79 {
80 strncpy(left.strTitle, m_title.c_str(), sizeof(left.strTitle) - 1);
81 strncpy(left.strEpgSearchString, m_searchPhrase.c_str(), sizeof(left.strEpgSearchString) - 1);
82 left.iTimerType = m_type;
83 if (m_anyChannel)
84 left.iClientChannelUid = PVR_TIMER_ANY_CHANNEL;
85 else
86 left.iClientChannelUid = m_channelId;
87 left.startTime = m_startTime;
88 left.endTime = m_endTime;
89 left.state = m_state;
90 left.iPriority = 0; // unused
91 left.iLifetime = 0; // unused
92 left.firstDay = 0; // unused
93 left.iWeekdays = m_weekdays;
94 left.iMarginStart = 0; // unused
95 left.iMarginEnd = 0; // unused
96 left.iGenreType = 0; // unused
97 left.iGenreSubType = 0; // unused
98 left.iClientIndex = m_clientIndex;
99 left.bStartAnyTime = m_startAnyTime;
100 left.bEndAnyTime = m_endAnyTime;
101 left.bFullTextEpgSearch = m_searchFulltext;
102 left.iPreventDuplicateEpisodes = m_deDup;
103 }
104
105 bool AutoTimer::UpdateFrom(TiXmlElement* autoTimerNode, Channels& channels)
106 {
107 std::string strTmp;
108 int iTmp;
109
110 m_type = Timer::EPG_AUTO_SEARCH;
111
112 //this is an auto timer so the state is always scheduled unless it's disabled
113 m_state = PVR_TIMER_STATE_SCHEDULED;
114
115 m_tags.clear();
116 if (XMLUtils::GetString(autoTimerNode, "e2tags", strTmp))
117 m_tags = strTmp;
118
119 if (autoTimerNode->QueryStringAttribute("name", &strTmp) == TIXML_SUCCESS)
120 m_title = strTmp;
121
122 if (autoTimerNode->QueryStringAttribute("match", &strTmp) == TIXML_SUCCESS)
123 m_searchPhrase = strTmp;
124
125 if (autoTimerNode->QueryStringAttribute("enabled", &strTmp) == TIXML_SUCCESS)
126 {
127 if (strTmp == AUTOTIMER_ENABLED_NO)
128 {
129 m_state = PVR_TIMER_STATE_DISABLED;
130 }
131 }
132
133 if (autoTimerNode->QueryIntAttribute("id", &iTmp) == TIXML_SUCCESS)
134 m_backendId = iTmp;
135
136 std::string from;
137 std::string to;
138 std::string avoidDuplicateDescription;
139 std::string searchForDuplicateDescription;
140 autoTimerNode->QueryStringAttribute("from", &from);
141 autoTimerNode->QueryStringAttribute("to", &to);
142 autoTimerNode->QueryStringAttribute("avoidDuplicateDescription", &avoidDuplicateDescription);
143 autoTimerNode->QueryStringAttribute("searchForDuplicateDescription", &searchForDuplicateDescription);
144
145 if (avoidDuplicateDescription != AUTOTIMER_AVOID_DUPLICATE_DISABLED)
146 {
147 if (searchForDuplicateDescription == AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE)
148 m_deDup = AutoTimer::DeDup::CHECK_TITLE;
149 else if (searchForDuplicateDescription == AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_SHORT_DESC)
150 m_deDup = AutoTimer::DeDup::CHECK_TITLE_AND_SHORT_DESC;
151 else if (searchForDuplicateDescription.empty() || searchForDuplicateDescription == AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_ALL_DESCS) //Even though this value should be 2 it is sent as ommitted for this attribute, we'll allow 2 anyway incase it changes in the future
152 m_deDup = AutoTimer::DeDup::CHECK_TITLE_AND_ALL_DESCS;
153 }
154
155 if (autoTimerNode->QueryStringAttribute("encoding", &strTmp) == TIXML_SUCCESS)
156 m_encoding = strTmp;
157
158 if (autoTimerNode->QueryStringAttribute("searchType", &strTmp) == TIXML_SUCCESS)
159 {
160 m_searchType = strTmp;
161 if (strTmp == AUTOTIMER_SEARCH_TYPE_DESCRIPTION)
162 m_searchFulltext = true;
163 }
164
165 if (autoTimerNode->QueryStringAttribute("searchCase", &strTmp) == TIXML_SUCCESS)
166 m_searchCase = strTmp;
167
168 TiXmlElement* serviceNode = autoTimerNode->FirstChildElement("e2service");
169
170 if (serviceNode)
171 {
172 const TiXmlElement* nextServiceNode = serviceNode->NextSiblingElement("e2service");
173
174 if (!nextServiceNode)
175 {
176 //If we only have one channel
177 if (XMLUtils::GetString(serviceNode, "e2servicereference", strTmp))
178 {
179 m_channelId = channels.GetChannelUniqueId(Channel::NormaliseServiceReference(strTmp.c_str()));
180
181 // For autotimers for channels we don't know about, such as when the addon only uses one bouquet or an old channel referene that doesn't exist
182 // we'll default to any channel (as that is what kodi PVR does) and leave in ERROR state
183 if (m_channelId == PVR_CHANNEL_INVALID_UID)
184 {
185 m_state = PVR_TIMER_STATE_ERROR;
186 Logger::Log(LEVEL_DEBUG, "%s Overriding AutoTimer state as channel not found, state is: ERROR", __FUNCTION__);
187 m_channelName = LocalizedString(30520); // Invalid Channel
188 m_channelId = PVR_TIMER_ANY_CHANNEL;
189 m_anyChannel = true;
190 }
191 else
192 {
193 m_channelName = channels.GetChannel(m_channelId)->GetChannelName();
194 }
195 }
196 }
197 else //otherwise set to any channel
198 {
199 m_channelId = PVR_TIMER_ANY_CHANNEL;
200 m_anyChannel = true;
201 }
202 }
203 else //otherwise set to any channel
204 {
205 m_channelId = PVR_TIMER_ANY_CHANNEL;
206 m_anyChannel = true;
207 }
208
209 m_weekdays = 0;
210
211 TiXmlElement* includeNode = autoTimerNode->FirstChildElement("include");
212
213 if (includeNode)
214 {
215 for (; includeNode != nullptr; includeNode = includeNode->NextSiblingElement("include"))
216 {
217 std::string includeVal = includeNode->GetText();
218
219 std::string where;
220 if (includeNode->QueryStringAttribute("where", &where) == TIXML_SUCCESS)
221 {
222 if (where == "dayofweek")
223 {
224 m_weekdays = m_weekdays |= (1 << std::atoi(includeVal.c_str()));
225 }
226 }
227 }
228 }
229
230 if (m_weekdays != PVR_WEEKDAY_NONE)
231 {
232 std::time_t t = std::time(nullptr);
233 std::tm timeinfo = *std::localtime(&t);
234 timeinfo.tm_sec = 0;
235 m_startTime = 0;
236 if (!from.empty())
237 {
238 ParseTime(from, timeinfo);
239 m_startTime = std::mktime(&timeinfo);
240 }
241
242 timeinfo = *std::localtime(&t);
243 timeinfo.tm_sec = 0;
244 m_endTime = 0;
245 if (!to.empty())
246 {
247 ParseTime(to, timeinfo);
248 m_endTime = std::mktime(&timeinfo);
249 }
250 }
251 else
252 {
253 for (int i = 0; i < DAYS_IN_WEEK; i++)
254 {
255 m_weekdays = m_weekdays |= (1 << i);
256 }
257 m_startAnyTime = true;
258 m_endAnyTime = true;
259 }
260
261 if (ContainsTag(TAG_FOR_GENRE_ID))
262 {
263 int genreId = 0;
264 if (std::sscanf(ReadTagValue(TAG_FOR_GENRE_ID).c_str(), "0x%02X", &genreId) == 1)
265 {
266 m_genreType = genreId & 0xF0;
267 m_genreSubType = genreId & 0x0F;
268 }
269 else
270 {
271 m_genreType = 0;
272 m_genreSubType = 0;
273 }
274 }
275
276 return true;
277 }
278
279 void AutoTimer::ParseTime(const std::string& time, std::tm& timeinfo) const
280 {
281 std::sscanf(time.c_str(), "%02d:%02d", &timeinfo.tm_hour, &timeinfo.tm_min);
282 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "Timer.h"
24 #include "tinyxml.h"
25 #include "kodi/libXBMC_pvr.h"
26
27 #include <ctime>
28 #include <string>
29 #include <type_traits>
30
31 namespace enigma2
32 {
33 static const std::string AUTOTIMER_SEARCH_CASE_SENSITIVE = "sensitive";
34 static const std::string AUTOTIMER_SEARCH_CASE_INSENITIVE = "";
35
36 static const std::string AUTOTIMER_ENABLED_YES = "yes";
37 static const std::string AUTOTIMER_ENABLED_NO = "no";
38
39 static const std::string AUTOTIMER_ENCODING = "UTF-8";
40
41 static const std::string AUTOTIMER_SEARCH_TYPE_EXACT = "exact";
42 static const std::string AUTOTIMER_SEARCH_TYPE_DESCRIPTION = "description";
43 static const std::string AUTOTIMER_SEARCH_TYPE_START = "start";
44 static const std::string AUTOTIMER_SEARCH_TYPE_PARTIAL = "";
45
46 static const std::string AUTOTIMER_AVOID_DUPLICATE_DISABLED = ""; //Require Description to be unique - No
47 static const std::string AUTOTIMER_AVOID_DUPLICATE_SAME_SERVICE = "1"; //Require Description to be unique - On same service
48 static const std::string AUTOTIMER_AVOID_DUPLICATE_ANY_SERVICE = "2"; //Require Description to be unique - On any service
49 static const std::string AUTOTIMER_AVOID_DUPLICATE_ANY_SERVICE_OR_RECORDING = "3"; //Require Description to be unique - On any service/recording
50
51 static const std::string AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE = "0"; //Check for uniqueness in - Title
52 static const std::string AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_SHORT_DESC = "1"; //Check for uniqueness in - Title and Short description
53 static const std::string AUTOTIMER_CHECK_SEARCH_FOR_DUP_IN_TITLE_AND_ALL_DESCS = "2"; //Check for uniqueness in - Title and all descpritions
54
55 static const std::string AUTOTIMER_DEFAULT = "";
56
57 static const int DAYS_IN_WEEK = 7;
58
59 namespace data
60 {
61 class AutoTimer : public Timer
62 {
63 public:
64 enum DeDup : unsigned int // same type as PVR_TIMER_TYPE.iPreventDuplicateEpisodes
65 {
66 DISABLED = 0,
67 CHECK_TITLE = 1,
68 CHECK_TITLE_AND_SHORT_DESC = 2,
69 CHECK_TITLE_AND_ALL_DESCS = 3
70 };
71
72 AutoTimer() = default;
73
74 const std::string& GetSearchPhrase() const { return m_searchPhrase; }
75 void SetSearchPhrase(const std::string& value) { m_searchPhrase = value; }
76
77 const std::string& GetEncoding() const { return m_encoding; }
78 void SetEncoding(const std::string& value) { m_encoding = value; }
79
80 const std::string& GetSearchCase() const { return m_searchCase; }
81 void SetSearchCase(const std::string& value) { m_searchCase = value; }
82
83 const std::string& GetSearchType() const { return m_searchType; }
84 void SetSearchType(const std::string& value) { m_searchType = value; }
85
86 unsigned int GetBackendId() const { return m_backendId; }
87 void SetBackendId(unsigned int value) { m_backendId = value; }
88
89 bool GetSearchFulltext() const { return m_searchFulltext; }
90 void SetSearchFulltext(bool value) { m_searchFulltext = value; }
91
92 bool GetStartAnyTime() const { return m_startAnyTime; }
93 void SetStartAnyTime(bool value) { m_startAnyTime = value; }
94
95 bool GetEndAnyTime() const { return m_endAnyTime; }
96 void SetEndAnyTime(bool value) { m_endAnyTime = value; }
97
98 bool GetAnyChannel() const { return m_anyChannel; }
99 void SetAnyChannel(bool value) { m_anyChannel = value; }
100
101 std::underlying_type<DeDup>::type GetDeDup() const { return m_deDup; }
102 void SetDeDup(const std::underlying_type<DeDup>::type value) { m_deDup = value; }
103
104 bool Like(const AutoTimer& right) const;
105 bool operator==(const AutoTimer& right) const;
106 void UpdateFrom(const AutoTimer& right);
107 void UpdateTo(PVR_TIMER& right) const;
108 bool UpdateFrom(TiXmlElement* autoTimerNode, Channels& channels);
109 void ParseTime(const std::string& time, std::tm& timeinfo) const;
110
111 private:
112 std::string m_searchPhrase;
113 std::string m_encoding;
114 std::string m_searchCase;
115 std::string m_searchType;
116 unsigned int m_backendId;
117 bool m_searchFulltext = false;
118 bool m_startAnyTime = false;
119 bool m_endAnyTime = false;
120 bool m_anyChannel = false;
121 std::underlying_type<DeDup>::type m_deDup = DeDup::DISABLED;
122 };
123 } //namespace data
124 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "tinyxml.h"
24 #include "kodi/libXBMC_pvr.h"
25
26 #include <memory>
27 #include <string>
28 #include <vector>
29
30 namespace enigma2
31 {
32 namespace data
33 {
34 class BaseChannel
35 {
36 public:
37 BaseChannel() = default;
38 BaseChannel(const BaseChannel& b) : m_radio(b.IsRadio()), m_uniqueId(b.GetUniqueId()),
39 m_channelName(b.GetChannelName()), m_serviceReference(b.GetServiceReference()) {};
40 ~BaseChannel() = default;
41
42 bool IsRadio() const { return m_radio; }
43 void SetRadio(bool value) { m_radio = value; }
44
45 int GetUniqueId() const { return m_uniqueId; }
46 void SetUniqueId(int value) { m_uniqueId = value; }
47
48 const std::string& GetChannelName() const { return m_channelName; }
49 void SetChannelName(const std::string& value) { m_channelName = value; }
50
51 const std::string& GetServiceReference() const { return m_serviceReference; }
52 void SetServiceReference(const std::string& value) { m_serviceReference = value; }
53
54 protected:
55 bool m_radio;
56 int m_uniqueId = -1;
57 std::string m_channelName;
58 std::string m_serviceReference;
59 };
60 } //namespace data
61 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "BaseEntry.h"
23
24 #include "inttypes.h"
25 #include "p8-platform/util/StringUtils.h"
26
27 using namespace enigma2;
28 using namespace enigma2::data;
29
30 void BaseEntry::ProcessPrependMode(PrependOutline prependOutlineMode)
31 {
32 // Some providers only use PlotOutline (e.g. freesat) and Kodi does not display it, if this is the case swap them
33 if (m_plot.empty())
34 {
35 m_plot = m_plotOutline;
36 m_plotOutline.clear();
37 }
38 else if ((Settings::GetInstance().GetPrependOutline() == prependOutlineMode ||
39 Settings::GetInstance().GetPrependOutline() == PrependOutline::ALWAYS) &&
40 !m_plotOutline.empty() && m_plotOutline != "N/A")
41 {
42 m_plot.insert(0, m_plotOutline + "\n");
43 m_plotOutline.clear();
44 }
45 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "../Settings.h"
24
25 #include <string>
26
27 namespace enigma2
28 {
29 namespace data
30 {
31 class BaseEntry
32 {
33 public:
34 const std::string& GetTitle() const { return m_title; }
35 void SetTitle(const std::string& value) { m_title = value; }
36
37 const std::string& GetPlotOutline() const { return m_plotOutline; }
38 void SetPlotOutline(const std::string& value) { m_plotOutline = value; }
39
40 const std::string& GetPlot() const { return m_plot; }
41 void SetPlot(const std::string& value) { m_plot = value; }
42
43 int GetGenreType() const { return m_genreType; }
44 void SetGenreType(int value) { m_genreType = value; }
45
46 int GetGenreSubType() const { return m_genreSubType; }
47 void SetGenreSubType(int value) { m_genreSubType = value; }
48
49 const std::string& GetGenreDescription() const { return m_genreDescription; }
50 void SetGenreDescription(const std::string& value) { m_genreDescription = value; }
51
52 int GetEpisodeNumber() const { return m_episodeNumber; }
53 void SetEpisodeNumber(int value) { m_episodeNumber = value; }
54
55 int GetEpisodePartNumber() const { return m_episodePartNumber; }
56 void SetEpisodePartNumber(int value) { m_episodePartNumber = value; }
57
58 int GetSeasonNumber() const { return m_seasonNumber; }
59 void SetSeasonNumber(int value) { m_seasonNumber = value; }
60
61 int GetYear() const { return m_year; }
62 void SetYear(int value) { m_year = value; }
63
64 void ProcessPrependMode(PrependOutline prependOutlineMode);
65
66 protected:
67 std::string m_title;
68 std::string m_plotOutline;
69 std::string m_plot;
70 int m_genreType = 0;
71 int m_genreSubType = 0;
72 std::string m_genreDescription;
73 int m_episodeNumber = 0;
74 int m_episodePartNumber = 0;
75 int m_seasonNumber = 0;
76 int m_year = 0;
77 };
78 } //namespace data
79 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Channel.h"
23
24 #include "../Settings.h"
25 #include "../utilities/WebUtils.h"
26 #include "ChannelGroup.h"
27 #include "inttypes.h"
28 #include "p8-platform/util/StringUtils.h"
29 #include "util/XMLUtils.h"
30
31 #include <regex>
32
33 using namespace enigma2;
34 using namespace enigma2::data;
35 using namespace enigma2::utilities;
36
37 bool Channel::Like(const Channel& right) const
38 {
39 bool isLike = (m_serviceReference == right.m_serviceReference);
40 isLike &= (m_channelName == right.m_channelName);
41
42 return isLike;
43 }
44
45 bool Channel::operator==(const Channel& right) const
46 {
47 bool isEqual = (m_serviceReference == right.m_serviceReference);
48 isEqual &= (m_channelName == right.m_channelName);
49 isEqual &= (m_radio == right.m_radio);
50 isEqual &= (m_genericServiceReference == right.m_genericServiceReference);
51 isEqual &= (m_streamURL == right.m_streamURL);
52 isEqual &= (m_m3uURL == right.m_m3uURL);
53 isEqual &= (m_iconPath == right.m_iconPath);
54 isEqual &= (m_providerName == right.m_providerName);
55
56 return isEqual;
57 }
58
59 bool Channel::operator!=(const Channel& right) const
60 {
61 return !(*this == right);
62 }
63
64 bool Channel::UpdateFrom(TiXmlElement* channelNode)
65 {
66 if (!XMLUtils::GetString(channelNode, "e2servicereference", m_serviceReference))
67 return false;
68
69 // Check whether the current element is not just a label or that it's not a hidden entry
70 if (m_serviceReference.compare(0, 5, "1:64:") == 0 || m_serviceReference.compare(0, 6, "1:320:") == 0)
71 return false;
72
73 if (!XMLUtils::GetString(channelNode, "e2servicename", m_channelName))
74 return false;
75
76 m_fuzzyChannelName = m_channelName;
77 m_fuzzyChannelName.erase(std::remove_if(m_fuzzyChannelName.begin(), m_fuzzyChannelName.end(), isspace), m_fuzzyChannelName.end());
78
79 if (m_radio != HasRadioServiceType())
80 return false;
81
82 m_extendedServiceReference = m_serviceReference;
83 const std::string commonServiceReference = CreateCommonServiceReference(m_serviceReference);
84 m_standardServiceReference = commonServiceReference + ":";
85 m_genericServiceReference = CreateGenericServiceReference(commonServiceReference);
86 m_iconPath = CreateIconPath(commonServiceReference);
87
88 const std::string iptvStreamURL = ExtractIptvStreamURL();
89
90 Settings& settings = Settings::GetInstance();
91 if (settings.UseStandardServiceReference())
92 m_serviceReference = m_standardServiceReference;
93
94 std::sscanf(m_serviceReference.c_str(), "%*X:%*X:%*X:%X:%*s", &m_streamProgramNumber);
95
96 Logger::Log(LEVEL_DEBUG, "%s: Loaded Channel: %s, sRef=%s, picon: %s, program number: %d", __FUNCTION__, m_channelName.c_str(), m_serviceReference.c_str(), m_iconPath.c_str(), m_streamProgramNumber);
97
98 if (m_isIptvStream)
99 {
100 Logger::Log(LEVEL_DEBUG, "%s: Loaded Channel: %s, sRef=%s, IPTV Stream URL: %s", __FUNCTION__, m_channelName.c_str(), m_serviceReference.c_str(), iptvStreamURL.c_str());
101 }
102
103 m_m3uURL = StringUtils::Format("%sweb/stream.m3u?ref=%s", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline(m_serviceReference).c_str());
104
105 if (!m_isIptvStream)
106 {
107 m_streamURL = StringUtils::Format(
108 "http%s://%s%s:%d/%s",
109 settings.UseSecureConnectionStream() ? "s" : "",
110 settings.UseLoginStream() ? StringUtils::Format("%s:%s@", settings.GetUsername().c_str(), settings.GetPassword().c_str()).c_str() : "",
111 settings.GetHostname().c_str(),
112 settings.GetStreamPortNum(),
113 commonServiceReference.c_str()
114 );
115 }
116 else
117 {
118 m_streamURL = iptvStreamURL;
119 }
120
121 return true;
122 }
123
124 std::string Channel::NormaliseServiceReference(const std::string& serviceReference)
125 {
126 if (Settings::GetInstance().UseStandardServiceReference())
127 return CreateStandardServiceReference(serviceReference);
128 else
129 return serviceReference;
130 }
131
132 std::string Channel::CreateStandardServiceReference(const std::string& serviceReference)
133 {
134 return CreateCommonServiceReference(serviceReference) + ":";
135 }
136
137 std::string Channel::CreateCommonServiceReference(const std::string& serviceReference)
138 {
139 //The common service reference contains only the first 10 groups of digits with colon's in between
140 std::string commonServiceReference = serviceReference;
141
142 int j = 0;
143 std::string::iterator it = commonServiceReference.begin();
144
145 while (j < 10 && it != commonServiceReference.end())
146 {
147 if (*it == ':')
148 j++;
149
150 it++;
151 }
152 std::string::size_type index = it - commonServiceReference.begin();
153
154 commonServiceReference = commonServiceReference.substr(0, index);
155
156 it = commonServiceReference.end() - 1;
157 if (*it == ':')
158 {
159 commonServiceReference.erase(it);
160 }
161
162 return commonServiceReference;
163 }
164
165 std::string Channel::CreateGenericServiceReference(const std::string& commonServiceReference)
166 {
167 //Same as common service reference but starts with SERVICE_REF_GENERIC_PREFIX and ends with SERVICE_REF_GENERIC_POSTFIX
168 std::regex startPrefixRegex("^\\d+:\\d+:\\d+:");
169 std::string replaceWith = "";
170 std::string genericServiceReference = std::regex_replace(commonServiceReference, startPrefixRegex, replaceWith);
171 std::regex endPostfixRegex(":\\d+:\\d+:\\d+$");
172 genericServiceReference = std::regex_replace(genericServiceReference, endPostfixRegex, replaceWith);
173 genericServiceReference = SERVICE_REF_GENERIC_PREFIX + genericServiceReference + SERVICE_REF_GENERIC_POSTFIX;
174
175 return genericServiceReference;
176 }
177
178 std::string Channel::CreateIconPath(const std::string& commonServiceReference)
179 {
180 std::string iconPath = commonServiceReference;
181
182 if (Settings::GetInstance().UsePiconsEuFormat())
183 {
184 iconPath = m_genericServiceReference;
185 }
186
187 std::replace(iconPath.begin(), iconPath.end(), ':', '_');
188
189 if (Settings::GetInstance().UseOnlinePicons())
190 iconPath = StringUtils::Format("%spicon/%s.png", Settings::GetInstance().GetConnectionURL().c_str(), iconPath.c_str());
191 else
192 iconPath = Settings::GetInstance().GetIconPath().c_str() + iconPath + ".png";
193
194 return iconPath;
195 }
196
197 std::string Channel::ExtractIptvStreamURL()
198 {
199 std::string iptvStreamURL;
200
201 std::size_t found = m_extendedServiceReference.find(m_standardServiceReference);
202 if (found != std::string::npos)
203 {
204 const std::string possibleIptvStreamURL = m_extendedServiceReference.substr(m_standardServiceReference.length());
205 found = possibleIptvStreamURL.find("%3a"); //look for an URL encoded colon which means we have an embedded URL
206 if (found != std::string::npos)
207 {
208 m_isIptvStream = true;
209 iptvStreamURL = possibleIptvStreamURL;
210 std::size_t foundColon = iptvStreamURL.find_last_of(":");
211 if (foundColon != std::string::npos)
212 {
213 iptvStreamURL = iptvStreamURL.substr(0, foundColon);
214 }
215 iptvStreamURL = std::regex_replace(iptvStreamURL, std::regex("%3a"), ":");
216 }
217 }
218
219 return iptvStreamURL;
220 }
221
222 bool Channel::HasRadioServiceType()
223 {
224 std::string radioServiceType = m_serviceReference.substr(4, m_serviceReference.size());
225 size_t found = radioServiceType.find(':');
226 if (found != std::string::npos)
227 radioServiceType = radioServiceType.substr(0, found);
228
229 return radioServiceType == RADIO_SERVICE_TYPE;
230 }
231
232 void Channel::UpdateTo(PVR_CHANNEL& left) const
233 {
234 left.iUniqueId = m_uniqueId;
235 left.bIsRadio = m_radio;
236 left.iChannelNumber = m_channelNumber;
237 strncpy(left.strChannelName, m_channelName.c_str(), sizeof(left.strChannelName) - 1);
238 strncpy(left.strInputFormat, "", 0); // unused
239 left.iEncryptionSystem = 0;
240 left.bIsHidden = false;
241 strncpy(left.strIconPath, m_iconPath.c_str(), sizeof(left.strIconPath) - 1);
242 }
243
244 void Channel::AddChannelGroup(std::shared_ptr<ChannelGroup>& channelGroup)
245 {
246 m_channelGroupList.emplace_back(channelGroup);
247 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "BaseChannel.h"
24 #include "tinyxml.h"
25 #include "kodi/libXBMC_pvr.h"
26
27 #include <memory>
28 #include <string>
29 #include <vector>
30
31 namespace enigma2
32 {
33 namespace data
34 {
35 class ChannelGroup;
36
37 class Channel : public BaseChannel
38 {
39 public:
40 const std::string SERVICE_REF_GENERIC_PREFIX = "1:0:1:";
41 const std::string SERVICE_REF_GENERIC_POSTFIX = ":0:0:0";
42 const std::string RADIO_SERVICE_TYPE = "2";
43
44 Channel() = default;
45 Channel(const Channel &c) : BaseChannel(c), m_channelNumber(c.GetChannelNumber()), m_standardServiceReference(c.GetStandardServiceReference()),
46 m_extendedServiceReference(c.GetExtendedServiceReference()), m_genericServiceReference(c.GetGenericServiceReference()),
47 m_streamURL(c.GetStreamURL()), m_m3uURL(c.GetM3uURL()), m_iconPath(c.GetIconPath()),
48 m_providerName(c.GetProviderName()), m_fuzzyChannelName(c.GetFuzzyChannelName()),
49 m_streamProgramNumber(c.GetStreamProgramNumber()), m_usingDefaultChannelNumber(c.UsingDefaultChannelNumber()),
50 m_isIptvStream(c.IsIptvStream()) {};
51 ~Channel() = default;
52
53 int GetChannelNumber() const { return m_channelNumber; }
54 void SetChannelNumber(int value) { m_channelNumber = value; }
55
56 const std::string& GetStandardServiceReference() const { return m_standardServiceReference; }
57 void SetStandardServiceReference(const std::string& value) { m_standardServiceReference = value; }
58
59 const std::string& GetExtendedServiceReference() const { return m_extendedServiceReference; }
60 void SetExtendedServiceReference(const std::string& value) { m_extendedServiceReference = value; }
61
62 const std::string& GetGenericServiceReference() const { return m_genericServiceReference; }
63 void SetGenericServiceReference(const std::string& value) { m_genericServiceReference = value; }
64
65 const std::string& GetStreamURL() const { return m_streamURL; }
66 void SetStreamURL(const std::string& value) { m_streamURL = value; }
67
68 const std::string& GetM3uURL() const { return m_m3uURL; }
69 void SetM3uURL(const std::string& value) { m_m3uURL = value; }
70
71 const std::string& GetIconPath() const { return m_iconPath; }
72 void SetIconPath(const std::string& value) { m_iconPath = value; }
73
74 const std::string& GetProviderName() const { return m_providerName; }
75 void SetProviderlName(const std::string& value) { m_providerName = value; }
76
77 const std::string& GetFuzzyChannelName() const { return m_fuzzyChannelName; }
78 void SetFuzzyChannelName(const std::string& value) { m_fuzzyChannelName = value; }
79
80 int GetStreamProgramNumber() const { return m_streamProgramNumber; }
81 void SetStreamProgramNumber(int value) { m_streamProgramNumber = value; }
82
83 bool UsingDefaultChannelNumber() const { return m_usingDefaultChannelNumber; }
84 void SetUsingDefaultChannelNumber(bool value) { m_usingDefaultChannelNumber = value; }
85
86 bool IsIptvStream() const { return m_isIptvStream; }
87
88 bool UpdateFrom(TiXmlElement* channelNode);
89 void UpdateTo(PVR_CHANNEL& left) const;
90
91 void AddChannelGroup(std::shared_ptr<enigma2::data::ChannelGroup>& channelGroup);
92 std::vector<std::shared_ptr<enigma2::data::ChannelGroup>> GetChannelGroupList() { return m_channelGroupList; };
93
94 bool Like(const Channel& right) const;
95 bool operator==(const Channel& right) const;
96 bool operator!=(const Channel& right) const;
97
98 static std::string NormaliseServiceReference(const std::string& serviceReference);
99 static std::string CreateStandardServiceReference(const std::string& serviceReference);
100
101 private:
102 static std::string CreateCommonServiceReference(const std::string& serviceReference);
103 std::string CreateGenericServiceReference(const std::string& commonServiceReference);
104 std::string CreateIconPath(const std::string& commonServiceReference);
105 std::string ExtractIptvStreamURL();
106 bool HasRadioServiceType();
107
108 int m_channelNumber;
109 bool m_usingDefaultChannelNumber = true;
110 bool m_isIptvStream = false;
111 std::string m_standardServiceReference;
112 std::string m_extendedServiceReference;
113 std::string m_genericServiceReference;
114 std::string m_streamURL;
115 std::string m_m3uURL;
116 std::string m_iconPath;
117 std::string m_providerName;
118 std::string m_fuzzyChannelName;
119 int m_streamProgramNumber;
120
121 std::vector<std::shared_ptr<enigma2::data::ChannelGroup>> m_channelGroupList;
122 };
123 } //namespace data
124 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "ChannelGroup.h"
23
24 #include "inttypes.h"
25 #include "p8-platform/util/StringUtils.h"
26 #include "util/XMLUtils.h"
27
28 using namespace enigma2;
29 using namespace enigma2::data;
30 using namespace enigma2::utilities;
31
32 bool ChannelGroup::Like(const ChannelGroup& right) const
33 {
34 bool isLike = (m_serviceReference == right.m_serviceReference);
35 isLike &= (m_groupName == right.m_groupName);
36
37 return isLike;
38 }
39
40 bool ChannelGroup::operator==(const ChannelGroup& right) const
41 {
42 bool isEqual = (m_serviceReference == right.m_serviceReference);
43 isEqual &= (m_groupName == right.m_groupName);
44 isEqual &= (m_radio == right.m_radio);
45 isEqual &= (m_lastScannedGroup == right.m_lastScannedGroup);
46
47 for (int i = 0; i < m_channelList.size(); i++)
48 {
49 isEqual &= (*(m_channelList.at(i)) == *(right.m_channelList.at(i)));
50
51 if (!isEqual)
52 break;
53 }
54
55 return isEqual;
56 }
57
58 bool ChannelGroup::operator!=(const ChannelGroup& right) const
59 {
60 return !(*this == right);
61 }
62
63 bool ChannelGroup::UpdateFrom(TiXmlElement* groupNode, bool radio)
64 {
65 std::string serviceReference;
66 std::string groupName;
67
68 if (!XMLUtils::GetString(groupNode, "e2servicereference", serviceReference))
69 return false;
70
71 // Check whether the current element is not just a label
72 if (serviceReference.compare(0, 5, "1:64:") == 0)
73 return false;
74
75 if (!XMLUtils::GetString(groupNode, "e2servicename", groupName))
76 return false;
77
78 // Check if the current element is hidden or a separator
79 if (groupName == "<n/a>" || StringUtils::EndsWith(groupName.c_str(), " - Separator"))
80 return false;
81
82 m_serviceReference = serviceReference;
83 m_groupName = groupName;
84 m_radio = radio;
85
86 if (!radio && (Settings::GetInstance().GetTVChannelGroupMode() == ChannelGroupMode::SOME_GROUPS ||
87 Settings::GetInstance().GetTVChannelGroupMode() == ChannelGroupMode::CUSTOM_GROUPS))
88 {
89 auto& customGroupNamelist = Settings::GetInstance().GetCustomTVChannelGroupNameList();
90 auto it = std::find_if(customGroupNamelist.begin(), customGroupNamelist.end(),
91 [&groupName](std::string& customGroupName) { return customGroupName == groupName; });
92
93 if (it == customGroupNamelist.end())
94 return false;
95 else
96 Logger::Log(LEVEL_DEBUG, "%s Custom TV groups are set, current e2servicename '%s' matched", __FUNCTION__, groupName.c_str());
97 }
98 else if (radio && (Settings::GetInstance().GetRadioChannelGroupMode() == ChannelGroupMode::SOME_GROUPS ||
99 Settings::GetInstance().GetRadioChannelGroupMode() == ChannelGroupMode::CUSTOM_GROUPS))
100 {
101 auto& customGroupNamelist = Settings::GetInstance().GetCustomRadioChannelGroupNameList();
102 auto it = std::find_if(customGroupNamelist.begin(), customGroupNamelist.end(),
103 [&groupName](std::string& customGroupName) { return customGroupName == groupName; });
104
105 if (it == customGroupNamelist.end())
106 return false;
107 else
108 Logger::Log(LEVEL_DEBUG, "%s Custom Radio groups are set, current e2servicename '%s' matched", __FUNCTION__, groupName.c_str());
109 }
110 else if (groupName == "Last Scanned")
111 {
112 // Last scanned contains TV and Radio channels mixed, therefore we discard here and handle it separately,
113 // similar to Favourites when loading channel groups.
114 // Note that if Last Scanned is used in only one group for TV we do not discard and only allow it for TV
115 // as it is never supplied as a radio group from Enigma2
116 return false;
117 }
118
119 return true;
120 }
121
122 void ChannelGroup::UpdateTo(PVR_CHANNEL_GROUP& left) const
123 {
124 left.bIsRadio = m_radio;
125 left.iPosition = 0; // groups default order, unused
126 strncpy(left.strGroupName, m_groupName.c_str(), sizeof(left.strGroupName) - 1);
127 }
128
129 void ChannelGroup::AddChannel(std::shared_ptr<Channel> channel)
130 {
131 m_channelList.emplace_back(channel);
132 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "Channel.h"
24 #include "EpgEntry.h"
25 #include "tinyxml.h"
26 #include "kodi/libXBMC_pvr.h"
27
28 #include <memory>
29 #include <string>
30 #include <vector>
31
32 namespace enigma2
33 {
34 namespace data
35 {
36 class ChannelGroup
37 {
38 public:
39 ChannelGroup() = default;
40 ChannelGroup(ChannelGroup &c) : m_radio(c.IsRadio()), m_uniqueId(c.GetUniqueId()),
41 m_groupName(c.GetGroupName()), m_serviceReference(c.GetServiceReference()), m_lastScannedGroup(c.IsLastScannedGroup()),
42 m_startChannelNumber(c.GetStartChannelNumber()), m_emptyGroup(c.IsEmptyGroup()) {};
43 ~ChannelGroup() = default;
44
45 bool IsRadio() const { return m_radio; }
46 void SetRadio(bool value) { m_radio = value; }
47
48 int GetUniqueId() const { return m_uniqueId; }
49 void SetUniqueId(int value) { m_uniqueId = value; }
50
51 const std::string& GetServiceReference() const { return m_serviceReference; }
52 void SetServiceReference(const std::string& value) { m_serviceReference = value; }
53
54 const std::string& GetGroupName() const { return m_groupName; }
55 void SetGroupName(const std::string& value) { m_groupName = value; }
56
57 bool IsLastScannedGroup() const { return m_lastScannedGroup; }
58 void SetLastScannedGroup(bool value) { m_lastScannedGroup = value; }
59
60 bool IsEmptyGroup() const { return m_emptyGroup; }
61 void SetEmptyGroup(bool value) { m_emptyGroup = value; }
62
63 int GetStartChannelNumber() const { return m_startChannelNumber; }
64 void SetStartChannelNumber(int value) { m_startChannelNumber = value; }
65
66 bool HasStartChannelNumber() const { return m_startChannelNumber >= 0; }
67
68 void AddChannel(std::shared_ptr<enigma2::data::Channel> channel);
69
70 bool UpdateFrom(TiXmlElement* groupNode, bool radio);
71 void UpdateTo(PVR_CHANNEL_GROUP& left) const;
72
73 std::vector<std::shared_ptr<enigma2::data::Channel>> GetChannelList() { return m_channelList; };
74
75 bool Like(const ChannelGroup& right) const;
76 bool operator==(const ChannelGroup& right) const;
77 bool operator!=(const ChannelGroup& right) const;
78
79 private:
80 bool m_radio;
81 int m_uniqueId;
82 std::string m_serviceReference;
83 std::string m_groupName;
84 bool m_lastScannedGroup;
85 bool m_emptyGroup;
86 int m_startChannelNumber = -1;
87
88 std::vector<std::shared_ptr<enigma2::data::Channel>> m_channelList;
89 };
90 } //namespace data
91 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "BaseChannel.h"
24 #include "EpgEntry.h"
25 #include "tinyxml.h"
26 #include "kodi/libXBMC_pvr.h"
27
28 #include <memory>
29 #include <string>
30 #include <vector>
31
32 namespace enigma2
33 {
34 namespace data
35 {
36 class EpgEntry;
37
38 class EpgChannel : public BaseChannel
39 {
40 public:
41 EpgChannel() = default;
42 EpgChannel(const EpgChannel& e) : BaseChannel(e){};
43 ~EpgChannel() = default;
44
45 bool RequiresInitialEpg() const { return m_requiresInitialEpg; }
46 void SetRequiresInitialEpg(bool value) { m_requiresInitialEpg = value; }
47
48 std::vector<EpgEntry>& GetInitialEPG() { return m_initialEPG; }
49
50 private:
51 bool m_requiresInitialEpg = true;
52
53 std::vector<EpgEntry> m_initialEPG;
54 };
55 } //namespace data
56 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "EpgEntry.h"
23
24 #include "inttypes.h"
25 #include "util/XMLUtils.h"
26
27 using namespace enigma2;
28 using namespace enigma2::data;
29 using namespace enigma2::utilities;
30
31 void EpgEntry::UpdateTo(EPG_TAG& left) const
32 {
33 left.iUniqueBroadcastId = m_epgId;
34 left.strTitle = m_title.c_str();
35 left.iUniqueChannelId = m_channelId;
36 left.startTime = m_startTime;
37 left.endTime = m_endTime;
38 left.strPlotOutline = m_plotOutline.c_str();
39 left.strPlot = m_plot.c_str();
40 left.strOriginalTitle = nullptr; // unused
41 left.strCast = nullptr; // unused
42 left.strDirector = nullptr; // unused
43 left.strWriter = nullptr; // unused
44 left.iYear = m_year;
45 left.strIMDBNumber = nullptr; // unused
46 left.strIconPath = ""; // unused
47 left.iGenreType = m_genreType;
48 left.iGenreSubType = m_genreSubType;
49 left.strGenreDescription = m_genreDescription.c_str();
50 left.firstAired = 0; // unused
51 left.iParentalRating = 0; // unused
52 left.iStarRating = 0; // unused
53 left.bNotify = false;
54 left.iSeriesNumber = m_seasonNumber;
55 left.iEpisodeNumber = m_episodeNumber;
56 left.iEpisodePartNumber = m_episodePartNumber;
57 left.strEpisodeName = ""; // unused
58 left.iFlags = EPG_TAG_FLAG_UNDEFINED;
59 }
60
61 bool EpgEntry::UpdateFrom(TiXmlElement* eventNode, std::map<std::string, std::shared_ptr<EpgChannel>>& epgChannelsMap)
62 {
63 if (!XMLUtils::GetString(eventNode, "e2eventservicereference", m_serviceReference))
64 return false;
65
66 // Check whether the current element is not just a label or that it's not an empty record
67 if (m_serviceReference.compare(0, 5, "1:64:") == 0)
68 return false;
69
70 m_serviceReference = Channel::NormaliseServiceReference(m_serviceReference);
71
72 std::shared_ptr<data::EpgChannel> epgChannel = std::make_shared<data::EpgChannel>();
73
74 auto epgChannelSearch = epgChannelsMap.find(m_serviceReference);
75 if (epgChannelSearch != epgChannelsMap.end())
76 epgChannel = epgChannelSearch->second;
77
78 if (!epgChannel)
79 {
80 Logger::Log(LEVEL_DEBUG, "%s could not find channel so skipping entry", __FUNCTION__);
81 return false;
82 }
83
84 m_channelId = epgChannel->GetUniqueId();
85
86 return UpdateFrom(eventNode, epgChannel, 0, 0);
87 }
88
89 bool EpgEntry::UpdateFrom(TiXmlElement* eventNode, const std::shared_ptr<EpgChannel>& epgChannel, time_t iStart, time_t iEnd)
90 {
91 std::string strTmp;
92
93 int iTmpStart;
94 int iTmp;
95
96 // check and set event starttime and endtimes
97 if (!XMLUtils::GetInt(eventNode, "e2eventstart", iTmpStart))
98 return false;
99
100 // Skip unneccessary events
101 if (iStart > iTmpStart)
102 return false;
103
104 if (!XMLUtils::GetInt(eventNode, "e2eventduration", iTmp))
105 return false;
106
107 if ((iEnd > 1) && (iEnd < (iTmpStart + iTmp)))
108 return false;
109
110 m_startTime = iTmpStart;
111 m_endTime = iTmpStart + iTmp;
112
113 if (!XMLUtils::GetInt(eventNode, "e2eventid", iTmp))
114 return false;
115
116 m_epgId = iTmp;
117 m_channelId = epgChannel->GetUniqueId();
118
119 if (!XMLUtils::GetString(eventNode, "e2eventtitle", strTmp))
120 return false;
121
122 m_title = strTmp;
123
124 m_serviceReference = epgChannel->GetServiceReference().c_str();
125
126 // Check that it's not an empty record
127 if (m_epgId == 0 && m_title == "None")
128 return false;
129
130 if (XMLUtils::GetString(eventNode, "e2eventdescriptionextended", strTmp))
131 m_plot = strTmp;
132
133 if (XMLUtils::GetString(eventNode, "e2eventdescription", strTmp))
134 m_plotOutline = strTmp;
135
136 ProcessPrependMode(PrependOutline::IN_EPG);
137
138 if (XMLUtils::GetString(eventNode, "e2eventgenre", strTmp))
139 {
140 m_genreDescription = strTmp;
141
142 TiXmlElement* genreNode = eventNode->FirstChildElement("e2eventgenre");
143 if (genreNode)
144 {
145 int genreId = 0;
146 if (genreNode->QueryIntAttribute("id", &genreId) == TIXML_SUCCESS)
147 {
148 m_genreType = genreId & 0xF0;
149 m_genreSubType = genreId & 0x0F;
150 }
151 }
152 }
153
154 return true;
155 }
0 #pragma once
1 /*
2 * Copyleft (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "BaseEntry.h"
24 #include "EpgChannel.h"
25 #include "tinyxml.h"
26 #include "kodi/libXBMC_pvr.h"
27
28 #include <map>
29 #include <string>
30
31 namespace enigma2
32 {
33 namespace data
34 {
35 class EpgEntry : public BaseEntry
36 {
37 public:
38 unsigned int GetEpgId() const { return m_epgId; }
39 void SetEpgId(int value) { m_epgId = value; }
40
41 const std::string& GetServiceReference() const { return m_serviceReference; }
42 void SetServiceReference(const std::string& value) { m_serviceReference = value; }
43
44 int GetChannelId() const { return m_channelId; }
45 void SetChannelId(int value) { m_channelId = value; }
46
47 time_t GetStartTime() const { return m_startTime; }
48 void SetStartTime(time_t value) { m_startTime = value; }
49
50 time_t GetEndTime() const { return m_endTime; }
51 void SetEndTime(time_t value) { m_endTime = value; }
52
53 void UpdateTo(EPG_TAG& left) const;
54 bool UpdateFrom(TiXmlElement* eventNode, std::map<std::string, std::shared_ptr<EpgChannel>>& m_epgChannelsMap);
55 bool UpdateFrom(TiXmlElement* eventNode, const std::shared_ptr<EpgChannel>& epgChannel, time_t iStart, time_t iEnd);
56
57 protected:
58 unsigned int m_epgId;
59 std::string m_serviceReference;
60 int m_channelId;
61 time_t m_startTime;
62 time_t m_endTime;
63 };
64 } //namespace data
65 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "BaseEntry.h"
24
25 #include <string>
26
27 namespace enigma2
28 {
29 namespace data
30 {
31 class EpgPartialEntry : public BaseEntry
32 {
33 public:
34 unsigned int GetEpgUid() const { return m_epgUid; }
35 void SetEpgUid(unsigned int value) { m_epgUid = value; }
36
37 bool EntryFound() const { return m_epgUid != 0; };
38
39 private:
40 unsigned int m_epgUid = 0;
41 };
42 } //namespace data
43 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "RecordingEntry.h"
23
24 #include "../utilities/WebUtils.h"
25 #include "inttypes.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "util/XMLUtils.h"
28
29 #include <cstdlib>
30
31 using namespace enigma2;
32 using namespace enigma2::data;
33 using namespace enigma2::utilities;
34
35 bool RecordingEntry::UpdateFrom(TiXmlElement* recordingNode, const std::string& directory, bool deleted, Channels& channels)
36 {
37 std::string strTmp;
38 int iTmp;
39
40 m_directory = directory;
41 m_deleted = deleted;
42
43 if (XMLUtils::GetString(recordingNode, "e2servicereference", strTmp))
44 m_recordingId = strTmp;
45
46 if (XMLUtils::GetString(recordingNode, "e2title", strTmp))
47 m_title = strTmp;
48
49 if (XMLUtils::GetString(recordingNode, "e2description", strTmp))
50 m_plotOutline = strTmp;
51
52 if (XMLUtils::GetString(recordingNode, "e2descriptionextended", strTmp))
53 m_plot = strTmp;
54
55 if (XMLUtils::GetString(recordingNode, "e2servicename", strTmp))
56 m_channelName = strTmp;
57
58 if (XMLUtils::GetInt(recordingNode, "e2time", iTmp))
59 m_startTime = iTmp;
60
61 if (XMLUtils::GetString(recordingNode, "e2length", strTmp))
62 {
63 iTmp = TimeStringToSeconds(strTmp.c_str());
64 m_duration = iTmp;
65 }
66 else
67 m_duration = 0;
68
69 if (XMLUtils::GetString(recordingNode, "e2filename", strTmp))
70 {
71 m_edlURL = strTmp;
72
73 strTmp = StringUtils::Format("%sfile?file=%s", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline(strTmp).c_str());
74 m_streamURL = strTmp;
75
76 m_edlURL = m_edlURL.substr(0, m_edlURL.find_last_of('.')) + ".edl";
77 m_edlURL = StringUtils::Format("%sfile?file=%s", Settings::GetInstance().GetConnectionURL().c_str(), WebUtils::URLEncodeInline(m_edlURL).c_str());
78 }
79
80 ProcessPrependMode(PrependOutline::IN_RECORDINGS);
81
82 m_tags.clear();
83 if (XMLUtils::GetString(recordingNode, "e2tags", strTmp))
84 m_tags = strTmp;
85
86 if (ContainsTag(TAG_FOR_GENRE_ID))
87 {
88 int genreId = 0;
89 if (std::sscanf(ReadTagValue(TAG_FOR_GENRE_ID).c_str(), "0x%02X", &genreId) == 1)
90 {
91 m_genreType = genreId & 0xF0;
92 m_genreSubType = genreId & 0x0F;
93 }
94 else
95 {
96 m_genreType = 0;
97 m_genreSubType = 0;
98 }
99 }
100
101 if (ContainsTag(TAG_FOR_PLAY_COUNT))
102 {
103 if (std::sscanf(ReadTagValue(TAG_FOR_PLAY_COUNT).c_str(), "%d", &m_playCount) != 1)
104 m_playCount = 0;
105 }
106
107 if (ContainsTag(TAG_FOR_LAST_PLAYED))
108 {
109 if (std::sscanf(ReadTagValue(TAG_FOR_LAST_PLAYED).c_str(), "%d", &m_lastPlayedPosition) != 1)
110 m_lastPlayedPosition = 0;
111 }
112
113 if (ContainsTag(TAG_FOR_NEXT_SYNC_TIME))
114 {
115 long long scannedTime = 0;
116 if (std::sscanf(ReadTagValue(TAG_FOR_NEXT_SYNC_TIME).c_str(), "%lld", &scannedTime) != 1)
117 m_nextSyncTime = 0;
118 else
119 m_nextSyncTime = static_cast<time_t>(scannedTime);
120
121 }
122
123 auto channel = FindChannel(channels);
124
125 if (channel)
126 {
127 m_radio = channel->IsRadio();
128 m_channelUniqueId = channel->GetUniqueId();
129 m_iconPath = channel->GetIconPath();
130 m_haveChannelType = true;
131 }
132
133 return true;
134 }
135
136 long RecordingEntry::TimeStringToSeconds(const std::string& timeString)
137 {
138 std::vector<std::string> tokens;
139
140 std::string s = timeString;
141 const std::string delimiter = ":";
142
143 size_t pos = 0;
144 std::string token;
145 while ((pos = s.find(delimiter)) != std::string::npos)
146 {
147 token = s.substr(0, pos);
148 tokens.emplace_back(token);
149 s.erase(0, pos + delimiter.length());
150 }
151 tokens.emplace_back(s);
152
153 int timeInSecs = 0;
154
155 if (tokens.size() == 2)
156 {
157 timeInSecs += std::atoi(tokens[0].c_str()) * 60;
158 timeInSecs += std::atoi(tokens[1].c_str());
159 }
160
161 return timeInSecs;
162 }
163
164 void RecordingEntry::UpdateTo(PVR_RECORDING& left, Channels& channels, bool isInRecordingFolder)
165 {
166 std::string strTmp;
167 strncpy(left.strRecordingId, m_recordingId.c_str(), sizeof(left.strRecordingId) - 1);
168 strncpy(left.strTitle, m_title.c_str(), sizeof(left.strTitle) - 1);
169 strncpy(left.strPlotOutline, m_plotOutline.c_str(), sizeof(left.strPlotOutline) - 1);
170 strncpy(left.strPlot, m_plot.c_str(), sizeof(left.strPlot) - 1);
171 strncpy(left.strChannelName, m_channelName.c_str(), sizeof(left.strChannelName) - 1);
172 strncpy(left.strIconPath, m_iconPath.c_str(), sizeof(left.strIconPath) - 1);
173
174 if (!Settings::GetInstance().GetKeepRecordingsFolders())
175 {
176 if (isInRecordingFolder)
177 strTmp = StringUtils::Format("/%s/", m_title.c_str());
178 else
179 strTmp = StringUtils::Format("/");
180
181 m_directory = strTmp;
182 }
183
184 strncpy(left.strDirectory, m_directory.c_str(), sizeof(left.strDirectory) - 1);
185 left.bIsDeleted = m_deleted;
186 left.recordingTime = m_startTime;
187 left.iDuration = m_duration;
188
189 left.iChannelUid = m_channelUniqueId;
190 left.channelType = PVR_RECORDING_CHANNEL_TYPE_UNKNOWN;
191
192 if (m_haveChannelType)
193 {
194 if (m_radio)
195 left.channelType = PVR_RECORDING_CHANNEL_TYPE_RADIO;
196 else
197 left.channelType = PVR_RECORDING_CHANNEL_TYPE_TV;
198 }
199
200 left.iPlayCount = m_playCount;
201 left.iLastPlayedPosition = m_lastPlayedPosition;
202 left.iSeriesNumber = m_seasonNumber;
203 left.iEpisodeNumber = m_episodeNumber;
204 left.iYear = m_year;
205 left.iGenreType = m_genreType;
206 left.iGenreSubType = m_genreSubType;
207 strncpy(left.strGenreDescription, m_genreDescription.c_str(), sizeof(left.strGenreDescription) - 1);
208 }
209
210 std::shared_ptr<Channel> RecordingEntry::FindChannel(Channels& channels) const
211 {
212 std::shared_ptr<Channel> channel = GetChannelFromChannelReferenceTag(channels);
213
214 if (channel)
215 return channel;
216
217 if (ContainsTag(TAG_FOR_CHANNEL_TYPE))
218 {
219 m_radio = ReadTagValue(TAG_FOR_CHANNEL_TYPE) == VALUE_FOR_CHANNEL_TYPE_RADIO;
220 m_haveChannelType = true;
221 }
222
223 m_anyChannelTimerSource = ContainsTag(TAG_FOR_ANY_CHANNEL);
224
225 channel = GetChannelFromChannelNameSearch(channels);
226
227 if (channel)
228 {
229 if (!m_hasStreamProgramNumber)
230 {
231 m_streamProgramNumber = channel->GetStreamProgramNumber();
232 m_hasStreamProgramNumber = true;
233 }
234
235 return channel;
236 }
237
238 channel = GetChannelFromChannelNameFuzzySearch(channels);
239
240 if (channel && !m_hasStreamProgramNumber)
241 {
242 m_streamProgramNumber = channel->GetStreamProgramNumber();
243 m_hasStreamProgramNumber = true;
244 }
245
246 return channel;
247 }
248
249 std::shared_ptr<Channel> RecordingEntry::GetChannelFromChannelReferenceTag(Channels& channels) const
250 {
251 std::string channelServiceReference;
252
253 if (ContainsTag(TAG_FOR_CHANNEL_REFERENCE))
254 {
255 channelServiceReference = Channel::NormaliseServiceReference(ReadTagValue(TAG_FOR_CHANNEL_REFERENCE, true));
256
257 std::sscanf(channelServiceReference.c_str(), "%*X:%*X:%*X:%X:%*s", &m_streamProgramNumber);
258 m_hasStreamProgramNumber = true;
259 }
260
261 return channels.GetChannel(channelServiceReference);
262 }
263
264 std::shared_ptr<Channel> RecordingEntry::GetChannelFromChannelNameSearch(Channels& channels) const
265 {
266 //search for channel name using exact match
267 for (const auto& channel : channels.GetChannelsList())
268 {
269 if (m_channelName == channel->GetChannelName() && (!m_haveChannelType || (channel->IsRadio() == m_radio)))
270 {
271 return channel;
272 }
273 }
274
275 return nullptr;
276 }
277
278 std::shared_ptr<Channel> RecordingEntry::GetChannelFromChannelNameFuzzySearch(Channels& channels) const
279 {
280 std::string fuzzyRecordingChannelName;
281
282 //search for channel name using fuzzy match
283 for (const auto& channel : channels.GetChannelsList())
284 {
285 fuzzyRecordingChannelName = m_channelName;
286 fuzzyRecordingChannelName.erase(remove_if(fuzzyRecordingChannelName.begin(), fuzzyRecordingChannelName.end(), isspace), fuzzyRecordingChannelName.end());
287
288 if (fuzzyRecordingChannelName == channel->GetFuzzyChannelName() && (!m_haveChannelType || (channel->IsRadio() == m_radio)))
289 {
290 return channel;
291 }
292 }
293
294 return nullptr;
295 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "../Channels.h"
24 #include "BaseEntry.h"
25 #include "Channel.h"
26 #include "Tags.h"
27 #include "tinyxml.h"
28 #include "kodi/libXBMC_pvr.h"
29
30 #include <string>
31 namespace enigma2
32 {
33 namespace data
34 {
35 static const std::string TAG_FOR_PLAY_COUNT = "PlayCount";
36 static const std::string TAG_FOR_LAST_PLAYED = "LastPlayed";
37 static const std::string TAG_FOR_NEXT_SYNC_TIME = "NextSyncTime";
38
39 class RecordingEntry : public BaseEntry, public Tags
40 {
41 public:
42 const std::string& GetRecordingId() const { return m_recordingId; }
43 void SetRecordingId(const std::string& value) { m_recordingId = value; }
44
45 time_t GetStartTime() const { return m_startTime; }
46 void SetStartTime(time_t value) { m_startTime = value; }
47
48 int GetDuration() const { return m_duration; }
49 void SetDuration(int value) { m_duration = value; }
50
51 int GetPlayCount() const { return m_playCount; }
52 void SetPlayCount(int value) { m_playCount = value; }
53
54 int GetLastPlayedPosition() const { return m_lastPlayedPosition; }
55 void SetLastPlayedPosition(int value) { m_lastPlayedPosition = value; }
56
57 time_t GetNextSyncTime() const { return m_nextSyncTime; }
58 void SetNextSyncTime(time_t value) { m_nextSyncTime = value; }
59
60 const std::string& GetStreamURL() const { return m_streamURL; }
61 void SetStreamURL(const std::string& value) { m_streamURL = value; }
62
63 const std::string& GetEdlURL() const { return m_edlURL; }
64 void SetEdlURL(const std::string& value) { m_edlURL = value; }
65
66 const std::string& GetChannelName() const { return m_channelName; }
67 void SetChannelName(const std::string& value) { m_channelName = value; }
68
69 int GetChannelUniqueId() const { return m_channelUniqueId; }
70 void SetChannelUniqueId(int value) { m_channelUniqueId = value; }
71
72 const std::string& GetDirectory() const { return m_directory; }
73 void SetDirectory(const std::string& value) { m_directory = value; }
74
75 const std::string& GetIconPath() const { return m_iconPath; }
76 void SetIconPath(const std::string& value) { m_iconPath = value; }
77
78 int GetStreamProgramNumber() const { return m_streamProgramNumber; }
79 void SetStreamProgramNumber(int value) { m_streamProgramNumber = value; }
80
81 bool HasStreamProgramNumber() const { return m_hasStreamProgramNumber; }
82
83 bool IsRadio() const { return m_radio; }
84 void SetRadio(bool value) { m_radio = value; }
85
86 bool IsDeleted() const { return m_deleted; }
87 void SetDeleted(bool value) { m_deleted = value; }
88
89 bool UpdateFrom(TiXmlElement* recordingNode, const std::string& directory, bool deleted, enigma2::Channels& channels);
90 void UpdateTo(PVR_RECORDING& left, Channels& channels, bool isInRecordingFolder);
91
92 private:
93 long TimeStringToSeconds(const std::string& timeString);
94
95 std::shared_ptr<Channel> FindChannel(enigma2::Channels& channels) const;
96 std::shared_ptr<Channel> GetChannelFromChannelReferenceTag(enigma2::Channels& channels) const;
97 std::shared_ptr<Channel> GetChannelFromChannelNameSearch(enigma2::Channels& channels) const;
98 std::shared_ptr<Channel> GetChannelFromChannelNameFuzzySearch(enigma2::Channels& channels) const;
99
100 std::string m_recordingId;
101 time_t m_startTime;
102 int m_duration;
103 int m_playCount = 0;
104 int m_lastPlayedPosition = 0;
105 time_t m_nextSyncTime = 0;
106 std::string m_streamURL;
107 std::string m_edlURL;
108 std::string m_channelName;
109 int m_channelUniqueId = PVR_CHANNEL_INVALID_UID;
110 std::string m_directory;
111 std::string m_iconPath;
112 mutable bool m_radio = false;
113 mutable bool m_haveChannelType = false;
114 mutable bool m_anyChannelTimerSource = false;
115 bool m_deleted = false;
116 mutable int m_streamProgramNumber;
117 mutable bool m_hasStreamProgramNumber = false;
118 };
119 } //namespace data
120 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "p8-platform/util/StringUtils.h"
24
25 #include <regex>
26 #include <string>
27
28 namespace enigma2
29 {
30 namespace data
31 {
32 static const std::string TAG_FOR_GENRE_ID = "GenreId";
33 static const std::string TAG_FOR_CHANNEL_REFERENCE = "ChannelRef";
34 static const std::string TAG_FOR_CHANNEL_TYPE = "ChannelType";
35 static const std::string TAG_FOR_ANY_CHANNEL = "AnyChannel";
36 static const std::string VALUE_FOR_CHANNEL_TYPE_TV = "TV";
37 static const std::string VALUE_FOR_CHANNEL_TYPE_RADIO = "Radio";
38
39 class Tags
40 {
41 public:
42 Tags() = default;
43 Tags(const std::string& tags) : m_tags(tags) {};
44
45 const std::string& GetTags() const { return m_tags; }
46 void SetTags(const std::string& value) { m_tags = value; }
47
48 bool ContainsTag(const std::string& tag) const
49 {
50 std::regex regex("^.* ?" + tag + " ?.*$");
51
52 return (std::regex_match(m_tags, regex));
53 }
54
55 void AddTag(const std::string& tagName, const std::string& tagValue = "", bool replaceUnderscores = false)
56 {
57 RemoveTag(tagName);
58
59 if (!m_tags.empty())
60 m_tags.append(" ");
61
62 m_tags.append(tagName);
63
64 if (!tagValue.empty())
65 {
66 std::string val = tagValue;
67 if (replaceUnderscores)
68 std::replace(val.begin(), val.end(), ' ', '_');
69 m_tags.append(StringUtils::Format("=%s", val.c_str()));
70 }
71 }
72
73 std::string ReadTagValue(const std::string& tagName, bool replaceUnderscores = false) const
74 {
75 std::string tagValue;
76
77 size_t found = m_tags.find(tagName + "=");
78 if (found != std::string::npos)
79 {
80 tagValue = m_tags.substr(found + tagName.size() + 1, m_tags.size());
81
82 found = tagValue.find(" ");
83 if (found != std::string::npos)
84 tagValue = tagValue.substr(0, found);
85
86 tagValue = StringUtils::Trim(tagValue);
87
88 if (replaceUnderscores)
89 std::replace(tagValue.begin(), tagValue.end(), '_', ' ');
90 }
91
92 return tagValue;
93 }
94
95 void RemoveTag(const std::string& tagName)
96 {
97 std::regex regex(" *" + tagName + "=?[^\\s-]*");
98 std::string replaceWith = "";
99
100 m_tags = std::regex_replace(m_tags, regex, replaceWith);
101 }
102
103 protected:
104 std::string m_tags;
105 };
106 } //namespace data
107 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "Timer.h"
23
24 #include "../utilities/LocalizedString.h"
25 #include "inttypes.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "util/XMLUtils.h"
28
29 #include <regex>
30
31 using namespace enigma2;
32 using namespace enigma2::data;
33 using namespace enigma2::utilities;
34
35 bool Timer::Like(const Timer& right) const
36 {
37 bool isLike = (m_startTime == right.m_startTime);
38 isLike &= (m_endTime == right.m_endTime);
39 isLike &= (m_channelId == right.m_channelId);
40 isLike &= (m_weekdays == right.m_weekdays);
41 isLike &= (m_epgId == right.m_epgId);
42
43 return isLike;
44 }
45
46 bool Timer::operator==(const Timer& right) const
47 {
48 bool isEqual = (m_startTime == right.m_startTime);
49 isEqual &= (m_endTime == right.m_endTime);
50 isEqual &= (m_channelId == right.m_channelId);
51 isEqual &= (m_weekdays == right.m_weekdays);
52 isEqual &= (m_epgId == right.m_epgId);
53 isEqual &= (m_paddingStartMins == right.m_paddingStartMins);
54 isEqual &= (m_paddingEndMins == right.m_paddingEndMins);
55 isEqual &= (m_state == right.m_state);
56 isEqual &= (m_title == right.m_title);
57 isEqual &= (m_plot == right.m_plot);
58 isEqual &= (m_tags == right.m_tags);
59 isEqual &= (m_plotOutline == right.m_plotOutline);
60 isEqual &= (m_plot == right.m_plot);
61 isEqual &= (m_genreType == right.m_genreType);
62 isEqual &= (m_genreSubType == right.m_genreSubType);
63 isEqual &= (m_genreDescription == right.m_genreDescription);
64 isEqual &= (m_episodeNumber == right.m_episodeNumber);
65 isEqual &= (m_episodePartNumber == right.m_episodePartNumber);
66 isEqual &= (m_seasonNumber == right.m_seasonNumber);
67 isEqual &= (m_year == right.m_year);
68
69 return isEqual;
70 }
71
72 void Timer::UpdateFrom(const Timer& right)
73 {
74 m_title = right.m_title;
75 m_plot = right.m_plot;
76 m_channelId = right.m_channelId;
77 m_channelName = right.m_channelName;
78 m_startTime = right.m_startTime;
79 m_endTime = right.m_endTime;
80 m_weekdays = right.m_weekdays;
81 m_epgId = right.m_epgId;
82 m_tags = right.m_tags;
83 m_state = right.m_state;
84 m_paddingStartMins = right.m_paddingStartMins;
85 m_paddingEndMins = right.m_paddingEndMins;
86 m_plotOutline = right.m_plotOutline;
87 m_plot = right.m_plot;
88 m_genreType = right.m_genreType;
89 m_genreSubType = right.m_genreSubType;
90 m_genreDescription = right.m_genreDescription;
91 m_episodeNumber = right.m_episodeNumber;
92 m_episodePartNumber = right.m_episodePartNumber;
93 m_seasonNumber = right.m_seasonNumber;
94 m_year = right.m_year;
95 }
96
97 void Timer::UpdateTo(PVR_TIMER& left) const
98 {
99 strncpy(left.strTitle, m_title.c_str(), sizeof(left.strTitle) - 1);
100 strncpy(left.strDirectory, "/", sizeof(left.strDirectory) - 1); // unused
101 strncpy(left.strSummary, m_plot.c_str(), sizeof(left.strSummary) - 1);
102 left.iTimerType = m_type;
103 left.iClientChannelUid = m_channelId;
104 left.startTime = m_startTime;
105 left.endTime = m_endTime;
106 left.state = m_state;
107 left.iPriority = 0; // unused
108 left.iLifetime = 0; // unused
109 left.firstDay = 0; // unused
110 left.iWeekdays = m_weekdays;
111 left.iEpgUid = m_epgId;
112 left.iMarginStart = m_paddingStartMins;
113 left.iMarginEnd = m_paddingEndMins;
114 left.iGenreType = 0; // unused
115 left.iGenreSubType = 0; // unused
116 left.iClientIndex = m_clientIndex;
117 left.iParentClientIndex = m_parentClientIndex;
118 }
119
120 bool Timer::IsScheduled() const
121 {
122 return m_state == PVR_TIMER_STATE_SCHEDULED || m_state == PVR_TIMER_STATE_RECORDING;
123 }
124
125 bool Timer::IsRunning(std::time_t* now, std::string* channelName, std::time_t startTime) const
126 {
127 if (!IsScheduled())
128 return false;
129 if (now && !(GetRealStartTime() <= *now && *now <= GetRealEndTime()))
130 return false;
131 if (channelName && m_channelName != *channelName)
132 return false;
133 if (GetRealStartTime() != startTime)
134 return false;
135 return true;
136 }
137
138 bool Timer::IsChildOfParent(const Timer& parent) const
139 {
140 time_t time;
141 std::tm timeinfo;
142 int weekday = 0;
143
144 time = m_startTime;
145 timeinfo = *std::localtime(&time);
146 const std::string childStartTime = StringUtils::Format("%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
147 int tmDayOfWeek = timeinfo.tm_wday - 1;
148 if (tmDayOfWeek < 0)
149 tmDayOfWeek = 6;
150 weekday = (1 << tmDayOfWeek);
151
152 time = m_endTime;
153 timeinfo = *std::localtime(&time);
154 const std::string childEndTime = StringUtils::Format("%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
155
156 time = parent.m_startTime;
157 timeinfo = *std::localtime(&time);
158 const std::string parentStartTime = StringUtils::Format("%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
159
160 time = parent.m_endTime;
161 timeinfo = *std::localtime(&time);
162 const std::string parentEndTime = StringUtils::Format("%02d:%02d", timeinfo.tm_hour, timeinfo.tm_min);
163
164 bool isChild = true;
165
166 isChild = isChild && (m_title == parent.m_title);
167 isChild = isChild && (childStartTime == parentStartTime);
168 isChild = isChild && (childEndTime == parentEndTime);
169 isChild = isChild && (m_paddingStartMins == parent.m_paddingStartMins);
170 isChild = isChild && (m_paddingEndMins == parent.m_paddingEndMins);
171 isChild = isChild && (m_channelId == parent.m_channelId);
172 isChild = isChild && (weekday & parent.m_weekdays);
173
174 return isChild;
175 }
176
177 bool Timer::UpdateFrom(TiXmlElement* timerNode, Channels& channels)
178 {
179 std::string strTmp;
180
181 int iTmp;
182 bool bTmp;
183 int iDisabled;
184
185 if (XMLUtils::GetString(timerNode, "e2name", strTmp))
186 Logger::Log(LEVEL_DEBUG, "%s Processing timer '%s'", __FUNCTION__, strTmp.c_str());
187
188 if (!XMLUtils::GetInt(timerNode, "e2state", iTmp))
189 return false;
190
191 if (!XMLUtils::GetInt(timerNode, "e2disabled", iDisabled))
192 return false;
193
194 m_title = strTmp;
195
196 if (XMLUtils::GetString(timerNode, "e2servicereference", strTmp))
197 {
198 m_serviceReference = strTmp;
199 m_channelId = channels.GetChannelUniqueId(Channel::NormaliseServiceReference(strTmp.c_str()));
200 }
201
202 // Skip timers for channels we don't know about, such as when the addon only uses one bouquet or an old channel referene that doesn't exist
203 if (m_channelId == PVR_CHANNEL_INVALID_UID)
204 {
205 m_channelName = LocalizedString(30520); // Invalid Channel
206 }
207 else
208 {
209 m_channelName = channels.GetChannel(m_channelId)->GetChannelName();
210 }
211
212
213 if (!XMLUtils::GetInt(timerNode, "e2timebegin", iTmp))
214 return false;
215
216 m_startTime = iTmp;
217
218 if (!XMLUtils::GetInt(timerNode, "e2timeend", iTmp))
219 return false;
220
221 m_endTime = iTmp;
222
223 if (XMLUtils::GetString(timerNode, "e2descriptionextended", strTmp))
224 m_plot = strTmp;
225
226 if (XMLUtils::GetString(timerNode, "e2description", strTmp))
227 m_plotOutline = strTmp;
228
229 if (m_plot == "N/A")
230 m_plot.clear();
231
232 // Some providers only use PlotOutline (e.g. freesat) and Kodi does not display it, if this is the case swap them
233 if (m_plot.empty())
234 {
235 m_plot = m_plotOutline;
236 m_plotOutline.clear();
237 }
238 else if (Settings::GetInstance().GetPrependOutline() == PrependOutline::ALWAYS &&
239 m_plot != m_plotOutline && !m_plotOutline.empty() && m_plotOutline != "N/A")
240 {
241 m_plot.insert(0, m_plotOutline + "\n");
242 m_plotOutline.clear();
243 }
244
245 if (XMLUtils::GetInt(timerNode, "e2repeated", iTmp))
246 m_weekdays = iTmp;
247 else
248 m_weekdays = 0;
249
250 if (XMLUtils::GetInt(timerNode, "e2eit", iTmp))
251 m_epgId = iTmp;
252 else
253 m_epgId = 0;
254
255 m_state = PVR_TIMER_STATE_NEW;
256
257 if (!XMLUtils::GetInt(timerNode, "e2state", iTmp))
258 return false;
259
260 Logger::Log(LEVEL_DEBUG, "%s e2state is: %d ", __FUNCTION__, iTmp);
261
262 if (iTmp == 0)
263 {
264 m_state = PVR_TIMER_STATE_SCHEDULED;
265 Logger::Log(LEVEL_DEBUG, "%s Timer state is: SCHEDULED", __FUNCTION__);
266 }
267
268 if (iTmp == 2)
269 {
270 m_state = PVR_TIMER_STATE_RECORDING;
271 Logger::Log(LEVEL_DEBUG, "%s Timer state is: RECORDING", __FUNCTION__);
272 }
273
274 if (iTmp == 3 && iDisabled == 0)
275 {
276 m_state = PVR_TIMER_STATE_COMPLETED;
277 Logger::Log(LEVEL_DEBUG, "%s Timer state is: COMPLETED", __FUNCTION__);
278 }
279
280 if (XMLUtils::GetBoolean(timerNode, "e2cancled", bTmp))
281 {
282 if (bTmp)
283 {
284 // If a timer is cancelled by the backend mark it as an error so it will show as such in the UI
285 // We don't use CANCELLED or ABORTED as they are synonymous with DISABLED and we won't use them at all
286 // Note there is no user/API action to change to cancelled
287 m_state = PVR_TIMER_STATE_ERROR;
288 Logger::Log(LEVEL_DEBUG, "%s Timer state is: ERROR", __FUNCTION__);
289 }
290 }
291
292 if (iDisabled == 1)
293 {
294 m_state = PVR_TIMER_STATE_DISABLED;
295 Logger::Log(LEVEL_DEBUG, "%s Timer state is: Disabled", __FUNCTION__);
296 }
297
298 if (m_state == PVR_TIMER_STATE_NEW)
299 Logger::Log(LEVEL_DEBUG, "%s Timer state is: NEW", __FUNCTION__);
300
301 if (m_channelId == PVR_CHANNEL_INVALID_UID)
302 {
303 m_state = PVR_TIMER_STATE_ERROR;
304 Logger::Log(LEVEL_DEBUG, "%s Overriding Timer as channel not found, state is: ERROR", __FUNCTION__);
305 }
306
307 m_tags.clear();
308 if (XMLUtils::GetString(timerNode, "e2tags", strTmp))
309 m_tags = strTmp;
310
311 if (ContainsTag(TAG_FOR_MANUAL_TIMER))
312 {
313 //We create a Manual tag on Manual timers created from Kodi, this allows us to set the Timer Type correctly
314 if (m_weekdays != PVR_WEEKDAY_NONE)
315 {
316 m_type = Timer::MANUAL_REPEATING;
317 }
318 else
319 {
320 m_type = Timer::MANUAL_ONCE;
321 }
322 }
323 else
324 { //Default to EPG for all other standard timers
325 if (m_weekdays != PVR_WEEKDAY_NONE)
326 {
327 m_type = Timer::EPG_REPEATING;
328 }
329 else
330 {
331 if (ContainsTag(TAG_FOR_AUTOTIMER))
332 {
333 m_type = Timer::EPG_AUTO_ONCE;
334
335 if (!ContainsTag(TAG_FOR_PADDING))
336 {
337 //We need to add this as these timers are created by the backend so won't have a padding to read
338 m_tags.append(StringUtils::Format(" Padding=%u,%u",
339 Settings::GetInstance().GetDeviceSettings()->GetGlobalRecordingStartMargin(),
340 Settings::GetInstance().GetDeviceSettings()->GetGlobalRecordingEndMargin()));
341 }
342 }
343 else
344 {
345 m_type = Timer::EPG_ONCE;
346 }
347 }
348 }
349
350 if (ContainsTag(TAG_FOR_PADDING))
351 {
352 if (std::sscanf(ReadTagValue(TAG_FOR_PADDING).c_str(), "%u,%u", &m_paddingStartMins, &m_paddingEndMins) != 2)
353 {
354 m_paddingStartMins = 0;
355 m_paddingEndMins = 0;
356 }
357 }
358
359 if (m_paddingStartMins > 0)
360 m_startTime += m_paddingStartMins * 60;
361
362 if (m_paddingEndMins > 0)
363 m_endTime -= m_paddingEndMins * 60;
364
365 if (ContainsTag(TAG_FOR_GENRE_ID))
366 {
367 int genreId = 0;
368 if (std::sscanf(ReadTagValue(TAG_FOR_GENRE_ID).c_str(), "0x%02X", &genreId) == 1)
369 {
370 m_genreType = genreId & 0xF0;
371 m_genreSubType = genreId & 0x0F;
372 }
373 else
374 {
375 m_genreType = 0;
376 m_genreSubType = 0;
377 }
378 }
379
380 return true;
381 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "../Channels.h"
24 #include "../utilities/UpdateState.h"
25 #include "BaseEntry.h"
26 #include "Tags.h"
27 #include "tinyxml.h"
28 #include "kodi/libXBMC_pvr.h"
29
30 #include <ctime>
31 #include <string>
32 #include <type_traits>
33
34 namespace enigma2
35 {
36 namespace data
37 {
38 static const std::string TAG_FOR_AUTOTIMER = "AutoTimer";
39 static const std::string TAG_FOR_MANUAL_TIMER = "Manual";
40 static const std::string TAG_FOR_EPG_TIMER = "EPG";
41 static const std::string TAG_FOR_PADDING = "Padding";
42
43 class Timer : public EpgEntry, public Tags
44 {
45 public:
46
47 enum Type
48 : unsigned int // same type as PVR_TIMER_TYPE.iId
49 {
50 MANUAL_ONCE = PVR_TIMER_TYPE_NONE + 1,
51 MANUAL_REPEATING = PVR_TIMER_TYPE_NONE + 2,
52 READONLY_REPEATING_ONCE = PVR_TIMER_TYPE_NONE + 3,
53 EPG_ONCE = PVR_TIMER_TYPE_NONE + 4,
54 EPG_REPEATING = PVR_TIMER_TYPE_NONE + 5, //Can't be created on Kodi, only on the engima2 box
55 EPG_AUTO_SEARCH = PVR_TIMER_TYPE_NONE + 6,
56 EPG_AUTO_ONCE = PVR_TIMER_TYPE_NONE + 7,
57 };
58
59 Timer()
60 {
61 m_updateState = enigma2::utilities::UPDATE_STATE_NEW;
62 m_parentClientIndex = PVR_TIMER_NO_PARENT;
63 }
64
65 Type GetType() const { return m_type; }
66 void SetType(const Type value) { m_type = value; }
67
68 const std::string& GetChannelName() const { return m_channelName; }
69 void SetChannelName(const std::string& value) { m_channelName = value; }
70
71 time_t GetRealStartTime() const { return m_startTime - (m_paddingStartMins * 60); }
72 time_t GetRealEndTime() const { return m_endTime + (m_paddingEndMins * 60); }
73
74 int GetWeekdays() const { return m_weekdays; }
75 void SetWeekdays(int value) { m_weekdays = value; }
76
77 PVR_TIMER_STATE GetState() const { return m_state; }
78 void SetState(PVR_TIMER_STATE value) { m_state = value; }
79
80 int GetUpdateState() const { return m_updateState; }
81 void SetUpdateState(int value) { m_updateState = value; }
82
83 unsigned int GetClientIndex() const { return m_clientIndex; }
84 void SetClientIndex(unsigned int value) { m_clientIndex = value; }
85
86 unsigned int GetParentClientIndex() const { return m_parentClientIndex; }
87 void SetParentClientIndex(unsigned int value) { m_parentClientIndex = value; }
88
89 int GetPaddingStartMins() const { return m_paddingStartMins; }
90 void SetPaddingStartMins(int value) { m_paddingStartMins = value; }
91
92 int GetPaddingEndMins() const { return m_paddingEndMins; }
93 void SetPaddingEndMins(int value) { m_paddingEndMins = value; }
94
95 bool IsScheduled() const;
96 bool IsRunning(std::time_t* now, std::string* channelName, std::time_t startTime) const;
97 bool IsChildOfParent(const Timer& parent) const;
98
99 bool Like(const Timer& right) const;
100 bool operator==(const Timer& right) const;
101 void UpdateFrom(const Timer& right);
102 void UpdateTo(PVR_TIMER& right) const;
103 bool UpdateFrom(TiXmlElement* timerNode, Channels& channels);
104
105 protected:
106 Type m_type = Type::MANUAL_ONCE;
107 std::string m_channelName;
108 int m_weekdays;
109 PVR_TIMER_STATE m_state;
110 int m_updateState;
111 unsigned int m_clientIndex;
112 unsigned int m_parentClientIndex;
113 unsigned int m_paddingStartMins = 0;
114 unsigned int m_paddingEndMins = 0;
115 };
116 } //namespace data
117 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "EpgEntryExtractor.h"
23
24 #include "../utilities/FileUtils.h"
25 #include "GenreIdMapper.h"
26 #include "GenreRytecTextMapper.h"
27 #include "ShowInfoExtractor.h"
28
29 using namespace enigma2;
30 using namespace enigma2::data;
31 using namespace enigma2::extract;
32 using namespace enigma2::utilities;
33
34 EpgEntryExtractor::EpgEntryExtractor()
35 : IExtractor()
36 {
37 FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + GENRE_DIR, GENRE_ADDON_DATA_BASE_DIR, true);
38 FileUtils::CopyDirectory(FileUtils::GetResourceDataPath() + SHOW_INFO_DIR, SHOW_INFO_ADDON_DATA_BASE_DIR, true);
39
40 if (Settings::GetInstance().GetMapGenreIds())
41 m_extractors.emplace_back(new GenreIdMapper());
42 if (Settings::GetInstance().GetMapRytecTextGenres())
43 m_extractors.emplace_back(new GenreRytecTextMapper());
44 if (Settings::GetInstance().GetExtractShowInfo())
45 m_extractors.emplace_back(new ShowInfoExtractor());
46
47 m_anyExtractorEnabled = false;
48 for (auto& extractor : m_extractors)
49 {
50 if (extractor->IsEnabled())
51 m_anyExtractorEnabled = true;
52 }
53 }
54
55 EpgEntryExtractor::~EpgEntryExtractor(void) {}
56
57 void EpgEntryExtractor::ExtractFromEntry(BaseEntry& entry)
58 {
59 for (auto& extractor : m_extractors)
60 {
61 if (extractor->IsEnabled())
62 extractor->ExtractFromEntry(entry);
63 }
64 }
65
66 bool EpgEntryExtractor::IsEnabled() { return m_anyExtractorEnabled; }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "IExtractor.h"
24
25 #include <memory>
26 #include <string>
27 #include <vector>
28
29 namespace enigma2
30 {
31 namespace extract
32 {
33 static const std::string GENRE_DIR = "/genres";
34 static const std::string GENRE_ADDON_DATA_BASE_DIR = ADDON_DATA_BASE_DIR + GENRE_DIR;
35 static const std::string SHOW_INFO_DIR = "/showInfo";
36 static const std::string SHOW_INFO_ADDON_DATA_BASE_DIR = ADDON_DATA_BASE_DIR + SHOW_INFO_DIR;
37
38 class EpgEntryExtractor : public IExtractor
39 {
40 public:
41 EpgEntryExtractor();
42 ~EpgEntryExtractor(void);
43
44 void ExtractFromEntry(enigma2::data::BaseEntry& entry);
45 bool IsEnabled();
46
47 private:
48 std::vector<std::unique_ptr<IExtractor>> m_extractors;
49 bool m_anyExtractorEnabled;
50 };
51 } //namespace extract
52 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <regex>
24
25 namespace enigma2
26 {
27 namespace extract
28 {
29 struct EpisodeSeasonPattern
30 {
31 EpisodeSeasonPattern(const std::string& masterPattern, const std::string& seasonPattern, const std::string& episodePattern)
32 {
33 m_masterRegex = std::regex(masterPattern);
34 m_seasonRegex = std::regex(seasonPattern);
35 m_episodeRegex = std::regex(episodePattern);
36 m_hasSeasonRegex = true;
37 }
38
39 EpisodeSeasonPattern(const std::string& masterPattern, const std::string& episodePattern)
40 {
41 m_masterRegex = std::regex(masterPattern);
42 m_episodeRegex = std::regex(episodePattern);
43 m_hasSeasonRegex = false;
44 }
45
46 std::regex m_masterRegex;
47 std::regex m_seasonRegex;
48 std::regex m_episodeRegex;
49 bool m_hasSeasonRegex;
50 };
51 } //namespace extract
52 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "GenreIdMapper.h"
23
24 #include "../utilities/FileUtils.h"
25 #include "tinyxml.h"
26 #include "kodi/libXBMC_pvr.h"
27 #include "util/XMLUtils.h"
28
29 #include <cstdlib>
30
31 using namespace enigma2;
32 using namespace enigma2::data;
33 using namespace enigma2::extract;
34 using namespace enigma2::utilities;
35
36 GenreIdMapper::GenreIdMapper() : IExtractor()
37 {
38 LoadGenreIdMapFile();
39 }
40
41 GenreIdMapper::~GenreIdMapper(void) {}
42
43 void GenreIdMapper::ExtractFromEntry(BaseEntry& entry)
44 {
45 if (entry.GetGenreType() != 0)
46 {
47 int combinedGenreType = entry.GetGenreType() | entry.GetGenreSubType();
48
49 const int mappedGenreId = LookupGenreIdInMap(combinedGenreType);
50
51 if (mappedGenreId != EPG_EVENT_CONTENTMASK_UNDEFINED)
52 {
53 entry.SetGenreType(GetGenreTypeFromCombined(mappedGenreId));
54 entry.SetGenreSubType(GetGenreSubTypeFromCombined(mappedGenreId));
55 }
56 }
57 }
58
59 bool GenreIdMapper::IsEnabled()
60 {
61 return Settings::GetInstance().GetMapGenreIds();
62 }
63
64 int GenreIdMapper::GetGenreTypeFromCombined(int combinedGenreType)
65 {
66 return combinedGenreType & 0xF0;
67 }
68
69 int GenreIdMapper::GetGenreSubTypeFromCombined(int combinedGenreType)
70 {
71 return combinedGenreType & 0x0F;
72 }
73
74 int GenreIdMapper::LookupGenreIdInMap(const int combinedGenreType)
75 {
76 int genreType = EPG_EVENT_CONTENTMASK_UNDEFINED;
77
78 auto genreMapSearch = m_genreIdToDvbIdMap.find(combinedGenreType);
79 if (genreMapSearch != m_genreIdToDvbIdMap.end())
80 {
81 genreType = genreMapSearch->second;
82 }
83
84 return genreType;
85 }
86
87 void GenreIdMapper::LoadGenreIdMapFile()
88 {
89 if (!LoadIdToIdGenreFile(Settings::GetInstance().GetMapGenreIdsFile(), m_genreIdToDvbIdMap))
90 Logger::Log(LEVEL_ERROR, "%s Could not load genre id to dvb id file: %s", __FUNCTION__, Settings::GetInstance().GetMapGenreIdsFile().c_str());
91 }
92
93 bool GenreIdMapper::LoadIdToIdGenreFile(const std::string& xmlFile, std::map<int, int>& map)
94 {
95 map.clear();
96
97 if (!FileUtils::FileExists(xmlFile.c_str()))
98 {
99 Logger::Log(LEVEL_ERROR, "%s No XML file found: %s", __FUNCTION__, xmlFile.c_str());
100 return false;
101 }
102
103 Logger::Log(LEVEL_DEBUG, "%s Loading XML File: %s", __FUNCTION__, xmlFile.c_str());
104
105 const std::string fileContents = FileUtils::ReadXmlFileToString(xmlFile);
106
107 if (fileContents.empty())
108 {
109 Logger::Log(LEVEL_ERROR, "%s No Content in XML file: %s", __FUNCTION__, xmlFile.c_str());
110 return false;
111 }
112
113 TiXmlDocument xmlDoc;
114 if (!xmlDoc.Parse(fileContents.c_str()))
115 {
116 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
117 return false;
118 }
119
120 TiXmlHandle hDoc(&xmlDoc);
121
122 TiXmlElement* pElem = hDoc.FirstChildElement("genreIdMappings").Element();
123
124 if (!pElem)
125 {
126 Logger::Log(LEVEL_ERROR, "%s Could not find <genreIdMappings> element!", __FUNCTION__);
127 return false;
128 }
129
130 std::string mapperName;
131
132 if (!XMLUtils::GetString(pElem, "mapperName", mapperName))
133 return false;
134
135 TiXmlHandle hRoot = TiXmlHandle(pElem);
136
137 TiXmlElement* pNode = hRoot.FirstChildElement("mappings").Element();
138
139 if (!pNode)
140 {
141 Logger::Log(LEVEL_ERROR, "%s Could not find <mappings> element", __FUNCTION__);
142 return false;
143 }
144
145 pNode = pNode->FirstChildElement("mapping");
146
147 if (!pNode)
148 {
149 Logger::Log(LEVEL_ERROR, "%s Could not find <mapping> element", __FUNCTION__);
150 return false;
151 }
152
153 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("mapping"))
154 {
155 const std::string sourceIdString = pNode->Attribute("sourceId");
156 const std::string targetIdString = pNode->GetText();
157
158 int sourceId = std::strtol(sourceIdString.c_str(), nullptr, 16);
159 int targetId = std::strtol(targetIdString.c_str(), nullptr, 16);
160
161 map.insert({sourceId, targetId});
162
163 Logger::Log(LEVEL_TRACE, "%s Read ID Mapping for: %s, sourceId=%#02X, targetId=%#02X", __FUNCTION__, mapperName.c_str(), sourceId, targetId);
164 }
165
166 return true;
167 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "IExtractor.h"
24
25 #include <map>
26 #include <string>
27
28 namespace enigma2
29 {
30 namespace extract
31 {
32 class GenreIdMapper : public IExtractor
33 {
34 public:
35 GenreIdMapper();
36 ~GenreIdMapper();
37
38 void ExtractFromEntry(enigma2::data::BaseEntry& entry);
39 bool IsEnabled();
40
41 private:
42 static int GetGenreTypeFromCombined(int combinedGenreType);
43 static int GetGenreSubTypeFromCombined(int combinedGenreType);
44
45 int LookupGenreIdInMap(const int genreId);
46
47 void LoadGenreIdMapFile();
48 bool LoadIdToIdGenreFile(const std::string& xmlFile, std::map<int, int>& map);
49 void CreateGenreAddonDataDirectories();
50
51 std::map<int, int> m_genreIdToDvbIdMap;
52 };
53 } //namespace extract
54 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "GenreRytecTextMapper.h"
23
24 #include "../utilities/FileUtils.h"
25 #include "tinyxml.h"
26 #include "kodi/libXBMC_pvr.h"
27 #include "util/XMLUtils.h"
28
29 #include <cstdlib>
30
31 using namespace enigma2;
32 using namespace enigma2::data;
33 using namespace enigma2::extract;
34 using namespace enigma2::utilities;
35
36 GenreRytecTextMapper::GenreRytecTextMapper() : IExtractor()
37 {
38 LoadGenreTextMappingFiles();
39
40 for (const auto& genreMapEntry : m_kodiGenreTextToDvbIdMap)
41 {
42 m_kodiDvbIdToGenreTextMap.insert({genreMapEntry.second, genreMapEntry.first});
43 }
44
45 m_genrePattern = std::regex(GENRE_PATTERN);
46 m_genreMajorPattern = std::regex(GENRE_MAJOR_PATTERN);
47 }
48
49 GenreRytecTextMapper::~GenreRytecTextMapper(void) {}
50
51 void GenreRytecTextMapper::ExtractFromEntry(BaseEntry& entry)
52 {
53 if (entry.GetGenreType() == 0)
54 {
55 const std::string genreText = GetMatchedText(entry.GetPlotOutline(), entry.GetPlot(), m_genrePattern);
56
57 if (!genreText.empty() && genreText != GENRE_RESERVED_IGNORE)
58 {
59 int combinedGenreType = GetGenreTypeFromText(genreText, entry.GetTitle());
60
61 if (combinedGenreType == EPG_EVENT_CONTENTMASK_UNDEFINED)
62 {
63 if (m_settings.GetLogMissingGenreMappings())
64 Logger::Log(LEVEL_NOTICE, "%s: Could not lookup genre using genre description string instead:'%s'", __FUNCTION__, genreText.c_str());
65
66 entry.SetGenreType(EPG_GENRE_USE_STRING);
67 entry.SetGenreDescription(genreText);
68 }
69 else
70 {
71 entry.SetGenreType(GetGenreTypeFromCombined(combinedGenreType));
72 entry.SetGenreSubType(GetGenreSubTypeFromCombined(combinedGenreType));
73 }
74 }
75 }
76 }
77
78 bool GenreRytecTextMapper::IsEnabled()
79 {
80 return Settings::GetInstance().GetMapRytecTextGenres();
81 }
82
83 int GenreRytecTextMapper::GetGenreTypeFromCombined(int combinedGenreType)
84 {
85 return combinedGenreType & 0xF0;
86 }
87
88 int GenreRytecTextMapper::GetGenreSubTypeFromCombined(int combinedGenreType)
89 {
90 return combinedGenreType & 0x0F;
91 }
92
93 int GenreRytecTextMapper::GetGenreTypeFromText(const std::string& genreText, const std::string& showName)
94 {
95 int genreType = LookupGenreValueInMaps(genreText);
96
97 if (genreType == EPG_EVENT_CONTENTMASK_UNDEFINED)
98 {
99 if (m_settings.GetLogMissingGenreMappings())
100 Logger::Log(LEVEL_NOTICE, "%s: Tried to find genre text but no value: '%s', show - '%s'", __FUNCTION__, genreText.c_str(), showName.c_str());
101
102 std::string genreMajorText = GetMatchTextFromString(genreText, m_genreMajorPattern);
103
104 if (!genreMajorText.empty())
105 {
106 genreType = LookupGenreValueInMaps(genreMajorText);
107
108 if (genreType == EPG_EVENT_CONTENTMASK_UNDEFINED && m_settings.GetLogMissingGenreMappings())
109 Logger::Log(LEVEL_NOTICE, "%s: Tried to find major genre text but no value: '%s', show - '%s'", __FUNCTION__, genreMajorText.c_str(), showName.c_str());
110 }
111 }
112
113 return genreType;
114 }
115
116 int GenreRytecTextMapper::LookupGenreValueInMaps(const std::string& genreText)
117 {
118 int genreType = EPG_EVENT_CONTENTMASK_UNDEFINED;
119
120 auto genreMapSearch = m_genreMap.find(genreText);
121 if (genreMapSearch != m_genreMap.end())
122 {
123 genreType = genreMapSearch->second;
124 }
125 else
126 {
127 auto kodiGenreMapSearch = m_kodiGenreTextToDvbIdMap.find(genreText);
128 if (kodiGenreMapSearch != m_kodiGenreTextToDvbIdMap.end())
129 {
130 genreType = kodiGenreMapSearch->second;
131 }
132 }
133
134 return genreType;
135 }
136
137 void GenreRytecTextMapper::LoadGenreTextMappingFiles()
138 {
139 if (!LoadTextToIdGenreFile(GENRE_KODI_DVB_FILEPATH, m_kodiGenreTextToDvbIdMap))
140 Logger::Log(LEVEL_ERROR, "%s Could not load text to genre id file: %s", __FUNCTION__, GENRE_KODI_DVB_FILEPATH.c_str());
141
142 if (!LoadTextToIdGenreFile(Settings::GetInstance().GetMapRytecTextGenresFile(), m_genreMap))
143 Logger::Log(LEVEL_ERROR, "%s Could not load genre id to dvb id file: %s", __FUNCTION__, Settings::GetInstance().GetMapRytecTextGenresFile().c_str());
144 }
145
146 bool GenreRytecTextMapper::LoadTextToIdGenreFile(const std::string& xmlFile, std::map<std::string, int>& map)
147 {
148 map.clear();
149
150 if (!FileUtils::FileExists(xmlFile.c_str()))
151 {
152 Logger::Log(LEVEL_ERROR, "%s No XML file found: %s", __FUNCTION__, xmlFile.c_str());
153 return false;
154 }
155
156 Logger::Log(LEVEL_DEBUG, "%s Loading XML File: %s", __FUNCTION__, xmlFile.c_str());
157
158 const std::string fileContents = FileUtils::ReadXmlFileToString(xmlFile);
159
160 if (fileContents.empty())
161 {
162 Logger::Log(LEVEL_ERROR, "%s No Content in XML file: %s", __FUNCTION__, xmlFile.c_str());
163 return false;
164 }
165
166 TiXmlDocument xmlDoc;
167 if (!xmlDoc.Parse(fileContents.c_str()))
168 {
169 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
170 return false;
171 }
172
173 TiXmlHandle hDoc(&xmlDoc);
174
175 TiXmlElement* pElem = hDoc.FirstChildElement("genreTextMappings").Element();
176
177 if (!pElem)
178 {
179 Logger::Log(LEVEL_ERROR, "%s Could not find <genreTextMappings> element!", __FUNCTION__);
180 return false;
181 }
182
183 std::string mapperName;
184
185 if (!XMLUtils::GetString(pElem, "mapperName", mapperName))
186 return false;
187
188 TiXmlHandle hRoot = TiXmlHandle(pElem);
189
190 TiXmlElement* pNode = hRoot.FirstChildElement("mappings").Element();
191
192 if (!pNode)
193 {
194 Logger::Log(LEVEL_ERROR, "%s Could not find <mappings> element", __FUNCTION__);
195 return false;
196 }
197
198 pNode = pNode->FirstChildElement("mapping");
199
200 if (!pNode)
201 {
202 Logger::Log(LEVEL_ERROR, "%s Could not find <mapping> element", __FUNCTION__);
203 return false;
204 }
205
206 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("mapping"))
207 {
208 const std::string targetIdString = pNode->Attribute("targetId");
209 const std::string textMapping = pNode->GetText();
210
211 int targetId = std::strtol(targetIdString.c_str(), nullptr, 16);
212
213 map.insert({textMapping, targetId});
214
215 Logger::Log(LEVEL_TRACE, "%s Read Text Mapping for: %s, text=%s, targetId=%#02X", __FUNCTION__, mapperName.c_str(), textMapping.c_str(), targetId);
216 }
217
218 return true;
219 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "IExtractor.h"
24
25 #include <map>
26 #include <regex>
27 #include <string>
28
29 namespace enigma2
30 {
31 namespace extract
32 {
33 static const std::string GENRE_PATTERN = "^\\[([a-zA-Z /]{3}[a-zA-Z ./]+)\\][^]*";
34 static const std::string GENRE_MAJOR_PATTERN = "^([a-zA-Z /]{3,})\\.?.*";
35 static const std::string GENRE_RESERVED_IGNORE = "reserved";
36
37 static const std::string GENRE_KODI_DVB_FILEPATH = "special://userdata/addon_data/pvr.vuplus/genres/kodiDvbGenres.xml";
38
39 class GenreRytecTextMapper : public IExtractor
40 {
41 public:
42 GenreRytecTextMapper();
43 ~GenreRytecTextMapper();
44
45 void ExtractFromEntry(enigma2::data::BaseEntry& entry);
46 bool IsEnabled();
47
48 private:
49 static int GetGenreTypeFromCombined(int combinedGenreType);
50 static int GetGenreSubTypeFromCombined(int combinedGenreType);
51
52 int GetGenreTypeFromText(const std::string& genreText, const std::string& showName);
53 int LookupGenreValueInMaps(const std::string& genreText);
54
55 void LoadGenreTextMappingFiles();
56 bool LoadTextToIdGenreFile(const std::string& xmlFile, std::map<std::string, int>& map);
57 void CreateGenreAddonDataDirectories();
58
59 std::regex m_genrePattern;
60 std::regex m_genreMajorPattern;
61 std::map<std::string, int> m_kodiGenreTextToDvbIdMap;
62 std::map<int, std::string> m_kodiDvbIdToGenreTextMap;
63 std::map<std::string, int> m_genreMap;
64 };
65 } //namespace extract
66 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "../Settings.h"
24 #include "../data/BaseEntry.h"
25
26 #include <regex>
27
28 namespace enigma2
29 {
30 namespace extract
31 {
32 class IExtractor
33 {
34 public:
35 IExtractor() = default;
36 virtual ~IExtractor() = default;
37 virtual void ExtractFromEntry(enigma2::data::BaseEntry& entry) = 0;
38 virtual bool IsEnabled() = 0;
39
40 protected:
41 static std::string GetMatchTextFromString(const std::string& text, const std::regex& pattern)
42 {
43 std::string matchText = "";
44 std::smatch match;
45
46 if (std::regex_match(text, match, pattern))
47 {
48 if (match.size() == 2)
49 {
50 std::ssub_match base_sub_match = match[1];
51 matchText = base_sub_match.str();
52 }
53 }
54
55 return matchText;
56 };
57
58 static std::string GetMatchedText(const std::string& firstText, const std::string& secondText, const std::regex& pattern)
59 {
60 std::string matchedText = GetMatchTextFromString(firstText, pattern);
61
62 if (matchedText.empty())
63 matchedText = GetMatchTextFromString(secondText, pattern);
64
65 return matchedText;
66 }
67
68 enigma2::Settings& m_settings = Settings::GetInstance();
69 };
70 } //namespace extract
71 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team XBMC
2 * http://www.xbmc.org
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
17 * MA 02110-1335, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 */
21
22 #include "ShowInfoExtractor.h"
23
24 #include "../utilities/FileUtils.h"
25 #include "tinyxml.h"
26 #include "util/XMLUtils.h"
27
28 #include <cstdlib>
29
30 using namespace enigma2;
31 using namespace enigma2::data;
32 using namespace enigma2::extract;
33 using namespace enigma2::utilities;
34
35 ShowInfoExtractor::ShowInfoExtractor() : IExtractor()
36 {
37 if (!LoadShowInfoPatternsFile(Settings::GetInstance().GetExtractShowInfoFile(), m_episodeSeasonPatterns, m_yearPatterns))
38 Logger::Log(LEVEL_ERROR, "%s Could not load show info patterns file: %s", __FUNCTION__, Settings::GetInstance().GetExtractShowInfoFile().c_str());
39 }
40
41 ShowInfoExtractor::~ShowInfoExtractor(void) {}
42
43 void ShowInfoExtractor::ExtractFromEntry(BaseEntry& entry)
44 {
45 for (const auto& patternSet : m_episodeSeasonPatterns)
46 {
47 const std::string masterText = GetMatchedText(entry.GetPlotOutline(), entry.GetPlot(), patternSet.m_masterRegex);
48
49 if (!masterText.empty())
50 {
51 if (patternSet.m_hasSeasonRegex && entry.GetSeasonNumber() == 0)
52 {
53 const std::string seasonText = GetMatchTextFromString(masterText, patternSet.m_seasonRegex);
54 if (!seasonText.empty())
55 {
56 entry.SetSeasonNumber(std::atoi(seasonText.c_str()));
57 }
58 }
59
60 if (entry.GetEpisodeNumber() == 0)
61 {
62 const std::string episodeText = GetMatchTextFromString(masterText, patternSet.m_episodeRegex);
63 if (!episodeText.empty())
64 {
65 entry.SetEpisodeNumber(std::atoi(episodeText.c_str()));
66 }
67 }
68 }
69
70 //Once we have at least an episode number we are done
71 if (entry.GetEpisodeNumber() != 0)
72 break;
73 }
74
75 for (const auto& pattern : m_yearPatterns)
76 {
77 const std::string yearText = GetMatchedText(entry.GetPlotOutline(), entry.GetPlot(), pattern);
78
79 if (!yearText.empty() && entry.GetYear() == 0)
80 {
81 entry.SetYear(std::atoi(yearText.c_str()));
82 }
83
84 if (entry.GetYear() != 0)
85 break;
86 }
87 }
88
89 bool ShowInfoExtractor::IsEnabled()
90 {
91 return Settings::GetInstance().GetExtractShowInfo();
92 }
93
94 bool ShowInfoExtractor::LoadShowInfoPatternsFile(const std::string& xmlFile, std::vector<EpisodeSeasonPattern>& episodeSeasonPatterns, std::vector<std::regex> yearPatterns)
95 {
96 episodeSeasonPatterns.clear();
97 yearPatterns.clear();
98
99 if (!FileUtils::FileExists(xmlFile.c_str()))
100 {
101 Logger::Log(LEVEL_ERROR, "%s No XML file found: %s", __FUNCTION__, xmlFile.c_str());
102 return false;
103 }
104
105 Logger::Log(LEVEL_DEBUG, "%s Loading XML File: %s", __FUNCTION__, xmlFile.c_str());
106
107 const std::string fileContents = FileUtils::ReadXmlFileToString(xmlFile);
108
109 if (fileContents.empty())
110 {
111 Logger::Log(LEVEL_ERROR, "%s No Content in XML file: %s", __FUNCTION__, xmlFile.c_str());
112 return false;
113 }
114
115 TiXmlDocument xmlDoc;
116 if (!xmlDoc.Parse(fileContents.c_str()))
117 {
118 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
119 return false;
120 }
121
122 TiXmlHandle hDoc(&xmlDoc);
123
124 TiXmlElement* pElem = hDoc.FirstChildElement("showInfo").Element();
125
126 if (!pElem)
127 {
128 Logger::Log(LEVEL_ERROR, "%s Could not find <showInfo> element!", __FUNCTION__);
129 return false;
130 }
131
132 std::string name;
133
134 if (!XMLUtils::GetString(pElem, "name", name))
135 return false;
136
137 TiXmlHandle hRoot = TiXmlHandle(pElem);
138
139 //First we do the seasonEpisodes
140 TiXmlElement* pNode = hRoot.FirstChildElement("seasonEpisodes").Element();
141
142 if (!pNode)
143 {
144 Logger::Log(LEVEL_ERROR, "%s Could not find <seasonEpisodes> element", __FUNCTION__);
145 return false;
146 }
147
148 pNode = pNode->FirstChildElement("seasonEpisode");
149
150 if (!pNode)
151 {
152 Logger::Log(LEVEL_ERROR, "%s Could not find <seasonEpisode> element", __FUNCTION__);
153 return false;
154 }
155
156 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("seasonEpisode"))
157 {
158 TiXmlElement* childNode = pNode->FirstChildElement("master");
159
160 if (childNode)
161 {
162 const std::string masterPattern = childNode->Attribute("pattern");
163
164 childNode = pNode->FirstChildElement("episode");
165
166 if (childNode)
167 {
168 const std::string episodePattern = childNode->Attribute("pattern");
169
170 childNode = pNode->FirstChildElement("season");
171 if (childNode != nullptr)
172 {
173 const std::string seasonPattern = childNode->Attribute("pattern");
174
175 if (!masterPattern.empty() && !seasonPattern.empty() && !episodePattern.empty())
176 {
177 episodeSeasonPatterns.emplace_back(EpisodeSeasonPattern(masterPattern, seasonPattern, episodePattern));
178
179 Logger::Log(LEVEL_DEBUG, "%s Adding seasonEpisode pattern: %s, master: %s, season: %s, episode: %s", __FUNCTION__, name.c_str(), masterPattern.c_str(), seasonPattern.c_str(), episodePattern.c_str());
180 }
181 }
182 else
183 {
184 if (!masterPattern.empty() && !episodePattern.empty())
185 {
186 episodeSeasonPatterns.emplace_back(EpisodeSeasonPattern(masterPattern, episodePattern));
187
188 Logger::Log(LEVEL_DEBUG, "%s Adding episode pattern from: %s, master: %s, episode: %s", __FUNCTION__, name.c_str(), masterPattern.c_str(), episodePattern.c_str());
189 }
190 }
191 }
192 else
193 {
194 Logger::Log(LEVEL_ERROR, "%s Could find <episode> element, skipping pattern from: %s", __FUNCTION__, name.c_str());
195 }
196 }
197 else
198 {
199 Logger::Log(LEVEL_ERROR, "%s Could find <master> element, skipping pattern from: %s", __FUNCTION__, name.c_str());
200 }
201 }
202
203 //Now we do the years
204 pNode = hRoot.FirstChildElement("years").Element();
205
206 if (!pNode)
207 {
208 Logger::Log(LEVEL_ERROR, "%s Could not find <years> element", __FUNCTION__);
209 return false;
210 }
211
212 pNode = pNode->FirstChildElement("year");
213
214 if (!pNode)
215 {
216 Logger::Log(LEVEL_ERROR, "%s Could not find <year> element", __FUNCTION__);
217 return false;
218 }
219
220 for (; pNode != nullptr; pNode = pNode->NextSiblingElement("year"))
221 {
222 const std::string yearPattern = pNode->Attribute("pattern");
223
224 yearPatterns.emplace_back(std::regex(yearPattern));
225
226 Logger::Log(LEVEL_DEBUG, "%s Adding year pattern from: %s, pattern: %s", __FUNCTION__, name.c_str(), yearPattern.c_str());
227 }
228
229 return true;
230 }
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "EpisodeSeasonPattern.h"
24 #include "IExtractor.h"
25
26 #include <regex>
27 #include <string>
28 #include <vector>
29
30 namespace enigma2
31 {
32 namespace extract
33 {
34 // (S4E37) (S04E37) (S2 Ep3/6) (S2 Ep7)
35 static const std::string MASTER_SEASON_EPISODE_PATTERN = "^.*\\(?([sS]\\.?[0-9]+ ?[eE][pP]?\\.?[0-9]+/?[0-9]*)\\)?[^]*$";
36 // (E130) (Ep10) (E7/9) (Ep7/10) (Ep.25)
37 static const std::string MASTER_EPISODE_PATTERN = "^.*\\(?([eE][pP]?\\.?[0-9]+/?[0-9]*)\\)?[^]*$";
38 // (2015E22) (2007E3) (2007E3/6)
39 static const std::string MASTER_YEAR_EPISODE_PATTERN = "^.*\\(?([12][0-9][0-9][0-9][eE][pP]?\\.?[0-9]+\\.?/?[0-9]*)\\)?[^]*$";
40 // Starts with 2/4 6/6, no prefix
41 static const std::string MASTER_EPISODE_NO_PREFIX_PATTERN = "^.*([0-9]+/[0-9]+)\\.? +[^]*$";
42
43 // Get from matster match, prefixed by S,s,E,e,Ep
44 static const std::string GET_SEASON_PATTERN = "^.*[sS]\\.?([0-9][0-9]*).*$";
45 static const std::string GET_EPISODE_PATTERN = "^.*[eE][pP]?\\.?([0-9][0-9]*).*$";
46 // Get from master match, no prefix
47 static const std::string GET_EPISODE_NO_PREFIX_PATTERN = "^([0-9]+)/[0-9]+";
48
49 // (2018)
50 static const std::string GET_YEAR_PATTERN = "^.*\\(([12][0-9][0-9][0-9])\\)[^]*$";
51 // (2018E25)
52 static const std::string GET_YEAR_EPISODE_PATTERN = "^.*\\(([12][0-9][0-9][0-9])[eE][pP]?\\.?[0-9]+/?[0-9]*\\)[^]*$";
53
54 class ShowInfoExtractor : public IExtractor
55 {
56 public:
57 ShowInfoExtractor();
58 ~ShowInfoExtractor(void);
59
60 void ExtractFromEntry(enigma2::data::BaseEntry& entry);
61 bool IsEnabled();
62
63 private:
64 bool LoadShowInfoPatternsFile(const std::string& xmlFile, std::vector<EpisodeSeasonPattern>& episodeSeasonPatterns, std::vector<std::regex> yearPatterns);
65
66 std::vector<EpisodeSeasonPattern> m_episodeSeasonPatterns;
67 std::vector<std::regex> m_yearPatterns;
68 };
69 } //namespace extract
70 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team Kodi
2 * http://kodi.tv
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 * http://www.gnu.org/copyleft/gpl.html
18 *
19 */
20
21 #include "CurlFile.h"
22
23 #include "../Settings.h"
24 #include "Logger.h"
25
26 #include <cstdarg>
27
28 using namespace enigma2::utilities;
29
30 bool CurlFile::Get(const std::string& strURL, std::string& strResult)
31 {
32 void* fileHandle = XBMC->OpenFile(strURL.c_str(), 0);
33 if (fileHandle)
34 {
35 char buffer[1024];
36 while (XBMC->ReadFileString(fileHandle, buffer, 1024))
37 strResult.append(buffer);
38 XBMC->CloseFile(fileHandle);
39 return true;
40 }
41 return false;
42 }
43
44 bool CurlFile::Post(const std::string& strURL, std::string& strResult)
45 {
46 void* fileHandle = XBMC->CURLCreate(strURL.c_str());
47
48 if (!fileHandle)
49 {
50 Logger::Log(LEVEL_ERROR, "%s Unable to create curl handle for %s", __FUNCTION__, strURL.c_str());
51 return false;
52 }
53
54 XBMC->CURLAddOption(fileHandle, XFILE::CURL_OPTION_PROTOCOL, "postdata", "POST");
55
56 if (!XBMC->CURLOpen(fileHandle, XFILE::READ_NO_CACHE))
57 {
58 Logger::Log(LEVEL_ERROR, "%s Unable to open url: %s", __FUNCTION__, strURL.c_str());
59 XBMC->CloseFile(fileHandle);
60 return false;
61 }
62
63 char buffer[1024];
64 while (XBMC->ReadFileString(fileHandle, buffer, 1024))
65 strResult.append(buffer);
66 XBMC->CloseFile(fileHandle);
67
68 if (!strResult.empty())
69 return true;
70
71 return false;
72 }
73
74 bool CurlFile::Check(const std::string& strURL)
75 {
76 void* fileHandle = XBMC->CURLCreate(strURL.c_str());
77
78 if (!fileHandle)
79 {
80 Logger::Log(LEVEL_ERROR, "%s Unable to create curl handle for %s", __FUNCTION__, strURL.c_str());
81 return false;
82 }
83
84 XBMC->CURLAddOption(fileHandle, XFILE::CURL_OPTION_PROTOCOL, "connection-timeout",
85 std::to_string(Settings::GetInstance().GetConnectioncCheckTimeoutSecs()).c_str());
86
87 if (!XBMC->CURLOpen(fileHandle, XFILE::READ_NO_CACHE))
88 {
89 Logger::Log(LEVEL_TRACE, "%s Unable to open url: %s", __FUNCTION__, strURL.c_str());
90 XBMC->CloseFile(fileHandle);
91 return false;
92 }
93
94 XBMC->CloseFile(fileHandle);
95
96 return true;
97 }
0 #pragma once
1
2 /*
3 * Copyright (C) 2005-2019 Team Kodi
4 * http://kodi.tv
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "../../client.h"
24
25 #include <string>
26
27 namespace enigma2
28 {
29 namespace utilities
30 {
31 class CurlFile
32 {
33 public:
34 CurlFile(void) {};
35 ~CurlFile(void) {};
36
37 bool Get(const std::string& strURL, std::string& strResult);
38 bool Post(const std::string& strURL, std::string& strResult);
39 bool Check(const std::string& strURL);
40 };
41 } // namespace utilities
42 } // namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <regex>
24
25 namespace enigma2
26 {
27 namespace utilities
28 {
29 class DeviceInfo
30 {
31 public:
32 DeviceInfo() = default;
33 DeviceInfo(const std::string& serverName, const std::string& enigmaVersion, const std::string& imageVersion, const std::string& distroName,
34 const std::string& webIfVersion, unsigned int webIfVersionAsNum)
35 : m_serverName(serverName), m_enigmaVersion(enigmaVersion), m_imageVersion(imageVersion), m_distroName(distroName),
36 m_webIfVersion(webIfVersion), m_webIfVersionAsNum(webIfVersionAsNum) {};
37
38 const std::string& GetServerName() const { return m_serverName; }
39 const std::string& GetEnigmaVersion() const { return m_enigmaVersion; }
40 const std::string& GetImageVersion() const { return m_imageVersion; }
41 const std::string& GetDistroName() const { return m_distroName; }
42 const std::string& GetWebIfVersion() const { return m_webIfVersion; }
43 unsigned int GetWebIfVersionAsNum() const { return m_webIfVersionAsNum; }
44
45 private:
46 std::string m_serverName = "Enigma2";
47 std::string m_enigmaVersion;
48 std::string m_imageVersion;
49 std::string m_distroName;
50 std::string m_webIfVersion;
51 unsigned int m_webIfVersionAsNum;
52 };
53 } //namespace utilities
54 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <regex>
24
25 namespace enigma2
26 {
27 namespace utilities
28 {
29 class DeviceSettings
30 {
31 public:
32 DeviceSettings() = default;
33
34 bool IsAddTagAutoTimerToTagsEnabled() const { return m_addTagAutoTimerToTagsEnabled; }
35 void SetAddTagAutoTimerToTagsEnabled(bool value) { m_addTagAutoTimerToTagsEnabled = value; }
36
37 bool IsAddAutoTimerNameToTagsEnabled() const { return m_addAutoTimerNameToTagsEnabled; }
38 void SetAddAutoTimerNameToTagsEnabled(bool value) { m_addAutoTimerNameToTagsEnabled = value; }
39
40 int GetGlobalRecordingStartMargin() const { return m_globalRecrordingStartMargin; }
41 void SetGlobalRecordingStartMargin(int value) { m_globalRecrordingStartMargin = value; }
42
43 int GetGlobalRecordingEndMargin() const { return m_globalRecrordingEndMargin; }
44 void SetGlobalRecordingEndMargin(int value) { m_globalRecrordingEndMargin = value; }
45
46 private:
47 bool m_addTagAutoTimerToTagsEnabled = false;
48 bool m_addAutoTimerNameToTagsEnabled = false;
49 int m_globalRecrordingStartMargin = 0;
50 int m_globalRecrordingEndMargin = 0;
51 };
52 } //namespace utilities
53 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team Kodi
2 * http://kodi.tv
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 * http://www.gnu.org/copyleft/gpl.html
18 *
19 */
20
21 #include "FileUtils.h"
22
23 #include "../../client.h"
24 #include "Logger.h"
25
26 #include <kodi/kodi_vfs_types.h>
27
28 using namespace enigma2;
29 using namespace enigma2::utilities;
30
31 bool FileUtils::FileExists(const std::string& file)
32 {
33 return XBMC->FileExists(file.c_str(), false);
34 }
35
36 bool FileUtils::CopyFile(const std::string& sourceFile, const std::string& targetFile)
37 {
38 bool copySuccessful = true;
39
40 Logger::Log(LEVEL_DEBUG, "%s Copying file: %s, to %s", __FUNCTION__, sourceFile.c_str(), targetFile.c_str());
41
42 void* sourceFileHandle = XBMC->OpenFile(sourceFile.c_str(), 0x08); //READ_NO_CACHE
43
44 if (sourceFileHandle)
45 {
46 const std::string fileContents = ReadFileContents(sourceFileHandle);
47
48 XBMC->CloseFile(sourceFileHandle);
49
50 void* targetFileHandle = XBMC->OpenFileForWrite(targetFile.c_str(), true);
51
52 if (targetFileHandle)
53 {
54 XBMC->WriteFile(targetFileHandle, fileContents.c_str(), fileContents.length());
55 XBMC->CloseFile(targetFileHandle);
56 }
57 else
58 {
59 Logger::Log(LEVEL_ERROR, "%s Could not open target file to copy to: %s", __FUNCTION__, targetFile.c_str());
60 copySuccessful = false;
61 }
62 }
63 else
64 {
65 Logger::Log(LEVEL_ERROR, "%s Could not open source file to copy: %s", __FUNCTION__, sourceFile.c_str());
66 copySuccessful = false;
67 }
68
69 return copySuccessful;
70 }
71
72 bool FileUtils::WriteStringToFile(const std::string& fileContents, const std::string& targetFile)
73 {
74 bool writeSuccessful = true;
75
76 Logger::Log(LEVEL_DEBUG, "%s Writing strig to file: %s", __FUNCTION__, targetFile.c_str());
77
78 void* targetFileHandle = XBMC->OpenFileForWrite(targetFile.c_str(), true);
79
80 if (targetFileHandle)
81 {
82 XBMC->WriteFile(targetFileHandle, fileContents.c_str(), fileContents.length());
83 XBMC->CloseFile(targetFileHandle);
84 }
85 else
86 {
87 Logger::Log(LEVEL_ERROR, "%s Could not open target file to write to: %s", __FUNCTION__, targetFile.c_str());
88 writeSuccessful = false;
89 }
90
91 return writeSuccessful;
92 }
93
94 std::string FileUtils::ReadXmlFileToString(const std::string& sourceFile)
95 {
96 return ReadFileToString(sourceFile) + "\n";
97 }
98
99 std::string FileUtils::ReadFileToString(const std::string& sourceFile)
100 {
101 std::string fileContents;
102
103 Logger::Log(LEVEL_DEBUG, "%s Reading file to string: %s", __FUNCTION__, sourceFile.c_str());
104
105 void* sourceFileHandle = XBMC->OpenFile(sourceFile.c_str(), 0x08); //READ_NO_CACHE
106
107 if (sourceFileHandle)
108 {
109 fileContents = ReadFileContents(sourceFileHandle);
110
111 XBMC->CloseFile(sourceFileHandle);
112 }
113 else
114 {
115 Logger::Log(LEVEL_ERROR, "%s Could not open source file to read: %s", __FUNCTION__, sourceFile.c_str());
116 }
117
118 return fileContents;
119 }
120
121 std::string FileUtils::ReadFileContents(void* fileHandle)
122 {
123 std::string fileContents;
124
125 char buffer[1024];
126 int bytesRead = 0;
127
128 // Read until EOF or explicit error
129 while ((bytesRead = XBMC->ReadFile(fileHandle, buffer, sizeof(buffer) - 1)) > 0)
130 fileContents.append(buffer, bytesRead);
131
132 return fileContents;
133 }
134
135 bool FileUtils::CopyDirectory(const std::string& sourceDir, const std::string& targetDir, bool recursiveCopy)
136 {
137 bool copySuccessful = true;
138
139 XBMC->CreateDirectory(targetDir.c_str());
140
141 VFSDirEntry* entries;
142 unsigned int numEntries;
143
144 if (XBMC->GetDirectory(sourceDir.c_str(), "", &entries, &numEntries))
145 {
146 for (int i = 0; i < numEntries; i++)
147 {
148 if (entries[i].folder && recursiveCopy)
149 {
150 copySuccessful = CopyDirectory(sourceDir + "/" + entries[i].label, targetDir + "/" + entries[i].label, true);
151 }
152 else if (!entries[i].folder)
153 {
154 copySuccessful = CopyFile(sourceDir + "/" + entries[i].label, targetDir + "/" + entries[i].label);
155 }
156 }
157
158 XBMC->FreeDirectory(entries, numEntries);
159 }
160 else
161 {
162 Logger::Log(LEVEL_ERROR, "%s Could not copy directory: %s, to directory: %s", __FUNCTION__, sourceDir.c_str(), targetDir.c_str());
163 copySuccessful = false;
164 }
165 return copySuccessful;
166 }
167
168 std::vector<std::string> FileUtils::GetFilesInDirectory(const std::string& dir)
169 {
170 std::vector<std::string> files;
171
172 VFSDirEntry* entries;
173 unsigned int numEntries;
174
175 if (XBMC->GetDirectory(dir.c_str(), "", &entries, &numEntries))
176 {
177 for (int i = 0; i < numEntries; i++)
178 {
179 if (!entries[i].folder)
180 {
181 files.emplace_back(entries[i].label);
182 }
183 }
184
185 XBMC->FreeDirectory(entries, numEntries);
186 }
187 else
188 {
189 Logger::Log(LEVEL_ERROR, "%s Could not get files in directory: %s", __FUNCTION__, dir.c_str());
190 }
191
192 return files;
193 }
194
195 std::string FileUtils::GetResourceDataPath()
196 {
197 char path[1024];
198 XBMC->GetSetting("__addonpath__", path);
199 std::string resourcesDataPath = path;
200 resourcesDataPath += "/resources/data";
201
202 return resourcesDataPath;
203 }
0 #pragma once
1
2 /*
3 * Copyright (C) 2005-2019 Team Kodi
4 * http://kodi.tv
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <string>
24 #include <vector>
25
26 namespace enigma2
27 {
28 namespace utilities
29 {
30 class FileUtils
31 {
32 public:
33 static bool FileExists(const std::string& file);
34 static bool CopyFile(const std::string& sourceFile, const std::string& targetFile);
35 static bool WriteStringToFile(const std::string& fileContents, const std::string& targetFile);
36 static std::string ReadFileToString(const std::string& sourceFile);
37 static std::string ReadXmlFileToString(const std::string& sourceFile);
38 static bool CopyDirectory(const std::string& sourceDir, const std::string& targetDir, bool recursiveCopy);
39 static std::vector<std::string> GetFilesInDirectory(const std::string& dir);
40 static std::string GetResourceDataPath();
41
42 private:
43 static std::string ReadFileContents(void* fileHandle);
44 };
45 } // namespace utilities
46 } // namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "../../client.h"
24
25 #include <string>
26
27 namespace enigma2
28 {
29 class LocalizedString
30 {
31 public:
32 explicit LocalizedString(int id)
33 {
34 Load(id);
35 }
36
37 bool Load(int id)
38 {
39 char* str;
40 if ((str = XBMC->GetLocalizedString(id)))
41 {
42 m_localizedString = str;
43 XBMC->FreeString(str);
44 return true;
45 }
46
47 m_localizedString = "";
48 return false;
49 }
50
51 std::string Get()
52 {
53 return m_localizedString;
54 }
55
56 operator std::string()
57 {
58 return Get();
59 }
60
61 const char* c_str()
62 {
63 return m_localizedString.c_str();
64 }
65
66 private:
67 LocalizedString() = delete;
68 LocalizedString(const LocalizedString&) = delete;
69 LocalizedString& operator=(const LocalizedString&) = delete;
70
71 std::string m_localizedString;
72 };
73 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team Kodi
2 * http://kodi.tv
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 * http://www.gnu.org/copyleft/gpl.html
18 *
19 */
20
21 #include "Logger.h"
22
23 #include <cstdarg>
24
25 #include "p8-platform/util/StringUtils.h"
26
27 using namespace enigma2::utilities;
28
29 Logger::Logger()
30 {
31 // Use an empty implementation by default
32 SetImplementation([](LogLevel level, const char* message)
33 {
34 });
35 }
36
37 Logger& Logger::GetInstance()
38 {
39 static Logger instance;
40 return instance;
41 }
42
43 void Logger::Log(LogLevel level, const char* message, ...)
44 {
45 auto& logger = GetInstance();
46
47 std::string logMessage;
48
49 // Prepend the prefix when set
50 const std::string prefix = logger.m_prefix;
51 if (!prefix.empty())
52 logMessage = prefix + " - ";
53
54 logMessage += message;
55
56 va_list arguments;
57 va_start(arguments, message);
58 logMessage = StringUtils::FormatV(logMessage.c_str(), arguments);
59 va_end(arguments);
60
61 logger.m_implementation(level, logMessage.c_str());
62 }
63
64 void Logger::SetImplementation(LoggerImplementation implementation)
65 {
66 m_implementation = implementation;
67 }
68
69 void Logger::SetPrefix(const std::string& prefix)
70 {
71 m_prefix = prefix;
72 }
0 #pragma once
1
2 /*
3 * Copyright (C) 2005-2019 Team Kodi
4 * http://kodi.tv
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <functional>
24 #include <string>
25
26 namespace enigma2
27 {
28 namespace utilities
29 {
30 /**
31 * Represents the log level
32 */
33 enum LogLevel
34 {
35 LEVEL_ERROR,
36 LEVEL_NOTICE,
37 LEVEL_INFO,
38 LEVEL_DEBUG,
39 LEVEL_TRACE
40 };
41
42 /**
43 * Short-hand for a function that acts as the logger implementation
44 */
45 typedef std::function<void(LogLevel level, const char* message)> LoggerImplementation;
46
47 /**
48 * The logger class. It is a singleton that by default comes with no
49 * underlying implementation. It is up to the user to supply a suitable
50 * implementation as a lambda using SetImplementation().
51 */
52 class Logger
53 {
54 public:
55 /**
56 * Returns the singleton instance
57 * @return
58 */
59 static Logger& GetInstance();
60
61 /**
62 * Logs the specified message using the specified log level
63 * @param level the log level
64 * @param message the log message
65 * @param ... parameters for the log message
66 */
67 static void Log(LogLevel level, const char* message, ...);
68
69 /**
70 * Configures the logger to use the specified implementation
71 * @param implementation lambda
72 */
73 void SetImplementation(LoggerImplementation implementation);
74
75 /**
76 * Sets the prefix to use in log messages
77 * @param prefix
78 */
79 void SetPrefix(const std::string& prefix);
80
81 private:
82 Logger();
83
84 /**
85 * The logger implementation
86 */
87 LoggerImplementation m_implementation;
88
89 /**
90 * The log message prefix
91 */
92 std::string m_prefix;
93 };
94 } // namespace utilities
95 } // namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <string>
24
25 namespace enigma2
26 {
27 namespace utilities
28 {
29 static const int POLL_INTERVAL_SECONDS = 10;
30
31 struct SignalStatus
32 {
33 int m_snrPercentage;
34 long m_ber;
35 int m_signalStrength;
36 std::string m_adapterName;
37 std::string m_adapterStatus;
38 };
39 } //namespace utilities
40 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <string>
24
25 namespace enigma2
26 {
27 namespace utilities
28 {
29 enum class StreamType
30 : int // same type as addon settings
31 {
32 DIRECTLY_STREAMED = 0,
33 TRANSCODED
34 };
35
36 struct StreamStatus
37 {
38 std::string m_ipAddress;
39 std::string m_serviceReference;
40 std::string m_channelName;
41 StreamType m_streamType;
42 };
43 } //namespace utilities
44 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://www.xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <string>
24
25 namespace enigma2
26 {
27 namespace utilities
28 {
29 struct Tuner
30 {
31 Tuner(int tunerNumber, const std::string& tunerName, const std::string& tunerModel)
32 : m_tunerNumber(tunerNumber), m_tunerName(tunerName), m_tunerModel(tunerModel){};
33
34 int m_tunerNumber;
35 std::string m_tunerName;
36 std::string m_tunerModel;
37 };
38 } //namespace utilities
39 } //namespace enigma2
0 #pragma once
1 /*
2 * Copyright (C) 2005-2019 Team XBMC
3 * http://xbmc.org
4 *
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
9 *
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with XBMC; see the file COPYING. If not, write to
17 * the Free Software Foundation, 51 Franklin Street, Fifth Floor, Boston,
18 * MA 02110-1335, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include "../data/BaseEntry.h"
24
25 #include <string>
26
27 namespace enigma2
28 {
29 namespace utilities
30 {
31 typedef enum UPDATE_STATE
32 {
33 UPDATE_STATE_NONE,
34 UPDATE_STATE_FOUND,
35 UPDATE_STATE_UPDATED,
36 UPDATE_STATE_NEW
37 } UPDATE_STATE;
38 } // namespace utilities
39 } //namespace enigma2
0 /*
1 * Copyright (C) 2005-2019 Team Kodi
2 * http://kodi.tv
3 *
4 * This Program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2, or (at your option)
7 * any later version.
8 *
9 * This Program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with XBMC; see the file COPYING. If not, write to
16 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
17 * http://www.gnu.org/copyleft/gpl.html
18 *
19 */
20
21 #include "WebUtils.h"
22
23 #include "../Settings.h"
24 #include "CurlFile.h"
25 #include "Logger.h"
26 #include "p8-platform/util/StringUtils.h"
27 #include "tinyxml.h"
28 #include "util/XMLUtils.h"
29
30 using namespace enigma2;
31 using namespace enigma2::utilities;
32
33 const char SAFE[256] =
34 {
35 /* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
36 /* 0 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
37 /* 1 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
38 /* 2 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
39 /* 3 */ 1,1,1,1, 1,1,1,1, 1,1,0,0, 0,0,0,0,
40
41 /* 4 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
42 /* 5 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
43 /* 6 */ 0,1,1,1, 1,1,1,1, 1,1,1,1, 1,1,1,1,
44 /* 7 */ 1,1,1,1, 1,1,1,1, 1,1,1,0, 0,0,0,0,
45
46 /* 8 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
47 /* 9 */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
48 /* A */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
49 /* B */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
50
51 /* C */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
52 /* D */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
53 /* E */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0,
54 /* F */ 0,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0
55 };
56
57 std::string WebUtils::URLEncodeInline(const std::string& sSrc)
58 {
59 const char DEC2HEX[16 + 1] = "0123456789ABCDEF";
60 const unsigned char* pSrc = (const unsigned char*)sSrc.c_str();
61 const int SRC_LEN = sSrc.length();
62 unsigned char* const pStart = new unsigned char[SRC_LEN * 3];
63 unsigned char* pEnd = pStart;
64 const unsigned char* const SRC_END = pSrc + SRC_LEN;
65
66 for (; pSrc < SRC_END; ++pSrc)
67 {
68 if (SAFE[*pSrc])
69 *pEnd++ = *pSrc;
70 else
71 {
72 // escape this char
73 *pEnd++ = '%';
74 *pEnd++ = DEC2HEX[*pSrc >> 4];
75 *pEnd++ = DEC2HEX[*pSrc & 0x0F];
76 }
77 }
78
79 std::string sResult((char*)pStart, (char*)pEnd);
80 delete[] pStart;
81 return sResult;
82 }
83
84 bool WebUtils::CheckHttp(const std::string& url)
85 {
86 Logger::Log(LEVEL_TRACE, "%s Check webAPI with URL: '%s'", __FUNCTION__, url.c_str());
87
88 CurlFile http;
89 if (!http.Check(url))
90 {
91 Logger::Log(LEVEL_TRACE, "%s - Could not open webAPI.", __FUNCTION__);
92 return false;
93 }
94
95 Logger::Log(LEVEL_TRACE, "%s WebAPI available", __FUNCTION__);
96
97 return true;
98 }
99
100 std::string WebUtils::GetHttp(const std::string& url)
101 {
102 Logger::Log(LEVEL_INFO, "%s Open webAPI with URL: '%s'", __FUNCTION__, url.c_str());
103
104 std::string strTmp;
105
106 CurlFile http;
107 if (!http.Get(url, strTmp))
108 {
109 Logger::Log(LEVEL_ERROR, "%s - Could not open webAPI.", __FUNCTION__);
110 return "";
111 }
112
113 Logger::Log(LEVEL_INFO, "%s Got result. Length: %u", __FUNCTION__, strTmp.length());
114
115 return strTmp;
116 }
117
118 std::string WebUtils::GetHttpXML(const std::string& url)
119 {
120 std::string strTmp = GetHttp(url);
121
122 // If there is no newline add it as it not being there will cause a parse error
123 // TODO: Remove once bug is fixed in Open WebIf
124 if (strTmp.back() != '\n')
125 strTmp += "\n";
126
127 return strTmp;
128 }
129
130 std::string WebUtils::PostHttpJson(const std::string& url)
131 {
132 Logger::Log(LEVEL_INFO, "%s Open webAPI with URL: '%s'", __FUNCTION__, url.c_str());
133
134 std::string strTmp;
135
136 CurlFile http;
137 if (!http.Post(url, strTmp))
138 {
139 Logger::Log(LEVEL_ERROR, "%s - Could not open webAPI.", __FUNCTION__);
140 return "";
141 }
142
143 // If there is no newline add it as it not being there will cause a parse error
144 // TODO: Remove once bug is fixed in Open WebIf
145 if (strTmp.back() != '\n')
146 strTmp += "\n";
147
148 Logger::Log(LEVEL_INFO, "%s Got result. Length: %u", __FUNCTION__, strTmp.length());
149
150 return strTmp;
151 }
152
153 bool WebUtils::SendSimpleCommand(const std::string& strCommandURL, std::string& strResultText, bool bIgnoreResult)
154 {
155 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), strCommandURL.c_str());
156
157 const std::string strXML = WebUtils::GetHttpXML(url);
158
159 if (!bIgnoreResult)
160 {
161
162 TiXmlDocument xmlDoc;
163 if (!xmlDoc.Parse(strXML.c_str()))
164 {
165 Logger::Log(LEVEL_ERROR, "%s Unable to parse XML: %s at line %d", __FUNCTION__, xmlDoc.ErrorDesc(), xmlDoc.ErrorRow());
166 return false;
167 }
168
169 TiXmlHandle hDoc(&xmlDoc);
170 TiXmlElement* pElem;
171 TiXmlHandle hRoot(0);
172
173 pElem = hDoc.FirstChildElement("e2simplexmlresult").Element();
174
175 if (!pElem)
176 {
177 Logger::Log(LEVEL_ERROR, "%s Could not find <e2simplexmlresult> element!", __FUNCTION__);
178 return false;
179 }
180
181 bool bTmp;
182
183 if (!XMLUtils::GetBoolean(pElem, "e2state", bTmp))
184 {
185 Logger::Log(LEVEL_ERROR, "%s Could not parse e2state from result!", __FUNCTION__);
186 strResultText = StringUtils::Format("Could not parse e2state!");
187 return false;
188 }
189
190 if (!XMLUtils::GetString(pElem, "e2statetext", strResultText))
191 {
192 Logger::Log(LEVEL_ERROR, "%s Could not parse e2state from result!", __FUNCTION__);
193 return false;
194 }
195
196 if (!bTmp)
197 Logger::Log(LEVEL_ERROR, "%s Error message from backend: '%s'", __FUNCTION__, strResultText.c_str());
198
199 return bTmp;
200 }
201 return true;
202 }
203
204 bool WebUtils::SendSimpleJsonCommand(const std::string& strCommandURL, std::string& strResultText, bool bIgnoreResult)
205 {
206 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), strCommandURL.c_str());
207
208 const std::string strJson = WebUtils::GetHttp(url);
209
210 if (!bIgnoreResult)
211 {
212 if (strJson.find("\"result\": true") != std::string::npos)
213 {
214 strResultText = "Success!";
215 }
216 else
217 {
218 strResultText = StringUtils::Format("Invalid Command");
219 Logger::Log(LEVEL_ERROR, "%s Error message from backend: '%s'", __FUNCTION__, strResultText.c_str());
220 return false;
221 }
222 }
223
224 return true;
225 }
226
227 bool WebUtils::SendSimpleJsonPostCommand(const std::string& strCommandURL, std::string& strResultText, bool bIgnoreResult)
228 {
229 const std::string url = StringUtils::Format("%s%s", Settings::GetInstance().GetConnectionURL().c_str(), strCommandURL.c_str());
230
231 const std::string strJson = WebUtils::PostHttpJson(url);
232
233 if (!bIgnoreResult)
234 {
235 if (strJson.find("\"result\": true") != std::string::npos)
236 {
237 strResultText = "Success!";
238 }
239 else
240 {
241 strResultText = StringUtils::Format("Invalid Command");
242 Logger::Log(LEVEL_ERROR, "%s Error message from backend: '%s'", __FUNCTION__, strResultText.c_str());
243 return false;
244 }
245 }
246
247 return true;
248 }
249
250 std::string& WebUtils::Escape(std::string& s, const std::string from, const std::string to)
251 {
252 std::string::size_type pos = -1;
253 while ((pos = s.find(from, pos + 1)) != std::string::npos)
254 s.erase(pos, from.length()).insert(pos, to);
255
256 return s;
257 }
0 #pragma once
1
2 /*
3 * Copyright (C) 2005-2019 Team Kodi
4 * http://kodi.tv
5 *
6 * This Program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This Program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with XBMC; see the file COPYING. If not, write to
18 * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19 * http://www.gnu.org/copyleft/gpl.html
20 *
21 */
22
23 #include <string>
24
25 namespace enigma2
26 {
27 namespace utilities
28 {
29 class WebUtils
30 {
31 public:
32 static std::string URLEncodeInline(const std::string& sStr);
33 static bool CheckHttp(const std::string& url);
34 static std::string GetHttp(const std::string& url);
35 static std::string GetHttpXML(const std::string& url);
36 static std::string PostHttpJson(const std::string& url);
37 static bool SendSimpleCommand(const std::string& strCommandURL, std::string& strResultText, bool bIgnoreResult = false);
38 static bool SendSimpleJsonCommand(const std::string& strCommandURL, std::string& strResultText, bool bIgnoreResult = false);
39 static bool SendSimpleJsonPostCommand(const std::string& strCommandURL, std::string& strResultText, bool bIgnoreResult = false);
40 static std::string& Escape(std::string& s, const std::string from, const std::string to);
41 };
42 } // namespace utilities
43 } // namespace enigma2