示例#1
0
    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))
示例#2
0
    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.")
示例#3
0
 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})
示例#4
0
    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
示例#5
0
    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
示例#6
0
    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))
示例#7
0
 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()
示例#8
0
    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)
示例#9
0
    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()
示例#10
0
    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)))
示例#11
0
    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)
示例#12
0
    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([])
示例#13
0
    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()
示例#14
0
    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)
示例#15
0
 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()
示例#16
0
 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)
示例#17
0
    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()
示例#18
0
    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
示例#19
0
    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()
示例#20
0
    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)
示例#21
0
    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)
示例#22
0
    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)
示例#23
0
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()
示例#24
0
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()
示例#25
0
    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)
示例#26
0
    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
示例#27
0
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
示例#28
0
 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})
示例#29
0
    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()
示例#30
0
 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)