def add_user(): ''' Add or remove users from the default server session. ''' if not window('jellyfin_online.bool'): return session = TheVoid('GetSession', {}).get() users = TheVoid('GetUsers', {'IsDisabled': False, 'IsHidden': False}).get() current = session[0]['AdditionalUsers'] result = dialog("select", translate(33061), [translate(33062), translate(33063)] if current else [translate(33062)]) if result < 0: return if not result: # Add user eligible = [x for x in users if x['Id'] not in [current_user['UserId'] for current_user in current]] resp = dialog("select", translate(33064), [x['Name'] for x in eligible]) if resp < 0: return user = eligible[resp] event('AddUser', {'Id': user['Id'], 'Add': True}) else: # Remove user resp = dialog("select", translate(33064), [x['UserName'] for x in current]) if resp < 0: return user = current[resp] event('AddUser', {'Id': user['UserId'], 'Add': False})
def action_menu(self): selected = self._selected_option.decode('utf-8') if selected == OPTIONS['Refresh']: TheVoid('RefreshItem', { 'ServerId': self.server, 'Id': self.item['Id'] }) elif selected == OPTIONS['AddFav']: TheVoid('FavoriteItem', { 'ServerId': self.server, 'Id': self.item['Id'], 'Favorite': True }) elif selected == OPTIONS['RemoveFav']: TheVoid('FavoriteItem', { 'ServerId': self.server, 'Id': self.item['Id'], 'Favorite': False }) elif selected == OPTIONS['Addon']: xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)') elif selected == OPTIONS['Delete']: self.delete_item()
def _set_intros(self, item): ''' if we have any play them when the movie/show is not being resumed. ''' intros = TheVoid('GetIntros', {'ServerId': self.server_id, 'Id': item['Id']}).get() if intros['Items']: enabled = True if settings('askCinema') == "true": resp = dialog("yesno", heading="{emby}", line1=_(33016)) if not resp: enabled = False LOG.info("Skip trailers.") if enabled: for intro in intros['Items']: listitem = xbmcgui.ListItem() LOG.info("[ intro/%s ] %s", intro['Id'], intro['Name']) play = playutils.PlayUtils(intro, False, self.server_id, self.server) source = play.select_source(play.get_sources()) self.set_listitem(intro, listitem, intro=True) listitem.setPath(intro['PlaybackInfo']['Path']) playutils.set_properties(intro, intro['PlaybackInfo']['Method'], self.server_id) self.stack.append([intro['PlaybackInfo']['Path'], listitem]) window('emby.skip.%s' % intro['Id'], value="true")
def __init__(self, server_id=None): self.server_id = server_id or None self.server = TheVoid('GetServerAddress', { 'ServerId': self.server_id }).get() self.stack = []
def transcode(self): item = TheVoid('GetItem', { 'Id': self.item['Id'], 'ServerId': self.server }).get() Actions(self.server).play(item, self.kodi_id, True)
def get_sources(self, source_id=None): ''' Return sources based on the optional source_id or the device profile. ''' params = { 'ServerId': self.info['ServerId'], 'Id': self.item['Id'], 'Profile': self.get_device_profile() } info = TheVoid('GetPlaybackInfo', params).get() LOG.info(info) self.info['PlaySessionId'] = info['PlaySessionId'] sources = [] if not info.get('MediaSources'): LOG.info("No MediaSources found.") elif source_id: for source in info: if source['Id'] == source_id: sources.append(source) break elif not self.is_selection(info) or len(info['MediaSources']) == 1: LOG.info("Skip source selection.") sources.append(info['MediaSources'][0]) else: sources.extend([x for x in info['MediaSources']]) return sources
def __init__(self, server_id=None, server=None, *args, **kwargs): self.server_id = server_id or None self.server = server or TheVoid('GetServerAddress', { 'ServerId': self.server_id }).get() self.stack = []
def get_fanart(item_id, path, server_id=None): ''' Get extra fanart for listitems. This is called by skinhelper. Images are stored locally, due to the Kodi caching system. ''' if not item_id and 'plugin.video.emby' in path: item_id = path.split('/')[-2] if not item_id: return LOG.info("[ extra fanart ] %s", item_id) objects = Objects() list_li = [] directory = xbmc.translatePath("special://thumbnails/emby/%s/" % item_id).decode('utf-8') server = TheVoid('GetServerAddress', {'ServerId': server_id}).get() if not xbmcvfs.exists(directory): xbmcvfs.mkdirs(directory) item = TheVoid('GetItem', {'ServerId': server_id, 'Id': item_id}).get() obj = objects.map(item, 'Artwork') backdrops = api.API(item, server).get_all_artwork(obj) tags = obj['BackdropTags'] for index, backdrop in enumerate(backdrops): tag = tags[index] fanart = os.path.join(directory, "fanart%s.jpg" % tag) li = xbmcgui.ListItem(tag, path=fanart) xbmcvfs.copy(backdrop, fanart) list_li.append((fanart, li, False)) else: LOG.debug("cached backdrop found") dirs, files = xbmcvfs.listdir(directory) for file in files: fanart = os.path.join(directory, file.decode('utf-8')) li = xbmcgui.ListItem(file, path=fanart) list_li.append((fanart, li, False)) xbmcplugin.addDirectoryItems(int(sys.argv[1]), list_li, len(list_li)) xbmcplugin.endOfDirectory(int(sys.argv[1]))
def delete_item(self): delete = True if not settings('skipContextMenu.bool'): if not dialog("yesno", "{jellyfin}", translate(33015)): delete = False if delete: TheVoid('DeleteItem', {'ServerId': self.server, 'Id': self.item['Id']})
def delete_item(self): delete = True if not settings('skipContextMenu.bool'): if not dialog("yesno", heading="{emby}", line1=_(33015)): delete = False if delete: TheVoid('DeleteItem', {'ServerId': self.server, 'Id': self.item['Id']})
def get_video_extras(item_id, path, server_id=None): ''' Returns the video files for the item as plugin listing, can be used to browse actual files or video extras, etc. ''' if not item_id and 'plugin.video.jellyfin' in path: item_id = path.split('/')[-2] if not item_id: return item = TheVoid('GetItem', {'ServerId': server_id, 'Id': item_id}).get() # TODO """
def __init__(self, item, force_transcode=False, server_id=None, server=None, token=None): ''' Item will be updated with the property PlaybackInfo, which holds all the playback information. ''' item['PlaybackInfo'] = {} self.info = { 'Item': item, 'ServerId': server_id, 'ServerAddress': server, 'ForceTranscode': force_transcode, 'Token': token or TheVoid('GetToken', {'ServerId': server_id}).get() }
def live_stream(self, source): ''' Get live stream media info. ''' params = { 'ServerId': self.info['ServerId'], 'Id': self.item['Id'], 'Profile': self.get_device_profile(), 'PlaySessionId': self.info['PlaySessionId'], 'Token': source['OpenToken'] } info = TheVoid('GetLiveStream', params).get() LOG.info(info) if info['MediaSource'].get('RequiresClosing'): self.info['LiveStreamId'] = source['LiveStreamId'] return info['MediaSource']
def _set_additional_parts(self, item_id): ''' Create listitems and add them to the stack of playlist. ''' parts = TheVoid('GetAdditionalParts', {'ServerId': self.server_id, 'Id': item_id}).get() for part in parts['Items']: listitem = xbmcgui.ListItem() LOG.info("[ part/%s ] %s", part['Id'], part['Name']) play = playutils.PlayUtils(part, False, self.server_id, self.server) source = play.select_source(play.get_sources()) play.set_external_subs(source, listitem) self.set_listitem(part, listitem) listitem.setPath(part['PlaybackInfo']['Path']) playutils.set_properties(part, part['PlaybackInfo']['Method'], self.server_id) self.stack.append([part['PlaybackInfo']['Path'], listitem])
def __init__(self, transcode=False, delete=False): try: self.kodi_id = sys.listitem.getVideoInfoTag().getDbId() or None self.media = self.get_media_type() self.server = sys.listitem.getProperty('embyserver') or None item_id = sys.listitem.getProperty('embyid') except AttributeError: self.server = None if xbmc.getInfoLabel('ListItem.Property(embyid)'): item_id = xbmc.getInfoLabel('ListItem.Property(embyid)') else: self.kodi_id = xbmc.getInfoLabel('ListItem.DBID') self.media = xbmc.getInfoLabel('ListItem.DBTYPE') item_id = None if self.server or item_id: self.item = TheVoid('GetItem', { 'ServerId': self.server, 'Id': item_id }).get() else: self.item = self.get_item_id() if self.item: if transcode: self.transcode() elif delete: self.delete_item() elif self.select_menu(): self.action_menu() if self._selected_option.decode('utf-8') in ( OPTIONS['Delete'], OPTIONS['AddFav'], OPTIONS['RemoveFav']): xbmc.sleep(500) xbmc.executebuiltin('Container.Refresh')
def __init__(self, play=False, transcode=False, delete=False): self.server = None self.kodi_id = None self.media = None try: self.kodi_id = max( sys.listitem.getVideoInfoTag().getDbId(), 0) or max( sys.listitem.getMusicInfoTag().getDbId(), 0) or None self.media = self.get_media_type() self.server = sys.listitem.getProperty('embyserver') or None item_id = sys.listitem.getProperty('embyid') except AttributeError: if xbmc.getInfoLabel('ListItem.Property(embyid)'): item_id = xbmc.getInfoLabel('ListItem.Property(embyid)') else: self.kodi_id = xbmc.getInfoLabel('ListItem.DBID') self.media = xbmc.getInfoLabel('ListItem.DBTYPE') item_id = None if self.server or item_id: self.item = TheVoid('GetItem', { 'ServerId': self.server, 'Id': item_id }).get() else: self.item = self.get_item_id() if self.item: if play or transcode: self.play(transcode) elif delete: self.delete_item() elif self.select_menu(): self.action_menu()
def __init__(self, params, server_id=None): ''' Workflow: Strm that calls our webservice in database. When played, the webserivce returns a dummy file to play. Meanwhile, PlayStrm adds the real listitems for items to play to the playlist. ''' self.info = { 'Item': None, 'Id': params.get('id'), 'DbId': params.get('dbid'), 'Transcode': params.get('transcode'), 'ServerId': server_id, 'Server': TheVoid('GetServerAddress', {'ServerId': server_id}).get(), } if self.info['Transcode'] is None: self.info['Transcode'] = settings('playFromTranscode.bool') if settings('playFromStream.bool') else None self.actions = Actions(server_id, self.info['Server']) self.set_listitem = self.actions.set_listitem self.params = params self._detect_play() LOG.info("[ play simple ]")
def browse_letters(media, view_id, server_id=None): ''' Display letters as options. ''' letters = "#ABCDEFGHIJKLMNOPQRSTUVWXYZ" view = TheVoid('GetItem', {'ServerId': server_id, 'Id': view_id}).get() xbmcplugin.setPluginCategory(int(sys.argv[1]), view['Name']) for node in letters: params = { 'id': view_id, 'mode': "browse", 'type': media, 'folder': 'firstletter-%s' % node, 'server': server_id } path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params)) directory(node, path) xbmcplugin.setContent(int(sys.argv[1]), 'files') xbmcplugin.endOfDirectory(int(sys.argv[1]))
def browse_subfolders(media, view_id, server_id=None): ''' Display submenus for jellyfin views. ''' from views import DYNNODES view = TheVoid('GetItem', {'ServerId': server_id, 'Id': view_id}).get() xbmcplugin.setPluginCategory(int(sys.argv[1]), view['Name']) nodes = DYNNODES[media] for node in nodes: params = { 'id': view_id, 'mode': "browse", 'type': media, 'folder': view_id if node[0] == 'all' else node[0], 'server': server_id } path = "%s?%s" % ("plugin://plugin.video.jellyfin/", urlencode(params)) directory(node[1] or view['Name'], path) xbmcplugin.setContent(int(sys.argv[1]), 'files') xbmcplugin.endOfDirectory(int(sys.argv[1]))
def add_user(permanent=False): ''' Add or remove users from the default server session. permanent=True from the add-on settings. ''' if not window('emby_online.bool'): return session = TheVoid('GetSession', {}).get() users = TheVoid('GetUsers', {'IsDisabled': False, 'IsHidden': False}).get() for user in users: if user['Id'] == session[0]['UserId']: users.remove(user) break while True: session = TheVoid('GetSession', {}).get() additional = current = session[0]['AdditionalUsers'] add_session = True if permanent: perm_users = settings('addUsers').split(',') if settings('addUsers') else [] current = [] for user in users: for perm_user in perm_users: if user['Id'] == perm_user: current.append({'UserName': user['Name'], 'UserId': user['Id']}) result = dialog("select", _(33061), [_(33062), _(33063)] if current else [_(33062)]) if result < 0: break if not result: # Add user eligible = [x for x in users if x['Id'] not in [current_user['UserId'] for current_user in current]] resp = dialog("select", _(33064), [x['Name'] for x in eligible]) if resp < 0: break user = eligible[resp] if permanent: perm_users.append(user['Id']) settings('addUsers', ','.join(perm_users)) if user['Id'] in [current_user['UserId'] for current_user in additional]: add_session = False if add_session: event('AddUser', {'Id': user['Id'], 'Add': True}) dialog("notification", heading="{emby}", message="%s %s" % (_(33067), user['Name']), icon="{emby}", time=1000, sound=False) else: # Remove user resp = dialog("select", _(33064), [x['UserName'] for x in current]) if resp < 0: break user = current[resp] if permanent: perm_users.remove(user['UserId']) settings('addUsers', ','.join(perm_users)) if add_session: event('AddUser', {'Id': user['UserId'], 'Add': False}) dialog("notification", heading="{emby}", message="%s %s" % (_(33066), user['UserName']), icon="{emby}", time=1000, sound=False)
def _get_item(self): self.info['Item'] = TheVoid('GetItem', {'Id': self.info['Id'], 'ServerId': self.info['Server']}).get()
def __init__(self): ''' Parse the parameters. Reroute to our service.py where user is fully identified already. ''' base_url = sys.argv[0] path = sys.argv[2] try: params = dict(urlparse.parse_qsl(path[1:])) except Exception: params = {} mode = params.get('mode') server = params.get('server') if server == 'None': server = None LOG.warn("path: %s params: %s", path, json.dumps(params, indent=4)) if '/extrafanart' in base_url: emby_path = path[1:] emby_id = params.get('id') get_fanart(emby_id, emby_path, server) elif '/Extras' in base_url or '/VideoFiles' in base_url: emby_path = path[1:] emby_id = params.get('id') get_video_extras(emby_id, emby_path, server) elif mode == 'play': item = TheVoid('GetItem', {'Id': params['id'], 'ServerId': server}).get() Actions(server).play(item, params.get('dbid'), params.get('transcode') == 'true', playlist=params.get('playlist') == 'true') elif mode =='playstrm': while not window('emby.playlist.play.bool'): xbmc.sleep(50) if window('emby.playlist.aborted.bool'): LOG.info("[ playback aborted ]") break else: LOG.info("[ playback started ]") xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, xbmcgui.ListItem()) window('emby.playlist.aborted', clear=True) elif mode == 'playsimple': from helper import playsimple playsimple.PlaySimple(params, server).play() elif mode == 'playlist': event('PlayPlaylist', {'Id': params['id'], 'ServerId': server}) elif mode == 'deviceid': client.reset_device_id() elif mode == 'reset': reset() elif mode == 'delete': delete_item() elif mode == 'refreshboxsets': event('SyncLibrary', {'Id': "Boxsets:Refresh"}) elif mode == 'nextepisodes': get_next_episodes(params['id'], params['limit']) elif mode == 'browse': browse(params.get('type'), params.get('id'), params.get('folder'), server) elif mode == 'synclib': event('SyncLibrary', {'Id': params.get('id')}) elif mode == 'updatelib': event('SyncLibrary', {'Id': params.get('id'), 'Update': True}) elif mode == 'repairlib': event('RepairLibrary', {'Id': params.get('id')}) elif mode == 'removelib': event('RemoveLibrary', {'Id': params.get('id')}) elif mode == 'repairlibs': event('RepairLibrarySelection') elif mode == 'updatelibs': event('SyncLibrarySelection') elif mode == 'removelibs': event('RemoveLibrarySelection') elif mode == 'addlibs': event('AddLibrarySelection') elif mode == 'connect': event('EmbyConnect') elif mode == 'addserver': event('AddServer') elif mode == 'login': event('ServerConnect', {'Id': server}) elif mode == 'removeserver': event('RemoveServer', {'Id': server}) elif mode == 'settings': xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)') elif mode == 'adduser': add_user(params.get('permanent') == 'true') elif mode == 'checkupdate': event('CheckUpdate') elif mode == 'updateserver': event('UpdateServer') elif mode == 'thememedia': get_themes() elif mode == 'managelibs': manage_libraries() elif mode == 'texturecache': cache_artwork() elif mode == 'backup': backup() elif mode == 'restartservice': window('emby.restart.bool', True) elif mode == 'patchmusic': event('PatchMusic', {'Notification': True}) else: listing()
def browse(media, view_id=None, folder=None, server_id=None): ''' Browse content dynamically. ''' LOG.info("--[ v:%s/%s ] %s", view_id, media, folder) if not window('emby_online.bool') and server_id is None: monitor = xbmc.Monitor() for i in range(300): if window('emby_online.bool'): break elif monitor.waitForAbort(0.1): return else: LOG.error("Default server is not online.") return folder = folder.lower() if folder else None if folder is None and media in ('homevideos', 'movies', 'books', 'audiobooks'): return browse_subfolders(media, view_id, server_id) if folder and folder == 'firstletter': return browse_letters(media, view_id, server_id) if view_id: view = TheVoid('GetItem', {'ServerId': server_id, 'Id': view_id}).get() xbmcplugin.setPluginCategory(int(sys.argv[1]), view['Name']) content_type = "files" if media in ('tvshows', 'seasons', 'episodes', 'movies', 'musicvideos', 'songs', 'albums'): content_type = media elif media in ('homevideos', 'photos'): content_type = "images" elif media in ('books', 'audiobooks'): content_type = "videos" elif media == 'music': content_type = "artists" if folder == 'recentlyadded': listing = TheVoid('RecentlyAdded', {'Id': view_id, 'ServerId': server_id}).get() elif folder == 'genres': listing = TheVoid('Genres', {'Id': view_id, 'ServerId': server_id}).get() elif media == 'livetv': listing = TheVoid('LiveTV', {'Id': view_id, 'ServerId': server_id}).get() elif folder == 'unwatched': listing = TheVoid('Browse', {'Id': view_id, 'ServerId': server_id, 'Filters': ['IsUnplayed']}).get() elif folder == 'favorite': listing = TheVoid('Browse', {'Id': view_id, 'ServerId': server_id, 'Filters': ['IsFavorite']}).get() elif folder == 'inprogress': listing = TheVoid('Browse', {'Id': view_id, 'ServerId': server_id, 'Filters': ['IsResumable']}).get() elif folder == 'boxsets': listing = TheVoid('Browse', {'Id': view_id, 'ServerId': server_id, 'Media': get_media_type('boxsets'), 'Recursive': True}).get() elif folder == 'random': listing = TheVoid('Browse', {'Id': view_id, 'ServerId': server_id, 'Media': get_media_type(content_type), 'Sort': "Random", 'Limit': 25, 'Recursive': True}).get() elif (folder or "").startswith('firstletter-'): listing = TheVoid('Browse', {'Id': view_id, 'ServerId': server_id, 'Media': get_media_type(content_type), 'Params': {'NameStartsWith': folder.split('-')[1]}}).get() elif (folder or "").startswith('genres-'): listing = TheVoid('Browse', {'Id': view_id, 'ServerId': server_id, 'Media': get_media_type(content_type), 'Params': {'GenreIds': folder.split('-')[1]}}).get() elif folder == 'favepisodes': listing = TheVoid('Browse', {'Media': get_media_type(content_type), 'ServerId': server_id, 'Limit': 25, 'Filters': ['IsFavorite']}).get() elif media == 'homevideos': listing = TheVoid('Browse', {'Id': folder or view_id, 'Media': get_media_type(content_type), 'ServerId': server_id, 'Recursive': False}).get() elif media == 'movies': listing = TheVoid('Browse', {'Id': folder or view_id, 'Media': get_media_type(content_type), 'ServerId': server_id, 'Recursive': True}).get() elif media in ('boxset', 'library'): listing = TheVoid('Browse', {'Id': folder or view_id, 'ServerId': server_id, 'Recursive': True}).get() elif media == 'episodes': listing = TheVoid('Browse', {'Id': folder or view_id, 'Media': get_media_type(content_type), 'ServerId': server_id, 'Recursive': True}).get() elif media == 'boxsets': listing = TheVoid('Browse', {'Id': folder or view_id, 'ServerId': server_id, 'Recursive': False, 'Filters': ["Boxsets"]}).get() elif media == 'tvshows': listing = TheVoid('Browse', {'Id': folder or view_id, 'ServerId': server_id, 'Recursive': True, 'Media': get_media_type(content_type)}).get() elif media == 'seasons': listing = TheVoid('BrowseSeason', {'Id': folder, 'ServerId': server_id}).get() elif media != 'files': listing = TheVoid('Browse', {'Id': folder or view_id, 'ServerId': server_id, 'Recursive': False, 'Media': get_media_type(content_type)}).get() else: listing = TheVoid('Browse', {'Id': folder or view_id, 'ServerId': server_id, 'Recursive': False}).get() if listing: actions = Actions(server_id) list_li = [] listing = listing if type(listing) == list else listing.get('Items', []) for item in listing: li = xbmcgui.ListItem() li.setProperty('embyid', item['Id']) li.setProperty('embyserver', server_id) actions.set_listitem(item, li) if item.get('IsFolder'): params = { 'id': view_id or item['Id'], 'mode': "browse", 'type': get_folder_type(item, media) or media, 'folder': item['Id'], 'server': server_id } path = "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) context = [] if item['Type'] in ('Series', 'Season', 'Playlist'): context.append(("Play", "RunPlugin(plugin://plugin.video.emby/?mode=playlist&id=%s&server=%s)" % (item['Id'], server_id))) if item['UserData']['Played']: context.append((_(16104), "RunPlugin(plugin://plugin.video.emby/?mode=unwatched&id=%s&server=%s)" % (item['Id'], server_id))) else: context.append((_(16103), "RunPlugin(plugin://plugin.video.emby/?mode=watched&id=%s&server=%s)" % (item['Id'], server_id))) li.addContextMenuItems(context) list_li.append((path, li, True)) elif item['Type'] == 'Genre': params = { 'id': view_id or item['Id'], 'mode': "browse", 'type': get_folder_type(item, media) or media, 'folder': 'genres-%s' % item['Id'], 'server': server_id } path = "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) list_li.append((path, li, True)) else: if item['Type'] not in ('Photo', 'PhotoAlbum'): params = { 'id': item['Id'], 'mode': "play", 'server': server_id } path = "%s?%s" % ("plugin://plugin.video.emby/", urllib.urlencode(params)) li.setProperty('path', path) context = [(_(13412), "RunPlugin(plugin://plugin.video.emby/?mode=playlist&id=%s&server=%s)" % (item['Id'], server_id))] if item['UserData']['Played']: context.append((_(16104), "RunPlugin(plugin://plugin.video.emby/?mode=unwatched&id=%s&server=%s)" % (item['Id'], server_id))) else: context.append((_(16103), "RunPlugin(plugin://plugin.video.emby/?mode=watched&id=%s&server=%s)" % (item['Id'], server_id))) li.addContextMenuItems(context) list_li.append((li.getProperty('path'), li, False)) xbmcplugin.addDirectoryItems(int(sys.argv[1]), list_li, len(list_li)) if content_type == 'images': xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_TITLE) xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_YEAR) xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE) xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RATING) xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_RUNTIME) xbmcplugin.setContent(int(sys.argv[1]), content_type) xbmcplugin.endOfDirectory(int(sys.argv[1]))
def get_audio_subs(self, source, audio=None, subtitle=None): ''' For transcoding only Present the list of audio/subs to select from, before playback starts. Since Emby returns all possible tracks together, sort them. IsTextSubtitleStream if true, is available to download from server. ''' prefs = "" audio_streams = collections.OrderedDict() subs_streams = collections.OrderedDict() streams = source['MediaStreams'] for stream in streams: index = stream['Index'] stream_type = stream['Type'] if stream_type == 'Audio': codec = stream['Codec'] channel = stream.get('ChannelLayout', "") if 'Language' in stream: track = "%s - %s - %s %s" % (index, stream['Language'], codec, channel) else: track = "%s - %s %s" % (index, codec, channel) audio_streams[track] = index elif stream_type == 'Subtitle': if 'Language' in stream: track = "%s - %s" % (index, stream['Language']) else: track = "%s - %s" % (index, stream['Codec']) if stream['IsDefault']: track = "%s - Default" % track if stream['IsForced']: track = "%s - Forced" % track subs_streams[track] = index skip_dialog = int(settings('skipDialogTranscode') or 0) audio_selected = None if audio: audio_selected = audio elif skip_dialog in (0, 1): if len(audio_streams) > 1: selection = list(audio_streams.keys()) resp = dialog("select", _(33013), selection) audio_selected = audio_streams[selection[ resp]] if resp else source['DefaultAudioStreamIndex'] else: # Only one choice audio_selected = audio_streams[next(iter(audio_streams))] else: audio_selected = source['DefaultAudioStreamIndex'] self.info['AudioStreamIndex'] = audio_selected prefs += "&AudioStreamIndex=%s" % audio_selected prefs += "&AudioBitrate=384000" if streams[audio_selected].get( 'Channels', 0) > 2 else "&AudioBitrate=192000" if subtitle: index = subtitle server_settings = TheVoid('GetTranscodeOptions', { 'ServerId': self.info['ServerId'] }).get() stream = streams[index] if server_settings['EnableSubtitleExtraction'] and stream[ 'SupportsExternalStream']: self.info['SubtitleUrl'] = self.get_subtitles( source, stream, index) else: prefs += "&SubtitleStreamIndex=%s" % index self.info['SubtitleStreamIndex'] = index elif skip_dialog in (0, 2) and len(subs_streams): selection = list(['No subtitles']) + list(subs_streams.keys()) resp = dialog("select", _(33014), selection) if resp: index = subs_streams[ selection[resp]] if resp > -1 else source.get( 'DefaultSubtitleStreamIndex') if index is not None: server_settings = TheVoid('GetTranscodeOptions', { 'ServerId': self.info['ServerId'] }).get() stream = streams[index] if server_settings['EnableSubtitleExtraction'] and stream[ 'SupportsExternalStream']: self.info['SubtitleUrl'] = self.get_subtitles( source, stream, index) else: prefs += "&SubtitleStreamIndex=%s" % index self.info['SubtitleStreamIndex'] = index return prefs
def get_themes(): ''' Add theme media locally, via strm. This is only for tv tunes. If another script is used, adjust this code. ''' from helper.utils import normalize_string from helper.playutils import PlayUtils from helper.xmls import tvtunes_nfo library = xbmc.translatePath("special://profile/addon_data/plugin.video.emby/library").decode('utf-8') play = settings('useDirectPaths') == "1" if not xbmcvfs.exists(library + '/'): xbmcvfs.mkdir(library) 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: dialog("ok", heading="{emby}", line1=_(33152)) return with Database('emby') as embydb: all_views = emby_db.EmbyDatabase(embydb.cursor).get_views() views = [x[0] for x in all_views if x[2] in ('movies', 'tvshows', 'mixed')] items = {} server = TheVoid('GetServerAddress', {'ServerId': None}).get() token = TheVoid('GetToken', {'ServerId': None}).get() for view in views: result = TheVoid('GetThemes', {'Type': "Video", 'Id': view}).get() for item in result['Items']: folder = normalize_string(item['Name'].encode('utf-8')) items[item['Id']] = folder result = TheVoid('GetThemes', {'Type': "Song", 'Id': view}).get() for item in result['Items']: folder = normalize_string(item['Name'].encode('utf-8')) items[item['Id']] = folder for item in items: nfo_path = os.path.join(library, items[item]) nfo_file = os.path.join(nfo_path, "tvtunes.nfo") if not xbmcvfs.exists(nfo_path): xbmcvfs.mkdir(nfo_path) themes = TheVoid('GetTheme', {'Id': item}).get() paths = [] for theme in themes['ThemeVideosResult']['Items'] + themes['ThemeSongsResult']['Items']: putils = PlayUtils(theme, False, None, server, token) if play: paths.append(putils.direct_play(theme['MediaSources'][0]).encode('utf-8')) else: paths.append(putils.direct_url(theme['MediaSources'][0]).encode('utf-8')) tvtunes_nfo(nfo_file, paths) dialog("notification", heading="{emby}", message=_(33153), icon="{emby}", time=1000, sound=False)
def __init__(self): ''' Parse the parameters. Reroute to our service.py where user is fully identified already. ''' base_url = sys.argv[0] path = sys.argv[2] try: params = dict(urlparse.parse_qsl(path[1:])) except Exception: params = {} mode = params.get('mode') server = params.get('server') if server == 'None': server = None LOG.warn("path: %s params: %s", path, json.dumps(params, indent=4)) if '/extrafanart' in base_url: jellyfin_path = path[1:] jellyfin_id = params.get('id') get_fanart(jellyfin_id, jellyfin_path, server) elif '/Extras' in base_url or '/VideoFiles' in base_url: jellyfin_path = path[1:] jellyfin_id = params.get('id') get_video_extras(jellyfin_id, jellyfin_path, server) elif mode == 'play': item = TheVoid('GetItem', { 'Id': params['id'], 'ServerId': server }).get() Actions(server).play(item, params.get('dbid'), params.get('transcode') == 'true', playlist=params.get('playlist') == 'true') elif mode == 'playlist': event('PlayPlaylist', {'Id': params['id'], 'ServerId': server}) elif mode == 'deviceid': client.reset_device_id() elif mode == 'reset': reset() elif mode == 'delete': delete_item() elif mode == 'refreshboxsets': event('SyncLibrary', {'Id': "Boxsets:Refresh"}) elif mode == 'nextepisodes': get_next_episodes(params['id'], params['limit']) elif mode == 'browse': browse(params.get('type'), params.get('id'), params.get('folder'), server) elif mode == 'synclib': event('SyncLibrary', {'Id': params.get('id')}) elif mode == 'updatelib': event('SyncLibrary', {'Id': params.get('id'), 'Update': True}) elif mode == 'repairlib': event('RepairLibrary', {'Id': params.get('id')}) elif mode == 'removelib': event('RemoveLibrary', {'Id': params.get('id')}) elif mode == 'repairlibs': event('RepairLibrarySelection') elif mode == 'updatelibs': event('SyncLibrarySelection') elif mode == 'removelibs': event('RemoveLibrarySelection') elif mode == 'addlibs': event('AddLibrarySelection') elif mode == 'addserver': event('AddServer') elif mode == 'login': event('ServerConnect', {'Id': server}) elif mode == 'removeserver': event('RemoveServer', {'Id': server}) elif mode == 'settings': xbmc.executebuiltin('Addon.OpenSettings(plugin.video.jellyfin)') elif mode == 'adduser': add_user() elif mode == 'updateserver': event('UpdateServer') elif mode == 'thememedia': get_themes() elif mode == 'managelibs': manage_libraries() elif mode == 'backup': backup() elif mode == 'restartservice': window('jellyfin.restart.bool', True) else: listing()
def get_audio_subs(self, source, audio=None, subtitle=None): ''' For transcoding only Present the list of audio/subs to select from, before playback starts. Since Jellyfin returns all possible tracks together, sort them. IsTextSubtitleStream if true, is available to download from server. ''' prefs = "" audio_streams = collections.OrderedDict() subs_streams = collections.OrderedDict() streams = source['MediaStreams'] allow_burned_subs = settings('allowBurnedSubs.bool') for stream in streams: index = stream['Index'] stream_type = stream['Type'] if stream_type == 'Audio': profile = stream['Profile'] if 'Profile' in stream else None codec = self.get_commercial_codec_name(stream['Codec'], profile) channel = stream.get('ChannelLayout', "").capitalize() if 'Language' in stream: track = "%s - %s %s" % (stream['Language'].capitalize(), codec, channel) else: track = "%s %s" % (codec, channel) audio_streams[track] = index elif stream_type == 'Subtitle': downloadable = stream['IsTextSubtitleStream'] and stream[ 'IsExternal'] and stream['SupportsExternalStream'] if not downloadable and not allow_burned_subs: continue codec = self.get_commercial_codec_name(stream['Codec'], None) if 'Language' in stream: track = "%s - %s" % (stream['Language'].capitalize(), codec) else: track = "%s" % codec if stream['IsDefault']: track = "%s - Default" % track if stream['IsForced']: track = "%s - Forced" % track subs_streams[track] = index skip_dialog = int(settings('skipDialogTranscode') or 0) audio_selected = None if audio: audio_selected = audio elif skip_dialog in (0, 1): if len(audio_streams) > 1: selection = list(audio_streams.keys()) resp = dialog("select", translate(33013), selection) audio_selected = audio_streams[selection[ resp]] if resp else source['DefaultAudioStreamIndex'] else: # Only one choice audio_selected = audio_streams[next(iter(audio_streams))] else: audio_selected = source['DefaultAudioStreamIndex'] self.info['AudioStreamIndex'] = audio_selected prefs += "&AudioStreamIndex=%s" % audio_selected if subtitle: index = subtitle server_settings = TheVoid('GetTranscodeOptions', { 'ServerId': self.info['ServerId'] }).get() stream = streams[index] if server_settings['EnableSubtitleExtraction'] and stream[ 'SupportsExternalStream']: self.info['SubtitleUrl'] = self.get_subtitles( source, stream, index) self.info['SubtitleStreamIndex'] = index elif allow_burned_subs: prefs += "&SubtitleStreamIndex=%s" % index self.info['SubtitleStreamIndex'] = index elif skip_dialog in (0, 2) and len(subs_streams): selection = list(['No subtitles']) + list(subs_streams.keys()) resp = dialog("select", translate(33014), selection) if resp: index = subs_streams[ selection[resp]] if resp > -1 else source.get( 'DefaultSubtitleStreamIndex') if index is not None: server_settings = TheVoid('GetTranscodeOptions', { 'ServerId': self.info['ServerId'] }).get() stream = streams[index] if server_settings['EnableSubtitleExtraction'] and stream[ 'SupportsExternalStream']: self.info['SubtitleUrl'] = self.get_subtitles( source, stream, index) self.info['SubtitleStreamIndex'] = index elif allow_burned_subs: prefs += "&SubtitleStreamIndex=%s" % index self.info['SubtitleStreamIndex'] = index return prefs