def getSelection(unselect = True): # return an array of all selected elements, and unselect by default # these elements if MpGlobal.Player.selCount == 0 : return [] R = [[]]*MpGlobal.Player.selCount i = 0; time = DateTime.now() - 60*60*24 for song in MpGlobal.Player.library: if song[MpMusic.SELECTED] and not song.banish : if MpGlobal.PLAYLIST_SKIP_RECENT and song[MpMusic.DATEVALUE] >= time: # if skip recent is enabled remove them from the selection. song[MpMusic.SELECTED] = False MpGlobal.Player.selCount -= 1 else: R[i] = song i += 1 if unselect : song[MpMusic.SELECTED] = False MpGlobal.Player.selCount -= 1 MpGlobal.Window.emit(SIGNAL("UPDATE_STATUSBAR"),0,MpGlobal.Player.selCount) MpGlobal.PLAYLIST_SKIP_RECENT = False return R[:i]
def getSelection(unselect=True): # return an array of all selected elements, and unselect by default # these elements if MpGlobal.Player.selCount == 0: return [] R = [[]] * MpGlobal.Player.selCount i = 0 time = DateTime.now() - 60 * 60 * 24 for song in MpGlobal.Player.library: if song[MpMusic.SELECTED] and not song.banish: if MpGlobal.PLAYLIST_SKIP_RECENT and song[ MpMusic.DATEVALUE] >= time: # if skip recent is enabled remove them from the selection. song[MpMusic.SELECTED] = False MpGlobal.Player.selCount -= 1 else: R[i] = song i += 1 if unselect: song[MpMusic.SELECTED] = False MpGlobal.Player.selCount -= 1 MpGlobal.Window.emit(SIGNAL("UPDATE_STATUSBAR"), 0, MpGlobal.Player.selCount) MpGlobal.PLAYLIST_SKIP_RECENT = False return R[:i]
def testbench_build_library(): library = [] time = DateTime.now() for i in range(30): song=Song("C:/Folder%d/Artist%d/Title%d.mp3"%(i,i,i)) song[MpMusic.ARTIST] = u"%dArtist The Band"%(i%10) # id will have 10 different A,B,T song[MpMusic.TITLE] = u"%dTitle of The Song"%(i%10) song[MpMusic.ALBUM] = u"%dMonthly Album"%(i%10) song[MpMusic.GENRE] = (u"ROCK",u"POP","ALT")[(i%3)] song[MpMusic.DATEVALUE] = time - (60*60*24*i)# each song is one day older song[MpMusic.DATESTAMP] = DateTime.formatDateTime(song[MusicContainer.DATEVALUE]) song[MpMusic.COMMENT] = "" song[MpMusic.RATING] = i%6 # in 30 songs, 5 of each rating value song[MpMusic.LENGTH] = 15*i song[MpMusic.SONGINDEX] = 0 song[MpMusic.PLAYCOUNT] = i song[MpMusic.SKIPCOUNT] = i song[MpMusic.FILESIZE] = 0 song[MpMusic.FREQUENCY] = 2*i song[MpMusic.BITRATE] = 0 song[MpMusic.SPECIAL] = False song[MpMusic.SELECTED] = False song.update() library.append(song) return library;
def testbench_build_library(): library = [] time = DateTime.now() for i in range(30): song = Song("C:/Folder%d/Artist%d/Title%d.mp3" % (i, i, i)) song[MpMusic.ARTIST] = u"%dArtist The Band" % ( i % 10) # id will have 10 different A,B,T song[MpMusic.TITLE] = u"%dTitle of The Song" % (i % 10) song[MpMusic.ALBUM] = u"%dMonthly Album" % (i % 10) song[MpMusic.GENRE] = (u"ROCK", u"POP", "ALT")[(i % 3)] song[MpMusic.DATEVALUE] = time - (60 * 60 * 24 * i ) # each song is one day older song[MpMusic.DATESTAMP] = DateTime.formatDateTime( song[MusicContainer.DATEVALUE]) song[MpMusic.COMMENT] = "" song[MpMusic.RATING] = i % 6 # in 30 songs, 5 of each rating value song[MpMusic.LENGTH] = 15 * i song[MpMusic.SONGINDEX] = 0 song[MpMusic.PLAYCOUNT] = i song[MpMusic.SKIPCOUNT] = i song[MpMusic.FILESIZE] = 0 song[MpMusic.FREQUENCY] = 2 * i song[MpMusic.BITRATE] = 0 song[MpMusic.SPECIAL] = False song[MpMusic.SELECTED] = False song.update() library.append(song) return library
def updateSongRecord(self,song,newtime=-1): # update the given song because it has just finished playing # update the lengths if there is a discrepancy using newtime as the new length if song == None: debug("None Song Passed to updateSongRecord") return if newtime >= 0: if (newtime < song[MpMusic.LENGTH]-1 or newtime > song[MpMusic.LENGTH]+1) and newtime > 1 : MpGlobal.Window.emit(SIGNAL("DEBUG_MESSAGE"),"%s : OldTime: %d NewTime: %d"%(song[MpMusic.TITLE],song[MpMusic.LENGTH],newtime)) song[MpMusic.LENGTH] = newtime dt = DateTime() days_elapsed = dt.daysElapsed(song[MpMusic.DATESTAMP]) # number of days since the date stamp song[MpMusic.DATESTAMP] = dt.currentDateTime(); song[MpMusic.DATEVALUE] = DateTime.now(); song.updateFrequency(days_elapsed) song[MpMusic.PLAYCOUNT] += 1 song.calcBaseScore(); song.calcScore(MpGlobal.Histogram); song.update(); # refill the library, if it was in view, its text needs to be updated #Player_set_unsaved() MpGlobal.Window.emit(SIGNAL("QUEUE_FUNCTION"),Player_set_unsaved) MpGlobal.Window.emit(SIGNAL("FILL_LIBRARY"))
def id3_createSongFromPath(path): """ attempt to read the id3 data from the song if the songs format is not supported, return a blank song with the path set. """ #check the extension and build a new song array from that type fext = fileGetExt(path).lower() song = Song(path) try: if fext in ext_mp3: id3_mp3_createSongFromPath(song) if fext in ext_mp4: id3_mp4_createSongFromPath(song) if fext in ext_asf: id3_asf_createSongFromPath(song) if fext in ext_flac: id3_flac_createSongFromPath(song) except Exception as e: print traceback.format_exc() print " *** Error [%s] Reading Tags for Type: %s" % (song, fext) for i in e: print "%s" % str(i) song[EnumSong.FILESIZE] = fileGetSize(path) song[EnumSong.DATEADDED] = DateTime.now() song[EnumSong.DATEADDEDS] = DateTime().currentDateTime() if song[EnumSong. LENGTH] > 2000: # 2k seconds = 32 minutes. is that a good break point? song[ EnumSong. LENGTH] /= 1000 # assume that th time measured was in milliseconds song.update() return song # return the blank song instead
def id3_createSongFromPath(path): """ attempt to read the id3 data from the song if the songs format is not supported, return a blank song with the path set. """ #check the extension and build a new song array from that type fext = fileGetExt(path).lower() song = Song(path) try : if fext in ext_mp3: id3_mp3_createSongFromPath(song) if fext in ext_mp4: id3_mp4_createSongFromPath(song) if fext in ext_asf: id3_asf_createSongFromPath(song) if fext in ext_flac: id3_flac_createSongFromPath(song) except Exception as e: print traceback.format_exc() print " *** Error [%s] Reading Tags for Type: %s"%(song, fext) for i in e: print "%s"%str(i) song[EnumSong.FILESIZE] = fileGetSize(path) song[EnumSong.DATEADDED ] = DateTime.now() song[EnumSong.DATEADDEDS] = DateTime().currentDateTime() if song[EnumSong.LENGTH] > 2000: # 2k seconds = 32 minutes. is that a good break point? song[EnumSong.LENGTH] /= 1000 # assume that th time measured was in milliseconds song.update(); return song # return the blank song instead
def calcBaseScore(self): """ s=1000 t=255 MpGlobal.Hist = [0]*(s+1) MpGlobal.Histpcnt = [0]*(t+1) for song in MpGlobal.Player.library: delta = DateTime().daysElapsedUTC(song[EnumSong.DATEADDED],DateTime.now()) song[EnumSong.SPECIAL] = int((s)*(float(song[EnumSong.PLAYCOUNT])/delta)) MpGlobal.Hist [ min(s,song[ EnumSong.SPECIAL ] )] += 1 MpGlobal.Histpcnt[ min(t,song[ EnumSong.PLAYCOUNT ] )] += 1 l = len(MpGlobal.Player.library) for song in MpGlobal.Player.library: m = min(s,song[ EnumSong.SPECIAL ] ); n = min(t,song[ EnumSong.PLAYCOUNT ] ); _m = float(sum(MpGlobal.Hist [:m])); _n = float(sum(MpGlobal.Histpcnt[:n])); _d = int( 1000*(_m/l) ) _p = int( 1000*(_n/l) ) song[ EnumSong.SCORE ] = int(.25*_p+.75*_d) """ MAX_SCORE = 9999 delta = DateTime().daysElapsedUTC(self[EnumSong.DATEADDED],DateTime.now()) p = int(MAX_SCORE*(float(self[EnumSong.PLAYCOUNT])/delta)) _f = float(9999 if self[EnumSong.FREQUENCY] == 0 else self[EnumSong.FREQUENCY]) f = int( MAX_SCORE*(1/_f)*7 ) # 7 scales such that once a week is really good self.basescore = (min(MAX_SCORE,f) + min(MAX_SCORE,p)) / 2 self[EnumSong.SPECIAL] = self.basescore return self.basescore
def _compileTerm(self,flag_type,flag,ostr): """ flag_type: either EXIF, ARTIST,PLAYCOUNT ETC flag : OR combination of SEARCH dir and mod. < <= >= > = and . + ! * ostr : relevant string term for a search of flag_type """ if ostr == "": return None ostr = unicode(ostr) cf = ostr[:] rf = None; fptr = None; if flag_type < EnumSong.STRINGTERM: fptr = self._compareTerm_String if (flag_type == EnumSong.SPEC_DATESTD ) : dt = DateTime(flag_type&0xF) cf = dt.getEpochTime(dt.repairDateTime(cf)) rf = cf + 24*60*60 if cf == 0: return None dt = DateTime(flag_type&0xF) ostr = dt.repairDateTime(ostr) if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.GT flag_type = EnumSong.DATESTAMP # change type to standard date format fptr = self._compareSongElement elif (flag_type == EnumSong.SPEC_DATEEU ) : dt = DateTime(flag_type&0xF) # set which format to use for dates, for help check the definition for SPEC_DATESTD, and the enumeration in DateTime cf = dt.getEpochTime(dt.repairDateTime(cf)) # autocomplete the entered date then convert to seconds rf = cf + 24*60*60 if cf == 0: return None dt = DateTime(flag_type&0xF) ostr = dt.repairDateTime(ostr) if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.GT flag_type = EnumSong.DATESTAMP # change type to standard date format fptr = self._compareSongElement elif (flag_type == EnumSong.SPEC_DATEUS ) : dt = DateTime(flag_type&0xF) cf = dt.getEpochTime(dt.repairDateTime(cf)) rf = cf + 24*60*60 if cf == 0: return None dt = DateTime(flag_type&0xF) ostr = dt.repairDateTime(ostr) if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.GT flag_type = EnumSong.DATESTAMP # change type to standard date format fptr = self._compareSongElement elif (flag_type == EnumSong.SPEC_MONTH ) : if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.GT flag_type = EnumSong.DATESTAMP cf = DateTime.now() try : cf -= 30*int(ostr)*24*60*60 rf = cf + 28*24*60*60 ostr = "month: %s"%ostr except: pass fptr = self._compareSongElement elif (flag_type == EnumSong.SPEC_WEEK ) : if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.GT flag_type = EnumSong.DATESTAMP cf = DateTime.now() try : cf -= 7*int(ostr)*24*60*60 rf = cf + 7*24*60*60 ostr = "week: %s"%ostr except: pass fptr = self._compareSongElement elif (flag_type == EnumSong.DATESTAMP) : if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.GT cf = DateTime.now() try : cf -= int(ostr)*24*60*60 rf = cf + 24*60*60 ostr = "day: %s"%ostr except: pass fptr = self._compareSongElement elif (flag_type == EnumSong.DATEADDED) : dt = DateTime(EnumSong.SPEC_DATESTD&0xF) cf = dt.getEpochTime(dt.repairDateTime(cf)) rf = cf + 24*60*60 if cf == 0: return None dt = DateTime(EnumSong.SPEC_DATESTD&0xF) ostr = dt.repairDateTime(ostr) if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.GT fptr = self._compareSongElement elif (flag_type == EnumSong.PATH ) : if cf == u"": return None rf = None fptr = self._compareSongElement elif flag_type >= EnumSong.STRINGTERM and flag_type < EnumSong.NUMTERM : if flag&SEARCH.DIR == 0:# if no DIR flags set, set EQ flag flag = flag|SEARCH.EQ try: cf = int(cf) except: cf = 0 return None rf = None # set the function to do the compare if flag_type == EnumSong.FREQUENCY: fptr = self._compareTerm_Frequency else: fptr = self._compareTerm_Number if flag_type == EnumSong.LENGTH: cf = DateTime.parseTimeDelta(ostr) term = SearchTerm(ostr,flag_type,flag,cf,rf,fptr) self.addTerm(flag&SEARCH.MOD,term)
def compile(self,string): """ Dot Words \\<table\\> \\<b\\>Dot Word\\</b\\> | \\<b\\>Field\\</b\\> | \\<b\\>Description\\</b\\> \\<b\\>Text Info\\</b\\> .alb .abm .album | Album | Search by album info. .art .artist | Artist | Search by artist info. .comm .comment | Comment | Search by user set comments. .gen .genre | Genre | Search by the songs genre. .path | Path | Search by the file path. .ttl .tit .title | Title | Search by song title. \\<b\\>Numerical\\</b\\> .freq | Frequency | Search by the average number of days between song plays. .pcnt .playcount | Play Count | Search by the playcount .scnt .skipcount | Skip Count | Search by the skipcount .size | File Size | Search by file size, in KB. .rte .rating | Rating | Search by the song rating, 0-5. \\</table\\> \\<table\\> \\<b\\>Advanced\\</b\\> | \\<b\\>Format\\</b\\> | \\<b\\>Description\\</b\\> .day | number | By number of days since last playing. .week | number | By number of weeks since last playing. .month | number | By number of months since last playing. .date | YYYY/MM/DD | enter a specific date to search by. formatted by year-month-day .dateUS | MM/DD/YYYY | see date. American date format .dateEU | DD/MM/YYYY | see date. Sane people format. \\<b\\>Special\\</b\\> .sel | Selected | Display songs from the selection pool .preset # | | This text is replaced with the text found in the given preset. .favorite | | Expands to a OR list of favorite artists. Set your favorite artists by right clicking their name in the Quick Selection tab \\</table\\> """ # # # # given a unicode string formatted as a search string, parse, set the 3 tupples for this object # # Parameters: # # str: a user input str # # there are three types of searchs to perform # # "c" or contains : target must contain any of these elements # # "o" or boolean or : target must contain at least one of these elements # # "n" or boolean not : target must contain none of these elements # # # # format: # # The following will be considered one search 'field': # # [.param] [.+!] [dir] term [ [.+!] [dir] term2 ...] [,;] ... # # where : # # .param : search type, eg .date, defaults to .exif when not included # # .+! : AND,OR,NOT include the following term in search results # # dir : <=,<,=,>,=> can be used to specify comparison direction # # term * : only mandatory string term, this will be compared against each song # # ,; : these optionally end a field # # if multiply fields are wanted, they must be separated by a comma or semicolon # # self._original = unicode(string) # create a copy of the string self._searchC = [] self._searchO = [] self._searchN = [] self._searchX = [[]] self.termCount = 0; fflag = { '<' : SEARCH.LT, '=' : SEARCH.EQ, '>' : SEARCH.GT, } ftype = { '.' : 0, '+' : SEARCH.OR, '!' : SEARCH.NT, '*' : SEARCH.IO, } #expand preset modifiers into their expressions for i in range(10): string = self._expand_preset(string,i) # expand favorite modifier if string[1:].find("favorite") >= 0: result = ".art +" if string[0] == "*": result = ".art *" for art in SearchObject_Controller.getFavoriteArtistList(): if len(art) > 0: result += u" \"%s\""%(art) result += ';' string = string[1:].replace("favorite",result,1); # ######################################################## # Begin Parsing User Input # quote first to protect anything the user wants protected. string = self.q.quote(string.lower()) # split the user input string into frames R = stringSplit(string,",;") # for each field in the string break into terms for x in range(len(R)): field = R[x] # the field is the entire string seperated by ; temp = field.split() if (len(temp) > 0): dword = temp[0] # the dot word will be the first word prepended with a sigil else: continue; frame = field.replace(dword,"",1).strip() # frame is everything but the dword key="" sigil = dword[0]; sigil_type = ftype.get(sigil,0) # integer translation of the sigil if not dword[0].isalpha(): key = dword[1:] #the dword with the sigil removed flag_type = EnumSong.EXIF if key == "sel": term = SearchTerm(dword,EnumSong.SELECTED,0,None,None,self._compareSongElement) self.addTerm(sigil_type,term) continue elif key == "spec": term = SearchTerm(dword,EnumSong.SPECIAL,0,None,None,self._compareSongElement) self.addTerm(sigil_type,term) continue elif key == "ban" or key == 'banish': term = SearchTerm(dword,EnumSong.BANISH,0,None,None,self._compareSongElement) self.addTerm(sigil_type,term) continue elif key[:4] == "freq" and key[4:5] in "<=>" and key[4:5] != "": # a slice never throws an exception, but can return empty # allow $freqX , where X is <=>, fdict = { '<' : EnumSong.SPEC_FREQ_L, '=' : EnumSong.SPEC_FREQ_E, '>' : EnumSong.SPEC_FREQ_G, } flag = fflag.get(key[4],0)|sigil_type term = SearchTerm(key,fdict[key[4]],flag,DateTime.now(),None,self._compareSongElement) self.addTerm(sigil_type,term) continue else: # get key or return the default value flag_type = SearchObject_Controller.getSearchDictionary().get(key,flag_type) #print flag_type,frame if flag_type == EnumSong.EXIF: self._parseFrame(flag_type,field) else: self._parseFrame(flag_type,frame) #self._addTerms(flag_type,frame,S) self.termCount = len(self._searchC)+len(self._searchO)+len(self._searchN) for lst in self._searchX: self.termCount += len(lst)