예제 #1
0
class VideoItem(Item):
    def __init__(self, url, parent, info=None, parse=True):
        self.autovars = [('deinterlace', 0)]
        Item.__init__(self, parent)

        self.type = 'video'
        self.set_url(url, info=parse)

        if info:
            self.info.set_variables(info)

        self.variants = []  # if this item has variants
        self.subitems = []  # more than one file/track to play
        self.current_subitem = None
        self.media_id = ''

        self.subtitle_file = {}  # text subtitles
        self.audio_file = {}  # audio dubbing

        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_player = []

        self.player = None
        self.player_rating = 0

        # 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.dirname(self.filename) + '/' + \
                                          show_name[0].lower())

                if image:
                    self.image = image

                from video import tv_show_informations
                if tv_show_informations.has_key(show_name[0].lower()):
                    tvinfo = tv_show_informations[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 infos in discset_informations
        if parent and parent.media:
            fid = parent.media.id + \
                  self.filename[len(os.path.join(parent.media.mountdir,'')):]
            from video import discset_informations
            if discset_informations.has_key(fid):
                self.mplayer_options = discset_informations[fid]

    def __str__(self):
        s = '\nvideo:videoitem:VideoItem:Info:s:'
        s += ' name=%r' % self.name
        s += ' filename=%r' % self.filename
        s += ' dir(self)=%r' % dir(self)
        return s

    def __repr__(self):
        s = '\nvideo:videoitem:VideoItem:Info:r:'
        s += ' name=%r' % self.name
        s += ' filename=%r' % self.filename
        #s += ' dir(self)=%r' % dir(self)
        return s

    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

    def id(self):
        """
        Return a unique id of the item. This id should be the same when the
        item is rebuild later with the same informations
        """
        ret = self.url
        if self.subitems:
            for s in self.subitems:
                ret += s.id()
        if self.variants:
            for v in self.variants:
                ret += v.id()
        return ret

    def __getitem__(self, key):
        """
        return the specific attribute
        """
        if key == 'geometry' and self.info['width'] and self.info['height']:
            return '%sx%s' % (self.info['width'], self.info['height'])

        if key == 'aspect':
            aspect = None
            if self.info['aspect']:
                aspect = str(self.info['aspect'])
                aspect[:aspect.find(' ')].replace('/', ':')
            else:
                if self.info['width'] and self.info['height']:
                    aspect = util.misc.human_aspect_ratio(
                        self.info['width'], self.info['height'])

            if aspect:
                return aspect

        if key == 'runtime':
            total = 0
            length = 0

            if self.info['runtime']:
                length = self.info['runtime']
                # Assuming that runtime is always a string
                # Assume that a time 1:40 is hours:minutes
                # Not sure when a '/' is used
                p = re.compile('([0-9]+)[:/]*([0-9]*)')
                m = p.match(length)
                if m:
                    length = int(m.group(1))
                    if m.group(2):
                        length *= 60 + int(m.group(2))
                else:
                    length = 0
                total = '%s min' % str(int(length))

            if length == 0:
                if self.subitems:
                    for s in self.subitems:
                        if s.info['length']:
                            length = s.info['length']
                        if not length and hasattr(s, 'length'):
                            length = s.length
                        if not length:
                            continue
                        try:
                            total += length
                        except ValueError, TypeError:
                            pass
                    total = '%s min' % str(int(total) / 60)

                else:
                    if self.info['length']:
                        total = self.info['length']
                    elif hasattr(self, 'length'):
                        total = self.length
                    if total != 'None':
                        total = '%s min' % str(int(total) / 60)
                    else:
                        total = ''

            return total

        return Item.__getitem__(self, key)
예제 #2
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
예제 #3
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)
예제 #4
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)