Beispiel #1
0
def parse_disc_set(fxd, node):
    """
    Callback for VideoItem <disc-set>
    """
    item = VideoItem('', fxd.getattr(None, 'parent', None), parse=False)

    dirname = os.path.dirname(fxd.filename)

    item.name = fxd.getattr(node, 'title')
    item.image = fxd.childcontent(node, 'cover-img')
    if item.image:
        item.image = vfs.abspath(os.path.join(dirname, item.image))

    fxd.parse_info(node, item, {'runtime': 'length'})
    item.__fxd_rom_info__ = True
    item.__fxd_rom_label__ = []
    item.__fxd_rom_id__ = []
    item.__fxd_files_options__ = []
    for disc in fxd.get_children(node, 'disc'):
        id = fxd.getattr(disc, 'media-id')
        if id:
            item.__fxd_rom_id__.append(id)

        label = fxd.getattr(disc, 'label-regexp')
        if label:
            item.__fxd_rom_label__.append(label)

        # what to do with the mplayer_options? We can't use them for
        # one disc, or can we? And file_ops? Also only on a per disc base.
        # Answer: it applies to all the files of the disc, unless there
        #         are <file-opt> which specify to what files the
        #         mplayer_options apply. <file-opt> is not such a good
        #         name,  though.
        # So I ignore that we are in a disc right now and use the 'item'
        item.mplayer_options = fxd.getattr(disc, 'mplayer-options')
        there_are_file_opts = 0
        for f in fxd.get_children(disc, 'file-opt'):
            there_are_file_opts = 1
            file_media_id = fxd.getattr(f, 'media-id')
            if not file_media_id:
                file_media_id = id
            mpl_opts = item.mplayer_options + ' ' + fxd.getattr(
                f, 'mplayer-options')
            opt = {
                'file-id': file_media_id + fxd.gettext(f),
                'mplayer-options': mpl_opts
            }
            item.__fxd_files_options__.append(opt)
        if there_are_file_opts:
            # in this case, the disc/@mplayer_options is retricted to the set
            # of files defined in the file-opt elements
            item.mplayer_options = ''

    if not item.files:
        item.files = FileInformation()
    item.files.fxd_file = fxd.filename
    if fxd.is_skin_fxd:
        item.skin_fxd = fxd.filename
    fxd.getattr(None, 'items', []).append(item)
Beispiel #2
0
    def set_url(self, url, info=True):
        """
        Sets a new url to the item. This functions also changes other
        attributes, like file name, mode, network_play and the list of possible
        players.

        B{WARNING}: This is called whenever self.url is set, therefore it is
        strictly forbidden to set self.url directly in this function, (infinite
        recursion!). Use self.__dict__['url'] instead!
        """
        Item.set_url(self, url, info)

        # additional types of urls
        if url.startswith('dvd://') or url.startswith('vcd://'):
            self.network_play = False
            self.mimetype = self.url[:self.url.find('://')].lower()
            if self.url.find('/VIDEO_TS/') > 0:
                # dvd on harddisc
                self.filename = self.url[5:self.url.rfind('/VIDEO_TS/')]
                self.info = util.mediainfo.get(self.filename)
                self.files = FileInformation()
                self.name = self.info['title:filename']
                if not self.name:
                    self.name = util.getname(self.filename)
                self.files.append(self.filename)
            elif self.url.rfind('.iso') + 4 == self.url.rfind('/'):
                # iso
                self.filename = self.url[5:self.url.rfind('/')]
            else:
                self.filename = ''

        elif url.endswith('.iso') and self.info['mime'] == 'video/dvd':
            self.mimetype = 'dvd'
            self.mode = 'dvd'
            self.__dict__['url'] = 'dvd' + self.url[4:] + '/'

        # cover image
        if not self.image or (self.parent and self.image == self.parent.image):
            image = vfs.getoverlay(self.filename + '.raw')
            if os.path.exists(image):
                self.image = image
                self.files.image = image

        # do a new player rating based on the new url
        self.rating()
Beispiel #3
0
    def set_url(self, url, info=True):
        """
        Sets a new url to the item. Always use this function and not set 'url'
        directly because this functions also changes other attributes, like
        filename, mode and network_play
        """
        Item.set_url(self, url, info)
        if url.startswith('dvd://') or url.startswith('vcd://'):
            self.network_play = False
            self.mimetype = self.url[:self.url.find('://')].lower()
            if self.url.find('/VIDEO_TS/') > 0:
                # dvd on harddisc
                self.filename = self.url[5:self.url.rfind('/VIDEO_TS/')]
                self.info = util.mediainfo.get(self.filename)
                self.files = FileInformation()
                self.name = self.info['title:filename']
                if not self.name:
                    self.name = util.getname(self.filename)
                self.files.append(self.filename)
            elif self.url.rfind('.iso') + 4 == self.url.rfind('/'):
                # iso
                self.filename = self.url[5:self.url.rfind('/')]
            else:
                self.filename = ''

        elif url.endswith('.iso') and self.info['mime'] == 'video/dvd':
            self.mimetype = 'dvd'
            self.mode = 'dvd'
            self.url = 'dvd' + self.url[4:] + '/'

        if not self.image or (self.parent and self.image == self.parent.image):
            image = vfs.getoverlay(self.filename + '.raw')
            if os.path.exists(image):
                self.image = image
                self.files.image = image

        if config.VIDEO_INTERLACING and self.info['interlaced'] \
               and not self['deinterlace']:
            # force deinterlacing
            self['deinterlace'] = 1
        else:
            self['deinterlace'] = 0
Beispiel #4
0
    def set_url(self, url, info=True):
        """
        Sets a new url to the item. This functions also changes other
        attributes, like file name, mode, network_play and the list of possible
        players.

        B{WARNING}: This is called whenever self.url is set, therefore it is
        strictly forbidden to set self.url directly in this function, (infinite
        recursion!). Use self.__dict__['url'] instead!
        """
        Item.set_url(self, url, info)

        # additional types of urls
        if url.startswith('dvd://') or url.startswith('vcd://'):
            self.network_play = False
            self.mimetype = self.url[:self.url.find('://')].lower()
            if self.url.find('/VIDEO_TS/') > 0:
                # dvd on harddisc
                self.filename = self.url[5:self.url.rfind('/VIDEO_TS/')]
                self.info     = util.mediainfo.get(self.filename)
                self.files    = FileInformation()
                self.name     = self.info['title:filename']
                if not self.name:
                    self.name = util.getname(self.filename)
                self.files.append(self.filename)
            elif self.url.rfind('.iso') + 4 == self.url.rfind('/'):
                # iso
                self.filename = self.url[5:self.url.rfind('/')]
            else:
                self.filename = ''

        elif url.endswith('.iso') and self.info['mime'] == 'video/dvd':
            self.mimetype = 'dvd'
            self.mode     = 'dvd'
            self.__dict__['url'] = 'dvd' + self.url[4:] + '/'

        # cover image
        if not self.image or (self.parent and self.image == self.parent.image):
            image = vfs.getoverlay(self.filename + '.raw')
            if os.path.exists(image):
                self.image = image
                self.files.image = image

        # do a new player rating based on the new url
        self.rating()
Beispiel #5
0
class VideoItem(Item):
    """
    A class describing a video item.

    @ivar autovars: a list of variables.
    @ivar type: the item type, video for this item.
    @ivar variants: a list of audio variants.
    @ivar subitems: a list of files or tracks to play.
    @ivar current_subitem: the current video item.
    @ivar media_id: media id when the item is on removable media
    @ivar subtitle_file: file name of a file containing subtitles.
    @ivar audio_file: file name of a file containing audio.
    @ivar mplayer_options: additional options for mplayer.
    @ivar tv_show: if the item is a tv programme.
    @ivar video_width: width of the video.
    @ivar video_height: height of the video.
    @ivar selected_subtitle: current subtitle track.
    @ivar selected_audio: current audio track.
    @ivar elapsed: seconds that the item has played.
    @ivar possible_players: a list of possible players.
    @ivar player: current player.
    @ivar player_rating: rating of the current player.
    """
    def __init__(self, url, parent, info=None, parse=True):
        """
        Create an instance of a VideoItem

        @param url: the pysudo URL for the VideoItem
        @param parent: the parent of the VideoItem
        @param info: controls if additional information is found
        @type info: boolean
        @param parse: controls if the url is parsed
        @type parse: boolean
        """
        self.autovars = []
        Item.__init__(self, parent)
        self.type = 'video'

        self.variants = []
        self.subitems = []
        self.current_subitem = None
        self.media_id = ''

        self.subtitle_file = {}
        self.audio_file = {}

        self.mplayer_options = ''
        self.tv_show = False

        self.video_width = 0
        self.video_height = 0

        self.selected_subtitle = None
        self.selected_audio = None
        self.elapsed = 0

        self.possible_players = []
        self.player = None
        self.player_rating = 0

        # set the url (this influences the list of possible players!)
        self.set_url(url, info=parse)
        if info:
            self.info.set_variables(info)

        # deinterlacing and related things
        video_deinterlace = config.VIDEO_DEINTERLACE != None and config.VIDEO_DEINTERLACE or False
        self['deinterlace'] = video_deinterlace

        video_use_xvmc = config.VIDEO_USE_XVMC != None and config.VIDEO_USE_XVMC or False
        self['xvmc'] = video_use_xvmc

        video_field_dominance = config.VIDEO_FIELD_DOMINANCE != None and config.VIDEO_FIELD_DOMINANCE or False
        self['field-dominance'] = video_field_dominance

        # find image for tv show and build new title
        if config.VIDEO_SHOW_REGEXP_MATCH(
                self.name
        ) and not self.network_play and config.VIDEO_SHOW_DATA_DIR:

            show_name = config.VIDEO_SHOW_REGEXP_SPLIT(self.name)
            if show_name[0] and show_name[1] and show_name[2] and show_name[3]:
                self.name = show_name[0] + u' ' + show_name[
                    1] + u'x' + show_name[2] + u' - ' + show_name[3]
                image = util.getimage(
                    (config.VIDEO_SHOW_DATA_DIR + show_name[0].lower()))
                if self.filename and not image:
                    image = util.getimage(
                        os.path.join(os.path.dirname(self.filename),
                                     show_name[0].lower()))

                if image:
                    self.image = image

                from video import tv_show_information
                if tv_show_information.has_key(show_name[0].lower()):
                    tvinfo = tv_show_information[show_name[0].lower()]
                    self.info.set_variables(tvinfo[1])
                    if not self.image:
                        self.image = tvinfo[0]
                    self.skin_fxd = tvinfo[3]
                    self.mplayer_options = tvinfo[2]

                self.tv_show = True
                self.show_name = show_name
                self.tv_show_name = show_name[0]
                self.tv_show_ep = show_name[3]

        # extra info in discset_information
        if parent and parent.media:
            fid = String(
                parent.media.id
            ) + self.filename[len(os.path.join(parent.media.mountdir, '')):]
            from video import discset_information
            if discset_information.has_key(fid):
                self.mplayer_options = discset_information[fid]

        if config.VIDEO_DEINTERLACE and self.info['interlaced']:
            # force deinterlacing
            self['deinterlace'] = True
        else:
            self['deinterlace'] = False

    def __str__(self):
        """
        Create a string for a VideoItem instance.
        @returns: string representation
        """
        s = pformat(self, depth=2)
        return s

    def __repr__(self):
        """
        Create a raw string for a VideoItem instance.
        @returns: string representation
        """
        if hasattr(self, 'name'):
            s = '%s: %r' % (self.name, self.__class__)
        else:
            s = '%r' % (self.__class__)
        return s

    def set_url(self, url, info=True):
        """
        Sets a new url to the item. This functions also changes other
        attributes, like file name, mode, network_play and the list of possible
        players.

        B{WARNING}: This is called whenever self.url is set, therefore it is
        strictly forbidden to set self.url directly in this function, (infinite
        recursion!). Use self.__dict__['url'] instead!
        """
        Item.set_url(self, url, info)

        # additional types of urls
        if url.startswith('dvd://') or url.startswith('vcd://'):
            self.network_play = False
            self.mimetype = self.url[:self.url.find('://')].lower()
            if self.url.find('/VIDEO_TS/') > 0:
                # dvd on harddisc
                self.filename = self.url[5:self.url.rfind('/VIDEO_TS/')]
                self.info = util.mediainfo.get(self.filename)
                self.files = FileInformation()
                self.name = self.info['title:filename']
                if not self.name:
                    self.name = util.getname(self.filename)
                self.files.append(self.filename)
            elif self.url.rfind('.iso') + 4 == self.url.rfind('/'):
                # iso
                self.filename = self.url[5:self.url.rfind('/')]
            else:
                self.filename = ''

        elif url.endswith('.iso') and self.info['mime'] == 'video/dvd':
            self.mimetype = 'dvd'
            self.mode = 'dvd'
            self.__dict__['url'] = 'dvd' + self.url[4:] + '/'

        # cover image
        if not self.image or (self.parent and self.image == self.parent.image):
            image = vfs.getoverlay(self.filename + '.raw')
            if os.path.exists(image):
                self.image = image
                self.files.image = image

        # do a new player rating based on the new url
        self.rating()

    def rating(self):
        """
        Calculate a new player rating for this item.

        The decision which player to use for a VideoItem is based on this
        rating.  First each player plugins is asked for a rate, on how good it
        can play this VideoItem. There are three possible rates: good (=2),
        possible (=1) and unplayable(=0). This rate is then weighted by a
        factor of ten.  Next the user's choice of prefered players is checked.
        The user can define a rank list of players with the variable
        VIDEO_PREFERED_PLAYER in local_conf.py. The rank that is calculated
        from this config variable is then added to the current rate. Last but
        not least there is the possibility that for some reason the use of a
        special player is forced.  In that case a value of 100 is added to the
        rate.

        In the end a sorted list of possible_players is created. All players in
        this list have a rating for this special VideoItem of not less than 10.
        The first one is the default one, the others are offered to the user as
        choices in the "Alternate Player" menu.
        """
        # create a new player rating
        self.possible_players = []
        self.player = None
        self.player_rating = 0
        # some debug info
        try:
            logger.log(9, 'rating: url=%r', self.url)
            logger.log(9, 'rating: mode=%r', self.mode)
            logger.log(9, 'rating: mimetype=%r', self.mimetype)
            logger.log(9, 'rating: network_play=%r', self.network_play)
        except Exception, e:
            print 'videoitem.py: %s' % e
        for p in plugin.getbyname(plugin.VIDEO_PLAYER, True):
            rating = p.rate(self) * 10
            if p.name in config.VIDEO_PREFERED_PLAYER:
                # do we have a rank list for all possible players?
                if type(config.VIDEO_PREFERED_PLAYER) in [list, tuple]:
                    # get the rank of this player
                    rank = config.VIDEO_PREFERED_PLAYER.index(p.name)
                    # lower index means higher rank, therefor more calculations
                    rank = len(config.VIDEO_PREFERED_PLAYER) - rank
                    # finally increade the rating
                    rating += rank
                else:  # it is more simple if just one player is prefered
                    rating += 1
            if hasattr(self, 'force_player') and p.name == self.force_player:
                rating += 100
            if (rating, p) not in self.possible_players:
                self.possible_players += [(rating, p)]
        # just use players with a rating of at last 10
        self.possible_players = filter(lambda l: l[0] >= 10,
                                       self.possible_players)
        # sort the players in the order of the rating
        self.possible_players.sort(lambda l, o: -cmp(l[0], o[0]))
        if len(self.possible_players) > 0:
            # choose the best player as default player
            self.player_rating, self.player = self.possible_players[0]
        logger.log(9, "rating: url=%r possible_players=%r", self.url,
                   self.possible_players)
Beispiel #6
0
    def __init__(self,
                 directory,
                 parent,
                 name='',
                 display_type=None,
                 add_args=None,
                 create_metainfo=True):
        self.autovars = [('num_dir_items', 0), ('show_all_items', False)]
        Playlist.__init__(self, parent=parent, display_type=display_type)
        self.type = 'dir'
        self.menu = None

        # store FileInformation for moving/copying
        self.files = FileInformation()
        if self.media:
            self.files.read_only = True
        self.files.append(directory)

        self.dir = os.path.abspath(directory)
        self.info = mediainfo.get_dir(directory)

        #FIXME This should be done in the cache create
        if not self.image:
            mminfo = mmpython.parse(directory)
            if mminfo:
                if mminfo['image']:
                    self.image = mminfo['image']
                if mminfo['title']:
                    self.title = mminfo['title']
                if mminfo['comment']:
                    self.comment = mminfo['comment']

        if name:
            self.name = Unicode(name)
        elif self.info['title:filename']:
            self.name = self.info['title:filename']
        elif self.info['title']:
            self.name = self.info['title']
        else:
            self.name = util.getname(directory, skip_ext=False)

        if add_args == None and hasattr(parent, 'add_args'):
            add_args = parent.add_args

        self.add_args = add_args

        if self.parent and hasattr(parent, 'skin_display_type'):
            self.skin_display_type = parent.skin_display_type
        elif parent:
            self.skin_display_type = parent.display_type
        else:
            self.skin_display_type = display_type

        if self['show_all_items']:
            self.display_type = None

        # set tv to video now
        if self.display_type == 'tv':
            display_type = 'video'

        # set directory variables to default
        global all_variables
        self.all_variables = copy.copy(all_variables)

        # Check mimetype plugins if they want to add something
        for p in plugin.mimetype(display_type):
            self.all_variables += p.dirconfig(self)

        # set the variables to the default values
        for var in self.all_variables:
            if hasattr(parent, var[0]):
                setattr(self, var[0], getattr(parent, var[0]))
            elif hasattr(config, var[0]):
                setattr(self, var[0], getattr(config, var[0]))
            else:
                setattr(self, var[0], False)

        self.modified_vars = []

        # Check for a cover in current dir
        if self.info['image']:
            image = self.info['image']
        else:
            image = util.getimage(os.path.join(directory, 'cover'))
        # if we have an image then use it
        if image:
            self.image = image
            self.files.image = image

        # Check for a folder.fxd in current dir
        self.folder_fxd = directory + '/folder.fxd'
        if vfs.isfile(self.folder_fxd):
            self.set_fxd_file(self.folder_fxd)

        # Check mimetype plugins if they want to add something
        for p in plugin.mimetype(display_type):
            p.dirinfo(self)

        if self.DIRECTORY_SORT_BY_DATE == 2 and self.display_type != 'tv':
            self.DIRECTORY_SORT_BY_DATE = 0

        # create some extra info
        if create_metainfo:
            self.create_metainfo()
Beispiel #7
0
class DirItem(Playlist):
    """
    class for handling directories
    """
    def __init__(self,
                 directory,
                 parent,
                 name='',
                 display_type=None,
                 add_args=None,
                 create_metainfo=True):
        self.autovars = [('num_dir_items', 0), ('show_all_items', False)]
        Playlist.__init__(self, parent=parent, display_type=display_type)
        self.type = 'dir'
        self.menu = None

        # store FileInformation for moving/copying
        self.files = FileInformation()
        if self.media:
            self.files.read_only = True
        self.files.append(directory)

        self.dir = os.path.abspath(directory)
        self.info = mediainfo.get_dir(directory)

        #FIXME This should be done in the cache create
        if not self.image:
            mminfo = mmpython.parse(directory)
            if mminfo:
                if mminfo['image']:
                    self.image = mminfo['image']
                if mminfo['title']:
                    self.title = mminfo['title']
                if mminfo['comment']:
                    self.comment = mminfo['comment']

        if name:
            self.name = Unicode(name)
        elif self.info['title:filename']:
            self.name = self.info['title:filename']
        elif self.info['title']:
            self.name = self.info['title']
        else:
            self.name = util.getname(directory, skip_ext=False)

        if add_args == None and hasattr(parent, 'add_args'):
            add_args = parent.add_args

        self.add_args = add_args

        if self.parent and hasattr(parent, 'skin_display_type'):
            self.skin_display_type = parent.skin_display_type
        elif parent:
            self.skin_display_type = parent.display_type
        else:
            self.skin_display_type = display_type

        if self['show_all_items']:
            self.display_type = None

        # set tv to video now
        if self.display_type == 'tv':
            display_type = 'video'

        # set directory variables to default
        global all_variables
        self.all_variables = copy.copy(all_variables)

        # Check mimetype plugins if they want to add something
        for p in plugin.mimetype(display_type):
            self.all_variables += p.dirconfig(self)

        # set the variables to the default values
        for var in self.all_variables:
            if hasattr(parent, var[0]):
                setattr(self, var[0], getattr(parent, var[0]))
            elif hasattr(config, var[0]):
                setattr(self, var[0], getattr(config, var[0]))
            else:
                setattr(self, var[0], False)

        self.modified_vars = []

        # Check for a cover in current dir
        if self.info['image']:
            image = self.info['image']
        else:
            image = util.getimage(os.path.join(directory, 'cover'))
        # if we have an image then use it
        if image:
            self.image = image
            self.files.image = image

        # Check for a folder.fxd in current dir
        self.folder_fxd = directory + '/folder.fxd'
        if vfs.isfile(self.folder_fxd):
            self.set_fxd_file(self.folder_fxd)

        # Check mimetype plugins if they want to add something
        for p in plugin.mimetype(display_type):
            p.dirinfo(self)

        if self.DIRECTORY_SORT_BY_DATE == 2 and self.display_type != 'tv':
            self.DIRECTORY_SORT_BY_DATE = 0

        # create some extra info
        if create_metainfo:
            self.create_metainfo()

    def __str__(self):
        s = pformat(self, depth=2)
        return s

    def __repr__(self):
        if hasattr(self, 'name'):
            s = '<%s: %r>' % (self.name, self.__class__)
        else:
            s = '<%r>' % (self.__class__)
        return s

    def set_fxd_file(self, file):
        """
        Set self.folder_fxd and parse it
        """
        self.folder_fxd = file
        if self.folder_fxd and vfs.isfile(self.folder_fxd):
            if self.display_type == 'tv':
                display_type = 'video'
            try:
                parser = util.fxdparser.FXD(self.folder_fxd)
                parser.set_handler('folder', self.read_folder_fxd)
                parser.set_handler('skin', self.read_folder_fxd)
                parser.parse()
            except:
                print "fxd file %s corrupt" % self.folder_fxd
                traceback.print_exc()

    def read_folder_fxd(self, fxd, node):
        """
        parse the xml file for directory settings::

            <?xml version="1.0" ?>
            <freevo>
                <folder title="Incoming TV Shows" cover-img="foo.jpg">
                    <setvar name="directory_autoplay_single_item" val="0"/>
                    <info>
                        <content>Episodes for current tv shows not seen yet</content>
                    </info>
                </folder>
            </freevo>
        """
        if node.name == 'skin':
            self.skin_fxd = self.folder_fxd
            return

        # read attributes
        self.name = Unicode(fxd.getattr(node, 'title', self.name))

        image = fxd.childcontent(node, 'cover-img')
        if image and vfs.isfile(os.path.join(self.dir, image)):
            self.image = os.path.join(self.dir, image)

        # parse <info> tag
        fxd.parse_info(fxd.get_children(node, 'info', 1), self, {
            'description': 'content',
            'content': 'content'
        })

        for child in fxd.get_children(node, 'setvar', 1):
            # <setvar name="directory_smart_sort" val="1"/>
            for v, n, d, type_list in self.all_variables:
                if child.attrs[('', 'name')].upper() == v.upper():
                    if type_list:
                        if int(child.attrs[('', 'val')]):
                            setattr(self, v, [self.display_type])
                        else:
                            setattr(self, v, [])
                    else:
                        try:
                            setattr(self, v, int(child.attrs[('', 'val')]))
                        except ValueError:
                            setattr(self, v, child.attrs[('', 'val')])
                    self.modified_vars.append(v)

    def __is_type_list_var__(self, var):
        """
        return if this variable to be saved is a type_list
        """
        for v, n, d, type_list in self.all_variables:
            if v == var:
                return type_list
        return False

    def write_folder_fxd(self, fxd, node):
        """
        callback to save the modified fxd file
        """
        # remove old setvar
        for child in copy.copy(node.children):
            if child.name == 'setvar':
                node.children.remove(child)

        # add current vars as setvar
        for v in self.modified_vars:
            if self.__is_type_list_var__(v):
                if getattr(self, v):
                    val = 1
                else:
                    val = 0
            else:
                val = getattr(self, v)
            fxd.add(fxd.XMLnode('setvar', (('name', v.lower()), ('val', val))),
                    node, 0)

    def __getitem__(self, key):
        """
        return the specific attribute
        """
        if key == 'type':
            if self.media and hasattr(self.media, 'label'):
                return _('Directory on disc [%s]') % self.media.label
            return _('Directory')

        if key == 'num_items':
            display_type = self.display_type or 'all'
            if self.display_type == 'tv':
                display_type = 'video'
            return self['num_%s_items' % display_type] + self['num_dir_items']

        if key == 'num_play_items':
            display_type = self.display_type
            if self.display_type == 'tv':
                display_type = 'video'
            return self['num_%s_items' % display_type]

        if key in ('freespace', 'totalspace'):
            if self.media:
                return None

            space = getattr(util, key)(self.dir) / 1000000
            if space > 1000:
                space = '%s,%s' % (space / 1000, space % 1000)
            return space

        return Item.__getitem__(self, key)

    # eventhandler for this item
    def eventhandler(self, event, menuw=None):
        if event == DIRECTORY_CHANGE_DISPLAY_TYPE and menuw.menustack[
                -1] == self.menu:
            possible_display_types = []

            for p in plugin.get('mimetype'):
                for t in p.display_type:
                    if not t in possible_display_types:
                        possible_display_types.append(t)

            try:
                pos = possible_display_types.index(self.display_type)
                type = possible_display_types[(pos + 1) %
                                              len(possible_display_types)]

                menuw.delete_menu(allow_reload=False)

                newdir = DirItem(self.dir, self.parent, self.name, type,
                                 self.add_args)
                newdir.DIRECTORY_AUTOPLAY_SINGLE_ITEM = False
                newdir.cwd(menuw=menuw)

                menuw.menustack[-2].selected = newdir
                pos = menuw.menustack[-2].choices.index(self)
                menuw.menustack[-2].choices[pos] = newdir
                rc.post_event(Event(OSD_MESSAGE, arg='%s view' % type))
                return True
            except (IndexError, ValueError):
                pass

        return Playlist.eventhandler(self, event, menuw)

    # ======================================================================
    # metainfo
    # ======================================================================

    def create_metainfo(self):
        """
        create some metainfo for the directory
        """
        display_type = self.display_type

        if self.display_type == 'tv':
            display_type = 'video'

        name = display_type or 'all'

        # check autovars
        for var, val in self.autovars:
            if var == 'num_%s_timestamp' % name:
                break
        else:
            self.autovars += [('num_%s_timestamp' % name, 0),
                              ('num_%s_items' % name, 0)]

        try:
            timestamp = os.stat(self.dir)[stat.ST_MTIME]
        except OSError:
            return

        num_timestamp = self.info['num_%s_timestamp' % name]

        if not num_timestamp or num_timestamp < timestamp:
            _debug_('create metainfo for %s', self.dir)
            need_umount = False
            if self.media:
                need_umount = not self.media.is_mounted()
                self.media.mount()

            num_dir_items = 0
            num_play_items = 0
            files = vfs.listdir(self.dir, include_overlay=True)

            # play items and playlists
            for p in plugin.mimetype(display_type):
                num_play_items += p.count(self, files)

            # normal DirItems
            for filename in files:
                if os.path.isdir(filename):
                    num_dir_items += 1

            # store info
            if num_play_items != self['num_%s_items' % name]:
                self['num_%s_items' % name] = num_play_items
            if self['num_dir_items'] != num_dir_items:
                self['num_dir_items'] = num_dir_items
            self['num_%s_timestamp' % name] = timestamp

            if need_umount:
                self.media.umount()

    # ======================================================================
    # actions
    # ======================================================================

    def actions(self):
        """
        return a list of actions for this item
        """
        if self.media:
            self.media.mount()

        display_type = self.display_type
        if self.display_type == 'tv':
            display_type = 'video'

        items = [(self.cwd, _('Browse directory'))]

        if self['num_%s_items' % display_type]:
            items.append((self.play, _('Play all files in directory')))

        if display_type in self.DIRECTORY_AUTOPLAY_ITEMS and not self[
                'num_dir_items']:
            items.reverse()

        if self['num_%s_items' % display_type]:
            items.append((self.play_random, _('Random play all items')))
        if self['num_dir_items']:
            items += [(self.play_random_recursive,
                       _('Recursive random play all items')),
                      (self.play_recursive, _('Recursive play all items'))]

        items.append((self.configure, _('Configure directory'), 'configure'))

        if self.folder_fxd:
            items += fxditem.mimetype.get(self, [self.folder_fxd])

        if self.media:
            self.media.umount()

        return items

    def cwd(self, arg=None, menuw=None):
        """
        browse directory
        """
        self.check_password_and_build(arg=None, menuw=menuw)

    def play(self, arg=None, menuw=None):
        """
        play directory
        """
        if arg == 'next':
            Playlist.play(self, arg=arg, menuw=menuw)
        else:
            self.check_password_and_build(arg='play', menuw=menuw)

    def play_random(self, arg=None, menuw=None):
        """
        play in random order
        """
        self.check_password_and_build(arg='playlist:random', menuw=menuw)

    def play_recursive(self, arg=None, menuw=None):
        """
        play recursive
        """
        self.check_password_and_build(arg='playlist:recursive', menuw=menuw)

    def play_random_recursive(self, arg=None, menuw=None):
        """
        play recursive in random order
        """
        self.check_password_and_build(arg='playlist:random_recursive',
                                      menuw=menuw)

    def check_password_and_build(self, arg=None, menuw=None):
        """
        password checker
        """
        if not self.menuw:
            self.menuw = menuw

        # are we on a ROM_DRIVE and have to mount it first?
        for media in config.REMOVABLE_MEDIA:
            if self.dir.find(media.mountdir) == 0:
                util.mount(self.dir)
                self.media = media

        if vfs.isfile(self.dir + '/.password'):
            print 'password protected dir'
            self.arg = arg
            self.menuw = menuw
            pb = InputBox(text=_('Enter Password'),
                          handler=self.pass_cmp_cb,
                          type='password')
            pb.show()
        else:
            self.build(arg=arg, menuw=menuw)

    def pass_cmp_cb(self, word=None):
        """
        read the contents of self.dir/.passwd and compare to word
        callback for check_password_and_build
        """
        try:
            pwfile = vfs.open(self.dir + '/.password')
            line = pwfile.readline()
        except IOError, e:
            print 'error %d (%s) reading password file for %s' % \
                  (e.errno, e.strerror, self.dir)
            return

        pwfile.close()
        password = line.strip()
        if word == password:
            self.build(self.arg, self.menuw)
        else:
            pb = AlertBox(text=_('Password incorrect'))
            pb.show()
            return
Beispiel #8
0
class VideoItem(Item):
    """
    A class describing a video item.

    @ivar autovars: a list of variables.
    @ivar type: the item type, video for this item.
    @ivar variants: a list of audio variants.
    @ivar subitems: a list of files or tracks to play.
    @ivar current_subitem: the current video item.
    @ivar media_id: media id when the item is on removable media
    @ivar subtitle_file: file name of a file containing subtitles.
    @ivar audio_file: file name of a file containing audio.
    @ivar mplayer_options: additional options for mplayer.
    @ivar tv_show: if the item is a tv programme.
    @ivar video_width: width of the video.
    @ivar video_height: height of the video.
    @ivar selected_subtitle: current subtitle track.
    @ivar selected_audio: current audio track.
    @ivar elapsed: seconds that the item has played.
    @ivar possible_players: a list of possible players.
    @ivar player: current player.
    @ivar player_rating: rating of the current player.
    """

    def __init__(self, url, parent, info=None, parse=True):
        """
        Create an instance of a VideoItem

        @param url: the pysudo URL for the VideoItem
        @param parent: the parent of the VideoItem
        @param info: controls if additional information is found
        @type info: boolean
        @param parse: controls if the url is parsed
        @type parse: boolean
        """
        self.autovars          = []
        Item.__init__(self, parent)
        self.type              = 'video'
        self.variants          = []
        self.subitems          = []
        self.current_subitem   = None
        self.media_id          = ''

        self.subtitle_file     = {}
        self.audio_file        = {}

        self.mplayer_options   = ''
        self.tv_show           = False

        self.video_width       = 0
        self.video_height      = 0

        self.selected_subtitle = None
        self.selected_audio    = None
        self.elapsed           = 0

        self.possible_players  = []
        self.player            = None
        self.player_rating     = 0

        # set the url (this influences the list of possible players!)
        self.set_url(url, info=parse)
        if info:
            self.info.set_variables(info)

        if parse:
            self.name = self.parse_name(self.name)

        # deinterlacing and related things
        video_deinterlace = config.VIDEO_DEINTERLACE != None and config.VIDEO_DEINTERLACE or False
        self['deinterlace'] = video_deinterlace

        video_use_xvmc = config.VIDEO_USE_XVMC != None and config.VIDEO_USE_XVMC or False
        self['xvmc'] = video_use_xvmc

        video_field_dominance = config.VIDEO_FIELD_DOMINANCE != None and config.VIDEO_FIELD_DOMINANCE or False
        self['field-dominance'] = video_field_dominance

        # extra info in discset_information
        if parent and parent.media:
            fid = String(parent.media.id) + self.filename[len(os.path.join(parent.media.mountdir,'')):]
            from video import discset_information
            if discset_information.has_key(fid):
                self.mplayer_options = discset_information[fid]

        if config.VIDEO_DEINTERLACE and self.info['interlaced']:
            # force deinterlacing
            self['deinterlace'] = True
        else:
            self['deinterlace'] = False



    def parse_name(self, name):        
        # find image for tv show and build new name
        if config.VIDEO_SHOW_REGEXP_MATCH(name) and not self.network_play:

            show_name = config.VIDEO_SHOW_REGEXP_SPLIT(name)

            if show_name[0] and show_name[1] and show_name[2]:

                ep   = config.IMDB_SEASON_EPISODE_FORMAT % (int(show_name[1]), int(show_name[2]))
                name = '%s %s %s' % (show_name[0], ep, show_name[3])

                if config.VIDEO_SHOW_DATA_DIR:
                    image = util.getimage((config.VIDEO_SHOW_DATA_DIR + show_name[0].lower()))
                    if self.filename and not image:
                        image = util.getimage(os.path.join(os.path.dirname(self.filename), show_name[0].lower()))
                    if image:
                        self.image = image

                from video import tv_show_information
                if tv_show_information.has_key(show_name[0].lower()):
                    tvinfo = tv_show_information[show_name[0].lower()]
                    self.info.set_variables(tvinfo[1])
                    if not self.image:
                        self.image = tvinfo[0]
                    self.skin_fxd = tvinfo[3]
                    self.mplayer_options = tvinfo[2]

                self.tv_show          = True
                self.show_name        = show_name
                self.subtitle         = '%s - Season %s' % (show_name[0], show_name[1])
                self.tv_show_name     = show_name[0]
                self.tv_show_season   = show_name[1]
                self.tv_show_episode  = show_name[2]
                self.tv_show_title    = show_name[3]

        if not hasattr(self, 'subtitle') or not self.subtitle:
            self.subtitle = self.parent['title']

        self.title = name
        return self.format_name(name)


    def format_name(self, name):
        """ Return a formatted string for use in item.py """
        # Since we can't specify the length of the integer in the
        # format string (Python doesn't seem to recognize it) we
        # strip it out first, when we see the only thing that can be
        # a number.

        if name and config.DIRECTORY_VIDEO_MENU_TABLE:
            if self.tv_show:
                video_info = {  'n'  : self.format(self.tv_show_name, name),
                                't'  : self.format(self.tv_show_title, ''),
                                'e'  : self.format(int(self.tv_show_episode), 0, '%0.2d'),
                                's'  : self.format(int(self.tv_show_season), 0, '%d'),
                                'r'  : self['length'],
                                'f'  : self['name'],
                             }
            else:
                video_info = {  'n'  : name,
                                't'  : self['title'],
                                'e'  : '',
                                's'  : '',
                                'r'  : self['length'],
                                'f'  : self['name'],
                             }

            if hasattr(self.parent, 'DIRECTORY_VIDEO_FORMAT_STRING'):
                formatstring = unicode(self.parent.DIRECTORY_VIDEO_FORMAT_STRING)
            else:
                formatstring = unicode(config.DIRECTORY_VIDEO_FORMAT_STRING)
 
            formatted_info = formatstring % video_info

            logger.log(9, 'formatted_info=%r', formatted_info)
 
            # check if the video info was not empty
            if formatted_info != (formatstring % { 'n' : '', 't' : '', 'e' : '', 's' : '', 'r' : '', 'f' : '' }):
                return formatted_info.strip()

        # fallback to current video name
        if self.name:
            return self.name

        # last fallback: return filename
        return os.path.split(self.filename)[1]


    def __str__(self):
        """
        Create a string for a VideoItem instance.
        @returns: string representation
        """
        s = pformat(self, depth=2)
        return s


    def __repr__(self):
        """
        Create a raw string for a VideoItem instance.
        @returns: string representation
        """
        if hasattr(self, 'name'):
            s = '%s: %r' % (self.name, self.__class__)
        else:
            s = '%r' % (self.__class__)
        return s


    def set_url(self, url, info=True):
        """
        Sets a new url to the item. This functions also changes other
        attributes, like file name, mode, network_play and the list of possible
        players.

        B{WARNING}: This is called whenever self.url is set, therefore it is
        strictly forbidden to set self.url directly in this function, (infinite
        recursion!). Use self.__dict__['url'] instead!
        """
        Item.set_url(self, url, info)

        # additional types of urls
        if url.startswith('dvd://') or url.startswith('vcd://'):
            self.network_play = False
            self.mimetype = self.url[:self.url.find('://')].lower()
            if self.url.find('/VIDEO_TS/') > 0:
                # dvd on harddisc
                self.filename = self.url[5:self.url.rfind('/VIDEO_TS/')]
                self.info     = util.mediainfo.get(self.filename)
                self.files    = FileInformation()
                self.name     = self.info['title:filename']
                if not self.name:
                    self.name = util.getname(self.filename)
                self.files.append(self.filename)
            elif self.url.rfind('.iso') + 4 == self.url.rfind('/'):
                # iso
                self.filename = self.url[5:self.url.rfind('/')]
            else:
                self.filename = ''

        elif url.endswith('.iso') and self.info['mime'] == 'video/dvd':
            self.mimetype = 'dvd'
            self.mode     = 'dvd'
            self.__dict__['url'] = 'dvd' + self.url[4:] + '/'

        # cover image
        if not self.image or (self.parent and self.image == self.parent.image):
            image = vfs.getoverlay(self.filename + '.raw')
            if os.path.exists(image):
                self.image = image
                self.files.image = image

        # do a new player rating based on the new url
        self.rating()


    def rating(self):
        """
        Calculate a new player rating for this item.

        The decision which player to use for a VideoItem is based on this
        rating.  First each player plugins is asked for a rate, on how good it
        can play this VideoItem. There are three possible rates: good (=2),
        possible (=1) and unplayable(=0). This rate is then weighted by a
        factor of ten.  Next the user's choice of prefered players is checked.
        The user can define a rank list of players with the variable
        VIDEO_PREFERED_PLAYER in local_conf.py. The rank that is calculated
        from this config variable is then added to the current rate. Last but
        not least there is the possibility that for some reason the use of a
        special player is forced.  In that case a value of 100 is added to the
        rate.

        In the end a sorted list of possible_players is created. All players in
        this list have a rating for this special VideoItem of not less than 10.
        The first one is the default one, the others are offered to the user as
        choices in the "Alternate Player" menu.
        """
        # create a new player rating
        self.possible_players =[]
        self.player = None
        self.player_rating = 0
        # some debug info
        try:
            logger.log( 9, 'rating: url=%r', self.url)
            logger.log( 9, 'rating: mode=%r', self.mode)
            logger.log( 9, 'rating: mimetype=%r', self.mimetype)
            logger.log( 9, 'rating: network_play=%r', self.network_play)
        except Exception, e:
            print 'videoitem.py: %s' %e
        for p in plugin.getbyname(plugin.VIDEO_PLAYER, True):
            rating = p.rate(self) * 10
            if p.name in config.VIDEO_PREFERED_PLAYER:
                # do we have a rank list for all possible players?
                if type(config.VIDEO_PREFERED_PLAYER) in [list, tuple]:
                    # get the rank of this player
                    rank = config.VIDEO_PREFERED_PLAYER.index(p.name)
                    # lower index means higher rank, therefor more calculations
                    rank = len(config.VIDEO_PREFERED_PLAYER)-rank
                    # finally increade the rating
                    rating += rank
                else: # it is more simple if just one player is prefered
                    rating +=1
            if hasattr(self, 'force_player') and p.name == self.force_player:
                rating += 100
            if (rating, p) not in self.possible_players:
                self.possible_players += [(rating, p)]
        # just use players with a rating of at last 10
        self.possible_players = filter(lambda l: l[0] >= 10, self.possible_players)
        # sort the players in the order of the rating
        self.possible_players.sort(lambda l, o: -cmp(l[0], o[0]))
        if len(self.possible_players) > 0:
            # choose the best player as default player
            self.player_rating, self.player = self.possible_players[0]
        logger.log( 9, "rating: url=%r possible_players=%r", self.url, self.possible_players)
Beispiel #9
0
def parse_movie(fxd, node):
    """
    Callback for VideoItem <movie>::

        <movie title>
            <cover-img>file</cover-img>
            <video mplayer-options>
                <dvd|vcd|file id name media_id mplayer-options>file</>+
            <variants>
                <variant>
                    <part ref mplayer-options>
                        <subtitle media_id>file</subtitle>
                        <audio media_id>file</audio>
                    </part>+
                </variant>+
            </variants>
            <info/>
        </movie>
    """

    files = []

    def parse_video_child(fxd, node, dirname):
        """
        parse a subitem from <video>
        """
        filename   = String(fxd.gettext(node))
        media_id   = fxd.getattr(node, 'media-id')
        mode       = node.name
        id         = fxd.getattr(node, 'id')
        options    = fxd.getattr(node, 'mplayer-options')
        player     = fxd.childcontent(node, 'player')
        playlist   = fxd.get_children(node, 'playlist') and True or False

        if mode == 'file':
            if not media_id:
                filename = os.path.join(dirname, filename)
                if vfs.isoverlay(filename):
                    filename = vfs.normalize(filename)
            if filename and not filename in files:
                files.append(filename)
        if mode == 'url':
            return id, filename, media_id, options, player, playlist
        return id, String('%s://%s' % (String(mode), String(filename))), \
               media_id, options, player, playlist


    item = VideoItem('', fxd.getattr(None, 'parent', None), parse=False)

    dirname  = os.path.dirname(fxd.filename)
    image      = ''
    title      = fxd.getattr(node, 'title')
    item.name  = title
    item.image = fxd.childcontent(node, 'cover-img')
    if item.image:
        try:
            item.image = vfs.abspath(os.path.join(dirname, str(item.image)))
        except UnicodeEncodeError:
            logger.debug('os.path.join(dirname=%r, item.image=%r)', dirname, item.image)
            raise
        image = item.image

    fxd.parse_info(node, item, {'runtime': 'length'})

    video = fxd.get_children(node, 'video')
    if video:
        mplayer_options = fxd.getattr(video[0], 'mplayer-options')
        video = fxd.get_children(video[0], 'file') + \
                fxd.get_children(video[0], 'vcd') + \
                fxd.get_children(video[0], 'dvd') + \
                fxd.get_children(video[0], 'url')

    variants = fxd.get_children(node, 'variants')
    if variants:
        variants = fxd.get_children(variants[0], 'variant')

    if variants:
        # a list of variants
        id = {}
        for v in video:
            video_child = parse_video_child(fxd, v, dirname)
            id[video_child[0]] = video_child

        for variant in variants:
            mplayer_options += " " + fxd.getattr(variant, 'mplayer-options');
            parts = fxd.get_children(variant, 'part')
            if len(parts) == 1:
                # a variant with one file
                ref = fxd.getattr(parts[0] ,'ref')
                v = VideoItem(id[ref][1], parent=item, info=item.info, parse=False)
                v.files = None
                v.media_id, v.mplayer_options, player, is_playlist = id[ref][2:]
                if player:
                    v.force_player = player
                if is_playlist:
                    v.is_playlist  = True

                audio = fxd.get_children(parts[0], 'audio')
                if audio:
                    audio = { 'media_id': fxd.getattr(audio[0], 'media-id'),
                              'file'    : fxd.gettext(audio[0]) }
                    if not audio['media_id']:
                        audio['file'] = os.path.join(dirname, audio['file'])
                else:
                    audio = {}
                v.audio_file = audio

                subtitle = fxd.get_children(parts[0], 'subtitle')
                if subtitle:
                    subtitle = { 'media_id': fxd.getattr(subtitle[0], 'media-id'),
                                 'file'    : fxd.gettext(subtitle[0]) }
                    if not subtitle['media_id']:
                        subtitle['file'] = os.path.join(dirname, subtitle['file'])
                else:
                    subtitle = {}
                v.subtitle_file = subtitle

                # global <video> mplayer_options
                if mplayer_options:
                    v.mplayer_options += mplayer_options
            else:
                # a variant with a list of files
                v = VideoItem('', parent=item, info=item.info, parse=False)
                for p in parts:
                    ref = fxd.getattr(p ,'ref')
                    audio    = fxd.get_children(p, 'audio')
                    subtitle = fxd.get_children(p, 'subtitle')

                    if audio:
                        audio = { 'media_id': fxd.getattr(audio[0], 'media-id'),
                                  'file'    : fxd.gettext(audio[0]) }
                        if not audio['media_id']:
                            audio['file'] = os.path.join(dirname, audio['file'])
                    else:
                        audio = {}

                    if subtitle:
                        subtitle = { 'media_id': fxd.getattr(subtitle[0], 'media-id'),
                                     'file'    : fxd.gettext(subtitle[0]) }
                        if not subtitle['media_id']:
                            subtitle['file'] = os.path.join(dirname, subtitle['file'])
                    else:
                        subtitle = {}

                    sub = VideoItem(id[ref][1], parent=v, info=item.info, parse=False)
                    sub.files = None
                    sub.media_id, sub.mplayer_options, player, is_playlist = id[ref][2:]
                    sub.subtitle_file = subtitle
                    sub.audio_file    = audio
                    # global <video> mplayer_options
                    if mplayer_options:
                        sub.mplayer_options += mplayer_options
                    v.subitems.append(sub)

            v.name = fxd.getattr(variant, 'name')
            item.variants.append(v)

    else:
        # one or more files, this is directly for the item

        try:
            id, url, item.media_id, item.mplayer_options, player, is_playlist = parse_video_child(
                fxd, video[0], dirname)
        except (IndexError, TypeError), why:
            logger.warning('%r is corrupt', fxd.filename)
            raise
        if url.startswith('file://') and os.path.isfile(url[7:]):
            variables = item.info.get_variables()
            item.set_url(url, info=True)
            item.info.set_variables(variables)
        elif url.startswith('file://') and os.path.isdir(url[7:]):
            # dvd dir
            variables = item.info.get_variables()
            item.set_url(url.replace('file://', 'dvd:/')+ '/VIDEO_TS/', info=True)
            item.info.set_variables(variables)
        else:
            item.set_url(url, info=False)
        if title:
            item.name = title
        if player:
            item.force_player = player
        if is_playlist:
            item.is_playlist  = True
        if len(video) == 1:
            # global <video> mplayer_options
            if mplayer_options:
                item.mplayer_options += mplayer_options

        # if there is more than one item add them to subitems
        if len(video) > 1:
            # a list of files
            subitem_matched = False
            for s in video:
                #id, url, item.media_id, mplayer_options, player, is_playlist = parse_video_child(fxd, s, dirname)
                video_child = parse_video_child(fxd, s, dirname)
                url = video_child[1]

                v = VideoItem(url, parent=item, info=item.info, parse=False)

                if url.startswith('file://'):
                    v.files = FileInformation()

                    v.files.append(url[7:])
                    if url == item.url and not subitem_matched:
                        subitem_matched = True
                        v.files.fxd_file  = fxd.filename
                        if item.image:
                            v.files.image = item.image
                else:
                    v.files = None

                v.media_id, v.mplayer_options, player, is_playlist = video_child[2:]
                if player:
                    v.force_player = player
                if is_playlist:
                    item.is_playlist = True
                # global <movie> mplayer_options
                if mplayer_options:
                    v.mplayer_options += ' ' + mplayer_options
                item.subitems.append(v)
Beispiel #10
0
                            v.files.image = item.image
                else:
                    v.files = None

                v.media_id, v.mplayer_options, player, is_playlist = video_child[2:]
                if player:
                    v.force_player = player
                if is_playlist:
                    item.is_playlist = True
                # global <movie> mplayer_options
                if mplayer_options:
                    v.mplayer_options += ' ' + mplayer_options
                item.subitems.append(v)

    if not hasattr(item, 'files') or not item.files:
        item.files = FileInformation()
    item.files.files     = files

    item.files.fxd_file  = fxd.filename
    if image:
        item.files.image = image

    # remove them from the filelist (if given)
    duplicates = fxd.getattr(None, 'duplicate_check', [])
    for f in files:
        try:
            duplicates.remove(f)
        except:
            pass

    if fxd.is_skin_fxd: