def movies(self, embycursor, kodicursor, pdialog): # Get movies from emby emby_db = embydb.Embydb_Functions(embycursor) movies = Movies(embycursor, kodicursor, pdialog) views = emby_db.getView_byType('movies') views += emby_db.getView_byType('mixed') log.info("Media folders: %s" % views) ##### PROCESS MOVIES ##### for view in views: log.info("Processing: %s", view) view_name = view['name'] # Get items per view if pdialog: pdialog.update(heading=lang(29999), message="%s %s..." % (lang(33017), view_name)) all_movies = self.emby.getMovies(view['id'], dialog=pdialog) movies.add_all("Movie", all_movies, view) log.debug("Movies finished.") ##### PROCESS BOXSETS ##### if pdialog: pdialog.update(heading=lang(29999), message=lang(33018)) boxsets = self.emby.getBoxset(dialog=pdialog) movies.add_all("BoxSet", boxsets) log.debug("Boxsets finished.") return True
def modify_playlist(self, item_ids): conn = kodiSQL('emby') cursor = conn.cursor() emby_db = embydb.Embydb_Functions(cursor) log.info("---*** ADD TO PLAYLIST ***---") log.info("Items: %s", item_ids) playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) for item_id in item_ids: log.info("Adding %s to playlist", item_id) item = emby_db.getItem_byId(item_id) try: db_id = item[0] media_type = item[4] except TypeError: # Item is not found in our database, add item manually item = self.emby.getItem(item_id) self.add_to_xbmc_playlist(playlist, item) else: # Add to playlist self.add_to_playlist(db_id, media_type) self.verify_playlist() cursor.close() return playlist
def modifyPlaylist(self, itemids): log = self.logMsg embyconn = utils.kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) log("---*** ADD TO PLAYLIST ***---", 1) log("Items: %s" % itemids, 1) # player = xbmc.Player() playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) for itemid in itemids: embydb_item = emby_db.getItem_byId(itemid) try: dbid = embydb_item[0] mediatype = embydb_item[4] except TypeError: # Item is not found in our database, add item manually item = self.emby.getItem(itemid) self.addtoPlaylist_xbmc(playlist, item) else: # Add to playlist self.addtoPlaylist(dbid, mediatype) log("Adding %s to playlist." % itemid, 1) self.verifyPlaylist() embycursor.close() return playlist
def tvshows(self, embycursor, kodicursor, pdialog): # Get shows from emby emby_db = embydb.Embydb_Functions(embycursor) tvshows = TVShows(embycursor, kodicursor, pdialog) views = emby_db.getView_byType('tvshows') views += emby_db.getView_byType('mixed') log.info("Media folders: %s" % views) for view in views: # Get items per view if pdialog: pdialog.update( heading=lang(29999), message="%s %s..." % (lang(33020), view['name'])) all_tvshows = self.emby.getShows(view['id'], dialog=pdialog) tvshows.add_all("Series", all_tvshows, view) else: log.debug("TVShows finished.") return True
def musicvideos(self, embycursor, kodicursor, pdialog): # Get musicvideos from emby emby_db = embydb.Embydb_Functions(embycursor) mvideos = MusicVideos(embycursor, kodicursor, pdialog) views = emby_db.getView_byType('musicvideos') log.info("Media folders: %s" % views) for view in views: log.info("Processing: %s", view) # Get items per view viewId = view['id'] viewName = view['name'] if pdialog: pdialog.update( heading=lang(29999), message="%s %s..." % (lang(33019), viewName)) # Initial or repair sync all_mvideos = self.emby.getMusicVideos(viewId, dialog=pdialog) mvideos.add_all("MusicVideo", all_mvideos, view) else: log.debug("MusicVideos finished.") return True
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_movies.KodiMovies(self.kodicursor) self.pdialog = pdialog self.new_time = int(settings('newvideotime')) * 1000 Items.__init__(self)
def _get_item_id(cls, kodi_id, item_type): item_id = None with DatabaseConn('emby') as cursor: emby_db = embydb.Embydb_Functions(cursor) db_item = emby_db.getItem_byKodiId(kodi_id, item_type) try: item_id = db_item[0] except TypeError: log.info("Could not retrieve item Id") return item_id
def playAll(self, itemids, startat): log = self.logMsg window = utils.window embyconn = utils.kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) player = xbmc.Player() playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) playlist.clear() log("---*** PLAY ALL ***---", 1) log("Items: %s and start at: %s" % (itemids, startat), 1) started = False window('emby_customplaylist', value="true") if startat != 0: # Seek to the starting position window('emby_customplaylist.seektime', str(startat)) with embydb.GetEmbyDB() as emby_db: for itemid in itemids: embydb_item = emby_db.getItem_byId(itemid) try: dbid = embydb_item[0] mediatype = embydb_item[4] except TypeError: # Item is not found in our database, add item manually log( "Item was not found in the database, manually adding item.", 1) item = PlexFunctions.GetPlexMetadata(itemid) if item is None or item == 401: log('Could not download itemid %s' % itemid, -1) else: self.addtoPlaylist_xbmc(playlist, item) else: # Add to playlist self.addtoPlaylist(dbid, mediatype) log("Adding %s to playlist." % itemid, 1) if not started: started = True player.play(playlist) self.verifyPlaylist()
def __init__(self, emby_cursor, kodi_cursor): self.emby_cursor = emby_cursor self.kodi_cursor = kodi_cursor self.total_nodes = 0 self.nodes = list() self.playlists = list() self.views = list() self.sorted_views = list() self.grouped_views = list() self.video_nodes = VideoNodes() self.playlist = Playlist() self.emby = embyserver.Read_EmbyServer() self.emby_db = embydb.Embydb_Functions(emby_cursor)
def _get_item_id(cls, kodi_id, item_type): item_id = xbmc.getInfoLabel('ListItem.Property(embyid)') if not item_id and kodi_id and item_type: with DatabaseConn('emby') as cursor: emby_db = embydb.Embydb_Functions(cursor) item = emby_db.getItem_byKodiId(kodi_id, item_type) try: item_id = item[0] except TypeError: pass return item_id
def deleteItem(): # Serves as a keymap action if xbmc.getInfoLabel('ListItem.Property(embyid)'): # If we already have the embyid embyid = xbmc.getInfoLabel('ListItem.Property(embyid)') else: dbid = xbmc.getInfoLabel('ListItem.DBID') itemtype = xbmc.getInfoLabel('ListItem.DBTYPE') if not itemtype: if xbmc.getCondVisibility('Container.Content(albums)'): itemtype = "album" elif xbmc.getCondVisibility('Container.Content(artists)'): itemtype = "artist" elif xbmc.getCondVisibility('Container.Content(songs)'): itemtype = "song" elif xbmc.getCondVisibility('Container.Content(pictures)'): itemtype = "picture" else: utils.logMsg("EMBY delete", "Unknown type, unable to proceed.", 1) return embyconn = utils.kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) item = emby_db.getItem_byKodiId(dbid, itemtype) embycursor.close() try: embyid = item[0] except TypeError: utils.logMsg("EMBY delete", "Unknown embyId, unable to proceed.", 1) return if utils.settings('skipContextMenu') != "true": resp = xbmcgui.Dialog().yesno( heading="Confirm delete", line1=("Delete file from Emby Server? This will " "also delete the file(s) from disk!")) if not resp: utils.logMsg("EMBY delete", "User skipped deletion for: %s." % embyid, 1) return doUtils = downloadutils.DownloadUtils() url = "{server}/emby/Items/%s?format=json" % embyid utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0) doUtils.downloadUrl(url, type="DELETE")
def _get_item_id(cls, kodi_id, item_type): item_id = None 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
def _get_item_id(cls, kodi_id, item_type): item_id = xbmc.getInfoLabel('ListItem.Property(embyid)') if not item_id and kodi_id and item_type: conn = kodiSQL('emby') cursor = conn.cursor() emby_db = embydb.Embydb_Functions(cursor) item = emby_db.getItem_byKodiId(kodi_id, item_type) cursor.close() try: item_id = item[0] except TypeError: pass return item_id
def playAll(self, itemids, startat): embyconn = kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) player = xbmc.Player() playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) playlist.clear() log("---*** PLAY ALL ***---", 1) log("Items: %s and start at: %s" % (itemids, startat), 1) started = False window('emby_customplaylist', value="true") if startat != 0: # Seek to the starting position window('emby_customplaylist.seektime', str(startat)) for itemid in itemids: embydb_item = emby_db.getItem_byId(itemid) try: dbid = embydb_item[0] mediatype = embydb_item[4] except TypeError: # Item is not found in our database, add item manually log( "Item was not found in the database, manually adding item.", 1) item = self.emby.getItem(itemid) self.addtoPlaylist_xbmc(playlist, item) else: # Add to playlist self.addtoPlaylist(dbid, mediatype) log("Adding %s to playlist." % itemid, 1) if not started: started = True player.play(playlist) self.verifyPlaylist() embycursor.close()
def play_all(self, item_ids, start_at): conn = kodiSQL('emby') cursor = conn.cursor() emby_db = embydb.Embydb_Functions(cursor) player = xbmc.Player() playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO) playlist.clear() log.info("---*** PLAY ALL ***---") log.info("Items: %s and start at: %s", item_ids, start_at) started = False window('emby_customplaylist', value="true") if start_at: # Seek to the starting position window('emby_customplaylist.seektime', str(start_at)) for item_id in item_ids: log.info("Adding %s to playlist", item_id) item = emby_db.getItem_byId(item_id) try: db_id = item[0] media_type = item[4] except TypeError: # Item is not found in our database, add item manually log.info( "Item was not found in the database, manually adding item") item = self.emby.getItem(item_id) self.add_to_xbmc_playlist(playlist, item) else: # Add to playlist self.add_to_playlist(db_id, media_type) if not started: started = True player.play(playlist) self.verify_playlist() cursor.close()
def deleteItem(): # Serves as a keymap action if xbmc.getInfoLabel( 'ListItem.Property(embyid)'): # If we already have the embyid itemId = xbmc.getInfoLabel('ListItem.Property(embyid)') else: dbId = xbmc.getInfoLabel('ListItem.DBID') itemType = xbmc.getInfoLabel('ListItem.DBTYPE') if not itemType: if xbmc.getCondVisibility('Container.Content(albums)'): itemType = "album" elif xbmc.getCondVisibility('Container.Content(artists)'): itemType = "artist" elif xbmc.getCondVisibility('Container.Content(songs)'): itemType = "song" elif xbmc.getCondVisibility('Container.Content(pictures)'): itemType = "picture" else: log("Unknown type, unable to proceed.", 1) return embyconn = utils.kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) item = emby_db.getItem_byKodiId(dbId, itemType) embycursor.close() try: embyid = item[0] except TypeError: log("Unknown embyId, unable to proceed.", 1) return if settings('skipContextMenu') != "true": resp = xbmcgui.Dialog().yesno(heading=lang(29999), line1=lang(33041)) if not resp: log("User skipped deletion for: %s." % itemId, 1) return embyserver.Read_EmbyServer().deleteItem(itemId)
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_music.KodiMusic(self.kodicursor) self.pdialog = pdialog self.new_time = int(settings('newmusictime')) * 1000 self.directstream = settings('streamMusic') == "true" self.enableimportsongrating = settings( 'enableImportSongRating') == "true" self.enableexportsongrating = settings( 'enableExportSongRating') == "true" self.enableupdatesongrating = settings( 'enableUpdateSongRating') == "true" self.userid = window('emby_currUser') self.server = window('emby_server%s' % self.userid) Items.__init__(self)
def music(self, embycursor, kodicursor, pdialog): # Get music from emby emby_db = embydb.Embydb_Functions(embycursor) music = Music(embycursor, kodicursor, pdialog) views = emby_db.getView_byType('music') log.info("Media folders: %s", views) # Add music artists and everything will fall into place if pdialog: pdialog.update(heading=lang(29999), message="%s Music..." % lang(33021)) for view in views: all_artists = self.emby.getArtists(view['id'], dialog=pdialog) music.add_all("MusicArtist", all_artists) log.debug("Finished syncing music") return True
def incrementalSync(self): update_embydb = False pDialog = None # do a view update if needed if self.refresh_views: self.refreshViews() self.refresh_views = False self.forceLibraryUpdate = True # do a lib update if any items in list totalUpdates = len(self.addedItems) + len(self.updateItems) + len(self.userdataItems) + len(self.removeItems) if totalUpdates > 0: with database.DatabaseConn('emby') as cursor_emby: with database.DatabaseConn('video') as cursor_video: emby_db = embydb.Embydb_Functions(cursor_emby) incSyncIndicator = int(settings('incSyncIndicator') or 10) if incSyncIndicator != -1 and totalUpdates > incSyncIndicator: # Only present dialog if we are going to process items pDialog = self.progressDialog('Incremental sync') log.info("incSyncIndicator=" + str(incSyncIndicator) + " totalUpdates=" + str(totalUpdates)) process = { 'added': self.addedItems, 'update': self.updateItems, 'userdata': self.userdataItems, 'remove': self.removeItems } for process_type in ['added', 'update', 'userdata', 'remove']: if process[process_type] and window('emby_kodiScan') != "true": listItems = list(process[process_type]) del process[process_type][:] # Reset class list items_process = itemtypes.Items(cursor_emby, cursor_video) update = False # Prepare items according to process process_type if process_type == "added": items = self.emby.sortby_mediatype(listItems) elif process_type in ("userdata", "remove"): items = emby_db.sortby_mediaType(listItems, unsorted=False) else: items = emby_db.sortby_mediaType(listItems) if items.get('Unsorted'): sorted_items = self.emby.sortby_mediatype(items['Unsorted']) doupdate = items_process.itemsbyId(sorted_items, "added", pDialog) if doupdate: embyupdate, kodiupdate_video = doupdate if embyupdate: update_embydb = True if kodiupdate_video: self.forceLibraryUpdate = True del items['Unsorted'] doupdate = items_process.itemsbyId(items, process_type, pDialog) if doupdate: embyupdate, kodiupdate_video = doupdate if embyupdate: update_embydb = True if kodiupdate_video: self.forceLibraryUpdate = True # if stuff happened then do some stuff if update_embydb: update_embydb = False log.info("Updating emby database.") self.saveLastSync() if self.forceLibraryUpdate: # Force update the Kodi library self.forceLibraryUpdate = False log.info("Updating video library.") window('emby_kodiScan', value="true") xbmc.executebuiltin('UpdateLibrary(video)') if pDialog: pDialog.close()
def run_internal(self): dialog = xbmcgui.Dialog() startupComplete = False log.warn("---===### Starting LibrarySync ###===---") while not self.monitor.abortRequested(): # In the event the server goes offline while self.suspend_thread: # Set in service.py if self.monitor.waitForAbort(5): # Abort was requested while waiting. We should exit break if (window('emby_dbCheck') != "true" and settings('SyncInstallRunDone') == "true"): # Verify the validity of the database log.info("Doing DB Version Check") with database.DatabaseConn('emby') as cursor: emby_db = embydb.Embydb_Functions(cursor) currentVersion = emby_db.get_version() ###$ Begin migration $### if not currentVersion: currentVersion = emby_db.get_version(settings('dbCreatedWithVersion') or self.clientInfo.get_version()) log.info("Migration of database version completed") ###$ End migration $### window('emby_version', value=currentVersion) minVersion = window('emby_minDBVersion') uptoDate = self.compareDBVersion(currentVersion, minVersion) if not uptoDate: log.warn("Database version out of date: %s minimum version required: %s" % (currentVersion, minVersion)) resp = dialog.yesno(lang(29999), lang(33022)) if not resp: log.warn("Database version is out of date! USER IGNORED!") dialog.ok(lang(29999), lang(33023)) else: database.db_reset() break window('emby_dbCheck', value="true") if not startupComplete: # Verify the video database can be found videoDb = database.video_database() if not xbmcvfs.exists(videoDb): # Database does not exists log.error( "The current Kodi version is incompatible " "with the Emby for Kodi add-on. Please visit " "https://github.com/MediaBrowser/Emby.Kodi/wiki " "to know which Kodi versions are supported.") dialog.ok( heading=lang(29999), line1=lang(33024)) break # Run start up sync log.warn("Database version: %s", window('emby_version')) log.info("SyncDatabase (started)") startTime = datetime.now() librarySync = self.startSync() elapsedTime = datetime.now() - startTime log.info("SyncDatabase (finished in: %s) %s" % (str(elapsedTime).split('.')[0], librarySync)) # Add other servers at this point # TODO: re-add once plugin listing is created # self.user.load_connect_servers() # Only try the initial sync once per kodi session regardless # This will prevent an infinite loop in case something goes wrong. startupComplete = True # Process updates if window('emby_dbScan') != "true" and window('emby_shouldStop') != "true": self.incrementalSync() if window('emby_onWake') == "true" and window('emby_online') == "true": # Kodi is waking up # Set in kodimonitor.py window('emby_onWake', clear=True) if window('emby_syncRunning') != "true": log.info("SyncDatabase onWake (started)") librarySync = self.startSync() log.info("SyncDatabase onWake (finished) %s" % librarySync) if self.stop_thread: # Set in service.py log.debug("Service terminated thread.") break if self.monitor.waitForAbort(1): # Abort was requested while waiting. We should exit break log.warn("###===--- LibrarySync Stopped ---===###")
if not itemtype and xbmc.getCondVisibility("Container.Content(albums)"): itemtype = "album" if not itemtype and xbmc.getCondVisibility("Container.Content(artists)"): itemtype = "artist" if not itemtype and xbmc.getCondVisibility("Container.Content(songs)"): itemtype = "song" if not itemtype and xbmc.getCondVisibility("Container.Content(pictures)"): itemtype = "picture" if (not itemid or itemid == "-1") and xbmc.getInfoLabel("ListItem.Property(embyid)"): embyid = xbmc.getInfoLabel("ListItem.Property(embyid)") else: embyconn = utils.kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) item = emby_db.getItem_byKodiId(itemid, itemtype) embycursor.close() if item: embyid = item[0] logMsg("Contextmenu opened for embyid: %s - itemtype: %s" % (embyid, itemtype)) if embyid: item = emby.getItem(embyid) API = api.API(item) userdata = API.getUserData() likes = userdata['Likes'] favourite = userdata['Favorite'] options = []
def getThemeMedia(): doUtils = downloadutils.DownloadUtils() dialog = xbmcgui.Dialog() playback = None # Choose playback method resp = dialog.select("Playback method for your themes", ["Direct Play", "Direct Stream"]) if resp == 0: playback = "DirectPlay" elif resp == 1: playback = "DirectStream" else: return library = xbmc.translatePath( "special://profile/addon_data/plugin.video.emby/library/").decode('utf-8') # Create library directory if not xbmcvfs.exists(library): xbmcvfs.mkdir(library) # Set custom path for user tvtunes_path = xbmc.translatePath( "special://profile/addon_data/script.tvtunes/").decode('utf-8') if xbmcvfs.exists(tvtunes_path): tvtunes = xbmcaddon.Addon(id="script.tvtunes") tvtunes.setSetting('custom_path_enable', "true") tvtunes.setSetting('custom_path', library) utils.logMsg("EMBY", "TV Tunes custom path is enabled and set.", 1) else: # if it does not exist this will not work so warn user # often they need to edit the settings first for it to be created. dialog.ok( heading="Warning", line1=( "The settings file does not exist in tvtunes. ", "Go to the tvtunes addon and change a setting, then come back and re-run.")) xbmc.executebuiltin('Addon.OpenSettings(script.tvtunes)') return # Get every user view Id embyconn = utils.kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) viewids = emby_db.getViews() embycursor.close() # Get Ids with Theme Videos itemIds = {} for view in viewids: url = "{server}/emby/Users/{UserId}/Items?HasThemeVideo=True&ParentId=%s&format=json" % view result = doUtils.downloadUrl(url) if result['TotalRecordCount'] != 0: for item in result['Items']: itemId = item['Id'] folderName = item['Name'] folderName = utils.normalize_string(folderName.encode('utf-8')) itemIds[itemId] = folderName # Get paths for theme videos for itemId in itemIds: nfo_path = xbmc.translatePath( "special://profile/addon_data/plugin.video.emby/library/%s/" % itemIds[itemId]) # Create folders for each content if not xbmcvfs.exists(nfo_path): xbmcvfs.mkdir(nfo_path) # Where to put the nfos nfo_path = "%s%s" % (nfo_path, "tvtunes.nfo") url = "{server}/emby/Items/%s/ThemeVideos?format=json" % itemId result = doUtils.downloadUrl(url) # Create nfo and write themes to it nfo_file = xbmcvfs.File(nfo_path, 'w') pathstowrite = "" # May be more than one theme for theme in result['Items']: putils = playutils.PlayUtils(theme) if playback == "DirectPlay": playurl = putils.directPlay() else: playurl = putils.directStream() pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8')) # Check if the item has theme songs and add them url = "{server}/emby/Items/%s/ThemeSongs?format=json" % itemId result = doUtils.downloadUrl(url) # May be more than one theme for theme in result['Items']: putils = playutils.PlayUtils(theme) if playback == "DirectPlay": playurl = putils.directPlay() else: playurl = putils.directStream() pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8')) nfo_file.write( '<tvtunes>%s</tvtunes>' % pathstowrite ) # Close nfo file nfo_file.close() # Get Ids with Theme songs musicitemIds = {} for view in viewids: url = "{server}/emby/Users/{UserId}/Items?HasThemeSong=True&ParentId=%s&format=json" % view result = doUtils.downloadUrl(url) if result['TotalRecordCount'] != 0: for item in result['Items']: itemId = item['Id'] folderName = item['Name'] folderName = utils.normalize_string(folderName.encode('utf-8')) musicitemIds[itemId] = folderName # Get paths for itemId in musicitemIds: # if the item was already processed with video themes back out if itemId in itemIds: continue nfo_path = xbmc.translatePath( "special://profile/addon_data/plugin.video.emby/library/%s/" % musicitemIds[itemId]) # Create folders for each content if not xbmcvfs.exists(nfo_path): xbmcvfs.mkdir(nfo_path) # Where to put the nfos nfo_path = "%s%s" % (nfo_path, "tvtunes.nfo") url = "{server}/emby/Items/%s/ThemeSongs?format=json" % itemId result = doUtils.downloadUrl(url) # Create nfo and write themes to it nfo_file = xbmcvfs.File(nfo_path, 'w') pathstowrite = "" # May be more than one theme for theme in result['Items']: putils = playutils.PlayUtils(theme) if playback == "DirectPlay": playurl = putils.directPlay() else: playurl = putils.directStream() pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8')) nfo_file.write( '<tvtunes>%s</tvtunes>' % pathstowrite ) # Close nfo file nfo_file.close() dialog.notification( heading="Emby for Kodi", message="Themes added!", icon="special://home/addons/plugin.video.emby/icon.png", time=1000, sound=False)
def incrementalSync(self): embyconn = utils.kodiSQL('emby') embycursor = embyconn.cursor() kodiconn = utils.kodiSQL('video') kodicursor = kodiconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) pDialog = None update_embydb = False if self.refresh_views: # Received userconfig update self.refresh_views = False self.maintainViews(embycursor, kodicursor) self.forceLibraryUpdate = True update_embydb = True incSyncIndicator = int(settings('incSyncIndicator') or 10) totalUpdates = len(self.addedItems) + len(self.updateItems) + len( self.userdataItems) + len(self.removeItems) if incSyncIndicator != -1 and totalUpdates > incSyncIndicator: # Only present dialog if we are going to process items pDialog = self.progressDialog('Incremental sync') log.info("incSyncIndicator=" + str(incSyncIndicator) + " totalUpdates=" + str(totalUpdates)) process = { 'added': self.addedItems, 'update': self.updateItems, 'userdata': self.userdataItems, 'remove': self.removeItems } for process_type in ['added', 'update', 'userdata', 'remove']: if process[process_type] and window('emby_kodiScan') != "true": listItems = list(process[process_type]) del process[process_type][:] # Reset class list items_process = itemtypes.Items(embycursor, kodicursor) update = False # Prepare items according to process process_type if process_type == "added": items = self.emby.sortby_mediatype(listItems) elif process_type in ("userdata", "remove"): items = emby_db.sortby_mediaType(listItems, unsorted=False) else: items = emby_db.sortby_mediaType(listItems) if items.get('Unsorted'): sorted_items = self.emby.sortby_mediatype( items['Unsorted']) doupdate = items_process.itemsbyId( sorted_items, "added", pDialog) if doupdate: embyupdate, kodiupdate_video = doupdate if embyupdate: update_embydb = True if kodiupdate_video: self.forceLibraryUpdate = True del items['Unsorted'] doupdate = items_process.itemsbyId(items, process_type, pDialog) if doupdate: embyupdate, kodiupdate_video = doupdate if embyupdate: update_embydb = True if kodiupdate_video: self.forceLibraryUpdate = True if update_embydb: update_embydb = False log.info("Updating emby database.") embyconn.commit() self.saveLastSync() if self.forceLibraryUpdate: # Force update the Kodi library self.forceLibraryUpdate = False self.dbCommit(kodiconn) log.info("Updating video library.") window('emby_kodiScan', value="true") xbmc.executebuiltin('UpdateLibrary(video)') if pDialog: pDialog.close() kodicursor.close() embycursor.close()
def onNotification(self, sender, method, data): doUtils = self.doUtils if method not in ("Playlist.OnAdd"): log("Method: %s Data: %s" % (method, data), 1) if data: data = json.loads(data, 'utf-8') if method == "Player.OnPlay": # Set up report progress for emby playback item = data.get('item') try: kodiid = item['id'] item_type = item['type'] except (KeyError, TypeError): log("Item is invalid for playstate update.", 1) else: if ((settings('useDirectPaths') == "1" and not item_type == "song") or (item_type == "song" and settings('enableMusic') == "true")): # Set up properties for player embyconn = kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type) try: itemid = emby_dbitem[0] except TypeError: log("No kodiId returned.", 1) else: url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid result = doUtils.downloadUrl(url) log("Item: %s" % result, 2) playurl = None count = 0 while not playurl and count < 2: try: playurl = xbmc.Player().getPlayingFile() except RuntimeError: count += 1 xbmc.sleep(200) else: listItem = xbmcgui.ListItem() playback = pbutils.PlaybackUtils(result) if item_type == "song" and settings( 'streamMusic') == "true": window('emby_%s.playmethod' % playurl, value="DirectStream") else: window('emby_%s.playmethod' % playurl, value="DirectPlay") # Set properties for player.py playback.setProperties(playurl, listItem) finally: embycursor.close() elif method == "VideoLibrary.OnUpdate": # Manually marking as watched/unwatched playcount = data.get('playcount') item = data.get('item') try: kodiid = item['id'] item_type = item['type'] except (KeyError, TypeError): log("Item is invalid for playstate update.", 1) else: # Send notification to the server. embyconn = kodiSQL('emby') embycursor = embyconn.cursor() emby_db = embydb.Embydb_Functions(embycursor) emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type) try: itemid = emby_dbitem[0] except TypeError: log("Could not find itemid in emby database.", 1) else: # Stop from manually marking as watched unwatched, with actual playback. if window('emby_skipWatched%s' % itemid) == "true": # property is set in player.py window('emby_skipWatched%s' % itemid, clear=True) else: # notify the server url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid if playcount != 0: doUtils.downloadUrl(url, action_type="POST") log("Mark as watched for itemid: %s" % itemid, 1) else: doUtils.downloadUrl(url, action_type="DELETE") log("Mark as unwatched for itemid: %s" % itemid, 1) finally: embycursor.close() elif method == "VideoLibrary.OnRemove": # 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.OnWake": # Allow network to wake up xbmc.sleep(10000) window('emby_onWake', value="true") elif method == "GUI.OnScreensaverDeactivated": if settings('dbSyncScreensaver') == "true": xbmc.sleep(5000) window('emby_onWake', value="true") elif method == "Playlist.OnClear": pass
def fullSync(self, manualrun=False, repair=False): # Only run once when first setting up. Can be run manually. music_enabled = settings('enableMusic') == "true" xbmc.executebuiltin('InhibitIdleShutdown(true)') screensaver = utils.getScreensaver() utils.setScreensaver(value="") window('emby_dbScan', value="true") # Add sources utils.sourcesXML() # use emby and video DBs with database.DatabaseConn('emby') as cursor_emby: with database.DatabaseConn('video') as cursor_video: # content sync: movies, tvshows, musicvideos, music if manualrun: message = "Manual sync" elif repair: message = "Repair sync" repair_list = [] choices = ['all', 'movies', 'musicvideos', 'tvshows'] if music_enabled: choices.append('music') if self.kodi_version > 15: # Jarvis or higher types = xbmcgui.Dialog().multiselect(lang(33094), choices) if types is None: pass elif 0 in types: # all choices.pop(0) repair_list.extend(choices) else: for index in types: repair_list.append(choices[index]) else: resp = xbmcgui.Dialog().select(lang(33094), choices) if resp == 0: # all choices.pop(resp) repair_list.extend(choices) else: repair_list.append(choices[resp]) log.info("Repair queued for: %s", repair_list) else: message = "Initial sync" window('emby_initialScan', value="true") pDialog = self.progressDialog("%s" % message) starttotal = datetime.now() # Set views views.Views(cursor_emby, cursor_video).maintain() cursor_emby.connection.commit() #self.maintainViews(cursor_emby, cursor_video) # Sync video library process = { 'movies': self.movies, 'musicvideos': self.musicvideos, 'tvshows': self.tvshows } for itemtype in process: if repair and itemtype not in repair_list: continue startTime = datetime.now() completed = process[itemtype](cursor_emby, cursor_video, pDialog) if not completed: xbmc.executebuiltin('InhibitIdleShutdown(false)') utils.setScreensaver(value=screensaver) window('emby_dbScan', clear=True) if pDialog: pDialog.close() return False else: elapsedTime = datetime.now() - startTime log.info("SyncDatabase (finished %s in: %s)" % (itemtype, str(elapsedTime).split('.')[0])) # sync music # use emby and music if music_enabled: if repair and 'music' not in repair_list: pass else: with database.DatabaseConn('emby') as cursor_emby: with database.DatabaseConn('music') as cursor_music: startTime = datetime.now() completed = self.music(cursor_emby, cursor_music, pDialog) if not completed: xbmc.executebuiltin('InhibitIdleShutdown(false)') utils.setScreensaver(value=screensaver) window('emby_dbScan', clear=True) if pDialog: pDialog.close() return False else: elapsedTime = datetime.now() - startTime log.info("SyncDatabase (finished music in: %s)" % (str(elapsedTime).split('.')[0])) if pDialog: pDialog.close() with database.DatabaseConn('emby') as cursor_emby: emby_db = embydb.Embydb_Functions(cursor_emby) current_version = emby_db.get_version(self.clientInfo.get_version()) window('emby_version', current_version) settings('SyncInstallRunDone', value="true") self.saveLastSync() xbmc.executebuiltin('UpdateLibrary(video)') elapsedtotal = datetime.now() - starttotal xbmc.executebuiltin('InhibitIdleShutdown(false)') utils.setScreensaver(value=screensaver) window('emby_dbScan', clear=True) window('emby_initialScan', clear=True) xbmcgui.Dialog().notification( heading=lang(29999), message="%s %s %s" % (message, lang(33025), str(elapsedtotal).split('.')[0]), icon="special://home/addons/plugin.video.emby/icon.png", sound=False) return True
def getThemeMedia(): doUtils = downloadutils.DownloadUtils() dialog = xbmcgui.Dialog() playback = None # Choose playback method resp = dialog.select(lang(33072), [lang(30165), lang(33071)]) if resp == 0: playback = "DirectPlay" elif resp == 1: playback = "DirectStream" else: return library = xbmc.translatePath( "special://profile/addon_data/emby.for.kodi/library/").decode('utf-8') # Create library directory if not xbmcvfs.exists(library): xbmcvfs.mkdir(library) # Set custom path for user if xbmc.getCondVisibility('System.HasAddon(script.tvtunes)'): tvtunes = xbmcaddon.Addon(id="script.tvtunes") tvtunes.setSetting('custom_path_enable', "true") tvtunes.setSetting('custom_path', library) log.info("TV Tunes custom path is enabled and set.") else: # if it does not exist this will not work so warn user # often they need to edit the settings first for it to be created. dialog.ok(heading=lang(29999), line1=lang(33073)) xbmc.executebuiltin('Addon.OpenSettings(script.tvtunes)') return # Get every user view Id with database.DatabaseConn('emby') as cursor: emby_db = embydb.Embydb_Functions(cursor) viewids = emby_db.getViews() # Get Ids with Theme Videos itemIds = {} for view in viewids: url = "{server}/emby/Users/{UserId}/Items?HasThemeVideo=True&ParentId=%s&format=json" % view result = doUtils.downloadUrl(url) if result['TotalRecordCount'] != 0: for item in result['Items']: itemId = item['Id'] folderName = item['Name'] folderName = utils.normalize_string(folderName.encode('utf-8')) itemIds[itemId] = folderName # Get paths for theme videos for itemId in itemIds: nfo_path = xbmc.translatePath( "special://profile/addon_data/emby.for.kodi/library/%s/" % itemIds[itemId]) # Create folders for each content if not xbmcvfs.exists(nfo_path): xbmcvfs.mkdir(nfo_path) # Where to put the nfos nfo_path = "%s%s" % (nfo_path, "tvtunes.nfo") url = "{server}/emby/Items/%s/ThemeVideos?format=json" % itemId result = doUtils.downloadUrl(url) # Create nfo and write themes to it nfo_file = xbmcvfs.File(nfo_path, 'w') pathstowrite = "" # May be more than one theme for theme in result['Items']: putils = playutils.PlayUtils(theme) if playback == "DirectPlay": playurl = putils.directPlay() else: playurl = putils.directStream() pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8')) # Check if the item has theme songs and add them url = "{server}/emby/Items/%s/ThemeSongs?format=json" % itemId result = doUtils.downloadUrl(url) # May be more than one theme for theme in result['Items']: if playback == "DirectPlay": playurl = api.API(theme).get_file_path() else: playurl = playutils.PlayUtils(theme).directStream() pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8')) nfo_file.write( '<tvtunes>%s</tvtunes>' % pathstowrite ) # Close nfo file nfo_file.close() # Get Ids with Theme songs musicitemIds = {} for view in viewids: url = "{server}/emby/Users/{UserId}/Items?HasThemeSong=True&ParentId=%s&format=json" % view result = doUtils.downloadUrl(url) if result['TotalRecordCount'] != 0: for item in result['Items']: itemId = item['Id'] folderName = item['Name'] folderName = utils.normalize_string(folderName.encode('utf-8')) musicitemIds[itemId] = folderName # Get paths for itemId in musicitemIds: # if the item was already processed with video themes back out if itemId in itemIds: continue nfo_path = xbmc.translatePath( "special://profile/addon_data/emby.for.kodi/library/%s/" % musicitemIds[itemId]) # Create folders for each content if not xbmcvfs.exists(nfo_path): xbmcvfs.mkdir(nfo_path) # Where to put the nfos nfo_path = "%s%s" % (nfo_path, "tvtunes.nfo") url = "{server}/emby/Items/%s/ThemeSongs?format=json" % itemId result = doUtils.downloadUrl(url) # Create nfo and write themes to it nfo_file = xbmcvfs.File(nfo_path, 'w') pathstowrite = "" # May be more than one theme for theme in result['Items']: if playback == "DirectPlay": playurl = api.API(theme).get_file_path() else: playurl = playutils.PlayUtils(theme).directStream() pathstowrite += ('<file>%s</file>' % playurl.encode('utf-8')) nfo_file.write( '<tvtunes>%s</tvtunes>' % pathstowrite ) # Close nfo file nfo_file.close() dialog.notification( heading=lang(29999), message=lang(33069), icon="special://home/addons/emby.for.kodi/icon.png", time=1000, sound=False)
def maintainViews(self, embycursor, kodicursor): # Compare the views to emby emby = self.emby emby_db = embydb.Embydb_Functions(embycursor) kodi_db = kodidb.Kodidb_Functions(kodicursor) # Get views result = self.doUtils("{server}/emby/Users/{UserId}/Views?format=json") grouped_views = result['Items'] if 'Items' in result else [] ordered_views = self.emby.getViews(sortedlist=True) all_views = [] sorted_views = [] for view in ordered_views: all_views.append(view['name']) if view['type'] == "music": continue if view['type'] == "mixed": sorted_views.append(view['name']) sorted_views.append(view['name']) log.info("Sorted views: %s" % sorted_views) # total nodes for window properties self.vnodes.clearProperties() totalnodes = len(sorted_views) + 0 current_views = emby_db.getViews() # Set views for supported media type emby_mediatypes = { 'movies': "Movie", 'tvshows': "Series", 'musicvideos': "MusicVideo", 'homevideos': "Video", 'music': "Audio", 'photos': "Photo" } for mediatype in [ 'movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos' ]: nodes = [] # Prevent duplicate for nodes of the same type playlists = [] # Prevent duplicate for playlists of the same type # Get media folders from server folders = self.emby.getViews(mediatype, root=True) for folder in folders: folderid = folder['id'] foldername = folder['name'] viewtype = folder['type'] if foldername not in all_views: # Media folders are grouped into userview params = { 'ParentId': folderid, 'Recursive': True, 'Limit': 1, 'IncludeItemTypes': emby_mediatypes[mediatype] } # Get one item from server using the folderid url = "{server}/emby/Users/{UserId}/Items?format=json" result = self.doUtils(url, parameters=params) try: verifyitem = result['Items'][0]['Id'] except (TypeError, IndexError): # Something is wrong. Keep the same folder name. # Could be the view is empty or the connection pass else: for grouped_view in grouped_views: # This is only reserved for the detection of grouped views if (grouped_view['Type'] == "UserView" and grouped_view.get('CollectionType') == mediatype): # Take the userview, and validate the item belong to the view if self.emby.verifyView( grouped_view['Id'], verifyitem): # Take the name of the userview log.info( "Found corresponding view: %s %s" % (grouped_view['Name'], grouped_view['Id'])) foldername = grouped_view['Name'] break else: # Unable to find a match, add the name to our sorted_view list sorted_views.append(foldername) log.info( "Couldn't find corresponding grouped view: %s" % sorted_views) # Failsafe try: sorted_views.index(foldername) except ValueError: sorted_views.append(foldername) # Get current media folders from emby database view = emby_db.getView_byId(folderid) try: current_viewname = view[0] current_viewtype = view[1] current_tagid = view[2] except TypeError: log.info("Creating viewid: %s in Emby database." % folderid) tagid = kodi_db.createTag(foldername) # Create playlist for the video library if (foldername not in playlists and mediatype in ('movies', 'tvshows', 'musicvideos')): utils.playlistXSP(mediatype, foldername, folderid, viewtype) playlists.append(foldername) # Create the video node if foldername not in nodes and mediatype not in ( "musicvideos", "music"): self.vnodes.viewNode(sorted_views.index(foldername), foldername, mediatype, viewtype, folderid) if viewtype == "mixed": # Change the value sorted_views[sorted_views.index( foldername)] = "%ss" % foldername nodes.append(foldername) totalnodes += 1 # Add view to emby database emby_db.addView(folderid, foldername, viewtype, tagid) else: log.debug(' '.join(("Found viewid: %s" % folderid, "viewname: %s" % current_viewname, "viewtype: %s" % current_viewtype, "tagid: %s" % current_tagid))) # View is still valid try: current_views.remove(folderid) except ValueError: # View was just created, nothing to remove pass # View was modified, update with latest info if current_viewname != foldername: log.info("viewid: %s new viewname: %s" % (folderid, foldername)) tagid = kodi_db.createTag(foldername) # Update view with new info emby_db.updateView(foldername, tagid, folderid) if mediatype != "music": if emby_db.getView_byName( current_viewname) is None: # The tag could be a combined view. Ensure there's no other tags # with the same name before deleting playlist. utils.playlistXSP(mediatype, current_viewname, folderid, current_viewtype, True) # Delete video node if mediatype != "musicvideos": self.vnodes.viewNode( indexnumber=None, tagname=current_viewname, mediatype=mediatype, viewtype=current_viewtype, viewid=folderid, delete=True) # Added new playlist if (foldername not in playlists and mediatype in ('movies', 'tvshows', 'musicvideos')): utils.playlistXSP(mediatype, foldername, folderid, viewtype) playlists.append(foldername) # Add new video node if foldername not in nodes and mediatype != "musicvideos": self.vnodes.viewNode( sorted_views.index(foldername), foldername, mediatype, viewtype, folderid) if viewtype == "mixed": # Change the value sorted_views[sorted_views.index( foldername)] = "%ss" % foldername nodes.append(foldername) totalnodes += 1 # Update items with new tag items = emby_db.getItem_byView(folderid) for item in items: # Remove the "s" from viewtype for tags kodi_db.updateTag(current_tagid, tagid, item[0], current_viewtype[:-1]) else: # Validate the playlist exists or recreate it if mediatype != "music": if (foldername not in playlists and mediatype in ('movies', 'tvshows', 'musicvideos')): utils.playlistXSP(mediatype, foldername, folderid, viewtype) playlists.append(foldername) # Create the video node if not already exists if foldername not in nodes and mediatype != "musicvideos": self.vnodes.viewNode( sorted_views.index(foldername), foldername, mediatype, viewtype, folderid) if viewtype == "mixed": # Change the value sorted_views[sorted_views.index( foldername)] = "%ss" % foldername nodes.append(foldername) totalnodes += 1 else: # Add video nodes listings self.vnodes.singleNode(totalnodes, "Favorite movies", "movies", "favourites") totalnodes += 1 self.vnodes.singleNode(totalnodes, "Favorite tvshows", "tvshows", "favourites") totalnodes += 1 self.vnodes.singleNode(totalnodes, "Favorite episodes", "episodes", "favourites") totalnodes += 1 self.vnodes.singleNode(totalnodes, "channels", "movies", "channels") totalnodes += 1 # Save total window('Emby.nodes.total', str(totalnodes)) # Remove any old referenced views log.info("Removing views: %s" % current_views) for view in current_views: emby_db.removeView(view) # Remove any items that belongs to the old view items = emby_db.get_item_by_view(view) items = [i[0] for i in items] # Convert list of tuple to list self.triage_items("remove", items)