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))})
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)
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)
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
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)]))
def _create(self, string): return FileFromPattern(string)
def __set_pattern(self, widget=None): self.__pattern = FileFromPattern( os.path.join(self.mountpoint, self['pattern']))
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)
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)