This commit is contained in:
angelblue05 2016-09-10 06:15:58 -05:00 committed by GitHub
parent cd06049e86
commit b34007f727
13 changed files with 640 additions and 732 deletions

View file

@ -109,7 +109,7 @@ class ContextMenu(object):
def _select_menu(self): def _select_menu(self):
# Display select dialog # Display select dialog
userdata = self.api.getUserData() userdata = self.api.get_userdata()
options = [] options = []
if userdata['Favorite']: if userdata['Favorite']:
@ -178,7 +178,7 @@ class ContextMenu(object):
new_value = 5 new_value = 5
if settings('enableUpdateSongRating') == "true": if settings('enableUpdateSongRating') == "true":
musicutils.updateRatingToFile(new_value, self.api.getFilePath()) musicutils.updateRatingToFile(new_value, self.api.get_file_path())
query = "UPDATE song SET rating = ? WHERE idSong = ?" query = "UPDATE song SET rating = ? WHERE idSong = ?"
cursor.execute(query, (new_value, self.kodi_id,)) cursor.execute(query, (new_value, self.kodi_id,))

View file

@ -70,7 +70,7 @@ class Main(object):
elif mode == 'texturecache': elif mode == 'texturecache':
import artwork import artwork
artwork.Artwork().fullTextureCacheSync() artwork.Artwork().texture_cache_sync()
else: else:
entrypoint.doMainListing() entrypoint.doMainListing()
@ -136,7 +136,7 @@ class Main(object):
dialog(type_="ok", dialog(type_="ok",
heading="{emby}", heading="{emby}",
line1=lang(33034)) line1=lang(33034))
log.warn("Not connected to the emby server.") log.warn("Not connected to the emby server")
elif window('emby_dbScan') != "true": elif window('emby_dbScan') != "true":
import librarysync import librarysync
@ -149,7 +149,7 @@ class Main(object):
else: else:
library_sync.fullSync(repair=True) library_sync.fullSync(repair=True)
else: else:
log.warn("Database scan is already running.") log.warn("Database scan is already running")
if __name__ == "__main__": if __name__ == "__main__":

View file

@ -14,45 +14,42 @@ log = logging.getLogger("EMBY."+__name__)
################################################################################################## ##################################################################################################
class API(): class API(object):
def __init__(self, item): def __init__(self, item):
# item is the api response # item is the api response
self.item = item self.item = item
def getUserData(self): def get_userdata(self):
# Default # Default
favorite = False favorite = False
likes = None likes = None
playcount = None playcount = None
played = False played = False
lastPlayedDate = None last_played = None
resume = 0 resume = 0
userrating = 0 user_rating = 0
try: try:
userdata = self.item['UserData'] userdata = self.item['UserData']
except KeyError: # No userdata found. except KeyError: # No userdata found.
pass pass
else: else:
favorite = userdata['IsFavorite'] favorite = userdata['IsFavorite']
likes = userdata.get('Likes') likes = userdata.get('Likes')
# Userrating is based on likes and favourite # Userrating is based on likes and favourite
if favorite: if favorite:
userrating = 5 user_rating = 5
elif likes: elif likes:
userrating = 3 user_rating = 3
elif likes == False: elif likes is False:
userrating = 0 user_rating = 0
else: else:
userrating = 1 user_rating = 1
lastPlayedDate = userdata.get('LastPlayedDate') last_played = userdata.get('LastPlayedDate')
if lastPlayedDate: if last_played:
lastPlayedDate = lastPlayedDate.split('.')[0].replace('T', " ") last_played = last_played.split('.')[0].replace('T', " ")
if userdata['Played']: if userdata['Played']:
# Playcount is tied to the watch status # Playcount is tied to the watch status
@ -61,12 +58,12 @@ class API():
if playcount == 0: if playcount == 0:
playcount = 1 playcount = 1
if lastPlayedDate is None: if last_played is None:
lastPlayedDate = self.getDateCreated() last_played = self.get_date_created()
playbackPosition = userdata.get('PlaybackPositionTicks') playback_position = userdata.get('PlaybackPositionTicks')
if playbackPosition: if playback_position:
resume = playbackPosition / 10000000.0 resume = playback_position / 10000000.0
return { return {
@ -74,12 +71,12 @@ class API():
'Likes': likes, 'Likes': likes,
'PlayCount': playcount, 'PlayCount': playcount,
'Played': played, 'Played': played,
'LastPlayedDate': lastPlayedDate, 'LastPlayedDate': last_played,
'Resume': resume, 'Resume': resume,
'UserRating': userrating 'UserRating': user_rating
} }
def getPeople(self): def get_people(self):
# Process People # Process People
director = [] director = []
writer = [] writer = []
@ -87,21 +84,19 @@ class API():
try: try:
people = self.item['People'] people = self.item['People']
except KeyError: except KeyError:
pass pass
else: else:
for person in people: for person in people:
type = person['Type'] type_ = person['Type']
name = person['Name'] name = person['Name']
if "Director" in type: if type_ == 'Director':
director.append(name) director.append(name)
elif "Actor" in type: elif type_ == 'Actor':
cast.append(name) cast.append(name)
elif type in ("Writing", "Writer"): elif type_ in ('Writing', 'Writer'):
writer.append(name) writer.append(name)
return { return {
@ -111,38 +106,58 @@ class API():
'Cast': cast 'Cast': cast
} }
def getMediaStreams(self): def get_media_streams(self):
videotracks = []
audiotracks = [] video_tracks = []
subtitlelanguages = [] audio_tracks = []
subtitle_languages = []
try: try:
media_streams = self.item['MediaSources'][0]['MediaStreams'] media_streams = self.item['MediaSources'][0]['MediaStreams']
except KeyError: except KeyError:
if not self.item.get("MediaStreams"): return None if not self.item.get("MediaStreams"):
return None
media_streams = self.item['MediaStreams'] media_streams = self.item['MediaStreams']
for media_stream in media_streams: for media_stream in media_streams:
# Sort through Video, Audio, Subtitle # Sort through Video, Audio, Subtitle
stream_type = media_stream['Type'] stream_type = media_stream['Type']
codec = media_stream.get('Codec', "").lower()
profile = media_stream.get('Profile', "").lower()
if stream_type == "Video": if stream_type == "Video":
self._video_stream(video_tracks, media_stream)
elif stream_type == "Audio":
self._audio_stream(audio_tracks, media_stream)
elif stream_type == "Subtitle":
subtitle_languages.append(media_stream.get('Language', "Unknown"))
return {
'video': video_tracks,
'audio': audio_tracks,
'subtitle': subtitle_languages
}
def _video_stream(self, video_tracks, stream):
codec = stream.get('Codec', "").lower()
profile = stream.get('Profile', "").lower()
# Height, Width, Codec, AspectRatio, AspectFloat, 3D # Height, Width, Codec, AspectRatio, AspectFloat, 3D
track = { track = {
'codec': codec, 'codec': codec,
'height': media_stream.get('Height'), 'height': stream.get('Height'),
'width': media_stream.get('Width'), 'width': stream.get('Width'),
'video3DFormat': self.item.get('Video3DFormat'), 'video3DFormat': self.item.get('Video3DFormat'),
'aspect': 1.85 'aspect': 1.85
} }
try: try:
container = self.item['MediaSources'][0]['Container'].lower() container = self.item['MediaSources'][0]['Container'].lower()
except: except Exception:
container = "" container = ""
# Sort codec vs container/profile # Sort codec vs container/profile
@ -156,17 +171,18 @@ class API():
track['codec'] = "avc1" track['codec'] = "avc1"
# Aspect ratio # Aspect ratio
if self.item.get('AspectRatio'): if 'AspectRatio' in self.item:
# Metadata AR # Metadata AR
aspect = self.item['AspectRatio'] aspect = self.item['AspectRatio']
else: # File AR else: # File AR
aspect = media_stream.get('AspectRatio', "0") aspect = stream.get('AspectRatio', "0")
try: try:
aspectwidth, aspectheight = aspect.split(':') aspect_width, aspect_height = aspect.split(':')
track['aspect'] = round(float(aspectwidth) / float(aspectheight), 6) track['aspect'] = round(float(aspect_width) / float(aspect_height), 6)
except (ValueError, ZeroDivisionError): except (ValueError, ZeroDivisionError):
width = track.get('width') width = track.get('width')
height = track.get('height') height = track.get('height')
@ -175,37 +191,30 @@ class API():
else: else:
track['aspect'] = 1.85 track['aspect'] = 1.85
if self.item.get("RunTimeTicks"): if 'RunTimeTicks' in self.item:
track['duration'] = self.item.get("RunTimeTicks") / 10000000.0 track['duration'] = self.get_runtime()
videotracks.append(track) video_tracks.append(track)
elif stream_type == "Audio": def _audio_stream(self, audio_tracks, stream):
codec = stream.get('Codec', "").lower()
profile = stream.get('Profile', "").lower()
# Codec, Channels, language # Codec, Channels, language
track = { track = {
'codec': codec, 'codec': codec,
'channels': media_stream.get('Channels'), 'channels': stream.get('Channels'),
'language': media_stream.get('Language') 'language': stream.get('Language')
} }
if "dca" in codec and "dts-hd ma" in profile: if "dca" in codec and "dts-hd ma" in profile:
track['codec'] = "dtshd_ma" track['codec'] = "dtshd_ma"
audiotracks.append(track) audio_tracks.append(track)
elif stream_type == "Subtitle": def get_runtime(self):
# Language
subtitlelanguages.append(media_stream.get('Language', "Unknown"))
return {
'video': videotracks,
'audio': audiotracks,
'subtitle': subtitlelanguages
}
def getRuntime(self):
try: try:
runtime = self.item['RunTimeTicks'] / 10000000.0 runtime = self.item['RunTimeTicks'] / 10000000.0
@ -214,7 +223,8 @@ class API():
return runtime return runtime
def adjustResume(self, resume_seconds): @classmethod
def adjust_resume(cls, resume_seconds):
resume = 0 resume = 0
if resume_seconds: if resume_seconds:
@ -226,24 +236,23 @@ class API():
return resume return resume
def getStudios(self): def get_studios(self):
# Process Studios # Process Studios
studios = [] studios = []
try: try:
studio = self.item['SeriesStudio'] studio = self.item['SeriesStudio']
studios.append(self.verifyStudio(studio)) studios.append(self.verify_studio(studio))
except KeyError: except KeyError:
studioList = self.item['Studios'] for studio in self.item['Studios']:
for studio in studioList:
name = studio['Name'] name = studio['Name']
studios.append(self.verifyStudio(name)) studios.append(self.verify_studio(name))
return studios return studios
def verifyStudio(self, studioName): @classmethod
def verify_studio(cls, studio_name):
# Convert studio for Kodi to properly detect them # Convert studio for Kodi to properly detect them
studios = { studios = {
@ -254,9 +263,9 @@ class API():
'wgn america': "WGN" 'wgn america': "WGN"
} }
return studios.get(studioName.lower(), studioName) return studios.get(studio_name.lower(), studio_name)
def getChecksum(self): def get_checksum(self):
# Use the etags checksum and userdata # Use the etags checksum and userdata
userdata = self.item['UserData'] userdata = self.item['UserData']
@ -265,7 +274,7 @@ class API():
self.item['Etag'], self.item['Etag'],
userdata['Played'], userdata['Played'],
userdata['IsFavorite'], userdata['IsFavorite'],
userdata.get('Likes',''), userdata.get('Likes', ""),
userdata['PlaybackPositionTicks'], userdata['PlaybackPositionTicks'],
userdata.get('UnplayedItemCount', ""), userdata.get('UnplayedItemCount', ""),
userdata.get('LastPlayedDate', "") userdata.get('LastPlayedDate', "")
@ -273,7 +282,7 @@ class API():
return checksum return checksum
def getGenres(self): def get_genres(self):
all_genres = "" all_genres = ""
genres = self.item.get('Genres', self.item.get('SeriesGenres')) genres = self.item.get('Genres', self.item.get('SeriesGenres'))
@ -282,17 +291,17 @@ class API():
return all_genres return all_genres
def getDateCreated(self): def get_date_created(self):
try: try:
dateadded = self.item['DateCreated'] date_added = self.item['DateCreated']
dateadded = dateadded.split('.')[0].replace('T', " ") date_added = date_added.split('.')[0].replace('T', " ")
except KeyError: except KeyError:
dateadded = None date_added = None
return dateadded return date_added
def getPremiereDate(self): def get_premiere_date(self):
try: try:
premiere = self.item['PremiereDate'] premiere = self.item['PremiereDate']
@ -302,7 +311,7 @@ class API():
return premiere return premiere
def getOverview(self): def get_overview(self):
try: try:
overview = self.item['Overview'] overview = self.item['Overview']
@ -314,7 +323,7 @@ class API():
return overview return overview
def getTagline(self): def get_tagline(self):
try: try:
tagline = self.item['Taglines'][0] tagline = self.item['Taglines'][0]
@ -323,16 +332,16 @@ class API():
return tagline return tagline
def getProvider(self, providername): def get_provider(self, name):
try: try:
provider = self.item['ProviderIds'][providername] provider = self.item['ProviderIds'][name]
except KeyError: except KeyError:
provider = None provider = None
return provider return provider
def getMpaa(self): def get_mpaa(self):
# Convert more complex cases # Convert more complex cases
mpaa = self.item.get('OfficialRating', "") mpaa = self.item.get('OfficialRating', "")
@ -342,7 +351,7 @@ class API():
return mpaa return mpaa
def getCountry(self): def get_country(self):
try: try:
country = self.item['ProductionLocations'][0] country = self.item['ProductionLocations'][0]
@ -351,7 +360,7 @@ class API():
return country return country
def getFilePath(self): def get_file_path(self):
try: try:
filepath = self.item['Path'] filepath = self.item['Path']

View file

@ -2,9 +2,7 @@
################################################################################################# #################################################################################################
import json
import logging import logging
import requests
import os import os
import urllib import urllib
from sqlite3 import OperationalError from sqlite3 import OperationalError
@ -12,9 +10,10 @@ from sqlite3 import OperationalError
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcvfs import xbmcvfs
import requests
import image_cache_thread import image_cache_thread
from utils import window, settings, language as lang, kodiSQL from utils import window, settings, dialog, language as lang, kodiSQL, JSONRPC
################################################################################################## ##################################################################################################
@ -23,58 +22,54 @@ log = logging.getLogger("EMBY."+__name__)
################################################################################################## ##################################################################################################
class Artwork(): class Artwork(object):
xbmc_host = 'localhost' xbmc_host = 'localhost'
xbmc_port = None xbmc_port = None
xbmc_username = None xbmc_username = None
xbmc_password = None xbmc_password = None
imageCacheThreads = [] image_cache_threads = []
imageCacheLimitThreads = 0 image_cache_limit = 0
def __init__(self): def __init__(self):
self.enableTextureCache = settings('enableTextureCache') == "true" self.enable_texture_cache = settings('enableTextureCache') == "true"
self.imageCacheLimitThreads = int(settings('imageCacheLimit')) self.image_cache_limit = int(settings('imageCacheLimit')) * 5
self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5) log.info("image cache thread count: %s", self.image_cache_limit)
log.info("Using Image Cache Thread Count: %s" % self.imageCacheLimitThreads)
if not self.xbmc_port and self.enableTextureCache: if not self.xbmc_port and self.enable_texture_cache:
self.setKodiWebServerDetails() self._set_webserver_details()
self.userId = window('emby_currUser') self.user_id = window('emby_currUser')
self.server = window('emby_server%s' % self.userId) self.server = window('emby_server%s' % self.user_id)
def double_urlencode(self, text): def _double_urlencode(self, text):
text = self.single_urlencode(text)
text = self.single_urlencode(text) text = self._single_urlencode(text)
text = self._single_urlencode(text)
return text return text
def single_urlencode(self, text): @classmethod
def _single_urlencode(cls, text):
# urlencode needs a utf- string # urlencode needs a utf- string
text = urllib.urlencode({'blahblahblah':text.encode("utf-8")}) text = urllib.urlencode({'blahblahblah': text.encode('utf-8')})
text = text[13:] text = text[13:]
return text.decode("utf-8") #return the result again as unicode return text.decode('utf-8') #return the result again as unicode
def setKodiWebServerDetails(self): def _set_webserver_details(self):
# Get the Kodi webserver details - used to set the texture cache # Get the Kodi webserver details - used to set the texture cache
web_query = { get_setting_value = JSONRPC('Settings.GetSettingValue')
"jsonrpc": "2.0", web_query = {
"id": 1,
"method": "Settings.GetSettingValue",
"params": {
"setting": "services.webserver" "setting": "services.webserver"
} }
} result = get_setting_value.execute(web_query)
result = xbmc.executeJSONRPC(json.dumps(web_query))
result = json.loads(result)
try: try:
xbmc_webserver_enabled = result['result']['value'] xbmc_webserver_enabled = result['result']['value']
except (KeyError, TypeError): except (KeyError, TypeError):
@ -82,48 +77,30 @@ class Artwork():
if not xbmc_webserver_enabled: if not xbmc_webserver_enabled:
# Enable the webserver, it is disabled # Enable the webserver, it is disabled
web_port = { set_setting_value = JSONRPC('Settings.SetSettingValue')
"jsonrpc": "2.0", web_port = {
"id": 1,
"method": "Settings.SetSettingValue",
"params": {
"setting": "services.webserverport", "setting": "services.webserverport",
"value": 8080 "value": 8080
} }
} set_setting_value.execute(web_port)
result = xbmc.executeJSONRPC(json.dumps(web_port))
self.xbmc_port = 8080 self.xbmc_port = 8080
web_user = { web_user = {
"jsonrpc": "2.0",
"id": 1,
"method": "Settings.SetSettingValue",
"params": {
"setting": "services.webserver", "setting": "services.webserver",
"value": True "value": True
} }
} set_setting_value.execute(web_user)
result = xbmc.executeJSONRPC(json.dumps(web_user))
self.xbmc_username = "kodi" self.xbmc_username = "kodi"
# Webserver already enabled # Webserver already enabled
web_port = { web_port = {
"jsonrpc": "2.0",
"id": 1,
"method": "Settings.GetSettingValue",
"params": {
"setting": "services.webserverport" "setting": "services.webserverport"
} }
} result = get_setting_value.execute(web_port)
result = xbmc.executeJSONRPC(json.dumps(web_port))
result = json.loads(result)
try: try:
self.xbmc_port = result['result']['value'] self.xbmc_port = result['result']['value']
except (TypeError, KeyError): except (TypeError, KeyError):
@ -131,16 +108,9 @@ class Artwork():
web_user = { web_user = {
"jsonrpc": "2.0",
"id": 1,
"method": "Settings.GetSettingValue",
"params": {
"setting": "services.webserverusername" "setting": "services.webserverusername"
} }
} result = get_setting_value.execute(web_user)
result = xbmc.executeJSONRPC(json.dumps(web_user))
result = json.loads(result)
try: try:
self.xbmc_username = result['result']['value'] self.xbmc_username = result['result']['value']
except TypeError: except TypeError:
@ -148,28 +118,19 @@ class Artwork():
web_pass = { web_pass = {
"jsonrpc": "2.0",
"id": 1,
"method": "Settings.GetSettingValue",
"params": {
"setting": "services.webserverpassword" "setting": "services.webserverpassword"
} }
} result = get_setting_value.execute(web_pass)
result = xbmc.executeJSONRPC(json.dumps(web_pass))
result = json.loads(result)
try: try:
self.xbmc_password = result['result']['value'] self.xbmc_password = result['result']['value']
except TypeError: except TypeError:
pass pass
def fullTextureCacheSync(self): def texture_cache_sync(self):
# This method will sync all Kodi artwork to textures13.db # This method will sync all Kodi artwork to textures13.db
# and cache them locally. This takes diskspace! # and cache them locally. This takes diskspace!
dialog = xbmcgui.Dialog() if not dialog(type_="yesno",
heading="{emby}",
if not dialog.yesno(
heading=lang(29999),
line1=lang(33042)): line1=lang(33042)):
return return
@ -179,41 +140,36 @@ class Artwork():
pdialog.create(lang(29999), lang(33043)) pdialog.create(lang(29999), lang(33043))
# ask to rest all existing or not # ask to rest all existing or not
if dialog.yesno(lang(29999), lang(33044)): if dialog(type_="yesno", heading="{emby}", line1=lang(33044)):
log.info("Resetting all cache data first.") log.info("Resetting all cache data first")
self._delete_cache()
# Remove all existing textures first
path = xbmc.translatePath('special://thumbnails/').decode('utf-8')
if xbmcvfs.exists(path):
allDirs, allFiles = xbmcvfs.listdir(path)
for dir in allDirs:
allDirs, allFiles = xbmcvfs.listdir(path+dir)
for file in allFiles:
if os.path.supports_unicode_filenames:
path = os.path.join(path+dir.decode('utf-8'),file.decode('utf-8'))
xbmcvfs.delete(path)
else:
xbmcvfs.delete(os.path.join(path.encode('utf-8')+dir,file))
# remove all existing data from texture DB
connection = kodiSQL('texture')
cursor = connection.cursor()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
rows = cursor.fetchall()
for row in rows:
tableName = row[0]
if tableName != "version":
cursor.execute("DELETE FROM " + tableName)
connection.commit()
cursor.close()
# Cache all entries in video DB # Cache all entries in video DB
connection = kodiSQL('video') self._cache_all_video_entries(pdialog)
cursor = connection.cursor() # Cache all entries in music DB
self._cache_all_music_entries(pdialog)
pdialog.update(100, "%s %s" % (lang(33046), len(self.image_cache_threads)))
log.info("Waiting for all threads to exit")
while len(self.image_cache_threads):
for thread in self.image_cache_threads:
if thread.is_finished:
self.image_cache_threads.remove(thread)
pdialog.update(100, "%s %s" % (lang(33046), len(self.image_cache_threads)))
log.info("Waiting for all threads to exit: %s", len(self.image_cache_threads))
xbmc.sleep(500)
pdialog.close()
def _cache_all_video_entries(self, pdialog):
conn = kodiSQL('video')
cursor = conn.cursor()
cursor.execute("SELECT url FROM art WHERE media_type != 'actor'") # dont include actors cursor.execute("SELECT url FROM art WHERE media_type != 'actor'") # dont include actors
result = cursor.fetchall() result = cursor.fetchall()
total = len(result) total = len(result)
log.info("Image cache sync about to process %s images" % total) log.info("Image cache sync about to process %s images", total)
cursor.close() cursor.close()
count = 0 count = 0
@ -223,18 +179,19 @@ class Artwork():
break break
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
message = "%s of %s (%s)" % (count, total, self.imageCacheThreads) message = "%s of %s (%s)" % (count, total, len(self.image_cache_threads))
pdialog.update(percentage, "%s %s" % (lang(33045), message)) pdialog.update(percentage, "%s %s" % (lang(33045), message))
self.cacheTexture(url[0]) self.cache_texture(url[0])
count += 1 count += 1
# Cache all entries in music DB def _cache_all_music_entries(self, pdialog):
connection = kodiSQL('music')
cursor = connection.cursor() conn = kodiSQL('music')
cursor = conn.cursor()
cursor.execute("SELECT url FROM art") cursor.execute("SELECT url FROM art")
result = cursor.fetchall() result = cursor.fetchall()
total = len(result) total = len(result)
log.info("Image cache sync about to process %s images" % total) log.info("Image cache sync about to process %s images", total)
cursor.close() cursor.close()
count = 0 count = 0
@ -246,68 +203,84 @@ class Artwork():
percentage = int((float(count) / float(total))*100) percentage = int((float(count) / float(total))*100)
message = "%s of %s" % (count, total) message = "%s of %s" % (count, total)
pdialog.update(percentage, "%s %s" % (lang(33045), message)) pdialog.update(percentage, "%s %s" % (lang(33045), message))
self.cacheTexture(url[0]) self.cache_texture(url[0])
count += 1 count += 1
pdialog.update(100, "%s %s" % (lang(33046), len(self.imageCacheThreads))) @classmethod
log.info("Waiting for all threads to exit") def _delete_cache(cls):
# Remove all existing textures first
path = xbmc.translatePath('special://thumbnails/').decode('utf-8')
if xbmcvfs.exists(path):
dirs, ignore_files = xbmcvfs.listdir(path)
for directory in dirs:
ignore_dirs, files = xbmcvfs.listdir(path + directory)
for file_ in files:
while len(self.imageCacheThreads): if os.path.supports_unicode_filenames:
for thread in self.imageCacheThreads: filename = os.path.join(path + directory.decode('utf-8'),
if thread.is_finished: file_.decode('utf-8'))
self.imageCacheThreads.remove(thread) else:
pdialog.update(100, "%s %s" % (lang(33046), len(self.imageCacheThreads))) filename = os.path.join(path.encode('utf-8') + directory, file_)
log.info("Waiting for all threads to exit: %s" % len(self.imageCacheThreads))
xbmc.sleep(500)
pdialog.close() xbmcvfs.delete(filename)
log.info("deleted: %s", filename)
def addWorkerImageCacheThread(self, url): # remove all existing data from texture DB
conn = kodiSQL('texture')
cursor = conn.cursor()
cursor.execute('SELECT tbl_name FROM sqlite_master WHERE type="table"')
rows = cursor.fetchall()
for row in rows:
table_name = row[0]
if table_name != "version":
cursor.execute("DELETE FROM " + table_name)
conn.commit()
cursor.close()
def _add_worker_image_thread(self, url):
while True: while True:
# removed finished # removed finished
for thread in self.imageCacheThreads: for thread in self.image_cache_threads:
if thread.is_finished: if thread.is_finished:
self.imageCacheThreads.remove(thread) self.image_cache_threads.remove(thread)
# add a new thread or wait and retry if we hit our limit # add a new thread or wait and retry if we hit our limit
if len(self.imageCacheThreads) < self.imageCacheLimitThreads: if len(self.image_cache_threads) < self.image_cache_limit:
newThread = image_cache_thread.ImageCacheThread()
newThread.set_url(self.double_urlencode(url)) new_thread = image_cache_thread.ImageCacheThread()
newThread.set_host(self.xbmc_host, self.xbmc_port) new_thread.set_url(self._double_urlencode(url))
newThread.set_auth(self.xbmc_username, self.xbmc_password) new_thread.set_host(self.xbmc_host, self.xbmc_port)
newThread.start() new_thread.set_auth(self.xbmc_username, self.xbmc_password)
self.imageCacheThreads.append(newThread)
new_thread.start()
self.image_cache_threads.append(new_thread)
return return
else: else:
log.info("Waiting for empty queue spot: %s" % len(self.imageCacheThreads)) log.info("Waiting for empty queue spot: %s", len(self.image_cache_threads))
xbmc.sleep(50) xbmc.sleep(50)
def cacheTexture(self, url): def cache_texture(self, url):
# Cache a single image url to the texture cache # Cache a single image url to the texture cache
if url and self.enableTextureCache: if url and self.enable_texture_cache:
log.debug("Processing: %s" % url) log.debug("Processing: %s", url)
if not self.imageCacheLimitThreads: if not self.image_cache_limit:
# Add image to texture cache by simply calling it at the http endpoint
url = self.double_urlencode(url) url = self._double_urlencode(url)
try: # Extreme short timeouts so we will have a exception. try: # Add image to texture cache by simply calling it at the http endpoint
response = requests.head( requests.head(url=("http://%s:%s/image/image://%s"
url=("http://%s:%s/image/image://%s"
% (self.xbmc_host, self.xbmc_port, url)), % (self.xbmc_host, self.xbmc_port, url)),
auth=(self.xbmc_username, self.xbmc_password), auth=(self.xbmc_username, self.xbmc_password),
timeout=(0.01, 0.01)) timeout=(0.01, 0.01))
# We don't need the result except Exception: # We don't need the result
except: pass pass
else: else:
self.addWorkerImageCacheThread(url) self._add_worker_image_thread(url)
def add_artwork(self, artwork, kodi_id, media_type, cursor):
def addArtwork(self, artwork, kodiId, mediaType, cursor):
# Kodi conversion table # Kodi conversion table
kodiart = { kodi_artwork = {
'Primary': ["thumb", "poster"], 'Primary': ["thumb", "poster"],
'Banner': "banner", 'Banner': "banner",
@ -318,15 +291,14 @@ class Artwork():
'Backdrop': "fanart", 'Backdrop': "fanart",
'BoxRear': "poster" 'BoxRear': "poster"
} }
# Artwork is a dictionary # Artwork is a dictionary
for art in artwork: for artwork_type in artwork:
if art == "Backdrop": if artwork_type == 'Backdrop':
# Backdrop entry is a list # Backdrop entry is a list
# Process extra fanart for artwork downloader (fanart, fanart1, fanart2...) # Process extra fanart for artwork downloader (fanart, fanart1, fanart2...)
backdrops = artwork[art] backdrops = artwork[artwork_type]
backdropsNumber = len(backdrops) backdrops_number = len(backdrops)
query = ' '.join(( query = ' '.join((
@ -336,10 +308,10 @@ class Artwork():
"AND media_type = ?", "AND media_type = ?",
"AND type LIKE ?" "AND type LIKE ?"
)) ))
cursor.execute(query, (kodiId, mediaType, "fanart%",)) cursor.execute(query, (kodi_id, media_type, "fanart%",))
rows = cursor.fetchall() rows = cursor.fetchall()
if len(rows) > backdropsNumber: if len(rows) > backdrops_number:
# More backdrops in database. Delete extra fanart. # More backdrops in database. Delete extra fanart.
query = ' '.join(( query = ' '.join((
@ -348,47 +320,40 @@ class Artwork():
"AND media_type = ?", "AND media_type = ?",
"AND type LIKE ?" "AND type LIKE ?"
)) ))
cursor.execute(query, (kodiId, mediaType, "fanart_",)) cursor.execute(query, (kodi_id, media_type, "fanart_",))
# Process backdrops and extra fanart # Process backdrops and extra fanart
index = "" for index, backdrop in enumerate(backdrops):
for backdrop in backdrops:
self.addOrUpdateArt( self.add_update_art(image_url=backdrop,
imageUrl=backdrop, kodi_id=kodi_id,
kodiId=kodiId, media_type=media_type,
mediaType=mediaType, image_type=("fanart" if not index else "%s%s"
imageType="%s%s" % ("fanart", index), % ("fanart", index)),
cursor=cursor) cursor=cursor)
if backdropsNumber > 1: elif artwork_type == 'Primary':
try: # Will only fail on the first try, str to int.
index += 1
except TypeError:
index = 1
elif art == "Primary":
# Primary art is processed as thumb and poster for Kodi. # Primary art is processed as thumb and poster for Kodi.
for artType in kodiart[art]: for art_type in kodi_artwork[artwork_type]:
self.addOrUpdateArt( self.add_update_art(image_url=artwork[artwork_type],
imageUrl=artwork[art], kodi_id=kodi_id,
kodiId=kodiId, media_type=media_type,
mediaType=mediaType, image_type=art_type,
imageType=artType,
cursor=cursor) cursor=cursor)
elif kodiart.get(art): elif artwork_type in kodi_artwork:
# Process the rest artwork type that Kodi can use # Process the rest artwork type that Kodi can use
self.addOrUpdateArt( self.add_update_art(image_url=artwork[artwork_type],
imageUrl=artwork[art], kodi_id=kodi_id,
kodiId=kodiId, media_type=media_type,
mediaType=mediaType, image_type=kodi_artwork[artwork_type],
imageType=kodiart[art],
cursor=cursor) cursor=cursor)
def addOrUpdateArt(self, imageUrl, kodiId, mediaType, imageType, cursor): def add_update_art(self, image_url, kodi_id, media_type, image_type, cursor):
# Possible that the imageurl is an empty string # Possible that the imageurl is an empty string
if imageUrl: if image_url:
cacheimage = False
cache_image = False
query = ' '.join(( query = ' '.join((
@ -398,13 +363,13 @@ class Artwork():
"AND media_type = ?", "AND media_type = ?",
"AND type = ?" "AND type = ?"
)) ))
cursor.execute(query, (kodiId, mediaType, imageType,)) cursor.execute(query, (kodi_id, media_type, image_type,))
try: # Update the artwork try: # Update the artwork
url = cursor.fetchone()[0] url = cursor.fetchone()[0]
except TypeError: # Add the artwork except TypeError: # Add the artwork
cacheimage = True cache_image = True
log.debug("Adding Art Link for kodiId: %s (%s)" % (kodiId, imageUrl)) log.debug("Adding Art Link for kodiId: %s (%s)", kodi_id, image_url)
query = ( query = (
''' '''
@ -413,20 +378,21 @@ class Artwork():
VALUES (?, ?, ?, ?) VALUES (?, ?, ?, ?)
''' '''
) )
cursor.execute(query, (kodiId, mediaType, imageType, imageUrl)) cursor.execute(query, (kodi_id, media_type, image_type, image_url))
else: # Only cache artwork if it changed else: # Only cache artwork if it changed
if url != imageUrl: if url != image_url:
cacheimage = True
cache_image = True
# Only for the main backdrop, poster # Only for the main backdrop, poster
if (window('emby_initialScan') != "true" and if (window('emby_initialScan') != "true" and
imageType in ("fanart", "poster")): image_type in ("fanart", "poster")):
# Delete current entry before updating with the new one # Delete current entry before updating with the new one
self.deleteCachedArtwork(url) self.delete_cached_artwork(url)
log.info("Updating Art url for %s kodiId: %s (%s) -> (%s)" log.info("Updating Art url for %s kodiId: %s (%s) -> (%s)",
% (imageType, kodiId, url, imageUrl)) image_type, kodi_id, url, image_url)
query = ' '.join(( query = ' '.join((
@ -436,13 +402,13 @@ class Artwork():
"AND media_type = ?", "AND media_type = ?",
"AND type = ?" "AND type = ?"
)) ))
cursor.execute(query, (imageUrl, kodiId, mediaType, imageType)) cursor.execute(query, (image_url, kodi_id, media_type, image_type))
# Cache fanart and poster in Kodi texture cache # Cache fanart and poster in Kodi texture cache
if cacheimage and imageType in ("fanart", "poster"): if cache_image and image_type in ("fanart", "poster"):
self.cacheTexture(imageUrl) self.cache_texture(image_url)
def deleteArtwork(self, kodiId, mediaType, cursor): def delete_artwork(self, kodi_id, media_type, cursor):
query = ' '.join(( query = ' '.join((
@ -451,85 +417,83 @@ class Artwork():
"WHERE media_id = ?", "WHERE media_id = ?",
"AND media_type = ?" "AND media_type = ?"
)) ))
cursor.execute(query, (kodiId, mediaType,)) cursor.execute(query, (kodi_id, media_type,))
rows = cursor.fetchall() rows = cursor.fetchall()
for row in rows: for row in rows:
url = row[0] url = row[0]
imageType = row[1] image_type = row[1]
if imageType in ("poster", "fanart"): if image_type in ("poster", "fanart"):
self.deleteCachedArtwork(url) self.delete_cached_artwork(url)
def deleteCachedArtwork(self, url): @classmethod
def delete_cached_artwork(cls, url):
# Only necessary to remove and apply a new backdrop or poster # Only necessary to remove and apply a new backdrop or poster
connection = kodiSQL('texture') conn = kodiSQL('texture')
cursor = connection.cursor() cursor = conn.cursor()
try: try:
cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url,)) cursor.execute("SELECT cachedurl FROM texture WHERE url = ?", (url,))
cachedurl = cursor.fetchone()[0] cached_url = cursor.fetchone()[0]
except TypeError: except TypeError:
log.info("Could not find cached url.") log.info("Could not find cached url")
except OperationalError: except OperationalError:
log.info("Database is locked. Skip deletion process.") log.info("Database is locked. Skip deletion process.")
else: # Delete thumbnail as well as the entry else: # Delete thumbnail as well as the entry
thumbnails = xbmc.translatePath("special://thumbnails/%s" % cachedurl).decode('utf-8') thumbnails = xbmc.translatePath("special://thumbnails/%s", cached_url).decode('utf-8')
log.info("Deleting cached thumbnail: %s" % thumbnails) log.info("Deleting cached thumbnail: %s", thumbnails)
xbmcvfs.delete(thumbnails) xbmcvfs.delete(thumbnails)
try: try:
cursor.execute("DELETE FROM texture WHERE url = ?", (url,)) cursor.execute("DELETE FROM texture WHERE url = ?", (url,))
connection.commit() conn.commit()
except OperationalError: except OperationalError:
log.debug("Issue deleting url from cache. Skipping.") log.debug("Issue deleting url from cache. Skipping.")
finally: finally:
cursor.close() cursor.close()
def getPeopleArtwork(self, people): def get_people_artwork(self, people):
# append imageurl if existing # append imageurl if existing
for person in people: for person in people:
personId = person['Id']
tag = person.get('PrimaryImageTag')
image = "" image = ""
if tag: person_id = person['Id']
if "PrimaryImageTag" in person:
image = ( image = (
"%s/emby/Items/%s/Images/Primary?" "%s/emby/Items/%s/Images/Primary?"
"MaxWidth=400&MaxHeight=400&Index=0&Tag=%s" "MaxWidth=400&MaxHeight=400&Index=0&Tag=%s"
% (self.server, personId, tag)) % (self.server, person_id, person['PrimaryImageTag']))
person['imageurl'] = image person['imageurl'] = image
return people return people
def getUserArtwork(self, itemId, itemType): def get_user_artwork(self, item_id, item_type):
# Load user information set by UserClient # Load user information set by UserClient
image = ("%s/emby/Users/%s/Images/%s?Format=original" return "%s/emby/Users/%s/Images/%s?Format=original" % (self.server, item_id, item_type)
% (self.server, itemId, itemType))
return image
def getAllArtwork(self, item, parentInfo=False): def get_all_artwork(self, item, parent_info=False):
itemid = item['Id'] item_id = item['Id']
artworks = item['ImageTags'] artworks = item['ImageTags']
backdrops = item.get('BackdropImageTags', []) backdrops = item.get('BackdropImageTags', [])
maxHeight = 10000 max_height = 10000
maxWidth = 10000 max_width = 10000
customquery = "" custom_query = ""
if settings('compressArt') == "true": if settings('compressArt') == "true":
customquery = "&Quality=90" custom_query = "&Quality=90"
if settings('enableCoverArt') == "false": if settings('enableCoverArt') == "false":
customquery += "&EnableImageEnhancers=false" custom_query += "&EnableImageEnhancers=false"
allartworks = { all_artwork = {
'Primary': "", 'Primary': "",
'Art': "", 'Art': "",
@ -540,71 +504,52 @@ class Artwork():
'Backdrop': [] 'Backdrop': []
} }
# Process backdrops def get_backdrops(backdrops):
for index, tag in enumerate(backdrops): for index, tag in enumerate(backdrops):
artwork = ( artwork = ("%s/emby/Items/%s/Images/Backdrop/%s?"
"%s/emby/Items/%s/Images/Backdrop/%s?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s" "MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (self.server, itemid, index, maxWidth, maxHeight, tag, customquery)) % (self.server, item_id, index, max_width, max_height,
allartworks['Backdrop'].append(artwork) tag, custom_query))
all_artwork['Backdrop'].append(artwork)
def get_artwork(type_, tag):
artwork = ("%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (self.server, item_id, type_, max_width, max_height, tag, custom_query))
all_artwork[type_] = artwork
# Process backdrops
get_backdrops(backdrops)
# Process the rest of the artwork # Process the rest of the artwork
for art in artworks: for artwork in artworks:
# Filter backcover # Filter backcover
if art != "BoxRear": if artwork != "BoxRear":
tag = artworks[art] get_artwork(artwork, artworks[artwork])
artwork = (
"%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (self.server, itemid, art, maxWidth, maxHeight, tag, customquery))
allartworks[art] = artwork
# Process parent items if the main item is missing artwork # Process parent items if the main item is missing artwork
if parentInfo: if parent_info:
# Process parent backdrops # Process parent backdrops
if not allartworks['Backdrop']: if not all_artwork['Backdrop']:
parentId = item.get('ParentBackdropItemId') if 'ParentBackdropItemId' in item:
if parentId: # If there is a parent_id, go through the parent backdrop list
# If there is a parentId, go through the parent backdrop list get_backdrops(item['ParentBackdropImageTags'])
parentbackdrops = item['ParentBackdropImageTags']
for index, tag in enumerate(parentbackdrops):
artwork = (
"%s/emby/Items/%s/Images/Backdrop/%s?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (self.server, parentId, index, maxWidth, maxHeight, tag, customquery))
allartworks['Backdrop'].append(artwork)
# Process the rest of the artwork # Process the rest of the artwork
parentartwork = ['Logo', 'Art', 'Thumb'] for parent_artwork in ('Logo', 'Art', 'Thumb'):
for parentart in parentartwork:
if not allartworks[parentart]: if not all_artwork[parent_artwork]:
parentId = item.get('Parent%sItemId' % parentart) if 'Parent%sItemId' % parent_artwork in item:
if parentId: get_artwork(parent_artwork, item['Parent%sImageTag' % parent_artwork])
parentTag = item['Parent%sImageTag' % parentart]
artwork = (
"%s/emby/Items/%s/Images/%s/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (self.server, parentId, parentart,
maxWidth, maxHeight, parentTag, customquery))
allartworks[parentart] = artwork
# Parent album works a bit differently # Parent album works a bit differently
if not allartworks['Primary']: if not all_artwork['Primary']:
parentId = item.get('AlbumId') if 'AlbumId' in item and 'AlbumPrimaryImageTag' in item:
if parentId and item.get('AlbumPrimaryImageTag'): get_artwork('Primary', item['AlbumPrimaryImageTag'])
parentTag = item['AlbumPrimaryImageTag'] return all_artwork
artwork = (
"%s/emby/Items/%s/Images/Primary/0?"
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
% (self.server, parentId, maxWidth, maxHeight, parentTag, customquery))
allartworks['Primary'] = artwork
return allartworks

View file

@ -191,7 +191,7 @@ class Embydb_Functions():
self.embycursor.execute(query, (parentid, mediatype,)) self.embycursor.execute(query, (parentid, mediatype,))
return self.embycursor.fetchall() return self.embycursor.fetchall()
def getChecksum(self, mediatype): def get_checksum(self, mediatype):
query = ' '.join(( query = ' '.join((

View file

@ -319,7 +319,7 @@ def addUser():
url = "{server}/emby/Users/%s?format=json" % userid url = "{server}/emby/Users/%s?format=json" % userid
result = doUtils.downloadUrl(url) result = doUtils.downloadUrl(url)
window('EmbyAdditionalUserImage.%s' % count, window('EmbyAdditionalUserImage.%s' % count,
value=art.getUserArtwork(result['Id'], 'Primary')) value=art.get_user_artwork(result['Id'], 'Primary'))
window('EmbyAdditionalUserPosition.%s' % userid, value=str(count)) window('EmbyAdditionalUserPosition.%s' % userid, value=str(count))
count +=1 count +=1
@ -608,7 +608,7 @@ def createListItemFromEmbyItem(item,art=artwork.Artwork(),doUtils=downloadutils.
li.setProperty("embyid",itemid) li.setProperty("embyid",itemid)
allart = art.getAllArtwork(item) allart = art.get_all_artwork(item)
if item["Type"] == "Photo": if item["Type"] == "Photo":
#listitem setup for pictures... #listitem setup for pictures...
@ -621,16 +621,16 @@ def createListItemFromEmbyItem(item,art=artwork.Artwork(),doUtils=downloadutils.
li.setArt( {"fanart": img_path}) #add image as fanart for use with skinhelper auto thumb/backgrund creation li.setArt( {"fanart": img_path}) #add image as fanart for use with skinhelper auto thumb/backgrund creation
li.setInfo('pictures', infoLabels={ "picturepath": img_path, "date": premieredate, "size": picture.get("Size"), "exif:width": str(picture.get("Width")), "exif:height": str(picture.get("Height")), "title": title}) li.setInfo('pictures', infoLabels={ "picturepath": img_path, "date": premieredate, "size": picture.get("Size"), "exif:width": str(picture.get("Width")), "exif:height": str(picture.get("Height")), "title": title})
li.setThumbnailImage(img_path) li.setThumbnailImage(img_path)
li.setProperty("plot",API.getOverview()) li.setProperty("plot",API.get_overview())
li.setIconImage('DefaultPicture.png') li.setIconImage('DefaultPicture.png')
else: else:
#normal video items #normal video items
li.setProperty('IsPlayable', 'true') li.setProperty('IsPlayable', 'true')
path = "%s?id=%s&mode=play" % (sys.argv[0], item.get("Id")) path = "%s?id=%s&mode=play" % (sys.argv[0], item.get("Id"))
li.setProperty("path",path) li.setProperty("path",path)
genre = API.getGenres() genre = API.get_genres()
overlay = 0 overlay = 0
userdata = API.getUserData() userdata = API.get_userdata()
runtime = item.get("RunTimeTicks",0)/ 10000000.0 runtime = item.get("RunTimeTicks",0)/ 10000000.0
seektime = userdata['Resume'] seektime = userdata['Resume']
if seektime: if seektime:
@ -655,7 +655,7 @@ def createListItemFromEmbyItem(item,art=artwork.Artwork(),doUtils=downloadutils.
'genre': genre, 'genre': genre,
'playcount': str(playcount), 'playcount': str(playcount),
'title': title, 'title': title,
'plot': API.getOverview(), 'plot': API.get_overview(),
'Overlay': str(overlay), 'Overlay': str(overlay),
'duration': runtime 'duration': runtime
} }
@ -672,7 +672,7 @@ def createListItemFromEmbyItem(item,art=artwork.Artwork(),doUtils=downloadutils.
else: else:
pbutils.PlaybackUtils(item).setArtwork(li) pbutils.PlaybackUtils(item).setArtwork(li)
mediastreams = API.getMediaStreams() mediastreams = API.get_media_streams()
videostreamFound = False videostreamFound = False
if mediastreams: if mediastreams:
for key, value in mediastreams.iteritems(): for key, value in mediastreams.iteritems():
@ -1084,7 +1084,7 @@ def getExtraFanArt(embyId,embyPath):
xbmcvfs.mkdirs(fanartDir) xbmcvfs.mkdirs(fanartDir)
item = emby.getItem(embyId) item = emby.getItem(embyId)
if item: if item:
backdrops = art.getAllArtwork(item)['Backdrop'] backdrops = art.get_all_artwork(item)['Backdrop']
tags = item['BackdropImageTags'] tags = item['BackdropImageTags']
count = 0 count = 0
for backdrop in backdrops: for backdrop in backdrops:

View file

@ -307,31 +307,31 @@ class Movies(Items):
log.debug("View tag found: %s" % viewtag) log.debug("View tag found: %s" % viewtag)
# fileId information # fileId information
checksum = API.getChecksum() checksum = API.get_checksum()
dateadded = API.getDateCreated() dateadded = API.get_date_created()
userdata = API.getUserData() userdata = API.get_userdata()
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
# item details # item details
people = API.getPeople() people = API.get_people()
writer = " / ".join(people['Writer']) writer = " / ".join(people['Writer'])
director = " / ".join(people['Director']) director = " / ".join(people['Director'])
genres = item['Genres'] genres = item['Genres']
title = item['Name'] title = item['Name']
plot = API.getOverview() plot = API.get_overview()
shortplot = item.get('ShortOverview') shortplot = item.get('ShortOverview')
tagline = API.getTagline() tagline = API.get_tagline()
votecount = item.get('VoteCount') votecount = item.get('VoteCount')
rating = item.get('CommunityRating') rating = item.get('CommunityRating')
year = item.get('ProductionYear') year = item.get('ProductionYear')
imdb = API.getProvider('Imdb') imdb = API.get_provider('Imdb')
sorttitle = item['SortName'] sorttitle = item['SortName']
runtime = API.getRuntime() runtime = API.get_runtime()
mpaa = API.getMpaa() mpaa = API.get_mpaa()
genre = " / ".join(genres) genre = " / ".join(genres)
country = API.getCountry() country = API.get_country()
studios = API.getStudios() studios = API.get_studios()
try: try:
studio = studios[0] studio = studios[0]
except IndexError: except IndexError:
@ -366,7 +366,7 @@ class Movies(Items):
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
playurl = API.getFilePath() playurl = API.get_file_path()
if "\\" in playurl: if "\\" in playurl:
# Local path # Local path
@ -461,14 +461,14 @@ class Movies(Items):
# Process countries # Process countries
self.kodi_db.addCountries(movieid, item['ProductionLocations'], "movie") self.kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = artwork.get_people_artwork(item['People'])
self.kodi_db.addPeople(movieid, people, "movie") self.kodi_db.addPeople(movieid, people, "movie")
# Process genres # Process genres
self.kodi_db.addGenres(movieid, genres, "movie") self.kodi_db.addGenres(movieid, genres, "movie")
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), movieid, "movie", kodicursor) artwork.add_artwork(artwork.get_all_artwork(item), movieid, "movie", kodicursor)
# Process stream details # Process stream details
streams = API.getMediaStreams() streams = API.get_media_streams()
self.kodi_db.addStreams(fileid, streams, runtime) self.kodi_db.addStreams(fileid, streams, runtime)
# Process studios # Process studios
self.kodi_db.addStudios(movieid, studios, "movie") self.kodi_db.addStudios(movieid, studios, "movie")
@ -479,7 +479,7 @@ class Movies(Items):
tags.append("Favorite movies") tags.append("Favorite movies")
self.kodi_db.addTags(movieid, tags, "movie") self.kodi_db.addTags(movieid, tags, "movie")
# Process playstates # Process playstates
resume = API.adjustResume(userdata['Resume']) resume = API.adjust_resume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
@ -500,7 +500,7 @@ class Movies(Items):
setid = self.kodi_db.createBoxset(title) setid = self.kodi_db.createBoxset(title)
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(boxset), setid, "set", self.kodicursor) artwork.add_artwork(artwork.get_all_artwork(boxset), setid, "set", self.kodicursor)
# Process movies inside boxset # Process movies inside boxset
current_movies = emby_db.getItemId_byParentId(setid, "movie") current_movies = emby_db.getItemId_byParentId(setid, "movie")
@ -556,9 +556,9 @@ class Movies(Items):
# Get emby information # Get emby information
itemid = item['Id'] itemid = item['Id']
checksum = API.getChecksum() checksum = API.get_checksum()
userdata = API.getUserData() userdata = API.get_userdata()
runtime = API.getRuntime() runtime = API.get_runtime()
# Get Kodi information # Get Kodi information
emby_dbitem = emby_db.getItem_byId(itemid) emby_dbitem = emby_db.getItem_byId(itemid)
@ -578,7 +578,7 @@ class Movies(Items):
# Process playstates # Process playstates
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
resume = API.adjustResume(userdata['Resume']) resume = API.adjust_resume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
log.debug("%s New resume point: %s" % (itemid, resume)) log.debug("%s New resume point: %s" % (itemid, resume))
@ -604,7 +604,7 @@ class Movies(Items):
# Remove the emby reference # Remove the emby reference
emby_db.removeItem(itemid) emby_db.removeItem(itemid)
# Remove artwork # Remove artwork
artwork.deleteArtwork(kodiid, mediatype, kodicursor) artwork.delete_artwork(kodiid, mediatype, kodicursor)
if mediatype == "movie": if mediatype == "movie":
# Delete kodi movie and file # Delete kodi movie and file
@ -693,30 +693,30 @@ class MusicVideos(Items):
log.debug("View tag found: %s" % viewtag) log.debug("View tag found: %s" % viewtag)
# fileId information # fileId information
checksum = API.getChecksum() checksum = API.get_checksum()
dateadded = API.getDateCreated() dateadded = API.get_date_created()
userdata = API.getUserData() userdata = API.get_userdata()
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
# item details # item details
runtime = API.getRuntime() runtime = API.get_runtime()
plot = API.getOverview() plot = API.get_overview()
title = item['Name'] title = item['Name']
year = item.get('ProductionYear') year = item.get('ProductionYear')
genres = item['Genres'] genres = item['Genres']
genre = " / ".join(genres) genre = " / ".join(genres)
studios = API.getStudios() studios = API.get_studios()
studio = " / ".join(studios) studio = " / ".join(studios)
artist = " / ".join(item.get('Artists')) artist = " / ".join(item.get('Artists'))
album = item.get('Album') album = item.get('Album')
track = item.get('Track') track = item.get('Track')
people = API.getPeople() people = API.get_people()
director = " / ".join(people['Director']) director = " / ".join(people['Director'])
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
playurl = API.getFilePath() playurl = API.get_file_path()
if "\\" in playurl: if "\\" in playurl:
# Local path # Local path
@ -833,14 +833,14 @@ class MusicVideos(Items):
for artist in artists: for artist in artists:
artist['Type'] = "Artist" artist['Type'] = "Artist"
people.extend(artists) people.extend(artists)
people = artwork.getPeopleArtwork(people) people = artwork.get_people_artwork(people)
self.kodi_db.addPeople(mvideoid, people, "musicvideo") self.kodi_db.addPeople(mvideoid, people, "musicvideo")
# Process genres # Process genres
self.kodi_db.addGenres(mvideoid, genres, "musicvideo") self.kodi_db.addGenres(mvideoid, genres, "musicvideo")
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), mvideoid, "musicvideo", kodicursor) artwork.add_artwork(artwork.get_all_artwork(item), mvideoid, "musicvideo", kodicursor)
# Process stream details # Process stream details
streams = API.getMediaStreams() streams = API.get_media_streams()
self.kodi_db.addStreams(fileid, streams, runtime) self.kodi_db.addStreams(fileid, streams, runtime)
# Process studios # Process studios
self.kodi_db.addStudios(mvideoid, studios, "musicvideo") self.kodi_db.addStudios(mvideoid, studios, "musicvideo")
@ -851,7 +851,7 @@ class MusicVideos(Items):
tags.append("Favorite musicvideos") tags.append("Favorite musicvideos")
self.kodi_db.addTags(mvideoid, tags, "musicvideo") self.kodi_db.addTags(mvideoid, tags, "musicvideo")
# Process playstates # Process playstates
resume = API.adjustResume(userdata['Resume']) resume = API.adjust_resume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
@ -863,9 +863,9 @@ class MusicVideos(Items):
# Get emby information # Get emby information
itemid = item['Id'] itemid = item['Id']
checksum = API.getChecksum() checksum = API.get_checksum()
userdata = API.getUserData() userdata = API.get_userdata()
runtime = API.getRuntime() runtime = API.get_runtime()
# Get Kodi information # Get Kodi information
emby_dbitem = emby_db.getItem_byId(itemid) emby_dbitem = emby_db.getItem_byId(itemid)
@ -887,7 +887,7 @@ class MusicVideos(Items):
# Process playstates # Process playstates
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
resume = API.adjustResume(userdata['Resume']) resume = API.adjust_resume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
@ -922,7 +922,7 @@ class MusicVideos(Items):
url = row[0] url = row[0]
imagetype = row[1] imagetype = row[1]
if imagetype in ("poster", "fanart"): if imagetype in ("poster", "fanart"):
artwork.deleteCachedArtwork(url) artwork.delete_cached_artwork(url)
kodicursor.execute("DELETE FROM musicvideo WHERE idMVideo = ?", (mvideoid,)) kodicursor.execute("DELETE FROM musicvideo WHERE idMVideo = ?", (mvideoid,))
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,)) kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
@ -1033,28 +1033,28 @@ class TVShows(Items):
log.debug("View tag found: %s" % viewtag) log.debug("View tag found: %s" % viewtag)
# fileId information # fileId information
checksum = API.getChecksum() checksum = API.get_checksum()
dateadded = API.getDateCreated() dateadded = API.get_date_created()
userdata = API.getUserData() userdata = API.get_userdata()
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
# item details # item details
genres = item['Genres'] genres = item['Genres']
title = item['Name'] title = item['Name']
plot = API.getOverview() plot = API.get_overview()
rating = item.get('CommunityRating') rating = item.get('CommunityRating')
premieredate = API.getPremiereDate() premieredate = API.get_premiere_date()
tvdb = API.getProvider('Tvdb') tvdb = API.get_provider('Tvdb')
sorttitle = item['SortName'] sorttitle = item['SortName']
mpaa = API.getMpaa() mpaa = API.get_mpaa()
genre = " / ".join(genres) genre = " / ".join(genres)
studios = API.getStudios() studios = API.get_studios()
studio = " / ".join(studios) studio = " / ".join(studios)
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
playurl = API.getFilePath() playurl = API.get_file_path()
if self.directpath: if self.directpath:
# Direct paths is set the Kodi way # Direct paths is set the Kodi way
@ -1142,12 +1142,12 @@ class TVShows(Items):
kodicursor.execute(query, (path, None, None, 1, pathid)) kodicursor.execute(query, (path, None, None, 1, pathid))
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = artwork.get_people_artwork(item['People'])
self.kodi_db.addPeople(showid, people, "tvshow") self.kodi_db.addPeople(showid, people, "tvshow")
# Process genres # Process genres
self.kodi_db.addGenres(showid, genres, "tvshow") self.kodi_db.addGenres(showid, genres, "tvshow")
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), showid, "tvshow", kodicursor) artwork.add_artwork(artwork.get_all_artwork(item), showid, "tvshow", kodicursor)
# Process studios # Process studios
self.kodi_db.addStudios(showid, studios, "tvshow") self.kodi_db.addStudios(showid, studios, "tvshow")
# Process tags: view, emby tags # Process tags: view, emby tags
@ -1164,7 +1164,7 @@ class TVShows(Items):
# Finally, refresh the all season entry # Finally, refresh the all season entry
seasonid = self.kodi_db.addSeason(showid, -1) seasonid = self.kodi_db.addSeason(showid, -1)
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor) artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
if force_episodes: if force_episodes:
# We needed to recreate the show entry. Re-add episodes now. # We needed to recreate the show entry. Re-add episodes now.
@ -1199,7 +1199,7 @@ class TVShows(Items):
emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid) emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid)
# Process artwork # Process artwork
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor) artwork.add_artwork(artwork.get_all_artwork(item), seasonid, "season", kodicursor)
def add_updateEpisode(self, item): def add_updateEpisode(self, item):
# Process single episode # Process single episode
@ -1225,7 +1225,7 @@ class TVShows(Items):
except TypeError: except TypeError:
update_item = False update_item = False
log.info("episodeid: %s not found." % itemid) log.debug("episodeid: %s not found." % itemid)
# episodeid # episodeid
kodicursor.execute("select coalesce(max(idEpisode),0) from episode") kodicursor.execute("select coalesce(max(idEpisode),0) from episode")
episodeid = kodicursor.fetchone()[0] + 1 episodeid = kodicursor.fetchone()[0] + 1
@ -1242,21 +1242,21 @@ class TVShows(Items):
log.info("episodeid: %s missing from Kodi, repairing the entry." % episodeid) log.info("episodeid: %s missing from Kodi, repairing the entry." % episodeid)
# fileId information # fileId information
checksum = API.getChecksum() checksum = API.get_checksum()
dateadded = API.getDateCreated() dateadded = API.get_date_created()
userdata = API.getUserData() userdata = API.get_userdata()
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
# item details # item details
people = API.getPeople() people = API.get_people()
writer = " / ".join(people['Writer']) writer = " / ".join(people['Writer'])
director = " / ".join(people['Director']) director = " / ".join(people['Director'])
title = item['Name'] title = item['Name']
plot = API.getOverview() plot = API.get_overview()
rating = item.get('CommunityRating') rating = item.get('CommunityRating')
runtime = API.getRuntime() runtime = API.get_runtime()
premieredate = API.getPremiereDate() premieredate = API.get_premiere_date()
# episode details # episode details
try: try:
@ -1308,7 +1308,7 @@ class TVShows(Items):
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
playurl = API.getFilePath() playurl = API.get_file_path()
if "\\" in playurl: if "\\" in playurl:
# Local path # Local path
@ -1431,16 +1431,16 @@ class TVShows(Items):
kodicursor.execute(query, (pathid, filename, dateadded, fileid)) kodicursor.execute(query, (pathid, filename, dateadded, fileid))
# Process cast # Process cast
people = artwork.getPeopleArtwork(item['People']) people = artwork.get_people_artwork(item['People'])
self.kodi_db.addPeople(episodeid, people, "episode") self.kodi_db.addPeople(episodeid, people, "episode")
# Process artwork # Process artwork
artworks = artwork.getAllArtwork(item) artworks = artwork.get_all_artwork(item)
artwork.addOrUpdateArt(artworks['Primary'], episodeid, "episode", "thumb", kodicursor) artwork.add_update_art(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
# Process stream details # Process stream details
streams = API.getMediaStreams() streams = API.get_media_streams()
self.kodi_db.addStreams(fileid, streams, runtime) self.kodi_db.addStreams(fileid, streams, runtime)
# Process playstates # Process playstates
resume = API.adjustResume(userdata['Resume']) resume = API.adjust_resume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed) self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
if not self.directpath and resume: if not self.directpath and resume:
@ -1464,10 +1464,10 @@ class TVShows(Items):
# Get emby information # Get emby information
itemid = item['Id'] itemid = item['Id']
checksum = API.getChecksum() checksum = API.get_checksum()
userdata = API.getUserData() userdata = API.get_userdata()
runtime = API.getRuntime() runtime = API.get_runtime()
dateadded = API.getDateCreated() dateadded = API.get_date_created()
# Get Kodi information # Get Kodi information
emby_dbitem = emby_db.getItem_byId(itemid) emby_dbitem = emby_db.getItem_byId(itemid)
@ -1491,7 +1491,7 @@ class TVShows(Items):
# Process playstates # Process playstates
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
resume = API.adjustResume(userdata['Resume']) resume = API.adjust_resume(userdata['Resume'])
total = round(float(runtime), 6) total = round(float(runtime), 6)
log.debug("%s New resume point: %s" % (itemid, resume)) log.debug("%s New resume point: %s" % (itemid, resume))
@ -1627,7 +1627,7 @@ class TVShows(Items):
def removeShow(self, kodiid): def removeShow(self, kodiid):
kodicursor = self.kodicursor kodicursor = self.kodicursor
self.artwork.deleteArtwork(kodiid, "tvshow", kodicursor) self.artwork.delete_artwork(kodiid, "tvshow", kodicursor)
kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,)) kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,))
log.debug("Removed tvshow: %s." % kodiid) log.debug("Removed tvshow: %s." % kodiid)
@ -1635,7 +1635,7 @@ class TVShows(Items):
kodicursor = self.kodicursor kodicursor = self.kodicursor
self.artwork.deleteArtwork(kodiid, "season", kodicursor) self.artwork.delete_artwork(kodiid, "season", kodicursor)
kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,)) kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,))
log.debug("Removed season: %s." % kodiid) log.debug("Removed season: %s." % kodiid)
@ -1643,7 +1643,7 @@ class TVShows(Items):
kodicursor = self.kodicursor kodicursor = self.kodicursor
self.artwork.deleteArtwork(kodiid, "episode", kodicursor) self.artwork.delete_artwork(kodiid, "episode", kodicursor)
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,)) kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,))
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,)) kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
log.debug("Removed episode: %s." % kodiid) log.debug("Removed episode: %s." % kodiid)
@ -1724,16 +1724,16 @@ class Music(Items):
##### The artist details ##### ##### The artist details #####
lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S') lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
dateadded = API.getDateCreated() dateadded = API.get_date_created()
checksum = API.getChecksum() checksum = API.get_checksum()
name = item['Name'] name = item['Name']
musicBrainzId = API.getProvider('MusicBrainzArtist') musicBrainzId = API.get_provider('MusicBrainzArtist')
genres = " / ".join(item.get('Genres')) genres = " / ".join(item.get('Genres'))
bio = API.getOverview() bio = API.get_overview()
# Associate artwork # Associate artwork
artworks = artwork.getAllArtwork(item, parentInfo=True) artworks = artwork.get_all_artwork(item, parent_info=True)
thumb = artworks['Primary'] thumb = artworks['Primary']
backdrops = artworks['Backdrop'] # List backdrops = artworks['Backdrop'] # List
@ -1784,7 +1784,7 @@ class Music(Items):
# Update artwork # Update artwork
artwork.addArtwork(artworks, artistid, "artist", kodicursor) artwork.add_artwork(artworks, artistid, "artist", kodicursor)
def add_updateAlbum(self, item): def add_updateAlbum(self, item):
# Process a single artist # Process a single artist
@ -1805,16 +1805,16 @@ class Music(Items):
##### The album details ##### ##### The album details #####
lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S') lastScraped = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
dateadded = API.getDateCreated() dateadded = API.get_date_created()
userdata = API.getUserData() userdata = API.get_userdata()
checksum = API.getChecksum() checksum = API.get_checksum()
name = item['Name'] name = item['Name']
musicBrainzId = API.getProvider('MusicBrainzAlbum') musicBrainzId = API.get_provider('MusicBrainzAlbum')
year = item.get('ProductionYear') year = item.get('ProductionYear')
genres = item.get('Genres') genres = item.get('Genres')
genre = " / ".join(genres) genre = " / ".join(genres)
bio = API.getOverview() bio = API.get_overview()
rating = userdata['UserRating'] rating = userdata['UserRating']
artists = item['AlbumArtists'] artists = item['AlbumArtists']
if not artists: if not artists:
@ -1825,7 +1825,7 @@ class Music(Items):
artistname = " / ".join(artistname) artistname = " / ".join(artistname)
# Associate artwork # Associate artwork
artworks = artwork.getAllArtwork(item, parentInfo=True) artworks = artwork.get_all_artwork(item, parent_info=True)
thumb = artworks['Primary'] thumb = artworks['Primary']
if thumb: if thumb:
thumb = "<thumb>%s</thumb>" % thumb thumb = "<thumb>%s</thumb>" % thumb
@ -1952,7 +1952,7 @@ class Music(Items):
# Add genres # Add genres
self.kodi_db.addMusicGenres(albumid, genres, "album") self.kodi_db.addMusicGenres(albumid, genres, "album")
# Update artwork # Update artwork
artwork.addArtwork(artworks, albumid, "album", kodicursor) artwork.add_artwork(artworks, albumid, "album", kodicursor)
def add_updateSong(self, item): def add_updateSong(self, item):
# Process single song # Process single song
@ -1974,15 +1974,15 @@ class Music(Items):
log.debug("songid: %s not found." % itemid) log.debug("songid: %s not found." % itemid)
##### The song details ##### ##### The song details #####
checksum = API.getChecksum() checksum = API.get_checksum()
dateadded = API.getDateCreated() dateadded = API.get_date_created()
userdata = API.getUserData() userdata = API.get_userdata()
playcount = userdata['PlayCount'] playcount = userdata['PlayCount']
dateplayed = userdata['LastPlayedDate'] dateplayed = userdata['LastPlayedDate']
# item details # item details
title = item['Name'] title = item['Name']
musicBrainzId = API.getProvider('MusicBrainzTrackId') musicBrainzId = API.get_provider('MusicBrainzTrackId')
genres = item.get('Genres') genres = item.get('Genres')
genre = " / ".join(genres) genre = " / ".join(genres)
artists = " / ".join(item['Artists']) artists = " / ".join(item['Artists'])
@ -1993,7 +1993,7 @@ class Music(Items):
else: else:
track = disc*2**16 + tracknumber track = disc*2**16 + tracknumber
year = item.get('ProductionYear') year = item.get('ProductionYear')
duration = API.getRuntime() duration = API.get_runtime()
rating = userdata['UserRating'] rating = userdata['UserRating']
#if enabled, try to get the rating from file and/or emby #if enabled, try to get the rating from file and/or emby
@ -2001,7 +2001,7 @@ class Music(Items):
rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating) rating, comment, hasEmbeddedCover = musicutils.getAdditionalSongTags(itemid, rating, API, kodicursor, emby_db, self.enableimportsongrating, self.enableexportsongrating, self.enableupdatesongrating)
else: else:
hasEmbeddedCover = False hasEmbeddedCover = False
comment = API.getOverview() comment = API.get_overview()
##### GET THE FILE AND PATH ##### ##### GET THE FILE AND PATH #####
@ -2009,7 +2009,7 @@ class Music(Items):
path = "%s/emby/Audio/%s/" % (self.server, itemid) path = "%s/emby/Audio/%s/" % (self.server, itemid)
filename = "stream.mp3" filename = "stream.mp3"
else: else:
playurl = API.getFilePath() playurl = API.get_file_path()
if "\\" in playurl: if "\\" in playurl:
# Local path # Local path
@ -2063,7 +2063,7 @@ class Music(Items):
album_name = item.get('Album') album_name = item.get('Album')
if album_name: if album_name:
log.info("Creating virtual music album for song: %s." % itemid) log.info("Creating virtual music album for song: %s." % itemid)
albumid = self.kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum')) albumid = self.kodi_db.addAlbum(album_name, API.get_provider('MusicBrainzAlbum'))
emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album") emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album")
else: else:
# No album Id associated to the song. # No album Id associated to the song.
@ -2257,14 +2257,14 @@ class Music(Items):
self.kodi_db.addMusicGenres(songid, genres, "song") self.kodi_db.addMusicGenres(songid, genres, "song")
# Update artwork # Update artwork
allart = artwork.getAllArtwork(item, parentInfo=True) allart = artwork.get_all_artwork(item, parent_info=True)
if hasEmbeddedCover: if hasEmbeddedCover:
allart["Primary"] = "image://music@" + artwork.single_urlencode( playurl ) allart["Primary"] = "image://music@" + artwork.single_urlencode( playurl )
artwork.addArtwork(allart, songid, "song", kodicursor) artwork.add_artwork(allart, songid, "song", kodicursor)
if item.get('AlbumId') is None: if item.get('AlbumId') is None:
# Update album artwork # Update album artwork
artwork.addArtwork(allart, albumid, "album", kodicursor) artwork.add_artwork(allart, albumid, "album", kodicursor)
def updateUserdata(self, item): def updateUserdata(self, item):
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks # This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
@ -2275,9 +2275,9 @@ class Music(Items):
# Get emby information # Get emby information
itemid = item['Id'] itemid = item['Id']
checksum = API.getChecksum() checksum = API.get_checksum()
userdata = API.getUserData() userdata = API.get_userdata()
runtime = API.getRuntime() runtime = API.get_runtime()
rating = userdata['UserRating'] rating = userdata['UserRating']
# Get Kodi information # Get Kodi information
@ -2401,15 +2401,15 @@ class Music(Items):
kodicursor = self.kodicursor kodicursor = self.kodicursor
self.artwork.deleteArtwork(kodiId, "song", self.kodicursor) self.artwork.delete_artwork(kodiId, "song", self.kodicursor)
self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiId,)) self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiId,))
def removeAlbum(self, kodiId): def removeAlbum(self, kodiId):
self.artwork.deleteArtwork(kodiId, "album", self.kodicursor) self.artwork.delete_artwork(kodiId, "album", self.kodicursor)
self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiId,)) self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiId,))
def removeArtist(self, kodiId): def removeArtist(self, kodiId):
self.artwork.deleteArtwork(kodiId, "artist", self.kodicursor) self.artwork.delete_artwork(kodiId, "artist", self.kodicursor)
self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiId,)) self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiId,))

View file

@ -420,7 +420,7 @@ class Kodidb_Functions():
if "writing" in arttype: if "writing" in arttype:
arttype = "writer" arttype = "writer"
self.artwork.addOrUpdateArt(thumb, actorid, arttype, "thumb", self.cursor) self.artwork.add_update_art(thumb, actorid, arttype, "thumb", self.cursor)
def addGenres(self, kodiid, genres, mediatype): def addGenres(self, kodiid, genres, mediatype):

View file

@ -25,79 +25,72 @@ class KodiMonitor(xbmc.Monitor):
def __init__(self): def __init__(self):
self.doUtils = downloadutils.DownloadUtils() self.download = downloadutils.DownloadUtils().downloadUrl
log.info("Kodi monitor started")
log.info("Kodi monitor started.")
def onScanStarted(self, library): def onScanStarted(self, library):
log.debug("Kodi library scan %s running." % library)
log.debug("Kodi library scan %s running", library)
if library == "video": if library == "video":
window('emby_kodiScan', value="true") window('emby_kodiScan', value="true")
def onScanFinished(self, library): def onScanFinished(self, library):
log.debug("Kodi library scan %s finished." % library)
log.debug("Kodi library scan %s finished", library)
if library == "video": if library == "video":
window('emby_kodiScan', clear=True) window('emby_kodiScan', clear=True)
def onSettingsChanged(self): def onSettingsChanged(self):
# Monitor emby settings # Monitor emby settings
# Review reset setting at a later time, need to be adjusted to account for initial setup current_log_level = settings('logLevel')
# changes. if window('emby_logLevel') != current_log_level:
'''currentPath = utils.settings('useDirectPaths')
if utils.window('emby_pluginpath') != currentPath:
# Plugin path value changed. Offer to reset
log("Changed to playback mode detected", 1)
utils.window('emby_pluginpath', value=currentPath)
resp = xbmcgui.Dialog().yesno(
heading="Playback mode change detected",
line1=(
"Detected the playback mode has changed. The database "
"needs to be recreated for the change to be applied. "
"Proceed?"))
if resp:
utils.reset()'''
currentLog = settings('logLevel')
if window('emby_logLevel') != currentLog:
# The log level changed, set new prop # The log level changed, set new prop
log.info("New log level: %s" % currentLog) log.info("New log level: %s", current_log_level)
window('emby_logLevel', value=currentLog) window('emby_logLevel', value=current_log_level)
def onNotification(self, sender, method, data): def onNotification(self, sender, method, data):
doUtils = self.doUtils if method not in ('Playlist.OnAdd', 'Player.OnStop', 'Player.OnClear'):
if method not in ("Playlist.OnAdd"): log.info("Method: %s Data: %s", method, data)
log.info("Method: %s Data: %s" % (method, data))
if data: if data:
data = json.loads(data, 'utf-8') data = json.loads(data, 'utf-8')
if method == 'Player.OnPlay':
self._on_play_(data)
if method == "Player.OnPlay": elif method == 'VideoLibrary.OnUpdate':
self._video_update(data)
elif method == 'System.OnSleep':
# Connection is going to sleep
log.info("Marking the server as offline. System.OnSleep activated.")
window('emby_online', value="sleep")
elif method == 'System.OnWake':
self._system_wake()
elif method == 'GUI.OnScreensaverDeactivated':
self._screensaver_deactivated()
def _on_play_(self, data):
# Set up report progress for emby playback # Set up report progress for emby playback
item = data.get('item')
try: try:
kodiid = item['id'] item = data['item']
kodi_id = item['id']
item_type = item['type'] item_type = item['type']
except (KeyError, TypeError): except (KeyError, TypeError):
log.info("Item is invalid for playstate update.") log.info("Item is invalid for playstate update")
else: else:
if ((settings('useDirectPaths') == "1" and not item_type == "song") or if ((settings('useDirectPaths') == "1" and not item_type == "song") or
(item_type == "song" and settings('enableMusic') == "true")): (item_type == "song" and settings('enableMusic') == "true")):
# Set up properties for player # Set up properties for player
embyconn = kodiSQL('emby') item_id = self._get_item_id(kodi_id, item_type)
embycursor = embyconn.cursor() if item_id:
emby_db = embydb.Embydb_Functions(embycursor) url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % item_id
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type) result = self.download(url)
try: log.debug("Item: %s", result)
itemid = emby_dbitem[0]
except TypeError:
log.info("No kodiId returned.")
else:
url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid
result = doUtils.downloadUrl(url)
log.debug("Item: %s" % result)
playurl = None playurl = None
count = 0 count = 0
@ -108,7 +101,7 @@ class KodiMonitor(xbmc.Monitor):
count += 1 count += 1
xbmc.sleep(200) xbmc.sleep(200)
else: else:
listItem = xbmcgui.ListItem() listitem = xbmcgui.ListItem()
playback = pbutils.PlaybackUtils(result) playback = pbutils.PlaybackUtils(result)
if item_type == "song" and settings('streamMusic') == "true": if item_type == "song" and settings('streamMusic') == "true":
@ -116,101 +109,62 @@ class KodiMonitor(xbmc.Monitor):
else: else:
window('emby_%s.playmethod' % playurl, value="DirectPlay") window('emby_%s.playmethod' % playurl, value="DirectPlay")
# Set properties for player.py # Set properties for player.py
playback.setProperties(playurl, listItem) playback.setProperties(playurl, listitem)
finally:
embycursor.close()
def _video_update(self, data):
elif method == "VideoLibrary.OnUpdate":
# Manually marking as watched/unwatched # Manually marking as watched/unwatched
playcount = data.get('playcount')
item = data.get('item')
try: try:
kodiid = item['id'] item = data['item']
kodi_id = item['id']
item_type = item['type'] item_type = item['type']
except (KeyError, TypeError): except (KeyError, TypeError):
log.info("Item is invalid for playstate update.") log.info("Item is invalid for playstate update")
else: else:
# Send notification to the server. # Send notification to the server.
embyconn = kodiSQL('emby') item_id = self._get_item_id(kodi_id, item_type)
embycursor = embyconn.cursor() if item_id:
emby_db = embydb.Embydb_Functions(embycursor)
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
try:
itemid = emby_dbitem[0]
except TypeError:
log.info("Could not find itemid in emby database.")
else:
# Stop from manually marking as watched unwatched, with actual playback. # Stop from manually marking as watched unwatched, with actual playback.
if window('emby_skipWatched%s' % itemid) == "true": if window('emby_skipWatched%s' % item_id) == "true":
# property is set in player.py # property is set in player.py
window('emby_skipWatched%s' % itemid, clear=True) window('emby_skipWatched%s' % item_id, clear=True)
else: else:
# notify the server # notify the server
url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % item_id
if playcount != 0: if data.get('playcount') != 0:
doUtils.downloadUrl(url, action_type="POST") self.download(url, action_type="POST")
log.info("Mark as watched for itemid: %s" % itemid) log.info("Mark as watched for itemid: %s", item_id)
else: else:
doUtils.downloadUrl(url, action_type="DELETE") self.download(url, action_type="DELETE")
log.info("Mark as unwatched for itemid: %s" % itemid) log.info("Mark as unwatched for itemid: %s", item_id)
finally:
embycursor.close()
@classmethod
elif method == "VideoLibrary.OnRemove": def _system_wake(cls):
# Removed function, because with plugin paths + clean library, it will wipe
# entire library if user has permissions. Instead, use the emby context menu available
# in Isengard and higher version
pass
'''try:
kodiid = data['id']
type = data['type']
except (KeyError, TypeError):
log("Item is invalid for emby deletion.", 1)
else:
# Send the delete action to the server.
embyconn = utils.kodiSQL('emby')
embycursor = embyconn.cursor()
emby_db = embydb.Embydb_Functions(embycursor)
emby_dbitem = emby_db.getItem_byKodiId(kodiid, type)
try:
itemid = emby_dbitem[0]
except TypeError:
log("Could not find itemid in emby database.", 1)
else:
if utils.settings('skipContextMenu') != "true":
resp = xbmcgui.Dialog().yesno(
heading="Confirm delete",
line1="Delete file on Emby Server?")
if not resp:
log("User skipped deletion.", 1)
embycursor.close()
return
url = "{server}/emby/Items/%s?format=json" % itemid
log("Deleting request: %s" % itemid)
doUtils.downloadUrl(url, action_type="DELETE")
finally:
embycursor.close()'''
elif method == "System.OnSleep":
# Connection is going to sleep
log.info("Marking the server as offline. System.OnSleep activated.")
window('emby_online', value="sleep")
elif method == "System.OnWake":
# Allow network to wake up # Allow network to wake up
xbmc.sleep(10000) xbmc.sleep(10000)
window('emby_online', value="false") window('emby_online', value="false")
window('emby_onWake', value="true") window('emby_onWake', value="true")
@classmethod
def _screensaver_deactivated(cls):
elif method == "GUI.OnScreensaverDeactivated":
if settings('dbSyncScreensaver') == "true": if settings('dbSyncScreensaver') == "true":
xbmc.sleep(5000); xbmc.sleep(5000)
window('emby_onWake', value="true") window('emby_onWake', value="true")
@classmethod
def _get_item_id(cls, kodi_id, item_type):
elif method == "Playlist.OnClear": item_id = None
pass
conn = kodiSQL('emby')
cursor = conn.cursor()
emby_db = embydb.Embydb_Functions(cursor)
db_item = emby_db.getItem_byKodiId(kodi_id, item_type)
cursor.close()
try:
item_id = db_item[0]
except TypeError:
log.info("Could not retrieve item Id")
return item_id

View file

@ -1049,12 +1049,12 @@ class ManualSync(LibrarySync):
# Pull the list of movies and boxsets in Kodi # Pull the list of movies and boxsets in Kodi
try: try:
all_kodimovies = dict(emby_db.getChecksum('Movie')) all_kodimovies = dict(emby_db.get_checksum('Movie'))
except ValueError: except ValueError:
all_kodimovies = {} all_kodimovies = {}
try: try:
all_kodisets = dict(emby_db.getChecksum('BoxSet')) all_kodisets = dict(emby_db.get_checksum('BoxSet'))
except ValueError: except ValueError:
all_kodisets = {} all_kodisets = {}
@ -1088,7 +1088,7 @@ class ManualSync(LibrarySync):
all_embymoviesIds.add(itemid) all_embymoviesIds.add(itemid)
if all_kodimovies.get(itemid) != API.getChecksum(): if all_kodimovies.get(itemid) != API.get_checksum():
# Only update if movie is not in Kodi or checksum is different # Only update if movie is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
@ -1179,7 +1179,7 @@ class ManualSync(LibrarySync):
# Pull the list of musicvideos in Kodi # Pull the list of musicvideos in Kodi
try: try:
all_kodimvideos = dict(emby_db.getChecksum('MusicVideo')) all_kodimvideos = dict(emby_db.get_checksum('MusicVideo'))
except ValueError: except ValueError:
all_kodimvideos = {} all_kodimvideos = {}
@ -1211,7 +1211,7 @@ class ManualSync(LibrarySync):
all_embymvideosIds.add(itemid) all_embymvideosIds.add(itemid)
if all_kodimvideos.get(itemid) != API.getChecksum(): if all_kodimvideos.get(itemid) != API.get_checksum():
# Only update if musicvideo is not in Kodi or checksum is different # Only update if musicvideo is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
@ -1258,12 +1258,12 @@ class ManualSync(LibrarySync):
# Pull the list of tvshows and episodes in Kodi # Pull the list of tvshows and episodes in Kodi
try: try:
all_koditvshows = dict(emby_db.getChecksum('Series')) all_koditvshows = dict(emby_db.get_checksum('Series'))
except ValueError: except ValueError:
all_koditvshows = {} all_koditvshows = {}
try: try:
all_kodiepisodes = dict(emby_db.getChecksum('Episode')) all_kodiepisodes = dict(emby_db.get_checksum('Episode'))
except ValueError: except ValueError:
all_kodiepisodes = {} all_kodiepisodes = {}
@ -1297,7 +1297,7 @@ class ManualSync(LibrarySync):
all_embytvshowsIds.add(itemid) all_embytvshowsIds.add(itemid)
if all_koditvshows.get(itemid) != API.getChecksum(): if all_koditvshows.get(itemid) != API.get_checksum():
# Only update if movie is not in Kodi or checksum is different # Only update if movie is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
@ -1341,7 +1341,7 @@ class ManualSync(LibrarySync):
itemid = embyepisode['Id'] itemid = embyepisode['Id']
all_embyepisodesIds.add(itemid) all_embyepisodesIds.add(itemid)
if all_kodiepisodes.get(itemid) != API.getChecksum(): if all_kodiepisodes.get(itemid) != API.get_checksum():
# Only update if movie is not in Kodi or checksum is different # Only update if movie is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
@ -1388,17 +1388,17 @@ class ManualSync(LibrarySync):
# Pull the list of artists, albums, songs # Pull the list of artists, albums, songs
try: try:
all_kodiartists = dict(emby_db.getChecksum('MusicArtist')) all_kodiartists = dict(emby_db.get_checksum('MusicArtist'))
except ValueError: except ValueError:
all_kodiartists = {} all_kodiartists = {}
try: try:
all_kodialbums = dict(emby_db.getChecksum('MusicAlbum')) all_kodialbums = dict(emby_db.get_checksum('MusicAlbum'))
except ValueError: except ValueError:
all_kodialbums = {} all_kodialbums = {}
try: try:
all_kodisongs = dict(emby_db.getChecksum('Audio')) all_kodisongs = dict(emby_db.get_checksum('Audio'))
except ValueError: except ValueError:
all_kodisongs = {} all_kodisongs = {}
@ -1429,17 +1429,17 @@ class ManualSync(LibrarySync):
itemid = embyitem['Id'] itemid = embyitem['Id']
if data_type == "artists": if data_type == "artists":
all_embyartistsIds.add(itemid) all_embyartistsIds.add(itemid)
if all_kodiartists.get(itemid) != API.getChecksum(): if all_kodiartists.get(itemid) != API.get_checksum():
# Only update if artist is not in Kodi or checksum is different # Only update if artist is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
elif data_type == "albums": elif data_type == "albums":
all_embyalbumsIds.add(itemid) all_embyalbumsIds.add(itemid)
if all_kodialbums.get(itemid) != API.getChecksum(): if all_kodialbums.get(itemid) != API.get_checksum():
# Only update if album is not in Kodi or checksum is different # Only update if album is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
else: else:
all_embysongsIds.add(itemid) all_embysongsIds.add(itemid)
if all_kodisongs.get(itemid) != API.getChecksum(): if all_kodisongs.get(itemid) != API.get_checksum():
# Only update if songs is not in Kodi or checksum is different # Only update if songs is not in Kodi or checksum is different
updatelist.append(itemid) updatelist.append(itemid)
log.info("%s to update: %s" % (data_type, updatelist)) log.info("%s to update: %s" % (data_type, updatelist))

View file

@ -74,7 +74,7 @@ def getAdditionalSongTags(embyid, emby_rating, API, kodicursor, emby_db, enablei
emby = embyserver.Read_EmbyServer() emby = embyserver.Read_EmbyServer()
previous_values = None previous_values = None
filename = API.getFilePath() filename = API.get_file_path()
rating = 0 rating = 0
emby_rating = int(round(emby_rating, 0)) emby_rating = int(round(emby_rating, 0))

View file

@ -82,8 +82,8 @@ class PlaybackUtils():
############### RESUME POINT ################ ############### RESUME POINT ################
userdata = self.API.getUserData() userdata = self.API.get_userdata()
seektime = self.API.adjustResume(userdata['Resume']) seektime = self.API.adjust_resume(userdata['Resume'])
# We need to ensure we add the intro and additional parts only once. # We need to ensure we add the intro and additional parts only once.
# Otherwise we get a loop. # Otherwise we get a loop.
@ -309,7 +309,7 @@ class PlaybackUtils():
def setArtwork(self, listItem): def setArtwork(self, listItem):
# Set up item and item info # Set up item and item info
allartwork = self.artwork.getAllArtwork(self.item, parentInfo=True) allartwork = self.artwork.get_all_artwork(self.item, parent_info=True)
# Set artwork for listitem # Set artwork for listitem
arttypes = { arttypes = {
@ -346,20 +346,20 @@ class PlaybackUtils():
def setListItem(self, listItem): def setListItem(self, listItem):
people = self.API.getPeople() people = self.API.get_people()
studios = self.API.getStudios() studios = self.API.get_studios()
metadata = { metadata = {
'title': self.item.get('Name', "Missing name"), 'title': self.item.get('Name', "Missing name"),
'year': self.item.get('ProductionYear'), 'year': self.item.get('ProductionYear'),
'plot': self.API.getOverview(), 'plot': self.API.get_overview(),
'director': people.get('Director'), 'director': people.get('Director'),
'writer': people.get('Writer'), 'writer': people.get('Writer'),
'mpaa': self.API.getMpaa(), 'mpaa': self.API.get_mpaa(),
'genre': " / ".join(self.item['Genres']), 'genre': " / ".join(self.item['Genres']),
'studio': " / ".join(studios), 'studio': " / ".join(studios),
'aired': self.API.getPremiereDate(), 'aired': self.API.get_premiere_date(),
'rating': self.item.get('CommunityRating'), 'rating': self.item.get('CommunityRating'),
'votes': self.item.get('VoteCount') 'votes': self.item.get('VoteCount')
} }

View file

@ -147,7 +147,7 @@ class UserClient(threading.Thread):
settings('username', value=self._user['Name']) settings('username', value=self._user['Name'])
if "PrimaryImageTag" in self._user: if "PrimaryImageTag" in self._user:
window('EmbyUserImage', window('EmbyUserImage',
value=artwork.Artwork().getUserArtwork(self._user['Id'], 'Primary')) value=artwork.Artwork().get_user_artwork(self._user['Id'], 'Primary'))
self._server = self.download("{server}/emby/System/Configuration?format=json") self._server = self.download("{server}/emby/System/Configuration?format=json")
settings('markPlayed', value=str(self._server['MaxResumePct'])) settings('markPlayed', value=str(self._server['MaxResumePct']))