Example #1
0
def browse(media, view_id=None, folder=None, server_id=None, api_client=None):
    ''' Browse content dynamically.
    '''
    LOG.info("--[ v:%s/%s ] %s", view_id, media, folder)

    if not window('jellyfin_online.bool') and server_id is None:

        monitor = xbmc.Monitor()

        for i in range(300):
            if window('jellyfin_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 = api_client.get_item(view_id)
        xbmcplugin.setPluginCategory(PROCESS_HANDLE, 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 = api_client.get_recently_added(None, view_id, None)
    elif folder == 'genres':
        listing = api_client.get_genres(view_id)
    elif media == 'livetv':
        listing = api_client.get_channels()
    elif folder == 'unwatched':
        listing = get_filtered_section(view_id, None, None, None, None, None,
                                       ['IsUnplayed'], None, server_id,
                                       api_client)
    elif folder == 'favorite':
        listing = get_filtered_section(view_id, None, None, None, None, None,
                                       ['IsFavorite'], None, server_id,
                                       api_client)
    elif folder == 'inprogress':
        listing = get_filtered_section(view_id, None, None, None, None, None,
                                       ['IsResumable'], None, server_id,
                                       api_client)
    elif folder == 'boxsets':
        listing = get_filtered_section(view_id, get_media_type('boxsets'),
                                       None, True, None, None, None, None,
                                       server_id, api_client)
    elif folder == 'random':
        listing = get_filtered_section(view_id, get_media_type(content_type),
                                       25, True, "Random", None, None, None,
                                       server_id, api_client)
    elif (folder or "").startswith('firstletter-'):
        listing = get_filtered_section(
            view_id, get_media_type(content_type), None, None, None, None,
            None, {'NameStartsWith': folder.split('-')[1]}, server_id,
            api_client)
    elif (folder or "").startswith('genres-'):
        listing = get_filtered_section(view_id, get_media_type(content_type),
                                       None, None, None, None, None,
                                       {'GenreIds': folder.split('-')[1]},
                                       server_id, api_client)
    elif folder == 'favepisodes':
        listing = get_filtered_section(None, get_media_type(content_type), 25,
                                       None, None, None, ['IsFavorite'], None,
                                       server_id, api_client)
    elif folder and media == 'playlists':
        listing = get_filtered_section(folder, get_media_type(content_type),
                                       None, False, 'None', None, None, None,
                                       server_id, api_client)
    elif media == 'homevideos':
        listing = get_filtered_section(folder or view_id,
                                       get_media_type(content_type), None,
                                       False, None, None, None, None,
                                       server_id, api_client)
    elif media in ['movies', 'episodes']:
        listing = get_filtered_section(folder or view_id,
                                       get_media_type(content_type), None,
                                       True, None, None, None, None, server_id,
                                       api_client)
    elif media in ('boxset', 'library'):
        listing = get_filtered_section(folder or view_id, None, None, True,
                                       None, None, None, None, server_id,
                                       api_client)
    elif media == 'boxsets':
        listing = get_filtered_section(folder or view_id, None, None, False,
                                       None, None, ['Boxsets'], None,
                                       server_id, api_client)
    elif media == 'tvshows':
        listing = get_filtered_section(folder or view_id,
                                       get_media_type(content_type), None,
                                       True, None, None, None, None, server_id,
                                       api_client)
    elif media == 'seasons':
        listing = api_client.get_seasons(folder)
    elif media != 'files':
        listing = get_filtered_section(folder or view_id,
                                       get_media_type(content_type), None,
                                       False, None, None, None, None,
                                       server_id, api_client)
    else:
        listing = get_filtered_section(folder or view_id, None, None, False,
                                       None, None, None, None, server_id,
                                       api_client)

    if listing:

        actions = Actions(server_id, api_client)
        list_li = []
        listing = listing if type(listing) == list else listing.get(
            'Items', [])

        for item in listing:

            li = xbmcgui.ListItem()
            li.setProperty('jellyfinid', item['Id'])
            li.setProperty('jellyfinserver', 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.jellyfin/",
                                  urlencode(params))
                context = []

                if item['Type'] in ('Series', 'Season', 'Playlist'):
                    context.append((
                        "Play",
                        "RunPlugin(plugin://plugin.video.jellyfin/?mode=playlist&id=%s&server=%s)"
                        % (item['Id'], server_id)))

                if item['UserData']['Played']:
                    context.append((translate(
                        16104
                    ), "RunPlugin(plugin://plugin.video.jellyfin/?mode=unwatched&id=%s&server=%s)"
                                    % (item['Id'], server_id)))
                else:
                    context.append((translate(
                        16103
                    ), "RunPlugin(plugin://plugin.video.jellyfin/?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.jellyfin/",
                                  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.jellyfin/",
                                      urlencode(params))
                    li.setProperty('path', path)
                    context = [(translate(
                        13412
                    ), "RunPlugin(plugin://plugin.video.jellyfin/?mode=playlist&id=%s&server=%s)"
                                % (item['Id'], server_id))]

                    if item['UserData']['Played']:
                        context.append((translate(
                            16104
                        ), "RunPlugin(plugin://plugin.video.jellyfin/?mode=unwatched&id=%s&server=%s)"
                                        % (item['Id'], server_id)))
                    else:
                        context.append((translate(
                            16103
                        ), "RunPlugin(plugin://plugin.video.jellyfin/?mode=watched&id=%s&server=%s)"
                                        % (item['Id'], server_id)))

                    li.addContextMenuItems(context)

                list_li.append((li.getProperty('path'), li, False))

        xbmcplugin.addDirectoryItems(PROCESS_HANDLE, list_li, len(list_li))

    if content_type == 'images':
        xbmcplugin.addSortMethod(PROCESS_HANDLE,
                                 xbmcplugin.SORT_METHOD_VIDEO_TITLE)
        xbmcplugin.addSortMethod(PROCESS_HANDLE, xbmcplugin.SORT_METHOD_DATE)
        xbmcplugin.addSortMethod(PROCESS_HANDLE,
                                 xbmcplugin.SORT_METHOD_VIDEO_RATING)
        xbmcplugin.addSortMethod(PROCESS_HANDLE,
                                 xbmcplugin.SORT_METHOD_VIDEO_RUNTIME)

    xbmcplugin.setContent(PROCESS_HANDLE, content_type)
    xbmcplugin.endOfDirectory(PROCESS_HANDLE)
Example #2
0
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]))
Example #3
0
class PlayStrm(object):
    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 = {
            'Intros': None,
            'Item': None,
            'Id': params.get('Id'),
            'DbId': params.get('KodiId'),
            'Transcode': params.get('transcode'),
            'AdditionalParts': None,
            'ServerId': server_id,
            'KodiPlaylist': xbmc.PlayList(xbmc.PLAYLIST_VIDEO),
            'Server': Emby(server_id).get_client()
        }
        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']['auth/server-address'])
        self.set_listitem = self.actions.set_listitem
        self.params = params
        self._detect_play()
        LOG.info("[ play strm ]")

    def remove_from_playlist(self, index, playlist_id=None):

        playlist = playlist_id or 1
        JSONRPC('Playlist.Remove').execute({
            'playlistid': playlist_id,
            'position': index
        })

    def remove_from_playlist_by_path(self, path):

        LOG.debug("[ removing ] %s", path)
        self.info['KodiPlaylist'].remove(path)

    def _get_intros(self):
        self.info['Intros'] = self.info['Server']['api'].get_intros(
            self.info['Id'])

    def _get_additional_parts(self):
        self.info['AdditionalParts'] = self.info['Server'][
            'api'].get_additional_parts(self.info['Id'])

    def _get_item(self):
        self.info['Item'] = self.info['Server']['api'].get_item(
            self.info['Id'])

    def _detect_play(self):
        ''' Download all information needed to build the playlist for item requested.
        '''
        if self.info['Id']:

            self._get_intros()
            self._get_item()
            self._get_additional_parts()

    def start_playback(self, index=0):
        xbmc.Player().play(self.info['KodiPlaylist'],
                           startpos=index,
                           windowed=False)

    def play(self, delayed=True):
        ''' Create and add listitems to the Kodi playlist.
        '''
        if window('emby_playlistclear.bool'):

            LOG.info("[ play clearing playlist ]")
            self.actions.get_playlist(self.info['Item']).clear()
            window('emby_playlistclear.bool', clear=True)

        self.info['StartIndex'] = max(self.info['KodiPlaylist'].getposition(),
                                      0)
        self.info['Index'] = self.info['StartIndex']
        LOG.info("[ play/%s/%s ]", self.info['Id'], self.info['Index'])

        listitem = xbmcgui.ListItem()
        self._set_playlist(listitem)

        if not delayed:
            self.start_playback(self.info['StartIndex'])

        return self.info['StartIndex']

    def play_folder(self, position=None):
        ''' When an entire queue is requested, 
            queue playlist items using strm links to setup playback later.
        '''
        self.info['StartIndex'] = position or max(
            self.info['KodiPlaylist'].size(), 0)
        self.info['Index'] = self.info['StartIndex'] + 1
        LOG.info("[ play folder/%s/%s ]", self.info['Id'], self.info['Index'])

        listitem = xbmcgui.ListItem()
        self.actions.set_listitem(self.info['Item'], listitem,
                                  self.info['DbId'])
        url = "http://127.0.0.1:57578/emby/play/file.strm?mode=playfolder&Id=%s" % self.info[
            'Id']

        if self.info['DbId']:
            url += "&KodiId=%s" % self.info['DbId']

        if self.info['ServerId']:
            url += "&server=%s" % self.info['ServerId']

        if self.info['Transcode']:
            url += "&transcode=true"

        listitem.setPath(url)
        self.info['KodiPlaylist'].add(url=url,
                                      listitem=listitem,
                                      index=self.info['Index'])

        return self.info['Index']

    def _set_playlist(self, listitem):
        ''' Verify seektime, set intros, set main item and set additional parts.
            Detect the seektime for video type content.
            Verify the default video action set in Kodi for accurate resume behavior.
        '''
        seektime = window('emby.resume')
        window('emby.resume', clear=True)
        seektime = seektime == 'true' if seektime else None

        if seektime is None and self.info['Item']['MediaType'] in ('Video',
                                                                   'Audio'):
            resume = self.info['Item']['UserData'].get('PlaybackPositionTicks')

            if resume:
                choice = self.actions.resume_dialog(
                    api.API(self.info['Item'],
                            self.info['Server']).adjust_resume(
                                (resume or 0) / 10000000.0), self.info['Item'])

                if choice is None:
                    raise Exception("User backed out of resume dialog.")

                seektime = False if not choice else True

        if settings('enableCinema.bool') and not seektime:
            self._set_intros()

        LOG.info("[ main/%s/%s ] %s", self.info['Item']['Id'],
                 self.info['Index'], self.info['Item']['Name'])
        play = playutils.PlayUtilsStrm(self.info['Item'],
                                       self.info['Transcode'],
                                       self.info['ServerId'],
                                       self.info['Server'])
        source = play.select_source(play.get_sources())

        if not source:
            raise Exception("Playback selection cancelled")

        play.set_external_subs(source, listitem)
        self.set_listitem(self.info['Item'], listitem, self.info['DbId'],
                          seektime)
        listitem.setPath(self.info['Item']['PlaybackInfo']['Path'])
        playutils.set_properties(self.info['Item'],
                                 self.info['Item']['PlaybackInfo']['Method'],
                                 self.info['ServerId'])

        self.info['KodiPlaylist'].add(
            url=self.info['Item']['PlaybackInfo']['Path'],
            listitem=listitem,
            index=self.info['Index'])
        self.info['Index'] += 1

        if self.info['Item'].get('PartCount'):
            self._set_additional_parts()

    def _set_intros(self):
        ''' if we have any play them when the movie/show is not being resumed.
        '''
        if self.info['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 self.info['Intros']['Items']:

                    listitem = xbmcgui.ListItem()
                    LOG.info("[ intro/%s/%s ] %s", intro['Id'],
                             self.info['Index'], intro['Name'])

                    play = playutils.PlayUtilsStrm(intro, False,
                                                   self.info['ServerId'],
                                                   self.info['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.info['ServerId'])

                    self.info['KodiPlaylist'].add(
                        url=intro['PlaybackInfo']['Path'],
                        listitem=listitem,
                        index=self.info['Index'])
                    self.info['Index'] += 1

                    window('emby.skip.%s' % intro['Id'], value="true")

    def _set_additional_parts(self, item_id):
        ''' Create listitems and add them to the stack of playlist.
        '''
        for part in self.info['AdditionalParts']['Items']:

            listitem = xbmcgui.ListItem()
            LOG.info("[ part/%s/%s ] %s", part['Id'], self.info['Index'],
                     part['Name'])

            play = playutils.PlayUtilsStrm(part, self.info['Transcode'],
                                           self.info['ServerId'],
                                           self.info['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.info['ServerId'])

            self.info['KodiPlaylist'].add(url=part['PlaybackInfo']['Path'],
                                          listitem=listitem,
                                          index=self.info['Index'])
            self.info['Index'] += 1