mirror of
https://github.com/jellyfin/jellyfin-kodi.git
synced 2024-12-26 02:36:10 +00:00
938538c54f
Server api changed recursivecount. It now returns 0 regardless of the show containing episodes. There's no way to detect empty shows as far as I'm aware so remove check.
922 lines
35 KiB
Python
922 lines
35 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
##################################################################################################
|
|
|
|
import logging
|
|
from ntpath import dirname
|
|
|
|
import api
|
|
import embydb_functions as embydb
|
|
import _kodi_tvshows
|
|
from _common import Items, catch_except
|
|
from utils import window, settings, language as lang, plugin_path
|
|
|
|
##################################################################################################
|
|
|
|
log = logging.getLogger("EMBY."+__name__)
|
|
|
|
##################################################################################################
|
|
|
|
|
|
class TVShows(Items):
|
|
|
|
|
|
def __init__(self, embycursor, kodicursor, pdialog=None):
|
|
|
|
self.embycursor = embycursor
|
|
self.emby_db = embydb.Embydb_Functions(self.embycursor)
|
|
self.kodicursor = kodicursor
|
|
self.kodi_db = _kodi_tvshows.KodiTVShows(self.kodicursor)
|
|
self.pdialog = pdialog
|
|
|
|
self.new_time = int(settings('newvideotime'))*1000
|
|
|
|
Items.__init__(self)
|
|
|
|
def _get_func(self, item_type, action):
|
|
|
|
if item_type == "Series":
|
|
actions = {
|
|
'added': self.add_shows,
|
|
'update': self.add_update,
|
|
'userdata': self.updateUserdata,
|
|
'remove': self.remove
|
|
}
|
|
elif item_type == "Season":
|
|
actions = {
|
|
'added': self.add_seasons,
|
|
'update': self.add_updateSeason,
|
|
'remove': self.remove
|
|
}
|
|
elif item_type == "Episode":
|
|
actions = {
|
|
'added': self.add_episodes,
|
|
'update': self.add_updateEpisode,
|
|
'userdata': self.updateUserdata,
|
|
'remove': self.remove
|
|
}
|
|
else:
|
|
log.info("Unsupported item_type: %s", item_type)
|
|
actions = {}
|
|
|
|
return actions.get(action)
|
|
|
|
def compare_all(self):
|
|
# Pull the list of movies and boxsets in Kodi
|
|
pdialog = self.pdialog
|
|
views = self.emby_db.getView_byType('tvshows')
|
|
views += self.emby_db.getView_byType('mixed')
|
|
log.info("Media folders: %s", views)
|
|
|
|
# Pull the list of tvshows and episodes in Kodi
|
|
try:
|
|
all_koditvshows = dict(self.emby_db.get_checksum('Series'))
|
|
except ValueError:
|
|
all_koditvshows = {}
|
|
|
|
log.info("all_koditvshows = %s", all_koditvshows)
|
|
|
|
try:
|
|
all_kodiepisodes = dict(self.emby_db.get_checksum('Episode'))
|
|
except ValueError:
|
|
all_kodiepisodes = {}
|
|
|
|
all_embytvshowsIds = set()
|
|
all_embyepisodesIds = set()
|
|
updatelist = []
|
|
|
|
# TODO: Review once series pooling is explicitely returned in api
|
|
for view in views:
|
|
|
|
if self.should_stop():
|
|
return False
|
|
|
|
# Get items per view
|
|
viewId = view['id']
|
|
viewName = view['name']
|
|
|
|
if pdialog:
|
|
pdialog.update(
|
|
heading=lang(29999),
|
|
message="%s %s..." % (lang(33029), viewName))
|
|
|
|
all_embytvshows = self.emby.getShows(viewId, basic=True, dialog=pdialog)
|
|
for embytvshow in all_embytvshows['Items']:
|
|
|
|
if self.should_stop():
|
|
return False
|
|
|
|
API = api.API(embytvshow)
|
|
itemid = embytvshow['Id']
|
|
all_embytvshowsIds.add(itemid)
|
|
|
|
|
|
if all_koditvshows.get(itemid) != API.get_checksum():
|
|
# Only update if movie is not in Kodi or checksum is different
|
|
updatelist.append(itemid)
|
|
|
|
log.info("TVShows to update for %s: %s", viewName, updatelist)
|
|
embytvshows = self.emby.getFullItems(updatelist)
|
|
self.total = len(updatelist)
|
|
del updatelist[:]
|
|
|
|
|
|
if pdialog:
|
|
pdialog.update(heading="Processing %s / %s items" % (viewName, self.total))
|
|
|
|
self.count = 0
|
|
for embytvshow in embytvshows:
|
|
# Process individual show
|
|
if self.should_stop():
|
|
return False
|
|
|
|
itemid = embytvshow['Id']
|
|
title = embytvshow['Name']
|
|
all_embytvshowsIds.add(itemid)
|
|
self.update_pdialog()
|
|
|
|
self.add_update(embytvshow, view)
|
|
self.count += 1
|
|
|
|
else:
|
|
# Get all episodes in view
|
|
if pdialog:
|
|
pdialog.update(
|
|
heading=lang(29999),
|
|
message="%s %s..." % (lang(33030), viewName))
|
|
|
|
all_embyepisodes = self.emby.getEpisodes(viewId, basic=True, dialog=pdialog)
|
|
for embyepisode in all_embyepisodes['Items']:
|
|
|
|
if self.should_stop():
|
|
return False
|
|
|
|
API = api.API(embyepisode)
|
|
itemid = embyepisode['Id']
|
|
all_embyepisodesIds.add(itemid)
|
|
if "SeriesId" in embyepisode:
|
|
all_embytvshowsIds.add(embyepisode['SeriesId'])
|
|
|
|
if all_kodiepisodes.get(itemid) != API.get_checksum():
|
|
# Only update if movie is not in Kodi or checksum is different
|
|
updatelist.append(itemid)
|
|
|
|
log.info("Episodes to update for %s: %s", viewName, updatelist)
|
|
embyepisodes = self.emby.getFullItems(updatelist)
|
|
self.total = len(updatelist)
|
|
del updatelist[:]
|
|
|
|
self.count = 0
|
|
for episode in embyepisodes:
|
|
|
|
# Process individual episode
|
|
if self.should_stop():
|
|
return False
|
|
self.title = "%s - %s" % (episode.get('SeriesName', "Unknown"), episode['Name'])
|
|
self.add_updateEpisode(episode)
|
|
self.count += 1
|
|
|
|
##### PROCESS DELETES #####
|
|
|
|
log.info("all_embytvshowsIds = %s ", all_embytvshowsIds)
|
|
|
|
for koditvshow in all_koditvshows:
|
|
if koditvshow not in all_embytvshowsIds:
|
|
self.remove(koditvshow)
|
|
|
|
log.info("TVShows compare finished.")
|
|
|
|
for kodiepisode in all_kodiepisodes:
|
|
if kodiepisode not in all_embyepisodesIds:
|
|
self.remove(kodiepisode)
|
|
|
|
log.info("Episodes compare finished.")
|
|
|
|
return True
|
|
|
|
|
|
def add_shows(self, items, total=None, view=None):
|
|
|
|
for item in self.added(items, total):
|
|
if self.add_update(item, view):
|
|
# Add episodes
|
|
all_episodes = self.emby.getEpisodesbyShow(item['Id'])
|
|
self.add_episodes(all_episodes['Items'])
|
|
|
|
def add_seasons(self, items, total=None, view=None):
|
|
|
|
update = True if not self.total else False
|
|
|
|
for item in self.added(items, total, update):
|
|
self.title = "%s - %s" % (item.get('SeriesName', "Unknown"), self.title)
|
|
|
|
if self.add_updateSeason(item):
|
|
# Add episodes
|
|
all_episodes = self.emby.getEpisodesbySeason(item['Id'])
|
|
self.add_episodes(all_episodes['Items'])
|
|
|
|
def add_episodes(self, items, total=None, view=None):
|
|
|
|
update = True if not self.total else False
|
|
|
|
for item in self.added(items, total, update):
|
|
self.title = "%s - %s" % (item.get('SeriesName', "Unknown"), self.title)
|
|
|
|
if self.add_updateEpisode(item):
|
|
self.content_pop(self.title)
|
|
|
|
@catch_except()
|
|
def add_update(self, item, view=None):
|
|
# Process single tvshow
|
|
kodicursor = self.kodicursor
|
|
emby = self.emby
|
|
emby_db = self.emby_db
|
|
artwork = self.artwork
|
|
API = api.API(item)
|
|
|
|
# Server api changed or something? RecursiveItemCount always returns 0
|
|
"""if settings('syncEmptyShows') == "false" and not item.get('RecursiveItemCount'):
|
|
if item.get('Name', None) is not None:
|
|
log.info("Skipping empty show: %s", item['Name'])
|
|
return"""
|
|
# If the item already exist in the local Kodi DB we'll perform a full item update
|
|
# If the item doesn't exist, we'll add it to the database
|
|
update_item = True
|
|
force_episodes = False
|
|
itemid = item['Id']
|
|
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
|
|
if view is None:
|
|
# Get view tag from emby
|
|
viewtag, viewid = emby_db.getView_embyId(itemid)
|
|
log.debug("View tag found: %s", viewtag)
|
|
else:
|
|
viewtag = view['name']
|
|
viewid = view['id']
|
|
|
|
# fileId information
|
|
checksum = API.get_checksum()
|
|
userdata = API.get_userdata()
|
|
|
|
# item details
|
|
genres = item['Genres']
|
|
title = item['Name']
|
|
plot = API.get_overview()
|
|
rating = item.get('CommunityRating')
|
|
votecount = item.get('VoteCount')
|
|
premieredate = API.get_premiere_date()
|
|
tvdb = API.get_provider('Tvdb')
|
|
sorttitle = item['SortName']
|
|
mpaa = API.get_mpaa()
|
|
genre = " / ".join(genres)
|
|
studios = API.get_studios()
|
|
studio = " / ".join(studios)
|
|
|
|
##### GET THE FILE AND PATH #####
|
|
playurl = API.get_file_path()
|
|
|
|
if self.direct_path:
|
|
# Direct paths is set the Kodi way
|
|
if "\\" in playurl:
|
|
# Local path
|
|
path = "%s\\" % playurl
|
|
toplevelpath = "%s\\" % dirname(dirname(path))
|
|
else:
|
|
# Network path
|
|
path = "%s/" % playurl
|
|
toplevelpath = "%s/" % dirname(dirname(path))
|
|
|
|
if not self.path_validation(path):
|
|
return False
|
|
|
|
window('emby_pathverified', value="true")
|
|
else:
|
|
# Set plugin path
|
|
toplevelpath = "plugin://plugin.video.emby.tvshows/"
|
|
path = "%s%s/" % (toplevelpath, itemid)
|
|
|
|
|
|
try:
|
|
showid = emby_dbitem[0]
|
|
pathid = emby_dbitem[2]
|
|
log.info("showid: %s pathid: %s", showid, pathid)
|
|
|
|
except TypeError:
|
|
update_item = False
|
|
showid = None
|
|
log.debug("showid: %s not found", itemid)
|
|
|
|
if self.emby_db.get_view_grouped_series(viewid) and tvdb:
|
|
# search kodi db for same provider id
|
|
if self.kodi_version > 16:
|
|
query = "SELECT idShow FROM tvshow_view WHERE uniqueid_value = ?"
|
|
kodicursor.execute(query, (tvdb,))
|
|
else:
|
|
query = "SELECT idShow FROM tvshow WHERE C12 = ?"
|
|
kodicursor.execute(query, (tvdb,))
|
|
|
|
try:
|
|
temps_showid = kodicursor.fetchall()
|
|
except TypeError: pass
|
|
else:
|
|
for temp_showid in temps_showid:
|
|
emby_other = emby_db.getItem_byKodiId(temp_showid[0], "tvshow")
|
|
if emby_other and viewid == emby_other[2]:
|
|
log.info("Applying series pooling for: %s %s", itemid, title)
|
|
emby_other_item = emby_db.getItem_byId(emby_other[0])
|
|
showid = emby_other_item[0]
|
|
pathid = self.kodi_db.add_path(path)
|
|
emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid,
|
|
checksum=checksum, mediafolderid=viewid)
|
|
return
|
|
|
|
showid = self.kodi_db.create_entry()
|
|
|
|
else:
|
|
# Verification the item is still in Kodi
|
|
if self.kodi_db.get_tvshow(showid) is None:
|
|
# item is not found, let's recreate it.
|
|
update_item = False
|
|
log.info("showid: %s missing from Kodi, repairing the entry", showid)
|
|
# Force re-add episodes after the show is re-created.
|
|
force_episodes = True
|
|
|
|
|
|
# Verify series pooling
|
|
"""if not update_item and tvdb:
|
|
query = "SELECT idShow FROM tvshow WHERE C12 = ?"
|
|
kodicursor.execute(query, (tvdb,))
|
|
try:
|
|
temp_showid = kodicursor.fetchone()[0]
|
|
except TypeError:
|
|
pass
|
|
else:
|
|
emby_other = emby_db.getItem_byKodiId(temp_showid, "tvshow")
|
|
if emby_other and viewid == emby_other[2]:
|
|
log.info("Applying series pooling for %s", title)
|
|
emby_other_item = emby_db.getItem_byId(emby_other[0])
|
|
showid = emby_other_item[0]
|
|
pathid = emby_other_item[2]
|
|
log.info("showid: %s pathid: %s", showid, pathid)
|
|
# Create the reference in emby table
|
|
emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid,
|
|
checksum=checksum, mediafolderid=viewid)
|
|
update_item = True"""
|
|
|
|
|
|
##### UPDATE THE TVSHOW #####
|
|
if update_item:
|
|
log.info("UPDATE tvshow itemid: %s - Title: %s", itemid, title)
|
|
|
|
# update new ratings Kodi 17
|
|
if self.kodi_version > 16:
|
|
ratingid = self.kodi_db.get_ratingid("tvshow", showid)
|
|
|
|
self.kodi_db.update_ratings(showid, "tvshow", "default", rating, votecount,ratingid)
|
|
|
|
# update new uniqueid Kodi 17
|
|
if self.kodi_version > 16:
|
|
uniqueid = self.kodi_db.get_uniqueid("tvshow", showid)
|
|
|
|
self.kodi_db.update_uniqueid(showid, "tvshow", tvdb, "unknown", uniqueid)
|
|
|
|
# Update the tvshow entry
|
|
if self.kodi_version > 16:
|
|
self.kodi_db.update_tvshow(title, plot, uniqueid, premieredate, genre, title,
|
|
uniqueid, mpaa, studio, sorttitle, showid)
|
|
else:
|
|
self.kodi_db.update_tvshow(title, plot, rating, premieredate, genre, title,
|
|
tvdb, mpaa, studio, sorttitle, showid)
|
|
# Update the checksum in emby table
|
|
emby_db.updateReference(itemid, checksum)
|
|
|
|
##### OR ADD THE TVSHOW #####
|
|
else:
|
|
log.info("ADD tvshow itemid: %s - Title: %s", itemid, title)
|
|
|
|
# add new ratings Kodi 17
|
|
if self.kodi_version > 16:
|
|
ratingid = self.kodi_db.create_entry_rating()
|
|
|
|
self.kodi_db.add_ratings(ratingid, showid, "tvshow", "default", rating, votecount)
|
|
|
|
# add new uniqueid Kodi 17
|
|
if self.kodi_version > 16:
|
|
uniqueid = self.kodi_db.create_entry_uniqueid()
|
|
|
|
self.kodi_db.add_uniqueid(uniqueid, showid, "tvshow", tvdb, "unknown")
|
|
|
|
# Add top path
|
|
toppathid = self.kodi_db.add_path(toplevelpath)
|
|
self.kodi_db.update_path(toppathid, toplevelpath, "tvshows", "metadata.local")
|
|
|
|
# Add path
|
|
pathid = self.kodi_db.add_path(path)
|
|
|
|
# Create the tvshow entry
|
|
if self.kodi_version > 16:
|
|
self.kodi_db.add_tvshow(showid, title, plot, uniqueid, premieredate, genre,
|
|
title, uniqueid, mpaa, studio, sorttitle)
|
|
else:
|
|
self.kodi_db.add_tvshow(showid, title, plot, rating, premieredate, genre,
|
|
title, tvdb, mpaa, studio, sorttitle)
|
|
|
|
# Create the reference in emby table
|
|
emby_db.addReference(itemid, showid, "Series", "tvshow", pathid=pathid,
|
|
checksum=checksum, mediafolderid=viewid)
|
|
|
|
|
|
# Link the path
|
|
self.kodi_db.link_tvshow(showid, pathid)
|
|
|
|
# Update the path
|
|
self.kodi_db.update_path(pathid, path, None, None)
|
|
|
|
# Process cast
|
|
people = artwork.get_people_artwork(item['People'])
|
|
self.kodi_db.add_people(showid, people, "tvshow")
|
|
# Process genres
|
|
self.kodi_db.add_genres(showid, genres, "tvshow")
|
|
# Process artwork
|
|
artwork.add_artwork(artwork.get_all_artwork(item), showid, "tvshow", kodicursor)
|
|
# Process studios
|
|
self.kodi_db.add_studios(showid, studios, "tvshow")
|
|
# Process tags: view, emby tags
|
|
tags = [viewtag]
|
|
tags.extend(item['Tags'])
|
|
if userdata['Favorite']:
|
|
tags.append("Favorite tvshows")
|
|
self.kodi_db.add_tags(showid, tags, "tvshow")
|
|
# Process seasons
|
|
all_seasons = emby.getSeasons(itemid)
|
|
for season in all_seasons['Items']:
|
|
log.info("found season: %s", season)
|
|
self.add_updateSeason(season, showid=showid)
|
|
else:
|
|
# Finally, refresh the all season entry
|
|
seasonid = self.kodi_db.get_season(showid, -1)
|
|
# Process artwork
|
|
artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
|
|
|
|
if force_episodes:
|
|
# We needed to recreate the show entry. Re-add episodes now.
|
|
log.info("Repairing episodes for showid: %s %s", showid, title)
|
|
all_episodes = emby.getEpisodesbyShow(itemid)
|
|
self.add_episodes(all_episodes['Items'], None)
|
|
|
|
return True
|
|
|
|
def add_updateSeason(self, item, showid=None):
|
|
|
|
kodicursor = self.kodicursor
|
|
emby_db = self.emby_db
|
|
artwork = self.artwork
|
|
|
|
seasonnum = item.get('IndexNumber', 1)
|
|
|
|
if showid is None:
|
|
try:
|
|
seriesId = item['SeriesId']
|
|
showid = emby_db.getItem_byId(seriesId)[0]
|
|
except KeyError:
|
|
return
|
|
except TypeError:
|
|
# Show is missing, update show instead.
|
|
show = self.emby.getItem(seriesId)
|
|
self.add_update(show)
|
|
return
|
|
|
|
seasonid = self.kodi_db.get_season(showid, seasonnum, item['Name'])
|
|
|
|
if item['LocationType'] != "Virtual":
|
|
# Create the reference in emby table
|
|
emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid)
|
|
|
|
# Process artwork
|
|
artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
|
|
|
|
log.info("Processed seasonid: %s index: %s", item['Id'], seasonnum)
|
|
return True
|
|
|
|
@catch_except()
|
|
def add_updateEpisode(self, item):
|
|
# Process single episode
|
|
kodicursor = self.kodicursor
|
|
emby_db = self.emby_db
|
|
artwork = self.artwork
|
|
API = api.API(item)
|
|
|
|
if item.get('LocationType') == "Virtual": # TODO: Filter via api instead
|
|
log.info("Skipping virtual episode: %s", item['Name'])
|
|
return
|
|
|
|
# If the item already exist in the local Kodi DB we'll perform a full item update
|
|
# If the item doesn't exist, we'll add it to the database
|
|
update_item = True
|
|
itemid = item['Id']
|
|
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
try:
|
|
episodeid = emby_dbitem[0]
|
|
fileid = emby_dbitem[1]
|
|
pathid = emby_dbitem[2]
|
|
log.info("episodeid: %s fileid: %s pathid: %s", episodeid, fileid, pathid)
|
|
|
|
except TypeError:
|
|
update_item = False
|
|
log.debug("episodeid: %s not found", itemid)
|
|
# episodeid
|
|
episodeid = self.kodi_db.create_entry_episode()
|
|
|
|
else:
|
|
# Verification the item is still in Kodi
|
|
if self.kodi_db.get_episode(episodeid) is None:
|
|
# item is not found, let's recreate it.
|
|
update_item = False
|
|
log.info("episodeid: %s missing from Kodi, repairing the entry", episodeid)
|
|
|
|
# fileId information
|
|
checksum = API.get_checksum()
|
|
dateadded = API.get_date_created()
|
|
userdata = API.get_userdata()
|
|
playcount = userdata['PlayCount']
|
|
dateplayed = userdata['LastPlayedDate']
|
|
|
|
# item details
|
|
people = API.get_people()
|
|
writer = " / ".join(people['Writer'])
|
|
director = " / ".join(people['Director'])
|
|
title = item['Name']
|
|
plot = API.get_overview()
|
|
rating = item.get('CommunityRating')
|
|
runtime = API.get_runtime()
|
|
premieredate = API.get_premiere_date()
|
|
|
|
votecount = item.get('VoteCount')
|
|
tvdb = API.get_provider('Tvdb')
|
|
|
|
# episode details
|
|
try:
|
|
seriesId = item['SeriesId']
|
|
except KeyError:
|
|
# Missing seriesId, skip
|
|
log.error("Skipping: %s. SeriesId is missing.", itemid)
|
|
return False
|
|
|
|
season = item.get('ParentIndexNumber')
|
|
episode = item.get('IndexNumber', -1)
|
|
|
|
if season is None:
|
|
if item.get('AbsoluteEpisodeNumber'):
|
|
# Anime scenario
|
|
season = 1
|
|
episode = item['AbsoluteEpisodeNumber']
|
|
else:
|
|
season = -1 if "Specials" not in item['Path'] else 0
|
|
|
|
# Specials ordering within season
|
|
if item.get('AirsAfterSeasonNumber'):
|
|
airsBeforeSeason = item['AirsAfterSeasonNumber']
|
|
airsBeforeEpisode = 4096 # Kodi default number for afterseason ordering
|
|
else:
|
|
airsBeforeSeason = item.get('AirsBeforeSeasonNumber')
|
|
airsBeforeEpisode = item.get('AirsBeforeEpisodeNumber')
|
|
|
|
# Append multi episodes to title
|
|
if item.get('IndexNumberEnd'):
|
|
title = "| %02d | %s" % (item['IndexNumberEnd'], title)
|
|
|
|
# Get season id
|
|
show = emby_db.getItem_byId(seriesId)
|
|
try:
|
|
showid = show[0]
|
|
except TypeError:
|
|
# Show is missing from database
|
|
show = self.emby.getItem(seriesId)
|
|
self.add_update(show)
|
|
show = emby_db.getItem_byId(seriesId)
|
|
try:
|
|
showid = show[0]
|
|
except TypeError:
|
|
log.error("Skipping: %s. Unable to add series: %s", itemid, seriesId)
|
|
return False
|
|
|
|
seasonid = self.kodi_db.get_season(showid, season)
|
|
|
|
|
|
##### GET THE FILE AND PATH #####
|
|
playurl = API.get_file_path()
|
|
|
|
if "\\" in playurl:
|
|
# Local path
|
|
filename = playurl.rsplit("\\", 1)[1]
|
|
else: # Network share
|
|
filename = playurl.rsplit("/", 1)[1]
|
|
|
|
if self.direct_path:
|
|
# Direct paths is set the Kodi way
|
|
if not self.path_validation(playurl):
|
|
return False
|
|
|
|
path = playurl.replace(filename, "")
|
|
window('emby_pathverified', value="true")
|
|
else:
|
|
# Set plugin path and media flags using real filename
|
|
path = "plugin://plugin.video.emby.tvshows/%s/" % seriesId
|
|
params = {
|
|
|
|
'filename': filename.encode('utf-8'),
|
|
'id': itemid,
|
|
'dbid': episodeid,
|
|
'mode': "play"
|
|
}
|
|
filename = plugin_path(path, params)
|
|
|
|
##### UPDATE THE EPISODE #####
|
|
if update_item:
|
|
log.info("UPDATE episode itemid: %s - Title: %s", itemid, title)
|
|
|
|
# update new ratings Kodi 17
|
|
if self.kodi_version >= 17:
|
|
ratingid = self.kodi_db.get_ratingid("episode", episodeid)
|
|
|
|
self.kodi_db.update_ratings(episodeid, "episode", "default", rating, votecount,ratingid)
|
|
|
|
# update new uniqueid Kodi 17
|
|
if self.kodi_version >= 17:
|
|
uniqueid = self.kodi_db.get_uniqueid("episode", episodeid)
|
|
|
|
self.kodi_db.update_uniqueid(episodeid, "episode", tvdb, "tvdb",uniqueid)
|
|
|
|
# Update the episode entry
|
|
if self.kodi_version >= 17:
|
|
# Kodi Krypton
|
|
self.kodi_db.update_episode_16(title, plot, uniqueid, writer, premieredate, runtime,
|
|
director, season, episode, title, airsBeforeSeason,
|
|
airsBeforeEpisode, seasonid, showid, episodeid)
|
|
elif self.kodi_version >= 16 and self.kodi_version < 17:
|
|
# Kodi Jarvis
|
|
self.kodi_db.update_episode_16(title, plot, rating, writer, premieredate, runtime,
|
|
director, season, episode, title, airsBeforeSeason,
|
|
airsBeforeEpisode, seasonid, showid, episodeid)
|
|
else:
|
|
self.kodi_db.update_episode(title, plot, rating, writer, premieredate, runtime,
|
|
director, season, episode, title, airsBeforeSeason,
|
|
airsBeforeEpisode, showid, episodeid)
|
|
|
|
# Update the checksum in emby table
|
|
emby_db.updateReference(itemid, checksum)
|
|
# Update parentid reference
|
|
emby_db.updateParentId(itemid, seasonid)
|
|
|
|
##### OR ADD THE EPISODE #####
|
|
else:
|
|
log.info("ADD episode itemid: %s - Title: %s", itemid, title)
|
|
|
|
# add new ratings Kodi 17
|
|
if self.kodi_version >= 17:
|
|
ratingid = self.kodi_db.create_entry_rating()
|
|
|
|
self.kodi_db.add_ratings(ratingid, episodeid, "episode", "default", rating, votecount)
|
|
|
|
# add new uniqueid Kodi 17
|
|
if self.kodi_version >= 17:
|
|
uniqueid = self.kodi_db.create_entry_uniqueid()
|
|
|
|
self.kodi_db.add_uniqueid(uniqueid, episodeid, "episode", tvdb, "tvdb")
|
|
|
|
# Add path
|
|
pathid = self.kodi_db.add_path(path)
|
|
# Add the file
|
|
fileid = self.kodi_db.add_file(filename, pathid)
|
|
|
|
# Create the episode entry
|
|
if self.kodi_version >= 17:
|
|
# Kodi Krypton
|
|
self.kodi_db.add_episode_16(episodeid, fileid, title, plot, uniqueid, writer,
|
|
premieredate, runtime, director, season, episode, title,
|
|
showid, airsBeforeSeason, airsBeforeEpisode, seasonid)
|
|
elif self.kodi_version >= 16 and self.kodi_version < 17:
|
|
# Kodi Jarvis
|
|
self.kodi_db.add_episode_16(episodeid, fileid, title, plot, rating, writer,
|
|
premieredate, runtime, director, season, episode, title,
|
|
showid, airsBeforeSeason, airsBeforeEpisode, seasonid)
|
|
else:
|
|
self.kodi_db.add_episode(episodeid, fileid, title, plot, rating, writer,
|
|
premieredate, runtime, director, season, episode, title,
|
|
showid, airsBeforeSeason, airsBeforeEpisode)
|
|
|
|
# Create the reference in emby table
|
|
emby_db.addReference(itemid, episodeid, "Episode", "episode", fileid, pathid,
|
|
seasonid, checksum)
|
|
|
|
# Update the path
|
|
self.kodi_db.update_path(pathid, path, None, None)
|
|
# Update the file
|
|
self.kodi_db.update_file(fileid, filename, pathid, dateadded)
|
|
|
|
# Process cast
|
|
people = artwork.get_people_artwork(item['People'])
|
|
self.kodi_db.add_people(episodeid, people, "episode")
|
|
# Process artwork
|
|
artworks = artwork.get_all_artwork(item)
|
|
artwork.add_update_art(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
|
|
# Process stream details
|
|
streams = API.get_media_streams()
|
|
self.kodi_db.add_streams(fileid, streams, runtime)
|
|
# Process playstates
|
|
resume = API.adjust_resume(userdata['Resume'])
|
|
total = round(float(runtime), 6)
|
|
self.kodi_db.add_playstate(fileid, resume, total, playcount, dateplayed)
|
|
if not self.direct_path and resume:
|
|
# Create additional entry for widgets. This is only required for plugin/episode.
|
|
temppathid = self.kodi_db.get_path("plugin://plugin.video.emby.tvshows/")
|
|
tempfileid = self.kodi_db.add_file(filename, temppathid)
|
|
self.kodi_db.update_file(tempfileid, filename, temppathid, dateadded)
|
|
self.kodi_db.add_playstate(tempfileid, resume, total, playcount, dateplayed)
|
|
|
|
return True
|
|
|
|
def updateUserdata(self, item):
|
|
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
|
|
# Poster with progress bar
|
|
emby_db = self.emby_db
|
|
API = api.API(item)
|
|
|
|
# Get emby information
|
|
itemid = item['Id']
|
|
checksum = API.get_checksum()
|
|
userdata = API.get_userdata()
|
|
runtime = API.get_runtime()
|
|
dateadded = API.get_date_created()
|
|
|
|
# Get Kodi information
|
|
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
try:
|
|
kodiid = emby_dbitem[0]
|
|
fileid = emby_dbitem[1]
|
|
mediatype = emby_dbitem[4]
|
|
log.info("Update playstate for %s: %s fileid: %s", mediatype, item['Name'], fileid)
|
|
except TypeError:
|
|
return
|
|
|
|
# Process favorite tags
|
|
if mediatype == "tvshow":
|
|
if userdata['Favorite']:
|
|
self.kodi_db.get_tag(kodiid, "Favorite tvshows", "tvshow")
|
|
else:
|
|
self.kodi_db.remove_tag(kodiid, "Favorite tvshows", "tvshow")
|
|
elif mediatype == "episode":
|
|
# Process playstates
|
|
playcount = userdata['PlayCount']
|
|
dateplayed = userdata['LastPlayedDate']
|
|
resume = API.adjust_resume(userdata['Resume'])
|
|
total = round(float(runtime), 6)
|
|
|
|
log.debug("%s New resume point: %s", itemid, resume)
|
|
|
|
self.kodi_db.add_playstate(fileid, resume, total, playcount, dateplayed)
|
|
if not self.direct_path and not resume:
|
|
# Make sure there's no other bookmarks created by widget.
|
|
filename = self.kodi_db.get_filename(fileid)
|
|
self.kodi_db.remove_file("plugin://plugin.video.emby.tvshows/", filename)
|
|
|
|
if not self.direct_path and resume:
|
|
# Create additional entry for widgets. This is only required for plugin/episode.
|
|
filename = self.kodi_db.get_filename(fileid)
|
|
temppathid = self.kodi_db.get_path("plugin://plugin.video.emby.tvshows/")
|
|
tempfileid = self.kodi_db.add_file(filename, temppathid)
|
|
self.kodi_db.update_file(tempfileid, filename, temppathid, dateadded)
|
|
self.kodi_db.add_playstate(tempfileid, resume, total, playcount, dateplayed)
|
|
|
|
emby_db.updateReference(itemid, checksum)
|
|
|
|
def remove(self, itemid):
|
|
# Remove showid, fileid, pathid, emby reference
|
|
emby_db = self.emby_db
|
|
kodicursor = self.kodicursor
|
|
|
|
emby_dbitem = emby_db.getItem_byId(itemid)
|
|
try:
|
|
kodiid = emby_dbitem[0]
|
|
fileid = emby_dbitem[1]
|
|
parentid = emby_dbitem[3]
|
|
mediatype = emby_dbitem[4]
|
|
log.info("Removing %s kodiid: %s fileid: %s", mediatype, kodiid, fileid)
|
|
except TypeError:
|
|
return
|
|
|
|
##### PROCESS ITEM #####
|
|
|
|
# Remove the emby reference
|
|
emby_db.removeItem(itemid)
|
|
|
|
##### IF EPISODE #####
|
|
|
|
if mediatype == "episode":
|
|
# Delete kodi episode and file, verify season and tvshow
|
|
self.removeEpisode(kodiid, fileid)
|
|
|
|
# Season verification
|
|
season = emby_db.getItem_byKodiId(parentid, "season")
|
|
try:
|
|
showid = season[1]
|
|
except TypeError:
|
|
return
|
|
|
|
season_episodes = emby_db.getItem_byParentId(parentid, "episode")
|
|
if not season_episodes:
|
|
self.removeSeason(parentid)
|
|
emby_db.removeItem(season[0])
|
|
|
|
# Show verification
|
|
show = emby_db.getItem_byKodiId(showid, "tvshow")
|
|
query = ' '.join((
|
|
|
|
"SELECT totalCount",
|
|
"FROM tvshowcounts",
|
|
"WHERE idShow = ?"
|
|
))
|
|
kodicursor.execute(query, (showid,))
|
|
result = kodicursor.fetchone()
|
|
if result and result[0] is None:
|
|
# There's no episodes left, delete show and any possible remaining seasons
|
|
seasons = emby_db.getItem_byParentId(showid, "season")
|
|
for season in seasons:
|
|
self.removeSeason(season[1])
|
|
else:
|
|
# Delete emby season entries
|
|
emby_db.removeItems_byParentId(showid, "season")
|
|
self.removeShow(showid)
|
|
emby_db.removeItem(show[0])
|
|
|
|
##### IF TVSHOW #####
|
|
|
|
elif mediatype == "tvshow":
|
|
# Remove episodes, seasons, tvshow
|
|
seasons = emby_db.getItem_byParentId(kodiid, "season")
|
|
for season in seasons:
|
|
seasonid = season[1]
|
|
season_episodes = emby_db.getItem_byParentId(seasonid, "episode")
|
|
for episode in season_episodes:
|
|
self.removeEpisode(episode[1], episode[2])
|
|
else:
|
|
# Remove emby episodes
|
|
emby_db.removeItems_byParentId(seasonid, "episode")
|
|
else:
|
|
# Remove emby seasons
|
|
emby_db.removeItems_byParentId(kodiid, "season")
|
|
|
|
# Remove tvshow
|
|
self.removeShow(kodiid)
|
|
|
|
##### IF SEASON #####
|
|
|
|
elif mediatype == "season":
|
|
# Remove episodes, season, verify tvshow
|
|
season_episodes = emby_db.getItem_byParentId(kodiid, "episode")
|
|
for episode in season_episodes:
|
|
self.removeEpisode(episode[1], episode[2])
|
|
else:
|
|
# Remove emby episodes
|
|
emby_db.removeItems_byParentId(kodiid, "episode")
|
|
|
|
# Remove season
|
|
self.removeSeason(kodiid)
|
|
|
|
# Show verification
|
|
seasons = emby_db.getItem_byParentId(parentid, "season")
|
|
if not seasons:
|
|
# There's no seasons, delete the show
|
|
self.removeShow(parentid)
|
|
emby_db.removeItem_byKodiId(parentid, "tvshow")
|
|
|
|
log.info("Deleted %s: %s from kodi database", mediatype, itemid)
|
|
|
|
def removeShow(self, kodiid):
|
|
|
|
kodicursor = self.kodicursor
|
|
self.artwork.delete_artwork(kodiid, "tvshow", kodicursor)
|
|
self.kodi_db.remove_tvshow(kodiid)
|
|
log.debug("Removed tvshow: %s", kodiid)
|
|
|
|
def removeSeason(self, kodiid):
|
|
|
|
kodicursor = self.kodicursor
|
|
|
|
self.artwork.delete_artwork(kodiid, "season", kodicursor)
|
|
self.kodi_db.remove_season(kodiid)
|
|
log.debug("Removed season: %s", kodiid)
|
|
|
|
def removeEpisode(self, kodiid, fileid):
|
|
|
|
kodicursor = self.kodicursor
|
|
|
|
self.artwork.delete_artwork(kodiid, "episode", kodicursor)
|
|
self.kodi_db.remove_episode(kodiid, fileid)
|
|
log.debug("Removed episode: %s", kodiid)
|
|
|
|
def add_tvshow(self, item, view):
|
|
# The only way to keep things together is to drill down, like in the webclient.
|
|
# If series pooling is true, they will share the showid, extra tvshow entries
|
|
# will be added to emby.db due to server events.
|
|
pass
|