summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Moll <leo.moll@dtms.de>2018-01-14 22:25:12 +0100
committerMartijn Kaijser <martijn@xbmc.org>2018-01-15 18:48:50 +0100
commit144c832baedd948102c2ee0ef0c9ac5b118f8b6e (patch)
tree39995dbc3efd46dca72281c99e87a7867fa8fbbd
parente5d0f50b8d39ab7fd745b8f384ec622f6b0df5d9 (diff)
[plugin.video.mediathekview] 0.4.0
-rw-r--r--plugin.video.mediathekview/README.md164
-rw-r--r--plugin.video.mediathekview/addon.py114
-rw-r--r--plugin.video.mediathekview/addon.xml25
-rw-r--r--plugin.video.mediathekview/de/yeasoft/kodi/__init__.py0
-rw-r--r--plugin.video.mediathekview/resources/__init__.py (renamed from plugin.video.mediathekview/classes/__init__.py)0
-rw-r--r--plugin.video.mediathekview/resources/fanart.jpgbin148223 -> 178572 bytes
-rw-r--r--plugin.video.mediathekview/resources/icon.jpgbin195418 -> 0 bytes
-rw-r--r--plugin.video.mediathekview/resources/icon.pngbin0 -> 484822 bytes
-rw-r--r--plugin.video.mediathekview/resources/language/resource.language.de_de/strings.po (renamed from plugin.video.mediathekview/resources/language/German/strings.po)38
-rw-r--r--plugin.video.mediathekview/resources/language/resource.language.en_gb/strings.po (renamed from plugin.video.mediathekview/resources/language/English/strings.po)32
-rw-r--r--plugin.video.mediathekview/resources/language/resource.language.it_it/strings.po (renamed from plugin.video.mediathekview/resources/language/Italian/strings.po)32
-rw-r--r--plugin.video.mediathekview/resources/lib/__init__.py (renamed from plugin.video.mediathekview/de/__init__.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/base/Logger.py (renamed from plugin.video.mediathekview/de/yeasoft/base/Logger.py)2
-rw-r--r--plugin.video.mediathekview/resources/lib/base/__init__.py (renamed from plugin.video.mediathekview/de/yeasoft/__init__.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/channel.py (renamed from plugin.video.mediathekview/classes/channel.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/channelui.py (renamed from plugin.video.mediathekview/classes/channelui.py)11
-rw-r--r--plugin.video.mediathekview/resources/lib/exceptions.py (renamed from plugin.video.mediathekview/classes/exceptions.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/film.py (renamed from plugin.video.mediathekview/classes/film.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/filmui.py (renamed from plugin.video.mediathekview/classes/filmui.py)42
-rw-r--r--plugin.video.mediathekview/resources/lib/initialui.py (renamed from plugin.video.mediathekview/classes/initialui.py)14
-rw-r--r--plugin.video.mediathekview/resources/lib/kodi/KodiAddon.py (renamed from plugin.video.mediathekview/de/yeasoft/kodi/KodiAddon.py)16
-rw-r--r--plugin.video.mediathekview/resources/lib/kodi/KodiLogger.py (renamed from plugin.video.mediathekview/de/yeasoft/kodi/KodiLogger.py)19
-rw-r--r--plugin.video.mediathekview/resources/lib/kodi/KodiUI.py (renamed from plugin.video.mediathekview/de/yeasoft/kodi/KodiUI.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/kodi/__init__.py (renamed from plugin.video.mediathekview/de/yeasoft/base/__init__.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/mvupdate.py (renamed from plugin.video.mediathekview/classes/mvupdate.py)33
-rw-r--r--plugin.video.mediathekview/resources/lib/mvutils.py87
-rw-r--r--plugin.video.mediathekview/resources/lib/notifier.py (renamed from plugin.video.mediathekview/classes/notifier.py)9
-rw-r--r--plugin.video.mediathekview/resources/lib/settings.py (renamed from plugin.video.mediathekview/classes/settings.py)6
-rw-r--r--plugin.video.mediathekview/resources/lib/show.py (renamed from plugin.video.mediathekview/classes/show.py)0
-rw-r--r--plugin.video.mediathekview/resources/lib/showui.py (renamed from plugin.video.mediathekview/classes/showui.py)7
-rw-r--r--plugin.video.mediathekview/resources/lib/store.py (renamed from plugin.video.mediathekview/classes/store.py)11
-rw-r--r--plugin.video.mediathekview/resources/lib/storemysql.py (renamed from plugin.video.mediathekview/classes/storemysql.py)471
-rw-r--r--plugin.video.mediathekview/resources/lib/storesqlite.py (renamed from plugin.video.mediathekview/classes/storesqlite.py)129
-rw-r--r--plugin.video.mediathekview/resources/lib/ttml2srt.py (renamed from plugin.video.mediathekview/classes/ttml2srt.py)9
-rw-r--r--plugin.video.mediathekview/resources/lib/updater.py (renamed from plugin.video.mediathekview/classes/updater.py)269
-rw-r--r--plugin.video.mediathekview/resources/settings.xml20
-rwxr-xr-xplugin.video.mediathekview/resources/sql/exportstruct.sh3
-rw-r--r--plugin.video.mediathekview/resources/sql/filmliste-mysql-v1.sql454
-rw-r--r--plugin.video.mediathekview/resources/sql/filmliste-sqlite-v1.sql104
-rw-r--r--plugin.video.mediathekview/service.py26
40 files changed, 1023 insertions, 1124 deletions
diff --git a/plugin.video.mediathekview/README.md b/plugin.video.mediathekview/README.md
index b356e84..485d456 100644
--- a/plugin.video.mediathekview/README.md
+++ b/plugin.video.mediathekview/README.md
@@ -64,25 +64,16 @@ dies bedeutet, dass eine lokale SQLite-Datenbank benutzt wird, die auch
durch das Kodi-System lokal aktualisiert wird. Dies dürfte auch das
üblichste Szenario sein.
-Dieses Szenario birgt zwei Voraussetzungen die erfüllt sein sollten:
-* ein einigermaßen performantes Dateisystem für die Datenbank. Ein Raspberry
- mit seiner langsamen SD-Karte ist in diesem Fall sicherlich nicht die
- allerbeste Wahl. Das vollständige Update der Datenbank dauert hier um die
- 15-20 Minuten. Da dies aber im Hintergrund passiert, kann man unter Umständen
- gut damit leben.
-* der Entpacker 'xz' auf dem Kodi-System. Um den Datenbank-Aktualisierer zu
- benutzen, muss dieses Programm auf dem System in einem der Standard-
- Verzeichnisse (/bin, /usr/bin, /usr/local/bin) installiert werden.
- Unter Windows bzw. falls das Programm in einem anderen Verzeichnis
- installiert ist, muss der Pfad zum Programm in den Addon-Einstellungen
- angegeben werden. Sollte der Entpacker nicht vorhanden sein, so gibt
- das Addon eine Meldung aus und deaktiviert den Aktualisierungsprozess.
-
-Das Addon wurde auf verschiedenen Plattformen unter Linux, MacOS und LibreELEC
-bzw. OpenELEC getestet. Dort war auch der entsprechende Entpacker verfügbar.
-Unter Windows muss der Entpacker nachträglich installiert werden und dessen
-Pfad in den Addon-Einstellungen angegeben werden. Mangels Testsystem konnte
-dies jedoch zum jetzigen Zeitpunkt noch nicht getestet werden.
+Die Benutzung der lokalen Datenbank erfordert im Idealfall ein einigermaßen
+performantes Dateisystem. Ein Raspberry mit seiner langsamen SD-Karte ist in
+diesem Fall sicherlich nicht die allerbeste Wahl. Das vollständige Update der
+Datenbank dauert auf einem solchen System erfahrungsgemäß um die 15-20 Minuten.
+Da dies aber im Hintergrund passiert, kann man unter Umständen gut damit leben.
+
+Das Addon wurde auf verschiedenen Plattformen unter Linux, MacOS, Windows und
+LibreELEC bzw. OpenELEC getestet. Auch verschiedene Android Systeme konnten
+schon erfolgreich getestet werden. Wegen der Vielzahl der Plattformen ist es
+allerdings nicht möglich eine abschließende Kompatibilitätsaussage zu machen.
Alternativ-Konfigurationen
@@ -95,11 +86,13 @@ Datenbank (MySQL) zu nutzen.
Da viele Kodi-Nutzer über ein eigenes NAS-System verfügen um ihre Medien
dem Media-Center zur Verfügung zu stellen, eignet sich dieses in der Regel
-auch als MySQL Datenbank-Server da nahezu alle NAS-Betriebssysteme die
-Installation eines solchen anbieten.
+auch als MySQL bzw. MariaDB Datenbank-Server da nahezu alle NAS-Betriebssysteme
+die Installation eines solchen anbieten.
-Hierfür muss lediglich die entsprechende Datenbank im MySQL Server mit
-dem SQL-Skript `resources/sql/filmliste-mysql-v1.sql` erzeugt werden.
+Ist das Addon so konfiguriert, dass eine MySQL/MariaDB Datenbank genutzt werden
+soll, erzeugt dieses die Datenbank selbsttätig, falls diese auf dem
+Datenbankserver noch nicht existiert. Der angegebene Datenabankbenutzer muss
+dafür allerdings auch die Rechte besitzen.
Die Verbindung zur Datenbank kann in den Addon-Einstellungen im Abschnitt
_"Datenbank Einstellungen"_ vorgenommen werden.
@@ -117,7 +110,7 @@ Standalone Datenbank Update Prozess
Um die Datenbankaktualisierung von der Kommandozeile auszuführen, muss das
Zielsystem einen python2-Interpreter bereitstellen. Des weiteren müssen noch
folgende zwei Bibliotheken zur Verfügung stehen, sowie das Entpackprogramm
-'xz':
+'xz' (optional):
* ijson
* mysql-connector
@@ -145,19 +138,18 @@ das Programm spezifische Hilfe aus. Beispiel:
````
leo@bookpoldo ~/plugin.video.mediathekview $ ./mvupdate mysql -h
-usage: mvupdate mysql [-h] [-H HOST] [-u USER] [-p PASSWORD] [-d DATABASE]
+usage: mvupdate mysql [-h] [-H HOST] [-P PORT] [-u USER] [-p PASSWORD]
+ [-d DATABASE]
optional arguments:
-h, --help show this help message and exit
- -H HOST, --host HOST hostname or ip of the MySQL server (default:
- localhost)
- -u USER, --user USER username for the MySQL server connection (default:
- filmliste)
+ -H HOST, --host HOST hostname or ip address (default: localhost)
+ -P PORT, --port PORT connection port (default: 3306)
+ -u USER, --user USER connection username (default: mediathekview)
-p PASSWORD, --password PASSWORD
- password for the MySQL server connection (default:
- None)
+ connection password (default: None)
-d DATABASE, --database DATABASE
- MySQL database for mediathekview (default: filmliste)
+ database name (default: mediathekview)
````
@@ -216,22 +208,16 @@ After installation, the addon starts in local mode: this means that a local
SQLite database is used, which is also updated locally by the Kodi system.
This is probably the most common scenario.
-* a file system with a decent performance for the database. A Raspberry with
- its slow SD card is certainly not the very best choice in this case but still
- acceptable. The full update will take in this case about 15-20 Minutes but
- since this happens in the background, you may be able to live with it.
-* The unpacker 'xz' on the Kodi system. To use the database updater, this
- program must be installed on the system in one of the standard directories
- (/bin, /usr/bin, /usr/local/bin). Under Windows or if the program is
- installed in a different directory, the path to the program must be specified
- in the addon settings. If the unpacker is not available on the target system,
- the addon issues a message and disables the update process.
+Ideally, using the local database requires a file system with a decent
+performance. A Raspberry with a slow SD card is certainly not the very
+best choice in this case but still acceptable. The full update will take
+in this case about 15-20 Minutes but since this happens in the background,
+you may be able to live with it.
-The addon has been tested on different platforms under Linux, MacOS and
-LibreELEC/OpenELEC. The corresponding unpacker was also available there.
-Under Windows, the unpacker must be manually installed and its path must
-be specified in the addon settings. Due to the lack of a test system,
-however, this could not be tested at the present time.
+The addon has been tested on different platforms under Linux, MacOS,
+Windows and LibreELEC/OpenELEC. Various Android systems have also been
+tested successfully. Due to the variety of platforms, however, it is not
+possible to make a final compatibility statement.
Alternate Configurations
@@ -242,8 +228,13 @@ with a very slow SD card) or if the program 'xz' is missing, it is also
possible to use the addon with an external database (MySQL).
Since many Kodi users have their own NAS system to make their media available
-to the media center, this is usually also suitable as a MySQL database server
-since almost all NAS operating systems offer the installation of MySQL.
+to the media center, this is usually also suitable as a MySQL/MariaDB database
+server since almost all NAS operating systems offer the installation of MySQL.
+
+If the addon is configured to use a MySQL/MariaDB database, the database is
+created automatically if it does not yet exist on the database server. However,
+the specified database user must also have sufficient user rights in order to
+do this.
When you have a running MySQL server avaible, you have only to create the
database by running the SQL script `resources/sql/filmliste-mysql-v1.sql`.
@@ -289,19 +280,18 @@ the application shows specific help instructions:
````
leo@bookpoldo ~/plugin.video.mediathekview $ ./mvupdate mysql -h
-usage: mvupdate mysql [-h] [-H HOST] [-u USER] [-p PASSWORD] [-d DATABASE]
+usage: mvupdate mysql [-h] [-H HOST] [-P PORT] [-u USER] [-p PASSWORD]
+ [-d DATABASE]
optional arguments:
-h, --help show this help message and exit
- -H HOST, --host HOST hostname or ip of the MySQL server (default:
- localhost)
- -u USER, --user USER username for the MySQL server connection (default:
- filmliste)
+ -H HOST, --host HOST hostname or ip address (default: localhost)
+ -P PORT, --port PORT connection port (default: 3306)
+ -u USER, --user USER connection username (default: mediathekview)
-p PASSWORD, --password PASSWORD
- password for the MySQL server connection (default:
- None)
+ connection password (default: None)
-d DATABASE, --database DATABASE
- MySQL database for mediathekview (default: filmliste)
+ database name (default: mediathekview)
````
@@ -344,25 +334,22 @@ Come funziona
L'addon scarica il database da MediathekView e lo importa in un database SQLite
locale o, in alternativa, in un database MySQL locale o remoto (per l'uso da
-parte di più client Kodi).
-Durante il runtime di Kodi, i file differenziali vengono scaricati da
-MediathekView in un intervallo configurabile (predefinito: 2 ore) ed importati
-nel database. Al più tardi entro il giorno successivo all'ultimo aggiornamento,
-l'aggiornamento sarà nuovamente effettuato tramite l'aggiornamento completo
-di Mediathekview.
-
-* Un file system con prestazioni accettabili per il database. Un Raspberry con
- la sua lenta scheda SD non è certamente la miglior scelta ma sempre ancora
- accettabile. La durata di un aggiornamento completo in questo caso sarà
- intorno ai 15-20 minuti. Ma poiché questo accade in background, l'impatto
- sarà essere accetabile.
-* Il decompressore 'xz' sul sistema Kodi. Per utilizzare il programma di
- aggiornamento del database, questo programma deve essere installato sul
- sistema in una delle directory standard (/bin, /usr/bin, /usr/local/bin). In
- Windows o se il programma è installato in una directory diversa, il percorso
- del programma deve essere specificato nelle impostazioni dell'addon. Se il
- decompressore non è disponibile per il sistema, l'addon mostra un messaggio
- e disabilita il processo di aggiornamento.
+parte di molteplici sistemi Kodi). Durante il runtime di Kodi, i file di
+aggiornamento differenziali vengono scaricati da MediathekView in un intervallo
+configurabile (predefinito: 2 ore) ed importati nel database. Al più tardi
+entro il giorno successivo all'ultimo aggiornamento, l'aggiornamento sarà
+nuovamente effettuato tramite l'aggiornamento completo di Mediathekview.
+
+Idealmente, l'utilizzo del database locale richiede un file system con
+prestazioni accettabili. Un Raspberry di prima generazione con una scheda SD
+lenta non è certamente la miglior scelta ma sempre ancora accettabile. La
+durata di un aggiornamento completo in questo caso sarà intorno ai 15-20
+minuti. Ma poiché questo accade in background, l'impatto sarà accetabile.
+
+L'addon è stato testato su diverse piattaforme in Linux, MacOS, Windows e
+LibreELEC nonchè OpenELEC. Anche diversi sistemi Android sono stati testati
+con successo. A causa della varietà delle piattaforme, tuttavia, non è
+possibile fare una dichiarazione finale di compatibilità.
Configurazioni alternative
@@ -374,11 +361,13 @@ Raspberry PI con una scheda SD molto lenta) o se manca il programma 'xz',
Dal momento che molti utenti Kodi hanno il proprio sistema NAS per rendere i
loro contenuti mediali disponibili al media center, questo è di solito anche
-adatto come server di database MySQL, dal momento che quasi tutti i sistemi
-operativi NAS offrono l'installazione di un tale database.
+adatto come server di database MySQL/MariaDB, dal momento che quasi tutti i
+sistemi operativi NAS offrono l'installazione di un tale database.
-Dopodiche sarà sufficiente creare la banca dati mediante lo script SQL
-disponibile in `resources/sql/filmliste-mysql-v1.sql`.
+Se l' addon è configurato per utilizzare un database MySQL/MariaDB, il database
+verrà creato automaticamente se non esiste ancora sul database server.
+Tuttavia, anche l'utente del database specificato deve avere i diritti
+necessari.
Il collegamento al database può essere effettuato nelle impostazioni
dell'addon nella sezione "Impostazioni Banca Dati".
@@ -423,17 +412,16 @@ aggiornare, l'applicazione mostrerà le opzioni disponibili:
````
leo@bookpoldo ~/plugin.video.mediathekview $ ./mvupdate mysql -h
-usage: mvupdate mysql [-h] [-H HOST] [-u USER] [-p PASSWORD] [-d DATABASE]
+usage: mvupdate mysql [-h] [-H HOST] [-P PORT] [-u USER] [-p PASSWORD]
+ [-d DATABASE]
optional arguments:
-h, --help show this help message and exit
- -H HOST, --host HOST hostname or ip of the MySQL server (default:
- localhost)
- -u USER, --user USER username for the MySQL server connection (default:
- filmliste)
+ -H HOST, --host HOST hostname or ip address (default: localhost)
+ -P PORT, --port PORT connection port (default: 3306)
+ -u USER, --user USER connection username (default: mediathekview)
-p PASSWORD, --password PASSWORD
- password for the MySQL server connection (default:
- None)
+ connection password (default: None)
-d DATABASE, --database DATABASE
- MySQL database for mediathekview (default: filmliste)
+ database name (default: mediathekview)
````
diff --git a/plugin.video.mediathekview/addon.py b/plugin.video.mediathekview/addon.py
index 0c10b29..64e925d 100644
--- a/plugin.video.mediathekview/addon.py
+++ b/plugin.video.mediathekview/addon.py
@@ -27,21 +27,22 @@ from __future__ import unicode_literals # ,absolute_import, division
# from future import standard_library
# from builtins import *
# standard_library.install_aliases()
-import io,os,re,sys,urlparse,datetime,string,urllib,urllib2
-import xbmc,xbmcplugin,xbmcgui,xbmcaddon,xbmcvfs
+import os,re,sys,urlparse,datetime
+import xbmcplugin,xbmcgui,xbmcvfs
-from de.yeasoft.kodi.KodiAddon import KodiPlugin
-from de.yeasoft.kodi.KodiUI import KodiBGDialog
+from contextlib import closing
-from classes.store import Store
-from classes.notifier import Notifier
-from classes.settings import Settings
-from classes.filmui import FilmUI
-from classes.channelui import ChannelUI
-from classes.initialui import InitialUI
-from classes.showui import ShowUI
-from classes.updater import MediathekViewUpdater
-from classes.ttml2srt import ttml2srt
+from resources.lib.kodi.KodiAddon import KodiPlugin
+from resources.lib.kodi.KodiUI import KodiBGDialog
+
+from resources.lib.store import Store
+from resources.lib.notifier import Notifier
+from resources.lib.settings import Settings
+from resources.lib.filmui import FilmUI
+from resources.lib.channelui import ChannelUI
+from resources.lib.initialui import InitialUI
+from resources.lib.showui import ShowUI
+from resources.lib.ttml2srt import ttml2srt
# -- Classes ------------------------------------------------
class MediathekView( KodiPlugin ):
@@ -52,9 +53,6 @@ class MediathekView( KodiPlugin ):
self.notifier = Notifier()
self.db = Store( self.getNewLogger( 'Store' ), self.notifier, self.settings )
- def __del__( self ):
- del self.db
-
def showMainMenu( self ):
# Search
self.addFolderItem( 30901, { 'mode': "search" } )
@@ -79,6 +77,7 @@ class MediathekView( KodiPlugin ):
if len( searchText ) > 2:
self.db.Search( searchText, FilmUI( self ) )
else:
+ self.info( 'The following ERROR can be ignored. It is caused by the architecture of the Kodi Plugin Engine' )
self.endOfDirectory( False, cacheToDisc = True )
# self.showMainMenu()
@@ -87,6 +86,7 @@ class MediathekView( KodiPlugin ):
if len( searchText ) > 2:
self.db.SearchFull( searchText, FilmUI( self ) )
else:
+ self.info( 'The following ERROR can be ignored. It is caused by the architecture of the Kodi Plugin Engine' )
self.endOfDirectory( False, cacheToDisc = True )
# self.showMainMenu()
@@ -176,8 +176,8 @@ class MediathekView( KodiPlugin ):
videourl = film.url_video
# prepare names
- showname = self._cleanup_filename( film.show )[:64]
- filestem = self._cleanup_filename( film.title )[:64]
+ showname = mvutils.cleanup_filename( film.show )[:64]
+ filestem = mvutils.cleanup_filename( film.title )[:64]
extension = os.path.splitext( videourl )[1]
if not extension:
extension = u'.mp4'
@@ -211,7 +211,7 @@ class MediathekView( KodiPlugin ):
bgd.Create( self.language( 30974 ), fileepi + extension )
try:
bgd.Update( 0 )
- result = self._url_retrieve( videourl, movname, bgd.UrlRetrieveHook )
+ result = mvutils.url_retrieve_vfs( videourl, movname, bgd.UrlRetrieveHook )
bgd.Close()
if result is not None:
self.notifier.ShowNotification( self.language( 30960 ), self.language( 30976 ).format( videourl ) )
@@ -226,7 +226,7 @@ class MediathekView( KodiPlugin ):
bgd.Create( self.language( 30978 ), fileepi + u'.ttml' )
try:
bgd.Update( 0 )
- result = self._url_retrieve( film.url_sub, ttmname, bgd.UrlRetrieveHook )
+ result = mvutils.url_retrieve_vfs( film.url_sub, ttmname, bgd.UrlRetrieveHook )
try:
ttml2srt( xbmcvfs.File( ttmname, 'r' ), xbmcvfs.File( srtname, 'w' ) )
except Exception as err:
@@ -244,74 +244,43 @@ class MediathekView( KodiPlugin ):
def doEnqueueFilm( self, filmid ):
self.info( 'Enqueue {}', filmid )
- def _cleanup_filename( self, val ):
- cset = string.letters + string.digits + u' _-#äöüÄÖÜßáàâéèêíìîóòôúùûÁÀÉÈÍÌÓÒÚÙçÇœ'
- search = ''.join( [ c for c in val if c in cset ] )
- return search.strip()
-
def _make_nfo_files( self, film, episode, dirname, filename, videourl ):
# create NFO files
if not xbmcvfs.exists( dirname + 'tvshow.nfo' ):
try:
- file = xbmcvfs.File( dirname + 'tvshow.nfo', 'w' )
- file.write( bytearray( '<tvshow>\n', 'utf-8' ) )
- file.write( bytearray( '<id></id>\n', 'utf-8' ) )
- file.write( bytearray( '\t<title>{}</title>\n'.format( film.show ), 'utf-8' ) )
- file.write( bytearray( '\t<sorttitle>{}</sorttitle>\n'.format( film.show ), 'utf-8' ) )
-# file.write( bytearray( '\t<year>{}</year>\n'.format( 2018 ), 'utf-8' ) ) # XXX TODO: That might be incorrect!
- file.write( bytearray( '\t<studio>{}</studio>\n'.format( film.channel ), 'utf-8' ) )
- file.write( bytearray( '</tvshow>\n', 'utf-8' ) )
- file.close()
+ with closing( xbmcvfs.File( dirname + 'tvshow.nfo', 'w' ) ) as file:
+ file.write( b'<tvshow>\n' )
+ file.write( b'<id></id>\n' )
+ file.write( bytearray( '\t<title>{}</title>\n'.format( film.show ), 'utf-8' ) )
+ file.write( bytearray( '\t<sorttitle>{}</sorttitle>\n'.format( film.show ), 'utf-8' ) )
+# TODO: file.write( bytearray( '\t<year>{}</year>\n'.format( 2018 ), 'utf-8' ) )
+ file.write( bytearray( '\t<studio>{}</studio>\n'.format( film.channel ), 'utf-8' ) )
+ file.write( b'</tvshow>\n' )
except Exception as err:
self.error( 'Failure creating show NFO file for {}: {}', videourl, err )
try:
- file = xbmcvfs.File( filename, 'w' )
- file.write( bytearray( '<episodedetails>\n', 'utf-8' ) )
- file.write( bytearray( '\t<title>{}</title>\n'.format( film.title ), 'utf-8' ) )
- file.write( bytearray( '\t<season>1</season>\n', 'utf-8' ) )
- file.write( bytearray( '\t<episode>{}</episode>\n'.format( episode ), 'utf-8' ) )
- file.write( bytearray( '\t<showtitle>{}</showtitle>\n'.format( film.show ), 'utf-8' ) )
- file.write( bytearray( '\t<plot>{}</plot>\n'.format( film.description ), 'utf-8' ) )
- file.write( bytearray( '\t<aired>{}</aired>\n'.format( film.aired ), 'utf-8' ) )
- if film.seconds > 60:
- file.write( bytearray( '\t<runtime>{}</runtime>\n'.format( int( film.seconds / 60 ) ), 'utf-8' ) )
- file.write( bytearray( '\t<studio>{}</studio\n'.format( film.channel ), 'utf-8' ) )
- file.write( bytearray( '</episodedetails>\n', 'utf-8' ) )
- file.close()
+ with closing( xbmcvfs.File( filename, 'w' ) ) as file:
+ file.write( b'<episodedetails>\n' )
+ file.write( bytearray( '\t<title>{}</title>\n'.format( film.title ), 'utf-8' ) )
+ file.write( b'\t<season>1</season>\n' )
+ file.write( bytearray( '\t<episode>{}</episode>\n'.format( episode ), 'utf-8' ) )
+ file.write( bytearray( '\t<showtitle>{}</showtitle>\n'.format( film.show ), 'utf-8' ) )
+ file.write( bytearray( '\t<plot>{}</plot>\n'.format( film.description ), 'utf-8' ) )
+ file.write( bytearray( '\t<aired>{}</aired>\n'.format( film.aired ), 'utf-8' ) )
+ if film.seconds > 60:
+ file.write( bytearray( '\t<runtime>{}</runtime>\n'.format( int( film.seconds / 60 ) ), 'utf-8' ) )
+ file.write( bytearray( '\t<studio>{}</studio\n'.format( film.channel ), 'utf-8' ) )
+ file.write( b'</episodedetails>\n' )
except Exception as err:
self.error( 'Failure creating episode NFO file for {}: {}', videourl, err )
- def _url_retrieve( self, videourl, filename, reporthook, chunk_size = 8192 ):
- f = xbmcvfs.File( filename, 'wb' )
- u = urllib2.urlopen( videourl )
-
- total_size = int( u.info().getheader( 'Content-Length' ).strip() ) if u.info() and u.info().getheader( 'Content-Length' ) else 0
- total_chunks = 0
-
- while True:
- reporthook( total_chunks, chunk_size, total_size )
- chunk = u.read( chunk_size )
- if not chunk:
- break
- f.write( chunk )
- total_chunks += 1
- f.close()
- return ( filename, [], )
-
def Init( self ):
self.args = urlparse.parse_qs( sys.argv[2][1:] )
self.db.Init()
if self.settings.HandleFirstRun():
# TODO: Implement Issue #16
pass
- if MediathekViewUpdater( self.getNewLogger( 'Updater' ), self.notifier, self.settings ).PrerequisitesMissing():
- self.setSetting( 'updenabled', 'false' )
- self.settings.Reload()
- xbmcgui.Dialog().textviewer(
- self.language( 30963 ),
- self.language( 30964 )
- )
def Do( self ):
mode = self.args.get( 'mode', None )
@@ -327,7 +296,7 @@ class MediathekView( KodiPlugin ):
channel = self.args.get( 'channel', [0] )
self.db.GetRecents( channel[0], FilmUI( self ) )
elif mode[0] == 'recentchannels':
- self.db.GetRecentChannels( ChannelUI( self.addon_handle, next = 'recent' ) )
+ self.db.GetRecentChannels( ChannelUI( self.addon_handle, nextdir = 'recent' ) )
elif mode[0] == 'channels':
self.db.GetChannels( ChannelUI( self.addon_handle ) )
elif mode[0] == 'action-dbinfo':
@@ -352,6 +321,7 @@ class MediathekView( KodiPlugin ):
def Exit( self ):
self.db.Exit()
+
# -- Main Code ----------------------------------------------
if __name__ == '__main__':
addon = MediathekView()
diff --git a/plugin.video.mediathekview/addon.xml b/plugin.video.mediathekview/addon.xml
index 864bce7..596fe4b 100644
--- a/plugin.video.mediathekview/addon.xml
+++ b/plugin.video.mediathekview/addon.xml
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="plugin.video.mediathekview"
name="MediathekView"
- version="0.3.4"
+ version="0.4.0"
provider-name="MediathekView.de, Leo Moll">
<requires>
<import addon="xbmc.python" version="2.25.0"/>
@@ -19,13 +19,20 @@
library="service.py"
start="startup" />
<extension point="xbmc.addon.metadata">
- <summary lang="de">Öffentlich-Rechtliche Mediatheken</summary>
- <summary lang="en">Public service video-platforms</summary>
- <summary lang="it">Piattaforme video dalle emittenti pubbliche</summary>
- <description lang="de">Ermöglicht den Zugriff auf fast alle deutschen Mediatheken der öffentlich Rechtlichen basierend auf der Datenbank von MediathekView.de</description>
- <description lang="en">Gives access to most video-platforms from German public service broadcasters using the database of MediathekView.de</description>
- <description lang="it">Fornisce l'accesso a gran parte delle piattaforme video operate dalle emittenti pubbliche tedesche usando la banca dati di MediathekView.de</description>
- <news>v0.3.4 (2018-01-11):
+ <summary lang="de_DE">Öffentlich-Rechtliche Mediatheken</summary>
+ <summary lang="en_GB">Public service video-platforms</summary>
+ <summary lang="it_IT">Piattaforme video dalle emittenti pubbliche</summary>
+ <description lang="de_DE">Ermöglicht den Zugriff auf fast alle deutschen Mediatheken der öffentlich Rechtlichen basierend auf der Datenbank von MediathekView.de</description>
+ <description lang="en_GB">Gives access to most video-platforms from German public service broadcasters using the database of MediathekView.de</description>
+ <description lang="it_IT">Fornisce l'accesso a gran parte delle piattaforme video operate dalle emittenti pubbliche tedesche usando la banca dati di MediathekView.de</description>
+ <news>v0.4.0 (2018-01-14):
+- Android und Windows Kompatibilität da kein externer Entpacker mehr benötigt wird
+- Der Datenbanktreiber für MySQL kann nun die Datenbank selbsttätig anlegen
+- Im Datenbanktreiber für MySQL kann nun auch die Portnummer angegeben werden
+- Konfigurierbare Begrenzung der Suchergebnisse
+v0.3.5 (2018-01-11):
+- Anpassungen an die Kodi-Addon Regeln
+v0.3.4 (2018-01-11):
- Die Suche sucht nun auch im Sendungs-Name
- "Vor Kurzem hinzugefügt" nach Sendern durchsuchen
- Deutsche und Italienische Übersetzung funktionieren nun
@@ -53,7 +60,7 @@ v0.3.0 (2018-01-07):
<website>https://mediathekview.de/</website>
<email>info@mediathekview.de</email>
<assets>
- <icon>resources/icon.jpg</icon>
+ <icon>resources/icon.png</icon>
<fanart>resources/fanart.jpg</fanart>
<screenshot>resources/screenshot1.png</screenshot>
<screenshot>resources/screenshot2.png</screenshot>
diff --git a/plugin.video.mediathekview/de/yeasoft/kodi/__init__.py b/plugin.video.mediathekview/de/yeasoft/kodi/__init__.py
deleted file mode 100644
index e69de29..0000000
--- a/plugin.video.mediathekview/de/yeasoft/kodi/__init__.py
+++ /dev/null
diff --git a/plugin.video.mediathekview/classes/__init__.py b/plugin.video.mediathekview/resources/__init__.py
index e69de29..e69de29 100644
--- a/plugin.video.mediathekview/classes/__init__.py
+++ b/plugin.video.mediathekview/resources/__init__.py
diff --git a/plugin.video.mediathekview/resources/fanart.jpg b/plugin.video.mediathekview/resources/fanart.jpg
index 4d9bd9d..bc54726 100644
--- a/plugin.video.mediathekview/resources/fanart.jpg
+++ b/plugin.video.mediathekview/resources/fanart.jpg
Binary files differ
diff --git a/plugin.video.mediathekview/resources/icon.jpg b/plugin.video.mediathekview/resources/icon.jpg
deleted file mode 100644
index 79073be..0000000
--- a/plugin.video.mediathekview/resources/icon.jpg
+++ /dev/null
Binary files differ
diff --git a/plugin.video.mediathekview/resources/icon.png b/plugin.video.mediathekview/resources/icon.png
new file mode 100644
index 0000000..75403fe
--- /dev/null
+++ b/plugin.video.mediathekview/resources/icon.png
Binary files differ
diff --git a/plugin.video.mediathekview/resources/language/German/strings.po b/plugin.video.mediathekview/resources/language/resource.language.de_de/strings.po
index c6da721..d3832b3 100644
--- a/plugin.video.mediathekview/resources/language/German/strings.po
+++ b/plugin.video.mediathekview/resources/language/resource.language.de_de/strings.po
@@ -44,6 +44,10 @@ msgstr "Sendungen verschiedener Sender zusammenfassen"
msgctxt "#30114"
msgid "Download directory"
+msgstr "Suchergebnisse eingrenzen"
+
+msgctxt "#30115"
+msgid "Download directory"
msgstr "Download-Verzeichnis"
# Settings Page 2
@@ -56,14 +60,18 @@ msgid "Database hostname"
msgstr "Datenbank Hostname"
msgctxt "#30212"
+msgid "Database port"
+msgstr "Datenbank Portnummer"
+
+msgctxt "#30213"
msgid "Database username"
msgstr "Datenbank Benutzername"
-msgctxt "#30213"
+msgctxt "#30214"
msgid "Database password"
msgstr "Datenbank Passwort"
-msgctxt "#30214"
+msgctxt "#30215"
msgid "Database name"
msgstr "Datenbank Name"
@@ -83,14 +91,6 @@ msgctxt "#30232"
msgid "Update interval in hours"
msgstr "Aktualisierungsintervall in Stunden"
-msgctxt "#30233"
-msgid "XZ Program Location"
-msgstr "XZ Programm"
-
-msgctxt "#30238"
-msgid "Reset Database"
-msgstr "Datenbank zurücksetzen"
-
# Main Menu
msgctxt "#30901"
msgid "Search in Title"
@@ -131,11 +131,11 @@ msgstr "Video herunterladen"
msgctxt "#30922"
msgid "Download LoRes Video"
-msgstr "Niedrig auflösendes Video herunterladen"
+msgstr "SD Video herunterladen"
msgctxt "#30923"
msgid "Download HD Video"
-msgstr "Hoch auflösendes Video herunterladen"
+msgstr "HD Video herunterladen"
msgctxt "#30924"
msgid "Add to queue"
@@ -220,8 +220,8 @@ msgstr "Dieses Kodi Addon Ermöglicht den Zugriff auf fast alle deutschen Mediat
"Spende zu hinterlassen."
msgctxt "#30963"
-msgid "XZ Decompressor is Missing"
-msgstr "Entpacker XZ nicht gefunden"
+msgid "No Decompressor Available"
+msgstr "Kein Entpacker Verfügbar"
msgctxt "#30964"
msgid "The database updater needs the program 'xz' in order to process the database update files. "
@@ -279,7 +279,7 @@ msgstr "Differentielle Aktualisierung"
msgctxt "#30974"
msgid "Downloading Video"
-msgstr "Video wird herunterladen"
+msgstr "Video wird heruntergeladen"
msgctxt "#30975"
msgid "Error while downloading {}: {}"
@@ -300,3 +300,11 @@ msgstr "Untertitel werden heruntergeladen"
msgctxt "#30979"
msgid "Download path does not exist"
msgstr "Download-Verzeichnis existiert nicht"
+
+msgctxt "#30980"
+msgid "Results Limited"
+msgstr "Ergebnisse Beschränkt"
+
+msgctxt "#30981"
+msgid "Only the first {} results are shown."
+msgstr "Es werden nur die ersten {} Ergebnisse angezeigt."
diff --git a/plugin.video.mediathekview/resources/language/English/strings.po b/plugin.video.mediathekview/resources/language/resource.language.en_gb/strings.po
index e4c3cf5..5c121e8 100644
--- a/plugin.video.mediathekview/resources/language/English/strings.po
+++ b/plugin.video.mediathekview/resources/language/resource.language.en_gb/strings.po
@@ -43,6 +43,10 @@ msgid "Group shows of different channel"
msgstr "Group shows of different channel"
msgctxt "#30114"
+msgid "Limit search results"
+msgstr "Limit search results"
+
+msgctxt "#30115"
msgid "Download directory"
msgstr "Download directory"
@@ -56,14 +60,18 @@ msgid "Database hostname"
msgstr "Database hostname"
msgctxt "#30212"
+msgid "Database port"
+msgstr "Database port"
+
+msgctxt "#30213"
msgid "Database username"
msgstr "Database username"
-msgctxt "#30213"
+msgctxt "#30214"
msgid "Database password"
msgstr "Database password"
-msgctxt "#30214"
+msgctxt "#30215"
msgid "Database name"
msgstr "Database name"
@@ -83,14 +91,6 @@ msgctxt "#30232"
msgid "Update interval in hours"
msgstr "Update interval in hours"
-msgctxt "#30233"
-msgid "XZ Program Location"
-msgstr "XZ Program Location"
-
-msgctxt "#30238"
-msgid "Reset Database"
-msgstr "Reset Database"
-
# Main Menu
msgctxt "#30901"
msgid "Search in Title"
@@ -220,8 +220,8 @@ msgstr "This Kodi addon allows access to most video-platforms from German public
"Please consider donating to this great project! Visit MediathekView at https://mediathekview.de/"
msgctxt "#30963"
-msgid "XZ Decompressor is Missing"
-msgstr "XZ Decompressor is Missing"
+msgid "No Decompressor Available"
+msgstr "No Decompressor Available"
msgctxt "#30964"
msgid "The database updater needs the program 'xz' in order to process the database update files. "
@@ -298,3 +298,11 @@ msgstr "Downloading Subtitles"
msgctxt "#30979"
msgid "Download path does not exist"
msgstr "Download path does not exist"
+
+msgctxt "#30980"
+msgid "Results Limited"
+msgstr "Results Limited"
+
+msgctxt "#30981"
+msgid "Only the first {} results are shown."
+msgstr "Only the first {} results are shown."
diff --git a/plugin.video.mediathekview/resources/language/Italian/strings.po b/plugin.video.mediathekview/resources/language/resource.language.it_it/strings.po
index aadc963..f0d9027 100644
--- a/plugin.video.mediathekview/resources/language/Italian/strings.po
+++ b/plugin.video.mediathekview/resources/language/resource.language.it_it/strings.po
@@ -43,6 +43,10 @@ msgid "Group shows of different channel"
msgstr "Raggruppa trasmissioni su canali diversi"
msgctxt "#30114"
+msgid "Limit search results"
+msgstr "Limita risultati ricerche"
+
+msgctxt "#30115"
msgid "Download directory"
msgstr "Directory di download"
@@ -56,6 +60,10 @@ msgid "Database hostname"
msgstr "Hostname banca dati"
msgctxt "#30212"
+msgid "Database port"
+msgstr "Numero port banca dati"
+
+msgctxt "#30213"
msgid "Database username"
msgstr "Nome utente"
@@ -83,14 +91,6 @@ msgctxt "#30232"
msgid "Update interval in hours"
msgstr "Intervallo di attualizzazione in ore"
-msgctxt "#30233"
-msgid "XZ Program Location"
-msgstr "Programma XZ"
-
-msgctxt "#30238"
-msgid "Reset Database"
-msgstr "Ripristina Database"
-
# Main Menu
msgctxt "#30901"
msgid "Search in Title"
@@ -131,11 +131,11 @@ msgstr "Scarica video"
msgctxt "#30922"
msgid "Download LoRes Video"
-msgstr "Scarica video bassa risoluzione"
+msgstr "Scarica video SD"
msgctxt "#30923"
msgid "Download HD Video"
-msgstr "Scarica video alta risoluzione"
+msgstr "Scarica video HD"
msgctxt "#30924"
msgid "Add to queue"
@@ -221,8 +221,8 @@ msgstr "Questo addon di Kodi permette l'accesso a gran parte delle piattaforme v
"donare un piccolo contributo sulla pagina del progetto https://mediathekview.de/"
msgctxt "#30963"
-msgid "XZ Decompressor is Missing"
-msgstr "Decompressore XZ non trovato"
+msgid "No Decompressor Available"
+msgstr "Decompressore non disponibile"
msgctxt "#30964"
msgid "The database updater needs the program 'xz' in order to process the database update files. "
@@ -301,3 +301,11 @@ msgstr "Scaricamento sottotitoli"
msgctxt "#30979"
msgid "Download path does not exist"
msgstr "Directory di scaricamento non esiste"
+
+msgctxt "#30980"
+msgid "Results Limited"
+msgstr "Risultati limitati"
+
+msgctxt "#30981"
+msgid "Only the first {} results are shown."
+msgstr "Vengono mostrati solo i primi {} risultati."
diff --git a/plugin.video.mediathekview/de/__init__.py b/plugin.video.mediathekview/resources/lib/__init__.py
index e69de29..e69de29 100644
--- a/plugin.video.mediathekview/de/__init__.py
+++ b/plugin.video.mediathekview/resources/lib/__init__.py
diff --git a/plugin.video.mediathekview/de/yeasoft/base/Logger.py b/plugin.video.mediathekview/resources/lib/base/Logger.py
index 7fad5fc..3d74680 100644
--- a/plugin.video.mediathekview/de/yeasoft/base/Logger.py
+++ b/plugin.video.mediathekview/resources/lib/base/Logger.py
@@ -22,7 +22,7 @@ class Logger( object ):
def debug( self, message, *args ):
pass
-
+
def info( self, message, *args ):
pass
diff --git a/plugin.video.mediathekview/de/yeasoft/__init__.py b/plugin.video.mediathekview/resources/lib/base/__init__.py
index e69de29..e69de29 100644
--- a/plugin.video.mediathekview/de/yeasoft/__init__.py
+++ b/plugin.video.mediathekview/resources/lib/base/__init__.py
diff --git a/plugin.video.mediathekview/classes/channel.py b/plugin.video.mediathekview/resources/lib/channel.py
index d142383..d142383 100644
--- a/plugin.video.mediathekview/classes/channel.py
+++ b/plugin.video.mediathekview/resources/lib/channel.py
diff --git a/plugin.video.mediathekview/classes/channelui.py b/plugin.video.mediathekview/resources/lib/channelui.py
index 7061013..36743e8 100644
--- a/plugin.video.mediathekview/classes/channelui.py
+++ b/plugin.video.mediathekview/resources/lib/channelui.py
@@ -6,16 +6,15 @@
import sys, urllib
import xbmcplugin, xbmcgui
-from classes.channel import Channel
-from classes.settings import Settings
+from resources.lib.channel import Channel
# -- Classes ------------------------------------------------
class ChannelUI( Channel ):
- def __init__( self, handle, sortmethods = [ xbmcplugin.SORT_METHOD_TITLE ], next = 'initial' ):
+ def __init__( self, handle, sortmethods = None, nextdir = 'initial' ):
self.base_url = sys.argv[0]
- self.next = next
+ self.nextdir = nextdir
self.handle = handle
- self.sortmethods = sortmethods
+ self.sortmethods = sortmethods if sortmethods is not None else [ xbmcplugin.SORT_METHOD_TITLE ]
self.count = 0
def Begin( self ):
@@ -28,7 +27,7 @@ class ChannelUI( Channel ):
xbmcplugin.addDirectoryItem(
handle = self.handle,
url = self.build_url( {
- 'mode': self.next,
+ 'mode': self.nextdir,
'channel': self.id
} ),
listitem = li,
diff --git a/plugin.video.mediathekview/classes/exceptions.py b/plugin.video.mediathekview/resources/lib/exceptions.py
index 53d7f14..53d7f14 100644
--- a/plugin.video.mediathekview/classes/exceptions.py
+++ b/plugin.video.mediathekview/resources/lib/exceptions.py
diff --git a/plugin.video.mediathekview/classes/film.py b/plugin.video.mediathekview/resources/lib/film.py
index b417078..b417078 100644
--- a/plugin.video.mediathekview/classes/film.py
+++ b/plugin.video.mediathekview/resources/lib/film.py
diff --git a/plugin.video.mediathekview/classes/filmui.py b/plugin.video.mediathekview/resources/lib/filmui.py
index eb2cfa8..af04798 100644
--- a/plugin.video.mediathekview/classes/filmui.py
+++ b/plugin.video.mediathekview/resources/lib/filmui.py
@@ -3,18 +3,18 @@
#
# -- Imports ------------------------------------------------
-import xbmcaddon, xbmcplugin, xbmcgui
+import xbmcplugin, xbmcgui
-from classes.film import Film
-from classes.settings import Settings
+from resources.lib.film import Film
+from resources.lib.settings import Settings
# -- Classes ------------------------------------------------
class FilmUI( Film ):
- def __init__( self, plugin, sortmethods = [ xbmcplugin.SORT_METHOD_TITLE, xbmcplugin.SORT_METHOD_DATE, xbmcplugin.SORT_METHOD_DURATION, xbmcplugin.SORT_METHOD_SIZE ] ):
+ def __init__( self, plugin, sortmethods = None ):
self.plugin = plugin
self.handle = plugin.addon_handle
self.settings = Settings()
- self.sortmethods = sortmethods
+ self.sortmethods = sortmethods if sortmethods is not None else [ xbmcplugin.SORT_METHOD_TITLE, xbmcplugin.SORT_METHOD_DATE, xbmcplugin.SORT_METHOD_DURATION, xbmcplugin.SORT_METHOD_SIZE ]
self.showshows = False
self.showchannels = False
@@ -25,7 +25,7 @@ class FilmUI( Film ):
for method in self.sortmethods:
xbmcplugin.addSortMethod( self.handle, method )
- def Add( self, alttitle = None ):
+ def Add( self, alttitle = None, totalItems = None ):
# get the best url
videourl = self.url_video_hd if ( self.url_video_hd != "" and self.settings.preferhd ) else self.url_video if self.url_video != "" else self.url_video_sd
videohds = " (HD)" if ( self.url_video_hd != "" and self.settings.preferhd ) else ""
@@ -58,10 +58,11 @@ class FilmUI( Film ):
if self.aired is not None:
airedstring = '%s' % self.aired
- infoLabels['date'] = airedstring[8:10] + '-' + airedstring[5:7] + '-' + airedstring[:4]
- infoLabels['aired'] = airedstring
- infoLabels['dateadded'] = airedstring
-
+ if airedstring[:4] != '1970':
+ infoLabels['date'] = airedstring[8:10] + '-' + airedstring[5:7] + '-' + airedstring[:4]
+ infoLabels['aired'] = airedstring
+ infoLabels['dateadded'] = airedstring
+
li = xbmcgui.ListItem( resultingtitle, self.description )
li.setInfo( type = 'video', infoLabels = infoLabels )
li.setProperty( 'IsPlayable', 'true' )
@@ -94,12 +95,21 @@ class FilmUI( Film ):
# ) )
li.addContextMenuItems( contextmenu )
- xbmcplugin.addDirectoryItem(
- handle = self.handle,
- url = videourl,
- listitem = li,
- isFolder = False
- )
+ if totalItems is not None:
+ xbmcplugin.addDirectoryItem(
+ handle = self.handle,
+ url = videourl,
+ listitem = li,
+ isFolder = False,
+ totalItems = totalItems
+ )
+ else:
+ xbmcplugin.addDirectoryItem(
+ handle = self.handle,
+ url = videourl,
+ listitem = li,
+ isFolder = False
+ )
def End( self ):
xbmcplugin.endOfDirectory( self.handle, cacheToDisc = False )
diff --git a/plugin.video.mediathekview/classes/initialui.py b/plugin.video.mediathekview/resources/lib/initialui.py
index e9593d8..71d9aef 100644
--- a/plugin.video.mediathekview/classes/initialui.py
+++ b/plugin.video.mediathekview/resources/lib/initialui.py
@@ -6,13 +6,11 @@
import sys, urllib
import xbmcplugin, xbmcgui
-from classes.settings import Settings
-
# -- Classes ------------------------------------------------
class InitialUI( object ):
- def __init__( self, handle, sortmethods = [ xbmcplugin.SORT_METHOD_TITLE ] ):
+ def __init__( self, handle, sortmethods = None ):
self.handle = handle
- self.sortmethods = sortmethods
+ self.sortmethods = sortmethods if sortmethods is not None else [ xbmcplugin.SORT_METHOD_TITLE ]
self.channelid = 0
self.initial = ''
self.count = 0
@@ -30,7 +28,7 @@ class InitialUI( object ):
li = xbmcgui.ListItem( label = resultingname )
xbmcplugin.addDirectoryItem(
handle = self.handle,
- url = self.build_url( {
+ url = _build_url( {
'mode': "shows",
'channel': self.channelid,
'initial': self.initial,
@@ -43,5 +41,7 @@ class InitialUI( object ):
def End( self ):
xbmcplugin.endOfDirectory( self.handle )
- def build_url( self, query ):
- return sys.argv[0] + '?' + urllib.urlencode( query )
+# -- Functions ----------------------------------------------
+
+def _build_url( query ):
+ return sys.argv[0] + '?' + urllib.urlencode( query )
diff --git a/plugin.video.mediathekview/de/yeasoft/kodi/KodiAddon.py b/plugin.video.mediathekview/resources/lib/kodi/KodiAddon.py
index 9d2fa04..f9c0cd7 100644
--- a/plugin.video.mediathekview/de/yeasoft/kodi/KodiAddon.py
+++ b/plugin.video.mediathekview/resources/lib/kodi/KodiAddon.py
@@ -3,10 +3,10 @@
#
# -- Imports ------------------------------------------------
-import os, sys, urllib
+import sys, urllib
import xbmc, xbmcgui, xbmcaddon, xbmcplugin
-from de.yeasoft.kodi.KodiLogger import KodiLogger
+from resources.lib.kodi.KodiLogger import KodiLogger
# -- Classes ------------------------------------------------
class KodiAddon( KodiLogger ):
@@ -18,15 +18,15 @@ class KodiAddon( KodiLogger ):
self.fanart = self.addon.getAddonInfo( 'fanart' )
self.version = self.addon.getAddonInfo( 'version' )
self.path = self.addon.getAddonInfo( 'path' )
- self.datapath = os.path.join( xbmc.translatePath( "special://masterprofile" ).decode('utf-8'), 'addon_data', self.addon_id.decode('utf-8') )
+ self.datapath = xbmc.translatePath( self.addon.getAddonInfo('profile').decode('utf-8') )
self.language = self.addon.getLocalizedString
KodiLogger.__init__( self, self.addon_id, self.version )
- def getSetting( self, id ):
- return self.addon.getSetting( id )
+ def getSetting( self, setting_id ):
+ return self.addon.getSetting( setting_id )
- def setSetting( self, id, value ):
- return self.addon.setSetting( id, value )
+ def setSetting( self, setting_id, value ):
+ return self.addon.setSetting( setting_id, value )
def doAction( self, action ):
xbmc.executebuiltin( 'Action({})'.format( action ) )
@@ -54,7 +54,7 @@ class KodiPlugin( KodiAddon ):
self.addDirectoryItem( name, params, True )
def addDirectoryItem( self, name, params, isFolder ):
- if type( name ) is int:
+ if isinstance( name, int ):
name = self.language( name )
li = xbmcgui.ListItem( name )
xbmcplugin.addDirectoryItem(
diff --git a/plugin.video.mediathekview/de/yeasoft/kodi/KodiLogger.py b/plugin.video.mediathekview/resources/lib/kodi/KodiLogger.py
index f656b31..c57ec84 100644
--- a/plugin.video.mediathekview/de/yeasoft/kodi/KodiLogger.py
+++ b/plugin.video.mediathekview/resources/lib/kodi/KodiLogger.py
@@ -5,7 +5,7 @@
# -- Imports ------------------------------------------------
import xbmc
-from de.yeasoft.base.Logger import Logger
+from resources.lib.base.Logger import Logger
# -- Classes ------------------------------------------------
class KodiLogger( Logger ):
@@ -36,20 +36,3 @@ class KodiLogger( Logger ):
part = arg # arg.decode('utf-8')
parts.append( part )
xbmc.log( self.prefix + message.format( *parts ), level = level )
-# formatMessage = self._getFormatMessage( message )
-# xbmc.log( self.prefix + formatMessage.format( *parts ), level = level )
-
-# def _getFormatMessage( self, message ):
-# j = message.find( '{}' )
-# if j == -1:
-# return message
-# formatMessage = ''
-# i = 0
-# index = 0
-# while j != -1:
-# formatMessage += message[i:j] + '{' + str( index ) + '}'
-# i = j + len( '{}' )
-# j = message.find( '{}', i )
-# index += 1
-# formatMessage += message[i:]
-# return formatMessage
diff --git a/plugin.video.mediathekview/de/yeasoft/kodi/KodiUI.py b/plugin.video.mediathekview/resources/lib/kodi/KodiUI.py
index dee8dbb..dee8dbb 100644
--- a/plugin.video.mediathekview/de/yeasoft/kodi/KodiUI.py
+++ b/plugin.video.mediathekview/resources/lib/kodi/KodiUI.py
diff --git a/plugin.video.mediathekview/de/yeasoft/base/__init__.py b/plugin.video.mediathekview/resources/lib/kodi/__init__.py
index e69de29..e69de29 100644
--- a/plugin.video.mediathekview/de/yeasoft/base/__init__.py
+++ b/plugin.video.mediathekview/resources/lib/kodi/__init__.py
diff --git a/plugin.video.mediathekview/classes/mvupdate.py b/plugin.video.mediathekview/resources/lib/mvupdate.py
index f314679..7595417 100644
--- a/plugin.video.mediathekview/classes/mvupdate.py
+++ b/plugin.video.mediathekview/resources/lib/mvupdate.py
@@ -8,9 +8,8 @@ import argparse
import datetime
import xml.etree.ElementTree as ET
-from de.yeasoft.base.Logger import Logger
-from classes.store import Store
-from classes.updater import MediathekViewUpdater
+from resources.lib.base.Logger import Logger
+from resources.lib.updater import MediathekViewUpdater
# -- Classes ------------------------------------------------
class Settings( object ):
@@ -19,6 +18,7 @@ class Settings( object ):
self.type = { 'sqlite' : '0', 'mysql' : '1' }.get( args.dbtype, '0' )
if self.type == '1':
self.host = args.host
+ self.port = int( args.port )
self.user = args.user
self.password = args.password
self.database = args.database
@@ -27,7 +27,6 @@ class Settings( object ):
self.groupshows = False
self.updenabled = True
self.updinterval = 3600
- self.updxzbin = ''
class AppLogger( Logger ):
@@ -93,7 +92,7 @@ class Notifier( object ):
pass
def ShowDownloadError( self, name, err ):
pass
- def ShowMissingXZError( self ):
+ def ShowMissingExtractorError( self ):
pass
def ShowDownloadProgress( self ):
pass
@@ -119,7 +118,7 @@ class UpdateApp( AppLogger ):
tree = ET.parse( self.mypath + '/addon.xml' )
version = tree.getroot().attrib['version']
AppLogger.__init__( self, os.path.basename( sys.argv[0] ), version )
- except Exception as err:
+ except Exception:
AppLogger.__init__( self, os.path.basename( sys.argv[0] ), '0.0' )
def Init( self ):
@@ -148,26 +147,32 @@ class UpdateApp( AppLogger ):
mysqlopts.add_argument(
'-H', '--host',
dest = 'host',
- help = 'hostname or ip of the MySQL server',
+ help = 'hostname or ip address',
default = 'localhost'
)
mysqlopts.add_argument(
+ '-P', '--port',
+ dest = 'port',
+ help = 'connection port',
+ default = '3306'
+ )
+ mysqlopts.add_argument(
'-u', '--user',
dest = 'user',
- help = 'username for the MySQL server connection',
- default = 'filmliste'
+ help = 'connection username',
+ default = 'mediathekview'
)
mysqlopts.add_argument(
'-p', '--password',
dest = 'password',
- help = 'password for the MySQL server connection',
+ help = 'connection password',
default = None
)
mysqlopts.add_argument(
'-d', '--database',
dest = 'database',
- default = 'filmliste',
- help = 'MySQL database for mediathekview'
+ default = 'mediathekview',
+ help = 'database name'
)
self.args = parser.parse_args()
self.verbosity = self.args.verbose
@@ -177,10 +182,6 @@ class UpdateApp( AppLogger ):
self.notifier = Notifier()
self.monitor = MediathekViewMonitor()
self.updater = MediathekViewUpdater( self.getNewLogger( 'MediathekViewUpdater' ), self.notifier, self.settings, self.monitor )
- if self.updater.PrerequisitesMissing():
- self.error( 'Prerequisites are missing' )
- self.Exit()
- exit( 1 )
self.updater.Init()
def Run( self ):
diff --git a/plugin.video.mediathekview/resources/lib/mvutils.py b/plugin.video.mediathekview/resources/lib/mvutils.py
new file mode 100644
index 0000000..d4c7663
--- /dev/null
+++ b/plugin.video.mediathekview/resources/lib/mvutils.py
@@ -0,0 +1,87 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017-2018, Leo Moll
+
+# -- Imports ------------------------------------------------
+import os
+import stat
+import string
+import urllib2
+import xbmcvfs
+
+from contextlib import closing
+
+# -- Functions ----------------------------------------------
+def dir_exists( name ):
+ try:
+ s = os.stat( name )
+ return stat.S_ISDIR( s.st_mode )
+ except OSError:
+ return False
+
+def file_exists( name ):
+ try:
+ s = os.stat( name )
+ return stat.S_ISREG( s.st_mode )
+ except OSError:
+ return False
+
+def file_size( name ):
+ try:
+ s = os.stat( name )
+ return s.st_size
+ except OSError:
+ return 0
+
+def find_xz():
+ for xzbin in [ '/bin/xz', '/usr/bin/xz', '/usr/local/bin/xz' ]:
+ if file_exists( xzbin ):
+ return xzbin
+ return None
+
+def make_search_string( val ):
+ cset = string.letters + string.digits + ' _-#'
+ search = ''.join( [ c for c in val if c in cset ] )
+ return search.upper().strip()
+
+def make_duration( val ):
+ if val == "00:00:00":
+ return None
+ elif val is None:
+ return None
+ x = val.split( ':' )
+ if len( x ) != 3:
+ return None
+ return int( x[0] ) * 3600 + int( x[1] ) * 60 + int( x[2] )
+
+def cleanup_filename( val ):
+ cset = string.letters + string.digits + u' _-#äöüÄÖÜßáàâéèêíìîóòôúùûÁÀÉÈÍÌÓÒÚÙçÇœ'
+ search = ''.join( [ c for c in val if c in cset ] )
+ return search.strip()
+
+def url_retrieve( url, filename, reporthook, chunk_size = 8192 ):
+ with closing( urllib2.urlopen( url ) ) as u, closing( open( filename, 'wb' ) ) as f:
+ total_size = int( u.info().getheader( 'Content-Length' ).strip() ) if u.info() and u.info().getheader( 'Content-Length' ) else 0
+ total_chunks = 0
+
+ while True:
+ reporthook( total_chunks, chunk_size, total_size )
+ chunk = u.read( chunk_size )
+ if not chunk:
+ break
+ f.write( chunk )
+ total_chunks += 1
+ return ( filename, [], )
+
+def url_retrieve_vfs( videourl, filename, reporthook, chunk_size = 8192 ):
+ with closing( urllib2.urlopen( videourl ) ) as u, closing( xbmcvfs.File( filename, 'wb' ) ) as f:
+ total_size = int( u.info().getheader( 'Content-Length' ).strip() ) if u.info() and u.info().getheader( 'Content-Length' ) else 0
+ total_chunks = 0
+
+ while True:
+ reporthook( total_chunks, chunk_size, total_size )
+ chunk = u.read( chunk_size )
+ if not chunk:
+ break
+ f.write( chunk )
+ total_chunks += 1
+ return ( filename, [], )
diff --git a/plugin.video.mediathekview/classes/notifier.py b/plugin.video.mediathekview/resources/lib/notifier.py
index f76d059..d257a52 100644
--- a/plugin.video.mediathekview/classes/notifier.py
+++ b/plugin.video.mediathekview/resources/lib/notifier.py
@@ -3,9 +3,9 @@
#
# -- Imports ------------------------------------------------
-import xbmcaddon, xbmcplugin
+import xbmcaddon
-from de.yeasoft.kodi.KodiUI import KodiUI
+from resources.lib.kodi.KodiUI import KodiUI
# -- Classes ------------------------------------------------
class Notifier( KodiUI ):
@@ -19,9 +19,12 @@ class Notifier( KodiUI ):
def ShowDownloadError( self, name, err ):
self.ShowError( self.language( 30952 ), self.language( 30953 ).format( name, err ) )
- def ShowMissingXZError( self ):
+ def ShowMissingExtractorError( self ):
self.ShowError( self.language( 30952 ), self.language( 30954 ), time = 10000 )
+ def ShowLimitResults( self, maxresults ):
+ self.ShowNotification( self.language( 30980 ), self.language( 30981 ).format( maxresults ) )
+
def ShowDownloadProgress( self ):
self.ShowBGDialog( self.language( 30955 ) )
diff --git a/plugin.video.mediathekview/classes/settings.py b/plugin.video.mediathekview/resources/lib/settings.py
index 58ea805..32bd95a 100644
--- a/plugin.video.mediathekview/classes/settings.py
+++ b/plugin.video.mediathekview/resources/lib/settings.py
@@ -3,7 +3,6 @@
#
# -- Imports ------------------------------------------------
-import os
import xbmc,xbmcaddon
# -- Classes ------------------------------------------------
@@ -13,21 +12,22 @@ class Settings( object ):
self.Reload()
def Reload( self ):
- self.datapath = os.path.join( xbmc.translatePath( "special://masterprofile" ).decode('utf-8'), 'addon_data', self.addon.getAddonInfo( 'id' ).decode('utf-8') )
+ self.datapath = xbmc.translatePath( self.addon.getAddonInfo('profile').decode('utf-8') )
self.firstrun = self.addon.getSetting( 'firstrun' ) == 'true'
self.preferhd = self.addon.getSetting( 'quality' ) == 'true'
self.nofuture = self.addon.getSetting( 'nofuture' ) == 'true'
self.minlength = int( float( self.addon.getSetting( 'minlength' ) ) ) * 60
self.groupshows = self.addon.getSetting( 'groupshows' ) == 'true'
+ self.maxresults = int( self.addon.getSetting( 'maxresults' ) )
self.downloadpath = self.addon.getSetting( 'downloadpath' )
self.type = self.addon.getSetting( 'dbtype' )
self.host = self.addon.getSetting( 'dbhost' )
+ self.port = int( self.addon.getSetting( 'dbport' ) )
self.user = self.addon.getSetting( 'dbuser' )
self.password = self.addon.getSetting( 'dbpass' )
self.database = self.addon.getSetting( 'dbdata' )
self.updenabled = self.addon.getSetting( 'updenabled' ) == 'true'
self.updinterval = int( float( self.addon.getSetting( 'updinterval' ) ) ) * 3600
- self.updxzbin = self.addon.getSetting( 'updxzbin' )
def HandleFirstRun( self ):
if self.firstrun:
diff --git a/plugin.video.mediathekview/classes/show.py b/plugin.video.mediathekview/resources/lib/show.py
index e0c9127..e0c9127 100644
--- a/plugin.video.mediathekview/classes/show.py
+++ b/plugin.video.mediathekview/resources/lib/show.py
diff --git a/plugin.video.mediathekview/classes/showui.py b/plugin.video.mediathekview/resources/lib/showui.py
index b6f0bf8..b0bf7f9 100644
--- a/plugin.video.mediathekview/classes/showui.py
+++ b/plugin.video.mediathekview/resources/lib/showui.py
@@ -6,15 +6,14 @@
import sys, urllib
import xbmcplugin, xbmcgui
-from classes.show import Show
-from classes.settings import Settings
+from resources.lib.show import Show
# -- Classes ------------------------------------------------
class ShowUI( Show ):
- def __init__( self, handle, sortmethods = [ xbmcplugin.SORT_METHOD_TITLE ] ):
+ def __init__( self, handle, sortmethods = None ):
self.base_url = sys.argv[0]
self.handle = handle
- self.sortmethods = sortmethods
+ self.sortmethods = sortmethods if sortmethods is not None else [ xbmcplugin.SORT_METHOD_TITLE ]
self.querychannelid = 0
def Begin( self, channelid ):
diff --git a/plugin.video.mediathekview/classes/store.py b/plugin.video.mediathekview/resources/lib/store.py
index 15c6ef2..2312a3c 100644
--- a/plugin.video.mediathekview/classes/store.py
+++ b/plugin.video.mediathekview/resources/lib/store.py
@@ -3,8 +3,8 @@
#
# -- Imports ------------------------------------------------
-from classes.storemysql import StoreMySQL
-from classes.storesqlite import StoreSQLite
+from resources.lib.storemysql import StoreMySQL
+from resources.lib.storesqlite import StoreSQLite
# -- Classes ------------------------------------------------
class Store( object ):
@@ -15,7 +15,7 @@ class Store( object ):
# load storage engine
if settings.type == '0':
self.logger.info( 'Database driver: Internal (sqlite)' )
- self.db = StoreSQLite( logger.getNewLogger( 'StoreMySQL' ), notifier, self.settings )
+ self.db = StoreSQLite( logger.getNewLogger( 'StoreSQLite' ), notifier, self.settings )
elif settings.type == '1':
self.logger.info( 'Database driver: External (mysql)' )
self.db = StoreMySQL( logger.getNewLogger( 'StoreMySQL' ), notifier, self.settings )
@@ -23,11 +23,6 @@ class Store( object ):
self.logger.warn( 'Unknown Database driver selected' )
self.db = None
- def __del__( self ):
- if self.db is not None:
- del self.db
- self.db = None
-
def Init( self, reset = False ):
if self.db is not None:
self.db.Init( reset )
diff --git a/plugin.video.mediathekview/classes/storemysql.py b/plugin.video.mediathekview/resources/lib/storemysql.py
index a272277..e2419cc 100644
--- a/plugin.video.mediathekview/classes/storemysql.py
+++ b/plugin.video.mediathekview/resources/lib/storemysql.py
@@ -3,11 +3,12 @@
#
# -- Imports ------------------------------------------------
-import string, time
+import time
import mysql.connector
-from classes.film import Film
-from classes.exceptions import DatabaseCorrupted
+import resources.lib.mvutils as mvutils
+
+from resources.lib.film import Film
# -- Classes ------------------------------------------------
class StoreMySQL( object ):
@@ -18,6 +19,7 @@ class StoreMySQL( object ):
self.settings = settings
# useful query fragments
self.sql_query_films = "SELECT film.id,`title`,`show`,`channel`,`description`,TIME_TO_SEC(`duration`) AS `seconds`,`size`,`aired`,`url_sub`,`url_video`,`url_video_sd`,`url_video_hd` FROM `film` LEFT JOIN `show` ON show.id=film.showid LEFT JOIN `channel` ON channel.id=film.channelid"
+ self.sql_query_filmcnt = "SELECT COUNT(*) FROM `film` LEFT JOIN `show` ON show.id=film.showid LEFT JOIN `channel` ON channel.id=film.channelid"
self.sql_cond_recent = "( TIMESTAMPDIFF(HOUR,`aired`,CURRENT_TIMESTAMP()) < 24 )"
self.sql_cond_nofuture = " AND ( ( `aired` IS NULL ) OR ( TIMESTAMPDIFF(HOUR,`aired`,CURRENT_TIMESTAMP()) > 0 ) )" if settings.nofuture else ""
self.sql_cond_minlength = " AND ( ( `duration` IS NULL ) OR ( TIME_TO_SEC(`duration`) >= %d ) )" % settings.minlength if settings.minlength > 0 else ""
@@ -27,12 +29,17 @@ class StoreMySQL( object ):
try:
self.conn = mysql.connector.connect(
host = self.settings.host,
+ port = self.settings.port,
user = self.settings.user,
- password = self.settings.password,
- database = self.settings.database
+ password = self.settings.password
)
+ self.conn.database = self.settings.database
except mysql.connector.Error as err:
- self.conn = None
+ if err.errno == mysql.connector.errorcode.ER_BAD_DB_ERROR:
+ self.logger.info( '=== DATABASE {} DOES NOT EXIST. TRYING TO CREATE IT ===', self.settings.database )
+ self._handle_database_initialization()
+ return
+ self.conn = None
self.logger.error( 'Database error: {}', err )
self.notifier.ShowDatabaseError( err )
@@ -41,17 +48,17 @@ class StoreMySQL( object ):
self.conn.close()
def Search( self, search, filmui ):
- self._Search_Condition( '( ( `title` LIKE "%%%s%%" ) OR ( `show` LIKE "%%%s%%" ) )' % ( search, search, ), filmui, True, True )
+ self._Search_Condition( '( ( `title` LIKE "%%%s%%" ) OR ( `show` LIKE "%%%s%%" ) )' % ( search, search, ), filmui, True, True, self.settings.maxresults )
def SearchFull( self, search, filmui ):
- self._Search_Condition( '( ( `title` LIKE "%%%s%%" ) OR ( `show` LIKE "%%%s%%" ) ) OR ( `description` LIKE "%%%s%%") )' % ( search, search, search ), filmui, True, True )
+ self._Search_Condition( '( ( `title` LIKE "%%%s%%" ) OR ( `show` LIKE "%%%s%%" ) ) OR ( `description` LIKE "%%%s%%") )' % ( search, search, search ), filmui, True, True, self.settings.maxresults )
def GetRecents( self, channelid, filmui ):
sql_cond_channel = ' AND ( film.channelid=' + str( channelid ) + ' ) ' if channelid != '0' else ''
- self._Search_Condition( self.sql_cond_recent + sql_cond_channel, filmui, True, False )
+ self._Search_Condition( self.sql_cond_recent + sql_cond_channel, filmui, True, False, 10000 )
def GetLiveStreams( self, filmui ):
- self._Search_Condition( '( show.search="LIVESTREAM" )', filmui, False, False )
+ self._Search_Condition( '( show.search="LIVESTREAM" )', filmui, False, False, 10000 )
def GetChannels( self, channelui ):
self._Channels_Condition( None, channelui )
@@ -59,32 +66,12 @@ class StoreMySQL( object ):
def GetRecentChannels( self, channelui ):
self._Channels_Condition( self.sql_cond_recent, channelui )
- def _Channels_Condition( self, condition, channelui):
- if self.conn is None:
- return
- try:
- if condition is None:
- query = 'SELECT `id`,`channel`,0 AS `count` FROM `channel`'
- else:
- query = 'SELECT channel.id AS `id`,`channel`,COUNT(*) AS `count` FROM `film` LEFT JOIN `channel` ON channel.id=film.channelid WHERE ' + condition + ' GROUP BY channel.id'
- self.logger.info( 'MySQL Query: {}', query )
- cursor = self.conn.cursor()
- cursor.execute( query )
- channelui.Begin()
- for ( channelui.id, channelui.channel, channelui.count ) in cursor:
- channelui.Add()
- channelui.End()
- cursor.close()
- except mysql.connector.Error as err:
- self.logger.error( 'Database error: {}', err )
- self.notifier.ShowDatabaseError( err )
-
def GetInitials( self, channelid, initialui ):
if self.conn is None:
return
try:
condition = 'WHERE ( `channelid`=' + str( channelid ) + ' ) ' if channelid != '0' else ''
- self.logger.info( 'MySQL Query: {}',
+ self.logger.info( 'MySQL Query: {}',
'SELECT LEFT(`search`,1) AS letter,COUNT(*) AS `count` FROM `show` ' +
condition +
'GROUP BY LEFT(search,1)'
@@ -131,19 +118,39 @@ class StoreMySQL( object ):
return
if showid.find( ',' ) == -1:
# only one channel id
- condition = '( `showid=`%s )' % showid
+ condition = '( `showid`=%s )' % showid
showchannels = False
else:
# multiple channel ids
condition = '( `showid` IN ( %s ) )' % showid
showchannels = True
- self._Search_Condition( condition, filmui, False, showchannels )
+ self._Search_Condition( condition, filmui, False, showchannels, 10000 )
+
+ def _Channels_Condition( self, condition, channelui):
+ if self.conn is None:
+ return
+ try:
+ if condition is None:
+ query = 'SELECT `id`,`channel`,0 AS `count` FROM `channel`'
+ else:
+ query = 'SELECT channel.id AS `id`,`channel`,COUNT(*) AS `count` FROM `film` LEFT JOIN `channel` ON channel.id=film.channelid WHERE ' + condition + ' GROUP BY channel.id'
+ self.logger.info( 'MySQL Query: {}', query )
+ cursor = self.conn.cursor()
+ cursor.execute( query )
+ channelui.Begin()
+ for ( channelui.id, channelui.channel, channelui.count ) in cursor:
+ channelui.Add()
+ channelui.End()
+ cursor.close()
+ except mysql.connector.Error as err:
+ self.logger.error( 'Database error: {}', err )
+ self.notifier.ShowDatabaseError( err )
- def _Search_Condition( self, condition, filmui, showshows, showchannels ):
+ def _Search_Condition( self, condition, filmui, showshows, showchannels, maxresults ):
if self.conn is None:
return
try:
- self.logger.info( 'MySQL Query: {}',
+ self.logger.info( 'MySQL Query: {}',
self.sql_query_films +
' WHERE ' +
condition +
@@ -152,15 +159,27 @@ class StoreMySQL( object ):
)
cursor = self.conn.cursor()
cursor.execute(
+ self.sql_query_filmcnt +
+ ' WHERE ' +
+ condition +
+ self.sql_cond_nofuture +
+ self.sql_cond_minlength +
+ ' LIMIT {}'.format( maxresults + 1 ) if maxresults else ''
+ )
+ ( results, ) = cursor.fetchone()
+ if maxresults and results > maxresults:
+ self.notifier.ShowLimitResults( maxresults )
+ cursor.execute(
self.sql_query_films +
' WHERE ' +
condition +
self.sql_cond_nofuture +
- self.sql_cond_minlength
+ self.sql_cond_minlength +
+ ' LIMIT {}'.format( maxresults + 1 ) if maxresults else ''
)
filmui.Begin( showshows, showchannels )
for ( filmui.id, filmui.title, filmui.show, filmui.channel, filmui.description, filmui.seconds, filmui.size, filmui.aired, filmui.url_sub, filmui.url_video, filmui.url_video_sd, filmui.url_video_hd ) in cursor:
- filmui.Add()
+ filmui.Add( totalItems = results )
filmui.End()
cursor.close()
except mysql.connector.Error as err:
@@ -172,7 +191,7 @@ class StoreMySQL( object ):
return None
try:
condition = '( film.id={} )'.format( filmid )
- self.logger.info( 'MySQL Query: {}',
+ self.logger.info( 'MySQL Query: {}',
self.sql_query_films +
' WHERE ' +
condition
@@ -456,7 +475,7 @@ class StoreMySQL( object ):
if newchn or self.ft_show != film['show']:
# process changed show
self.ft_show = film['show']
- ( self.ft_showid, insshw ) = self._insert_show( self.ft_channelid, self.ft_show, self._make_search( self.ft_show ) )
+ ( self.ft_showid, insshw ) = self._insert_show( self.ft_channelid, self.ft_show, mvutils.make_search_string( self.ft_show ) )
if self.ft_showid == 0:
self.logger.info( 'Undefined error adding show "{}"', self.ft_show )
return ( 0, 0, 0, 0, )
@@ -467,7 +486,7 @@ class StoreMySQL( object ):
self.ft_channelid,
self.ft_showid,
film["title"],
- self._make_search( film['title'] ),
+ mvutils.make_search_string( film['title'] ),
film["aired"],
film["duration"],
film["size"],
@@ -516,10 +535,10 @@ class StoreMySQL( object ):
cursor = self.conn.cursor()
cursor.callproc( 'ftInsertShow', ( channelid, show, search, ) )
for result in cursor.stored_results():
- for ( id, added ) in result:
+ for ( idd, added ) in result:
cursor.close()
self.conn.commit()
- return ( id, added )
+ return ( idd, added )
# should never happen
cursor.close()
self.conn.commit()
@@ -528,7 +547,367 @@ class StoreMySQL( object ):
self.notifier.ShowDatabaseError( err )
return ( 0, 0, )
- def _make_search( self, val ):
- cset = string.letters + string.digits + ' _-#'
- search = ''.join( [ c for c in val if c in cset ] )
- return search.upper().strip()
+ def _handle_database_initialization( self ):
+ cursor = None
+ dbcreated = False
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute( 'CREATE DATABASE `{}` DEFAULT CHARACTER SET utf8'.format( self.settings.database ) )
+ dbcreated = True
+ self.conn.database = self.settings.database
+ cursor.execute( 'SET FOREIGN_KEY_CHECKS=0' )
+ self.conn.commit()
+ cursor.execute(
+ """
+CREATE TABLE `channel` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `dtCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `touched` smallint(1) NOT NULL DEFAULT '1',
+ `channel` varchar(255) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `channel` (`channel`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ """
+ )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE TABLE `film` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `dtCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `touched` smallint(1) NOT NULL DEFAULT '1',
+ `channelid` int(11) NOT NULL,
+ `showid` int(11) NOT NULL,
+ `title` varchar(255) NOT NULL,
+ `search` varchar(255) NOT NULL,
+ `aired` timestamp NULL DEFAULT NULL,
+ `duration` time DEFAULT NULL,
+ `size` int(11) DEFAULT NULL,
+ `description` longtext,
+ `website` varchar(384) DEFAULT NULL,
+ `url_sub` varchar(384) DEFAULT NULL,
+ `url_video` varchar(384) DEFAULT NULL,
+ `url_video_sd` varchar(384) DEFAULT NULL,
+ `url_video_hd` varchar(384) DEFAULT NULL,
+ `airedepoch` int(11) DEFAULT NULL,
+ PRIMARY KEY (`id`),
+ KEY `index_1` (`showid`,`title`),
+ KEY `index_2` (`channelid`,`title`),
+ KEY `dupecheck` (`channelid`,`showid`,`url_video`),
+ CONSTRAINT `FK_FilmChannel` FOREIGN KEY (`channelid`) REFERENCES `channel` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
+ CONSTRAINT `FK_FilmShow` FOREIGN KEY (`showid`) REFERENCES `show` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ """ )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE TABLE `show` (
+ `id` int(11) NOT NULL AUTO_INCREMENT,
+ `dtCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
+ `touched` smallint(1) NOT NULL DEFAULT '1',
+ `channelid` int(11) NOT NULL,
+ `show` varchar(255) NOT NULL,
+ `search` varchar(255) NOT NULL,
+ PRIMARY KEY (`id`),
+ KEY `show` (`show`),
+ KEY `search` (`search`),
+ KEY `combined_1` (`channelid`,`search`),
+ KEY `combined_2` (`channelid`,`show`),
+ CONSTRAINT `FK_ShowChannel` FOREIGN KEY (`channelid`) REFERENCES `channel` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ """ )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE TABLE `status` (
+ `modified` int(11) NOT NULL,
+ `status` varchar(255) NOT NULL,
+ `lastupdate` int(11) NOT NULL,
+ `filmupdate` int(11) NOT NULL,
+ `fullupdate` int(1) NOT NULL,
+ `add_chn` int(11) NOT NULL,
+ `add_shw` int(11) NOT NULL,
+ `add_mov` int(11) NOT NULL,
+ `del_chm` int(11) NOT NULL,
+ `del_shw` int(11) NOT NULL,
+ `del_mov` int(11) NOT NULL,
+ `tot_chn` int(11) NOT NULL,
+ `tot_shw` int(11) NOT NULL,
+ `tot_mov` int(11) NOT NULL
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+ """ )
+ self.conn.commit()
+
+ cursor.execute( 'INSERT INTO `status` VALUES (0,"IDLE",0,0,0,0,0,0,0,0,0,0,0,0);' )
+ self.conn.commit()
+
+ cursor.execute( 'SET FOREIGN_KEY_CHECKS=1' )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE PROCEDURE `ftInsertChannel`(
+ _channel VARCHAR(255)
+)
+BEGIN
+ DECLARE channelid_ INT(11);
+ DECLARE touched_ INT(1);
+ DECLARE added_ INT(1) DEFAULT 0;
+
+ SELECT `id`,
+ `touched`
+ INTO channelid_,
+ touched_
+ FROM `channel`
+ WHERE ( `channel`.`channel` = _channel );
+
+ IF ( channelid_ IS NULL ) THEN
+ INSERT INTO `channel` (
+ `channel`
+ )
+ VALUES (
+ _channel
+ );
+ SET channelid_ = LAST_INSERT_ID();
+ SET added_ = 1;
+ ELSE
+ UPDATE `channel`
+ SET `touched` = 1
+ WHERE ( `id` = channelid_ );
+ END IF;
+
+ SELECT channelid_ AS `id`,
+ added_ AS `added`;
+END
+ """ )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE PROCEDURE `ftInsertFilm`(
+ _channelid INT(11),
+ _showid INT(11),
+ _title VARCHAR(255),
+ _search VARCHAR(255),
+ _aired TIMESTAMP,
+ _duration TIME,
+ _size INT(11),
+ _description LONGTEXT,
+ _website VARCHAR(384),
+ _url_sub VARCHAR(384),
+ _url_video VARCHAR(384),
+ _url_video_sd VARCHAR(384),
+ _url_video_hd VARCHAR(384),
+ _airedepoch INT(11)
+)
+BEGIN
+ DECLARE id_ INT;
+ DECLARE added_ INT DEFAULT 0;
+
+ SELECT `id`
+ INTO id_
+ FROM `film` AS f
+ WHERE ( f.channelid = _channelid )
+ AND
+ ( f.showid = _showid )
+ AND
+ ( f.url_video = _url_video );
+
+ IF ( id_ IS NULL ) THEN
+ INSERT INTO `film` (
+ `channelid`,
+ `showid`,
+ `title`,
+ `search`,
+ `aired`,
+ `duration`,
+ `size`,
+ `description`,
+ `website`,
+ `url_sub`,
+ `url_video`,
+ `url_video_sd`,
+ `url_video_hd`,
+ `airedepoch`
+ )
+ VALUES (
+ _channelid,
+ _showid,
+ _title,
+ _search,
+ IF(_aired = "1980-01-01 00:00:00", NULL, _aired),
+ IF(_duration = "00:00:00", NULL, _duration),
+ _size,
+ _description,
+ _website,
+ _url_sub,
+ _url_video,
+ _url_video_sd,
+ _url_video_hd,
+ _airedepoch
+ );
+ SET id_ = LAST_INSERT_ID();
+ SET added_ = 1;
+ ELSE
+ UPDATE `film`
+ SET `touched` = 1
+ WHERE ( `id` = id_ );
+ END IF;
+ SELECT id_ AS `id`,
+ added_ AS `added`;
+END
+ """ )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE PROCEDURE `ftInsertShow`(
+ _channelid INT(11),
+ _show VARCHAR(255),
+ _search VARCHAR(255)
+)
+BEGIN
+ DECLARE showid_ INT(11);
+ DECLARE touched_ INT(1);
+ DECLARE added_ INT(1) DEFAULT 0;
+
+ SELECT `id`,
+ `touched`
+ INTO showid_,
+ touched_
+ FROM `show`
+ WHERE ( `show`.`channelid` = _channelid )
+ AND
+ ( `show`.`show` = _show );
+
+ IF ( showid_ IS NULL ) THEN
+ INSERT INTO `show` (
+ `channelid`,
+ `show`,
+ `search`
+ )
+ VALUES (
+ _channelid,
+ _show,
+ _search
+ );
+ SET showid_ = LAST_INSERT_ID();
+ SET added_ = 1;
+ ELSE
+ UPDATE `show`
+ SET `touched` = 1
+ WHERE ( `id` = showid_ );
+ END IF;
+
+
+ SELECT showid_ AS `id`,
+ added_ AS `added`;
+END
+ """ )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE PROCEDURE `ftUpdateEnd`(
+ _full INT(1)
+)
+BEGIN
+ DECLARE del_chn_ INT DEFAULT 0;
+ DECLARE del_shw_ INT DEFAULT 0;
+ DECLARE del_mov_ INT DEFAULT 0;
+ DECLARE cnt_chn_ INT DEFAULT 0;
+ DECLARE cnt_shw_ INT DEFAULT 0;
+ DECLARE cnt_mov_ INT DEFAULT 0;
+
+ IF ( _full = 1 ) THEN
+ SELECT COUNT(*)
+ INTO del_chn_
+ FROM `channel`
+ WHERE ( `touched` = 0 );
+
+ SELECT COUNT(*)
+ INTO del_shw_
+ FROM `show`
+ WHERE ( `touched` = 0 );
+
+ SELECT COUNT(*)
+ INTO del_mov_
+ FROM `film`
+ WHERE ( `touched` = 0 );
+
+ DELETE FROM `show`
+ WHERE ( `show`.`touched` = 0 )
+ AND
+ ( ( SELECT SUM( `film`.`touched` ) FROM `film` WHERE `film`.`showid` = `show`.`id` ) = 0 );
+
+ DELETE FROM `film`
+ WHERE ( `touched` = 0 );
+ ELSE
+ SET del_chn_ = 0;
+ SET del_shw_ = 0;
+ SET del_mov_ = 0;
+ END IF;
+
+ SELECT del_chn_ AS `del_chn`,
+ del_shw_ AS `del_shw`,
+ del_mov_ AS `del_mov`,
+ cnt_chn_ AS `cnt_chn`,
+ cnt_shw_ AS `cnt_shw`,
+ cnt_mov_ AS `cnt_mov`;
+END
+ """ )
+ self.conn.commit()
+
+ cursor.execute( """
+CREATE PROCEDURE `ftUpdateStart`(
+ _full INT(1)
+)
+BEGIN
+ DECLARE cnt_chn_ INT DEFAULT 0;
+ DECLARE cnt_shw_ INT DEFAULT 0;
+ DECLARE cnt_mov_ INT DEFAULT 0;
+
+ IF ( _full = 1 ) THEN
+ UPDATE `channel`
+ SET `touched` = 0;
+
+ UPDATE `show`
+ SET `touched` = 0;
+
+ UPDATE `film`
+ SET `touched` = 0;
+ END IF;
+
+ SELECT COUNT(*)
+ INTO cnt_chn_
+ FROM `channel`;
+
+ SELECT COUNT(*)
+ INTO cnt_shw_
+ FROM `show`;
+
+ SELECT COUNT(*)
+ INTO cnt_mov_
+ FROM `film`;
+
+ SELECT cnt_chn_ AS `cnt_chn`,
+ cnt_shw_ AS `cnt_shw`,
+ cnt_mov_ AS `cnt_mov`;
+END
+ """ )
+ self.conn.commit()
+
+ cursor.close()
+ self.logger.info( 'Database creation successfully completed' )
+ except mysql.connector.Error as err:
+ self.logger.error( '=== DATABASE CREATION ERROR: {} ===', err )
+ self.notifier.ShowDatabaseError( err )
+ try:
+ if dbcreated:
+ cursor.execute( 'DROP DATABASE `{}`'.format( self.settings.database ) )
+ self.conn.commit()
+ if cursor is not None:
+ cursor.close()
+ del cursor
+ if self.conn is not None:
+ self.conn.close()
+ self.conn = None
+ except mysql.connector.Error as err:
+ # should never happen
+ self.conn = None
diff --git a/plugin.video.mediathekview/classes/storesqlite.py b/plugin.video.mediathekview/resources/lib/storesqlite.py
index f73acdf..601db67 100644
--- a/plugin.video.mediathekview/classes/storesqlite.py
+++ b/plugin.video.mediathekview/resources/lib/storesqlite.py
@@ -3,11 +3,13 @@
#
# -- Imports ------------------------------------------------
-import os, stat, string, time
+import os, time
import sqlite3
-from classes.film import Film
-from classes.exceptions import DatabaseCorrupted
+import resources.lib.mvutils as mvutils
+
+from resources.lib.film import Film
+from resources.lib.exceptions import DatabaseCorrupted
# -- Classes ------------------------------------------------
class StoreSQLite( object ):
@@ -20,15 +22,16 @@ class StoreSQLite( object ):
self.dbfile = os.path.join( self.settings.datapath, 'filmliste-v1.db' )
# useful query fragments
self.sql_query_films = "SELECT film.id,title,show,channel,description,duration,size,datetime(aired, 'unixepoch', 'localtime'),url_sub,url_video,url_video_sd,url_video_hd FROM film LEFT JOIN show ON show.id=film.showid LEFT JOIN channel ON channel.id=film.channelid"
+ self.sql_query_filmcnt = "SELECT COUNT(*) FROM film LEFT JOIN show ON show.id=film.showid LEFT JOIN channel ON channel.id=film.channelid"
self.sql_cond_recent = "( ( UNIX_TIMESTAMP() - aired ) <= 86400 )"
self.sql_cond_nofuture = " AND ( ( aired IS NULL ) OR ( ( UNIX_TIMESTAMP() - aired ) > 0 ) )" if settings.nofuture else ""
self.sql_cond_minlength = " AND ( ( duration IS NULL ) OR ( duration >= %d ) )" % settings.minlength if settings.minlength > 0 else ""
def Init( self, reset = False ):
self.logger.info( 'Using SQLite version {}, python library sqlite3 version {}', sqlite3.sqlite_version, sqlite3.version )
- if not self._dir_exists( self.settings.datapath ):
+ if not mvutils.dir_exists( self.settings.datapath ):
os.mkdir( self.settings.datapath )
- if reset == True or not self._file_exists( self.dbfile ):
+ if reset == True or not mvutils.file_exists( self.dbfile ):
self.logger.info( '===== RESET: Database will be deleted and regenerated =====' )
self._file_remove( self.dbfile )
self.conn = sqlite3.connect( self.dbfile, timeout = 60 )
@@ -37,12 +40,12 @@ class StoreSQLite( object ):
try:
self.conn = sqlite3.connect( self.dbfile, timeout = 60 )
except sqlite3.DatabaseError as err:
- self.logger.error( 'Errore while opening database. Trying to fully reset the Database...' )
+ self.logger.error( 'Error while opening database: {}. trying to fully reset the Database...', err )
self.Init( reset = True )
self.conn.execute( 'pragma journal_mode=off' ) # 3x speed-up, check mode 'WAL'
self.conn.execute( 'pragma synchronous=off' ) # that is a bit dangerous :-) but faaaast
-
+
self.conn.create_function( 'UNIX_TIMESTAMP', 0, UNIX_TIMESTAMP )
self.conn.create_aggregate( 'GROUP_CONCAT', 1, GROUP_CONCAT )
@@ -52,17 +55,17 @@ class StoreSQLite( object ):
self.conn = None
def Search( self, search, filmui ):
- self._Search_Condition( '( ( title LIKE "%%%s%%" ) OR ( show LIKE "%%%s%%" ) )' % ( search, search ), filmui, True, True )
+ self._Search_Condition( '( ( title LIKE "%%%s%%" ) OR ( show LIKE "%%%s%%" ) )' % ( search, search ), filmui, True, True, self.settings.maxresults )
def SearchFull( self, search, filmui ):
- self._Search_Condition( '( ( title LIKE "%%%s%%" ) OR ( show LIKE "%%%s%%" ) OR ( description LIKE "%%%s%%") )' % ( search, search, search ), filmui, True, True )
+ self._Search_Condition( '( ( title LIKE "%%%s%%" ) OR ( show LIKE "%%%s%%" ) OR ( description LIKE "%%%s%%") )' % ( search, search, search ), filmui, True, True, self.settings.maxresults )
def GetRecents( self, channelid, filmui ):
sql_cond_channel = ' AND ( film.channelid=' + str( channelid ) + ' ) ' if channelid != '0' else ''
- self._Search_Condition( self.sql_cond_recent + sql_cond_channel, filmui, True, False )
+ self._Search_Condition( self.sql_cond_recent + sql_cond_channel, filmui, True, False, 10000 )
def GetLiveStreams( self, filmui ):
- self._Search_Condition( '( show.search="LIVESTREAM" )', filmui, False, False )
+ self._Search_Condition( '( show.search="LIVESTREAM" )', filmui, False, False, 10000 )
def GetChannels( self, channelui ):
self._Channels_Condition( None, channelui )
@@ -70,32 +73,12 @@ class StoreSQLite( object ):
def GetRecentChannels( self, channelui ):
self._Channels_Condition( self.sql_cond_recent, channelui )
- def _Channels_Condition( self, condition, channelui):
- if self.conn is None:
- return
- try:
- if condition is None:
- query = 'SELECT id,channel,0 AS `count` FROM channel'
- else:
- query = 'SELECT channel.id AS `id`,channel,COUNT(*) AS `count` FROM film LEFT JOIN channel ON channel.id=film.channelid WHERE ' + condition + ' GROUP BY channel'
- self.logger.info( 'SQLite Query: {}', query )
- cursor = self.conn.cursor()
- cursor.execute( query )
- channelui.Begin()
- for ( channelui.id, channelui.channel, channelui.count ) in cursor:
- channelui.Add()
- channelui.End()
- cursor.close()
- except sqlite3.Error as err:
- self.logger.error( 'Database error: {}', err )
- self.notifier.ShowDatabaseError( err )
-
def GetInitials( self, channelid, initialui ):
if self.conn is None:
return
try:
condition = 'WHERE ( channelid=' + str( channelid ) + ' ) ' if channelid != '0' else ''
- self.logger.info( 'SQlite Query: {}',
+ self.logger.info( 'SQlite Query: {}',
'SELECT SUBSTR(search,1,1),COUNT(*) FROM show ' +
condition +
'GROUP BY LEFT(search,1)'
@@ -148,13 +131,34 @@ class StoreSQLite( object ):
# multiple channel ids
condition = '( showid IN ( %s ) )' % showid
showchannels = True
- self._Search_Condition( condition, filmui, False, showchannels )
+ self._Search_Condition( condition, filmui, False, showchannels, 10000 )
- def _Search_Condition( self, condition, filmui, showshows, showchannels ):
+ def _Channels_Condition( self, condition, channelui ):
if self.conn is None:
return
try:
- self.logger.info( 'SQLite Query: {}',
+ if condition is None:
+ query = 'SELECT id,channel,0 AS `count` FROM channel'
+ else:
+ query = 'SELECT channel.id AS `id`,channel,COUNT(*) AS `count` FROM film LEFT JOIN channel ON channel.id=film.channelid WHERE ' + condition + ' GROUP BY channel'
+ self.logger.info( 'SQLite Query: {}', query )
+ cursor = self.conn.cursor()
+ cursor.execute( query )
+ channelui.Begin()
+ for ( channelui.id, channelui.channel, channelui.count ) in cursor:
+ channelui.Add()
+ channelui.End()
+ cursor.close()
+ except sqlite3.Error as err:
+ self.logger.error( 'Database error: {}', err )
+ self.notifier.ShowDatabaseError( err )
+
+ def _Search_Condition( self, condition, filmui, showshows, showchannels, maxresults ):
+ if self.conn is None:
+ return
+ try:
+ maxresults = int( maxresults )
+ self.logger.info( 'SQLite Query: {}',
self.sql_query_films +
' WHERE ' +
condition +
@@ -163,15 +167,27 @@ class StoreSQLite( object ):
)
cursor = self.conn.cursor()
cursor.execute(
+ self.sql_query_filmcnt +
+ ' WHERE ' +
+ condition +
+ self.sql_cond_nofuture +
+ self.sql_cond_minlength +
+ ' LIMIT {}'.format( maxresults + 1 ) if maxresults else ''
+ )
+ ( results, ) = cursor.fetchone()
+ if maxresults and results > maxresults:
+ self.notifier.ShowLimitResults( maxresults )
+ cursor.execute(
self.sql_query_films +
' WHERE ' +
condition +
self.sql_cond_nofuture +
- self.sql_cond_minlength
+ self.sql_cond_minlength +
+ ' LIMIT {}'.format( maxresults ) if maxresults else ''
)
filmui.Begin( showshows, showchannels )
for ( filmui.id, filmui.title, filmui.show, filmui.channel, filmui.description, filmui.seconds, filmui.size, filmui.aired, filmui.url_sub, filmui.url_video, filmui.url_video_sd, filmui.url_video_hd ) in cursor:
- filmui.Add()
+ filmui.Add( totalItems = results )
filmui.End()
cursor.close()
except sqlite3.Error as err:
@@ -183,7 +199,7 @@ class StoreSQLite( object ):
return None
try:
condition = '( film.id={} )'.format( filmid )
- self.logger.info( 'SQLite Query: {}',
+ self.logger.info( 'SQLite Query: {}',
self.sql_query_films +
' WHERE ' +
condition
@@ -523,7 +539,7 @@ class StoreSQLite( object ):
""", (
int( time.time() ),
self.ft_channelid, film['show'],
- self._make_search( film['show'] )
+ mvutils.make_search_string( film['show'] )
)
)
self.ft_show = film['show']
@@ -589,9 +605,9 @@ class StoreSQLite( object ):
self.ft_channelid,
self.ft_showid,
film['title'],
- self._make_search( film['title'] ),
+ mvutils.make_search_string( film['title'] ),
film['airedepoch'],
- self._make_duration( film['duration'] ),
+ mvutils.make_duration( film['duration'] ),
film['size'],
film['description'],
film['website'],
@@ -710,37 +726,8 @@ PRAGMA foreign_keys = true;
""" )
self.UpdateStatus( 'IDLE' )
- def _make_search( self, val ):
- cset = string.letters + string.digits + ' _-#'
- search = ''.join( [ c for c in val if c in cset ] )
- return search.upper().strip()
-
- def _make_duration( self, val ):
- if val == "00:00:00":
- return None
- elif val is None:
- return None
- x = val.split( ':' )
- if len( x ) != 3:
- return None
- return int( x[0] ) * 3600 + int( x[1] ) * 60 + int( x[2] )
-
- def _dir_exists( self, name ):
- try:
- s = os.stat( name )
- return stat.S_ISDIR( s.st_mode )
- except OSError as err:
- return False
-
- def _file_exists( self, name ):
- try:
- s = os.stat( name )
- return stat.S_ISREG( s.st_mode )
- except OSError as err:
- return False
-
def _file_remove( self, name ):
- if self._file_exists( name ):
+ if mvutils.file_exists( name ):
try:
os.remove( name )
return True
diff --git a/plugin.video.mediathekview/classes/ttml2srt.py b/plugin.video.mediathekview/resources/lib/ttml2srt.py
index e36b41e..7bfdc47 100644
--- a/plugin.video.mediathekview/classes/ttml2srt.py
+++ b/plugin.video.mediathekview/resources/lib/ttml2srt.py
@@ -26,7 +26,6 @@
import re
import io
-import sys
from datetime import timedelta
from xml.etree import ElementTree as ET
@@ -135,7 +134,7 @@ def ttml2srt( infile, outfile ):
# render subtitles on each timestamp
- def render_subtitles(elem, timestamp, parent_style={}):
+ def render_subtitles(elem, timestamp, parent_style=None):
if timestamp < elem.attrib['{abs}begin']:
return ''
@@ -144,7 +143,7 @@ def ttml2srt( infile, outfile ):
result = ''
- style = parent_style.copy()
+ style = parent_style.copy() if parent_style is not None else {}
if 'style' in elem.attrib:
style.update(styles[elem.attrib['style']])
@@ -200,7 +199,7 @@ def ttml2srt( infile, outfile ):
timestamp.total_seconds() % 60)).replace('.', ',')
- if type( outfile ) is str or type( outfile ) is unicode:
+ if isinstance( outfile, str ) or isinstance( outfile, unicode ):
file = io.open( outfile, 'w', encoding='utf-8' )
else:
file = outfile
@@ -210,7 +209,7 @@ def ttml2srt( infile, outfile ):
if content == '':
continue
file.write( bytearray( '%d\n' % srt_i, 'utf-8' ) )
- file.write( bytearray(
+ file.write( bytearray(
format_timestamp( timestamp ) +
' --> ' +
format_timestamp( rendered_grouped[i + 1][0] ) +
diff --git a/plugin.video.mediathekview/classes/updater.py b/plugin.video.mediathekview/resources/lib/updater.py
index 8609303..afdf840 100644
--- a/plugin.video.mediathekview/classes/updater.py
+++ b/plugin.video.mediathekview/resources/lib/updater.py
@@ -2,13 +2,32 @@
# Copyright (c) 2017-2018, Leo Moll
# -- Imports ------------------------------------------------
-import os, stat, urllib, urllib2, subprocess, ijson, datetime, time
+import os, urllib2, subprocess, ijson, datetime, time
import xml.etree.ElementTree as etree
+import resources.lib.mvutils as mvutils
+
from operator import itemgetter
-from classes.store import Store
-from classes.exceptions import DatabaseCorrupted
-from classes.exceptions import DatabaseLost
+#from resources.lib.utils import *
+from resources.lib.store import Store
+from resources.lib.exceptions import DatabaseCorrupted
+from resources.lib.exceptions import DatabaseLost
+
+# -- Unpacker support ---------------------------------------
+upd_can_bz2 = False
+upd_can_gz = False
+
+try:
+ import bz2
+ upd_can_bz2 = True
+except ImportError:
+ pass
+
+try:
+ import gzip
+ upd_can_gz = True
+except ImportError:
+ pass
# -- Constants ----------------------------------------------
FILMLISTE_AKT_URL = 'https://res.mediathekview.de/akt.xml'
@@ -22,6 +41,7 @@ class MediathekViewUpdater( object ):
self.settings = settings
self.monitor = monitor
self.db = None
+ self.use_xz = mvutils.find_xz() is not None
def Init( self ):
if self.db is not None:
@@ -35,13 +55,8 @@ class MediathekViewUpdater( object ):
del self.db
self.db = None
- def PrerequisitesMissing( self ):
- return self.settings.updenabled and self._find_xz() is None
-
def IsEnabled( self ):
- if self.settings.updenabled:
- xz = self._find_xz()
- return xz is not None
+ return self.settings.updenabled
def GetCurrentUpdateOperation( self ):
if not self.IsEnabled() or self.db is None:
@@ -57,7 +72,7 @@ class MediathekViewUpdater( object ):
# database not initialized
self.logger.debug( 'database not initialized' )
return 0
- elif status['status'] == "UPDATING" and tsnow - tsold > 86400:
+ elif status['status'] == "UPDATING" and tsnow - tsold > 10800:
# process was probably killed during update
self.logger.info( 'Stuck update pretending to run since epoch {} reset', tsold )
self.db.UpdateStatus( 'ABORTED' )
@@ -82,7 +97,7 @@ class MediathekViewUpdater( object ):
# do differential update
self.logger.debug( 'do differential update' )
return 2
-
+
def Update( self, full ):
if self.db is None:
return
@@ -91,71 +106,68 @@ class MediathekViewUpdater( object ):
self.Import( full )
def Import( self, full ):
- ( url, compfile, destfile, avgrecsize ) = self._get_update_info( full )
- if not self._file_exists( destfile ):
+ ( _, compfile, destfile, avgrecsize ) = self._get_update_info( full )
+ if not mvutils.file_exists( destfile ):
self.logger.error( 'File {} does not exists', destfile )
return False
# estimate number of records in update file
- records = int( self._file_size( destfile ) / avgrecsize )
+ records = int( mvutils.file_size( destfile ) / avgrecsize )
if not self.db.ftInit():
self.logger.warn( 'Failed to initialize update. Maybe a concurrency problem?' )
return False
try:
self.logger.info( 'Starting import of approx. {} records from {}', records, destfile )
- file = open( destfile, 'r' )
- parser = ijson.parse( file )
- flsm = 0
- flts = 0
- ( self.tot_chn, self.tot_shw, self.tot_mov ) = self._update_start( full )
- self.notifier.ShowUpdateProgress()
- for prefix, event, value in parser:
- if ( prefix, event ) == ( "X", "start_array" ):
- self._init_record()
- elif ( prefix, event ) == ( "X", "end_array" ):
- self._end_record( records )
- if self.count % 100 == 0 and self.monitor.abortRequested():
- # kodi is shutting down. Close all
- file.close()
- self._update_end( full, 'ABORTED' )
- self.notifier.CloseUpdateProgress()
- return True
- elif ( prefix, event ) == ( "X.item", "string" ):
- if value is not None:
-# self._add_value( value.strip().encode('utf-8') )
- self._add_value( value.strip() )
- else:
- self._add_value( "" )
- elif ( prefix, event ) == ( "Filmliste", "start_array" ):
- flsm += 1
- elif ( prefix, event ) == ( "Filmliste.item", "string" ):
- flsm += 1
- if flsm == 2 and value is not None:
- # this is the timestmap of this database update
- try:
- fldt = datetime.datetime.strptime( value.strip(), "%d.%m.%Y, %H:%M" )
- flts = int( time.mktime( fldt.timetuple() ) )
- self.db.UpdateStatus( filmupdate = flts )
- self.logger.info( 'Filmliste dated {}', value.strip() )
- except TypeError:
- # SEE: https://forum.kodi.tv/showthread.php?tid=112916&pid=1214507#pid1214507
- # Wonderful. His name is also Leopold
+ with open( destfile, 'r' ) as file:
+ parser = ijson.parse( file )
+ flsm = 0
+ flts = 0
+ ( self.tot_chn, self.tot_shw, self.tot_mov ) = self._update_start( full )
+ self.notifier.ShowUpdateProgress()
+ for prefix, event, value in parser:
+ if ( prefix, event ) == ( "X", "start_array" ):
+ self._init_record()
+ elif ( prefix, event ) == ( "X", "end_array" ):
+ self._end_record( records )
+ if self.count % 100 == 0 and self.monitor.abortRequested():
+ # kodi is shutting down. Close all
+ self._update_end( full, 'ABORTED' )
+ self.notifier.CloseUpdateProgress()
+ return True
+ elif ( prefix, event ) == ( "X.item", "string" ):
+ if value is not None:
+ # self._add_value( value.strip().encode('utf-8') )
+ self._add_value( value.strip() )
+ else:
+ self._add_value( "" )
+ elif ( prefix, event ) == ( "Filmliste", "start_array" ):
+ flsm += 1
+ elif ( prefix, event ) == ( "Filmliste.item", "string" ):
+ flsm += 1
+ if flsm == 2 and value is not None:
+ # this is the timestmap of this database update
try:
- flts = int( time.mktime( time.strptime( value.strip(), "%d.%m.%Y, %H:%M" ) ) )
+ fldt = datetime.datetime.strptime( value.strip(), "%d.%m.%Y, %H:%M" )
+ flts = int( time.mktime( fldt.timetuple() ) )
self.db.UpdateStatus( filmupdate = flts )
self.logger.info( 'Filmliste dated {}', value.strip() )
- except Exception as err:
- # If the universe hates us...
+ except TypeError:
+ # SEE: https://forum.kodi.tv/showthread.php?tid=112916&pid=1214507#pid1214507
+ # Wonderful. His name is also Leopold
+ try:
+ flts = int( time.mktime( time.strptime( value.strip(), "%d.%m.%Y, %H:%M" ) ) )
+ self.db.UpdateStatus( filmupdate = flts )
+ self.logger.info( 'Filmliste dated {}', value.strip() )
+ except Exception as err:
+ # If the universe hates us...
+ self.logger.debug( 'Could not determine date "{}" of filmliste: {}', value.strip(), err )
+ except ValueError as err:
pass
- except ValueError as err:
- pass
- file.close()
self._update_end( full, 'IDLE' )
self.logger.info( 'Import of {} finished', destfile )
self.notifier.CloseUpdateProgress()
return True
except KeyboardInterrupt:
- file.close()
self._update_end( full, 'ABORTED' )
self.logger.info( 'Interrupted by user' )
self.notifier.CloseUpdateProgress()
@@ -163,29 +175,21 @@ class MediathekViewUpdater( object ):
except DatabaseCorrupted as err:
self.logger.error( '{}', err )
self.notifier.CloseUpdateProgress()
- file.close()
except DatabaseLost as err:
self.logger.error( '{}', err )
self.notifier.CloseUpdateProgress()
- file.close()
except IOError as err:
self.logger.error( 'Error {} wile processing {}', err, destfile )
- try:
- self._update_end( full, 'ABORTED' )
- self.notifier.CloseUpdateProgress()
- file.close()
- except Exception as err:
- pass
- return False
+ self._update_end( full, 'ABORTED' )
+ self.notifier.CloseUpdateProgress()
+ return False
def GetNewestList( self, full ):
- # get xz binary
- xzbin = self._find_xz()
- if xzbin is None:
- self.notifier.ShowMissingXZError()
- return False
-
( url, compfile, destfile, avgrecsize ) = self._get_update_info( full )
+ if url is None:
+ self.logger.error( 'No suitable archive extractor available for this system' )
+ self.notifier.ShowMissingExtractorError()
+ return False
# get mirrorlist
self.logger.info( 'Opening {}', url )
@@ -193,7 +197,7 @@ class MediathekViewUpdater( object ):
data = urllib2.urlopen( url ).read()
except urllib2.URLError as err:
self.logger.error( 'Failure opening {}', url )
- self.notifier.ShowDowloadError( url, err )
+ self.notifier.ShowDownloadError( url, err )
return False
root = etree.fromstring ( data )
@@ -202,9 +206,9 @@ class MediathekViewUpdater( object ):
try:
URL = server.find( 'URL' ).text
Prio = server.find( 'Prio' ).text
- urls.append( ( URL, Prio ) )
+ urls.append( ( self._get_update_url( URL ), Prio ) )
self.logger.info( 'Found mirror {} (Priority {})', URL, Prio )
- except AttributeError as error:
+ except AttributeError:
pass
urls = sorted( urls, key = itemgetter( 1 ) )
urls = [ url[0] for url in urls ]
@@ -216,70 +220,83 @@ class MediathekViewUpdater( object ):
self._file_remove( destfile )
# download filmliste
- self.logger.info( 'Trying to download file...' )
self.notifier.ShowDownloadProgress()
lasturl = ''
for url in urls:
try:
lasturl = url
+ self.logger.info( 'Trying to download {} from {}...', os.path.basename( compfile ), url )
self.notifier.UpdateDownloadProgress( 0, url )
- result = urllib.urlretrieve( url, filename = compfile, reporthook = self._reporthook )
+ result = mvutils.url_retrieve( url, filename = compfile, reporthook = self._reporthook )
break
- except IOError as err:
- self.logger.error( 'Failure opening {}', url )
+ except urllib2.URLError as err:
+ self.logger.error( 'Failure downloading {}', url )
+ except Exception as err:
+ self.logger.error( 'Failure writng {}', url )
if result is None:
self.logger.info( 'No file downloaded' )
self.notifier.CloseDownloadProgress()
- self.notifier.ShowDowloadError( lasturl, err )
+ self.notifier.ShowDownloadError( lasturl, err )
return False
# decompress filmliste
- self.logger.info( 'Trying to decompress file...' )
- retval = subprocess.call( [ xzbin, '-d', compfile ] )
- self.logger.info( 'Return {}', retval )
+ if self.use_xz is True:
+ self.logger.info( 'Trying to decompress xz file...' )
+ retval = subprocess.call( [ mvutils.find_xz(), '-d', compfile ] )
+ self.logger.info( 'Return {}', retval )
+ elif upd_can_bz2 is True:
+ self.logger.info( 'Trying to decompress bz2 file...' )
+ retval = self._decompress_bz2( compfile, destfile )
+ self.logger.info( 'Return {}', retval )
+ elif upd_can_gz is True:
+ self.logger.info( 'Trying to decompress gz file...' )
+ retval = self._decompress_gz( compfile, destfile )
+ self.logger.info( 'Return {}', retval )
+ else:
+ # should nebver reach
+ pass
+
self.notifier.CloseDownloadProgress()
- return retval == 0 and self._file_exists( destfile )
+ return retval == 0 and mvutils.file_exists( destfile )
def _get_update_info( self, full ):
+ if self.use_xz is True:
+ ext = 'xz'
+ elif upd_can_bz2 is True:
+ ext = 'bz2'
+ elif upd_can_gz is True:
+ ext = 'gz'
+ else:
+ return ( None, None, None, 0, )
+
if full:
return (
FILMLISTE_AKT_URL,
- os.path.join( self.settings.datapath, 'Filmliste-akt.xz' ),
+ os.path.join( self.settings.datapath, 'Filmliste-akt.' + ext ),
os.path.join( self.settings.datapath, 'Filmliste-akt' ),
600,
)
else:
return (
FILMLISTE_DIF_URL,
- os.path.join( self.settings.datapath, 'Filmliste-diff.xz' ),
+ os.path.join( self.settings.datapath, 'Filmliste-diff.' + ext ),
os.path.join( self.settings.datapath, 'Filmliste-diff' ),
700,
)
-
- def _find_xz( self ):
- for xzbin in [ '/bin/xz', '/usr/bin/xz', '/usr/local/bin/xz' ]:
- if self._file_exists( xzbin ):
- return xzbin
- if self.settings.updxzbin != '' and self._file_exists( self.settings.updxzbin ):
- return self.settings.updxzbin
- return None
-
- def _file_exists( self, name ):
- try:
- s = os.stat( name )
- return stat.S_ISREG( s.st_mode )
- except OSError as err:
- return False
- def _file_size( self, name ):
- try:
- s = os.stat( name )
- return s.st_size
- except OSError as err:
- return 0
+ def _get_update_url( self, url ):
+ if self.use_xz is True:
+ return url
+ elif upd_can_bz2 is True:
+ return os.path.splitext( url )[0] + '.bz2'
+ elif upd_can_gz is True:
+ return os.path.splitext( url )[0] + '.gz'
+ else:
+ # should never happen since it will not be called
+ return None
def _file_remove( self, name ):
- if self._file_exists( name ):
+ if mvutils.file_exists( name ):
try:
os.remove( name )
return True
@@ -369,10 +386,10 @@ class MediathekViewUpdater( object ):
tot_mov = self.tot_mov + self.add_mov
)
self.count = self.count + 1
- ( filmid, cnt_chn, cnt_shw, cnt_mov ) = self.db.ftInsertFilm( self.film, True )
+ ( _, cnt_chn, cnt_shw, cnt_mov ) = self.db.ftInsertFilm( self.film, True )
else:
self.count = self.count + 1
- ( filmid, cnt_chn, cnt_shw, cnt_mov ) = self.db.ftInsertFilm( self.film, False )
+ ( _, cnt_chn, cnt_shw, cnt_mov ) = self.db.ftInsertFilm( self.film, False )
self.add_chn += cnt_chn
self.add_shw += cnt_shw
self.add_mov += cnt_mov
@@ -417,11 +434,6 @@ class MediathekViewUpdater( object ):
self.film["geo"] = val
self.index = self.index + 1
- def _make_search( self, val ):
- cset = string.letters + string.digits + ' _-#'
- search = ''.join( [ c for c in val if c in cset ] )
- return search.upper().strip()
-
def _make_url( self, val ):
x = val.split( '|' )
if len( x ) == 2:
@@ -429,3 +441,26 @@ class MediathekViewUpdater( object ):
return self.film["url_video"][:cnt] + x[1]
else:
return val
+
+ def _decompress_bz2( self, sourcefile, destfile ):
+ blocksize = 8192
+ try:
+ with open( destfile, 'wb' ) as df, open( sourcefile, 'rb' ) as sf:
+ decompressor = bz2.BZ2Decompressor()
+ for data in iter( lambda : sf.read( blocksize ), b'' ):
+ df.write( decompressor.decompress( data ) )
+ except Exception as err:
+ self.logger.error( 'bz2 decompression failed: {}'.format( err ) )
+ return -1
+ return 0
+
+ def _decompress_gz( self, sourcefile, destfile ):
+ blocksize = 8192
+ try:
+ with open( destfile, 'wb' ) as df, gzip.open( sourcefile ) as sf:
+ for data in iter( lambda : sf.read( blocksize ), b'' ):
+ df.write( data )
+ except Exception as err:
+ self.logger.error( 'gz decompression failed: {}'.format( err ) )
+ return -1
+ return 0
diff --git a/plugin.video.mediathekview/resources/settings.xml b/plugin.video.mediathekview/resources/settings.xml
index b50510a..a1ef62b 100644
--- a/plugin.video.mediathekview/resources/settings.xml
+++ b/plugin.video.mediathekview/resources/settings.xml
@@ -1,19 +1,21 @@
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<settings>
<category label="30001">
- <setting id="firstrun" type="bool" default="true" visible="false" />
- <setting id="quality" type="bool" label="30110" default="true" />
- <setting id="nofuture" type="bool" label="30111" default="true" />
- <setting id="minlength" type="slider" label="30112" default="0" range="0,30" />
- <setting id="groupshows" type="bool" label="30113" default="true" />
- <setting id="downloadpath" type="folder" label="30114" source="auto" option="writeable" />
+ <setting id="firstrun" type="bool" default="true" visible="false" />
+ <setting id="quality" type="bool" label="30110" default="true" />
+ <setting id="nofuture" type="bool" label="30111" default="true" />
+ <setting id="minlength" type="slider" label="30112" default="0" range="0,30" />
+ <setting id="groupshows" type="bool" label="30113" default="true" />
+ <setting id="maxresults" type="slider" label="30114" default="1000" range="100,100,3000" option="int" />
+ <setting id="downloadpath" type="folder" label="30115" source="auto" option="writeable" />
</category>
<category label="30002">
<setting id="dbtype" type="enum" label="30210" default="0" lvalues="30221|30222" />
<setting id="dbhost" type="text" label="30211" default="localhost" visible="eq(-1,1)" />
- <setting id="dbuser" type="text" label="30212" default="filmliste" visible="eq(-2,1)" />
- <setting id="dbpass" type="text" label="30213" default="" option="hidden" visible="eq(-3,1)" />
- <setting id="dbdata" type="text" label="30214" default="filmliste" visible="eq(-4,1)" />
+ <setting id="dbport" type="number" label="30212" default="3306" visible="eq(-2,1)" />
+ <setting id="dbuser" type="text" label="30213" default="mediathekview" visible="eq(-3,1)" />
+ <setting id="dbpass" type="text" label="30214" default="" option="hidden" visible="eq(-4,1)" />
+ <setting id="dbdata" type="text" label="30215" default="mediathekview" visible="eq(-5,1)" />
<setting id="updenabled" type="bool" label="30231" default="true" />
<setting id="updinterval" type="slider" label="30232" default="2" range="1,24" visible="eq(-1,true)" />
<setting id="updxzbin" type="file" label="30233" default="" visible="eq(-2,true)" />
diff --git a/plugin.video.mediathekview/resources/sql/exportstruct.sh b/plugin.video.mediathekview/resources/sql/exportstruct.sh
deleted file mode 100755
index 04c18a6..0000000
--- a/plugin.video.mediathekview/resources/sql/exportstruct.sh
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/bin/bash
-mysqldump -u root -p --add-drop-database --add-drop-table --events --routines --no-data --databases filmliste > filmliste-init-0.sql
-sed -i'' -e 's/ AUTO_INCREMENT=[0-9]*//g' filmliste-init-0.sql
diff --git a/plugin.video.mediathekview/resources/sql/filmliste-mysql-v1.sql b/plugin.video.mediathekview/resources/sql/filmliste-mysql-v1.sql
deleted file mode 100644
index 341fb74..0000000
--- a/plugin.video.mediathekview/resources/sql/filmliste-mysql-v1.sql
+++ /dev/null
@@ -1,454 +0,0 @@
--- MySQL dump 10.13 Distrib 5.7.20, for osx10.13 (x86_64)
---
--- Host: localhost Database: filmliste
--- ------------------------------------------------------
--- Server version 5.7.20
-
-/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
-/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
-/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
-/*!40101 SET NAMES utf8 */;
-/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
-/*!40103 SET TIME_ZONE='+00:00' */;
-/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
-/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
-/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
-/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
-
---
--- Current Database: `filmliste`
---
-
-/*!40000 DROP DATABASE IF EXISTS `filmliste`*/;
-
-CREATE DATABASE /*!32312 IF NOT EXISTS*/ `filmliste` /*!40100 DEFAULT CHARACTER SET utf8 */;
-
-USE `filmliste`;
-
---
--- Table structure for table `channel`
---
-
-DROP TABLE IF EXISTS `channel`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `channel` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `dtCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `touched` smallint(1) NOT NULL DEFAULT '1',
- `channel` varchar(255) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `channel` (`channel`)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `film`
---
-
-DROP TABLE IF EXISTS `film`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `film` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `dtCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `touched` smallint(1) NOT NULL DEFAULT '1',
- `channelid` int(11) NOT NULL,
- `showid` int(11) NOT NULL,
- `title` varchar(255) NOT NULL,
- `search` varchar(255) NOT NULL,
- `aired` timestamp NULL DEFAULT NULL,
- `duration` time DEFAULT NULL,
- `size` int(11) DEFAULT NULL,
- `description` longtext,
- `website` varchar(384) DEFAULT NULL,
- `url_sub` varchar(384) DEFAULT NULL,
- `url_video` varchar(384) DEFAULT NULL,
- `url_video_sd` varchar(384) DEFAULT NULL,
- `url_video_hd` varchar(384) DEFAULT NULL,
- `airedepoch` int(11) DEFAULT NULL,
- PRIMARY KEY (`id`),
- KEY `index_1` (`showid`,`title`),
- KEY `index_2` (`channelid`,`title`),
- KEY `dupecheck` (`channelid`,`showid`,`url_video`),
- CONSTRAINT `FK_FilmChannel` FOREIGN KEY (`channelid`) REFERENCES `channel` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION,
- CONSTRAINT `FK_FilmShow` FOREIGN KEY (`showid`) REFERENCES `show` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `show`
---
-
-DROP TABLE IF EXISTS `show`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `show` (
- `id` int(11) NOT NULL AUTO_INCREMENT,
- `dtCreated` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
- `touched` smallint(1) NOT NULL DEFAULT '1',
- `channelid` int(11) NOT NULL,
- `show` varchar(255) NOT NULL,
- `search` varchar(255) NOT NULL,
- PRIMARY KEY (`id`),
- KEY `show` (`show`),
- KEY `search` (`search`),
- KEY `combined_1` (`channelid`,`search`),
- KEY `combined_2` (`channelid`,`show`),
- CONSTRAINT `FK_ShowChannel` FOREIGN KEY (`channelid`) REFERENCES `channel` (`id`) ON DELETE CASCADE ON UPDATE NO ACTION
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Table structure for table `status`
---
-
-DROP TABLE IF EXISTS `status`;
-/*!40101 SET @saved_cs_client = @@character_set_client */;
-/*!40101 SET character_set_client = utf8 */;
-CREATE TABLE `status` (
- `modified` int(11) NOT NULL,
- `status` varchar(255) NOT NULL,
- `lastupdate` int(11) NOT NULL,
- `filmupdate` int(11) NOT NULL,
- `fullupdate` int(1) NOT NULL,
- `add_chn` int(11) NOT NULL,
- `add_shw` int(11) NOT NULL,
- `add_mov` int(11) NOT NULL,
- `del_chm` int(11) NOT NULL,
- `del_shw` int(11) NOT NULL,
- `del_mov` int(11) NOT NULL,
- `tot_chn` int(11) NOT NULL,
- `tot_shw` int(11) NOT NULL,
- `tot_mov` int(11) NOT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-/*!40101 SET character_set_client = @saved_cs_client */;
-
---
--- Dumping data for table `status`
---
-
-LOCK TABLES `status` WRITE;
-/*!40000 ALTER TABLE `status` DISABLE KEYS */;
-INSERT INTO `status` VALUES (0,'IDLE',0,0,0,0,0,0,0,0,0,0,0,0);
-/*!40000 ALTER TABLE `status` ENABLE KEYS */;
-UNLOCK TABLES;
-
---
--- Dumping routines for database 'filmliste'
---
-/*!50003 DROP PROCEDURE IF EXISTS `ftInsertChannel` */;
-/*!50003 SET @saved_cs_client = @@character_set_client */ ;
-/*!50003 SET @saved_cs_results = @@character_set_results */ ;
-/*!50003 SET @saved_col_connection = @@collation_connection */ ;
-/*!50003 SET character_set_client = utf8 */ ;
-/*!50003 SET character_set_results = utf8 */ ;
-/*!50003 SET collation_connection = utf8_general_ci */ ;
-/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
-/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
-DELIMITER ;;
-CREATE DEFINER=`root`@`localhost` PROCEDURE `ftInsertChannel`(
- _channel VARCHAR(255)
-)
-BEGIN
- DECLARE channelid_ INT(11);
- DECLARE touched_ INT(1);
- DECLARE added_ INT(1) DEFAULT 0;
-
- SELECT `id`,
- `touched`
- INTO channelid_,
- touched_
- FROM `channel`
- WHERE ( `channel`.`channel` = _channel );
-
- IF ( channelid_ IS NULL ) THEN
- INSERT INTO `channel` (
- `channel`
- )
- VALUES (
- _channel
- );
- SET channelid_ = LAST_INSERT_ID();
- SET added_ = 1;
- ELSE
- UPDATE `channel`
- SET `touched` = 1
- WHERE ( `id` = channelid_ );
- END IF;
-
- SELECT channelid_ AS `id`,
- added_ AS `added`;
-END ;;
-DELIMITER ;
-/*!50003 SET sql_mode = @saved_sql_mode */ ;
-/*!50003 SET character_set_client = @saved_cs_client */ ;
-/*!50003 SET character_set_results = @saved_cs_results */ ;
-/*!50003 SET collation_connection = @saved_col_connection */ ;
-/*!50003 DROP PROCEDURE IF EXISTS `ftInsertFilm` */;
-/*!50003 SET @saved_cs_client = @@character_set_client */ ;
-/*!50003 SET @saved_cs_results = @@character_set_results */ ;
-/*!50003 SET @saved_col_connection = @@collation_connection */ ;
-/*!50003 SET character_set_client = utf8 */ ;
-/*!50003 SET character_set_results = utf8 */ ;
-/*!50003 SET collation_connection = utf8_general_ci */ ;
-/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
-/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
-DELIMITER ;;
-CREATE DEFINER=`root`@`localhost` PROCEDURE `ftInsertFilm`(
- _channelid INT(11),
- _showid INT(11),
- _title VARCHAR(255),
- _search VARCHAR(255),
- _aired TIMESTAMP,
- _duration TIME,
- _size INT(11),
- _description LONGTEXT,
- _website VARCHAR(384),
- _url_sub VARCHAR(384),
- _url_video VARCHAR(384),
- _url_video_sd VARCHAR(384),
- _url_video_hd VARCHAR(384),
- _airedepoch INT(11)
-)
-BEGIN
- DECLARE id_ INT;
- DECLARE added_ INT DEFAULT 0;
-
- SELECT `id`
- INTO id_
- FROM `film` AS f
- WHERE ( f.channelid = _channelid )
- AND
- ( f.showid = _showid )
- AND
- ( f.url_video = _url_video );
-
- IF ( id_ IS NULL ) THEN
- INSERT INTO `film` (
- `channelid`,
- `showid`,
- `title`,
- `search`,
- `aired`,
- `duration`,
- `size`,
- `description`,
- `website`,
- `url_sub`,
- `url_video`,
- `url_video_sd`,
- `url_video_hd`,
- `airedepoch`
- )
- VALUES (
- _channelid,
- _showid,
- _title,
- _search,
- IF(_aired = "1980-01-01 00:00:00", NULL, _aired),
- IF(_duration = "00:00:00", NULL, _duration),
- _size,
- _description,
- _website,
- _url_sub,
- _url_video,
- _url_video_sd,
- _url_video_hd,
- _airedepoch
- );
- SET id_ = LAST_INSERT_ID();
- SET added_ = 1;
- ELSE
- UPDATE `film`
- SET `touched` = 1
- WHERE ( `id` = id_ );
- END IF;
- SELECT id_ AS `id`,
- added_ AS `added`;
-END ;;
-DELIMITER ;
-/*!50003 SET sql_mode = @saved_sql_mode */ ;
-/*!50003 SET character_set_client = @saved_cs_client */ ;
-/*!50003 SET character_set_results = @saved_cs_results */ ;
-/*!50003 SET collation_connection = @saved_col_connection */ ;
-/*!50003 DROP PROCEDURE IF EXISTS `ftInsertShow` */;
-/*!50003 SET @saved_cs_client = @@character_set_client */ ;
-/*!50003 SET @saved_cs_results = @@character_set_results */ ;
-/*!50003 SET @saved_col_connection = @@collation_connection */ ;
-/*!50003 SET character_set_client = utf8 */ ;
-/*!50003 SET character_set_results = utf8 */ ;
-/*!50003 SET collation_connection = utf8_general_ci */ ;
-/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
-/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
-DELIMITER ;;
-CREATE DEFINER=`root`@`localhost` PROCEDURE `ftInsertShow`(
- _channelid INT(11),
- _show VARCHAR(255),
- _search VARCHAR(255)
-)
-BEGIN
- DECLARE showid_ INT(11);
- DECLARE touched_ INT(1);
- DECLARE added_ INT(1) DEFAULT 0;
-
- SELECT `id`,
- `touched`
- INTO showid_,
- touched_
- FROM `show`
- WHERE ( `show`.`channelid` = _channelid )
- AND
- ( `show`.`show` = _show );
-
- IF ( showid_ IS NULL ) THEN
- INSERT INTO `show` (
- `channelid`,
- `show`,
- `search`
- )
- VALUES (
- _channelid,
- _show,
- _search
- );
- SET showid_ = LAST_INSERT_ID();
- SET added_ = 1;
- ELSE
- UPDATE `show`
- SET `touched` = 1
- WHERE ( `id` = showid_ );
- END IF;
-
-
- SELECT showid_ AS `id`,
- added_ AS `added`;
-END ;;
-DELIMITER ;
-/*!50003 SET sql_mode = @saved_sql_mode */ ;
-/*!50003 SET character_set_client = @saved_cs_client */ ;
-/*!50003 SET character_set_results = @saved_cs_results */ ;
-/*!50003 SET collation_connection = @saved_col_connection */ ;
-/*!50003 DROP PROCEDURE IF EXISTS `ftUpdateEnd` */;
-/*!50003 SET @saved_cs_client = @@character_set_client */ ;
-/*!50003 SET @saved_cs_results = @@character_set_results */ ;
-/*!50003 SET @saved_col_connection = @@collation_connection */ ;
-/*!50003 SET character_set_client = utf8 */ ;
-/*!50003 SET character_set_results = utf8 */ ;
-/*!50003 SET collation_connection = utf8_general_ci */ ;
-/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
-/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
-DELIMITER ;;
-CREATE DEFINER=`root`@`localhost` PROCEDURE `ftUpdateEnd`(
- _full INT(1)
-)
-BEGIN
- DECLARE del_chn_ INT DEFAULT 0;
- DECLARE del_shw_ INT DEFAULT 0;
- DECLARE del_mov_ INT DEFAULT 0;
- DECLARE cnt_chn_ INT DEFAULT 0;
- DECLARE cnt_shw_ INT DEFAULT 0;
- DECLARE cnt_mov_ INT DEFAULT 0;
-
- IF ( _full = 1 ) THEN
- SELECT COUNT(*)
- INTO del_chn_
- FROM `channel`
- WHERE ( `touched` = 0 );
-
- SELECT COUNT(*)
- INTO del_shw_
- FROM `show`
- WHERE ( `touched` = 0 );
-
- SELECT COUNT(*)
- INTO del_mov_
- FROM `film`
- WHERE ( `touched` = 0 );
-
- DELETE FROM `show`
- WHERE ( `show`.`touched` = 0 )
- AND
- ( ( SELECT SUM( `film`.`touched` ) FROM `film` WHERE `film`.`showid` = `show`.`id` ) = 0 );
-
- DELETE FROM `film`
- WHERE ( `touched` = 0 );
- ELSE
- SET del_chn_ = 0;
- SET del_shw_ = 0;
- SET del_mov_ = 0;
- END IF;
-
- SELECT del_chn_ AS `del_chn`,
- del_shw_ AS `del_shw`,
- del_mov_ AS `del_mov`,
- cnt_chn_ AS `cnt_chn`,
- cnt_shw_ AS `cnt_shw`,
- cnt_mov_ AS `cnt_mov`;
-END ;;
-DELIMITER ;
-/*!50003 SET sql_mode = @saved_sql_mode */ ;
-/*!50003 SET character_set_client = @saved_cs_client */ ;
-/*!50003 SET character_set_results = @saved_cs_results */ ;
-/*!50003 SET collation_connection = @saved_col_connection */ ;
-/*!50003 DROP PROCEDURE IF EXISTS `ftUpdateStart` */;
-/*!50003 SET @saved_cs_client = @@character_set_client */ ;
-/*!50003 SET @saved_cs_results = @@character_set_results */ ;
-/*!50003 SET @saved_col_connection = @@collation_connection */ ;
-/*!50003 SET character_set_client = utf8 */ ;
-/*!50003 SET character_set_results = utf8 */ ;
-/*!50003 SET collation_connection = utf8_general_ci */ ;
-/*!50003 SET @saved_sql_mode = @@sql_mode */ ;
-/*!50003 SET sql_mode = 'ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION' */ ;
-DELIMITER ;;
-CREATE DEFINER=`root`@`localhost` PROCEDURE `ftUpdateStart`(
- _full INT(1)
-)
-BEGIN
- DECLARE cnt_chn_ INT DEFAULT 0;
- DECLARE cnt_shw_ INT DEFAULT 0;
- DECLARE cnt_mov_ INT DEFAULT 0;
-
- IF ( _full = 1 ) THEN
- UPDATE `channel`
- SET `touched` = 0;
-
- UPDATE `show`
- SET `touched` = 0;
-
- UPDATE `film`
- SET `touched` = 0;
- END IF;
-
- SELECT COUNT(*)
- INTO cnt_chn_
- FROM `channel`;
-
- SELECT COUNT(*)
- INTO cnt_shw_
- FROM `show`;
-
- SELECT COUNT(*)
- INTO cnt_mov_
- FROM `film`;
-
- SELECT cnt_chn_ AS `cnt_chn`,
- cnt_shw_ AS `cnt_shw`,
- cnt_mov_ AS `cnt_mov`;
-END ;;
-DELIMITER ;
-/*!50003 SET sql_mode = @saved_sql_mode */ ;
-/*!50003 SET character_set_client = @saved_cs_client */ ;
-/*!50003 SET character_set_results = @saved_cs_results */ ;
-/*!50003 SET collation_connection = @saved_col_connection */ ;
-/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
-
-/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
-/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
-/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
-/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
-/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
-/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
-/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-
--- Dump completed on 2018-01-03 16:26:35
diff --git a/plugin.video.mediathekview/resources/sql/filmliste-sqlite-v1.sql b/plugin.video.mediathekview/resources/sql/filmliste-sqlite-v1.sql
deleted file mode 100644
index 8e7ee09..0000000
--- a/plugin.video.mediathekview/resources/sql/filmliste-sqlite-v1.sql
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- Navicat Premium Data Transfer
-
- Source Server : Kodi MediathekView
- Source Server Type : SQLite
- Source Server Version : 3012001
- Source Database : main
-
- Target Server Type : SQLite
- Target Server Version : 3012001
- File Encoding : utf-8
-
- Date: 12/27/2017 23:56:51 PM
-*/
-
-PRAGMA foreign_keys = false;
-
--- ----------------------------
--- Table structure for channel
--- ----------------------------
-DROP TABLE IF EXISTS "channel";
-CREATE TABLE "channel" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "dtCreated" integer(11,0) NOT NULL DEFAULT 0,
- "touched" integer(1,0) NOT NULL DEFAULT 1,
- "channel" TEXT(255,0) NOT NULL
-);
-
--- ----------------------------
--- Table structure for film
--- ----------------------------
-DROP TABLE IF EXISTS "film";
-CREATE TABLE "film" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "dtCreated" integer(11,0) NOT NULL DEFAULT 0,
- "touched" integer(1,0) NOT NULL DEFAULT 1,
- "channelid" INTEGER(11,0) NOT NULL,
- "showid" INTEGER(11,0) NOT NULL,
- "title" TEXT(255,0) NOT NULL,
- "search" TEXT(255,0) NOT NULL,
- "aired" integer(11,0),
- "duration" integer(11,0),
- "size" integer(11,0),
- "description" TEXT(2048,0),
- "website" TEXT(384,0),
- "url_sub" TEXT(384,0),
- "url_video" TEXT(384,0),
- "url_video_sd" TEXT(384,0),
- "url_video_hd" TEXT(384,0),
- CONSTRAINT "FK_FilmShow" FOREIGN KEY ("showid") REFERENCES "show" ("id") ON DELETE CASCADE,
- CONSTRAINT "FK_FilmChannel" FOREIGN KEY ("channelid") REFERENCES "channel" ("id") ON DELETE CASCADE
-);
-
--- ----------------------------
--- Table structure for show
--- ----------------------------
-DROP TABLE IF EXISTS "show";
-CREATE TABLE "show" (
- "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
- "dtCreated" integer(11,0) NOT NULL DEFAULT 0,
- "touched" integer(1,0) NOT NULL DEFAULT 1,
- "channelid" INTEGER(11,0) NOT NULL DEFAULT 0,
- "show" TEXT(255,0) NOT NULL,
- "search" TEXT(255,0) NOT NULL,
- CONSTRAINT "FK_ShowChannel" FOREIGN KEY ("channelid") REFERENCES "channel" ("id") ON DELETE CASCADE
-);
-
--- ----------------------------
--- Table structure for status
--- ----------------------------
-DROP TABLE IF EXISTS "status";
-CREATE TABLE "status" (
- "modified" integer(11,0),
- "status" TEXT(32,0),
- "lastupdate" integer(11,0),
- "filmupdate" integer(11,0),
- "fullupdate" integer(1,0),
- "add_chn" integer(11,0),
- "add_shw" integer(11,0),
- "add_mov" integer(11,0),
- "del_chm" integer(11,0),
- "del_shw" integer(11,0),
- "del_mov" integer(11,0),
- "tot_chn" integer(11,0),
- "tot_shw" integer(11,0),
- "tot_mov" integer(11,0)
-);
-
--- ----------------------------
--- Indexes structure for table film
--- ----------------------------
-CREATE INDEX "dupecheck" ON film ("channelid", "showid", "url_video");
-CREATE INDEX "index_1" ON film ("channelid", "title" COLLATE NOCASE);
-CREATE INDEX "index_2" ON film ("showid", "title" COLLATE NOCASE);
-
--- ----------------------------
--- Indexes structure for table show
--- ----------------------------
-CREATE INDEX "category" ON show ("category");
-CREATE INDEX "search" ON show ("search");
-CREATE INDEX "combined_1" ON show ("channelid", "search");
-CREATE INDEX "combined_2" ON show ("channelid", "show");
-
-PRAGMA foreign_keys = true;
diff --git a/plugin.video.mediathekview/service.py b/plugin.video.mediathekview/service.py
index a299ee4..933ce55 100644
--- a/plugin.video.mediathekview/service.py
+++ b/plugin.video.mediathekview/service.py
@@ -25,15 +25,13 @@
# -- Imports ------------------------------------------------
from __future__ import unicode_literals # ,absolute_import, division
-import time
import xbmc
-from de.yeasoft.kodi.KodiAddon import KodiService
+from resources.lib.kodi.KodiAddon import KodiService
-from classes.store import Store
-from classes.notifier import Notifier
-from classes.settings import Settings
-from classes.updater import MediathekViewUpdater
+from resources.lib.notifier import Notifier
+from resources.lib.settings import Settings
+from resources.lib.updater import MediathekViewUpdater
# -- Classes ------------------------------------------------
class MediathekViewMonitor( xbmc.Monitor ):
@@ -56,16 +54,10 @@ class MediathekViewService( KodiService ):
self.settings = Settings()
self.notifier = Notifier()
self.monitor = MediathekViewMonitor( self )
- self.updater = MediathekViewUpdater( self.getNewLogger( 'MediathekViewUpdater' ), self.notifier, self.settings, self.monitor )
-
- def __del__( self ):
- del self.updater
- del self.monitor
- del self.notifier
- del self.settings
+ self.updater = MediathekViewUpdater( self.getNewLogger( 'Updater' ), self.notifier, self.settings, self.monitor )
def Init( self ):
- self.info( 'Startup' )
+ self.info( 'Init' )
self.updater.Init()
def Run( self ):
@@ -83,11 +75,11 @@ class MediathekViewService( KodiService ):
# Sleep/wait for abort for 60 seconds
if self.monitor.waitForAbort( 60 ):
# Abort was requested while waiting. We should exit
- break
- self.info( 'Exiting...' )
+ break
+ self.info( 'Shutting down...' )
def Exit( self ):
- self.info( 'Shutdown' )
+ self.info( 'Exit' )
self.updater.Exit()
def ReloadSettings( self ):