summaryrefslogtreecommitdiff
path: root/plugin.video.mediathekview/classes/storesqlite.py
diff options
context:
space:
mode:
Diffstat (limited to 'plugin.video.mediathekview/classes/storesqlite.py')
-rw-r--r--plugin.video.mediathekview/classes/storesqlite.py766
1 files changed, 766 insertions, 0 deletions
diff --git a/plugin.video.mediathekview/classes/storesqlite.py b/plugin.video.mediathekview/classes/storesqlite.py
new file mode 100644
index 0000000..f73acdf
--- /dev/null
+++ b/plugin.video.mediathekview/classes/storesqlite.py
@@ -0,0 +1,766 @@
+# -*- coding: utf-8 -*-
+# Copyright 2017 Leo Moll
+#
+
+# -- Imports ------------------------------------------------
+import os, stat, string, time
+import sqlite3
+
+from classes.film import Film
+from classes.exceptions import DatabaseCorrupted
+
+# -- Classes ------------------------------------------------
+class StoreSQLite( object ):
+ def __init__( self, logger, notifier, settings ):
+ self.logger = logger
+ self.notifier = notifier
+ self.settings = settings
+ # internals
+ self.conn = None
+ 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_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 ):
+ os.mkdir( self.settings.datapath )
+ if reset == True or not self._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 )
+ self._handle_database_initialization()
+ else:
+ 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.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 )
+
+ def Exit( self ):
+ if self.conn is not None:
+ self.conn.close()
+ self.conn = None
+
+ def Search( self, search, filmui ):
+ self._Search_Condition( '( ( title LIKE "%%%s%%" ) OR ( show LIKE "%%%s%%" ) )' % ( search, search ), filmui, True, True )
+
+ 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 )
+
+ 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 )
+
+ def GetLiveStreams( self, filmui ):
+ self._Search_Condition( '( show.search="LIVESTREAM" )', filmui, False, False )
+
+ def GetChannels( self, channelui ):
+ self._Channels_Condition( None, channelui )
+
+ 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: {}',
+ 'SELECT SUBSTR(search,1,1),COUNT(*) FROM show ' +
+ condition +
+ 'GROUP BY LEFT(search,1)'
+ )
+ cursor = self.conn.cursor()
+ cursor.execute(
+ 'SELECT SUBSTR(search,1,1),COUNT(*) FROM show ' +
+ condition +
+ 'GROUP BY SUBSTR(search,1,1)'
+ )
+ initialui.Begin( channelid )
+ for ( initialui.initial, initialui.count ) in cursor:
+ initialui.Add()
+ initialui.End()
+ cursor.close()
+ except sqlite3.Error as err:
+ self.logger.error( 'Database error: {}', err )
+ self.notifier.ShowDatabaseError( err )
+
+ def GetShows( self, channelid, initial, showui ):
+ if self.conn is None:
+ return
+ try:
+ if channelid == '0' and self.settings.groupshows:
+ query = 'SELECT GROUP_CONCAT(show.id),GROUP_CONCAT(channelid),show,GROUP_CONCAT(channel) FROM show LEFT JOIN channel ON channel.id=show.channelid WHERE ( show LIKE "%s%%" ) GROUP BY show' % initial
+ elif channelid == '0':
+ query = 'SELECT show.id,show.channelid,show.show,channel.channel FROM show LEFT JOIN channel ON channel.id=show.channelid WHERE ( show LIKE "%s%%" )' % initial
+ else:
+ query = 'SELECT show.id,show.channelid,show.show,channel.channel FROM show LEFT JOIN channel ON channel.id=show.channelid WHERE ( channelid=%s ) AND ( show LIKE "%s%%" )' % ( channelid, initial )
+ self.logger.info( 'SQLite Query: {}', query )
+ cursor = self.conn.cursor()
+ cursor.execute( query )
+ showui.Begin( channelid )
+ for ( showui.id, showui.channelid, showui.show, showui.channel ) in cursor:
+ showui.Add()
+ showui.End()
+ cursor.close()
+ except sqlite3.Error as err:
+ self.logger.error( 'Database error: {}', err )
+ self.notifier.ShowDatabaseError( err )
+
+ def GetFilms( self, showid, filmui ):
+ if self.conn is None:
+ return
+ if showid.find( ',' ) == -1:
+ # only one channel id
+ condition = '( showid=%s )' % showid
+ showchannels = False
+ else:
+ # multiple channel ids
+ condition = '( showid IN ( %s ) )' % showid
+ showchannels = True
+ self._Search_Condition( condition, filmui, False, showchannels )
+
+ def _Search_Condition( self, condition, filmui, showshows, showchannels ):
+ if self.conn is None:
+ return
+ try:
+ self.logger.info( 'SQLite Query: {}',
+ self.sql_query_films +
+ ' WHERE ' +
+ condition +
+ self.sql_cond_nofuture +
+ self.sql_cond_minlength
+ )
+ cursor = self.conn.cursor()
+ cursor.execute(
+ self.sql_query_films +
+ ' WHERE ' +
+ condition +
+ self.sql_cond_nofuture +
+ self.sql_cond_minlength
+ )
+ 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.End()
+ cursor.close()
+ except sqlite3.Error as err:
+ self.logger.error( 'Database error: {}', err )
+ self.notifier.ShowDatabaseError( err )
+
+ def RetrieveFilmInfo( self, filmid ):
+ if self.conn is None:
+ return None
+ try:
+ condition = '( film.id={} )'.format( filmid )
+ self.logger.info( 'SQLite Query: {}',
+ self.sql_query_films +
+ ' WHERE ' +
+ condition
+ )
+ cursor = self.conn.cursor()
+ cursor.execute(
+ self.sql_query_films +
+ ' WHERE ' +
+ condition
+ )
+ film = Film()
+ for ( film.id, film.title, film.show, film.channel, film.description, film.seconds, film.size, film.aired, film.url_sub, film.url_video, film.url_video_sd, film.url_video_hd ) in cursor:
+ cursor.close()
+ return film
+ cursor.close()
+ except sqlite3.Error as err:
+ self.logger.error( 'Database error: {}', err )
+ self.notifier.ShowDatabaseError( err )
+ return None
+
+ def GetStatus( self ):
+ status = {
+ 'modified': int( time.time() ),
+ 'status': '',
+ 'lastupdate': 0,
+ 'filmupdate': 0,
+ 'fullupdate': 0,
+ 'add_chn': 0,
+ 'add_shw': 0,
+ 'add_mov': 0,
+ 'del_chn': 0,
+ 'del_shw': 0,
+ 'del_mov': 0,
+ 'tot_chn': 0,
+ 'tot_shw': 0,
+ 'tot_mov': 0
+ }
+ if self.conn is None:
+ status['status'] = "UNINIT"
+ return status
+ self.conn.commit()
+ cursor = self.conn.cursor()
+ cursor.execute( 'SELECT * FROM `status` LIMIT 1' )
+ r = cursor.fetchall()
+ cursor.close()
+ if len( r ) == 0:
+ status['status'] = "NONE"
+ return status
+ status['modified'] = r[0][0]
+ status['status'] = r[0][1]
+ status['lastupdate'] = r[0][2]
+ status['filmupdate'] = r[0][3]
+ status['fullupdate'] = r[0][4]
+ status['add_chn'] = r[0][5]
+ status['add_shw'] = r[0][6]
+ status['add_mov'] = r[0][7]
+ status['del_chn'] = r[0][8]
+ status['del_shw'] = r[0][9]
+ status['del_mov'] = r[0][10]
+ status['tot_chn'] = r[0][11]
+ status['tot_shw'] = r[0][12]
+ status['tot_mov'] = r[0][13]
+ return status
+
+ def UpdateStatus( self, status = None, lastupdate = None, filmupdate = None, fullupdate = None, add_chn = None, add_shw = None, add_mov = None, del_chn = None, del_shw = None, del_mov = None, tot_chn = None, tot_shw = None, tot_mov = None ):
+ if self.conn is None:
+ return
+ new = self.GetStatus()
+ old = new['status']
+ if status is not None:
+ new['status'] = status
+ if lastupdate is not None:
+ new['lastupdate'] = lastupdate
+ if filmupdate is not None:
+ new['filmupdate'] = filmupdate
+ if fullupdate is not None:
+ new['fullupdate'] = fullupdate
+ if add_chn is not None:
+ new['add_chn'] = add_chn
+ if add_shw is not None:
+ new['add_shw'] = add_shw
+ if add_mov is not None:
+ new['add_mov'] = add_mov
+ if del_chn is not None:
+ new['del_chn'] = del_chn
+ if del_shw is not None:
+ new['del_shw'] = del_shw
+ if del_mov is not None:
+ new['del_mov'] = del_mov
+ if tot_chn is not None:
+ new['tot_chn'] = tot_chn
+ if tot_shw is not None:
+ new['tot_shw'] = tot_shw
+ if tot_mov is not None:
+ new['tot_mov'] = tot_mov
+ # TODO: we should only write, if we have changed something...
+ new['modified'] = int( time.time() )
+ cursor = self.conn.cursor()
+ if old == "NONE":
+ # insert status
+ cursor.execute(
+ """
+ INSERT INTO `status` (
+ `modified`,
+ `status`,
+ `lastupdate`,
+ `filmupdate`,
+ `fullupdate`,
+ `add_chn`,
+ `add_shw`,
+ `add_mov`,
+ `del_chm`,
+ `del_shw`,
+ `del_mov`,
+ `tot_chn`,
+ `tot_shw`,
+ `tot_mov`
+ )
+ VALUES (
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?
+ )
+ """, (
+ new['modified'],
+ new['status'],
+ new['lastupdate'],
+ new['filmupdate'],
+ new['fullupdate'],
+ new['add_chn'],
+ new['add_shw'],
+ new['add_mov'],
+ new['del_chn'],
+ new['del_shw'],
+ new['del_mov'],
+ new['tot_chn'],
+ new['tot_shw'],
+ new['tot_mov'],
+ )
+ )
+ else:
+ # update status
+ cursor.execute(
+ """
+ UPDATE `status`
+ SET `modified` = ?,
+ `status` = ?,
+ `lastupdate` = ?,
+ `filmupdate` = ?,
+ `fullupdate` = ?,
+ `add_chn` = ?,
+ `add_shw` = ?,
+ `add_mov` = ?,
+ `del_chm` = ?,
+ `del_shw` = ?,
+ `del_mov` = ?,
+ `tot_chn` = ?,
+ `tot_shw` = ?,
+ `tot_mov` = ?
+ """, (
+ new['modified'],
+ new['status'],
+ new['lastupdate'],
+ new['filmupdate'],
+ new['fullupdate'],
+ new['add_chn'],
+ new['add_shw'],
+ new['add_mov'],
+ new['del_chn'],
+ new['del_shw'],
+ new['del_mov'],
+ new['tot_chn'],
+ new['tot_shw'],
+ new['tot_mov'],
+ )
+ )
+ cursor.close()
+ self.conn.commit()
+
+ def SupportsUpdate( self ):
+ return True
+
+ def ftInit( self ):
+ try:
+ # prevent concurrent updating
+ self.conn.commit()
+ cursor = self.conn.cursor()
+ cursor.execute(
+ """
+ UPDATE `status`
+ SET `modified` = ?,
+ `status` = 'UPDATING'
+ WHERE ( `status` != 'UPDATING' )
+ OR
+ ( `modified` < ? )
+ """, (
+ int( time.time() ),
+ int( time.time() ) - 86400
+ )
+ )
+ retval = cursor.rowcount > 0
+ self.conn.commit()
+ cursor.close()
+ self.ft_channel = None
+ self.ft_channelid = None
+ self.ft_show = None
+ self.ft_showid = None
+ return retval
+ except sqlite3.DatabaseError as err:
+ self._handle_database_corruption( err )
+ raise DatabaseCorrupted( 'Database error during critical operation: {} - Database will be rebuilt from scratch.'.format( err ) )
+
+ def ftUpdateStart( self, full ):
+ try:
+ cursor = self.conn.cursor()
+ if full:
+ cursor.executescript( """
+ UPDATE `channel`
+ SET `touched` = 0;
+
+ UPDATE `show`
+ SET `touched` = 0;
+
+ UPDATE `film`
+ SET `touched` = 0;
+ """ )
+ cursor.execute( 'SELECT COUNT(*) FROM `channel`' )
+ r1 = cursor.fetchone()
+ cursor.execute( 'SELECT COUNT(*) FROM `show`' )
+ r2 = cursor.fetchone()
+ cursor.execute( 'SELECT COUNT(*) FROM `film`' )
+ r3 = cursor.fetchone()
+ cursor.close()
+ self.conn.commit()
+ return ( r1[0], r2[0], r3[0], )
+ except sqlite3.DatabaseError as err:
+ self._handle_database_corruption( err )
+ raise DatabaseCorrupted( 'Database error during critical operation: {} - Database will be rebuilt from scratch.'.format( err ) )
+
+ def ftUpdateEnd( self, delete ):
+ try:
+ cursor = self.conn.cursor()
+ cursor.execute( 'SELECT COUNT(*) FROM `channel` WHERE ( touched = 0 )' )
+ ( del_chn, ) = cursor.fetchone()
+ cursor.execute( 'SELECT COUNT(*) FROM `show` WHERE ( touched = 0 )' )
+ ( del_shw, ) = cursor.fetchone()
+ cursor.execute( 'SELECT COUNT(*) FROM `film` WHERE ( touched = 0 )' )
+ ( del_mov, ) = cursor.fetchone()
+ if delete:
+ cursor.execute( 'DELETE FROM `show` WHERE ( show.touched = 0 ) AND ( ( SELECT SUM( film.touched ) FROM `film` WHERE film.showid = show.id ) = 0 )' )
+ cursor.execute( 'DELETE FROM `film` WHERE ( touched = 0 )' )
+ else:
+ del_chn = 0
+ del_shw = 0
+ del_mov = 0
+ cursor.execute( 'SELECT COUNT(*) FROM `channel`' )
+ ( cnt_chn, ) = cursor.fetchone()
+ cursor.execute( 'SELECT COUNT(*) FROM `show`' )
+ ( cnt_shw, ) = cursor.fetchone()
+ cursor.execute( 'SELECT COUNT(*) FROM `film`' )
+ ( cnt_mov, ) = cursor.fetchone()
+ cursor.close()
+ self.conn.commit()
+ return ( del_chn, del_shw, del_mov, cnt_chn, cnt_shw, cnt_mov, )
+ except sqlite3.DatabaseError as err:
+ self._handle_database_corruption( err )
+ raise DatabaseCorrupted( 'Database error during critical operation: {} - Database will be rebuilt from scratch.'.format( err ) )
+
+ def ftInsertFilm( self, film, commit ):
+ try:
+ cursor = self.conn.cursor()
+ newchn = False
+ inschn = 0
+ insshw = 0
+ insmov = 0
+
+ # handle channel
+ if self.ft_channel != film['channel']:
+ # process changed channel
+ newchn = True
+ cursor.execute( 'SELECT `id`,`touched` FROM `channel` WHERE channel.channel=?', ( film['channel'], ) )
+ r = cursor.fetchall()
+ if len( r ) > 0:
+ # get the channel data
+ self.ft_channel = film['channel']
+ self.ft_channelid = r[0][0]
+ if r[0][1] == 0:
+ # updated touched
+ cursor.execute( 'UPDATE `channel` SET `touched`=1 WHERE ( channel.id=? )', ( self.ft_channelid, ) )
+ else:
+ # insert the new channel
+ inschn = 1
+ cursor.execute( 'INSERT INTO `channel` ( `dtCreated`,`channel` ) VALUES ( ?,? )', ( int( time.time() ), film['channel'] ) )
+ self.ft_channel = film['channel']
+ self.ft_channelid = cursor.lastrowid
+
+ # handle show
+ if newchn or self.ft_show != film['show']:
+ # process changed show
+ cursor.execute( 'SELECT `id`,`touched` FROM `show` WHERE ( show.channelid=? ) AND ( show.show=? )', ( self.ft_channelid, film['show'] ) )
+ r = cursor.fetchall()
+ if len( r ) > 0:
+ # get the show data
+ self.ft_show = film['show']
+ self.ft_showid = r[0][0]
+ if r[0][1] == 0:
+ # updated touched
+ cursor.execute( 'UPDATE `show` SET `touched`=1 WHERE ( show.id=? )', ( self.ft_showid, ) )
+ else:
+ # insert the new show
+ insshw = 1
+ cursor.execute(
+ """
+ INSERT INTO `show` (
+ `dtCreated`,
+ `channelid`,
+ `show`,
+ `search`
+ )
+ VALUES (
+ ?,
+ ?,
+ ?,
+ ?
+ )
+ """, (
+ int( time.time() ),
+ self.ft_channelid, film['show'],
+ self._make_search( film['show'] )
+ )
+ )
+ self.ft_show = film['show']
+ self.ft_showid = cursor.lastrowid
+
+ # check if the movie is there
+ cursor.execute( """
+ SELECT `id`,
+ `touched`
+ FROM `film`
+ WHERE ( film.channelid = ? )
+ AND
+ ( film.showid = ? )
+ AND
+ ( film.url_video = ? )
+ """, ( self.ft_channelid, self.ft_showid, film['url_video'] ) )
+ r = cursor.fetchall()
+ if len( r ) > 0:
+ # film found
+ filmid = r[0][0]
+ if r[0][1] == 0:
+ # update touched
+ cursor.execute( 'UPDATE `film` SET `touched`=1 WHERE ( film.id=? )', ( filmid, ) )
+ else:
+ # insert the new film
+ insmov = 1
+ cursor.execute(
+ """
+ INSERT INTO `film` (
+ `dtCreated`,
+ `channelid`,
+ `showid`,
+ `title`,
+ `search`,
+ `aired`,
+ `duration`,
+ `size`,
+ `description`,
+ `website`,
+ `url_sub`,
+ `url_video`,
+ `url_video_sd`,
+ `url_video_hd`
+ )
+ VALUES (
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?,
+ ?
+ )
+ """, (
+ int( time.time() ),
+ self.ft_channelid,
+ self.ft_showid,
+ film['title'],
+ self._make_search( film['title'] ),
+ film['airedepoch'],
+ self._make_duration( film['duration'] ),
+ film['size'],
+ film['description'],
+ film['website'],
+ film['url_sub'],
+ film['url_video'],
+ film['url_video_sd'],
+ film['url_video_hd']
+ )
+ )
+ filmid = cursor.lastrowid
+ if commit:
+ self.conn.commit()
+ cursor.close()
+ return ( filmid, inschn, insshw, insmov )
+ except sqlite3.DatabaseError as err:
+ self._handle_database_corruption( err )
+ raise DatabaseCorrupted( 'Database error during critical operation: {} - Database will be rebuilt from scratch.'.format( err ) )
+
+ def _handle_database_corruption( self, err ):
+ self.logger.error( 'Database error during critical operation: {} - Database will be rebuilt from scratch.', err )
+ self.notifier.ShowDatabaseError( err )
+ self.Exit()
+ self.Init( reset = True )
+
+ def _handle_database_initialization( self ):
+ self.conn.executescript( """
+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;
+ """ )
+ 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 ):
+ try:
+ os.remove( name )
+ return True
+ except OSError as err:
+ self.logger.error( 'Failed to remove {}: error {}', name, err )
+ return False
+
+def UNIX_TIMESTAMP():
+ return int( time.time() )
+
+class GROUP_CONCAT:
+ def __init__( self ):
+ self.value = ''
+
+ def step( self, value ):
+ if value is not None:
+ if self.value == '':
+ self.value = '{0}'.format( value )
+ else:
+ self.value = '{0},{1}'.format( self.value, value )
+
+ def finalize(self):
+ return self.value