Exemple #1
0
def get_example_xml(song_path, rating, lastplayed):

    song_uri = URI.frompath(song_path)
    mount_uri = URI.frompath(find_mount_point(song_path))

    return """\
<?xml version="1.0" standalone="yes"?>
<rhythmdb version="1.9">
  <entry type="song">
    <title>Music</title>
    <genre>Unknown</genre>
    <track-number>7</track-number>
    <duration>199</duration>
    <file-size>4799124</file-size>
    <location>%s</location>
    <mountpoint>%s</mountpoint>
    <mtime>1378717158</mtime>
    <first-seen>1339576187</first-seen>
    <last-seen>1409855394</last-seen>
    <last-played>%d</last-played>
    <play-count>1</play-count>
    <bitrate>191</bitrate>
    <rating>%d</rating>
    <date>731881</date>
    <media-type>audio/mpeg</media-type>
    <composer>Unknown</composer>
  </entry>
</rhythmdb>\
""" % (song_uri, mount_uri, lastplayed, rating)
def get_example_xml(song_path, rating, lastplayed):

    song_uri = URI.frompath(song_path)
    mount_uri = URI.frompath(find_mount_point(song_path))

    return """\
<?xml version="1.0" standalone="yes"?>
<rhythmdb version="1.9">
  <entry type="song">
    <title>Music</title>
    <genre>Unknown</genre>
    <track-number>7</track-number>
    <duration>199</duration>
    <file-size>4799124</file-size>
    <location>%s</location>
    <mountpoint>%s</mountpoint>
    <mtime>1378717158</mtime>
    <first-seen>1339576187</first-seen>
    <last-seen>1409855394</last-seen>
    <last-played>%d</last-played>
    <play-count>1</play-count>
    <bitrate>191</bitrate>
    <rating>%d</rating>
    <date>731881</date>
    <media-type>audio/mpeg</media-type>
    <composer>Unknown</composer>
  </entry>
</rhythmdb>\
""" % (song_uri, mount_uri, lastplayed, rating)
Exemple #3
0
    def test_leading_slashes(self):
        self.assertEqual(str(URI("file://" + "/foo/bar")),
                         "file://" + "/foo/bar")
        self.assertEqual(str(URI("file://" + "//foo/bar")),
                         "file://" + "//foo/bar")

        self.assertEqual(URI("file://" + "//foo/bar").path, "//foo/bar")

        self.assertEqual(str(URI("file://" + "///foo/bar")),
                         "file://" + "///foo/bar")
        self.assertEqual(str(URI("file://" + "////foo/bar")),
                         "file://" + "////foo/bar")
Exemple #4
0
    def test_unc_paths(self):
        if os.name != "nt":
            return

        self.assertEqual(
            URI.frompath(u"\\\\server\\share\\path"),
            r"file:////server/share/path")
def __parse_playlist(name, plfilename, files, library):
    playlist = Playlist.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):
        try:
            uri = URI(filename)
        except ValueError:
            # 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:
            if uri.scheme == "file":
                # URI-encoded local filename.
                filename = os.path.realpath(
                    os.path.join(os.path.dirname(plfilename), uri.filename))
                if library and filename in library:
                    songs.append(library[filename])
                else:
                    songs.append(formats.MusicFile(filename))
            else:
                # Who knows! Hand it off to GStreamer.
                songs.append(formats.remote.RemoteFile(uri))
        if win.step():
            break
    win.destroy()
    playlist.extend(filter(None, songs))
    return playlist
Exemple #6
0
    def _get_image_uri(self, song):
        """A unicode file URI or an empty string"""

        fileobj = app.cover_manager.get_cover(song)
        self._set_image_fileobj(fileobj)
        if fileobj:
            image_path = fileobj.name
            return URI.frompath(image_path).decode("utf-8")
        return u""
Exemple #7
0
 def valid_uri(s):
     # TODO: some pattern validation too (that isn't slow)
     try:
         p = Pattern(s)
         u = URI(s)
         return (p and u.netloc
                 and u.scheme in ["http", "https", "ftp", "file"])
     except ValueError:
         return False
Exemple #8
0
    def _get_image_uri(self, song):
        """A unicode file URI or an empty string"""

        fileobj = app.cover_manager.get_cover(song)
        self._set_image_fileobj(fileobj)
        if fileobj:
            image_path = fileobj.name
            return URI.frompath(image_path).decode("utf-8")
        return u""
def browse_files_thunar(songs, display=""):
    bus = dbus.SessionBus()
    bus_object = bus.get_object(XFCE_NAME, XFCE_PATH)
    bus_iface = dbus.Interface(bus_object, dbus_interface=XFCE_IFACE)
    for song in songs:
        dirname = song("~dirname")
        basename = song("~basename")
        bus_iface.DisplayFolderAndSelect(URI.frompath(dirname), basename,
                                         display, get_startup_id())
Exemple #10
0
    def test_windows_path(self):
        if os.name != "nt":
            return

        win_path = u"C:\\SomeDir\xe4"
        uri = URI.frompath(win_path)
        self.assertEqual(uri, "file:///C:/SomeDir%C3%A4")
        self.assertTrue(uri.is_filename)
        self.assertTrue(is_fsnative(uri.filename))
        self.assertEqual(uri.filename, win_path)
Exemple #11
0
    def test_windows_path(self):
        if os.name != "nt":
            return

        win_path = u"C:\\SomeDir\xe4"
        uri = URI.frompath(win_path)
        self.assertEqual(uri, "file:///C:/SomeDir%C3%A4")
        self.assertTrue(uri.is_filename)
        self.assertTrue(is_fsnative(uri.filename))
        self.assertEqual(uri.filename, win_path)
Exemple #12
0
    def _verify_clipboard(self, text):
        # try to extract a URI from the clipboard
        for line in text.splitlines():
            line = line.strip()

            try:
                URI(line)
            except ValueError:
                pass
            else:
                return line
Exemple #13
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 = URI(uris[0]).filename
             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)
 def test_parse_onesong_uri(self):
     h, name = mkstemp()
     os.close(h)
     target = os.path.join(DATA_DIR, "silence-44-s.ogg")
     from quodlibet.util.uri import URI
     target = URI.frompath(target)
     target = self.prefix + target
     with open(name, "w") as f:
         f.write(target)
     list = self.Parse(name)
     os.unlink(name)
     self.failUnlessEqual(len(list), 1)
     self.failUnlessEqual(list[0]("title"), "Silence")
     list.delete()
 def test_parse_onesong_uri(self):
     h, name = mkstemp()
     os.close(h)
     target = os.path.join(DATA_DIR, "silence-44-s.ogg")
     from quodlibet.util.uri import URI
     target = URI.frompath(target)
     target = self.prefix + target
     with open(name, "w") as f:
         f.write(target)
     list = self.Parse(name)
     os.unlink(name)
     self.failUnlessEqual(len(list), 1)
     self.failUnlessEqual(list[0]("title"), "Silence")
     list.delete()
    def test_parse_onesong_uri(self):
        name = makename()
        target = os.path.join(os.getcwd(), "tests/data/silence-44-s.ogg")
        from quodlibet.util.uri import URI

        target = URI.frompath(target)
        target = self.prefix + target
        f = file(name, "w")
        f.write(target)
        f.close()
        list = self.Parse(name)
        os.unlink(name)
        self.failUnlessEqual(len(list), 1)
        self.failUnlessEqual(list[0]("title"), "Silence")
        list.delete()
Exemple #17
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:
                    p_uri = URI(uri)
                except ValueError:
                    return

                if not p_uri.is_filename:
                    return

                self._process_song(normalize_path(p_uri.filename), current)
Exemple #18
0
def _enqueue_files(app, value):
    """Enqueues comma-separated filenames or song names."""

    library = app.library
    window = app.window
    songs = []
    for param in value.split(","):
        try:
            song_path = URI(param).filename
        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)
Exemple #19
0
 def get_property(self, interface, name):
     if interface == MediaObject.IFACE:
         if name == "Parent":
             return EntryObject.PATH
         elif name == "Type":
             return "image"
         elif name == "Path":
             return Icon.PATH
         elif name == "DisplayName":
             return "I'm an icon \o/"
     elif interface == MediaItem.IFACE:
         if name == "URLs":
             return [URI.frompath(self.__f.name)]
         elif name == "MIMEType":
             return "image/png"
         elif name == "Width" or name == "Height":
             return Icon.SIZE
         elif name == "ColorDepth":
             return self.__depth
Exemple #20
0
 def get_property(self, interface, name):
     if interface == MediaObject.IFACE:
         if name == "Parent":
             return EntryObject.PATH
         elif name == "Type":
             return "image"
         elif name == "Path":
             return Icon.PATH
         elif name == "DisplayName":
             return "I'm an icon \o/"
     elif interface == MediaItem.IFACE:
         if name == "URLs":
             return [URI.frompath(self.__f.name)]
         elif name == "MIMEType":
             return "image/png"
         elif name == "Width" or name == "Height":
             return Icon.SIZE
         elif name == "ColorDepth":
             return self.__depth
Exemple #21
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:
                uri = URI(uri)
            except ValueError:
                continue

            if uri.is_filename:
                loc = os.path.normpath(uri.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")
Exemple #22
0
    def __drag_data_get(self, view, ctx, sel, tid, etime):
        model, rows = view.get_selection().get_selected_rows()
        dirs = [model[row][0] for row in rows]
        for songs in self.__find_songs(view.get_selection()):
            pass
        if tid == self.TARGET_QL:
            cant_add = filter(lambda s: not s.can_add, songs)
            if cant_add:
                qltk.ErrorMessage(
                    qltk.get_top_parent(self), _("Unable to copy songs"),
                    _("The files selected cannot be copied to other "
                      "song lists or the queue.")).run()
                ctx.drag_abort(etime)
                return
            to_add = filter(self.__library.__contains__, songs)
            self.__add_songs(view, to_add)

            qltk.selection_set_songs(sel, songs)
        else:
            # External target (app) is delivered a list of URIS of songs
            uris = list({URI.frompath(dir) for dir in dirs})
            print_d("Directories to drop: %s" % [u.filename for u in uris])
            sel.set_uris(uris)
Exemple #23
0
    def __drag_data_get(self, view, ctx, sel, tid, etime):
        model, rows = view.get_selection().get_selected_rows()
        dirs = [model[row][0] for row in rows]
        for songs in self.__find_songs(view.get_selection()):
            pass
        if tid == self.TARGET_QL:
            cant_add = filter(lambda s: not s.can_add, songs)
            if cant_add:
                qltk.ErrorMessage(
                    qltk.get_top_parent(self), _("Unable to copy songs"),
                    _("The files selected cannot be copied to other "
                      "song lists or the queue.")).run()
                ctx.drag_abort(etime)
                return
            to_add = filter(self.__library.__contains__, songs)
            self.__add_songs(view, to_add)

            qltk.selection_set_songs(sel, songs)
        else:
            # External target (app) is delivered a list of URIS of songs
            uris = list(set([URI.frompath(dir) for dir in dirs]))
            print_d("Directories to drop: %s" % [u.filename for u in uris])
            sel.set_uris(uris)
Exemple #24
0
def browse_folders_thunar(songs, display=""):
    # http://git.xfce.org/xfce/thunar/tree/thunar/thunar-dbus-service-infos.xml
    XFCE_PATH = "/org/xfce/FileManager"
    XFCE_NAME = "org.xfce.FileManager"
    XFCE_IFACE = "org.xfce.FileManager"

    if not dbus:
        raise BrowseError("no dbus")

    try:
        bus = dbus.SessionBus()
        bus_object = bus.get_object(XFCE_NAME, XFCE_PATH)
        bus_iface = dbus.Interface(bus_object, dbus_interface=XFCE_IFACE)

        # open each folder and select the first file we have selected
        for dirname, sub_songs in group_songs(songs).items():
            bus_iface.DisplayFolderAndSelect(
                URI.frompath(dirname),
                sub_songs[0]("~basename"),
                display,
                get_startup_id())
    except dbus.DBusException as e:
        raise BrowseError(e)
Exemple #25
0
    def __call__(self, key, default=u"", connector=" - "):
        """Return a key, synthesizing it if necessary. A default value
        may be given (like dict.get); the default default is an empty
        unicode string (even if the tag is numeric).

        If a tied tag ('a~b') is requested, the 'connector' keyword
        argument may be used to specify what it is tied with.
        In case the tied tag contains numeric and file path tags, the result
        will still be a unicode string.

        For details on tied tags, see the documentation for util.tagsplit.
        """

        if key[:1] == "~":
            key = key[1:]
            if "~" in key:
                real_key = "~" + key
                values = []
                for v in map(self.__call__, util.tagsplit(real_key)):
                    v = decode_value(real_key, v)
                    if v:
                        values.append(v)
                return connector.join(values) or default
            elif key == "#track":
                try:
                    return int(self["tracknumber"].split("/")[0])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "#disc":
                try:
                    return int(self["discnumber"].split("/")[0])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "length":
                length = self.get("~#length")
                if length is None:
                    return default
                else:
                    return util.format_time_display(length)
            elif key == "#rating":
                return dict.get(self, "~" + key, config.RATINGS.default)
            elif key == "rating":
                return util.format_rating(self("~#rating"))
            elif key == "people":
                return "\n".join(self.list_unique(PEOPLE)) or default
            elif key == "people:real":
                # Issue 1034: Allow removal of V.A. if others exist.
                unique = self.list_unique(PEOPLE)
                # Order is important, for (unlikely case): multiple removals
                for val in VARIOUS_ARTISTS_VALUES:
                    if len(unique) > 1 and val in unique:
                        unique.remove(val)
                return "\n".join(unique) or default
            elif key == "people:roles":
                return (self._role_call("performer", PEOPLE)
                        or default)
            elif key == "peoplesort":
                return ("\n".join(self.list_unique(PEOPLE_SORT)) or
                        self("~people", default, connector))
            elif key == "peoplesort:roles":
                # Ignores non-sort tags if there are any sort tags (e.g. just
                # returns "B" for {artist=A, performersort=B}).
                # TODO: figure out the "correct" behavior for mixed sort tags
                return (self._role_call("performersort", PEOPLE_SORT)
                        or self("~peoplesort", default, connector))
            elif key in ("performers", "performer"):
                return self._prefixvalue("performer") or default
            elif key in ("performerssort", "performersort"):
                return (self._prefixvalue("performersort") or
                        self("~" + key[-4:], default, connector))
            elif key in ("performers:roles", "performer:roles"):
                return (self._role_call("performer") or default)
            elif key in ("performerssort:roles", "performersort:roles"):
                return (self._role_call("performersort")
                        or self("~" + key.replace("sort", ""), default,
                                connector))
            elif key == "basename":
                return os.path.basename(self["~filename"]) or self["~filename"]
            elif key == "dirname":
                return os.path.dirname(self["~filename"]) or self["~filename"]
            elif key == "uri":
                try:
                    return self["~uri"]
                except KeyError:
                    return URI.frompath(self["~filename"])
            elif key == "format":
                return self.get("~format", self.format)
            elif key == "#date":
                date = self.get("date")
                if date is None:
                    return default
                return util.date_key(date)
            elif key == "year":
                return self.get("date", default)[:4]
            elif key == "#year":
                try:
                    return int(self.get("date", default)[:4])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "originalyear":
                return self.get("originaldate", default)[:4]
            elif key == "#originalyear":
                try:
                    return int(self.get("originaldate", default)[:4])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "#tracks":
                try:
                    return int(self["tracknumber"].split("/")[1])
                except (ValueError, IndexError, TypeError, KeyError):
                    return default
            elif key == "#discs":
                try:
                    return int(self["discnumber"].split("/")[1])
                except (ValueError, IndexError, TypeError, KeyError):
                    return default
            elif key == "lyrics":
                try:
                    fileobj = file(self.lyric_filename, "rU")
                except EnvironmentError:
                    return default
                else:
                    return fileobj.read().decode("utf-8", "replace")
            elif key == "filesize":
                return util.format_size(self("~#filesize", 0))
            elif key == "playlists":
                # See Issue 876
                # Avoid circular references from formats/__init__.py
                from quodlibet.util.collection import Playlist
                playlists = Playlist.playlists_featuring(self)
                return "\n".join([s.name for s in playlists]) or default
            elif key.startswith("#replaygain_"):
                try:
                    val = self.get(key[1:], default)
                    return round(float(val.split(" ")[0]), 2)
                except (ValueError, TypeError, AttributeError):
                    return default
            elif key[:1] == "#":
                key = "~" + key
                if key in self:
                    return self[key]
                elif key in INTERN_NUM_DEFAULT:
                    return dict.get(self, key, 0)
                else:
                    try:
                        val = self[key[2:]]
                    except KeyError:
                        return default
                    try:
                        return int(val)
                    except ValueError:
                        try:
                            return float(val)
                        except ValueError:
                            return default
            else:
                return dict.get(self, "~" + key, default)

        elif key == "title":
            title = dict.get(self, "title")
            if title is None:
                basename = self("~basename")
                return "%s [%s]" % (
                    decode_value("~basename", basename), _("Unknown"))
            else:
                return title
        elif key in SORT_TO_TAG:
            try:
                return self[key]
            except KeyError:
                key = SORT_TO_TAG[key]
        return dict.get(self, key, default)
Exemple #26
0
    def show_notification(self, song):
        """Returns True if showing the notification was successful"""

        if not song:
            return True

        try:
            if self.__enabled:
                # we are enabled try to work with the data we have and
                # keep it fresh
                if not self.__interface:
                    iface, caps, spec = self.__get_interface()
                    self.__interface = iface
                    self.__caps = caps
                    self.__spec_version = spec
                    if "actions" in caps:
                        self.__action_sig = iface.connect_to_signal(
                            "ActionInvoked", self.on_dbus_action)
                else:
                    iface = self.__interface
                    caps = self.__caps
                    spec = self.__spec_version
            else:
                # not enabled, just get everything temporary,
                # propably preview
                iface, caps, spec = self.__get_interface()

        except dbus.DBusException:
            print_w("[notify] %s" %
                    _("Couldn't connect to notification daemon."))
            self.__disconnect()
            return False

        strip_markup = lambda t: re.subn("\</?[iub]\>", "", t)[0]
        strip_links = lambda t: re.subn("\</?a.*?\>", "", t)[0]
        strip_images = lambda t: re.subn("\<img.*?\>", "", t)[0]

        title = XMLFromPattern(get_conf_value("titlepattern")) % song
        title = unescape(strip_markup(strip_links(strip_images(title))))

        body = ""
        if "body" in caps:
            body = XMLFromPattern(get_conf_value("bodypattern")) % song

            if "body-markup" not in caps:
                body = strip_markup(body)
            if "body-hyperlinks" not in caps:
                body = strip_links(body)
            if "body-images" not in caps:
                body = strip_images(body)

        image_path = ""
        if "icon-static" in caps:
            self.__image_fp = song.find_cover()
            if self.__image_fp:
                image_path = self.__image_fp.name

        is_temp = image_path.startswith(tempfile.gettempdir())

        # If it is not an embeded cover, drop the file handle
        if not is_temp:
            self.__image_fp = None

        # spec recommends it, and it seems to work
        if image_path and spec >= (1, 1):
            image_path = URI.frompath(image_path)

        actions = []
        if "actions" in caps:
            actions = ["next", _("Next")]

        hints = {
            "desktop-entry": "quodlibet",
        }

        try:
            self.__last_id = iface.Notify("Quod Libet", self.__last_id,
                                          image_path, title, body, actions,
                                          hints, get_conf_int("timeout"))
        except dbus.DBusException:
            print_w("[notify] %s" %
                    _("Couldn't connect to notification daemon."))
            self.__disconnect()
            return False

        # preview done, remove all references again
        if not self.__enabled:
            self.__disconnect()

        return True
Exemple #27
0
def process_arguments(argv):
    from quodlibet.util.uri import URI
    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", "order", "repeat", "query", "volume", "filter", "set-rating",
        "set-browser", "open-browser", "random", "song-list", "queue"
    ]

    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")),
        ("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")),
        ("order", _("Set or toggle the playback order"), "[order]|toggle"),
        ("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"),
        ("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"), "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 = {
        "order":
        ["0", "1", "t", "toggle", "inorder", "shuffle", "weighted",
         "onesong"].__contains__,
        "repeat": ["0", "1", "t", "on", "off", "toggle"].__contains__,
        "volume":
        is_vol,
        "seek":
        is_time,
        "set-rating":
        is_float,
    }

    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.") % sys.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 = URI(arg).filename
            except ValueError:
                filename = arg
            queue(command, filename)
        elif command == "enqueue-files":
            queue(command, arg)
        elif command == "play-file":
            try:
                filename = URI(arg).filename
            except ValueError:
                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 == "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
Exemple #28
0
    def __call__(self, key, default=u"", connector=" - "):
        """Return a key, synthesizing it if necessary. A default value
        may be given (like dict.get); the default default is an empty
        unicode string (even if the tag is numeric).

        If a tied tag ('a~b') is requested, the 'connector' keyword
        argument may be used to specify what it is tied with.

        For details on tied tags, see the documentation for util.tagsplit."""

        if key[:1] == "~":
            key = key[1:]
            if "~" in key:
                # FIXME: decode ~filename etc.
                if not isinstance(default, basestring): return default
                return connector.join(
                    filter(None,
                    map(lambda x: isinstance(x, basestring) and x or str(x),
                    map(lambda x: (isinstance(x, float) and "%.2f" % x) or x,
                    map(self.__call__, util.tagsplit("~" + key)))))) or default
            elif key == "#track":
                try: return int(self["tracknumber"].split("/")[0])
                except (ValueError, TypeError, KeyError): return default
            elif key == "#disc":
                try: return int(self["discnumber"].split("/")[0])
                except (ValueError, TypeError, KeyError): return default
            elif key == "length":
                length = self.get("~#length")
                if length is None: return default
                else: return util.format_time(length)
            elif key == "#rating":
                return dict.get(self, "~" + key, const.DEFAULT_RATING)
            elif key == "rating":
                return util.format_rating(self("~#rating"))
            elif key == "people":
                join = "\n".join
                people = filter(None, map(self.__call__, PEOPLE))
                if not people: return default
                people = join(people).split("\n")
                index = people.index
                return join([person for (i, person) in enumerate(people)
                        if index(person) == i])
            elif key == "peoplesort":
                join = "\n".join
                people = filter(None, map(self.__call__, PEOPLE_SORT))
                people = join(people).split("\n")
                index = people.index
                return (join([person for (i, person) in enumerate(people)
                              if index(person) == i]) or
                        self("~people", default, connector))
            elif key == "performers" or key == "performer":
                performers = {}
                for key in self.keys():
                    if key.startswith("performer:"):
                        role = key.split(":", 1)[1]
                        for value in self.list(key):
                            try:
                                performers[str(value)]
                            except:
                                performers[str(value)] = []
                            performers[str(value)].append(util.title(role))
                values = []
                if len(performers) > 0:
                    for performer in performers:
                        roles = ''
                        i = 0
                        for role in performers[performer]:
                            if i > 0:
                                roles += ', '
                            roles += role
                            i += 1
                        values.append("%s (%s)" % (performer, roles))
                values.extend(self.list("performer"))
                if not values: return default
                return "\n".join(values)
            elif key == "performerssort" or key == "performersort":
                values = []
                for key in self.keys():
                    if key.startswith("performersort:"):
                        role = key.split(":", 1)[1]
                        for value in self.list(key):
                            values.append("%s (%s)" % (value, role))
                values.extend(self.list("performersort"))
                return ("\n".join(values) or
                        self("~performers", default, connector))
            elif key == "basename":
                return os.path.basename(self["~filename"]) or self["~filename"]
            elif key == "dirname":
                return os.path.dirname(self["~filename"]) or self["~filename"]
            elif key == "uri":
                try: return self["~uri"]
                except KeyError:
                    return URI.frompath(self["~filename"])
            elif key == "format":
                return self.get("~format", self.format)
            elif key == "year":
                return self.get("date", default)[:4]
            elif key == "#year":
                try: return int(self.get("date", default)[:4])
                except (ValueError, TypeError, KeyError): return default
            elif key == "originalyear":
                return self.get("originaldate", default)[:4]
            elif key == "#originalyear":
                try: return int(self.get("originaldate", default)[:4])
                except (ValueError, TypeError, KeyError): return default
            elif key == "#tracks":
                try: return int(self["tracknumber"].split("/")[1])
                except (ValueError, IndexError, TypeError, KeyError):
                    return default
            elif key == "#discs":
                try: return int(self["discnumber"].split("/")[1])
                except (ValueError, IndexError, TypeError, KeyError):
                    return default
            elif key == "lyrics":
                try: fileobj = file(self.lyric_filename, "rU")
                except EnvironmentError: return default
                else: return fileobj.read().decode("utf-8", "replace")
            elif key == "playlists":
                # See Issue 876
                # Avoid circular references from formats/__init__.py
                from quodlibet.util.collection import Playlist
                try:
                    start = time.time()
                    playlists = Playlist.playlists_featuring(self)
                    import random
                    if not random.randint(0, 1000):
                        print_d("A sample song('~playlists') call: took %d μs "
                                % (1E6 * (time.time() - start)))
                    return "\n".join([s.name for s in playlists])
                except KeyError:
                    return default
            elif key.startswith("#replaygain_"):
                try:
                    val = self.get(key[1:], default)
                    return round(float(val.split(" ")[0]), 2)
                except (ValueError, TypeError, AttributeError): return default
            elif key[:1] == "#":
                key = "~" + key
                if key in self: self[key]
                elif key in INTERN_NUM_DEFAULT:
                    return dict.get(self, key, 0)
                else:
                    try: val = self[key[2:]]
                    except KeyError: return default
                    try: return int(val)
                    except ValueError:
                        try: return float(val)
                        except ValueError: return default
            else: return dict.get(self, "~" + key, default)

        elif key == "title":
            title = dict.get(self, "title")
            if title is None:
                basename = self("~basename")
                basename = basename.decode(const.FSCODING, "replace")
                return "%s [%s]" % (basename, _("Unknown"))
            else: return title
        elif key in SORT_TO_TAG:
            try: return self[key]
            except KeyError:
                key = SORT_TO_TAG[key]
        return dict.get(self, key, default)
Exemple #29
0
 def setUp(s):
     s.http_uri = URI("http://www.example.com/~piman;woo?bar=quux#whee")
     s.rfile_uri = URI("file://example.com/home/piman/crazy")
     s.file_uri = URI.frompath("/home/piman/cr!azy")
Exemple #30
0
 def __init__(self, uri):
     self["~uri"] = str(URI(uri))
     self.sanitize(fsnative(unicode(self["~uri"])))
Exemple #31
0
 def __init__(self, uri):
     self["~uri"] = self["~filename"] = str(URI(uri))
     self["~mountpoint"] = ""
     self.sanitize(uri)
Exemple #32
0
    def __call__(self, key, default=u"", connector=" - "):
        """Return a key, synthesizing it if necessary. A default value
        may be given (like dict.get); the default default is an empty
        unicode string (even if the tag is numeric).

        If a tied tag ('a~b') is requested, the 'connector' keyword
        argument may be used to specify what it is tied with.

        For details on tied tags, see the documentation for util.tagsplit."""
        if key[:1] == "~":
            key = key[1:]
            if "~" in key:
                # FIXME: decode ~filename etc.
                if not isinstance(default, basestring):
                    return default
                return connector.join(
                    filter(
                        None,
                        map(
                            lambda x: isinstance(x, basestring) and x or str(x
                                                                             ),
                            map(
                                lambda x:
                                (isinstance(x, float) and "%.2f" % x) or x,
                                map(self.__call__,
                                    util.tagsplit("~" + key)))))) or default
            elif key == "#track":
                try:
                    return int(self["tracknumber"].split("/")[0])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "#disc":
                try:
                    return int(self["discnumber"].split("/")[0])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "length":
                length = self.get("~#length")
                if length is None:
                    return default
                else:
                    return util.format_time_display(length)
            elif key == "#rating":
                return dict.get(self, "~" + key, config.RATINGS.default)
            elif key == "rating":
                return util.format_rating(self("~#rating"))
            elif key == "people":
                return "\n".join(self.list_unique(PEOPLE)) or default
            elif key == "people:real":
                # Issue 1034: Allow removal of V.A. if others exist.
                unique = self.list_unique(PEOPLE)
                # Order is important, for (unlikely case): multiple removals
                for val in VARIOUS_ARTISTS_VALUES:
                    if len(unique) > 1 and val in unique:
                        unique.remove(val)
                return "\n".join(unique) or default
            elif key == "people:roles":
                return (self._role_call("performer", PEOPLE) or default)
            elif key == "peoplesort":
                return ("\n".join(self.list_unique(PEOPLE_SORT))
                        or self("~people", default, connector))
            elif key == "peoplesort:roles":
                # Ignores non-sort tags if there are any sort tags (e.g. just
                # returns "B" for {artist=A, performersort=B}).
                # TODO: figure out the "correct" behavior for mixed sort tags
                return (self._role_call("performersort", PEOPLE_SORT)
                        or self("~peoplesort", default, connector))
            elif key in ("performers", "performer"):
                return self._prefixvalue("performer") or default
            elif key in ("performerssort", "performersort"):
                return (self._prefixvalue("performersort")
                        or self("~" + key[-4:], default, connector))
            elif key in ("performers:roles", "performer:roles"):
                return (self._role_call("performer") or default)
            elif key in ("performerssort:roles", "performersort:roles"):
                return (self._role_call("performersort") or self(
                    "~" + key.replace("sort", ""), default, connector))
            elif key == "basename":
                return os.path.basename(self["~filename"]) or self["~filename"]
            elif key == "dirname":
                return os.path.dirname(self["~filename"]) or self["~filename"]
            elif key == "uri":
                try:
                    return self["~uri"]
                except KeyError:
                    return URI.frompath(self["~filename"])
            elif key == "format":
                return self.get("~format", self.format)
            elif key == "#date":
                date = self.get("date")
                if date is None:
                    return default
                return util.date_key(date)
            elif key == "year":
                return self.get("date", default)[:4]
            elif key == "#year":
                try:
                    return int(self.get("date", default)[:4])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "originalyear":
                return self.get("originaldate", default)[:4]
            elif key == "#originalyear":
                try:
                    return int(self.get("originaldate", default)[:4])
                except (ValueError, TypeError, KeyError):
                    return default
            elif key == "#tracks":
                try:
                    return int(self["tracknumber"].split("/")[1])
                except (ValueError, IndexError, TypeError, KeyError):
                    return default
            elif key == "#discs":
                try:
                    return int(self["discnumber"].split("/")[1])
                except (ValueError, IndexError, TypeError, KeyError):
                    return default
            elif key == "lyrics":
                try:
                    fileobj = file(self.lyric_filename, "rU")
                except EnvironmentError:
                    return default
                else:
                    return fileobj.read().decode("utf-8", "replace")
            elif key == "filesize":
                return util.format_size(self("~#filesize", 0))
            elif key == "playlists":
                # See Issue 876
                # Avoid circular references from formats/__init__.py
                from quodlibet.util.collection import Playlist
                playlists = Playlist.playlists_featuring(self)
                return "\n".join([s.name for s in playlists]) or default
            elif key.startswith("#replaygain_"):
                try:
                    val = self.get(key[1:], default)
                    return round(float(val.split(" ")[0]), 2)
                except (ValueError, TypeError, AttributeError):
                    return default
            elif key[:1] == "#":
                key = "~" + key
                if key in self:
                    return self[key]
                elif key in INTERN_NUM_DEFAULT:
                    return dict.get(self, key, 0)
                else:
                    try:
                        val = self[key[2:]]
                    except KeyError:
                        return default
                    try:
                        return int(val)
                    except ValueError:
                        try:
                            return float(val)
                        except ValueError:
                            return default
            else:
                return dict.get(self, "~" + key, default)

        elif key == "title":
            title = dict.get(self, "title")
            if title is None:
                basename = self("~basename")
                basename = basename.decode(const.FSCODING, "replace")
                return "%s [%s]" % (basename, _("Unknown"))
            else:
                return title
        elif key in SORT_TO_TAG:
            try:
                return self[key]
            except KeyError:
                key = SORT_TO_TAG[key]
        return dict.get(self, key, default)
Exemple #33
0
    def __get_metadata(self):
        """http://xmms2.org/wiki/MPRIS_Metadata"""

        metadata = {}
        metadata["mpris:trackid"] = self.__get_current_track_id()

        song = app.player.info
        if not song:
            return metadata

        metadata["mpris:length"] = dbus.Int64(song("~#length") * 10**6)

        self.__cover = cover = app.cover_manager.get_cover(song)
        is_temp = False
        if cover:
            name = cover.name
            is_temp = name.startswith(tempfile.gettempdir())
            # This doesn't work for embedded images.. the file gets unlinked
            # after loosing the file handle
            metadata["mpris:artUrl"] = str(URI.frompath(name))

        if not is_temp:
            self.__cover = None

        # All list values
        list_val = {
            "artist": "artist",
            "albumArtist": "albumartist",
            "comment": "comment",
            "composer": "composer",
            "genre": "genre",
            "lyricist": "lyricist"
        }
        for xesam, tag in list_val.iteritems():
            vals = song.list(tag)
            if vals:
                metadata["xesam:" + xesam] = map(unival, vals)

        # All single values
        sing_val = {"album": "album", "title": "title", "asText": "~lyrics"}
        for xesam, tag in sing_val.iteritems():
            vals = song.comma(tag)
            if vals:
                metadata["xesam:" + xesam] = unival(vals)

        # URI
        metadata["xesam:url"] = song("~uri")

        # Integers
        num_val = {
            "audioBPM": "bpm",
            "discNumber": "disc",
            "trackNumber": "track",
            "useCount": "playcount"
        }

        for xesam, tag in num_val.iteritems():
            val = song("~#" + tag, None)
            if val is not None:
                metadata["xesam:" + xesam] = int(val)

        # Rating
        metadata["xesam:userRating"] = float(song("~#rating"))

        # Dates
        ISO_8601_format = "%Y-%m-%dT%H:%M:%S"
        tuple_time = time.gmtime(song("~#lastplayed"))
        iso_time = time.strftime(ISO_8601_format, tuple_time)
        metadata["xesam:lastUsed"] = iso_time

        year = song("~year")
        if year:
            try:
                tuple_time = time.strptime(year, "%Y")
                iso_time = time.strftime(ISO_8601_format, tuple_time)
            except ValueError:
                pass
            else:
                metadata["xesam:contentCreated"] = iso_time

        return metadata
Exemple #34
0
 def to_filename(s):
     try:
         return URI(s).filename
     except ValueError:
         return None
Exemple #35
0
    def __get_metadata(self):
        """http://xmms2.org/wiki/MPRIS_Metadata"""

        metadata = {}
        metadata["mpris:trackid"] = self.__get_current_track_id()

        song = app.player.info
        if not song:
            return metadata

        metadata["mpris:length"] = dbus.Int64(song("~#length") * 10 ** 6)

        self.__cover = cover = app.cover_manager.get_cover(song)
        is_temp = False
        if cover:
            name = cover.name
            is_temp = name.startswith(tempfile.gettempdir())
            # This doesn't work for embedded images.. the file gets unlinked
            # after loosing the file handle
            metadata["mpris:artUrl"] = str(URI.frompath(name))

        if not is_temp:
            self.__cover = None

        # All list values
        list_val = {
            "artist": "artist",
            "albumArtist": "albumartist",
            "comment": "comment",
            "composer": "composer",
            "genre": "genre",
            "lyricist": "lyricist",
        }
        for xesam, tag in list_val.iteritems():
            vals = song.list(tag)
            if vals:
                metadata["xesam:" + xesam] = map(unival, vals)

        # All single values
        sing_val = {"album": "album", "title": "title", "asText": "~lyrics"}
        for xesam, tag in sing_val.iteritems():
            vals = song.comma(tag)
            if vals:
                metadata["xesam:" + xesam] = unival(vals)

        # URI
        metadata["xesam:url"] = song("~uri")

        # Integers
        num_val = {"audioBPM": "bpm", "discNumber": "disc", "trackNumber": "track", "useCount": "playcount"}

        for xesam, tag in num_val.iteritems():
            val = song("~#" + tag, None)
            if val is not None:
                metadata["xesam:" + xesam] = int(val)

        # Rating
        metadata["xesam:userRating"] = float(song("~#rating"))

        # Dates
        ISO_8601_format = "%Y-%m-%dT%H:%M:%S"
        tuple_time = time.gmtime(song("~#lastplayed"))
        iso_time = time.strftime(ISO_8601_format, tuple_time)
        metadata["xesam:lastUsed"] = iso_time

        year = song("~year")
        if year:
            try:
                tuple_time = time.strptime(year, "%Y")
                iso_time = time.strftime(ISO_8601_format, tuple_time)
            except ValueError:
                pass
            else:
                metadata["xesam:contentCreated"] = iso_time

        return metadata
 def setUp(s):
     s.http_uri = URI("http://www.example.com/~piman;woo?bar=quux#whee")
     s.rfile_uri = URI("file://example.com/home/piman/crazy")
     s.file_uri = URI.frompath("/home/piman/cr!azy")
     s.extra_uri = URI("file:///////////home/piman")
Exemple #37
0
    def test_unc_paths(self):
        if os.name != "nt":
            return

        self.assertEqual(URI.frompath(u"\\\\server\\share\\path"),
                         r"file:////server/share/path")