def test_main(self):
     self.assertEqual(decode_value("~#foo", 0.25), u"0.25")
     self.assertEqual(decode_value("~#foo", 4), u"4")
     self.assertEqual(decode_value("~#foo", "bar"), u"bar")
     self.assertTrue(isinstance(decode_value("~#foo", "bar"), text_type))
     path = fsnative(u"/foobar")
     self.assertEqual(decode_value("~filename", path), fsn2text(path))
Exemple #2
0
def sort_key(song):
    """Sort by path so untagged albums have a good start order. Also
    take into account the directory in case it's split in different folders
    by medium.
    """

    return util.human_sort_key(fsn2text(song("~filename")))
    def test_path(self):
        try:
            path = bytes2fsn(b"\xff\xff", "utf-8")
        except ValueError:
            return

        assert decode_value("~filename", path) == fsn2text(path)
Exemple #4
0
def arg2text(arg):
    """Like fsn2text but is strict by default and raises CommandError"""

    try:
        return fsn2text(arg, strict=True)
    except ValueError as e:
        raise CommandError(e)
Exemple #5
0
def print_exc(exc_info=None, context=None):
    """Prints the stack trace of the current exception or the passed one.
    Depending on the configuration will either print a short summary or the
    whole stacktrace.
    """

    if exc_info is None:
        exc_info = sys.exc_info()

    etype, value, tb = exc_info

    if const.DEBUG:
        string = u"".join(format_exception(etype, value, tb))
    else:
        # try to get a short error message pointing at the cause of
        # the exception
        text = u"".join(format_exception_only(etype, value))
        try:
            filename, lineno, name, line = extract_tb(tb)[-1]
        except IndexError:
            # no stack
            string = text
        else:
            string = u"%s:%s:%s: %s" % (
                fsn2text(path2fsn(os.path.basename(filename))),
                lineno, name, text)

    _print_message(string, context, False, "E", "red", "errors")
Exemple #6
0
def get_available_languages(domain):
    """Returns a list of available translations for a given gettext domain.

    Args:
        domain (str)
    Returns:
        List[text_type]
    """

    locale_dir = gettext.bindtextdomain(domain)
    if locale_dir is None:
        return []

    try:
        entries = os.listdir(locale_dir)
    except OSError:
        return []

    langs = [u"C"]
    for lang in entries:
        mo_path = os.path.join(
            locale_dir, lang, "LC_MESSAGES", "%s.mo" % domain)
        if os.path.exists(mo_path):
            langs.append(fsn2text(path2fsn(lang)))
    return langs
Exemple #7
0
def _init_gettext(no_translations=False):
    """Call before using gettext helpers"""

    if no_translations:
        language = u"C"
    else:
        language = config.gettext("settings", "language")
        if not language:
            language = None

    i18n.init(language)

    # Use the locale dir in ../build/share/locale if there is one
    base_dir = get_base_dir()
    localedir = os.path.dirname(base_dir)
    localedir = os.path.join(localedir, "build", "share", "locale")
    if not os.path.isdir(localedir) and os.name == "nt":
        # py2exe case
        localedir = os.path.join(
            base_dir, "..", "..", "share", "locale")

    i18n.register_translation("quodlibet", localedir)
    debug_text = environ.get("QUODLIBET_TEST_TRANS")
    if debug_text is not None:
        i18n.set_debug_text(fsn2text(debug_text))
Exemple #8
0
    def scan(self, paths, exclude=[], cofuncid=None):

        def need_yield(last_yield=[0]):
            current = time.time()
            if abs(current - last_yield[0]) > 0.015:
                last_yield[0] = current
                return True
            return False

        def need_added(last_added=[0]):
            current = time.time()
            if abs(current - last_added[0]) > 1.0:
                last_added[0] = current
                return True
            return False

        # first scan each path for new files
        paths_to_load = []
        for scan_path in paths:
            print_d("Scanning %r." % scan_path)
            desc = _("Scanning %s") % (fsn2text(unexpand(scan_path)))
            with Task(_("Library"), desc) as task:
                if cofuncid:
                    task.copool(cofuncid)

                for real_path in iter_paths(scan_path, exclude=exclude):
                    if need_yield():
                        task.pulse()
                        yield
                    # skip unknown file extensions
                    if not formats.filter(real_path):
                        continue
                    # already loaded
                    if self.contains_filename(real_path):
                        continue
                    paths_to_load.append(real_path)

        yield

        # then (try to) load all new files
        with Task(_("Library"), _("Loading files")) as task:
            if cofuncid:
                task.copool(cofuncid)

            added = []
            for real_path in task.gen(paths_to_load):
                item = self.add_filename(real_path, False)
                if item is not None:
                    added.append(item)
                    if len(added) > 100 or need_added():
                        self.add(added)
                        added = []
                        yield
                if added and need_yield():
                    yield
            if added:
                self.add(added)
                added = []
                yield True
Exemple #9
0
 def cdf(column, cell, model, iter, data):
     row = model[iter]
     filename = fsn2text(unexpand(row[0]))
     function = row[1]
     line = row[2]
     cell.set_property(
         "markup", "<b>%s</b> line %d\n\t%s" % (
             util.escape(function), line, util.escape(filename)))
Exemple #10
0
        def label_path(path):
            l = Gtk.Label(label="<a href='%s'>%s</a>" % (
                            fsn2uri(path), escape(fsn2text(unexpand(path)))),
                          use_markup=True,
                          ellipsize=Pango.EllipsizeMode.MIDDLE,
                          xalign=0,
                          selectable=True)

            l.connect("activate-link", show_uri)
            return l
Exemple #11
0
    def __init__(self, parent, song):
        title = _("Unable to save song")

        fn_format = "<b>%s</b>" % util.escape(fsn2text(song("~basename")))
        description = _("Saving %(file-name)s failed. The file may be "
            "read-only, corrupted, or you do not have "
            "permission to edit it.") % {"file-name": fn_format}

        super(WriteFailedError, self).__init__(
            parent, title, description)
Exemple #12
0
    def _execute(self, options, args):
        if len(args) < 3:
            raise CommandError(_("Not enough arguments"))

        tag = fsn2text(args[0])
        value = fsn2text(args[1])
        paths = args[2:]

        songs = []
        for path in paths:
            song = self.load_song(path)

            if not song.can_change(tag):
                raise CommandError(_("Can not set %r") % tag)

            self.log("Add %r to %r" % (value, tag))
            song.add(tag, value)
            songs.append(song)

        self.save_songs(songs)
Exemple #13
0
    def __init__(self, parent, path):
        title = _("File exists")
        fn_format = "<b>%s</b>" % util.escape(fsn2text(path2fsn(path)))
        description = _("Replace %(file-name)s?") % {"file-name": fn_format}

        super(ConfirmFileReplace, self).__init__(
            parent, title, description, buttons=Gtk.ButtonsType.NONE)

        self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
        self.add_icon_button(_("_Replace File"), Icons.DOCUMENT_SAVE,
                             self.RESPONSE_REPLACE)
        self.set_default_response(Gtk.ResponseType.CANCEL)
Exemple #14
0
    def __preview(self, pattern, songs):
        rows = []
        for song in songs:
            match = pattern.match(song)
            row = [fsn2text(song("~basename"))]
            for header in pattern.headers:
                row.append(match.get(header, u""))
            rows.append(row)

        headers = [_("File")] + pattern.headers
        nicks = ["file"] + pattern.headers
        print_table(rows, headers, nicks, nicks)
Exemple #15
0
def unescape_filename(s):
    """Unescape a string in a manner suitable for a filename.

    Args:
        filename (fsnative)
    Returns:
        text_type
    """

    assert isinstance(s, fsnative)

    return fsn2text(unquote(s))
Exemple #16
0
    def search(self, data):
        for name in self._names:
            val = data.get(name)
            if val is None:
                # filename is the only real entry that's a path
                if name == "filename":
                    val = fsn2text(data.get("~filename", fsnative()))
                else:
                    val = data.get("~" + name, "")

            if self.res.search(unicode(val)):
                return True

        for name in self.__intern:
            if self.res.search(unicode(data(name))):
                return True

        for name in self.__fs:
            if self.res.search(fsn2text(data(name))):
                return True

        return False
Exemple #17
0
def parse_m3u(filename, library=None):
    plname = fsn2text(path2fsn(os.path.basename(
        os.path.splitext(filename)[0])))

    filenames = []

    with open(filename, "rb") as h:
        for line in h:
            line = line.strip()
            if line.startswith("#"):
                continue
            else:
                filenames.append(line)
    return __parse_playlist(plname, filename, filenames, library)
Exemple #18
0
def decode_value(tag, value):
    """Returns a unicode representation of the passed value, based on
    the type and the tag it originated from.

    Not reversible.
    """

    if isinstance(value, text_type):
        return value
    elif isinstance(value, float):
        return u"%.2f" % value
    elif tag in FILESYSTEM_TAGS:
        return fsn2text(value)
    return text_type(value)
Exemple #19
0
def fsdecode(path, note=True):
    """Takes a native path and returns unicode for displaying it.

    Can not fail and can't be reversed.
    """

    if isinstance(path, text_type):
        return path

    # XXX: glib paths on Windows
    if os.name == "nt" and isinstance(path, bytes):
        path = path.decode("utf-8")

    return fsn2text(path)
Exemple #20
0
    def __init__(self, paths):
        super(FileListExpander, self).__init__(label=_("Files:"))
        self.set_resize_toplevel(True)

        paths = [fsn2text(unexpand(p)) for p in paths]
        lab = Gtk.Label(label="\n".join(paths))
        lab.set_alignment(0.0, 0.0)
        lab.set_selectable(True)
        win = Gtk.ScrolledWindow()
        win.add_with_viewport(Align(lab, border=6))
        win.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC)
        win.set_shadow_type(Gtk.ShadowType.ETCHED_OUT)
        win.set_size_request(-1, 100)
        self.add(win)
        win.show_all()
Exemple #21
0
    def search(self, data):
        search = self.res.search
        fs_default = fsnative()

        for name in self._names:
            val = data.get(name)
            if val is None:
                if name in ("filename", "mountpoint"):
                    val = fsn2text(data.get("~" + name, fs_default))
                else:
                    val = data.get("~" + name, u"")

            if search(val):
                return True

        for name in self.__intern:
            if search(data(name)):
                return True

        for name in self.__fs:
            if search(fsn2text(data(name, fs_default))):
                return True

        return False
Exemple #22
0
    def sort_by_func(tag):
        """Returns a fast sort function for a specific tag (or pattern).
        Some keys are already in the sort cache, so we can use them."""
        def artist_sort(song):
            return song.sort_key[1][2]

        if callable(tag):
            return lambda song: human(tag(song))
        elif tag == "artistsort":
            return artist_sort
        elif tag in FILESYSTEM_TAGS:
            return lambda song: fsn2text(song(tag))
        elif tag.startswith("~#") and "~" not in tag[2:]:
            return lambda song: song(tag)
        return lambda song: human(song(tag))
Exemple #23
0
    def _song_to_text(self, song):
        # to text
        lines = []
        for key in sorted(song.realkeys(), key=sortkey):
            for value in song.list(key):
                lines.append(u"%s=%s" % (key, value))

        lines += [
            u"",
            u"#" * 80,
            u"# Lines that are empty or start with '#' will be ignored",
            u"# File: %r" % fsn2text(song("~filename")),
        ]

        return u"\n".join(lines)
Exemple #24
0
    def __init__(self, parent, song):
        title = _("Tag may not be accurate")

        fn_format = "<b>%s</b>" % util.escape(fsn2text(song("~basename")))
        description = _(
            "%(file-name)s changed while the program was running. "
            "Saving without refreshing your library may "
            "overwrite other changes to the song."
        ) % {"file-name": fn_format}

        super(OverwriteWarning, self).__init__(parent, title, description, buttons=Gtk.ButtonsType.NONE)

        self.add_button(_("_Cancel"), Gtk.ResponseType.CANCEL)
        self.add_icon_button(_("_Save"), Icons.DOCUMENT_SAVE, self.RESPONSE_SAVE)
        self.set_default_response(Gtk.ResponseType.CANCEL)
Exemple #25
0
    def __init__(self, filename):
        with translate_errors():
            with open(filename, "rb") as h:
                head = h.read(46)
                if len(head) != 46 or \
                        head[:27] != b'SNES-SPC700 Sound File Data':
                    raise IOError("Not a valid SNES-SPC700 file")

                if getbyte(head, 35) == b'\x1a':
                    data = h.read(210)
                    if len(data) == 210:
                        self.update(parse_id666(data))

        self.setdefault(
            "title", fsn2text(path2fsn(os.path.basename(filename)[:-4])))
        self.sanitize(filename)
Exemple #26
0
def parse_m3u(filename, library=None):
    plname = fsn2text(path2fsn(os.path.basename(
        os.path.splitext(filename)[0])))

    filenames = []

    with open(filename, "rb") as h:
        for line in h:
            line = line.strip()
            if line.startswith(b"#"):
                continue
            else:
                try:
                    filenames.append(bytes2fsn(line, "utf-8"))
                except ValueError:
                    continue
    return __parse_playlist(plname, filename, filenames, library)
Exemple #27
0
    def match_path(self, path):
        assert isinstance(path, fsnative)

        tail = os.path.splitdrive(path)[-1]

        # only match on the last n pieces of a filename, dictated by pattern
        # this means no pattern may effectively cross a /, despite .* doing so
        sep = os.path.sep
        matchon = sep + sep.join(tail.split(sep)[-self.slashes:])
        # work on unicode
        matchon = fsn2text(matchon)
        match = self.pattern.search(matchon)

        # dicts for all!
        if match is None:
            return {}
        else:
            return match.groupdict()
Exemple #28
0
def parse_pls(filename, name="", library=None):
    plname = fsn2text(path2fsn(os.path.basename(
        os.path.splitext(filename)[0])))

    filenames = []
    with open(filename) as h:
        for line in h:
            line = line.strip()
            if not line.lower().startswith("file"):
                continue
            else:
                try:
                    line = line[line.index("=") + 1:].strip()
                except ValueError:
                    pass
                else:
                    filenames.append(line)
    return __parse_playlist(plname, filename, filenames, library)
Exemple #29
0
    def __preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in itervalues(model)]

        pattern_text = gdecode(self.combo.get_child().get_text())

        try:
            pattern = FileFromPattern(pattern_text)
        except ValueError:
            qltk.ErrorMessage(
                self, _("Path is not absolute"),
                _("The pattern\n\t<b>%s</b>\ncontains / but "
                  "does not start from root. To avoid misnamed "
                  "folders, root your pattern by starting "
                  "it with / or ~/.") % (
                util.escape(pattern_text))).run()
            return
        else:
            if pattern:
                self.combo.prepend_text(pattern_text)
                self.combo.write(NBP)

        # native paths
        orignames = [song["~filename"] for song in songs]
        newnames = [fsn2text(pattern.format(song)) for song in songs]
        for f in self.filter_box.filters:
            if f.active:
                newnames = f.filter_list(orignames, newnames)

        model.clear()
        for song, newname in zip(songs, newnames):
            entry = Entry(song)
            entry.new_name = newname
            model.append(row=[entry])

        self.preview.set_sensitive(False)
        self.save.set_sensitive(bool(pattern_text))
        for song in songs:
            if not song.is_file:
                self.set_sensitive(False)
                break
        else:
            self.set_sensitive(True)
Exemple #30
0
    def comma(self, key):
        """Get all values of a tag, separated by commas. Synthetic
        tags are supported, but will be slower. All list items
        will be unicode.

        If the value is numeric, that is returned rather than a list.
        """

        if "~" in key or key == "title":
            v = self(key, u"")
            if key in FILESYSTEM_TAGS:
                v = fsn2text(v)
        else:
            v = self.get(key, u"")

        if isinstance(v, number_types):
            return v
        else:
            return v.replace("\n", ", ")
Exemple #31
0
def _name_for(filename):
    if not filename:
        return _("New Playlist")
    name = os.path.basename(os.path.splitext(filename)[0])
    return fsn2text(path2fsn(name))
Exemple #32
0
 def cell_data(column, cell, model, iter_, userdata):
     value = model.get_value(iter_)
     cell.set_property('text', fsn2text(os.path.basename(value)))
Exemple #33
0
 def name(self):
     return fsn2text(self.song("~basename"))
Exemple #34
0
def format_exception(*args, **kwargs):
    """Returns a list of text_type"""

    result_lines = traceback.format_exception(*args, **kwargs)
    return [fsn2text(path2fsn(l)) for l in result_lines]
Exemple #35
0
 def cell_data(column, cell, model, iter_, userdata):
     value = model.get_value(iter_)
     if value is not None:
         text = fsn2text(os.path.basename(value) or value)
         cell.set_property('text', text)
Exemple #36
0
    def cover(self):
        # TODO: Deserves some refactoring
        if not self.song.is_file:
            return None

        base = self.song('~dirname')
        images = []

        # Issue 374: Specify artwork filename
        if config.getboolean("albumart", "force_filename"):
            path = os.path.join(base, config.get("albumart", "filename"))
            if os.path.isfile(path):
                images = [(100, path)]
        else:
            entries = []
            try:
                entries = os.listdir(base)
            except EnvironmentError:
                print_w("Can't list album art directory %s" % base)

            fns = []
            for entry in entries:
                lentry = entry.lower()
                if get_ext(lentry) in self.cover_exts:
                    fns.append((None, entry))
                if lentry in self.cover_subdirs:
                    subdir = os.path.join(base, entry)
                    sub_entries = []
                    try:
                        sub_entries = os.listdir(subdir)
                    except EnvironmentError:
                        pass
                    for sub_entry in sub_entries:
                        lsub_entry = sub_entry.lower()
                        if get_ext(lsub_entry) in self.cover_exts:
                            fns.append((entry, sub_entry))

            for sub, fn in fns:
                dec_lfn = fsn2text(fn).lower()

                score = 0
                # check for the album label number
                labelid = self.song.get("labelid", "").lower()
                if labelid and labelid in dec_lfn:
                    score += 20

                # Track-related keywords
                values = self.song.list("~people") + [self.song("album")]
                lowers = [
                    value.lower().strip() for value in values if len(value) > 1
                ]
                score += 2 * sum([value in dec_lfn for value in lowers])

                # Generic keywords
                score += 3 * sum(
                    r.search(dec_lfn) is not None
                    for r in self.cover_positive_regexes)

                score -= 2 * sum(
                    r.search(dec_lfn) is not None
                    for r in self.cover_negative_regexes)

                # print("[%s - %s]: Album art \"%s\" scores %d." %
                #         (self.song("artist"), self.song("title"), fn, score))
                if score > 0:
                    if sub is not None:
                        fn = os.path.join(sub, fn)
                    images.append((score, os.path.join(base, fn)))
            images.sort(reverse=True)

        for score, path in images:
            # could be a directory
            if not os.path.isfile(path):
                continue
            try:
                return open(path, "rb")
            except IOError:
                print_w("Failed reading album art \"%s\"" % path)

        return None
 def _apply_value(self, model, iter_, cell, value):
     cell.set_property('text', fsn2text(unexpand(value)))
Exemple #38
0
    def cover(self):
        # TODO: Deserves some refactoring
        if not self.song.is_file:
            return None

        base = self.song('~dirname')
        images = []

        if config.getboolean("albumart", "force_filename"):
            score = 100
            for filename in config.get("albumart", "filename").split(","):
                # Remove white space to avoid confusion (e.g. "name, name2")
                filename = filename.strip()

                escaped_path = os.path.join(glob.escape(base), filename)
                try:
                    for path in glob.glob(escaped_path):
                        images.append((score, path))
                except sre_constants.error:
                    # Use literal filename if globbing causes errors
                    path = os.path.join(base, filename)

                    # We check this here, so we can search for alternative
                    # files in case no preferred file was found.
                    if os.path.isfile(path):
                        images.append((score, path))

                # So names and patterns at the start are preferred
                score -= 1

        if not images:
            entries = []
            try:
                entries = os.listdir(base)
            except EnvironmentError:
                print_w("Can't list album art directory %s" % base)

            fns = []
            for entry in entries:
                lentry = entry.lower()
                if get_ext(lentry) in self.cover_exts:
                    fns.append((None, entry))
                if lentry in self.cover_subdirs:
                    subdir = os.path.join(base, entry)
                    sub_entries = []
                    try:
                        sub_entries = os.listdir(subdir)
                    except EnvironmentError:
                        pass
                    for sub_entry in sub_entries:
                        lsub_entry = sub_entry.lower()
                        if get_ext(lsub_entry) in self.cover_exts:
                            fns.append((entry, sub_entry))

            for sub, fn in fns:
                dec_lfn = os.path.splitext(fsn2text(fn))[0].lower()

                score = 0
                # check for the album label number
                labelid = self.song.get("labelid", "").lower()
                if labelid and labelid in dec_lfn:
                    score += 20

                # Track-related keywords
                values = set(self.song.list("~people")) | {self.song("album")}
                lowers = [value.lower().strip() for value in values
                          if len(value) > 1]
                total_terms = sum(len(s.split()) for s in lowers)
                total_words = len([word for word in dec_lfn.split()
                                   if len(word) > 1])
                # Penalise for many extra words in filename (wrong file?)
                length_penalty = (- int((total_words - 1) / total_terms)
                                  if total_terms else 0)

                # Matching tag values are very good
                score += 3 * sum([value in dec_lfn for value in lowers])

                # Well known names matching exactly (folder.jpg)
                score += 4 * sum(r.search(dec_lfn) is not None
                                 for r in self.cover_name_regexes)

                # Generic keywords
                score += 2 * sum(r.search(dec_lfn) is not None
                                 for r in self.cover_positive_regexes)

                score -= 3 * sum(r.search(dec_lfn) is not None
                                 for r in self.cover_negative_regexes)

                sub_text = f" (in {sub!r})" if sub else ""
                if self.DEBUG:
                    print(f"[{self.song('~~people~title')}]: "
                          f"Album art {fn!r}{sub_text} "
                          f"scores {score} ({length_penalty})")
                score += length_penalty

                # Let's only match if we're quite sure.
                # This allows other sources to kick in
                if score > 2:
                    if sub is not None:
                        fn = os.path.join(sub, fn)
                    images.append((score, os.path.join(base, fn)))

        images.sort(reverse=True)
        for score, path in images:
            # could be a directory
            if not os.path.isfile(path):
                continue
            try:
                return open(path, "rb")
            except IOError:
                print_w("Failed reading album art \"%s\"" % path)

        return None
Exemple #39
0
    def copy(self, parent_widget, song):
        if self.__load_db() is None:
            return False
        track = gpod.itdb_track_new()

        # All values should be utf-8 encoded strings
        # Filepaths should be encoded with the fs encoding

        # Either combine tags with comma, or only take the first value
        if self['all_tags']:
            tag = song.comma
        else:
            tag = lambda key: (song.list(key) or ('', ))[0]

        title = tag('title')
        if self['title_version'] and song('version'):
            title = " - ".join([title, song('version')])
        track.title = encode(title)

        album = tag('album')
        if self['album_part'] and song('discsubtitle'):
            album = " - ".join([album, song('discsubtitle')])
        track.album = encode(album)

        # String keys
        for key in ['artist', 'genre', 'grouping', 'composer', 'albumartist']:
            if hasattr(track, key):  # albumartist since libgpod-0.4.2
                setattr(track, key, encode(tag(key)))
        # Sort keys (since libgpod-0.5.0)
        for key in ['artist', 'album', 'albumartist']:
            if hasattr(track, 'sort_' + key):
                setattr(track, 'sort_' + key, encode(tag(key + 'sort')))
        # Numeric keys
        for key in ['bitrate', 'playcount', 'year']:
            try:
                setattr(track, key, int(song('~#' + key)))
            except ValueError:
                continue
        # Numeric keys where the names differ
        for key, value in {
                'cd_nr': song('~#disc'),
                'cds': song('~#discs'),
                'rating': min(100,
                              song('~#rating') * 100),
                'time_added': self.__mactime(time.time()),
                'time_modified': self.__mactime(mtime(song('~filename'))),
                'track_nr': song('~#track'),
                'tracklen': song('~#length') * 1000,
                'tracks': song('~#tracks'),
                'size': filesize(song('~filename')),
                'soundcheck': self.__soundcheck(song),
        }.items():
            try:
                setattr(track, key, int(value))
            except ValueError:
                continue

        track.filetype = encode(song('~format'))
        track.comment = encode(fsn2text(song('~filename')))

        # Associate a cover with the track
        if self['covers']:
            cover = app.cover_manager.get_cover(song)
            if cover:
                # libgpod will copy the file later when the iTunesDB
                # is saved, so we have to keep a reference around in
                # case the cover is a temporary file.
                self.__covers.append(cover)
                gpod.itdb_track_set_thumbnails(track, fsn2glib(cover.name))

        # Add the track to the master playlist
        gpod.itdb_track_add(self.__itdb, track, -1)
        master = gpod.itdb_playlist_mpl(self.__itdb)
        gpod.itdb_playlist_add_track(master, track, -1)

        # Copy the actual file
        if gpod.itdb_cp_track_to_ipod(track, song['~filename'], None) == 1:
            return IPodSong(track)
        else:
            return False
 def filename(self):
     if self._song is not None:
         return fsn2text(self._song('~filename'))
     else:
         return self._filename
Exemple #41
0
 def cdf(column, cell, model, iter, data):
     row = model[iter]
     cell.set_property('text', fsn2text(row[0]))
Exemple #42
0
 def __name_datafunc(self, col, cell, model, itr, data):
     song = model[itr][0]
     if song:
         cell.set_property('text', fsn2text(song("~basename")))
     else:
         cell.set_property('text', '')
Exemple #43
0
    def scan(self,
             paths: Iterable[fsnative],
             exclude: Optional[Iterable[fsnative]] = None,
             cofuncid=None):
        def need_yield(last_yield=[0]):
            current = time.time()
            if abs(current - last_yield[0]) > 0.015:
                last_yield[0] = current
                return True
            return False

        def need_added(last_added=[0]):
            current = time.time()
            if abs(current - last_added[0]) > 1.0:
                last_added[0] = current
                return True
            return False

        # first scan each path for new files
        paths_to_load = []
        for scan_path in paths:
            print_d(f"Scanning {scan_path}", self._name)
            desc = _("Scanning %s") % (fsn2text(unexpand(scan_path)))
            with Task(_("Library"), desc) as task:
                if cofuncid:
                    task.copool(cofuncid)

                for real_path in iter_paths(scan_path, exclude=exclude):
                    if need_yield():
                        task.pulse()
                        yield
                    # skip unknown file extensions
                    if not formats.filter(real_path):
                        continue
                    # already loaded
                    if self.contains_filename(real_path):
                        continue
                    paths_to_load.append(real_path)

        yield

        # then (try to) load all new files
        with Task(_("Library"), _("Loading files")) as task:
            if cofuncid:
                task.copool(cofuncid)

            added = []
            for real_path in task.gen(paths_to_load):
                item = self.add_filename(real_path, False)
                if item is not None:
                    added.append(item)
                    if len(added) > 100 or need_added():
                        self.add(added)
                        added = []
                        yield
                if added and need_yield():
                    yield
            if added:
                self.add(added)
                added = []
                yield True
Exemple #44
0
def format_exception(etype, value, tb, limit=None):
    """Returns a list of text_type"""

    result_lines = traceback.format_exception(etype, value, tb, limit)
    return [fsn2text(path2fsn(l)) for l in result_lines]
Exemple #45
0
def format_exc(*args, **kwargs):
    """Returns text_type"""

    # stack traces can contain byte paths under py2
    return fsn2text(path2fsn(traceback.format_exc(*args, **kwargs)))
Exemple #46
0
def format_exception_only(etype, value):
    """Returns a list of str"""

    result_lines = traceback.format_exception_only(etype, value)
    return [fsn2text(path2fsn(l)) for l in result_lines]
Exemple #47
0
 def sanitize(self, filename):
     super(WAVEFile, self).sanitize(filename)
     self["title"] = fsn2text(
         os.path.splitext(os.path.basename(self["~filename"]))[0])
Exemple #48
0
def notfsnative(text=u""):
    fsn = fsnative(text)
    if isinstance(fsn, bytes):
        return fsn2text(fsn)
    else:
        return fsn2bytes(fsn, "utf-8")
Exemple #49
0
    def scan(self, paths, exclude=[], scan_dots=False, cofuncid=None):
        added = []
        exclude = [expanduser(path) for path in exclude if path]

        def need_yield(last_yield=[0]):
            current = time.time()
            if abs(current - last_yield[0]) > 0.015:
                last_yield[0] = current
                return True
            return False

        def need_added(last_added=[0]):
            current = time.time()
            if abs(current - last_added[0]) > 1.0:
                last_added[0] = current
                return True
            return False

        for fullpath in paths:
            print_d("Scanning %r." % fullpath, self)
            desc = _("Scanning %s") % (unexpand(fsn2text(fullpath)))
            with Task(_("Library"), desc) as task:
                if cofuncid:
                    task.copool(cofuncid)
                fullpath = expanduser(fullpath)
                if filter(fullpath.startswith, exclude):
                    continue
                for path, dnames, fnames in os.walk(fullpath):
                    if not scan_dots:
                        index = 0
                        while index < len(dnames):
                            if dnames[index].startswith('.'):
                                del (dnames[index])
                            else:
                                index += 1
                    for filename in fnames:
                        if not scan_dots and filename.startswith('.'):
                            continue
                        fullfilename = os.path.join(path, filename)
                        if filter(fullfilename.startswith, exclude):
                            continue
                        if fullfilename not in self._contents:
                            fullfilename = os.path.realpath(fullfilename)
                            # skip unknown file extensions
                            if not formats.filter(fullfilename):
                                continue
                            if filter(fullfilename.startswith, exclude):
                                continue
                            if fullfilename not in self._contents:
                                item = self.add_filename(fullfilename, False)
                                if item is not None:
                                    added.append(item)
                                    if len(added) > 100 or need_added():
                                        self.add(added)
                                        added = []
                                        task.pulse()
                                        yield
                                if added and need_yield():
                                    yield
                if added:
                    self.add(added)
                    added = []
                    task.pulse()
                    yield True
Exemple #50
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
Exemple #51
0
def test_text_fsn_roudntrip(text):
    if u"\x00" in text:
        return
    assert isinstance(fsn2text(text2fsn(text)), text_type)
Exemple #52
0
 def cdf(column, cell, model, iter_, data):
     path = model.get_value(iter_)
     cell.set_property('text', fsn2text(unexpand(path)))