def load(self, root, filter_tags): # this lists our root service, then building a # nice list del self.list[:] serviceHandler = eServiceCenter.getInstance() numberOfDirs = 0 reflist = root and serviceHandler.list(root) if reflist is None: print("[MovieList] listing of movies failed") return realtags = set() autotags = {} rootPath = os.path.normpath(root.getPath()) parent = None # Don't navigate above the "root" if len(rootPath) > 1 and (os.path.realpath(rootPath) != os.path.realpath( config.movielist.root.value)): parent = os.path.split(os.path.normpath(rootPath))[0] if parent and (parent not in defaultInhibitDirs): # enigma wants an extra '/' appended if not parent.endswith('/'): parent += '/' ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + parent) ref.flags = eServiceReference.flagDirectory self.list.append((ref, None, 0, -1)) numberOfDirs += 1 if config.usage.movielist_trashcan.value: here = os.path.realpath(rootPath) MovieList.InTrashFolder = here.startswith(getTrashFolder(here)) else: MovieList.InTrashFolder = False MovieList.UsingTrashSort = False if MovieList.InTrashFolder: if (config.usage.trashsort_deltime.value == "show record time"): MovieList.UsingTrashSort = MovieList.TRASHSORT_SHOWRECORD elif (config.usage.trashsort_deltime.value == "show delete time"): MovieList.UsingTrashSort = MovieList.TRASHSORT_SHOWDELETE while True: serviceref = reflist.getNext() if not serviceref.valid(): break if config.ParentalControl.servicepinactive.value and config.ParentalControl.storeservicepin.value != "never": from Components.ParentalControl import parentalControl if not parentalControl.sessionPinCached and parentalControl.isProtected( serviceref): continue info = serviceHandler.info(serviceref) if info is None: info = justStubInfo begin = info.getInfo(serviceref, iServiceInformation.sTimeCreate) begin2 = 0 if MovieList.UsingTrashSort: f_path = serviceref.getPath() if os.path.exists(f_path): # Override with deltime for sorting if MovieList.UsingTrashSort == MovieList.TRASHSORT_SHOWRECORD: begin2 = begin # Save for later re-instatement begin = os.stat(f_path).st_ctime if serviceref.flags & eServiceReference.mustDescent: dirname = info.getName(serviceref) if not dirname.endswith( '.AppleDouble/') and not dirname.endswith( '.AppleDesktop/') and not dirname.endswith( '.AppleDB/') and not dirname.endswith( 'Network Trash Folder/' ) and not dirname.endswith('Temporary Items/'): self.list.append((serviceref, info, begin, -1)) numberOfDirs += 1 continue # convert space-separated list of tags into a set this_tags = info.getInfoString( serviceref, iServiceInformation.sTags).split(' ') name = info.getName(serviceref) # OSX put a lot of stupid files ._* everywhere... we need to skip them if name[:2] == "._": continue if this_tags == ['']: # No tags? Auto tag! this_tags = name.replace(',', ' ').replace('.', ' ').replace( '_', ' ').replace(':', ' ').split() # For auto tags, we are keeping a (tag, movies) dictionary. #It will be used later to check if movies have a complete sentence in common. for tag in this_tags: if tag in autotags: autotags[tag].append(name) else: autotags[tag] = [name] else: realtags.update(this_tags) # filter_tags is either None (which means no filter at all), or # a set. In this case, all elements of filter_tags must be present, # otherwise the entry will be dropped. if filter_tags is not None: this_tags_fullname = [" ".join(this_tags)] this_tags_fullname = set(this_tags_fullname) this_tags = set(this_tags) if not this_tags.issuperset( filter_tags) and not this_tags_fullname.issuperset( filter_tags): # print("Skipping", name, "tags=", this_tags, " filter=", filter_tags) continue if begin2 != 0: self.list.append((serviceref, info, begin, -1, begin2)) else: self.list.append((serviceref, info, begin, -1)) self.firstFileEntry = numberOfDirs self.parentDirectory = 0 self.list.sort(key=self.buildGroupwiseSortkey) # Have we had a temporary sort method override set in MovieSelectiom.py? # If so use it, remove it (it's a one-off) and set the current method so # that the "Sort by" menu can highlight it and "Sort" knows which to # move on from (both in Screens/MovieSelection.py). # try: self.current_sort = self.temp_sort del self.temp_sort except: self.current_sort = self.sort_type if MovieList.UsingTrashSort: # Same as SORT_RECORDED, but must come first... self.list = sorted(self.list[:numberOfDirs], key=self.buildBeginTimeSortKey) + sorted( self.list[numberOfDirs:], key=self.buildBeginTimeSortKey) # Having sorted on *deletion* times, re-instate any record times for # *display* if that option is set. # self.list is a list of tuples, so we can't just assign to elements... # if config.usage.trashsort_deltime.value == "show record time": for i in range(len(self.list)): if len(self.list[i]) == 5: x = self.list[i] self.list[i] = (x[0], x[1], x[4], x[3]) elif self.current_sort == MovieList.SORT_ALPHANUMERIC: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaNumericSortKey) + sorted( self.list[numberOfDirs:], key=self.buildAlphaNumericSortKey) elif self.current_sort == MovieList.SORT_ALPHANUMERIC_REVERSE: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaNumericSortKey, reverse=True) + sorted( self.list[numberOfDirs:], key=self.buildAlphaNumericSortKey, reverse=True) elif self.current_sort == MovieList.SORT_ALPHANUMERIC_FLAT: self.list.sort(key=self.buildAlphaNumericFlatSortKey) elif self.current_sort == MovieList.SORT_ALPHANUMERIC_FLAT_REVERSE: self.list.sort(key=self.buildAlphaNumericFlatSortKey, reverse=True) elif self.current_sort == MovieList.SORT_RECORDED: self.list = sorted(self.list[:numberOfDirs], key=self.buildBeginTimeSortKey) + sorted( self.list[numberOfDirs:], key=self.buildBeginTimeSortKey) elif self.current_sort == MovieList.SORT_RECORDED_REVERSE: self.list = sorted(self.list[:numberOfDirs], key=self.buildBeginTimeSortKey, reverse=True) + sorted( self.list[numberOfDirs:], key=self.buildBeginTimeSortKey, reverse=True) elif self.current_sort == MovieList.SORT_SHUFFLE: dirlist = self.list[:numberOfDirs] shufflelist = self.list[numberOfDirs:] random.shuffle(shufflelist) self.list = dirlist + shufflelist elif self.current_sort == MovieList.SORT_ALPHA_DATE_OLDEST_FIRST: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey) + sorted( self.list[numberOfDirs:], key=self.buildAlphaDateSortKey) elif self.current_sort == MovieList.SORT_ALPHAREV_DATE_NEWEST_FIRST: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey, reverse=True) + sorted( self.list[numberOfDirs:], key=self.buildAlphaDateSortKey, reverse=True) elif self.sort_type == MovieList.SORT_DURATION_ALPHA: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey) + sorted( self.list[numberOfDirs:], key=self.buildLengthAlphaSortKey) elif self.sort_type == MovieList.SORT_DURATIONREV_ALPHA: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey) + sorted( self.list[numberOfDirs:], key=self.buildLengthRevAlphaSortKey) elif self.sort_type == MovieList.SORT_SIZE_ALPHA: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey) + sorted( self.list[numberOfDirs:], key=self.buildSizeAlphaSortKey) elif self.sort_type == MovieList.SORT_SIZEREV_ALPHA: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey) + sorted( self.list[numberOfDirs:], key=self.buildSizeRevAlphaSortKey) elif self.sort_type == MovieList.SORT_DESCRIPTION_ALPHA: self.list = sorted(self.list[:numberOfDirs], key=self.buildDescrAlphaSortKey) + sorted( self.list[numberOfDirs:], key=self.buildDescrAlphaSortKey) else: self.list.sort(key=self.buildGroupwiseSortkey) for x in self.list: if x[1]: tmppath = x[1].getName(x[0])[:-1] if x[1].getName( x[0]).endswith('/') else x[1].getName(x[0]) if tmppath.endswith('.Trash'): self.list.insert(0, self.list.pop(self.list.index(x))) break if self.root and numberOfDirs > 0: rootPath = os.path.normpath(self.root.getPath()) if not rootPath.endswith('/'): rootPath += '/' if rootPath != parent: # with new sort types directories may be in between files, so scan whole # list for parentDirectory index. Usually it is the first one anyway for index, item in enumerate(self.list): if item[0].flags & eServiceReference.mustDescent: itempath = os.path.normpath(item[0].getPath()) if not itempath.endswith('/'): itempath += '/' if itempath == rootPath: self.parentDirectory = index break self.root = root # finally, store a list of all tags which were found. these can be presented # to the user to filter the list # ML: Only use the tags that occur more than once in the list OR that were # really in the tag set of some file. # reverse the dictionary to see which unique movie each tag now references rautotags = {} for tag, movies in autotags.items(): if (len(movies) > 1): movies = tuple(movies) # a tuple can be hashed, but a list not item = rautotags.get(movies, []) if not item: rautotags[movies] = item item.append(tag) self.tags = {} for movies, tags in rautotags.items(): movie = movies[0] # format the tag lists so that they are in 'original' order tags.sort(key=movie.find) first = movie.find(tags[0]) last = movie.find(tags[-1]) + len(tags[-1]) match = movie start = 0 end = len(movie) # Check if the set has a complete sentence in common, and how far for m in movies[1:]: if m[start:end] != match: if not m.startswith(movie[:last]): start = first if not m.endswith(movie[first:]): end = last match = movie[start:end] if m[start:end] != match: match = '' break # Adding the longest common sentence to the tag list if match: self.tags[match] = set(tags) else: match = ' '.join(tags) if (len(match) > 2) or ( match in realtags): #Omit small words, only for auto tags self.tags[match] = set(tags) # Adding the realtags to the tag list for tag in realtags: self.tags[tag] = set([tag])
def load(self, root, filter_tags): # this lists our root service, then building a # nice list del self.list[:] serviceHandler = eServiceCenter.getInstance() numberOfDirs = 0 reflist = root and serviceHandler.list(root) if reflist is None: print "listing of movies failed" return realtags = set() autotags = {} rootPath = os.path.normpath(root.getPath()) parent = None # Don't navigate above the "root" if len(rootPath) > 1 and (os.path.realpath(rootPath) != os.path.realpath(config.movielist.root.value)): parent = os.path.split(os.path.normpath(rootPath))[0] currentfolder = os.path.normpath(rootPath) + '/' if parent and (parent not in defaultInhibitDirs) and not currentfolder.endswith(config.usage.default_path.value): # enigma wants an extra '/' appended if not parent.endswith('/'): parent += '/' ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + parent) ref.flags = eServiceReference.flagDirectory self.list.append((ref, None, 0, -1)) numberOfDirs += 1 if config.usage.movielist_trashcan.value: here = os.path.realpath(rootPath) MovieList.InTrashFolder = here.startswith(getTrashFolder(here)) else: MovieList.InTrashFolder = False MovieList.UsingTrashSort = False if MovieList.InTrashFolder: if (config.usage.trashsort_deltime.value == "show record time"): MovieList.UsingTrashSort = MovieList.TRASHSORT_SHOWRECORD elif (config.usage.trashsort_deltime.value == "show delete time"): MovieList.UsingTrashSort = MovieList.TRASHSORT_SHOWDELETE while 1: serviceref = reflist.getNext() if not serviceref.valid(): break if config.ParentalControl.servicepinactive.value and config.ParentalControl.storeservicepin.value != "never": from Components.ParentalControl import parentalControl if not parentalControl.sessionPinCached and parentalControl.isProtected(serviceref): continue info = serviceHandler.info(serviceref) if info is None: info = justStubInfo begin = info.getInfo(serviceref, iServiceInformation.sTimeCreate) begin2 = 0 if MovieList.UsingTrashSort: f_path = serviceref.getPath() if os.path.exists(f_path): # Override with deltime for sorting if MovieList.UsingTrashSort == MovieList.TRASHSORT_SHOWRECORD: begin2 = begin # Save for later re-instatement begin = os.stat(f_path).st_ctime if serviceref.flags & eServiceReference.mustDescent: dirname = info.getName(serviceref) if not dirname.endswith('.AppleDouble/') and not dirname.endswith('.AppleDesktop/') and not dirname.endswith('.AppleDB/') and not dirname.endswith('Network Trash Folder/') and not dirname.endswith('Temporary Items/'): self.list.append((serviceref, info, begin, -1)) numberOfDirs += 1 continue # convert space-separated list of tags into a set this_tags = info.getInfoString(serviceref, iServiceInformation.sTags).split(' ') name = info.getName(serviceref) # OSX put a lot of stupid files ._* everywhere... we need to skip them if name[:2] == "._": continue if this_tags == ['']: # No tags? Auto tag! this_tags = name.replace(',',' ').replace('.',' ').replace('_',' ').replace(':',' ').split() # For auto tags, we are keeping a (tag, movies) dictionary. #It will be used later to check if movies have a complete sentence in common. for tag in this_tags: if tag in autotags: autotags[tag].append(name) else: autotags[tag] = [name] else: realtags.update(this_tags) # filter_tags is either None (which means no filter at all), or # a set. In this case, all elements of filter_tags must be present, # otherwise the entry will be dropped. if filter_tags is not None: this_tags_fullname = [" ".join(this_tags)] this_tags_fullname = set(this_tags_fullname) this_tags = set(this_tags) if not this_tags.issuperset(filter_tags) and not this_tags_fullname.issuperset(filter_tags): # print "Skipping", name, "tags=", this_tags, " filter=", filter_tags continue if begin2 != 0: self.list.append((serviceref, info, begin, -1, begin2)) else: self.list.append((serviceref, info, begin, -1)) self.firstFileEntry = numberOfDirs self.parentDirectory = 0 self.list.sort(key=self.buildGroupwiseSortkey) # Have we had a temporary sort method override set in MovieSelectiom.py? # If so use it, remove it (it's a one-off) and set the current method so # that the "Sort by" menu can highlight it and "Sort" knows which to # move on from (both in Screens/MovieSelection.py). # try: self.current_sort = self.temp_sort del self.temp_sort except: self.current_sort = self.sort_type if MovieList.UsingTrashSort: # Same as SORT_RECORDED, but must come first... self.list = sorted(self.list[:numberOfDirs], key=self.buildBeginTimeSortKey) + sorted(self.list[numberOfDirs:], key=self.buildBeginTimeSortKey) # Having sorted on *deletion* times, re-instate any record times for # *display* if that option is set. # self.list is a list of tuples, so we can't just assign to elements... # if config.usage.trashsort_deltime.value == "show record time": for i in range(len(self.list)): if len(self.list[i]) == 5: x = self.list[i] self.list[i] = (x[0], x[1], x[4], x[3]) elif self.current_sort == MovieList.SORT_ALPHANUMERIC: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaNumericSortKey) + sorted(self.list[numberOfDirs:], key=self.buildAlphaNumericSortKey) elif self.current_sort == MovieList.SORT_ALPHANUMERIC_REVERSE: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaNumericSortKey, reverse = True) + sorted(self.list[numberOfDirs:], key=self.buildAlphaNumericSortKey, reverse = True) elif self.current_sort == MovieList.SORT_ALPHANUMERIC_FLAT: self.list.sort(key=self.buildAlphaNumericFlatSortKey) elif self.current_sort == MovieList.SORT_ALPHANUMERIC_FLAT_REVERSE: self.list.sort(key=self.buildAlphaNumericFlatSortKey, reverse = True) elif self.current_sort == MovieList.SORT_RECORDED: self.list = sorted(self.list[:numberOfDirs], key=self.buildBeginTimeSortKey) + sorted(self.list[numberOfDirs:], key=self.buildBeginTimeSortKey) elif self.current_sort == MovieList.SORT_RECORDED_REVERSE: self.list = sorted(self.list[:numberOfDirs], key=self.buildBeginTimeSortKey, reverse = True) + sorted(self.list[numberOfDirs:], key=self.buildBeginTimeSortKey, reverse = True) elif self.current_sort == MovieList.SHUFFLE: dirlist = self.list[:numberOfDirs] shufflelist = self.list[numberOfDirs:] random.shuffle(shufflelist) self.list = dirlist + shufflelist elif self.current_sort == MovieList.SORT_ALPHA_DATE_OLDEST_FIRST: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey) + sorted(self.list[numberOfDirs:], key=self.buildAlphaDateSortKey) elif self.current_sort == MovieList.SORT_ALPHAREV_DATE_NEWEST_FIRST: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaDateSortKey, reverse = True) + sorted(self.list[numberOfDirs:], key=self.buildAlphaDateSortKey, reverse = True) elif self.current_sort == MovieList.SORT_LONGEST: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaNumericSortKey) + sorted(self.list[numberOfDirs:], key=self.buildLengthSortKey, reverse = True) elif self.current_sort == MovieList.SORT_SHORTEST: self.list = sorted(self.list[:numberOfDirs], key=self.buildAlphaNumericSortKey) + sorted(self.list[numberOfDirs:], key=self.buildLengthSortKey) for x in self.list: if x[1]: tmppath = x[1].getName(x[0])[:-1] if x[1].getName(x[0]).endswith('/') else x[1].getName(x[0]) if tmppath.endswith('.Trash'): self.list.insert(0, self.list.pop(self.list.index(x))) break if self.root and numberOfDirs > 0: rootPath = os.path.normpath(self.root.getPath()) if not rootPath.endswith('/'): rootPath += '/' if rootPath != parent: # with new sort types directories may be in between files, so scan whole # list for parentDirectory index. Usually it is the first one anyway for index, item in enumerate(self.list): if item[0].flags & eServiceReference.mustDescent: itempath = os.path.normpath(item[0].getPath()) if not itempath.endswith('/'): itempath += '/' if itempath == rootPath: self.parentDirectory = index break self.root = root # finally, store a list of all tags which were found. these can be presented # to the user to filter the list # ML: Only use the tags that occur more than once in the list OR that were # really in the tag set of some file. # reverse the dictionary to see which unique movie each tag now references rautotags = {} for tag, movies in autotags.items(): if (len(movies) > 1): movies = tuple(movies) # a tuple can be hashed, but a list not item = rautotags.get(movies, []) if not item: rautotags[movies] = item item.append(tag) self.tags = {} for movies, tags in rautotags.items(): movie = movies[0] # format the tag lists so that they are in 'original' order tags.sort(key = movie.find) first = movie.find(tags[0]) last = movie.find(tags[-1]) + len(tags[-1]) match = movie start = 0 end = len(movie) # Check if the set has a complete sentence in common, and how far for m in movies[1:]: if m[start:end] != match: if not m.startswith(movie[:last]): start = first if not m.endswith(movie[first:]): end = last match = movie[start:end] if m[start:end] != match: match = '' break # Adding the longest common sentence to the tag list if match: self.tags[match] = set(tags) else: match = ' '.join(tags) if (len(match) > 2) or (match in realtags): #Omit small words, only for auto tags self.tags[match] = set(tags) # Adding the realtags to the tag list for tag in realtags: self.tags[tag] = set([tag])