예제 #1
0
 def test_uri2fsn(self):
     if os.name != "nt":
         path = uri2fsn("file:///home/piman/cr%21azy")
         self.assertTrue(is_fsnative(path))
         self.assertEqual(path, fsnative(u"/home/piman/cr!azy"))
     else:
         path = uri2fsn("file:///C:/foo")
         self.assertTrue(is_fsnative(path))
         self.assertEqual(path, fsnative(u"C:\\foo"))
예제 #2
0
 def test_uri2fsn(self):
     if os.name != "nt":
         path = uri2fsn("file:///home/piman/cr%21azy")
         self.assertTrue(isinstance(path, fsnative))
         self.assertEqual(path, fsnative(u"/home/piman/cr!azy"))
     else:
         path = uri2fsn("file:///C:/foo")
         self.assertTrue(isinstance(path, fsnative))
         self.assertEqual(path, fsnative(u"C:\\foo"))
예제 #3
0
파일: test_api.py 프로젝트: lazka/senf
def test_uri_roundtrip():
    if os.name == "nt":
        for path in [
                u"C:\\foo-\u1234", u"C:\\bla\\quux ha",
                u"\\\\\u1234\\foo\\\u1423", u"\\\\foo;\\f"
        ]:
            path = fsnative(path)
            assert uri2fsn(fsn2uri(path)) == path
            assert isinstance(uri2fsn(fsn2uri(path)), fsnative)
    else:
        path = path2fsn(b"/foo-\xe1\x88\xb4")

        assert uri2fsn(fsn2uri(fsnative(u"/foo"))) == "/foo"
        assert uri2fsn(fsn2uri(path)) == path
        assert isinstance(uri2fsn(fsn2uri(path)), fsnative)
예제 #4
0
파일: util.py 프로젝트: zsau/quodlibet
def __create_playlist(name, source_dir, files, library):
    playlist = FileBackedPlaylist.new(PLAYLISTS, name, library=library)
    print_d("Created playlist %s" % playlist)
    songs = []
    win = WaitLoadWindow(
        None, len(files),
        _("Importing playlist.\n\n%(current)d/%(total)d songs added."))
    win.show()
    for i, filename in enumerate(files):
        if not uri_is_valid(filename):
            # Plain filename.
            songs.append(_af_for(filename, library, source_dir))
        else:
            try:
                filename = uri2fsn(filename)
            except ValueError:
                # Who knows! Hand it off to GStreamer.
                songs.append(formats.remote.RemoteFile(filename))
            else:
                # URI-encoded local filename.
                songs.append(_af_for(filename, library, source_dir))
        if win.step():
            break
    win.destroy()
    playlist.extend(list(filter(None, songs)))
    return playlist
예제 #5
0
def __parse_playlist(name, plfilename, files, library):
    playlist = FileBackedPlaylist.new(PLAYLISTS, name, library=library)
    songs = []
    win = WaitLoadWindow(
        None, len(files),
        _("Importing playlist.\n\n%(current)d/%(total)d songs added."))
    win.show()
    for i, filename in enumerate(files):
        if not uri_is_valid(filename):
            # Plain filename.
            filename = os.path.realpath(os.path.join(
                os.path.dirname(plfilename), filename))
            if library and filename in library:
                songs.append(library[filename])
            else:
                songs.append(formats.MusicFile(filename))
        else:
            try:
                filename = uri2fsn(filename)
            except ValueError:
                # Who knows! Hand it off to GStreamer.
                songs.append(formats.remote.RemoteFile(filename))
            else:
                # URI-encoded local filename.
                filename = os.path.realpath(os.path.join(
                    os.path.dirname(plfilename), filename))
                if library and filename in library:
                    songs.append(library[filename])
                else:
                    songs.append(formats.MusicFile(filename))
        if win.step():
            break
    win.destroy()
    playlist.extend(filter(None, songs))
    return playlist
예제 #6
0
파일: util.py 프로젝트: tonydolan/quodlibet
def __parse_playlist(name, plfilename, files, library):
    playlist = FileBackedPlaylist.new(PLAYLISTS, name, library=library)
    songs = []
    win = WaitLoadWindow(
        None, len(files),
        _("Importing playlist.\n\n%(current)d/%(total)d songs added."))
    win.show()
    for i, filename in enumerate(files):
        if not uri_is_valid(filename):
            # Plain filename.
            filename = os.path.realpath(
                os.path.join(os.path.dirname(plfilename), filename))
            if library and filename in library:
                songs.append(library[filename])
            else:
                songs.append(formats.MusicFile(filename))
        else:
            try:
                filename = uri2fsn(filename)
            except ValueError:
                # Who knows! Hand it off to GStreamer.
                songs.append(formats.remote.RemoteFile(filename))
            else:
                # URI-encoded local filename.
                filename = os.path.realpath(
                    os.path.join(os.path.dirname(plfilename), filename))
                if library and filename in library:
                    songs.append(library[filename])
                else:
                    songs.append(formats.MusicFile(filename))
        if win.step():
            break
    win.destroy()
    playlist.extend(filter(None, songs))
    return playlist
예제 #7
0
def test_any_pathnames(path):
    fsn = path2fsn(path)
    abspath = os.path.abspath(fsn)
    if os.path.isabs(abspath):
        if is_wine:
            # FIXME: fails on native Windows
            assert uri2fsn(fsn2uri(abspath)) == abspath
예제 #8
0
def __create_playlist(name, source_dir, files, library):
    playlist = FileBackedPlaylist.new(PLAYLISTS, name, library=library)
    print_d("Created playlist %s" % playlist)
    songs = []
    win = WaitLoadWindow(
        None, len(files),
        _("Importing playlist.\n\n%(current)d/%(total)d songs added."))
    win.show()
    for i, filename in enumerate(files):
        if not uri_is_valid(filename):
            # Plain filename.
            songs.append(_af_for(filename, library, source_dir))
        else:
            try:
                filename = uri2fsn(filename)
            except ValueError:
                # Who knows! Hand it off to GStreamer.
                songs.append(formats.remote.RemoteFile(filename))
            else:
                # URI-encoded local filename.
                songs.append(_af_for(filename, library, source_dir))
        if win.step():
            break
    win.destroy()
    playlist.extend(list(filter(None, songs)))
    return playlist
예제 #9
0
def uri2gsturi(uri):
    """Takes a correct uri and returns a gstreamer-compatible uri"""
    if not is_windows():
        return uri
    try:
        # gstreamer requires extra slashes for network shares
        return GLib.filename_to_uri(uri2fsn(uri))
    except (GLib.Error, ValueError):
        return uri
예제 #10
0
    def read(self, db):
        """Iterate through the database and import data for songs found in
        the library
        """

        # use the Row class for extracting rows
        db.row_factory = sqlite3.Row

        # iterate over all songs in the database
        # throws sqlite3.OperationalError if CoreTracks is not found
        for row in db.execute("SELECT * FROM CoreTracks"):
            try:
                filename = uri2fsn(row["Uri"])
            except ValueError:
                continue

            song = self._library.get(normalize_path(filename))
            if not song:
                continue

            has_changed = False

            # rating is stored as integer from 0 to 5
            b_rating = row["Rating"] / 5.0
            if b_rating != song("~#rating"):
                song["~#rating"] = b_rating
                has_changed = True

            # play count is stored as integer from 0
            if row["PlayCount"] != song("~#playcount"):
                # summing play counts would break on multiple imports
                song["~#playcount"] = row["PlayCount"]
                has_changed = True

            # skip count is stored as integer from 0
            if row["SkipCount"] != song("~#skipcount"):
                song["~#skipcount"] = row["SkipCount"]
                has_changed = True

            # timestamp is stored as integer or None
            if row["LastPlayedStamp"] is not None:
                value = row["LastPlayedStamp"]
                # keep timestamp if it is newer than what we had
                if value > song("~#lastplayed", 0):
                    song["~#lastplayed"] = value
                    has_changed = True

            if row["DateAddedStamp"] is not None:
                value = row["DateAddedStamp"]
                # keep timestamp if it is older than what we had
                if value < song("~#added", 0):
                    song["~#added"] = value
                    has_changed = True

            if has_changed:
                self._changed_songs.append(song)
예제 #11
0
    def test_roundtrip(self):
        if os.name == "nt":
            paths = [u"C:\\öäü.txt"]
        else:
            paths = [u"/öäü.txt", u"/a/foo/bar", u"/a/b/foo/bar"]

        for source in paths:
            path = uri2fsn(fsn2uri(fsnative(source)))
            self.assertTrue(isinstance(path, fsnative))
            self.assertEqual(path, fsnative(source))
예제 #12
0
    def test_roundtrip(self):
        if os.name == "nt":
            paths = [u"C:\\öäü.txt"]
        else:
            paths = [u"/öäü.txt", u"//foo/bar", u"///foo/bar"]

        for source in paths:
            path = uri2fsn(fsn2uri(fsnative(source)))
            self.assertTrue(is_fsnative(path))
            self.assertEqual(path, fsnative(source))
예제 #13
0
    def endElement(self, name):
        self._tag = None
        if name == "entry" and self._current is not None:
            current = self._current
            self._current = None
            if len(current) > 1:
                uri = current.pop("location", "")
                try:
                    filename = uri2fsn(uri)
                except ValueError:
                    return

                self._process_song(normalize_path(filename), current)
예제 #14
0
    def endElement(self, name):
        self._tag = None
        if name == "entry" and self._current is not None:
            current = self._current
            self._current = None
            if len(current) > 1:
                uri = current.pop("location", "")
                try:
                    filename = uri2fsn(uri)
                except ValueError:
                    return

                self._process_song(normalize_path(filename), current)
예제 #15
0
파일: filesel.py 프로젝트: urielz/quodlibet
 def __drag_data_received(self, widget, drag_ctx, x, y, data, info, time):
     if info == 42:
         uris = data.get_uris()
         if uris:
             try:
                 filename = uri2fsn(uris[0])
             except ValueError:
                 pass
             else:
                 self.go_to(filename)
                 Gtk.drag_finish(drag_ctx, True, False, time)
                 return
     Gtk.drag_finish(drag_ctx, False, False, time)
예제 #16
0
 def __drag_data_received(self, widget, drag_ctx, x, y, data, info, time):
     if info == 42:
         uris = data.get_uris()
         if uris:
             try:
                 filename = uri2fsn(uris[0])
             except ValueError:
                 pass
             else:
                 self.go_to(filename)
                 Gtk.drag_finish(drag_ctx, True, False, time)
                 return
     Gtk.drag_finish(drag_ctx, False, False, time)
예제 #17
0
    def _populate_from_file(self):
        library = self.songs_lib
        try:
            tree = ET.parse(self.path)
            # TODO: validate some top-level tag data

            root = tree.getroot()
            if root.tag == "playlist":
                ns_mapping = None
                print_w(f"Using legacy namespace for import of {self.path}")
            elif root.tag == "{" + XSPF_NS + "}playlist":
                # Try correct format first
                ns_mapping = {"": XSPF_NS}
            else:
                raise ValueError(f"Unknown playlist root of {root.tag}")
            node = root.find("title", namespaces=ns_mapping)
            if node is None:
                print_w(f"No <title> found in {self.path} "
                        f"(Got nodes: {[el.tag for el in root.iter()]})")
            elif self.name != node.text:
                print_w(f"Playlist was named {node.text!r} in XML "
                        f"instead of {self.name!r} at {self.path!r}")

            for node in tree.iterfind(".//track", namespaces=ns_mapping):
                location = node.findtext("location",
                                         namespaces=ns_mapping).strip()
                path = location.replace("\n", "").replace("\r", "")
                try:
                    # TODO: process relative URIs too?
                    path = uri2fsn(path)
                except ValueError:
                    pass
                if path in library:
                    self._list.append(library[path])
                elif library and library.masked(path):
                    self._list.append(path)
                else:
                    # TODO: handle missing playlist items (#3105, #729, #3131)
                    node_dump = ET.tostring(node, method="xml").decode("utf-8")
                    print_w("Couldn't find %r in playlist at %r. "
                            "Perhaps its metadata will help: %r" %
                            (path, self.path, node_dump))
                    self._list.append(path)
                    library.mask(path)
        except (ET.ParseError, ValueError) as e:
            print_w("Couldn't load %r (%s)" % (self.path, e))
예제 #18
0
    def test_write(self):
        with self.wrap("playlist") as pl:
            pl.extend(NUMERIC_SONGS)
            some_path = fsnative(os.path.join(self.temp, "xf0xf0"))
            pl.extend([some_path])
            pl.write()

            assert exists(pl.path), "File doesn't exist"
            root = ElementTree().parse(pl.path)
            assert root.tag == "{http://xspf.org/ns/0/}playlist"
            tracks = root.findall(".//track", namespaces={"": XSPF_NS})
            assert len(tracks) == len(NUMERIC_SONGS) + 1, f"Hmm found {tracks}"
            # Should now write compliant local URLs
            last_location = tracks[-1].find("location",
                                            namespaces={
                                                "": XSPF_NS
                                            }).text
            assert uri2fsn(last_location) == some_path
예제 #19
0
def _enqueue_files(app, value):
    """Enqueues comma-separated filenames or song names.
    Commas in filenames should be backslash-escaped"""

    library = app.library
    window = app.window
    songs = []
    for param in split_escape(value, ","):
        try:
            song_path = uri2fsn(param)
        except ValueError:
            song_path = param
        if song_path in library:
            songs.append(library[song_path])
        elif os.path.isfile(song_path):
            songs.append(library.add_filename(os.path.realpath(value)))
    if songs:
        window.playlist.enqueue(songs)
예제 #20
0
def _enqueue_files(app, value):
    """Enqueues comma-separated filenames or song names.
    Commas in filenames should be backslash-escaped"""

    library = app.library
    window = app.window
    songs = []
    for param in split_escape(value, ","):
        try:
            song_path = uri2fsn(param)
        except ValueError:
            song_path = param
        if song_path in library:
            songs.append(library[song_path])
        elif os.path.isfile(song_path):
            songs.append(library.add_filename(os.path.realpath(value)))
    if songs:
        window.playlist.enqueue(songs)
예제 #21
0
def show_uri(label, uri):
    """Shows a uri. The uri can be anything handled by GIO or a quodlibet
    specific one.

    Currently handled quodlibet uris:
        - quodlibet:///prefs/plugins/<plugin id>

    Args:
        label (str)
        uri (str) the uri to show
    Returns:
        True on success, False on error
    """

    parsed = urlparse(uri)
    if parsed.scheme == "quodlibet":
        if parsed.netloc != "":
            print_w("Unknown QuodLibet URL format (%s)" % uri)
            return False
        else:
            return __show_quodlibet_uri(parsed)
    elif parsed.scheme == "file" and (is_windows() or is_osx()):
        # Gio on non-Linux can't handle file URIs for some reason,
        # fall back to our own implementation for now
        from quodlibet.qltk.showfiles import show_files

        try:
            filepath = uri2fsn(uri)
        except ValueError:
            return False
        else:
            return show_files(filepath, [])
    else:
        # Gtk.show_uri_on_window exists since 3.22
        try:
            if hasattr(Gtk, "show_uri_on_window"):
                from quodlibet.qltk import get_top_parent
                return Gtk.show_uri_on_window(get_top_parent(label), uri, 0)
            else:
                return Gtk.show_uri(None, uri, 0)
        except GLib.Error:
            return False
예제 #22
0
def show_uri(label, uri):
    """Shows a uri. The uri can be anything handled by GIO or a quodlibet
    specific one.

    Currently handled quodlibet uris:
        - quodlibet:///prefs/plugins/<plugin id>

    Args:
        label (str)
        uri (str) the uri to show
    Returns:
        True on success, False on error
    """

    parsed = urlparse(uri)
    if parsed.scheme == "quodlibet":
        if parsed.netloc != "":
            print_w("Unknown QuodLibet URL format (%s)" % uri)
            return False
        else:
            return __show_quodlibet_uri(parsed)
    elif parsed.scheme == "file" and (is_windows() or is_osx()):
        # Gio on non-Linux can't handle file URIs for some reason,
        # fall back to our own implementation for now
        from quodlibet.qltk.showfiles import show_files

        try:
            filepath = uri2fsn(uri)
        except ValueError:
            return False
        else:
            return show_files(filepath, [])
    else:
        # Gtk.show_uri_on_window exists since 3.22
        try:
            if hasattr(Gtk, "show_uri_on_window"):
                from quodlibet.qltk import get_top_parent
                return Gtk.show_uri_on_window(get_top_parent(label), uri, 0)
            else:
                return Gtk.show_uri(None, uri, 0)
        except GLib.Error:
            return False
예제 #23
0
    def __drag_data_received(self, widget, ctx, x, y, sel, tid, etime):
        assert tid == DND_URI_LIST

        uris = sel.get_uris()

        dirs = []
        error = False
        for uri in uris:
            try:
                filename = uri2fsn(uri)
            except ValueError:
                filename = None

            if filename is not None:
                loc = os.path.normpath(filename)
                if os.path.isdir(loc):
                    dirs.append(loc)
                else:
                    loc = os.path.realpath(loc)
                    if loc not in self.__library:
                        self.__library.add_filename(loc)
            elif app.player.can_play_uri(uri):
                if uri not in self.__library:
                    self.__library.add([RemoteFile(uri)])
            else:
                error = True
                break
        Gtk.drag_finish(ctx, not error, False, etime)
        if error:
            ErrorMessage(
                self, _("Unable to add songs"),
                _("%s uses an unsupported protocol.") % util.bold(uri)).run()
        else:
            if dirs:
                copool.add(self.__library.scan,
                           dirs,
                           cofuncid="library",
                           funcid="library")
예제 #24
0
def __create_playlist(name, source_dir, files, songs_lib, pl_lib):
    songs = []
    win = WaitLoadWindow(
        None, len(files),
        _("Importing playlist.\n\n%(current)d/%(total)d songs added."))
    win.show()
    for i, filename in enumerate(files):
        song = None
        if not uri_is_valid(filename):
            # Plain filename.
            song = _af_for(filename, songs_lib, source_dir)
        else:
            try:
                filename = uri2fsn(filename)
            except ValueError:
                # Who knows! Hand it off to GStreamer.
                song = formats.remote.RemoteFile(filename)
            else:
                # URI-encoded local filename.
                song = _af_for(filename, songs_lib, source_dir)

        # Only add existing (not None) files to the playlist.
        # Otherwise multiple errors are thrown when the files are accessed
        # to update the displayed track infos.
        if song is not None:
            songs.append(song)
        elif (os.path.exists(filename)
              or os.path.exists(os.path.join(source_dir, filename))):
            print_w("Can't add file to playlist:"
                    f" Unsupported file format. '{filename}'")
        else:
            print_w(
                f"Can't add file to playlist: File not found. '{filename}'")

        if win.step():
            break
    win.destroy()
    return pl_lib.create_from_songs(songs)
예제 #25
0
def __create_playlist(name, source_dir, files, songs_lib, pl_lib):
    songs = []
    win = WaitLoadWindow(
        None, len(files),
        _("Importing playlist.\n\n%(current)d/%(total)d songs added."))
    win.show()
    for i, filename in enumerate(files):
        if not uri_is_valid(filename):
            # Plain filename.
            songs.append(_af_for(filename, songs_lib, source_dir))
        else:
            try:
                filename = uri2fsn(filename)
            except ValueError:
                # Who knows! Hand it off to GStreamer.
                songs.append(formats.remote.RemoteFile(filename))
            else:
                # URI-encoded local filename.
                songs.append(_af_for(filename, songs_lib, source_dir))
        if win.step():
            break
    win.destroy()
    return pl_lib.create_from_songs(songs)
예제 #26
0
    def __drag_data_received(self, widget, ctx, x, y, sel, tid, etime):
        assert tid == DND_URI_LIST

        uris = sel.get_uris()

        dirs = []
        error = False
        for uri in uris:
            try:
                filename = uri2fsn(uri)
            except ValueError:
                filename = None

            if filename is not None:
                loc = os.path.normpath(filename)
                if os.path.isdir(loc):
                    dirs.append(loc)
                else:
                    loc = os.path.realpath(loc)
                    if loc not in self.__library:
                        self.__library.add_filename(loc)
            elif app.player.can_play_uri(uri):
                if uri not in self.__library:
                    self.__library.add([RemoteFile(uri)])
            else:
                error = True
                break
        Gtk.drag_finish(ctx, not error, False, etime)
        if error:
            ErrorMessage(
                self, _("Unable to add songs"),
                _("%s uses an unsupported protocol.") % util.bold(uri)).run()
        else:
            if dirs:
                copool.add(
                    self.__library.scan, dirs,
                    cofuncid="library", funcid="library")
예제 #27
0
 def to_filename(s):
     try:
         return uri2fsn(s)
     except ValueError:
         return None
예제 #28
0
 def to_filename(s):
     try:
         return uri2fsn(s)
     except ValueError:
         return None
예제 #29
0
파일: test_api.py 프로젝트: lazka/senf
def test_uri2fsn():
    if os.name != "nt":
        with pytest.raises(ValueError):
            assert uri2fsn(u"file:///%00")
        with pytest.raises(ValueError):
            assert uri2fsn("file:///%00")
        assert uri2fsn("file:///foo") == fsnative(u"/foo")
        assert uri2fsn(u"file:///foo") == fsnative(u"/foo")
        assert isinstance(uri2fsn("file:///foo"), fsnative)
        assert isinstance(uri2fsn(u"file:///foo"), fsnative)
        assert \
            uri2fsn("file:///foo-%E1%88%B4") == path2fsn(b"/foo-\xe1\x88\xb4")
        assert uri2fsn("file:NOPE") == fsnative(u"/NOPE")
        assert uri2fsn("file:/NOPE") == fsnative(u"/NOPE")
        with pytest.raises(ValueError):
            assert uri2fsn("file://NOPE")
        assert uri2fsn("file:///bla:[email protected]") == \
            fsnative(u"/bla:[email protected]")
        assert uri2fsn("file:///bla?x#b") == fsnative(u"/bla?x#b")
    else:
        assert uri2fsn("file:NOPE") == "\\NOPE"
        assert uri2fsn("file:/NOPE") == "\\NOPE"
        with pytest.raises(ValueError):
            assert uri2fsn(u"file:///C:/%00")
        with pytest.raises(ValueError):
            assert uri2fsn("file:///C:/%00")
        assert uri2fsn("file:///C:/foo") == fsnative(u"C:\\foo")
        assert uri2fsn(u"file:///C:/foo") == fsnative(u"C:\\foo")
        assert isinstance(uri2fsn("file:///C:/foo"), fsnative)
        assert isinstance(uri2fsn(u"file:///C:/foo"), fsnative)
        assert uri2fsn(u"file:///C:/foo-\u1234") == fsnative(u"C:\\foo-\u1234")
        assert \
            uri2fsn("file:///C:/foo-%E1%88%B4") == fsnative(u"C:\\foo-\u1234")
        assert uri2fsn(u"file://UNC/foo/bar") == u"\\\\UNC\\foo\\bar"
        assert uri2fsn(u"file://\u1234/\u4321") == u"\\\\\u1234\\\u4321"

    with pytest.raises(TypeError):
        uri2fsn(object())

    with pytest.raises(ValueError):
        uri2fsn("http://www.foo.bar")

    if os.name == "nt":
        with pytest.raises(ValueError):
            uri2fsn(u"\u1234")

    if PY3:
        with pytest.raises(TypeError):
            uri2fsn(b"file:///foo")
예제 #30
0
    def read(self, plist):
        for track in plist['Tracks'].values():
            try:
                filename = uri2fsn(track['Location']).replace('\\', '', 2)
            except ValueError:
                continue

            song = self._lib.get(normalize_path(filename))
            if not song:
                continue

            has_changed = False

        try:
            track['Rating Computed']
        except KeyError:
            try:
                iRating = track['Rating'] / 100.0
                if song("~#rating") == 0 or song("~#rating") == None:
                    song["~#rating"] = iRating
                    has_changed = True
                elif iRating != song["~#rating"]:
                    avgr = (iRating + song("~#rating")) / 2.0
                    song["~#rating"] = avgr
                    has_changed = True
            except KeyError:
                pass

            try:
                pc = track['Play Count']
                try:
                    pc = song["~#playcount"] + pc
                    song["~#playcount"] = pc
                    has_changed = True
                except KeyError:
                    song["~#playcount"] = pc
                    has_changed = True
            except KeyError:
                pass

            try:
                sc = track['Skip Count']
                try:
                    sc = song["~#skipcount"] + sc
                    song["~#skipcount"] = sc
                    has_changed = True
                except KeyError:
                    song["~#skipcount"] = sc
                    has_changed = True
            except KeyError:
                pass

        try:
            song["~#lastplayed"]
        except KeyError:
            try:
                song["~#lastplayed"] = track['Play Date']
                has_changed = True
            except KeyError:
                pass

        try:
            add_date = int(track['Date Added'].timestamp())
            if song["~#added"] > add_date:
                song['~#added'] = add_date
                has_changed = True
        except KeyError:
            pass

        if has_changed:
            self._changed_songs.append(song)
예제 #31
0
def process_arguments(argv):
    from quodlibet.util.path import uri_is_valid
    from quodlibet import util
    from quodlibet import const

    actions = []
    controls = [
        "next", "previous", "play", "pause", "play-pause", "stop",
        "hide-window", "show-window", "toggle-window", "focus", "quit",
        "unfilter", "refresh", "force-previous"
    ]
    controls_opt = [
        "seek", "repeat", "query", "volume", "filter", "set-rating",
        "set-browser", "open-browser", "shuffle", "song-list", "queue",
        "stop-after", "random", "repeat-type", "shuffle-type"
    ]

    options = util.OptionParser("Quod Libet", const.VERSION,
                                _("a music library and player"), _("[option]"))

    options.add("print-playing", help=_("Print the playing song and exit"))
    options.add("start-playing", help=_("Begin playing immediately"))
    options.add("start-hidden", help=_("Don't show any windows on start"))

    for opt, help in [
        ("next", _("Jump to next song")),
        ("previous",
         _("Jump to previous song or restart if near the beginning")),
        ("force-previous", _("Jump to previous song")),
        ("play", _("Start playback")),
        ("pause", _("Pause playback")),
        ("play-pause", _("Toggle play/pause mode")),
        ("stop", _("Stop playback")),
        ("volume-up", _("Turn up volume")),
        ("volume-down", _("Turn down volume")),
        ("status", _("Print player status")),
        ("hide-window", _("Hide main window")),
        ("show-window", _("Show main window")),
        ("toggle-window", _("Toggle main window visibility")),
        ("focus", _("Focus the running player")),
        ("unfilter", _("Remove active browser filters")),
        ("refresh", _("Refresh and rescan library")),
        ("list-browsers", _("List available browsers")),
        ("print-playlist", _("Print the current playlist")),
        ("print-queue", _("Print the contents of the queue")),
        ("print-query-text", _("Print the active text query")),
        ("no-plugins", _("Start without plugins")),
        ("run", _("Start Quod Libet if it isn't running")),
        ("quit", _("Exit Quod Libet")),
    ]:
        options.add(opt, help=help)

    for opt, help, arg in [
        ("seek", _("Seek within the playing song"), _("[+|-][HH:]MM:SS")),
        ("shuffle", _("Set or toggle shuffle mode"), "0|1|t"),
        ("shuffle-type", _("Set shuffle mode type"), "random|weighted|off"),
        ("repeat", _("Turn repeat off, on, or toggle it"), "0|1|t"),
        ("repeat-type", _("Set repeat mode type"), "current|all|one|off"),
        ("volume", _("Set the volume"), "(+|-|)0..100"),
        ("query", _("Search your audio library"), _("query")),
        ("play-file", _("Play a file"), C_("command", "filename")),
        ("set-rating", _("Rate the playing song"), "0.0..1.0"),
        ("set-browser", _("Set the current browser"), "BrowserName"),
        ("stop-after", _("Stop after the playing song"), "0|1|t"),
        ("open-browser", _("Open a new browser"), "BrowserName"),
        ("queue", _("Show or hide the queue"), "on|off|t"),
        ("song-list", _("Show or hide the main song list (deprecated)"),
         "on|off|t"),
        ("random", _("Filter on a random value"), C_("command", "tag")),
        ("filter", _("Filter on a tag value"), _("tag=value")),
        ("enqueue", _("Enqueue a file or query"),
         "%s|%s" % (C_("command", "filename"), _("query"))),
        ("enqueue-files", _("Enqueue comma-separated files"),
         "%s[,%s..]" % (_("filename"), _("filename"))),
        ("print-query", _("Print filenames of results of query to stdout"),
         _("query")),
        ("unqueue", _("Unqueue a file or query"),
         "%s|%s" % (C_("command", "filename"), _("query"))),
    ]:
        options.add(opt, help=help, arg=arg)

    options.add("sm-config-prefix", arg="dummy")
    options.add("sm-client-id", arg="prefix")
    options.add("screen", arg="dummy")

    def is_vol(str):
        if len(str) == 1 and str[0] in '+-':
            return True
        return is_float(str)

    def is_time(str):
        if str[0] not in "+-0123456789":
            return False
        elif str[0] in "+-":
            str = str[1:]
        parts = str.split(":")
        if len(parts) > 3:
            return False
        else:
            return not (False in [p.isdigit() for p in parts])

    def is_float(str):
        try:
            float(str)
        except ValueError:
            return False
        else:
            return True

    validators = {
        "shuffle": ["0", "1", "t", "on", "off", "toggle"].__contains__,
        "shuffle-type": ["random", "weighted", "off", "0"].__contains__,
        "repeat": ["0", "1", "t", "on", "off", "toggle"].__contains__,
        "repeat-type": ["current", "all", "one", "off", "0"].__contains__,
        "volume": is_vol,
        "seek": is_time,
        "set-rating": is_float,
        "stop-after": ["0", "1", "t"].__contains__,
    }

    cmds_todo = []

    def queue(*args):
        cmds_todo.append(args)

    # XXX: to make startup work in case the desktop file isn't passed
    # a file path/uri
    if argv[-1] == "--play-file":
        argv = argv[:-1]

    opts, args = options.parse(argv[1:])

    for command, arg in opts.items():
        if command in controls:
            queue(command)
        elif command in controls_opt:
            if command in validators and not validators[command](arg):
                print_e(_("Invalid argument for '%s'.") % command)
                print_e(_("Try %s --help.") % fsn2text(argv[0]))
                exit_(True, notify_startup=True)
            else:
                queue(command, arg)
        elif command == "status":
            queue("status")
        elif command == "print-playlist":
            queue("dump-playlist")
        elif command == "print-queue":
            queue("dump-queue")
        elif command == "list-browsers":
            queue("dump-browsers")
        elif command == "volume-up":
            queue("volume +")
        elif command == "volume-down":
            queue("volume -")
        elif command == "enqueue" or command == "unqueue":
            try:
                filename = uri2fsn(arg)
            except ValueError:
                filename = arg
            queue(command, filename)
        elif command == "enqueue-files":
            queue(command, arg)
        elif command == "play-file":
            if uri_is_valid(arg) and arg.startswith("quodlibet://"):
                # TODO: allow handling of URIs without --play-file
                queue("uri-received", arg)
            else:
                try:
                    filename = uri2fsn(arg)
                except ValueError:
                    filename = arg
                filename = os.path.abspath(util.path.expanduser(arg))
                queue("play-file", filename)
        elif command == "print-playing":
            try:
                queue("print-playing", args[0])
            except IndexError:
                queue("print-playing")
        elif command == "print-query":
            queue(command, arg)
        elif command == "print-query-text":
            queue(command)
        elif command == "start-playing":
            actions.append(command)
        elif command == "start-hidden":
            actions.append(command)
        elif command == "no-plugins":
            actions.append(command)
        elif command == "run":
            actions.append(command)

    if cmds_todo:
        for cmd in cmds_todo:
            control(*cmd, **{"ignore_error": "run" in actions})
    else:
        # this will exit if it succeeds
        control('focus', ignore_error=True)

    return actions, cmds_todo
예제 #32
0
파일: cli.py 프로젝트: piotrdrag/quodlibet
def process_arguments(argv):
    from quodlibet.util.path import uri_is_valid
    from quodlibet import util
    from quodlibet import const

    actions = []
    controls = ["next", "previous", "play", "pause", "play-pause", "stop",
                "hide-window", "show-window", "toggle-window",
                "focus", "quit", "unfilter", "refresh", "force-previous"]
    controls_opt = ["seek", "repeat", "query", "volume", "filter",
                    "set-rating", "set-browser", "open-browser", "shuffle",
                    "song-list", "queue", "stop-after"]

    options = util.OptionParser(
        "Quod Libet", const.VERSION,
        _("a music library and player"),
        _("[option]"))

    options.add("print-playing", help=_("Print the playing song and exit"))
    options.add("start-playing", help=_("Begin playing immediately"))

    for opt, help in [
        ("next", _("Jump to next song")),
        ("previous",
            _("Jump to previous song or restart if near the beginning")),
        ("force-previous", _("Jump to previous song")),
        ("play", _("Start playback")),
        ("pause", _("Pause playback")),
        ("play-pause", _("Toggle play/pause mode")),
        ("stop", _("Stop playback")),
        ("volume-up", _("Turn up volume")),
        ("volume-down", _("Turn down volume")),
        ("status", _("Print player status")),
        ("hide-window", _("Hide main window")),
        ("show-window", _("Show main window")),
        ("toggle-window", _("Toggle main window visibility")),
        ("focus", _("Focus the running player")),
        ("unfilter", _("Remove active browser filters")),
        ("refresh", _("Refresh and rescan library")),
        ("list-browsers", _("List available browsers")),
        ("print-playlist", _("Print the current playlist")),
        ("print-queue", _("Print the contents of the queue")),
        ("print-query-text", _("Print the active text query")),
        ("no-plugins", _("Start without plugins")),
        ("run", _("Start Quod Libet if it isn't running")),
        ("quit", _("Exit Quod Libet")),
            ]:
        options.add(opt, help=help)

    for opt, help, arg in [
        ("seek", _("Seek within the playing song"), _("[+|-][HH:]MM:SS")),
        ("shuffle", _("Set or toggle shuffle mode"), "[0|1|t"),
        ("repeat", _("Turn repeat off, on, or toggle it"), "0|1|t"),
        ("volume", _("Set the volume"), "(+|-|)0..100"),
        ("query", _("Search your audio library"), _("query")),
        ("play-file", _("Play a file"), C_("command", "filename")),
        ("set-rating", _("Rate the playing song"), "0.0..1.0"),
        ("set-browser", _("Set the current browser"), "BrowserName"),
        ("stop-after", _("Stop after the playing song"), "0|1|t"),
        ("open-browser", _("Open a new browser"), "BrowserName"),
        ("queue", _("Show or hide the queue"), "on|off|t"),
        ("song-list",
            _("Show or hide the main song list (deprecated)"), "on|off|t"),
        ("random", _("Filter on a random value"), C_("command", "tag")),
        ("filter", _("Filter on a tag value"), _("tag=value")),
        ("enqueue", _("Enqueue a file or query"), "%s|%s" % (
            C_("command", "filename"), _("query"))),
        ("enqueue-files", _("Enqueue comma-separated files"), "%s[,%s..]" % (
            _("filename"), _("filename"))),
        ("print-query", _("Print filenames of results of query to stdout"),
            _("query")),
        ("unqueue", _("Unqueue a file or query"), "%s|%s" % (
            C_("command", "filename"), _("query"))),
            ]:
        options.add(opt, help=help, arg=arg)

    options.add("sm-config-prefix", arg="dummy")
    options.add("sm-client-id", arg="prefix")
    options.add("screen", arg="dummy")

    def is_vol(str):
        if str[0] in '+-':
            if len(str) == 1:
                return True
            str = str[1:]
        return str.isdigit()

    def is_time(str):
        if str[0] not in "+-0123456789":
            return False
        elif str[0] in "+-":
            str = str[1:]
        parts = str.split(":")
        if len(parts) > 3:
            return False
        else:
            return not (False in [p.isdigit() for p in parts])

    def is_float(str):
        try:
            float(str)
        except ValueError:
            return False
        else:
            return True

    validators = {
        "shuffle": ["0", "1", "t", "on", "off", "toggle"].__contains__,
        "repeat": ["0", "1", "t", "on", "off", "toggle"].__contains__,
        "volume": is_vol,
        "seek": is_time,
        "set-rating": is_float,
        "stop-after": ["0", "1", "t"].__contains__,
        }

    cmds_todo = []

    def queue(*args):
        cmds_todo.append(args)

    # XXX: to make startup work in case the desktop file isn't passed
    # a file path/uri
    if argv[-1] == "--play-file":
        argv = argv[:-1]

    opts, args = options.parse(argv[1:])

    for command, arg in opts.items():
        if command in controls:
            queue(command)
        elif command in controls_opt:
            if command in validators and not validators[command](arg):
                print_e(_("Invalid argument for '%s'.") % command)
                print_e(_("Try %s --help.") % fsn2text(argv[0]))
                exit_(True, notify_startup=True)
            else:
                queue(command, arg)
        elif command == "status":
            queue("status")
        elif command == "print-playlist":
            queue("dump-playlist")
        elif command == "print-queue":
            queue("dump-queue")
        elif command == "list-browsers":
            queue("dump-browsers")
        elif command == "volume-up":
            queue("volume +")
        elif command == "volume-down":
            queue("volume -")
        elif command == "enqueue" or command == "unqueue":
            try:
                filename = uri2fsn(arg)
            except ValueError:
                filename = arg
            queue(command, filename)
        elif command == "enqueue-files":
            queue(command, arg)
        elif command == "play-file":
            if uri_is_valid(arg) and arg.startswith("quodlibet://"):
                # TODO: allow handling of URIs without --play-file
                queue("uri-received", arg)
            else:
                try:
                    filename = uri2fsn(arg)
                except ValueError:
                    filename = arg
                filename = os.path.abspath(util.path.expanduser(arg))
                queue("play-file", filename)
        elif command == "print-playing":
            try:
                queue("print-playing", args[0])
            except IndexError:
                queue("print-playing")
        elif command == "print-query":
            queue(command, arg)
        elif command == "print-query-text":
            queue(command)
        elif command == "start-playing":
            actions.append(command)
        elif command == "no-plugins":
            actions.append(command)
        elif command == "run":
            actions.append(command)

    if cmds_todo:
        for cmd in cmds_todo:
            control(*cmd, **{"ignore_error": "run" in actions})
    else:
        # this will exit if it succeeds
        control('focus', ignore_error=True)

    return actions, cmds_todo