def doTask(self): """ TODO: make this library aware. If not library is configured (instance returns none) thn don't bother. Rename also needs to be away Rename Should be removed entirely """ # get a thread local copy of the library # must compare to None, otherwise when it is a DB instance, # a thread access violation is thrown if Library.instance() is not None: self.lib = Library.instance().reopen() for i, path in enumerate(self.src_paths): name = self.view.split(path)[1] dst_path = self.view.join(self.dst_path, name) dst_path = generateUniquePath(self.view, dst_path) if self.lib: move_one_lib(self.view, self.lib, path, dst_path) else: self.move_one(path, dst_path) self.setProgress(100 * (i + 1) / len(self.src_paths))
def action_update_replace_impl(self, path): def strmatch(s1,s2,field): return s1[field].lower().replace(" ","") == \ s2[field].lower().replace(" ","") def _match(song, temp): # match songs based on index or title a = strmatch(song,temp,Song.artist) and \ strmatch(song,temp,Song.title) i = False if temp[Song.album_index] > 0: i = song[Song.album_index] == temp[Song.album_index] return a or i # load the given path as a song to get meta data temp = Song.fromPath( path ); p, n = os.path.split( path ) gp, _ = os.path.split( p ) # search grandparent for songs songs = Library.instance().searchDirectory( gp, recursive=True ) sys.stdout.write(gp+"\n") for song in songs: if _match(song, temp): Library.instance().update(song[Song.uid],**{Song.path:path}) break; else: print("failed to update/replace record.")
def duration_fix(self, song, new_length): new_length = int(new_length) if int(song[Song.length]) != new_length: sys.stdout.write( "%s length: %d new_length:%d\n" % (Song.toString(song), song[Song.length], self.last_tick)) Library.instance().update(song[Song.uid], **{Song.length: new_length})
def editing_finished(self, rows, new_value): new_value = new_value.replace('"', '') # fast update (this doesnt make sense from a user point of view) uids = [self.parent.data[row][Song.uid] for row in rows] Library.instance().update_many(uids, **{Song.path: new_value}) for row in rows: # the editor already updated the row, but did it wrong!! song = self.parent.data[row] song[Song.path] = new_value
def mouseDoubleClick(self, row_index, posx, posy): if not self.parent.rating_mouse_tracking: return False song = self.parent.data[row_index] song[Song.rating] = self.suggested_rating Library.instance().update(song[Song.uid], **{self.index: self.suggested_rating}) #self.parent.modify_song.emit(self.parent.data[row_index]) #self.parent.modify_song_rating.emit(self.parent.data[row_index]) return True #blocking return
def doTask(self): if Library.instance(): self.lib = Library.instance().reopen() for i, (src, dst) in enumerate(self.args): src = self.view.normpath(src, self.wd) dst = self.view.normpath(dst, self.wd) if self.lib: move_one_lib(self.view, self.lib, src, dst) else: self.view.move(src, dst) self.setProgress(100 * (i + 1) / len(self.args))
def action_bannish(self, songs, state): """ bannish or restore a set of songs """ lib = Library.instance() for song in songs: lib.update(song[Song.uid], **{Song.blocked: state}) song[Song.blocked] = state # for ui, prevent rerunning search self.update()
def rollPlaylist(self): """ generate new songs using the default query.""" index, _ = self.playlist.current() length = len(self.playlist) pcnt = 1.0 - index / length query, plsize = self.getCurrentQuery() size = int(plsize * .25) size = max(plsize - length + min(index, size), size) count = min(index, size) # number to deelte sys.stdout.write("insert songs using `%s` limit %d\n" % (query, size)) try: # generate a new list and insert it songs = Library.instance().search(query, orderby=Song.random, limit=size) lst = [song[Song.uid] for song in songs] self.playlist.insert(length, lst) # remove the same number of songs from the start of the list if count > 0: self.playlist.delete(list(range(count))) except ParseError as e: sys.stderr.write("%s" % e)
def on_playlist_end(self): """ create a new playlist using the default query, or a preset """ query, size = self.getCurrentQuery() sys.stdout.write("create playlist `%s` limit %d\n" % (query, size)) # TODO: set limit to size + 10 # filter the list by searching for any consecutive songs-by-artist # pop that song and cycle it to the end of the list # then use the first `size` elements of the list as the result # I also want to implement the hash.... limit total number of # songs per artist in the resulting list when possible try: lst = Library.instance().createPlaylist(query, size) #search(query, orderby=Song.random, limit=size) #lst = [ song[Song.uid] for song in songs ] except ParseError as e: sys.stderr.write("%s" % e) lst = [] self.playlist.set(lst) self.device.play_index(0) self.root.plview.updateData() self.root.plview.scrollToCurrent() self.root.backup_database()
def run(self): self.setMessage("Reticulating splines") # get a thread local copy lib = Library.instance().reopen() songs = lib.search(self.query) self.pbar.setMaximum(len(songs) - 1) QThread.usleep(2000000) self.setMessage("Updating MP3 Tags") count = 0 for i, song in enumerate(songs): try: write_tags(song) except UnsupportedFormatError: pass except PermissionError as e: sys.stderr.write("Permission Denied: %s\n" % song[Song.path]) sys.stderr.write("%s\n" % e) except OSError as e: sys.stderr.write("System Error: %s\n" % song[Song.path]) sys.stderr.write("%s\n" % e) else: count += 1 sys.stdout.write(Song.toString(song) + "\n") finally: self.valueChanged.emit(i) if count == 0: self.setMessage("No songs updated.") else: self.setMessage("Successfully update %d/%d files." % (count, len(songs)))
def doTask(self): hist = History.instance().reopen() ts = int( (datetime.datetime.now() - datetime.timedelta(28)).timestamp()) records = [] page_size = 500 result = self.client.history_get(hist, ts, None, 0, page_size) records += result page = 1 num_pages = 20 while len(result) > 0 and page < 20: p = 90.0 * (page + 1) / num_pages self.setProgress(p) result = self.client.history_get(hist, ts, None, page, page_size) records += result page += 1 print("num history pages: %d" % page) print("num history records: %d" % len(records)) title = "Import History" message = "Import %d records?" % len(records) options = ["cancel", "ok"] i = self.getInput(title, message, options) if i > 0: #hist = History.instance().reopen() # hist._import(records) lib = Library.instance().reopen() lib.import_record(records)
def run_search(self, text, setText=False, refresh=False): """ setText: if true set the text box to contain text """ if self.tbl_song.isEditorOpen(): return # TODO, should do something try: songs = Library.instance().search( text, \ orderby=self.tbl_song.sort_orderby, reverse = self.tbl_song.sort_reverse ) except ParseError as e: self.txt_search.setStyleSheet("background: #CC0000;") self.lbl_error.setText("%s" % e) self.lbl_error.show() except Exception as e: raise e else: self.displaySongs(songs) if setText: self.txt_search.setText(text) if not refresh: self.tbl_song.scrollTo(0) self.tbl_song.setSelection([])
def run(self): print(self.settings) target_path = self.settings["target_path"] bitrate = self.settings.get("bitrate", 0) no_exec = self.settings.get("no_exec", False) equalize = self.settings.get("equalize", False) # TODO windows only encoder_path = self.settings.get("encoder_path", "ffmpeg.exe") transcode = { "non": SyncManager.T_NON_MP3, "all": SyncManager.T_SPECIAL, "none": SyncManager.T_NONE, }.get(self.settings.get("transcode", "none"), SyncManager.T_NONE) dp = None if self.settings.get('save_playlists', False): dp = self.dynamic_playlists target_prefix = self.settings.get("target_prefix", "") format = self.settings.get("playlist_format", SyncManager.P_M3U) #dp = [("limited","limited"),] # TODO: pass playlist_format to Sync Manager lib = Library.instance().reopen() sm = QtSyncManager(lib,self.uids,target_path,encoder_path, \ transcode=transcode, equalize=equalize, dynamic_playlists=dp, target_prefix=target_prefix, playlist_format=format, no_exec=no_exec, parent=self) sm.run()
def run(self): # scan input paths for media files # for each file found emit on_ingest signal self.setMessage("Scanning input...") lib = Library.instance().reopen() for path in self.paths: if os.path.isdir(path): self.scan_directory(path) else: ext = os.path.splitext(path)[1] if ext in self.supported_exts: self.media_files.append(path) if len(self.media_files) == 0: self.setMessage("No Media Files Found...") return self.setMessage("Importing %d media files..." % len(self.media_files)) self.pbar.setMaximum(len(self.media_files)) for i, path in enumerate(self.media_files): if not self.alive: return self.load_file(lib, path) self.valueChanged.emit(i) self.setMessage("Successfully imported %d media files." % self.ingest_count)
def action_delete(self, songs): # emit a signal, with a set of songs to delete # these songs must be addded to a set so that undo delete # can be implemented. # display a warning message before emiting any signal uids = [song[Song.uid] for song in songs] print(uids) text = "Are you sure you want to delete %d songs?" % len(uids) msgbox = QMessageBox(QMessageBox.Question, "Delete Songs", text) msgbox.addButton("Delete", QMessageBox.DestructiveRole) msgbox.addButton(QMessageBox.Cancel) msgbox.setDefaultButton(QMessageBox.Cancel) result = msgbox.exec_() print(result) if result == 0: Library.instance().remove_many(uids) self.parent().refresh()
def generateData(self, songs=None): m = Settings.instance()['quicklist_minimum_song_count'] if songs is None: songs = Library.instance().search("ban=0") text_transform = lambda x : [x,] if self.display_class == Song.genre: text_transform = lambda x : [ x.strip().title() for x in (x.replace(",",";").split(";")) if x.strip() ] data = buildQuickList(songs,self.display_class,text_transform,minimum=m) self.setData(data)
def displaySongs(self, songs): self.tbl_song.setData(songs) self.lbl_search.setText("%d/%d" % (len(songs), len(Library.instance()))) if not self.lbl_error.isHidden(): self.txt_search.setStyleSheet("") self.lbl_error.hide()
def doTask(self): username = self.client.getUserName() if ":" in username: username, password = username.split(":") user = self.client.login(username, password) self.newApiKey.emit(username, user['apikey']) print(username) print(user['apikey']) lib = Library.instance().reopen() remote_songs = self.client.connect(callback=self._dlprogress) local_map = {s['uid']: s for s in lib.search(None)} for song in remote_songs: # match by id if song[Song.uid] in local_map: local_song = local_map[song[Song.uid]] del local_map[song[Song.uid]] song[Song.path] = local_song[Song.path] song[Song.remote] = SONG_SYNCED else: # not found locally song[Song.remote] = SONG_REMOTE # match by path # path = self.client.local_path(self.basedir, song) # if os.path.exists(path): # song[Song.path] = path # song[Song.remote] = SONG_SYNCED # # self.addToDbIfMissing(lib, song) # continue # songs not found on remote local_songs = list(local_map.values()) for song in local_songs: song[Song.remote] = SONG_LOCAL songs = remote_songs + local_songs clss = {0: 0, 1: 0, 2: 0, 3: 0} for s in songs: clss[s[Song.remote]] += 1 print(clss) self.setProgress(100) self.newLibrary.emit(songs) # success, update settings settings = Settings.instance().reopen() settings['remote_hostname'] = self.client.getHostName() settings['remote_username'] = self.client.getUserName() settings['remote_apikey'] = self.client.getApiKey() settings['remote_basedir'] = self.basedir
def on_song_end(self, song): try: idx, _ = self.device.current() except IndexError: sys.stderr.write("error: No Current Song\n") return if self.one_shot: self.device.play_index(idx) self.device.pause() self.one_shot = False else: Library.instance().incrementPlaycount(song[Song.uid]) self.duration_fix(song, self.last_tick) # return to the first song in the playlist if the current # song does not match the song that just finished. # for example, when the user makes a new playlist _, uid = self.playlist.current() if uid != song[Song.uid]: self.device.play_index(0) else: self.device.next() # todo: only if song matches current query? self.root.libview.refresh() if idx == self.stop_index: self.root.btn_playpause.setStopState(False) self.device.pause() self.stop_index = -1 # i have wanted this *forever*. # it could be annoying, so i should make it optional # when turned off, update() must be called instead. self.root.plview.scrollToCurrent()
def refreshData(self): data = Library.instance().getArtistAlbums() # convert the data to a tree root = Leaf(None, "Library (%d)" % len(data), None) for art, albs in data: a = Leaf(root, art, None) for alb in albs: Leaf(a, alb, None) root.checkable = True root.collapsed = False root.collapsible = False self.setRoot(root)
def run(self): lib = Library.instance().reopen() songs = lib.songFromIds(self.uids) self.setMessage("Saving Playlist...") with codecs.open(self.path, "w", "utf-8") as wf: wf.write("#EXTM3U") for i, song in enumerate(songs): wf.write( "#EXTINF:%d:%s - %s\n" % (song[Song.length], song[Song.artist], song[Song.title])) wf.write("%s\n" % song[Song.path]) self.valueChanged.emit(i)
def __init__(self,parent=None): super(DialogVolEqLearn, self).__init__(parent) self.vbox = QVBoxLayout(self) self.vbox.setSpacing(3) self.setWindowTitle("Volume Equalizer Learn") self.pbar = ProgressBar(self) self.btn_start = QPushButton("Start",self) self.btn_stop = QPushButton("Stop",self) self.btn_stop.hide() self.btn_start.clicked.connect(self.learn) self.btn_stop.clicked.connect(self.stop) self.gbox_opt = QGroupBox("Select",self) self.gbox_vbox = QVBoxLayout(self.gbox_opt); self.rbtn_lib = QRadioButton("Lib") self.rbtn_new = QRadioButton("New") self.rbtn_new.setChecked(True) self.gbox_vbox.addWidget( self.rbtn_lib ) self.gbox_vbox.addWidget( self.rbtn_new ) self.vbox.addWidget(self.gbox_opt) self.vbox.addWidget(self.pbar) self.vbox.addWidget(self.btn_start) self.vbox.addWidget(self.btn_stop) self.thread = None; self.sync_set_text.connect(self.sync_setText) self.sync_set_value.connect(self.sync_setValue) self.sync_set_done.connect(self.sync_done) self.songList = [] self.songListNew = [] self.cbk_close = None self.setLibrary( Library.instance().search(None) ) self.resize(500,60)
def main(): db_path = "./libimport.db" sqlstore = SQLStore(db_path) Library.init(sqlstore) PlaylistManager.init(sqlstore) pl = PlaylistManager.instance().openPlaylist("current") device = BassSoundDevice(pl, "./lib/win32/x86_64", True) songs = Library.instance().search(None, orderby=Song.random, limit=5) lst = [s['uid'] for s in songs] pl.set(lst) print("supports float", BassPlayer.supportsFloat()) device.setVolume(.25) device.play_index(0) YueRepl(device=device).repl()
def main(): ffmpeg = r"C:\ffmpeg\bin\ffmpeg.exe" db_path = "yue.db" #target = "ftp://*****:*****@192.168.0.9:2121/Music" target = "test" transcode = SyncManager.T_NON_MP3 equalize = True bitrate = 320 run = True no_exec = False format = SyncManager.P_M3U target_prefix = os.getcwd() sqlstore = SQLStore(db_path) Library.init(sqlstore) PlaylistManager.init(sqlstore) library = Library.instance() playlist = library.search("(.abm 0 limited execution)") uids = [s[Song.uid] for s in playlist] print(os.path.realpath(db_path)) print("lib", len(library)) dp = [ ("limited", "limited"), ] sm = SyncManager(library, uids, target, ffmpeg, transcode=transcode, equalize=equalize, dynamic_playlists=dp, target_prefix=target_prefix, playlist_format=format, no_exec=no_exec) sm.run()
def doTask(self): records = {} lib = Library.instance().reopen() for i, song in enumerate(self.songs): self._iterprogress = float(i) / len(self.songs) self._dlprogress() if song[Song.remote] != SONG_SYNCED: continue temp = song.copy() uid = temp[Song.uid] del temp[Song.path] del temp[Song.artist_key] del temp[Song.remote] del temp[Song.uid] for key in ["id", "art_path", "domain_id", "user_id", "file_size"]: if key in temp: del temp[key] records[uid] = temp lib.update_all(records)
def doTask(self): lib = Library.instance().reopen() for i, song in enumerate(self.songs): self._iterprogress = float(i) / len(self.songs) path = self.client.download_song(self.dir_base, song, self._dlprogress) temp = song.copy() temp[Song.path] = path del temp[Song.artist_key] del temp[Song.remote] # delete it before adding to db for key in ["id", "art_path", "domain_id", "user_id", "file_size"]: if key in temp: del temp[key] print(temp) # add the song to the library if the key does not exist try: if temp[Song.uid]: lib.songFromId(temp[Song.uid]) else: lib.insert(**temp) except KeyError: lib.insert(**temp) song[Song.remote] = SONG_SYNCED # no longer remote
def _connect(): # db_path = "/Users/nsetzer/Music/Library/yue.db" db_path = "D:\\Dropbox\\ConsolePlayer\\yue.db" sqlstore = SQLStore(db_path) History.init(sqlstore) Library.init(sqlstore) username = "******" apikey = "f45596be-5355-4cef-bd00-fb63f872b140" songs = Library.instance().search("beast") song = songs[0] api = ApiClient("http://localhost:4200") user = api.login("admin", "admin") print(user) api.setApiUser(username) api.setApiKey(user['apikey']) apiw = ApiClientWrapper(api) songs = apiw.connect() return songs, api, apiw
def editing_finished(self, rows, new_value): uids = [self.parent.data[row][Song.uid] for row in rows] Library.instance().update_many(uids, **{self.index: new_value})
def run(self): BassPlayer.init() bp = BassPlayer(); if len(self.songList)==0: self.update_progress(-1); return; for _,dsp in bp.dsp_blocks.items(): dsp.setEnabled(False); zblog = ZBLOG(priority = 500,filter_size=44100//8,lograte=44100//4); bp.addDsp("zblog",zblog); self.start_time = time.time() library = Library.instance().reopen() self.idx = 0; for song in self.songList: path = song[Song.path] #print pputf(path) try : #dt.timer_start() scale,samples = self.learn_one(bp,zblog,path) if scale != 0: # update time estimate ms = 0 # dt.timer_end(); self.update_estimate(ms,len(samples)) iscale = int(scale * 100); avg = sum(samples)/len(samples) iscale = max(0,min(1000,iscale)); #avgs = .35/avg; #print "iscale is %d; avg=%.3f midpoint=%d"%(iscale,avg,int(avgs*100)) song[Song.equalizer]=iscale library.update(song[Song.uid],**{Song.equalizer:iscale}) #print iscale else: self.errors += 1 except Exception as e: print("ERROR:"+str(e)) self.errors += 1; self.display_estimate() bp.unload() self.update_progress(self.idx); if not self.alive: break; self.idx += 1; self.display_estimate() # experimental code follows seq = [ song[Song.equalizer] for song in self.songList] bin = range(0,600,5); h = histogramGen(seq,bin) p = list(zip(bin,h)); p.sort(key=lambda x:x[1],reverse=True) print("top 5 results:") for i in range(5): print("%d: %s "%(i+1,p[i])) print("bottom 5 results:") for i in range(5): print("%d: %s "%(i+1,p[-i])) avg = sum(seq)/float(len(seq)) print("avg:", avg) if self.alive: self.update_progress(-1); self.parent.sync_set_done.emit()
def action_create_playlist(self): rule = self.formatCheckedAsQueryRule() songs = Library.instance().search(rule) uids = [song[Song.uid] for song in songs] self.parent().set_playlist.emit(uids)