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)
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
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)
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)