コード例 #1
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.")
コード例 #2
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))
コード例 #3
0
    def createTargetLibrary(self):
        if self.target_library is not None:
            return self.target_library

        sys.stdout.write("Generating target playlist & library\n")
        new_playlist = self.data.getTargetPlaylist()

        # TODO create local then COPY to target path
        db_path = os.path.join(os.getcwd(), "target.db")
        if os.path.exists(db_path):
            os.remove(db_path)
        sqlstore = SQLStore(db_path)
        library = Library(sqlstore)

        with library.sqlstore.conn:
            c = library.sqlstore.conn.cursor()
            for song in new_playlist:
                if "artist_key" in song:
                    del song['artist_key']
                if self.target_prefix_path:
                    song[Song.path] = self.target_source.join( \
                                      self.target_prefix_path,song[Song.path])
                library._insert(c, **song)

        self.target_library = library

        #db_path = self.getTargetLibraryPath()
        #source_copy_file(self.local_source ...,
        #                    self.target_source, ...)

        sys.stdout.write("finished creating target library\n")

        return library
コード例 #4
0
def main():

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)

    db_path = "./yue.db"
    sqlstore = SQLStore(db_path)
    Library.init(sqlstore)
    PlaylistManager.init(sqlstore)

    #playlist = Library.instance().search("(.abm 0 limited execution)")
    #uids = [s[Song.uid] for s in playlist]

    uids = list(PlaylistManager.instance().openPlaylist("Nexus5x").iter())
    dp = None  # [("limited","limited"),]

    pdialog = SyncProfileDialog()
    if pdialog.exec_():
        s = pdialog.export_settings()
        #s['no_exec'] = True
        sdialog = SyncDialog(uids, s, dp)
        sdialog.start()
        sdialog.show()

    sys.exit(app.exec_())
コード例 #5
0
    def test_history_export3(self):
        """
        show that export returns in the correct order
        """
        if os.path.exists(DB_PATH):
            os.remove(DB_PATH)

        sqlstore = SQLStore(DB_PATH)

        lib = Library(sqlstore)
        h = History(sqlstore)

        h.setLogEnabled(True)
        h.setUpdateEnabled(True)
        lib.history = h

        date = timegm(time.localtime(time.time()))

        dates = [date, date + 2, date + 4]
        uid = 0

        with h.sqlstore.conn:
            c = h.sqlstore.conn.cursor()
            for d in dates:
                h.incrementPlaycount(c, uid, d)

        records = list(h.export())
        self.assertEqual(len(records), 3)
        for d, r in zip(dates, records):
            self.assertEqual(r['date'], d)
コード例 #6
0
    def test_history_export(self):

        if os.path.exists(DB_PATH):
            os.remove(DB_PATH)

        sqlstore = SQLStore(DB_PATH)

        lib = Library(sqlstore)
        h = History(sqlstore)

        h.setLogEnabled(True)
        h.setUpdateEnabled(True)
        lib.history = h

        date = timegm(time.localtime(time.time()))

        uid = 0

        with h.sqlstore.conn:
            c = h.sqlstore.conn.cursor()
            h.incrementPlaycount(c, uid, date)

        records = list(h.export())
        self.assertEqual(len(records), 1)
        record = records[0]
        self.assertEqual(record['uid'], uid)
        self.assertEqual(record['date'], date)
        self.assertEqual(record['column'], Song.playtime)
コード例 #7
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})
コード例 #8
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
コード例 #9
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
コード例 #10
0
def main():

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)

    db_path = "./yue.db"
    sqlstore = SQLStore(db_path)
    Library.init(sqlstore)
    PlaylistManager.init(sqlstore)

    window = OpenPlaylistDialog()
    window.show()

    sys.exit(app.exec_())
コード例 #11
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))
コード例 #12
0
def main():

    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)


    db_path = "./libimport.db"
    sqlstore = SQLStore(db_path)
    Library.init( sqlstore )

    window = DialogVolEqLearn()
    window.show()


    sys.exit(app.exec_())
コード例 #13
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()
コード例 #14
0
ファイル: remote_view.py プロジェクト: hubitor/YueMusicPlayer
    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)
コード例 #15
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()
コード例 #16
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)))
コード例 #17
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)
コード例 #18
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([])
コード例 #19
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)
コード例 #20
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()
コード例 #21
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()
コード例 #22
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()
コード例 #23
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)
コード例 #24
0
ファイル: remote_view.py プロジェクト: hubitor/YueMusicPlayer
    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
コード例 #25
0
ファイル: LibraryTree.py プロジェクト: nsetzer/YueMusicPlayer
def main():
    app = QApplication(sys.argv)
    app.setQuitOnLastWindowClosed(True)

    db_path = "./yue.db"
    sqlstore = SQLStore(db_path)
    Library.init(sqlstore)
    PlaylistManager.init(sqlstore)

    table = LibraryTree()

    table.refreshData()

    table.container.resize(640, 320)
    table.container.show()
    #table.checkable= True
    #table.setStyleSheet('font-size: 12pt;')

    sys.exit(app.exec_())
コード例 #26
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()
コード例 #27
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()
コード例 #28
0
    def test_history_export2(self):

        if os.path.exists(DB_PATH):
            os.remove(DB_PATH)

        sqlstore = SQLStore(DB_PATH)

        lib = Library(sqlstore)
        h = History(sqlstore)

        h.setLogEnabled(True)
        h.setUpdateEnabled(True)
        lib.history = h

        uid = lib.insert(artist="artist1",
                         album='album1',
                         title='title1',
                         path='/path')

        lib.incrementPlaycount(uid)

        records = list(h.export())
        self.assertEqual(len(records), 1)
        record = records[0]
        self.assertEqual(record['uid'], uid)
        self.assertEqual(record['column'], Song.playtime)
コード例 #29
0
    def test_playlist_shuffle(self):
        sqlstore = SQLStore(DB_PATH)
        pm = PlaylistManager(sqlstore)
        lib = Library(sqlstore)
        pl = pm.openPlaylist(PL_NAME)
        pl.set([1, 2, 3, 4, 5])

        pl.shuffle_range(1, 3)
        # these two values should be the same every time.
        key = pl.get(0)
        self.assertEqual(1, key)
        key = pl.get(4)
        self.assertEqual(5, key)
コード例 #30
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()