Beispiel #1
0
 def test_same2(s):
     fpat = FileFromPattern('<~filename>')
     pat = Pattern('<~filename>')
     s.assertEquals(fpat.format_list(s.a),
                    {(fpat.format(s.a), fpat.format(s.a))})
     s.assertEquals(pat.format_list(s.a),
                    {(pat.format(s.a), pat.format(s.a))})
Beispiel #2
0
 def test_same2(s):
     fpat = FileFromPattern('<~filename>')
     pat = Pattern('<~filename>')
     s.assertEquals(fpat.format_list(s.a),
                    {(fpat.format(s.a), fpat.format(s.a))})
     s.assertEquals(pat.format_list(s.a),
                    {(pat.format(s.a), pat.format(s.a))})
Beispiel #3
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)
Beispiel #4
0
    def __preview(self, songs):
        model = self.view.get_model()
        if songs is None:
            songs = [e.song for e in model.itervalues()]

        pattern_text = self.combo.get_child().get_text().decode("utf-8")

        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)
Beispiel #5
0
    def plugin_playlist(self, playlist):
        pattern_text = CONFIG.default_pattern
        dialog = ExportToFolderDialog(self.plugin_window, pattern_text)
        if dialog.run() == Gtk.ResponseType.OK:
            directory = dialog.directory_chooser.get_filename()
            pattern = FileFromPattern(dialog.pattern_entry.get_text())

            task = Task("Export", _("Export Playlist to Folder"),
                        stop=self.__cancel_copy)
            copool.add(self.__copy_songs, task,
                       playlist.songs, directory, pattern,
                       funcid="export-playlist-folder")

        dialog.destroy()
    def _get_valid_inputs(self):
        """
        Ensure that all user inputs have been given. Shows a popup error message
        if values are not as expected.

        :return: The entered destination path and an fsnative pattern,
                 or None if an error occurred.
        """
        # Get text from the destination path entry
        destination_path = self.destination_entry.get_text()
        if not destination_path:
            self._show_sync_error(
                _('No destination path provided'),
                _('Please specify the directory where songs '
                  'should be exported.'))
            return None, None

        # Get text from the export pattern entry
        export_pattern = self.export_pattern_entry.get_text()
        if not export_pattern:
            self._show_sync_error(
                _('No export pattern provided'),
                _('Please specify an export pattern for the '
                  'names of the exported songs.'))
            return None, None

        # Combine destination path and export pattern to form the full pattern
        full_export_path = os.path.join(destination_path, export_pattern)
        try:
            pattern = FileFromPattern(full_export_path)
        except ValueError:
            self._show_sync_error(
                _('Export path is not absolute'),
                _('The pattern\n\n<b>{}</b>\n\ncontains "/" but does not start '
                  'from root. Please provide an absolute destination path by '
                  'making sure it starts with / or ~/.').format(
                      util.escape(full_export_path)))
            return None, None

        return destination_path, pattern
Beispiel #7
0
 def test_same2(s):
     fpat = FileFromPattern('<~filename>')
     pat = Pattern('<~filename>')
     s.assertEquals(fpat.format_list(s.a), set([fpat.format(s.a)]))
     s.assertEquals(pat.format_list(s.a), set([pat.format(s.a)]))
Beispiel #8
0
 def _create(self, string):
     return FileFromPattern(string)
Beispiel #9
0
 def test_same2(s):
     fpat = FileFromPattern('<~filename>')
     pat = Pattern('<~filename>')
     s.assertEquals(fpat.format_list(s.a), set([fpat.format(s.a)]))
     s.assertEquals(pat.format_list(s.a), set([pat.format(s.a)]))
Beispiel #10
0
 def __set_pattern(self, widget=None):
     self.__pattern = FileFromPattern(
         os.path.join(self.mountpoint, self['pattern']))
Beispiel #11
0
class StorageDevice(Device):
    protocol = 'storage'

    defaults = {
        'pattern': '<artist>/<album>/<title>',
        'covers': True,
        'unclutter': True,
    }

    __library = None
    __pattern = None

    def __init__(self, backend_id, device_id):
        super(StorageDevice, self).__init__(backend_id, device_id)
        filename = escape_filename(device_id)
        self.__library_path = os.path.join(CACHE, filename)
        self.__library_name = device_id

    def __set_pattern(self, widget=None):
        self.__pattern = FileFromPattern(
            os.path.join(self.mountpoint, self['pattern']))

    def Properties(self):
        props = []

        entry = Gtk.Entry()
        entry.set_text(self['pattern'])
        entry.connect_after('changed', self.__set_pattern)
        props.append((_("_Filename pattern:"), entry, 'pattern'))

        check = Gtk.CheckButton()
        check.set_active(self['covers'])
        props.append((_("Copy _album covers"), check, 'covers'))

        check = Gtk.CheckButton()
        check.set_active(self['unclutter'])
        props.append(
            (_("_Remove unused covers and directories"), check, 'unclutter'))

        return props

    def list(self, wlb):
        self.__load_library()

        wlb.setup()
        next = self.__library.rebuild([self.mountpoint]).next
        while True:
            if wlb.quit:
                wlb.hide()
                break
            if not wlb.paused:
                try:
                    next()
                except StopIteration:
                    break
            Gtk.main_iteration()

        self.__save_library()
        return self.__library.values()

    def contains(self, song):
        return song in self.__library

    def copy(self, parent_widget, song):
        if not self.__pattern:
            self.__set_pattern()

        target = strip_win32_incompat_from_path(self.__pattern.format(song))
        dirname = os.path.dirname(target)

        if os.path.exists(target):
            dialog = ConfirmFileReplace(parent_widget, target)
            resp = dialog.run()
            if resp == ConfirmFileReplace.RESPONSE_REPLACE:
                try:
                    # Remove the current song
                    self.__library.remove([self.__library[target]])
                except KeyError:
                    pass
            else:
                return False

        try:
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            shutil.copyfile(song['~filename'], target)

            if self['covers']:
                coverfile = os.path.join(dirname, 'folder.jpg')
                cover = app.cover_manager.get_cover(song)
                if cover and mtime(cover.name) > mtime(coverfile):
                    image = GdkPixbuf.Pixbuf.new_from_file_at_size(
                        cover.name, 200, 200)
                    image.savev(coverfile, "jpeg", [], [])

            song = copy.deepcopy(song)
            song.sanitize(target)
            self.__library.add([song])
            return song
        except (OSError, IOError, GLib.GError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def delete(self, parent_widget, song):
        try:
            path = song['~filename']
            dir = os.path.dirname(path)

            os.unlink(path)
            self.__library.remove([song])

            if self['unclutter']:
                files = glob(dir + '/*')
                if len(files) == 1 and os.path.isfile(files[0]) and \
                        os.path.basename(files[0]) == 'folder.jpg':
                    os.unlink(files[0])
                try:
                    os.removedirs(os.path.dirname(path))
                except OSError:
                    pass

            return True
        except (OSError, IOError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def cleanup(self, wlb, action):
        self.__save_library()
        return True

    def close(self):
        if self.__library:
            self.__library.destroy()
            self.__library = None

    def __load_library(self):
        if self.__library is None:
            self.__library = SongFileLibrary(self.__library_name)
            if os.path.isfile(self.__library_path):
                self.__library.load(self.__library_path)

    def __save_library(self):
        self.__library.save(self.__library_path)
Beispiel #12
0
 def __set_pattern(self, widget=None):
     self.__pattern = FileFromPattern(
         os.path.join(self.mountpoint, self['pattern']))
Beispiel #13
0
class StorageDevice(Device):
    protocol = 'storage'

    defaults = {
        'pattern': '<artist>/<album>/<title>',
        'covers': True,
        'unclutter': True,
    }

    __library = None
    __pattern = None

    def __init__(self, backend_id, device_id):
        super(StorageDevice, self).__init__(backend_id, device_id)
        filename = escape_filename(device_id)
        self.__library_path = os.path.join(CACHE, filename)
        self.__library_name = device_id

    def __set_pattern(self, widget=None):
        self.__pattern = FileFromPattern(
            os.path.join(self.mountpoint, self['pattern']))

    def Properties(self):
        props = []

        entry = Gtk.Entry()
        entry.set_text(self['pattern'])
        entry.connect_after('changed', self.__set_pattern)
        props.append((_("_Filename pattern:"), entry, 'pattern'))

        check = Gtk.CheckButton()
        check.set_active(self['covers'])
        props.append((_("Copy _album covers"), check, 'covers'))

        check = Gtk.CheckButton()
        check.set_active(self['unclutter'])
        props.append((_("_Remove unused covers and directories"),
            check, 'unclutter'))

        return props

    def list(self, wlb):
        self.__load_library()

        wlb.setup()
        next = self.__library.rebuild([self.mountpoint]).next
        while True:
            if wlb.quit:
                wlb.hide()
                break
            if not wlb.paused:
                try:
                    next()
                except StopIteration:
                    break
            Gtk.main_iteration()

        self.__save_library()
        return self.__library.values()

    def contains(self, song):
        return song in self.__library

    def copy(self, parent_widget, song):
        if not self.__pattern:
            self.__set_pattern()

        target = strip_win32_incompat_from_path(self.__pattern.format(song))
        dirname = os.path.dirname(target)

        if os.path.exists(target):
            dialog = ConfirmFileReplace(parent_widget, target)
            resp = dialog.run()
            if resp == ConfirmFileReplace.RESPONSE_REPLACE:
                try:
                    # Remove the current song
                    self.__library.remove([self.__library[target]])
                except KeyError:
                    pass
            else:
                return False

        try:
            if not os.path.isdir(dirname):
                os.makedirs(dirname)
            shutil.copyfile(song['~filename'], target)

            if self['covers']:
                coverfile = os.path.join(dirname, 'folder.jpg')
                cover = app.cover_manager.get_cover(song)
                if cover and mtime(cover.name) > mtime(coverfile):
                    image = GdkPixbuf.Pixbuf.new_from_file_at_size(
                        cover.name, 200, 200)
                    image.savev(coverfile, "jpeg", [], [])

            song = copy.deepcopy(song)
            song.sanitize(target)
            self.__library.add([song])
            return song
        except (OSError, IOError, GLib.GError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def delete(self, parent_widget, song):
        try:
            path = song['~filename']
            dir = os.path.dirname(path)

            os.unlink(path)
            self.__library.remove([song])

            if self['unclutter']:
                files = glob(dir + '/*')
                if len(files) == 1 and os.path.isfile(files[0]) and \
                        os.path.basename(files[0]) == 'folder.jpg':
                    os.unlink(files[0])
                try:
                    os.removedirs(os.path.dirname(path))
                except OSError:
                    pass

            return True
        except (OSError, IOError) as exc:
            encoding = util.get_locale_encoding()
            return str(exc).decode(encoding, 'replace')

    def cleanup(self, wlb, action):
        self.__save_library()
        return True

    def close(self):
        if self.__library:
            self.__library.destroy()
            self.__library = None

    def __load_library(self):
        if self.__library is None:
            self.__library = SongFileLibrary(self.__library_name)
            if os.path.isfile(self.__library_path):
                self.__library.load(self.__library_path)

    def __save_library(self):
        self.__library.save(self.__library_path)