HOME/Articles/

mysql example service (snippet)

Article Outline

Python mysql example 'service'

Modules used in program:

  • import resources.lib.utils as utils
  • import buggalo
  • import mysql.connector
  • import sqlite3
  • import time
  • import unicodedata
  • import sys, os
  • import re
  • import xbmc, xbmcgui, xbmcaddon, xbmcvfs

python service

Python mysql example: service

import xbmc, xbmcgui, xbmcaddon, xbmcvfs
import re
import sys, os
import unicodedata
import time
import sqlite3
import mysql.connector

import buggalo
buggalo.GMAIL_RECIPIENT = "[email protected]"
# buggalo.SUBMIT_URL = 'http://msahadl.ms.funpic.de/buggalo-web/submit.php'


import resources.lib.utils as utils

if utils.getSetting('dbbackup') == 'true':
    import zipfile
    import datetime




# Main class of the add-on
class WatchedList:
    def __init__(self):
        self.watchedmovielist_wl = list([]) # 0imdbnumber, 1empty, 2empty, 3lastPlayed, 4playCount, 5title, 6lastChange
        self.watchedepisodelist_wl = list([]) # 0imdbnumber, 1season, 2episode, 3lastplayed, 4playcount, 5empty, 6lastChange

        self.watchedmovielist_xbmc = list([]) # 0imdbnumber, 1empty, 2empty, 3lastPlayed, 4playCount, 5title, 6empty, 7movieid
        self.watchedepisodelist_xbmc = list([]) # 0imdbnumber, 1season, 2episode, 3lastplayed, 4playcount, 5name, 6empty, 7episodeid

        self.tvshows = {} # dict: key=xbmcid, value=[imdbnumber, showname]
        self.tvshownames = {} #dict: key=imdbnumber, value=showname

        self.sqlcon = 0
        self.sqlcursor = 0

        self.db_method = 'file' # either 'file' or 'mysql'

        # flag to remember copying the databasefile if requested
        self.dbcopydone = False   

        self.watch_user_changes_count = 0

        # normal access of files or access over the xbmc virtual file system (on unix)
        self.dbfileaccess = 'normal'

        self.dbpath = ''
        self.dbdirectory = ''

    # infinite loop for periodic database update
    def runProgram(self):
        # return codes:
        # 0    success
        # 3    error/exit
        try:
            # workaround to disable autostart, if requested
            if utils.getSetting("autostart") == 'false':
                return 0

            utils.buggalo_extradata_settings()
            utils.footprint()


            if self.sqlcursor == 0 or self.sqlcon == 0: 
                if self.load_db():
                    utils.showNotification(utils.getString(32102), utils.getString(32601))
                    return 3
            if len(self.tvshownames) == 0: self.sync_tvshows()
            if len(self.watchedmovielist_wl) == 0: self.get_watched_wl(1)
            if len(self.watchedmovielist_xbmc) == 0: self.get_watched_xbmc(1)
            executioncount = 0
            idletime = 0

            # wait the delay time after startup
            delaytime = float(utils.getSetting("delay")) * 60 # in seconds
            utils.log(u'Delay time before execution: %d seconds' % delaytime, xbmc.LOGDEBUG)
            utils.showNotification(utils.getString(32101), utils.getString(32004)%float(utils.getSetting("delay")))
            if utils.sleepsafe(delaytime):
                return 0


            if utils.getSetting("watch_user") == 'true': utils.showNotification(utils.getString(32101), utils.getString(32005))
            # handle the periodic execution
            while float(utils.getSetting("starttype")) > 0 or utils.getSetting("watch_user") == 'true':
                starttime = time.time()
                # determine sleeptime before full watched-database update
                if float(utils.getSetting("starttype")) > 0: 
                    if utils.getSetting("starttype") == '2':
                        sleeptime = float(utils.getSetting("interval")) * 3600 # wait interval until next startup in [seconds]
                        # wait and then update again
                        utils.log(u'wait %d seconds until next update' % sleeptime)
                        utils.showNotification(utils.getString(32101), utils.getString(32003)%(sleeptime/3600))
                    else:
                        sleeptime = 3600 # arbitrary time for infinite loop
                else:
                    sleeptime = 3600 # arbitrary time for infinite loop

                # workaround to sleep the requested time. When using the sleep-function, xbmc can not exit 
                while 1:
                    if xbmc.abortRequested: return 1
                    # check if user changes arrived
                    if utils.getSetting("watch_user") == 'true':
                        idletime_old = idletime
                        idletime = xbmc.getGlobalIdleTime() # xbmc idletime in seconds
                        # check if user could have made changes and process these changes to the wl database
                        self.watch_user_changes(idletime_old, idletime)
                    # check if time for update arrived
                    if time.time() > starttime + sleeptime:
                        break
                    xbmc.sleep(1000) # wait 1 second until next check if xbmc terminates
                if utils.getSetting("starttype") == '1' and executioncount == 0 or utils.getSetting("starttype") == '2':
                    self.runUpdate(False)
                    executioncount += 1
                if float(utils.getSetting("starttype")) < 2 and utils.getSetting("watch_user") == 'false':
                    return 0 # the program may exit. No purpose for background process
            # do not use the periodic update
            return 0
        except:
            buggalo.onExceptionRaised()  

    # entry point for manual start.
    # perform the update step by step
    def runUpdate(self, manualstart):
        # return codes:
        # 0    success
        # 3    Error opening database
        # 4    Error getting watched state from addon database
        # 5    Error getting watched state from xbmc database
        # 6    Error writing WL Database
        # 7    Error writing XBMC database
        try:
            utils.buggalo_extradata_settings()

            # check if player is running before doing the update. Only do this check for automatic start
            while xbmc.Player().isPlaying() == True and not manualstart:
                if utils.sleepsafe(60*1000): return 1 # wait one minute until next check for active playback
                if xbmc.Player().isPlaying() == False:
                    if utils.sleepsafe(180*1000): return 1 # wait 3 minutes so the dialogue does not pop up directly after the playback ends

            # load the addon-database

            if self.load_db(True): # True: Manual start
                utils.showNotification(utils.getString(32102), utils.getString(32601))
                return 3

            if self.sync_tvshows():
                utils.showNotification(utils.getString(32102), utils.getString(32604))
                return 5

            # get the watched state from the addon
            if self.get_watched_wl(0):
                utils.showNotification(utils.getString(32102), utils.getString(32602))
                return 4

            # get watched state from xbmc
            if self.get_watched_xbmc(0):
                utils.showNotification(utils.getString(32102), utils.getString(32603))
                return 5

            if self.sync_tvshows():
                utils.showNotification(utils.getString(32102), utils.getString(32604))
                return 5

            # import from xbmc into addon database
            res = self.write_wl_wdata()
            if res == 2: # user exit
                return 0 
            elif res == 1: # error
                utils.showNotification(utils.getString(32102), utils.getString(32604))
                return 6

            # close the sqlite database (addon)
            self.close_db() # should be closed by the functions directly accessing the database

            # export from addon database into xbmc database
            res = self.write_xbmc_wdata((utils.getSetting("progressdialog") == 'true'), 2)
            if res == 2: # user exit
                return 0 
            elif res == 1: # error
                utils.showNotification(utils.getString(32102), utils.getString(32605))
                return 7

            utils.showNotification(utils.getString(32101), utils.getString(32107))
            utils.log(u'runUpdate exited with success', xbmc.LOGDEBUG)

            return 0
        except:
            buggalo.onExceptionRaised()  

    def load_db(self, manualstart=False):
        # return codes:
        # 0    successfully opened database
        # 1    error
        # 2    shutdown (serious error in subfunction)

        # if manualstart, only retry opening db once
        try:
            #if utils.getSetting("db_format") == 0:
            if True:
                # SQlite3 database in a file
                # load the db path
                if utils.getSetting("extdb") == 'false':
                    # use the default file 
                    self.dbdirectory = xbmc.translatePath( utils.data_dir() ).decode('utf-8')
                    buggalo.addExtraData('dbdirectory', self.dbdirectory);
                    self.dbpath = os.path.join( self.dbdirectory , "watchedlist.db" )
                else:
                    wait_minutes = 1 # retry waittime if db path does not exist/ is offline

                    while xbmc.abortRequested == False:
                        # use a user specified file, for example to synchronize multiple clients
                        self.dbdirectory = xbmc.translatePath( utils.getSetting("dbpath") ).decode('utf-8')
                        self.dbfileaccess = utils.fileaccessmode(self.dbdirectory)
                        self.dbdirectory = utils.translateSMB(self.dbdirectory)

                        self.dbpath = os.path.join( self.dbdirectory , utils.getSetting("dbfilename").decode('utf-8') )
                        # xbmc.validatePath(self.dbdirectory) # does not work for smb
                        if not xbmcvfs.exists(self.dbdirectory): # do not use os.path.exists to access smb:// paths
                            if manualstart:
                                utils.log(u'db path does not exist: %s' % self.dbdirectory, xbmc.LOGWARNING)
                                return 1 # error
                            else:
                                utils.log(u'db path does not exist, wait %d minutes: %s' % (wait_minutes, self.dbdirectory), xbmc.LOGWARNING)

                            utils.showNotification(utils.getString(32102), utils.getString(32002) % self.dbdirectory )
                            # Wait "wait_minutes" minutes until next check for file path (necessary on network shares, that are offline)
                            wait_minutes += wait_minutes # increase waittime until next check
                            if utils.sleepsafe(wait_minutes*60): return 2
                        else:
                            break # directory exists, continue below      

                # on unix, smb-shares can not be accessed with sqlite3 --> copy the db with xbmc file system operations and work in mirror directory
                buggalo.addExtraData('dbfileaccess', self.dbfileaccess);
                buggalo.addExtraData('dbdirectory', self.dbdirectory);
                buggalo.addExtraData('dbpath', self.dbpath);
                if self.dbfileaccess == 'copy':
                    self.dbdirectory_copy = self.dbdirectory
                    self.dbpath_copy = self.dbpath # path to db file as in the settings (but not accessable)
                    buggalo.addExtraData('dbdirectory_copy', self.dbdirectory_copy);
                    buggalo.addExtraData('dbpath_copy', self.dbpath_copy);
                    # work in copy directory in the xbmc profile folder
                    self.dbdirectory = os.path.join( xbmc.translatePath( utils.data_dir() ).decode('utf-8'), 'dbcopy')
                    if not xbmcvfs.exists(self.dbdirectory):
                        xbmcvfs.mkdir(self.dbdirectory)
                        utils.log(u'created directory %s' % str(self.dbdirectory))  
                    self.dbpath = os.path.join( self.dbdirectory , "watchedlist.db" )
                    if xbmcvfs.exists(self.dbpath_copy):
                        success = xbmcvfs.copy(self.dbpath_copy, self.dbpath) # copy the external db file to local mirror directory
                        utils.log(u'copied db file %s -> %s. Success: %d' % (self.dbpath_copy, self.dbpath, success), xbmc.LOGDEBUG)  

                buggalo.addExtraData('dbdirectory', self.dbdirectory);
                buggalo.addExtraData('dbpath', self.dbpath);


                #connect to the database. create database if it does not exist
                self.sqlcon = sqlite3.connect(self.dbpath);
                self.sqlcursor = self.sqlcon.cursor()
            else:
                # MySQL Database on a server
                self.sqlcon = mysql.connector.connect(user=utils.getSetting("mysql_user"), password=utils.getSetting("mysql_pass"), database=utils.getSetting("mysql_db"), host=utils.getSetting("mysql_server"), port=utils.getSetting("mysql_port"))
                self.sqlcursor = self.sqlcon.cursor()

            # create tables if they don't exist
            if True: # sqlite file
                sql = "CREATE TABLE IF NOT EXISTS movie_watched (idMovieImdb INTEGER PRIMARY KEY,playCount INTEGER,lastChange INTEGER,lastPlayed INTEGER,title TEXT)"
                self.sqlcursor.execute(sql)
                sql = "CREATE TABLE IF NOT EXISTS episode_watched (idShow INTEGER, season INTEGER, episode INTEGER, playCount INTEGER,lastChange INTEGER,lastPlayed INTEGER, PRIMARY KEY (idShow, season, episode))"
                self.sqlcursor.execute(sql)
                sql = "CREATE TABLE IF NOT EXISTS tvshows (idShow INTEGER, title TEXT, PRIMARY KEY (idShow))"
                self.sqlcursor.execute(sql)
            else: # mysql network database
                sql = ("CREATE TABLE IF NOT EXISTS `movie_watched` ("
                      "`idMovieImdb` int unsigned NOT NULL,"
                      "`playCount` tinyint unsigned DEFAULT NULL,"
                      "`lastChange` timestamp NULL DEFAULT NULL,"
                      "`lastPlayed` timestamp NULL DEFAULT NULL,"
                      "`title` text,"
                      "PRIMARY KEY (`idMovieImdb`)"
                        ") ENGINE=InnoDB DEFAULT CHARSET=utf8;")
                self.sqlcursor.execute(sql)
                sql = ("CREATE TABLE IF NOT EXISTS `episode_watched` ("
                      "`idShow` int unsigned NOT NULL DEFAULT '0',"
                      "`season` smallint unsigned NOT NULL DEFAULT '0',"
                      "`episode` smallint unsigned NOT NULL DEFAULT '0',"
                      "`playCount` tinyint unsigned DEFAULT NULL,"
                      "`lastChange` timestamp NULL DEFAULT NULL,"
                      "`lastPlayed` timestamp NULL DEFAULT NULL,"
                      "PRIMARY KEY (`idShow`,`season`,`episode`)"
                        ") ENGINE=InnoDB DEFAULT CHARSET=utf8;")
                self.sqlcursor.execute(sql)
                sql = ("CREATE TABLE IF NOT EXISTS `tvshows` ("
                      "`idShow` int unsigned NOT NULL,"
                      "`title` text,"
                      "PRIMARY KEY (`idShow`)"
                        ") ENGINE=InnoDB DEFAULT CHARSET=utf8;")
                self.sqlcursor.execute(sql)

            buggalo.addExtraData('db_connstatus', 'connected')
        except sqlite3.Error as e:
            try:
                errstring = e.args[0] # TODO: Find out, why this does not work some times
            except:
                errstring = ''
            utils.log(u"Database error while opening %s. '%s'" % (self.dbpath, errstring), xbmc.LOGERROR)
            self.close_db()
            buggalo.addExtraData('db_connstatus', 'sqlite3 error, closed')
            return 1
        except mysql.connector.Error as err:
            # Catch common mysql errors and show them to guide the user
            utils.log(u"Database error while opening mySQL DB %s [%s:%s@%s]. %s" % (utils.getSetting("mysql_db"), utils.getSetting("mysql_user"), utils.getSetting("mysql_pass"), utils.getSetting("mysql_db"), err), xbmc.LOGERROR)
            if err.errno == mysql.connector.errorcode.ER_DBACCESS_DENIED_ERROR:
                utils.showNotification(utils.getString(32103), utils.getString(32210) % (utils.getSetting("mysql_user"), utils.getSetting("mysql_db"))) 
            elif err.errno == mysql.connector.errorcode.ER_ACCESS_DENIED_ERROR:
                utils.showNotification(utils.getString(32103), utils.getString(32208)) 
            elif err.errno == mysql.connector.errorcode.ER_BAD_DB_ERROR:
                utils.showNotification(utils.getString(32103), utils.getString(32209) % utils.getSetting("mysql_db") ) 
            buggalo.addExtraData('db_connstatus', 'mysql error, closed')
            self.close_db()
            return 1
        except:
            utils.log(u"Error while opening %s: %s" % (self.dbpath, sys.exc_info()[2]), xbmc.LOGERROR)
            self.close_db()
            buggalo.addExtraData('dbpath', self.dbpath)
            buggalo.addExtraData('db_connstatus', 'error, closed')
            buggalo.onExceptionRaised()
            return 1     
        # only commit the changes if no error occured to ensure database persistence
        self.sqlcon.commit()
        return 0



    def close_db(self):
        if self.sqlcon:
            self.sqlcon.close()
        self.sqlcon = 0

        # copy the db file back to the shared directory, if needed
        if utils.getSetting("db_format") == 0 and self.dbfileaccess == 'copy':
            if xbmcvfs.exists(self.dbpath):
                success = xbmcvfs.copy(self.dbpath, self.dbpath_copy)
                utils.log(u'copied db file %s -> %s. Success: %d' % (self.dbpath, self.dbpath_copy, success), xbmc.LOGDEBUG)  
                if not success:
                    utils.showNotification(utils.getString(32102), utils.getString(32606) % self.dbpath )
                    return 1
        buggalo.addExtraData('db_connstatus', 'closed')
        return 0
        # cursor is not changed -> error


    def get_watched_xbmc(self, silent):
        try:

            ############################################        
            # first tv shows with TheTVDB-ID, then tv episodes
            if utils.getSetting("w_episodes") == 'true':
                ############################################
                # get imdb tv-show id from xbmc database
                utils.log(u'get_watched_xbmc: Get all episodes from xbmc database', xbmc.LOGDEBUG)
                json_response = utils.executeJSON({
                          "jsonrpc": "2.0", 
                          "method": "VideoLibrary.GetTVShows", 
                          "params": {
                                     "properties": ["title", "imdbnumber"],
                                     "sort": { "order": "ascending", "method": "title" }
                                     }, 
                          "id": 1}) 
                if json_response.has_key('result') and json_response['result'] != None and json_response['result'].has_key('tvshows'):
                    for item in json_response['result']['tvshows']:
                        tvshowId_xbmc = int(item['tvshowid'])
                        try:
                            # check if series number is in imdb-format (scraper=imdb?)
                            res = re.compile('tt(\d+)').findall(item['imdbnumber'])
                            if len(res) == 0:
                                # number in thetvdb-format
                                tvshowId_imdb = int(item['imdbnumber'])
                            else:
                                # number in imdb-format
                                tvshowId_imdb = int(res[0])
                        except:
                            utils.log(u'get_watched_xbmc: tv show "%s" has no imdb-number in database. tvshowid=%d Try rescraping.' % (item['title'], tvshowId_xbmc), xbmc.LOGDEBUG)
                            continue
                        self.tvshows[tvshowId_xbmc] = list([tvshowId_imdb, item['title']])
                        self.tvshownames[tvshowId_imdb] = item['title']

            # Get all watched movies and episodes by unique id from xbmc-database via JSONRPC
            self.watchedmovielist_xbmc = list([])
            self.watchedepisodelist_xbmc = list([])
            for modus in ['movie', 'episode']:
                buggalo.addExtraData('modus', modus);
                if modus == 'movie' and utils.getSetting("w_movies") != 'true':
                    continue
                if modus == 'episode' and utils.getSetting("w_episodes") != 'true':
                    continue
                utils.log(u'get_watched_xbmc: Get all %ss from xbmc database' % modus, xbmc.LOGDEBUG)
                if modus == 'movie':
                    # use the JSON-RPC to access the xbmc-database.
                    json_response = utils.executeJSON({
                              "jsonrpc": "2.0",
                              "method": "VideoLibrary.GetMovies", 
                              "params": {
                                         "properties": ["title", "year", "imdbnumber", "lastplayed", "playcount"],
                                         "sort": { "order": "ascending", "method": "title" }
                                         }, 
                              "id": 1
                              })
                else:
                    json_response = utils.executeJSON({
                              "jsonrpc": "2.0",
                              "method": "VideoLibrary.GetEpisodes",
                              "params": {
                                         "properties": ["tvshowid", "season", "episode", "playcount", "showtitle", "lastplayed"]
                                         },
                              "id": 1
                              }) 
                if modus == 'movie': searchkey = 'movies'
                else: searchkey = 'episodes'     
                if json_response.has_key('result') and json_response['result'] != None and json_response['result'].has_key(searchkey):

                    # go through all watched movies and save them in the class-variable self.watchedmovielist_xbmc
                    for item in json_response['result'][searchkey]:
                        if modus == 'movie':
                            name = item['title'] + ' (' + str(item['year']) + ')'
                            res = re.compile('tt(\d+)').findall(item['imdbnumber'])
                            if len(res) == 0:
                                # no imdb-number for this movie in database. Skip
                                utils.log(u'get_watched_xbmc: Movie %s has no imdb-number in database. movieid=%d Try rescraping' % (name, int(item['movieid'])), xbmc.LOGDEBUG)
                                continue
                            imdbId = int(res[0])
                        else: # episodes
                            tvshowId_xbmc = item['tvshowid']
                            name = '%s S%02dE%02d' % (item['showtitle'], item['season'], item['episode'])
                            try:
                                tvshowId_imdb = self.tvshows[tvshowId_xbmc][0]
                            except:
                                utils.log(u'get_watched_xbmc: xbmc tv showid %d is not in table xbmc-tvshows. Skipping %s' % (item['tvshowid'], name), xbmc.LOGWARNING)
                                continue

                        lastplayed = utils.sqlDateTimeToTimeStamp(item['lastplayed']) # convert to integer-timestamp
                        playcount = int(item['playcount'])
                        # add data to the class-variables
                        if modus == 'movie':
                            self.watchedmovielist_xbmc.append(list([imdbId, 0, 0, lastplayed, playcount, name, 0, int(item['movieid'])]))# 0imdbnumber, 1empty, 2empty, 3lastPlayed, 4playCount, 5title, 6empty, 7movieid
                        else:
                            self.watchedepisodelist_xbmc.append(list([tvshowId_imdb, int(item['season']), int(item['episode']), lastplayed, playcount, name, 0, int(item['episodeid'])]))
            if not silent: utils.showNotification( utils.getString(32101), utils.getString(32299)%(len(self.watchedmovielist_xbmc), len(self.watchedepisodelist_xbmc)) )
            return 0
        except:
            utils.log(u'get_watched_xbmc: error getting the xbmc database : %s' % sys.exc_info()[2], xbmc.LOGERROR)
            self.close_db()
            buggalo.onExceptionRaised()  
            return 1          





    def get_watched_wl(self, silent):
        # return codes:
        # 0    successfully got watched states from WL-database
        # 1    unknown error (programming related)
        # 2    shutdown (error in subfunction)
        # 3    error related to opening the database
        try:
            buggalo.addExtraData('self_sqlcursor', self.sqlcursor); buggalo.addExtraData('self_sqlcon', self.sqlcon);
            if self.sqlcursor == 0 or self.sqlcon == 0:
                if self.load_db():
                    return 2
            # get watched movies from addon database
            self.watchedmovielist_wl = list([])
            if utils.getSetting("w_movies") == 'true':
                utils.log(u'get_watched_wl: Get watched movies from WL database', xbmc.LOGDEBUG)
                #if utils.getSetting("db_format") == 0: # SQLite3 File. Timestamp stored as integer
                if True: # SQLite3 File. Timestamp stored as integer
                    self.sqlcursor.execute("SELECT idMovieImdb, lastPlayed, playCount, title, lastChange FROM movie_watched ORDER BY title")
                else: # mySQL: Create integer timestamp with the request
                    self.sqlcursor.execute("SELECT `idMovieImdb`, strftime('%s', `lastPlayed`), `playCount`, `title`, strftime('%s', `lastChange`) FROM `movie_watched` ORDER BY `title`")
                rows = self.sqlcursor.fetchall()
                for row in rows:
                    self.watchedmovielist_wl.append(list([int(row[0]), 0, 0, int(row[1]), int(row[2]), row[3], int(row[4])])) # 0imdbnumber, 1empty, 2empty, 3lastPlayed, 4playCount, 5title, 6lastChange

            # get watched episodes from addon database
            self.watchedepisodelist_wl = list([])
            if utils.getSetting("w_episodes") == 'true':
                utils.log(u'get_watched_wl: Get watched episodes from WL database', xbmc.LOGDEBUG)
                #if utils.getSetting("db_format") == 0: # SQLite3 File. Timestamp stored as integer
                if True: # SQLite3 File. Timestamp stored as integer
                    self.sqlcursor.execute("SELECT idShow, season, episode, lastPlayed, playCount, lastChange FROM episode_watched ORDER BY idShow, season, episode")
                else: # mySQL: Create integer timestamp with the request
                    self.sqlcursor.execute("SELECT `idShow`, `season`, `episode`, strftime('%s', `lastPlayed`), `playCount`, strftime('%s', `lastChange`) FROM `episode_watched` ORDER BY `idShow`, `season`, `episode`")

                rows = self.sqlcursor.fetchall()
                for row in rows:
                    try:
                        name = '%s S%02dE%02d' % (self.tvshownames[int(row[0])], int(row[1]), int(row[2]))
                    except:
                        name = 'tvdb-id %d S%02dE%02d' % (int(row[0]), int(row[1]), int(row[2]))
                    self.watchedepisodelist_wl.append(list([int(row[0]), int(row[1]), int(row[2]), int(row[3]), int(row[4]), name, int(row[5])]))# 0imdbnumber, 1season, 2episode, 3lastplayed, 4playcount, 5name, 6lastChange

            if not silent: utils.showNotification(utils.getString(32101), utils.getString(32298)%(len(self.watchedmovielist_wl), len(self.watchedepisodelist_wl)))
            self.close_db()
            return 0
        except sqlite3.Error as e:
            try:
                errstring = e.args[0] # TODO: Find out, why this does not work some times
            except:
                errstring = ''
            utils.log(u'get_watched_wl: SQLite Database error getting the wl database. %s' % errstring, xbmc.LOGERROR)
            self.close_db()
            # error could be that the database is locked (for tv show strings). This is not an error to disturb the other functions
            return 3
        except mysql.connector.Error as err:
            utils.log(u'get_watched_wl: MySQL Database error getting the wl database. %s' % err, xbmc.LOGERROR)
            return 3
        except:
            utils.log(u'get_watched_wl: Error getting the wl database : %s' % sys.exc_info()[2], xbmc.LOGERROR)
            self.close_db()
            buggalo.onExceptionRaised()  
            return 1     


    def sync_tvshows(self):
        # return codes:
        # 0    successfully synched tv shows
        # 1    database access error
        # 2    database loading error
        try:
            utils.log(u'sync_tvshows: sync tvshows with wl database : %s' % sys.exc_info()[2], xbmc.LOGDEBUG)
            if self.sqlcursor == 0 or self.sqlcon == 0:
                if self.load_db():
                    return 2
            # write eventually new tv shows to wl database
            for xbmcid in self.tvshows:
                #if utils.getSetting("db_format") == 0: # sqlite3
                if True:
                    sql = "INSERT OR IGNORE INTO tvshows (idShow,title) VALUES (?, ?)"
                else: # mysql
                    sql = "INSERT IGNORE INTO tvshows (idShow,title) VALUES (%s, %s)"
                values = self.tvshows[xbmcid]
                self.sqlcursor.execute(sql, values)
            self.database_copy()    
            self.sqlcon.commit()
            # get all known tv shows from wl database
            self.sqlcursor.execute("SELECT idShow, title FROM tvshows") 
            rows = self.sqlcursor.fetchall() 
            for i in range(len(rows)):
                self.tvshownames[int(rows[i][0])] = rows[i][1]
            self.close_db()
        except sqlite3.Error as e:
            try:
                errstring = e.args[0] # TODO: Find out, why this does not work some times
            except:
                errstring = ''
            utils.log(u'sync_tvshows: SQLite Database error accessing the wl database: ''%s''' % errstring, xbmc.LOGERROR)
            self.close_db()
            # error could be that the database is locked (for tv show strings).
            return 1
        except mysql.connector.Error as err:
            utils.log(u"sync_tvshows: MySQL Database error accessing the wl database: ''%s''" % (err), xbmc.LOGERROR)
            self.close_db()
            return 1
        except:
            utils.log(u'sync_tvshows: Error getting the wl database: ''%s''' % sys.exc_info()[2], xbmc.LOGERROR)
            self.close_db()
            buggalo.onExceptionRaised()  
            return 1   
        return 0 



    def write_wl_wdata(self):
        # Go through all watched movies from xbmc and check whether they are up to date in the addon database
        # return codes:
        # 0    successfully written WL
        # 1    program exception
        # 2    database loading error

        buggalo.addExtraData('self_sqlcursor', self.sqlcursor); buggalo.addExtraData('self_sqlcon', self.sqlcon);
        if self.sqlcursor == 0 or self.sqlcon == 0:
            if self.load_db():
                return 2
        for modus in ['movie', 'episode']:
            buggalo.addExtraData('modus', modus);
            if modus == 'movie' and utils.getSetting("w_movies") != 'true':
                continue
            if modus == 'episode' and utils.getSetting("w_episodes") != 'true':
                continue
            utils.log(u'write_wl_wdata: Write watched %ss to WL database' % modus, xbmc.LOGDEBUG)
            count_insert = 0
            count_update = 0
            if utils.getSetting("progressdialog") == 'true':
                DIALOG_PROGRESS = xbmcgui.DialogProgress()
                DIALOG_PROGRESS.create( utils.getString(32101) , utils.getString(32105))
            if modus == 'movie':
                list_length = len(self.watchedmovielist_xbmc)
            else:
                list_length = len(self.watchedepisodelist_xbmc)

            for i in range(list_length):
                if xbmc.abortRequested: break # this loop can take some time in debug mode and prevents xbmc exit
                if utils.getSetting("progressdialog") == 'true' and DIALOG_PROGRESS.iscanceled():
                    if modus == 'movie': strno = 32202
                    else: strno = 32203;
                    utils.showNotification(utils.getString(strno), utils.getString(32301)%(count_insert, count_update))
                    return 2
                if modus == 'movie':
                    row_xbmc = self.watchedmovielist_xbmc[i]
                else:
                    row_xbmc = self.watchedepisodelist_xbmc[i]

                if utils.getSetting("progressdialog") == 'true':
                    DIALOG_PROGRESS.update(100*(i+1)/list_length, utils.getString(32105), utils.getString(32610) % (i+1, list_length, row_xbmc[5]) )  

                try:
                    count = self.wl_update_media(modus, row_xbmc, 0, 0)
                    count_insert += count[0]; count_update += count[1];

                except sqlite3.Error as e:
                    try:
                        errstring = e.args[0] # TODO: Find out, why this does not work some times
                    except:
                        errstring = ''
                    utils.log(u'write_wl_wdata: SQLite Database error ''%s'' while updating %s %s' % (errstring, modus, row_xbmc[5]), xbmc.LOGERROR)
                    # error at this place is the result of duplicate movies, which produces a DUPLICATE PRIMARY KEY ERROR
                    return 1
                except mysql.connector.Error as err:
                    utils.log(u'write_wl_wdata: MySQL Database error ''%s'' while updating %s %s' % (err, modus, row_xbmc[5]), xbmc.LOGERROR)
                    self.close_db()
                    return 1 # error while writing. Do not continue with episodes, if movies raised an exception
                except:
                    utils.log(u'write_wl_wdata: Error while updating %s %s: %s' % (modus, row_xbmc[5], sys.exc_info()[2]), xbmc.LOGERROR)
                    self.close_db()
                    if utils.getSetting("progressdialog") == 'true': DIALOG_PROGRESS.close()
                    buggalo.addExtraData('count_update', count_update); buggalo.addExtraData('count_insert', count_insert); 
                    buggalo.onExceptionRaised()  
                    return 1 

            if utils.getSetting("progressdialog") == 'true': DIALOG_PROGRESS.close()
            # only commit the changes if no error occured to ensure database persistence
            if count_insert > 0 or count_update > 0:
                self.database_copy()
                self.sqlcon.commit()
            if modus == 'movie': strno = [32202, 32301]
            else: strno = [32203, 32301];
            utils.showNotification(utils.getString(strno[0]), utils.getString(strno[1])%(count_insert, count_update))
        self.close_db()
        return 0





    # update the xbmc database.
    # progressdialogue
    # notifications: 0= no, 1=only changed info, 2=all
    def write_xbmc_wdata(self, progressdialogue, notifications):
        # Go through all watched movies/episodes from the wl-database and check, if the xbmc-database is up to date
        # return codes:
        # 0    successfully written XBMC database
        # 1    program exception
        # 2    cancel by user interaction

        for modus in ['movie', 'episode']:
            buggalo.addExtraData('modus', modus);
            if modus == 'movie' and utils.getSetting("w_movies") != 'true':
                continue
            if modus == 'episode' and utils.getSetting("w_episodes") != 'true':
                continue

            utils.log(u'write_xbmc_wdata: Write watched %ss to xbmc database (pd=%d, noti=%d)' % (modus, progressdialogue, notifications), xbmc.LOGDEBUG)
            count_update = 0
            if progressdialogue:
                DIALOG_PROGRESS = xbmcgui.DialogProgress()
                DIALOG_PROGRESS.create( utils.getString(32101), utils.getString(32106))

            # list to iterate over
            if modus == 'movie':
                list_length = len(self.watchedmovielist_wl)
            else:
                list_length = len(self.watchedepisodelist_wl)
            # iterate over wl-list
            for j in range(list_length):
                if xbmc.abortRequested: break # this loop can take some time in debug mode and prevents xbmc exit
                if progressdialogue and DIALOG_PROGRESS.iscanceled():
                    if notifications > 0: utils.showNotification(utils.getString(32204), utils.getString(32302)%(count_update))  
                    return 2
                # get media-specific list items
                if modus == 'movie':
                    row_wl = self.watchedmovielist_wl[j]
                else:
                    row_wl = self.watchedepisodelist_wl[j]
                    season = row_wl[1]
                    episode = row_wl[2]
                imdbId = row_wl[0]
                name =  row_wl[5]

                if progressdialogue:
                    DIALOG_PROGRESS.update(100*(j+1)/list_length, utils.getString(32106), utils.getString(32610) % (j+1, list_length, name) )
                try:
                    # search the unique movie/episode id in the xbmc-list
                    if modus == 'movie':
                        indices = [i for i, x in enumerate(self.watchedmovielist_xbmc) if x[0] == imdbId] # the movie can have multiple entries in xbmc
                    else:
                        indices = [i for i, x in enumerate(self.watchedepisodelist_xbmc) if x[0] == imdbId and x[1] == season and x[2] == episode]
                    lastplayed_wl = row_wl[3]
                    playcount_wl = row_wl[4]
                    lastchange_wl = row_wl[6]
                    if len(indices) > 0:
                        # the movie/episode is already in the xbmc-list
                        for i in indices:
                            if modus == 'movie':
                                row_xbmc = self.watchedmovielist_xbmc[i] 
                            else:
                                row_xbmc = self.watchedepisodelist_xbmc[i]

                            lastplayed_xbmc = row_xbmc[3]
                            playcount_xbmc = row_xbmc[4]

                            change_xbmc_db = False
                            # check if movie/episode is set as unwatched in the wl database
                            if playcount_wl != playcount_xbmc and lastchange_wl > lastplayed_xbmc:
                                change_xbmc_db = True
                            # compare playcount and lastplayed (update if xbmc data is older)
                            if playcount_xbmc < playcount_wl or (lastplayed_xbmc < lastplayed_wl and playcount_wl > 0):
                                change_xbmc_db = True
                            if not change_xbmc_db:    
                                if utils.getSetting("debug") == 'true':
                                    # utils.log(u'write_xbmc_wdata: xbmc database up-to-date for tt%d, %s' % (imdbId, row_xbmc[2]), xbmc.LOGDEBUG)
                                    pass
                                continue
                            # check if the lastplayed-timestamp in wl is useful
                            if playcount_wl == 0:
                                lastplayed_new = 0
                            else:
                                if lastplayed_wl == 0:
                                    lastplayed_new = lastplayed_xbmc
                                else:
                                    lastplayed_new = lastplayed_wl
                            # update database
                            mediaid = row_xbmc[7]
                            if modus == 'movie': jsonmethod = "VideoLibrary.SetMovieDetails"; idfieldname = "movieid"
                            else: jsonmethod = "VideoLibrary.SetEpisodeDetails"; idfieldname = "episodeid"
                            jsondict = {
                                      "jsonrpc": "2.0", 
                                      "method": jsonmethod, 
                                      "params": {idfieldname: mediaid, "playcount": playcount_wl, "lastplayed": utils.TimeStamptosqlDateTime(lastplayed_new)}, 
                                      "id": 1
                                      }
                            json_response = utils.executeJSON(jsondict)
                            if (json_response.has_key('result') and json_response['result'] == 'OK'):
                                utils.log(u'write_xbmc_wdata: xbmc database updated for %s. playcount: {%d -> %d}, lastplayed: {"%s" -> "%s"} (%sid=%d)' % (name, playcount_xbmc, playcount_wl, utils.TimeStamptosqlDateTime(lastplayed_xbmc), utils.TimeStamptosqlDateTime(lastplayed_new), modus, mediaid), xbmc.LOGINFO)
                                if utils.getSetting("debug") == 'true':
                                    if playcount_wl == 0:
                                        if notifications > 0: utils.showNotification(utils.getString(32404), name)
                                    else:
                                        if notifications > 0: utils.showNotification(utils.getString(32401), name)
                                count_update += 1
                                # update the xbmc-db-mirror-variable
                                if modus == 'movie':
                                    self.watchedmovielist_xbmc[i][3] = lastplayed_new
                                    self.watchedmovielist_xbmc[i][4] = playcount_wl
                                else:
                                    self.watchedepisodelist_xbmc[i][3] = lastplayed_new
                                    self.watchedepisodelist_xbmc[i][4] = playcount_wl
                            else:
                                utils.log(u'write_xbmc_wdata: error updating xbmc database. %s. json_response=%s' % (name, str(json_response)), xbmc.LOGERROR)

                    else:
                        # the movie is in the watched-list but not in the xbmc-list -> no action
                        # utils.log(u'write_xbmc_wdata: movie not in xbmc database: tt%d, %s' % (imdbId, row_xbmc[2]), xbmc.LOGDEBUG)
                        continue
                except:
                    utils.log(u"write_xbmc_wdata: Error while updating %s %s: %s" % (modus, name, sys.exc_info()[2]), xbmc.LOGERROR)
                    if progressdialogue: DIALOG_PROGRESS.close()
                    buggalo.addExtraData('count_update', count_update);
                    buggalo.onExceptionRaised()  
                    return 1 

            if progressdialogue: DIALOG_PROGRESS.close() 
            if notifications > 1:
                if modus == 'movie': strno = [32204, 32302]
                else: strno = [32205, 32303];
                utils.showNotification(utils.getString(strno[0]), utils.getString(strno[1])%(count_update))    
        return 0





    # create a copy of the database, in case something goes wrong (only if database file is used)
    def database_copy(self):
        # return codes:
        # 0    successfully copied database
        # 1    file writing error
        # 2    program exception

        if utils.getSetting("db_format") != 0:
            return 0 # no backup needed since we are using mysql database

        if utils.getSetting('dbbackup') == 'false':
            return 0 # no backup requested in the addon settings

        if not self.dbcopydone:
            if not xbmcvfs.exists(self.dbpath): 
                utils.log(u'database_copy: directory %s does not exist. No backup possible.' % self.dbpath, xbmc.LOGERROR)
                return 1
            now = datetime.datetime.now()
            timestr = u'%04d%02d%02d_%02d%02d%02d' % (now.year, now.month, now.day, now.hour, now.minute, now.second)
            zipfilename = os.path.join(self.dbdirectory, utils.decode(timestr + u'-watchedlist.db.zip'))
            zf = False
            try:
                zf = zipfile.ZipFile(zipfilename, 'w')
                zf.write(self.dbpath, compress_type=zipfile.ZIP_DEFLATED)
                zf.close()
                self.dbcopydone = True
                utils.log(u'database_copy: database backup copy created to %s' % zipfilename, xbmc.LOGINFO)
                # copy the zip file with xbmc file system, if needed
                if self.dbfileaccess == 'copy':
                    xbmcvfs.copy(zipfilename, os.path.join(self.dbdirectory_copy, utils.decode(timestr + u'-watchedlist.db.zip')))
                    xbmcvfs.delete(zipfilename)
                return 0
            except:
                if zf:
                    zf.close()
                buggalo.addExtraData('zipfilename', zipfilename);
                buggalo.onExceptionRaised()  
                return 2


    # check if the user made changes in the watched states. Especially setting movies as "not watched". This can not be
    # recognized by the functions above
    def watch_user_changes(self, idletime_old, idletime):
        # return codes: Not defined

        if xbmc.Player().isPlaying() == True:
            return
        if idletime > idletime_old:
            # the idle time increased. No user interaction probably happened
            return
        utils.log(u'watch_user_changes: Check for user changes (no. %d)' % self.watch_user_changes_count, xbmc.LOGDEBUG)
        self.watch_user_changes_count = self.watch_user_changes_count + 1

        # save previous state
        old_watchedmovielist_xbmc = self.watchedmovielist_xbmc
        old_watchedepisodelist_xbmc = self.watchedepisodelist_xbmc
        # get new state
        self.get_watched_xbmc(1)
        #save exception information
        buggalo.addExtraData('len_old_watchedmovielist_xbmc', len(old_watchedmovielist_xbmc))
        buggalo.addExtraData('len_old_watchedepisodelist_xbmc', len(old_watchedepisodelist_xbmc))
        buggalo.addExtraData('len_self_watchedmovielist_xbmc', len(self.watchedmovielist_xbmc))
        buggalo.addExtraData('len_self_watchedepisodelist_xbmc', len(self.watchedepisodelist_xbmc))
        # separate the change detection and the change in the database to prevent circle reference
        indices_changed = list([])
        # compare states of movies/episodes
        for modus in ['movie', 'episode']:
            buggalo.addExtraData('modus', modus);
            if modus == 'movie' and utils.getSetting("w_movies") != 'true':
                continue
            if modus == 'episode' and utils.getSetting("w_episodes") != 'true':
                continue
            if modus == 'movie':
                list_new = self.watchedmovielist_xbmc
                list_old = old_watchedmovielist_xbmc
            else:
                list_new = self.watchedepisodelist_xbmc
                list_old = old_watchedepisodelist_xbmc
            if len(list_old) == 0 or len(list_new) == 0:
                # one of the lists is empty: nothing to compare. No user changes noticable
                continue
            for i_n, row_xbmc in enumerate(list_new):
                if xbmc.abortRequested: return
                mediaid = row_xbmc[7]
                lastplayed_new = row_xbmc[3]
                playcount_new = row_xbmc[4]
                # index of this movie/episode in the old database (before the change by the user)
                if (len(list_old) > i_n) and (list_old[i_n][7] == mediaid): i_o = i_n # db did not change
                else: # search the movieid
                    i_o = [i for i, x in enumerate(list_old) if x[7] == mediaid]
                    if len(i_o) == 0: continue #movie is not in old array
                    i_o = i_o[0] # convert list to int
                lastplayed_old = list_old[i_o][3]
                playcount_old = list_old[i_o][4]


                if playcount_new != playcount_old or lastplayed_new != lastplayed_old:
                    if playcount_new == playcount_old and playcount_new == 0:
                        continue # do not add lastplayed to database, when placount = 0
                    # The user changed the playcount or lastplayed.
                    # update wl with new watched state
                    indices_changed.append([i_n, i_o, row_xbmc])  

            # go through all movies changed by the user        
            for icx in indices_changed:  
                if xbmc.abortRequested: return 1
                i_o = icx[1]; row_xbmc = icx[2]
                i_n = icx[0];
                lastplayed_old = list_old[i_o][3]; playcount_old = list_old[i_o][4];
                lastplayed_new = row_xbmc[3]; playcount_new = row_xbmc[4]; mediaid = row_xbmc[7]
                utils.log(u'watch_user_changes: %s "%s" changed playcount {%d -> %d} lastplayed {"%s" -> "%s"}. %sid=%d' % (modus, row_xbmc[5], playcount_old, playcount_new, utils.TimeStamptosqlDateTime(lastplayed_old), utils.TimeStamptosqlDateTime(lastplayed_new), modus, mediaid))
                try:
                    self.wl_update_media(modus, row_xbmc, 1, 1)
                except sqlite3.Error as e:
                    try:
                        errstring = e.args[0] # TODO: Find out, why this does not work some times
                    except:
                        errstring = ''
                    utils.log(u'write_wl_wdata: SQLite Database error (%s) while updating %s %s' % (errstring, modus, row_xbmc[5]))
                    if utils.getSetting("debug") == 'true':
                        utils.showNotification(utils.getString(32102), utils.getString(32606) % ('(%s)' % errstring))   
                    # error because of db locked or similar error
                    self.close_db()
                    break
                except mysql.connector.Error as err:
                    # Catch common mysql errors and show them to guide the user
                    utils.log(u'write_wl_wdata: MySQL Database error (%s) while updating %s %s' % (err, modus, row_xbmc[5]))
                    if utils.getSetting("debug") == 'true':
                        utils.showNotification(utils.getString(32102), utils.getString(32606) % ('(%s)' % err))
                    self.close_db()
                    break

                # update xbmc watched status, e.g. to set duplicate movies also as watched
            if len(indices_changed) > 0:    
                self.write_xbmc_wdata(0, 1) # this changes self.watchedmovielist_xbmc
                self.close_db() # keep the db closed most of the time (no access problems)



    # update the wl database for one movie/episode with the information in row_xbmc.
    # Use saveanyway to skip checks whether not to save the changes. With commit, the db change is committed directly (slow with many movies, but safe)    
    def wl_update_media(self, mediatype, row_xbmc, saveanyway, commit):
        # return codes:

        # 2    error loading database

        buggalo.addExtraData('self_sqlcursor', self.sqlcursor); buggalo.addExtraData('self_sqlcon', self.sqlcon);
        buggalo.addExtraData('len_self_watchedmovielist_wl', len(self.watchedmovielist_wl))
        buggalo.addExtraData('len_self_watchedepisodelist_wl', len(self.watchedepisodelist_wl))
        buggalo.addExtraData('len_self_tvshownames', len(self.tvshownames))
        buggalo.addExtraData('row_xbmc', row_xbmc)
        buggalo.addExtraData('saveanyway', saveanyway)
        if self.sqlcursor == 0 or self.sqlcon == 0:
            if self.load_db():
                return 2
        for modus in [mediatype]:
            buggalo.addExtraData('modus', modus)
            # row_xbmc: 0imdbnumber, 1empty, 2empty, 3lastPlayed, 4playCount, 5title, 6empty, 7movieid
            imdbId = row_xbmc[0]
            lastplayed_xbmc = row_xbmc[3]
            playcount_xbmc = row_xbmc[4]
            name = row_xbmc[5]
            if modus == 'episode':
                season = row_xbmc[1]
                episode = row_xbmc[2]

            count_return = list([0, 0])
            self.database_copy()
            if self.sqlcursor == 0 or self.sqlcon == 0:
                if self.load_db():
                    return count_return
            if not saveanyway and playcount_xbmc == 0:
                # playcount in xbmc-list is empty. Nothing to save
                if utils.getSetting("debug") == 'true':
                    # utils.log(u'wl_update_%s: not watched in xbmc: tt%d, %s' % (modus, imdbId, name), xbmc.LOGDEBUG)
                    pass
                return count_return
            if modus == 'movie':
                j = [ii for ii, x in enumerate(self.watchedmovielist_wl) if x[0] == imdbId]
            if modus == 'episode':
                j = [ii for ii, x in enumerate(self.watchedepisodelist_wl) if x[0] == imdbId and x[1] == season and x[2] == episode]
            if len(j) > 0:
                j = j[0] # there can only be one valid index j, since only one entry in wl per imdbId
                # the movie is already in the watched-list
                if modus == 'movie':
                    row_wl = self.watchedmovielist_wl[j]
                else:
                    row_wl = self.watchedepisodelist_wl[j]
                lastplayed_wl = row_wl[3]    
                playcount_wl = row_wl[4]
                lastchange_wl = row_wl[6]

                if not saveanyway:
                    # compare playcount and lastplayed

                    # check if an update of the wl database is necessary (xbmc watched status newer)
                    if lastchange_wl > lastplayed_xbmc:
                        return count_return

                    if playcount_wl >= playcount_xbmc and lastplayed_wl >= lastplayed_xbmc:
                        if utils.getSetting("debug") == 'true':
                            # utils.log(u'wl_update_movie: wl database up-to-date for movie tt%d, %s' % (imdbId, moviename), xbmc.LOGDEBUG)
                            pass
                        return count_return
                    # check if the lastplayed-timestamp in xbmc is useful
                    if lastplayed_xbmc == 0:
                        lastplayed_new = lastplayed_wl
                    else:
                        lastplayed_new = lastplayed_xbmc
                else:
                    lastplayed_new = lastplayed_xbmc

                lastchange_new = int(time.time())
                if modus == 'movie':
                    #if utils.getSetting("db_format") == 0: # sqlite3
                    if True: # sqlite3
                        sql = 'UPDATE movie_watched SET playCount = ?, lastplayed = ?, lastChange = ? WHERE idMovieImdb LIKE ?'
                    else: # mysql
                        sql = 'UPDATE movie_watched SET playCount = %s, lastplayed = %s, lastChange = FROM_UNIXTIME(%s) WHERE idMovieImdb LIKE %s'
                    values = list([playcount_xbmc, lastplayed_new, lastchange_new, imdbId])
                else:
                    #if utils.getSetting("db_format") == 0: # sqlite3
                    if True: # sqlite3
                        sql = 'UPDATE episode_watched SET playCount = ?, lastPlayed = ?, lastChange = ? WHERE idShow LIKE ? AND season LIKE ? AND episode LIKE ?'
                    else: # mysql
                        sql = 'UPDATE episode_watched SET playCount = %s, lastPlayed = FROM_UNIXTIME(%s), lastChange = FROM_UNIXTIME(%s) WHERE idShow LIKE %s AND season LIKE %s AND episode LIKE %s'
                    values = list([playcount_xbmc, lastplayed_new, lastchange_new, imdbId, season, episode])
                self.sqlcursor.execute(sql, values)
                count_return[1] = 1
                # update the local mirror variable of the wl database: # 0imdbnumber, season, episode, 3lastPlayed, 4playCount, 5title, 6lastChange
                if modus == 'movie':
                    self.watchedmovielist_wl[j] = list([imdbId, 0, 0, lastplayed_new, playcount_xbmc, name, lastchange_new])
                else:
                    self.watchedepisodelist_wl[j] = list([imdbId, season, episode, lastplayed_new, playcount_xbmc, name, lastchange_new])
                if utils.getSetting("debug") == 'true':
                    utils.log(u'wl_update_%s: updated wl db for "%s" (tt%d). playcount: {%d -> %d}. lastplayed: {"%s" -> "%s"}. lastchange: "%s"' % (modus, name, imdbId, playcount_wl, playcount_xbmc, utils.TimeStamptosqlDateTime(lastplayed_wl), utils.TimeStamptosqlDateTime(lastplayed_new), utils.TimeStamptosqlDateTime(lastchange_new)))
                    if playcount_xbmc > 0:
                        utils.showNotification(utils.getString(32403), name)
                    else:
                        utils.showNotification(utils.getString(32405), name)       
            else:
                # the movie is not in the watched-list -> insert the movie
                # order: idMovieImdb,playCount,lastChange,lastPlayed,title
                lastchange_new = int(time.time())
                if modus == 'movie':
                    #if utils.getSetting("db_format") == 0: # sqlite3
                    if True: # sqlite3
                        sql = 'INSERT INTO movie_watched (idMovieImdb,playCount,lastChange,lastPlayed,title) VALUES (?, ?, ?, ?, ?)'
                    else: # mysql
                        sql = 'INSERT INTO movie_watched (idMovieImdb,playCount,lastChange,lastPlayed,title) VALUES (%s, %s, FROM_UNIXTIME(%s), FROM_UNIXTIME(%s), %s)'
                    values = list([imdbId, playcount_xbmc, lastchange_new, lastplayed_xbmc, name])
                else:
                    #if utils.getSetting("db_format") == 0: # sqlite3
                    if True: # sqlite3
                        sql = 'INSERT INTO episode_watched (idShow,season,episode,playCount,lastChange,lastPlayed) VALUES (?, ?, ?, ?, ?, ?)'
                    else: # mysql
                        sql = 'INSERT INTO episode_watched (idShow,season,episode,playCount,lastChange,lastPlayed) VALUES (%s, %s, %s, %s, FROM_UNIXTIME(%s), FROM_UNIXTIME(%s))'
                    values = list([imdbId, season, episode, playcount_xbmc, lastchange_new, lastplayed_xbmc])
                self.sqlcursor.execute(sql, values)
                utils.log(u'wl_update_%s: new entry for wl database: "%s", lastChange="%s", lastPlayed="%s", playCount=%d' % (modus, name, utils.TimeStamptosqlDateTime(lastchange_new), utils.TimeStamptosqlDateTime(lastplayed_xbmc), playcount_xbmc))
                count_return[0] = 1
                # update the local mirror variable of the wl database
                if modus == 'movie':
                    self.watchedmovielist_wl.append(list([imdbId, 0, 0, lastplayed_xbmc, playcount_xbmc, name, lastchange_new]))
                else:
                    self.watchedepisodelist_wl.append(list([imdbId, season, episode, lastplayed_xbmc, playcount_xbmc, name, lastchange_new]))
                if utils.getSetting("debug") == 'true':
                    if playcount_xbmc > 0:
                        utils.showNotification(utils.getString(32402), name)
                    else:
                        utils.showNotification(utils.getString(32405), name)
            if commit:
                self.sqlcon.commit()  

        return count_return