1429 lines
59 KiB
Python
1429 lines
59 KiB
Python
# -*- coding: utf-8 -*-
|
||
# ------------------------------------------------------------
|
||
# XBMC Library Tools
|
||
# ------------------------------------------------------------
|
||
# from future import standard_library
|
||
# standard_library.install_aliases()
|
||
#from builtins import str
|
||
import sys, os, threading, time, re, math, xbmc, xbmcgui
|
||
PY3 = False
|
||
if sys.version_info[0] >= 3: PY3 = True; unicode = str; unichr = chr; long = int
|
||
|
||
if PY3:
|
||
import urllib.request as urllib2 # Es muy lento en PY2. En PY3 es nativo
|
||
else:
|
||
import urllib2 # Usamos el nativo de PY2 que es más rápido
|
||
|
||
from core import filetools, jsontools
|
||
from platformcode import config, logger, platformtools
|
||
from core import scrapertools
|
||
from xml.dom import minidom
|
||
|
||
|
||
def mark_auto_as_watched(item):
|
||
def mark_as_watched_subThread(item):
|
||
logger.debug()
|
||
actual_time = 0
|
||
total_time = 0
|
||
# logger.debug("item:\n" + item.tostring('\n'))
|
||
# if item.options['continue']: item.played_time = platformtools.resume_playback(platformtools.get_played_time(item))
|
||
|
||
time_limit = time.time() + 30
|
||
while not platformtools.is_playing() and time.time() < time_limit:
|
||
time.sleep(1)
|
||
|
||
|
||
marked = False
|
||
sync = False
|
||
next_episode = None
|
||
show_server = True
|
||
|
||
percentage = float(config.get_setting("watched_setting")) / 100
|
||
time_from_end = config.get_setting('next_ep_seconds')
|
||
if item.contentType != 'movie' and config.get_setting('next_ep'):
|
||
next_dialogs = ['NextDialog.xml', 'NextDialogExtended.xml', 'NextDialogCompact.xml']
|
||
next_ep_type = config.get_setting('next_ep_type')
|
||
ND = next_dialogs[next_ep_type]
|
||
try: next_episode = next_ep(item)
|
||
except: next_episode = False
|
||
|
||
while platformtools.is_playing():
|
||
actual_time = xbmc.Player().getTime()
|
||
total_time = xbmc.Player().getTotalTime()
|
||
if item.played_time and xbmcgui.getCurrentWindowId() == 12005:
|
||
xbmc.Player().seekTime(item.played_time)
|
||
item.played_time = 0 # Fix for Slow Devices
|
||
|
||
mark_time = total_time * percentage
|
||
difference = total_time - actual_time
|
||
|
||
# Mark as Watched
|
||
if actual_time > mark_time and not marked:
|
||
logger.info("Marked as Watched")
|
||
item.playcount = 1
|
||
marked = True
|
||
item.played_time = 0
|
||
platformtools.set_played_time(item)
|
||
if item.options['strm'] : sync = True
|
||
show_server = False
|
||
from specials import videolibrary
|
||
videolibrary.mark_content_as_watched2(item)
|
||
if not next_episode:
|
||
break
|
||
|
||
# check for next Episode
|
||
if next_episode and sync and time_from_end >= difference:
|
||
nextdialog = NextDialog(ND, config.get_runtime_path())
|
||
nextdialog.show()
|
||
while platformtools.is_playing() and not nextdialog.is_exit():
|
||
xbmc.sleep(100)
|
||
if nextdialog.continuewatching:
|
||
next_episode.next_ep = True
|
||
xbmc.Player().stop()
|
||
nextdialog.close()
|
||
break
|
||
xbmc.sleep(1000)
|
||
|
||
# if item.options['continue']:
|
||
if 10 < actual_time < mark_time:
|
||
item.played_time = actual_time
|
||
else: item.played_time = 0
|
||
platformtools.set_played_time(item)
|
||
|
||
# Silent sync with Trakt
|
||
if sync and config.get_setting("trakt_sync"): sync_trakt_kodi()
|
||
|
||
while platformtools.is_playing():
|
||
xbmc.sleep(100)
|
||
if not show_server and item.play_from != 'window' and not item.no_return:
|
||
xbmc.sleep(700)
|
||
xbmc.executebuiltin('Action(ParentDir)')
|
||
xbmc.sleep(500)
|
||
if next_episode and next_episode.next_ep:
|
||
from platformcode.launcher import play_from_library
|
||
return play_from_library(next_episode)
|
||
|
||
# If it is configured to mark as seen
|
||
if config.get_setting("mark_as_watched", "videolibrary"):
|
||
threading.Thread(target=mark_as_watched_subThread, args=[item]).start()
|
||
|
||
|
||
|
||
|
||
|
||
def sync_trakt_addon(path_folder):
|
||
"""
|
||
Updates the values of episodes seen if
|
||
"""
|
||
logger.debug()
|
||
# if the addon exists we do the search
|
||
if xbmc.getCondVisibility('System.HasAddon("script.trakt")'):
|
||
# we import dependencies
|
||
paths = ["special://home/addons/script.module.dateutil/lib/", "special://home/addons/script.module.six/lib/",
|
||
"special://home/addons/script.module.arrow/lib/", "special://home/addons/script.module.trakt/lib/",
|
||
"special://home/addons/script.trakt/"]
|
||
|
||
for path in paths:
|
||
sys.path.append(xbmc.translatePath(path))
|
||
|
||
# the series seen is obtained
|
||
try:
|
||
from resources.lib.traktapi import traktAPI
|
||
traktapi = traktAPI()
|
||
except:
|
||
return
|
||
|
||
shows = traktapi.getShowsWatched({})
|
||
shows = list(shows.items())
|
||
|
||
# we get the series id to compare
|
||
_id = re.findall(r"\[(.*?)\]", path_folder, flags=re.DOTALL)[0]
|
||
logger.debug("the id is %s" % _id)
|
||
|
||
if "tt" in _id:
|
||
type_id = "imdb"
|
||
elif "tvdb_" in _id:
|
||
_id = _id.strip("tvdb_")
|
||
type_id = "tvdb"
|
||
elif "tmdb_" in _id:
|
||
type_id = "tmdb"
|
||
_id = _id.strip("tmdb_")
|
||
else:
|
||
logger.error("There is no _id of the series")
|
||
return
|
||
|
||
# we obtain the values of the series
|
||
from core import videolibrarytools
|
||
tvshow_file = filetools.join(path_folder, "tvshow.nfo")
|
||
head_nfo, serie = videolibrarytools.read_nfo(tvshow_file)
|
||
|
||
# we look in the trakt series
|
||
for show in shows:
|
||
show_aux = show[1].to_dict()
|
||
|
||
try:
|
||
_id_trakt = show_aux['ids'].get(type_id, None)
|
||
# logger.debug("ID ES %s" % _id_trakt)
|
||
if _id_trakt:
|
||
if _id == _id_trakt:
|
||
logger.debug("FOUND! %s" % show_aux)
|
||
|
||
# we create the trakt dictionary for the found series with the value that has "seen"
|
||
dict_trakt_show = {}
|
||
|
||
for idx_season, season in enumerate(show_aux['seasons']):
|
||
for idx_episode, episode in enumerate(show_aux['seasons'][idx_season]['episodes']):
|
||
sea_epi = "%sx%s" % (show_aux['seasons'][idx_season]['number'], str(show_aux['seasons'][idx_season]['episodes'][idx_episode]['number']).zfill(2))
|
||
|
||
dict_trakt_show[sea_epi] = show_aux['seasons'][idx_season]['episodes'][idx_episode]['watched']
|
||
logger.debug("dict_trakt_show %s " % dict_trakt_show)
|
||
|
||
# we get the keys that are episodes
|
||
regex_epi = re.compile(r'\d+x\d+')
|
||
keys_episodes = [key for key in serie.library_playcounts if regex_epi.match(key)]
|
||
# we get the keys that are seasons
|
||
keys_seasons = [key for key in serie.library_playcounts if 'season ' in key]
|
||
# we get the numbers of the seasons keys
|
||
seasons = [key.strip('season ') for key in keys_seasons]
|
||
|
||
# we mark the episodes watched
|
||
for k in keys_episodes:
|
||
serie.library_playcounts[k] = dict_trakt_show.get(k, 0)
|
||
|
||
for season in seasons:
|
||
episodios_temporada = 0
|
||
episodios_vistos_temporada = 0
|
||
|
||
# we obtain the keys of the episodes of a certain season
|
||
keys_season_episodes = [key for key in keys_episodes if key.startswith("%sx" % season)]
|
||
|
||
for k in keys_season_episodes:
|
||
episodios_temporada += 1
|
||
if serie.library_playcounts[k] > 0:
|
||
episodios_vistos_temporada += 1
|
||
|
||
# it is verified that if all the episodes are watched, the season is marked as watched
|
||
if episodios_temporada == episodios_vistos_temporada:
|
||
serie.library_playcounts.update({"season %s" % season: 1})
|
||
|
||
temporada = 0
|
||
temporada_vista = 0
|
||
|
||
for k in keys_seasons:
|
||
temporada += 1
|
||
if serie.library_playcounts[k] > 0:
|
||
temporada_vista += 1
|
||
|
||
# sCheck that if all seasons are viewed, the series is marked as view
|
||
if temporada == temporada_vista:
|
||
serie.library_playcounts.update({serie.title: 1})
|
||
|
||
logger.debug("the new values %s " % serie.library_playcounts)
|
||
filetools.write(tvshow_file, head_nfo + serie.tojson())
|
||
|
||
break
|
||
else:
|
||
continue
|
||
|
||
else:
|
||
logger.error("could not get id, trakt has: %s" % show_aux['ids'])
|
||
|
||
except:
|
||
import traceback
|
||
logger.error(traceback.format_exc())
|
||
|
||
|
||
def sync_trakt_kodi(silent=True):
|
||
# So that the synchronization is not silent it is worth with silent = False
|
||
if xbmc.getCondVisibility('System.HasAddon("script.trakt")'):
|
||
notificacion = True
|
||
if not config.get_setting("sync_trakt_notification", "videolibrary") and platformtools.is_playing():
|
||
notificacion = False
|
||
|
||
xbmc.executebuiltin('RunScript(script.trakt,action=sync,silent=%s)' % silent)
|
||
logger.debug("Synchronization with Trakt started")
|
||
|
||
if notificacion:
|
||
platformtools.dialog_notification(config.get_localized_string(20000), config.get_localized_string(60045), sound=False, time=2000)
|
||
|
||
|
||
def mark_content_as_watched_on_kodi(item, value=1):
|
||
"""
|
||
mark the content as seen or not seen in the Kodi library
|
||
@type item: item
|
||
@param item: element to mark
|
||
@type value: int
|
||
@param value: > 0 for seen, 0 for not seen
|
||
"""
|
||
logger.debug()
|
||
# logger.debug("item:\n" + item.tostring('\n'))
|
||
payload_f = ''
|
||
|
||
if item.contentType == "movie":
|
||
movieid = 0
|
||
payload = {"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies",
|
||
"params": {"properties": ["title", "playcount", "originaltitle", "file"]},
|
||
"id": 1}
|
||
|
||
data = get_data(payload)
|
||
if 'result' in data and "movies" in data['result']:
|
||
|
||
if item.strm_path: # If Item is from an episode
|
||
filename = filetools.basename(item.strm_path)
|
||
head, tail = filetools.split(filetools.split(item.strm_path)[0])
|
||
else: # If Item is from the Series
|
||
filename = filetools.basename(item.path)
|
||
head, tail = filetools.split(filetools.split(item.path)[0])
|
||
path = filetools.join(tail, filename)
|
||
|
||
for d in data['result']['movies']:
|
||
if d['file'].replace("/", "\\").endswith(path.replace("/", "\\")):
|
||
# logger.debug("I mark the movie as a view")
|
||
movieid = d['movieid']
|
||
break
|
||
|
||
if movieid != 0:
|
||
payload_f = {"jsonrpc": "2.0", "method": "VideoLibrary.SetMovieDetails", "params": {"movieid": movieid, "playcount": value}, "id": 1}
|
||
|
||
else: # item.contentType != 'movie'
|
||
episodeid = 0
|
||
payload = {"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes",
|
||
"params": {"properties": ["title", "playcount", "showtitle", "file", "tvshowid"]},
|
||
"id": 1}
|
||
|
||
data = get_data(payload)
|
||
if 'result' in data and "episodes" in data['result']:
|
||
|
||
if item.strm_path: # If Item is from an episode
|
||
filename = filetools.basename(item.strm_path)
|
||
head, tail = filetools.split(filetools.split(item.strm_path)[0])
|
||
else: # If Item is from the Series
|
||
filename = filetools.basename(item.path)
|
||
head, tail = filetools.split(filetools.split(item.path)[0])
|
||
path = filetools.join(tail, filename)
|
||
|
||
for d in data['result']['episodes']:
|
||
if d['file'].replace("/", "\\").endswith(path.replace("/", "\\")):
|
||
# logger.debug("I mark the episode as seen")
|
||
episodeid = d['episodeid']
|
||
break
|
||
|
||
if episodeid != 0:
|
||
payload_f = {"jsonrpc": "2.0", "method": "VideoLibrary.SetEpisodeDetails", "params": {"episodeid": episodeid, "playcount": value}, "id": 1}
|
||
|
||
if payload_f:
|
||
# Mark as seen
|
||
data = get_data(payload_f)
|
||
# logger.debug(str(data))
|
||
if data['result'] != 'OK':
|
||
logger.error("ERROR putting content as viewed")
|
||
|
||
|
||
def mark_season_as_watched_on_kodi(item, value=1):
|
||
"""
|
||
mark the entire season as seen or unseen in the Kodi library
|
||
@type item: item
|
||
@param item: element to mark
|
||
@type value: int
|
||
@param value: > 0 for seen, 0 for not seen
|
||
"""
|
||
logger.debug()
|
||
# logger.debug("item:\n" + item.tostring('\n'))
|
||
|
||
# We can only mark the season as seen in the Kodi database if the database is local, in case of sharing database this functionality will not work
|
||
if config.get_setting("db_mode", "videolibrary"):
|
||
return
|
||
|
||
if value == 0:
|
||
value = 'Null'
|
||
|
||
request_season = ''
|
||
if item.contentSeason > -1:
|
||
request_season = ' and c12= %s' % item.contentSeason
|
||
|
||
tvshows_path = filetools.join(config.get_videolibrary_path(), config.get_setting("folder_tvshows"))
|
||
item_path1 = "%" + item.path.replace("\\\\", "\\").replace(tvshows_path, "")
|
||
if item_path1[:-1] != "\\":
|
||
item_path1 += "\\"
|
||
item_path2 = item_path1.replace("\\", "/")
|
||
|
||
sql = 'update files set playCount= %s where idFile in (select idfile from episode_view where (strPath like "%s" or strPath like "%s")%s)' % (value, item_path1, item_path2, request_season)
|
||
|
||
execute_sql_kodi(sql)
|
||
|
||
def set_watched_on_kod(data):
|
||
from specials import videolibrary
|
||
from core import videolibrarytools
|
||
logger.debug('TYPE',type(data))
|
||
data = jsontools.load(data)
|
||
logger.debug('TYPE',type(data))
|
||
Type = data['item']['type']
|
||
ID = data['item']['id']
|
||
playcount = data['playcount']
|
||
for Type in ['movie', 'episode']:
|
||
sql = 'select strFileName, strPath, uniqueid_value from %s_view where (id%s like "%s")' % (Type, Type.capitalize(), ID)
|
||
n, records = execute_sql_kodi(sql)
|
||
if records:
|
||
for filename, path, uniqueid_value in records:
|
||
if Type in ['movie']:
|
||
title = filename.replace('.strm', ' [' + uniqueid_value + ']')
|
||
filename = title +'.nfo'
|
||
else:
|
||
title = filename.replace('.strm', '')
|
||
filename = 'tvshow.nfo'
|
||
|
||
path = filetools.join(path, filename)
|
||
head_nfo, item = videolibrarytools.read_nfo(path)
|
||
item.library_playcounts.update({title: playcount})
|
||
filetools.write(path, head_nfo + item.tojson())
|
||
|
||
if item.infoLabels['mediatype'] == "tvshow":
|
||
for season in item.library_playcounts:
|
||
if "season" in season:
|
||
season_num = int(scrapertools.find_single_match(season, r'season (\d+)'))
|
||
item = videolibrary.check_season_playcount(item, season_num)
|
||
filetools.write(path, head_nfo + item.tojson())
|
||
|
||
def mark_content_as_watched_on_kod(path):
|
||
from specials import videolibrary
|
||
from core import videolibrarytools
|
||
|
||
"""
|
||
mark the entire series or movie as viewed or unseen in the Alpha Video Library based on their status in the Kodi Video Library
|
||
@type str: path
|
||
@param path: content folder to mark
|
||
"""
|
||
logger.debug()
|
||
#logger.debug("path: " + path)
|
||
|
||
FOLDER_MOVIES = config.get_setting("folder_movies")
|
||
FOLDER_TVSHOWS = config.get_setting("folder_tvshows")
|
||
VIDEOLIBRARY_PATH = config.get_videolibrary_config_path()
|
||
if not VIDEOLIBRARY_PATH:
|
||
return
|
||
|
||
# We can only mark the content as a view in the Kodi database if the database is local, in case of sharing database this functionality will not work
|
||
# if config.get_setting("db_mode", "videolibrary"):
|
||
# return
|
||
|
||
path2 = ''
|
||
if "special://" in VIDEOLIBRARY_PATH:
|
||
if FOLDER_TVSHOWS in path:
|
||
path2 = re. sub(r'.*?%s' % FOLDER_TVSHOWS, filetools.join(VIDEOLIBRARY_PATH, FOLDER_TVSHOWS), path).replace("\\", "/")
|
||
if FOLDER_MOVIES in path:
|
||
path2 = re. sub(r'.*?%s' % FOLDER_MOVIES, filetools.join(VIDEOLIBRARY_PATH, FOLDER_MOVIES), path).replace("\\", "/")
|
||
|
||
if "\\" in path:
|
||
path = path.replace("/", "\\")
|
||
head_nfo, item = videolibrarytools.read_nfo(path) # I read the content .nfo
|
||
old = item.clone()
|
||
if not item:
|
||
logger.error('.NFO not found: ' + path)
|
||
return
|
||
|
||
if FOLDER_TVSHOWS in path: # I check if it is CINEMA or SERIES
|
||
contentType = "episode_view" # I mark the Kodi Video BBDD table
|
||
nfo_name = "tvshow.nfo" # I build the name of the .nfo
|
||
path1 = path.replace("\\\\", "\\").replace(nfo_name, '') # for SQL I just need the folder
|
||
if not path2:
|
||
path2 = path1.replace("\\", "/") # Format no Windows
|
||
else:
|
||
path2 = path2.replace(nfo_name, '')
|
||
|
||
else:
|
||
contentType = "movie_view" # I mark the Kodi Video BBDD table
|
||
path1 = path.replace("\\\\", "\\") # Windows format
|
||
if not path2:
|
||
path2 = path1.replace("\\", "/") # Format no Windows
|
||
nfo_name = scrapertools.find_single_match(path2, r'\]\/(.*?)$') # I build the name of the .nfo
|
||
path1 = path1.replace(nfo_name, '') # for SQL I just need the folder
|
||
path2 = path2.replace(nfo_name, '') # for SQL I just need the folder
|
||
path2 = filetools.remove_smb_credential(path2) # If the file is on an SMB server, we remove the credentials
|
||
|
||
# Let's execute the SQL statement
|
||
sql = 'select strFileName, playCount from %s where (strPath like "%s" or strPath like "%s")' % (contentType, path1, path2)
|
||
nun_records = 0
|
||
records = None
|
||
nun_records, records = execute_sql_kodi(sql) # SQL execution
|
||
if nun_records == 0: # is there an error?
|
||
logger.error("SQL error: " + sql + ": 0 registros")
|
||
return # we quit: either it is not cataloged in Kodi, or there is an error in the SQL
|
||
|
||
for title, playCount in records: # Now we go through all the records obtained
|
||
if contentType == "episode_view":
|
||
title_plain = title.replace('.strm', '') # If it is Serial, we remove the suffix .strm
|
||
else:
|
||
title_plain = scrapertools.find_single_match(item.strm_path, r'.(.*?\s\[.*?\])') # if it's a movie, we remove the title
|
||
if playCount is None or playCount == 0: # not yet seen, we set it to 0
|
||
playCount_final = 0
|
||
elif playCount >= 1:
|
||
playCount_final = 1
|
||
|
||
elif not PY3 and isinstance(title_plain, (str, unicode)):
|
||
title_plain = title_plain.decode("utf-8").encode("utf-8") # We do this because if it doesn't generate this: u'title_plain '
|
||
elif PY3 and isinstance(title_plain, bytes):
|
||
title_plain = title_plain.decode('utf-8')
|
||
item.library_playcounts.update({title_plain: playCount_final}) # update the .nfo playCount
|
||
|
||
if item.infoLabels['mediatype'] == "tvshow": # We update the Season and Series playCounts
|
||
for season in item.library_playcounts:
|
||
if "season" in season: # we look for the tags "season" inside playCounts
|
||
season_num = int(scrapertools.find_single_match(season, r'season (\d+)')) # we save the season number
|
||
item = videolibrary.check_season_playcount(item, season_num) # We call the method that updates Temps. and series
|
||
if item.library_playcounts != old.library_playcounts:
|
||
logger.debug('scrivo')
|
||
filetools.write(path, head_nfo + item.tojson())
|
||
|
||
#logger.debug(item)
|
||
|
||
|
||
def get_data(payload):
|
||
"""
|
||
get the information of the JSON-RPC call with the information passed in payload
|
||
@type payload: dict
|
||
@param payload: data
|
||
:return:
|
||
"""
|
||
try:
|
||
import urllib.request as urllib
|
||
except ImportError:
|
||
import urllib
|
||
logger.debug("payload: %s" % payload)
|
||
# Required header for XBMC JSON-RPC calls, otherwise you'll get a 415 HTTP response code - Unsupported media type
|
||
headers = {'content-type': 'application/json'}
|
||
|
||
if config.get_setting("db_mode", "videolibrary"):
|
||
try:
|
||
try:
|
||
xbmc_port = config.get_setting("xbmc_puerto", "videolibrary")
|
||
except:
|
||
xbmc_port = 0
|
||
|
||
xbmc_json_rpc_url = "http://" + config.get_setting("xbmc_host", "videolibrary") + ":" + str(xbmc_port) + "/jsonrpc"
|
||
req = urllib2.Request(xbmc_json_rpc_url, data=jsontools.dump(payload), headers=headers)
|
||
f = urllib.urlopen(req)
|
||
response = f.read()
|
||
f.close()
|
||
|
||
logger.debug("get_data: response %s" % response)
|
||
data = jsontools.load(response)
|
||
except Exception as ex:
|
||
template = "An exception of type %s occured. Arguments:\n%r"
|
||
message = template % (type(ex).__name__, ex.args)
|
||
logger.error("error en xbmc_json_rpc_url: %s" % message)
|
||
data = ["error"]
|
||
else:
|
||
try:
|
||
data = jsontools.load(xbmc.executeJSONRPC(jsontools.dump(payload)))
|
||
except Exception as ex:
|
||
template = "An exception of type %s occured. Arguments:\n%r"
|
||
message = template % (type(ex).__name__, ex.args)
|
||
logger.error("error en xbmc.executeJSONRPC: %s" % message)
|
||
data = ["error"]
|
||
|
||
logger.debug("data: %s" % data)
|
||
|
||
return data
|
||
|
||
|
||
def update(folder_content=config.get_setting("folder_tvshows"), folder=""):
|
||
"""
|
||
Update the library depending on the type of content and the path passed to it.
|
||
|
||
@type folder_content: str
|
||
@param folder_content: type of content to update, series or movies
|
||
@type folder: str
|
||
@param folder: name of the folder to scan.
|
||
"""
|
||
logger.debug(folder)
|
||
|
||
payload = {
|
||
"jsonrpc": "2.0",
|
||
"method": "VideoLibrary.Scan",
|
||
"id": 1
|
||
}
|
||
|
||
if folder:
|
||
folder = str(folder)
|
||
videolibrarypath = config.get_videolibrary_config_path()
|
||
|
||
if folder.endswith('/') or folder.endswith('\\'):
|
||
folder = folder[:-1]
|
||
|
||
update_path = None
|
||
|
||
if videolibrarypath.startswith("special:"):
|
||
if videolibrarypath.endswith('/'):
|
||
videolibrarypath = videolibrarypath[:-1]
|
||
update_path = videolibrarypath + "/" + folder_content + "/" + folder + "/"
|
||
else:
|
||
# update_path = filetools.join(videolibrarypath, folder_content, folder) + "/" # Encoder problems in "folder"
|
||
update_path = filetools.join(videolibrarypath, folder_content, ' ').rstrip()
|
||
|
||
if videolibrarypath.startswith("special:") or not scrapertools.find_single_match(update_path, r'(^\w+:\/\/)'):
|
||
payload["params"] = {"directory": update_path}
|
||
|
||
while xbmc.getCondVisibility('Library.IsScanningVideo()'):
|
||
xbmc.sleep(500)
|
||
|
||
data = get_data(payload)
|
||
|
||
|
||
def search_library_path():
|
||
sql = 'SELECT strPath FROM path WHERE strPath LIKE "special://%/plugin.video.kod/library/" AND idParentPath ISNULL'
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if nun_records >= 1:
|
||
logger.debug(records[0][0])
|
||
return records[0][0]
|
||
return None
|
||
|
||
|
||
def search_local_path(item):
|
||
ids = [item.infoLabels['imdb_id'], item.infoLabels['tmdb_id'], item.infoLabels['tvdb_id']]
|
||
for Id in ids:
|
||
nun_ids, ids = execute_sql_kodi('SELECT idShow FROM tvshow_view WHERE uniqueid_value LIKE "%s"' % Id)
|
||
if nun_ids >= 1:
|
||
nun_records, records = execute_sql_kodi('SELECT idPath FROM tvshowlinkpath WHERE idShow LIKE "%s"' % ids[0][0])
|
||
if nun_records >= 1:
|
||
for record in records:
|
||
num_path, path_records = execute_sql_kodi('SELECT strPath FROM path WHERE idPath LIKE "%s"' % record[0])
|
||
for path in path_records:
|
||
if config.get_setting('videolibrarypath') not in path[0]:
|
||
return path[0]
|
||
return ''
|
||
|
||
|
||
def set_content(content_type, silent=False, custom=False):
|
||
"""
|
||
Procedure to auto-configure the kodi video library with the default values
|
||
@type content_type: str ('movie' o 'tvshow')
|
||
@param content_type: content type to configure, series or movies
|
||
"""
|
||
logger.debug()
|
||
continuar = True
|
||
msg_text = ""
|
||
videolibrarypath = config.get_setting("videolibrarypath")
|
||
|
||
if content_type == 'movie':
|
||
scraper = [config.get_localized_string(70093), config.get_localized_string(70096)]
|
||
if not custom:
|
||
seleccion = 0 # tmdb
|
||
else:
|
||
seleccion = platformtools.dialog_select(config.get_localized_string(70094), scraper)
|
||
|
||
|
||
# Instalar The Movie Database
|
||
if seleccion == -1 or seleccion == 0:
|
||
if not xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)'):
|
||
if not silent:
|
||
# Ask if we want to install metadata.themoviedb.org
|
||
install = platformtools.dialog_yesno(config.get_localized_string(60046),'')
|
||
else:
|
||
install = True
|
||
|
||
if install:
|
||
try:
|
||
# Install metadata.themoviedb.org
|
||
xbmc.executebuiltin('InstallAddon(metadata.themoviedb.org)', True)
|
||
logger.debug("Instalado el Scraper de películas de TheMovieDB")
|
||
except:
|
||
pass
|
||
|
||
continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.themoviedb.org)'))
|
||
if not continuar:
|
||
msg_text = config.get_localized_string(60047)
|
||
if continuar:
|
||
xbmc.executebuiltin('Addon.OpenSettings(metadata.themoviedb.org)', True)
|
||
|
||
# Instalar Universal Movie Scraper
|
||
elif seleccion == 1:
|
||
if continuar and not xbmc.getCondVisibility('System.HasAddon(metadata.universal)'):
|
||
continuar = False
|
||
if not silent:
|
||
# Ask if we want to install metadata.universal
|
||
install = platformtools.dialog_yesno(config.get_localized_string(70095),'')
|
||
else:
|
||
install = True
|
||
|
||
if install:
|
||
try:
|
||
xbmc.executebuiltin('InstallAddon(metadata.universal)', True)
|
||
if xbmc.getCondVisibility('System.HasAddon(metadata.universal)'):
|
||
continuar = True
|
||
except:
|
||
pass
|
||
|
||
continuar = (install and continuar)
|
||
if not continuar:
|
||
msg_text = config.get_localized_string(70097)
|
||
if continuar:
|
||
xbmc.executebuiltin('Addon.OpenSettings(metadata.universal)', True)
|
||
|
||
else: # SERIES
|
||
scraper = [config.get_localized_string(70098), config.get_localized_string(70093)]
|
||
if not custom:
|
||
seleccion = 0 # tvdb
|
||
else:
|
||
seleccion = platformtools.dialog_select(config.get_localized_string(70107), scraper)
|
||
|
||
# Instalar The TVDB
|
||
if seleccion == -1 or seleccion == 0:
|
||
if not xbmc.getCondVisibility('System.HasAddon(metadata.tvdb.com)'):
|
||
if not silent:
|
||
#Ask if we want to install metadata.tvdb.com
|
||
install = platformtools.dialog_yesno(config.get_localized_string(60048),'')
|
||
else:
|
||
install = True
|
||
|
||
if install:
|
||
try:
|
||
# Install metadata.tvdb.com
|
||
xbmc.executebuiltin('InstallAddon(metadata.tvdb.com)', True)
|
||
logger.debug("The TVDB series Scraper installed ")
|
||
except:
|
||
pass
|
||
|
||
continuar = (install and xbmc.getCondVisibility('System.HasAddon(metadata.tvdb.com)'))
|
||
if not continuar:
|
||
msg_text = config.get_localized_string(60049)
|
||
if continuar:
|
||
xbmc.executebuiltin('Addon.OpenSettings(metadata.tvdb.com)', True)
|
||
|
||
# Instalar The Movie Database
|
||
elif seleccion == 1:
|
||
if continuar and not xbmc.getCondVisibility('System.HasAddon(metadata.tvshows.themoviedb.org)'):
|
||
continuar = False
|
||
if not silent:
|
||
# Ask if we want to install metadata.tvshows.themoviedb.org
|
||
install = platformtools.dialog_yesno(config.get_localized_string(60050),'')
|
||
else:
|
||
install = True
|
||
|
||
if install:
|
||
try:
|
||
# Install metadata.tvshows.themoviedb.org
|
||
xbmc.executebuiltin('InstallAddon(metadata.tvshows.themoviedb.org)', True)
|
||
if xbmc.getCondVisibility('System.HasAddon(metadata.tvshows.themoviedb.org)'):
|
||
continuar = True
|
||
except:
|
||
pass
|
||
|
||
continuar = (install and continuar)
|
||
if not continuar:
|
||
msg_text = config.get_localized_string(60051)
|
||
if continuar:
|
||
xbmc.executebuiltin('Addon.OpenSettings(metadata.tvshows.themoviedb.org)', True)
|
||
|
||
idPath = 0
|
||
idParentPath = 0
|
||
if continuar:
|
||
continuar = False
|
||
|
||
# We look for the idPath
|
||
sql = 'SELECT MAX(idPath) FROM path'
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if nun_records == 1:
|
||
idPath = records[0][0] + 1
|
||
|
||
sql_videolibrarypath = videolibrarypath
|
||
if sql_videolibrarypath.startswith("special://"):
|
||
sql_videolibrarypath = sql_videolibrarypath.replace('/profile/', '/%/').replace('/home/userdata/', '/%/')
|
||
sep = '/'
|
||
elif scrapertools.find_single_match(sql_videolibrarypath, r'(^\w+:\/\/)'):
|
||
sep = '/'
|
||
else:
|
||
sep = os.sep
|
||
|
||
if not sql_videolibrarypath.endswith(sep):
|
||
sql_videolibrarypath += sep
|
||
|
||
# We are looking for the idParentPath
|
||
sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_videolibrarypath
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if nun_records == 1:
|
||
idParentPath = records[0][0]
|
||
videolibrarypath = records[0][1][:-1]
|
||
continuar = True
|
||
else:
|
||
# There is no videolibrarypath in the DB: we insert it
|
||
sql_videolibrarypath = videolibrarypath
|
||
if not sql_videolibrarypath.endswith(sep):
|
||
sql_videolibrarypath += sep
|
||
|
||
sql = 'INSERT INTO path (idPath, strPath, scanRecursive, useFolderNames, noUpdate, exclude) VALUES ' \
|
||
'(%s, "%s", 0, 0, 0, 0)' % (idPath, sql_videolibrarypath)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if nun_records == 1:
|
||
continuar = True
|
||
idParentPath = idPath
|
||
idPath += 1
|
||
else:
|
||
msg_text = config.get_localized_string(70101)
|
||
|
||
if continuar:
|
||
continuar = False
|
||
|
||
# We set strContent, strScraper, scanRecursive and strSettings
|
||
if content_type == 'movie':
|
||
strContent = 'movies'
|
||
scanRecursive = 2147483647
|
||
if seleccion == -1 or seleccion == 0:
|
||
strScraper = 'metadata.themoviedb.org'
|
||
path_settings = xbmc.translatePath("special://profile/addon_data/metadata.themoviedb.org/settings.xml")
|
||
elif seleccion == 1:
|
||
strScraper = 'metadata.universal'
|
||
path_settings = xbmc.translatePath("special://profile/addon_data/metadata.universal/settings.xml")
|
||
if not os.path.exists(path_settings):
|
||
logger.debug("%s: %s" % (content_type, path_settings + " doesn't exist"))
|
||
return continuar
|
||
settings_data = filetools.read(path_settings)
|
||
strSettings = ' '.join(settings_data.split()).replace("> <", "><")
|
||
strSettings = strSettings.replace("\"","\'")
|
||
strActualizar = "Do you want to set this Scraper in Spanish as the default option for movies?"
|
||
if not videolibrarypath.endswith(sep):
|
||
videolibrarypath += sep
|
||
strPath = videolibrarypath + config.get_setting("folder_movies") + sep
|
||
else:
|
||
strContent = 'tvshows'
|
||
scanRecursive = 0
|
||
if seleccion == -1 or seleccion == 0:
|
||
strScraper = 'metadata.tvdb.com'
|
||
path_settings = xbmc.translatePath("special://profile/addon_data/metadata.tvdb.com/settings.xml")
|
||
elif seleccion == 1:
|
||
strScraper = 'metadata.tvshows.themoviedb.org'
|
||
path_settings = xbmc.translatePath("special://profile/addon_data/metadata.tvshows.themoviedb.org/settings.xml")
|
||
if not os.path.exists(path_settings):
|
||
logger.debug("%s: %s" % (content_type, path_settings + " doesn't exist"))
|
||
return continuar
|
||
settings_data = filetools.read(path_settings)
|
||
strSettings = ' '.join(settings_data.split()).replace("> <", "><")
|
||
strSettings = strSettings.replace("\"","\'")
|
||
strActualizar = "Do you want to configure this Scraper in Spanish as a default option for series?"
|
||
if not videolibrarypath.endswith(sep):
|
||
videolibrarypath += sep
|
||
strPath = videolibrarypath + config.get_setting("folder_tvshows") + sep
|
||
|
||
logger.debug("%s: %s" % (content_type, strPath))
|
||
# We check if strPath already exists in the DB to avoid duplicates
|
||
sql = 'SELECT idPath FROM path where strPath="%s"' % strPath
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
sql = ""
|
||
if nun_records == 0:
|
||
# Insertamos el scraper
|
||
sql = 'INSERT INTO path (idPath, strPath, strContent, strScraper, scanRecursive, useFolderNames, ' \
|
||
'strSettings, noUpdate, exclude, idParentPath) VALUES (%s, "%s", "%s", "%s", %s, 0, ' \
|
||
'"%s", 0, 0, %s)' % (
|
||
idPath, strPath, strContent, strScraper, scanRecursive, strSettings, idParentPath)
|
||
else:
|
||
if not silent:
|
||
# Preguntar si queremos configurar themoviedb.org como opcion por defecto
|
||
actualizar = platformtools.dialog_yesno(config.get_localized_string(70098), strActualizar)
|
||
else:
|
||
actualizar = True
|
||
|
||
if actualizar:
|
||
# Actualizamos el scraper
|
||
idPath = records[0][0]
|
||
sql = 'UPDATE path SET strContent="%s", strScraper="%s", scanRecursive=%s, strSettings="%s" ' \
|
||
'WHERE idPath=%s' % (strContent, strScraper, scanRecursive, strSettings, idPath)
|
||
|
||
if sql:
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if nun_records == 1:
|
||
continuar = True
|
||
|
||
if not continuar:
|
||
msg_text = config.get_localized_string(60055)
|
||
|
||
if not continuar:
|
||
heading = config.get_localized_string(70102) % content_type
|
||
elif content_type == 'tvshow' and not xbmc.getCondVisibility(
|
||
'System.HasAddon(metadata.tvshows.themoviedb.org)'):
|
||
heading = config.get_localized_string(70103) % content_type
|
||
msg_text = config.get_localized_string(60058)
|
||
else:
|
||
heading = config.get_localized_string(70103) % content_type
|
||
msg_text = config.get_localized_string(70104)
|
||
|
||
logger.debug("%s: %s" % (heading, msg_text))
|
||
return continuar
|
||
|
||
|
||
def update_db(old_path, new_path, old_movies_folder, new_movies_folder, old_tvshows_folder, new_tvshows_folder, progress):
|
||
def path_replace(path, old, new):
|
||
|
||
logger.debug()
|
||
logger.debug('path: ' + path + ', old: ' + old + ', new: ' + new)
|
||
|
||
if new.startswith("special://") or '://' in new: sep = '/'
|
||
else: sep = os.sep
|
||
|
||
path = path.replace(old,new)
|
||
if sep == '/': path = path.replace('\\','/')
|
||
else: path = path.replace('/','\\')
|
||
|
||
return path
|
||
|
||
logger.debug()
|
||
|
||
sql_old_path = old_path
|
||
if sql_old_path.startswith("special://"):
|
||
sql_old_path = sql_old_path.replace('/profile/', '/%/').replace('/home/userdata/', '/%/')
|
||
sep = '/'
|
||
elif '://' in sql_old_path:
|
||
sep = '/'
|
||
else: sep = os.sep
|
||
if not sql_old_path.endswith(sep):
|
||
sql_old_path += sep
|
||
|
||
logger.debug('sql_old_path: ' + sql_old_path)
|
||
# search MAIN path in the DB
|
||
sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_old_path
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
|
||
# change main path
|
||
if records:
|
||
idPath = records[0][0]
|
||
strPath = path_replace(records[0][1], old_path, new_path)
|
||
sql = 'UPDATE path SET strPath="%s" WHERE idPath=%s' % (strPath, idPath)
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
else:
|
||
progress.update(100)
|
||
xbmc.sleep(1000)
|
||
progress.close()
|
||
return
|
||
|
||
p = 80
|
||
progress.update(p, config.get_localized_string(20000) + '\n' + config.get_localized_string(80013))
|
||
|
||
for OldFolder, NewFolder in [[old_movies_folder, new_movies_folder], [old_tvshows_folder, new_tvshows_folder]]:
|
||
sql_old_folder = sql_old_path + OldFolder
|
||
if not sql_old_folder.endswith(sep): sql_old_folder += sep
|
||
|
||
# Search Main Sub Folder
|
||
sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_old_folder
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
|
||
# Change Main Sub Folder
|
||
if records:
|
||
for record in records:
|
||
idPath = record[0]
|
||
strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder))
|
||
sql = 'UPDATE path SET strPath="%s" WHERE idPath=%s' % (strPath, idPath)
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
|
||
# Search if Sub Folder exixt in all paths
|
||
sql_old_folder += '%'
|
||
sql = 'SELECT idPath, strPath FROM path where strPath LIKE "%s"' % sql_old_folder
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
|
||
#Change Sub Folder in all paths
|
||
if records:
|
||
for record in records:
|
||
idPath = record[0]
|
||
strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder))
|
||
sql = 'UPDATE path SET strPath="%s" WHERE idPath=%s' % (strPath, idPath)
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
|
||
|
||
if OldFolder == old_movies_folder:
|
||
# if is Movie Folder
|
||
# search and modify in "movie"
|
||
sql = 'SELECT idMovie, c22 FROM movie where c22 LIKE "%s"' % sql_old_folder
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if records:
|
||
for record in records:
|
||
idMovie = record[0]
|
||
strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder))
|
||
sql = 'UPDATE movie SET c22="%s" WHERE idMovie=%s' % (strPath, idMovie)
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
else:
|
||
# if is TV Show Folder
|
||
# search and modify in "episode"
|
||
sql = 'SELECT idEpisode, c18 FROM episode where c18 LIKE "%s"' % sql_old_folder
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if records:
|
||
for record in records:
|
||
idEpisode = record[0]
|
||
strPath = path_replace(record[1], filetools.join(old_path, OldFolder), filetools.join(new_path, NewFolder))
|
||
sql = 'UPDATE episode SET c18="%s" WHERE idEpisode=%s' % (strPath, idEpisode)
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
p += 5
|
||
progress.update(p, config.get_localized_string(20000) + '\n' + config.get_localized_string(80013))
|
||
|
||
progress.update(100)
|
||
xbmc.sleep(1000)
|
||
progress.close()
|
||
xbmc.executebuiltin('ReloadSkin()')
|
||
|
||
|
||
def clean(path_list=[]):
|
||
def sql_format(path):
|
||
if path.startswith("special://"):
|
||
path = path.replace('/profile/', '/%/').replace('/home/userdata/', '/%/')
|
||
sep = '/'
|
||
elif '://' in path or path.startswith('/') or path.startswith('%/'):
|
||
sep = '/'
|
||
else: sep = os.sep
|
||
|
||
if sep == '/': path = path.replace('\\','/')
|
||
else: path = path.replace('/','\\')
|
||
|
||
return path, sep
|
||
|
||
logger.debug()
|
||
|
||
progress = platformtools.dialog_progress_bg(config.get_localized_string(20000), config.get_localized_string(80025))
|
||
progress.update(0)
|
||
|
||
# if the path list is empty, clean the entire video library
|
||
if not path_list:
|
||
logger.debug('the path list is empty, clean the entire video library')
|
||
if not config.get_setting("videolibrary_kodi"):
|
||
sql_path, sep = sql_format(config.get_setting("videolibrarypath"))
|
||
if not sql_path.endswith(sep): sql_path += sep
|
||
sql = 'SELECT idPath FROM path where strPath LIKE "%s"' % sql_path
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
idPath = records[0][0]
|
||
sql = 'DELETE from path WHERE idPath=%s' % idPath
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
sql = 'DELETE from path WHERE idParentPath=%s' % idPath
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
|
||
from core import videolibrarytools
|
||
for path, folders, files in filetools.walk(videolibrarytools.MOVIES_PATH):
|
||
for folder in folders:
|
||
path_list.append(filetools.join(config.get_setting("videolibrarypath"), videolibrarytools.FOLDER_MOVIES, folder))
|
||
|
||
for path, folders, files in filetools.walk(videolibrarytools.TVSHOWS_PATH):
|
||
for folder in folders:
|
||
tvshow_nfo = filetools.join(path, folder, "tvshow.nfo")
|
||
if filetools.exists(tvshow_nfo):
|
||
path_list.append(filetools.join(config.get_setting("videolibrarypath"), videolibrarytools.FOLDER_TVSHOWS, folder))
|
||
|
||
logger.debug('path_list: ' + str(path_list))
|
||
if path_list: t = float(100) / len(path_list)
|
||
for i, path in enumerate(path_list):
|
||
progress.update(int(math.ceil((i + 1) * t)))
|
||
|
||
if not path:
|
||
continue
|
||
|
||
sql_path, sep = sql_format(path)
|
||
if filetools.isdir(path) and not sql_path.endswith(sep): sql_path += sep
|
||
logger.debug('path: ' + path)
|
||
logger.debug('sql_path: ' + sql_path)
|
||
|
||
if filetools.isdir(path):
|
||
# search movie in the DB
|
||
sql = 'SELECT idMovie FROM movie where c22 LIKE "%s"' % (sql_path + '%')
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
# delete movie
|
||
if records:
|
||
payload = {"jsonrpc": "2.0", "method": "VideoLibrary.RemoveMovie", "id": 1, "params": {"movieid": records[0][0]}}
|
||
data = get_data(payload)
|
||
continue
|
||
# search TV show in the DB
|
||
sql = 'SELECT idShow FROM tvshow_view where strPath LIKE "%s"' % sql_path
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
# delete TV show
|
||
if records:
|
||
payload = {"jsonrpc": "2.0", "method": "VideoLibrary.RemoveTVShow", "id": 1, "params": {"tvshowid": records[0][0]}}
|
||
data = get_data(payload)
|
||
elif config.get_setting("folder_movies") in sql_path:
|
||
# search movie in the DB
|
||
sql = 'SELECT idMovie FROM movie where c22 LIKE "%s"' % sql_path
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
# delete movie
|
||
if records:
|
||
payload = {"jsonrpc": "2.0", "method": "VideoLibrary.RemoveMovie", "id": 1, "params": {"movieid": records[0][0]}}
|
||
data = get_data(payload)
|
||
else:
|
||
# search episode in the DB
|
||
sql = 'SELECT idEpisode FROM episode where c18 LIKE "%s"' % sql_path
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
# delete episode
|
||
if records:
|
||
payload = {"jsonrpc": "2.0", "method": "VideoLibrary.RemoveEpisode", "id": 1, "params": {"episodeid": records[0][0]}}
|
||
data = get_data(payload)
|
||
|
||
progress.update(100)
|
||
xbmc.sleep(1000)
|
||
progress.close()
|
||
|
||
|
||
def check_db(path):
|
||
if '\\' in path: sep = '\\'
|
||
else: sep = '/'
|
||
if path.endswith(sep): path = path[:-len(sep)]
|
||
ret = False
|
||
sql_path = '%' + sep + path.split(sep)[-1] + sep + '%'
|
||
sql = 'SELECT idShow FROM tvshow_view where strPath LIKE "%s"' % sql_path
|
||
logger.debug('sql: ' + sql)
|
||
nun_records, records = execute_sql_kodi(sql)
|
||
if records:
|
||
ret = True
|
||
return ret
|
||
|
||
|
||
def execute_sql_kodi(sql):
|
||
"""
|
||
Run sql query against kodi database
|
||
@param sql: Valid sql query
|
||
@type sql: str
|
||
@return: Number of records modified or returned by the query
|
||
@rtype nun_records: int
|
||
@return: list with the query result
|
||
@rtype records: list of tuples
|
||
"""
|
||
logger.debug()
|
||
file_db = ""
|
||
nun_records = 0
|
||
records = None
|
||
|
||
# We look for the archive of the video database according to the version of kodi
|
||
video_db = config.get_platform(True)['video_db']
|
||
if video_db:
|
||
file_db = filetools.join(xbmc.translatePath("special://userdata/Database"), video_db)
|
||
|
||
# alternative method to locate the database
|
||
if not file_db or not filetools.exists(file_db):
|
||
file_db = ""
|
||
for f in filetools.listdir(xbmc.translatePath("special://userdata/Database")):
|
||
path_f = filetools.join(xbmc.translatePath("special://userdata/Database"), f)
|
||
|
||
if filetools.isfile(path_f) and f.lower().startswith('myvideos') and f.lower().endswith('.db'):
|
||
file_db = path_f
|
||
break
|
||
|
||
if file_db:
|
||
logger.debug("DB file: %s" % file_db)
|
||
conn = None
|
||
try:
|
||
import sqlite3
|
||
conn = sqlite3.connect(file_db)
|
||
cursor = conn.cursor()
|
||
|
||
logger.debug("Running sql: %s" % sql)
|
||
cursor.execute(sql)
|
||
conn.commit()
|
||
|
||
records = cursor.fetchall()
|
||
if sql.lower().startswith("select"):
|
||
nun_records = len(records)
|
||
if nun_records == 1 and records[0][0] is None:
|
||
nun_records = 0
|
||
records = []
|
||
else:
|
||
nun_records = conn.total_changes
|
||
|
||
conn.close()
|
||
logger.debug("Query executed. Records: %s" % nun_records)
|
||
|
||
except:
|
||
logger.error("Error executing sql query")
|
||
if conn:
|
||
conn.close()
|
||
|
||
else:
|
||
logger.debug("Database not found")
|
||
|
||
return nun_records, records
|
||
|
||
|
||
def check_sources(new_movies_path='', new_tvshows_path=''):
|
||
def format_path(path):
|
||
if path.startswith("special://") or '://' in path: sep = '/'
|
||
else: sep = os.sep
|
||
if not path.endswith(sep): path += sep
|
||
return path
|
||
|
||
logger.debug()
|
||
|
||
new_movies_path = format_path(new_movies_path)
|
||
new_tvshows_path = format_path(new_tvshows_path)
|
||
|
||
SOURCES_PATH = xbmc.translatePath("special://userdata/sources.xml")
|
||
if filetools.isfile(SOURCES_PATH):
|
||
xmldoc = minidom.parse(SOURCES_PATH)
|
||
|
||
video_node = xmldoc.childNodes[0].getElementsByTagName("video")[0]
|
||
paths_node = video_node.getElementsByTagName("path")
|
||
list_path = [p.firstChild.data for p in paths_node]
|
||
|
||
return new_movies_path in list_path, new_tvshows_path in list_path
|
||
else:
|
||
xmldoc = minidom.Document()
|
||
source_nodes = xmldoc.createElement("sources")
|
||
|
||
for type in ['programs', 'video', 'music', 'picture', 'files']:
|
||
nodo_type = xmldoc.createElement(type)
|
||
element_default = xmldoc.createElement("default")
|
||
element_default.setAttribute("pathversion", "1")
|
||
nodo_type.appendChild(element_default)
|
||
source_nodes.appendChild(nodo_type)
|
||
xmldoc.appendChild(source_nodes)
|
||
|
||
return False, False
|
||
|
||
|
||
def update_sources(new='', old=''):
|
||
logger.debug()
|
||
if new == old: return
|
||
|
||
SOURCES_PATH = xbmc.translatePath("special://userdata/sources.xml")
|
||
if filetools.isfile(SOURCES_PATH):
|
||
xmldoc = minidom.parse(SOURCES_PATH)
|
||
else:
|
||
xmldoc = minidom.Document()
|
||
source_nodes = xmldoc.createElement("sources")
|
||
|
||
for type in ['programs', 'video', 'music', 'picture', 'files']:
|
||
nodo_type = xmldoc.createElement(type)
|
||
element_default = xmldoc.createElement("default")
|
||
element_default.setAttribute("pathversion", "1")
|
||
nodo_type.appendChild(element_default)
|
||
source_nodes.appendChild(nodo_type)
|
||
xmldoc.appendChild(source_nodes)
|
||
|
||
# collect nodes
|
||
# nodes = xmldoc.getElementsByTagName("video")
|
||
video_node = xmldoc.childNodes[0].getElementsByTagName("video")[0]
|
||
paths_node = video_node.getElementsByTagName("path")
|
||
|
||
if old:
|
||
# delete old path
|
||
for node in paths_node:
|
||
if node.firstChild.data == old:
|
||
parent = node.parentNode
|
||
remove = parent.parentNode
|
||
remove.removeChild(parent)
|
||
|
||
# write changes
|
||
if sys.version_info[0] >= 3: #PY3
|
||
filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()]))
|
||
else:
|
||
filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()]), vfs=False)
|
||
logger.debug("The path %s has been removed from sources.xml" % old)
|
||
|
||
if new:
|
||
# create new path
|
||
list_path = [p.firstChild.data for p in paths_node]
|
||
if new in list_path:
|
||
logger.debug("The path %s already exists in sources.xml" % new)
|
||
return
|
||
logger.debug("The path %s does not exist in sources.xml" % new)
|
||
|
||
# if the path does not exist we create one
|
||
source_node = xmldoc.createElement("source")
|
||
|
||
# <name> Node
|
||
name_node = xmldoc.createElement("name")
|
||
sep = os.sep
|
||
if new.startswith("special://") or scrapertools.find_single_match(new, r'(^\w+:\/\/)'):
|
||
sep = "/"
|
||
name = new
|
||
if new.endswith(sep):
|
||
name = new[:-1]
|
||
name_node.appendChild(xmldoc.createTextNode(name.rsplit(sep)[-1]))
|
||
source_node.appendChild(name_node)
|
||
|
||
# <path> Node
|
||
path_node = xmldoc.createElement("path")
|
||
path_node.setAttribute("pathversion", "1")
|
||
path_node.appendChild(xmldoc.createTextNode(new))
|
||
source_node.appendChild(path_node)
|
||
|
||
# <allowsharing> Node
|
||
allowsharing_node = xmldoc.createElement("allowsharing")
|
||
allowsharing_node.appendChild(xmldoc.createTextNode('true'))
|
||
source_node.appendChild(allowsharing_node)
|
||
|
||
# Añadimos <source> a <video>
|
||
video_node.appendChild(source_node)
|
||
|
||
# write changes
|
||
if sys.version_info[0] >= 3: #PY3
|
||
filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()]))
|
||
else:
|
||
filetools.write(SOURCES_PATH, '\n'.join([x for x in xmldoc.toprettyxml().splitlines() if x.strip()]), vfs=False)
|
||
logger.debug("The path %s has been added to sources.xml" % new)
|
||
|
||
|
||
def ask_set_content(silent=False):
|
||
logger.debug()
|
||
logger.debug("videolibrary_kodi %s" % config.get_setting("videolibrary_kodi"))
|
||
|
||
def do_config(custom=False):
|
||
if set_content("movie", True, custom) and set_content("tvshow", True, custom):
|
||
platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(70104))
|
||
config.set_setting("videolibrary_kodi", True)
|
||
from specials import videolibrary
|
||
videolibrary.update_videolibrary()
|
||
update()
|
||
else:
|
||
platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80024))
|
||
config.set_setting("videolibrary_kodi", False)
|
||
|
||
# configuration during installation
|
||
if not silent:
|
||
# ask to configure Kodi video library
|
||
if platformtools.dialog_yesno(config.get_localized_string(20000), config.get_localized_string(80015)):
|
||
# ask for custom or default settings
|
||
if not platformtools.dialog_yesno(config.get_localized_string(80026), config.get_localized_string(80016), config.get_localized_string(80017), config.get_localized_string(80018)):
|
||
# input path and folders
|
||
path = platformtools.dialog_browse(3, config.get_localized_string(80019), config.get_setting("videolibrarypath"))
|
||
movies_folder = platformtools.dialog_input(config.get_setting("folder_movies"), config.get_localized_string(80020))
|
||
tvshows_folder = platformtools.dialog_input(config.get_setting("folder_tvshows"), config.get_localized_string(80021))
|
||
|
||
if path != "" and movies_folder != "" and tvshows_folder != "":
|
||
movies_path, tvshows_path = check_sources(filetools.join(path, movies_folder), filetools.join(path, tvshows_folder))
|
||
# configure later
|
||
if movies_path or tvshows_path:
|
||
platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80029))
|
||
# set path and folders
|
||
else:
|
||
update_sources(path, config.get_setting("videolibrarypath"))
|
||
config.set_setting("videolibrarypath", path)
|
||
config.set_setting("folder_movies", movies_folder)
|
||
config.set_setting("folder_tvshows", tvshows_folder)
|
||
config.verify_directories_created()
|
||
do_config(True)
|
||
# default path and folders
|
||
else:
|
||
platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80030))
|
||
do_config(True)
|
||
# default settings
|
||
else:
|
||
platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80027))
|
||
do_config(False)
|
||
# configure later
|
||
else:
|
||
platformtools.dialog_ok(config.get_localized_string(20000), config.get_localized_string(80022))
|
||
# configuration from the settings menu
|
||
else:
|
||
platformtools.dialog_ok(config.get_localized_string(80026), config.get_localized_string(80023))
|
||
do_config(True)
|
||
|
||
|
||
def next_ep(item):
|
||
from core.item import Item
|
||
logger.debug()
|
||
item.next_ep = False
|
||
|
||
# check if next file exist
|
||
current_filename = filetools.basename(item.strm_path)
|
||
base_path = filetools.basename(filetools.dirname(item.strm_path))
|
||
path = filetools.join(config.get_videolibrary_path(), config.get_setting("folder_tvshows"),base_path)
|
||
fileList = []
|
||
for file in filetools.listdir(path):
|
||
if file.endswith('.strm'):
|
||
fileList.append(file)
|
||
fileList.sort()
|
||
|
||
nextIndex = fileList.index(current_filename) + 1
|
||
if nextIndex == 0 or nextIndex == len(fileList): next_file = None
|
||
else: next_file = fileList[nextIndex]
|
||
logger.debug('Next File:' + str(next_file))
|
||
|
||
# start next episode window afther x time
|
||
if next_file:
|
||
season_ep = next_file.split('.')[0]
|
||
season = season_ep.split('x')[0]
|
||
episode = season_ep.split('x')[1]
|
||
next_ep = '%sx%s' % (season, episode)
|
||
item = Item(
|
||
action= 'play_from_library',
|
||
channel= 'videolibrary',
|
||
contentEpisodeNumber= episode,
|
||
contentSeason= season,
|
||
contentTitle= next_ep,
|
||
contentType= 'episode',
|
||
infoLabels= {'episode': episode, 'mediatype': 'episode', 'season': season, 'title': next_ep},
|
||
strm_path= filetools.join(base_path, next_file),
|
||
play_from = item.play_from)
|
||
|
||
global INFO
|
||
INFO = filetools.join(path, next_file.replace("strm", "nfo"))
|
||
else:
|
||
item=None
|
||
|
||
return item
|
||
|
||
|
||
class NextDialog(xbmcgui.WindowXMLDialog):
|
||
item = None
|
||
cancel = False
|
||
EXIT = False
|
||
continuewatching = True
|
||
|
||
def __init__(self, *args, **kwargs):
|
||
self.action_exitkeys_id = [xbmcgui.ACTION_STOP, xbmcgui.ACTION_BACKSPACE, xbmcgui.ACTION_PREVIOUS_MENU, xbmcgui.ACTION_NAV_BACK]
|
||
self.progress_control = None
|
||
|
||
# set info
|
||
f = filetools.file_open(INFO, 'r')
|
||
full_info = f.read().split('\n')
|
||
full_info = full_info[1:]
|
||
f.close()
|
||
full_info = "".join(full_info)
|
||
info = jsontools.load(full_info)
|
||
info = info["infoLabels"]
|
||
if "fanart" in info: img = info["fanart"]
|
||
elif "thumbnail" in info: img = info["thumbnail"]
|
||
else: img = filetools.join(config.get_runtime_path(), "resources", "noimage.png")
|
||
self.setProperty("next_img", img)
|
||
self.setProperty("title", info["tvshowtitle"])
|
||
self.setProperty("ep_title", "%dx%02d - %s" % (info["season"], info["episode"], info["title"]))
|
||
|
||
def set_exit(self, EXIT):
|
||
self.EXIT = EXIT
|
||
|
||
def set_continue_watching(self, continuewatching):
|
||
self.continuewatching = continuewatching
|
||
|
||
def is_exit(self):
|
||
return self.EXIT
|
||
|
||
def onFocus(self, controlId):
|
||
pass
|
||
|
||
def doAction(self):
|
||
pass
|
||
|
||
def closeDialog(self):
|
||
self.close()
|
||
|
||
def onClick(self, controlId):
|
||
if controlId == 3012: # Still watching
|
||
self.set_exit(True)
|
||
self.set_continue_watching(True)
|
||
self.close()
|
||
elif controlId == 3013: # Cancel
|
||
self.set_exit(True)
|
||
self.set_continue_watching(False)
|
||
self.close()
|
||
|
||
def onAction(self, action):
|
||
if action in self.action_exitkeys_id:
|
||
self.set_exit(True)
|
||
self.set_continue_watching(False)
|
||
self.close()
|