def __save_files(self, parent, model, library):
     win = WritingWindow(parent, len(model))
     was_changed = set()
     for song, track in [(r[0], r[2]) for r in model]:
         if song.get("tracknumber") == track:
             win.step()
             continue
         if not song.valid() and not qltk.ConfirmAction(
                 win, _("Tag may not be accurate"),
                 _("<b>%s</b> changed while the program was running. "
                   "Saving without refreshing your library may "
                   "overwrite other changes to the song.\n\n"
                   "Save this song anyway?") %
                 util.escape(fsdecode(song("~basename")))).run():
             break
         song["tracknumber"] = track
         try:
             song.write()
         except:
             util.print_exc()
             qltk.ErrorMessage(
                 win, _("Unable to save song"),
                 _("Saving <b>%s</b> failed. The file may be "
                   "read-only, corrupted, or you do not have "
                   "permission to edit it.") %
                 util.escape(fsdecode(song('~basename')))).run()
             library.reload(song, changed=was_changed)
             break
         was_changed.add(song)
         if win.step():
             break
     library.changed(was_changed)
     win.destroy()
Exemple #2
0
    def __save(self, addreplace, library):
        pattern_text = self.combo.get_child().get_text().decode('utf-8')
        pattern = TagsFromPattern(pattern_text)
        model = self.view.get_model()
        add = bool(addreplace.get_active())
        win = WritingWindow(self, len(model))
        win.show()

        was_changed = set()

        for row in (model or []):
            song = row[0]
            changed = False
            if not song.valid() and not qltk.ConfirmAction(
                self, _("Tag may not be accurate"),
                _("<b>%s</b> changed while the program was running. "
                  "Saving without refreshing your library may "
                  "overwrite other changes to the song.\n\n"
                  "Save this song anyway?") % (
                util.escape(fsdecode(song("~basename"))))
                ).run():
                break

            for i, h in enumerate(pattern.headers):
                if row[i + 2]:
                    text = row[i + 2].decode("utf-8")
                    if not add or h not in song or not song.multiple_values:
                        song[h] = text
                        changed = True
                    else:
                        for val in text.split("\n"):
                            if val not in song.list(h):
                                song.add(h, val)
                                changed = True

            if changed:
                try:
                    song.write()
                except:
                    qltk.ErrorMessage(
                        self, _("Unable to edit song"),
                        _("Saving <b>%s</b> failed. The file "
                          "may be read-only, corrupted, or you "
                          "do not have permission to edit it.") % (
                        util.escape(fsdecode(song('~basename'))))
                        ).run()
                    library.reload(song, changed=was_changed)
                    break
                was_changed.add(song)

            if win.step():
                break

        win.destroy()
        library.changed(was_changed)
        self.save.set_sensitive(False)
Exemple #3
0
    def __rename(self, library):
        model = self.view.get_model()
        win = WritingWindow(self, len(model))
        win.show()
        was_changed = set()
        skip_all = False
        self.view.freeze_child_notify()

        # FIXME: encoding/decoding mess
        rows = [(row[0], row[1], row[2].decode('utf-8')) for row in model]
        for song, oldname, newname in rows:
            try:
                newname = util.fsnative(newname)
                library.rename(song, newname, changed=was_changed)
            except StandardError:
                util.print_exc()
                if skip_all:
                    continue
                RESPONSE_SKIP_ALL = 1
                buttons = (_("Ignore _All Errors"), RESPONSE_SKIP_ALL,
                           Gtk.STOCK_STOP, Gtk.ResponseType.CANCEL,
                           _("_Continue"), Gtk.ResponseType.OK)
                msg = qltk.Message(
                    Gtk.MessageType.ERROR,
                    win,
                    _("Unable to rename file"),
                    _("Renaming <b>%s</b> to <b>%s</b> failed. "
                      "Possibly the target file already exists, "
                      "or you do not have permission to make the "
                      "new file or remove the old one.") % (util.escape(
                          fsdecode(oldname)), util.escape(fsdecode(newname))),
                    buttons=Gtk.ButtonsType.NONE)
                msg.add_buttons(*buttons)
                msg.set_default_response(Gtk.ResponseType.OK)
                resp = msg.run()
                skip_all |= (resp == RESPONSE_SKIP_ALL)
                # Preserve old behavior: shift-click is Ignore All
                mods = Gdk.Display.get_default().get_pointer()[3]
                skip_all |= mods & Gdk.ModifierType.SHIFT_MASK
                library.reload(song, changed=was_changed)
                if resp != Gtk.ResponseType.OK and resp != RESPONSE_SKIP_ALL:
                    break
            if win.step():
                break

        self.view.thaw_child_notify()
        win.destroy()
        library.changed(was_changed)
        self.save.set_sensitive(False)
Exemple #4
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(path.fsdecode(song("~filename")))
 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"), unicode))
     path = fsnative(u"/foobar")
     self.assertEqual(decode_value("~filename", path), fsdecode(path))
Exemple #6
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(path.fsdecode(song("~filename")))
Exemple #7
0
 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"), unicode))
     path = fsnative(u"/foobar")
     self.assertEqual(decode_value("~filename", path), fsdecode(path))
    def _post(self, value, song):
        if value:
            fn = song.get("~filename", ".")
            ext = fn[fn.rfind("."):].lower()
            val_ext = value[-len(ext):].lower()
            if not ext == val_ext:
                value += ext.lower()
            if os.name == "nt":
                value = strip_win32_incompat_from_path(value)

            value = expanduser(value)

            # Limit each path section to 255 (bytes on linux, chars on win).
            # http://en.wikipedia.org/wiki/Comparison_of_file_systems#Limits
            path, ext = os.path.splitext(value)
            path = map(util.fsnative, path.split(os.sep))
            limit = [255] * len(path)
            limit[-1] -= len(util.fsnative(ext))
            elip = lambda (p, l): (len(p) > l and p[:l - 2] + "..") or p
            path = os.sep.join(map(elip, zip(path, limit)))
            value = fsdecode(path) + ext

            if os.sep in value and not os.path.isabs(value):
                raise ValueError("Pattern is not rooted")
        return value
Exemple #9
0
 def cdf(column, cell, model, iter, data):
     row = model[iter]
     filename = fsdecode(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 __init__(self, parent, song):
        title = _("Unable to save song")

        fn_format = "<b>%s</b>" % util.escape(fsdecode(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 #11
0
def main(argv):
    import quodlibet
    from quodlibet.qltk import add_signal_watch, icons

    add_signal_watch(app.quit)

    opts = util.OptionParser("Ex Falso", const.VERSION, _("an audio tag editor"), "[%s]" % _("directory"))

    # FIXME: support unicode on Windows, sys.argv isn't good enough
    argv.append(os.path.abspath(fsnative(u".")))
    opts, args = opts.parse(argv[1:])
    args[0] = os.path.realpath(args[0])

    config.init(os.path.join(quodlibet.get_user_dir(), "config"))

    app.name = "Ex Falso"
    app.id = "exfalso"

    quodlibet.init(icon=icons.EXFALSO, name=app.name, proc_title=app.id)

    import quodlibet.library
    import quodlibet.player

    app.library = quodlibet.library.init()
    app.player = quodlibet.player.init_player("nullbe", app.librarian)
    from quodlibet.qltk.songlist import PlaylistModel

    app.player.setup(PlaylistModel(), None, 0)
    pm = quodlibet.init_plugins()
    pm.rescan()

    from quodlibet.qltk.exfalsowindow import ExFalsoWindow

    dir_ = args[0]
    if os.name == "nt":
        dir_ = fsdecode(dir_)
    app.window = ExFalsoWindow(app.library, dir_)
    app.window.init_plugins()

    from quodlibet.util.cover import CoverManager

    app.cover_manager = CoverManager()
    app.cover_manager.init_plugins()

    from quodlibet.qltk import session

    session.init("exfalso")

    quodlibet.enable_periodic_save(save_library=False)
    quodlibet.main(app.window)

    quodlibet.finish_first_session(app.id)
    config.save()

    print_d("Finished shutdown.")
Exemple #12
0
    def scan(self, paths, exclude=[], 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(fsdecode(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):
                    for filename in fnames:
                        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 #13
0
    def scan(self, paths, exclude=[], 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(fsdecode(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):
                    for filename in fnames:
                        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 #14
0
    def __init__(self, parent, song):
        title = _("Unable to save song")

        fn_format = "<b>%s</b>" % util.escape(fsdecode(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 #15
0
 def comma(self, key):
     value = self.__song.comma(key)
     if isinstance(value, str):
         value = fsdecode(value)
     elif not isinstance(value, unicode):
         if isinstance(value, float):
             value = "%.2f" % value
         value = unicode(value)
     if self.__formatter:
         return self.__formatter(key, value)
     return value
Exemple #16
0
 def filename(self):
     """a local filename equivalent to the URI"""
     if self.scheme != "file":
         raise ValueError("only the file scheme supports filenames")
     elif self.netloc:
         raise ValueError("only local files have filenames")
     else:
         if os.name == "nt":
             return fsdecode(url2pathname(self.path))
         else:
             return url2pathname(self.path)
Exemple #17
0
 def filename(self):
     """a local filename equivalent to the URI"""
     if self.scheme != "file":
         raise ValueError("only the file scheme supports filenames")
     elif self.netloc:
         raise ValueError("only local files have filenames")
     else:
         if os.name == "nt":
             return fsdecode(url2pathname(self.path))
         else:
             return url2pathname(self.path)
Exemple #18
0
 def __dict(self, song):
     dict = {}
     for key, value in (song or {}).items():
         if not isinstance(value, basestring):
             value = unicode(value)
         elif isinstance(value, str):
             value = fsdecode(value)
         dict[key] = dbusutils.dbus_unicode_validate(value)
     if song:
         dict["~uri"] = song("~uri")
     return dict
Exemple #19
0
 def __dict(self, song):
     dict = {}
     for key, value in (song or {}).items():
         if not isinstance(value, basestring):
             value = unicode(value)
         elif isinstance(value, str):
             value = fsdecode(value)
         dict[key] = dbusutils.dbus_unicode_validate(value)
     if song:
         dict["~uri"] = song("~uri")
     return dict
Exemple #20
0
 def comma(self, key):
     value = self.__song.comma(key)
     if isinstance(value, str):
         value = fsdecode(value)
     elif not isinstance(value, unicode):
         if isinstance(value, float):
             value = "%.2f" % value
         value = unicode(value)
     if self.__formatter:
         return self.__formatter(key, value)
     return value
Exemple #21
0
    def __preview(self, pattern, songs):
        rows = []
        for song in songs:
            match = pattern.match(song)
            row = [fsdecode(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 #22
0
    def __preview(self, pattern, songs):
        rows = []
        for song in songs:
            match = pattern.match(song)
            row = [fsdecode(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 #23
0
    def __init__(self, parent, path):
        title = _("File exists")
        fn_format = "<b>%s</b>" % util.escape(fsdecode(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 #24
0
    def __preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [row[0] for row in model]
        pattern = self.combo.get_child().get_text().decode("utf-8")

        try:
            pattern = FileFromPattern(pattern)
        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))).run()
            return
        else:
            if self.combo.get_child().get_text():
                self.combo.prepend_text(self.combo.get_child().get_text())
                self.combo.write(const.NBP)

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

        model.clear()
        for song, newname in zip(songs, newnames):
            basename = fsdecode(song("~basename"))
            newname = fsdecode(newname)
            model.append(row=[song, basename, newname])
        self.preview.set_sensitive(False)
        self.save.set_sensitive(bool(self.combo.get_child().get_text()))
        for song in songs:
            if not song.is_file:
                self.set_sensitive(False)
                break
        else:
            self.set_sensitive(True)
Exemple #25
0
    def __init__(self, parent, path):
        title = _("File exists")
        fn_format = "<b>%s</b>" % util.escape(fsdecode(path))
        description = _("Replace %(file-name)s?") % {"file-name": fn_format}

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

        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
        save_button = Button(_("_Replace File"), "document-save")
        save_button.show()
        self.add_action_widget(save_button, self.RESPONSE_REPLACE)
        self.set_default_response(Gtk.ResponseType.CANCEL)
Exemple #26
0
def parse_m3u(filename, library=None):
    plname = fsdecode(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 #27
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 = fsdecode(data.get("~filename", ""))
                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(fsdecode(data(name))):
                return True

        return False
Exemple #28
0
def parse_m3u(filename, library=None):
    plname = fsdecode(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 #29
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 = fsdecode(data.get("~filename", ""))
                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(fsdecode(data(name))):
                return True

        return False
Exemple #30
0
def main():
    global quodlibet

    from quodlibet.qltk import add_signal_watch, icons
    add_signal_watch(app.quit)

    opts = util.OptionParser("Ex Falso", const.VERSION,
                             _("an audio tag editor"), "[%s]" % _("directory"))

    # FIXME: support unicode on Windows, sys.argv isn't good enough
    sys.argv.append(os.path.abspath("."))
    opts, args = opts.parse()
    args[0] = os.path.realpath(args[0])

    config.init(const.CONFIG)

    app.name = "Ex Falso"
    app.id = "exfalso"

    quodlibet.init(icon=icons.EXFALSO, name=app.name, proc_title=app.id)

    import quodlibet.library
    import quodlibet.player
    app.library = quodlibet.library.init()
    app.player = quodlibet.player.init_player("nullbe", app.librarian)
    from quodlibet.qltk.songlist import PlaylistModel
    app.player.setup(PlaylistModel(), None, 0)
    pm = quodlibet.init_plugins()
    pm.rescan()

    from quodlibet.qltk.exfalsowindow import ExFalsoWindow
    dir_ = args[0]
    if os.name == "nt":
        dir_ = fsdecode(dir_)
    app.window = ExFalsoWindow(app.library, dir_)
    app.window.init_plugins()

    from quodlibet.util.cover import CoverManager
    app.cover_manager = CoverManager()
    app.cover_manager.init_plugins()

    from quodlibet.qltk import session
    session.init("exfalso")

    quodlibet.enable_periodic_save(save_library=False)
    quodlibet.main(app.window)

    quodlibet.finish_first_session(app.id)
    config.save(const.CONFIG)

    print_d("Finished shutdown.")
Exemple #31
0
    def __init__(self, parent, path):
        title = _("File exists")
        fn_format = "<b>%s</b>" % util.escape(fsdecode(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 #32
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 fsdecode(value)
    return text_type(value)
Exemple #33
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", fsdecode(os.path.basename(filename)[:-4]))
        self.sanitize(filename)
Exemple #34
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, unicode):
        return value
    elif isinstance(value, float):
        return u"%.2f" % value
    elif tag in FILESYSTEM_TAGS:
        return fsdecode(value)
    return unicode(value)
def parse_m3u(filename, library=None):
    plname = fsdecode(os.path.basename(
        os.path.splitext(filename)[0])).encode('utf-8')
    filenames = []

    h = file(filename)
    for line in h:
        line = line.strip()
        if line.startswith("#"):
            continue
        else:
            filenames.append(line)
    h.close()
    return __parse_playlist(plname, filename, filenames, library)
Exemple #36
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" % fsdecode(song("~filename")),
        ]

        return u"\n".join(lines)
Exemple #37
0
    def __init__(self, paths):
        super(FileListExpander, self).__init__(label=_("Files:"))
        self.set_resize_toplevel(True)

        paths = [fsdecode(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 #38
0
    def __init__(self, parent, path):
        title = _("File exists")
        fn_format = "<b>%s</b>" % util.escape(fsdecode(path))
        description = _("Replace %(file-name)s?") % {"file-name": fn_format}

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

        self.add_button(Gtk.STOCK_CANCEL, Gtk.ResponseType.CANCEL)
        save_button = Button(_("_Replace File"), "document-save")
        save_button.show()
        self.add_action_widget(save_button, self.RESPONSE_REPLACE)
        self.set_default_response(Gtk.ResponseType.CANCEL)
Exemple #39
0
    def __init__(self, paths):
        super(FileListExpander, self).__init__(label=_("Files:"))
        self.set_resize_toplevel(True)

        paths = [fsdecode(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(Alignment(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 #40
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: fsdecode(song(tag), note=False)
        elif tag.startswith("~#") and "~" not in tag[2:]:
            return lambda song: song(tag)
        return lambda song: human(song(tag))
Exemple #41
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" % fsdecode(song("~filename")),
        ]

        return u"\n".join(lines)
Exemple #42
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", fsdecode(os.path.basename(filename)[:-4]))
        self.sanitize(filename)
Exemple #43
0
    def __init__(self, parent, song):
        title = _("Tag may not be accurate")

        fn_format = "<b>%s</b>" % util.escape(fsdecode(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 #44
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: fsdecode(song(tag), note=False)
        elif tag.startswith("~#") and "~" not in tag[2:]:
            return lambda song: song(tag)
        return lambda song: human(song(tag))
Exemple #45
0
def parse_pls(filename, name="", library=None):
    plname = fsdecode(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 #46
0
    def match_path(self, path):
        assert is_fsnative(path)

        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 = fsdecode(matchon, note=False)
        match = self.pattern.search(matchon)

        # dicts for all!
        if match is None:
            return {}
        else:
            return match.groupdict()
Exemple #47
0
    def match_path(self, path):
        assert is_fsnative(path)

        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 = fsdecode(matchon, note=False)
        match = self.pattern.search(matchon)

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

    filenames = []
    h = file(filename)
    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)
    h.close()
    return __parse_playlist(plname, filename, filenames, library)
Exemple #49
0
    def __preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in model.itervalues()]

        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))).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 = [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 = fsdecode(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 #50
0
    def __preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in model.itervalues()]

        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))).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 = [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 = fsdecode(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 #51
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 = fsdecode(v)
        else:
            v = self.get(key, u"")

        if isinstance(v, number_types):
            return v
        else:
            return v.replace("\n", ", ")
Exemple #52
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 = fsdecode(v)
        else:
            v = self.get(key, u"")

        if isinstance(v, (int, long, float)):
            return v
        else:
            return v.replace("\n", ", ")
Exemple #53
0
    def __init__(self, parent, song):
        title = _("Tag may not be accurate")

        fn_format = "<b>%s</b>" % util.escape(fsdecode(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 #54
0
    def _file(self, song, box):
        def ftime(t):
            if t == 0:
                return _("Unknown")
            else:
                timestr = time.strftime("%c", time.localtime(t))
                encoding = util.get_locale_encoding()
                return timestr.decode(encoding)

        fn = fsdecode(unexpand(song["~filename"]))
        length = util.format_time_long(song.get("~#length", 0))
        size = util.format_size(
            song.get("~#filesize") or filesize(song["~filename"]))
        mtime = ftime(util.path.mtime(song["~filename"]))
        format_ = song("~format")
        codec = song("~codec")
        encoding = song.comma("~encoding")
        bitrate = song("~bitrate")

        t = Gtk.Table(n_rows=4, n_columns=2)
        t.set_col_spacings(6)
        t.set_homogeneous(False)
        table = [(_("length"), length),
                 (_("format"), format_),
                 (_("codec"), codec),
                 (_("encoding"), encoding),
                 (_("bitrate"), bitrate),
                 (_("file size"), size),
                 (_("modified"), mtime)]
        fnlab = Label(fn)
        fnlab.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
        t.attach(fnlab, 0, 2, 0, 1, xoptions=Gtk.AttachOptions.FILL)
        for i, (l, r) in enumerate(table):
            l = "<b>%s</b>" % util.capitalize(util.escape(l) + ":")
            lab = Label()
            lab.set_markup(l)
            t.attach(lab, 0, 1, i + 1, i + 2, xoptions=Gtk.AttachOptions.FILL)
            t.attach(Label(r), 1, 2, i + 1, i + 2)

        box.pack_start(Frame(_("File"), t), False, False, 0)
Exemple #55
0
    def _file(self, song, box):
        def ftime(t):
            if t == 0:
                return _("Unknown")
            else:
                timestr = time.strftime("%c", time.localtime(t))
                return timestr.decode(const.ENCODING)

        fn = fsdecode(unexpand(song["~filename"]))
        length = util.format_time_long(song.get("~#length", 0))
        size = util.format_size(
            song.get("~#filesize") or filesize(song["~filename"]))
        mtime = ftime(util.path.mtime(song["~filename"]))
        bitrate = song.get("~#bitrate", 0)
        if bitrate != 0:
            bitrate = _("%d kbps") % int(bitrate)
        else:
            bitrate = False

        t = Gtk.Table(n_rows=4, n_columns=2)
        t.set_col_spacings(6)
        t.set_homogeneous(False)
        table = [(_("length"), length),
                 (_("file size"), size),
                 (_("modified"), mtime)]
        if bitrate:
            table.insert(1, (_("bitrate"), bitrate))
        fnlab = Label(fn)
        fnlab.set_ellipsize(Pango.EllipsizeMode.MIDDLE)
        t.attach(fnlab, 0, 2, 0, 1, xoptions=Gtk.AttachOptions.FILL)
        for i, (l, r) in enumerate(table):
            l = "<b>%s</b>" % util.capitalize(util.escape(l) + ":")
            lab = Label()
            lab.set_markup(l)
            t.attach(lab, 0, 1, i + 1, i + 2, xoptions=Gtk.AttachOptions.FILL)
            t.attach(Label(r), 1, 2, i + 1, i + 2)

        box.pack_start(Frame(_("File"), t), False, False, 0)
 def _cdf(self, column, cell, model, iter_, user_data):
     values = model.get_value(iter_).list(self.header_name)
     value = values[0] if values else fsnative(u"")
     if not self._needs_update(value):
         return
     cell.set_property('text', fsdecode(unexpand(value)))
Exemple #57
0
 def cell_data(column, cell, model, iter_, userdata):
     value = model.get_value(iter_)
     cell.set_property('text', fsdecode(os.path.basename(value)))
Exemple #58
0
 def cell_data(column, cell, model, iter_, userdata):
     value = model.get_value(iter_)
     if value is not None:
         text = fsdecode(os.path.basename(value) or value)
         cell.set_property('text', text)
Exemple #59
0
 def sanitize(self, filename):
     super(WAVEFile, self).sanitize(filename)
     self["title"] = fsdecode(os.path.splitext(
         os.path.basename(self["~filename"]))[0])