def setUp(self): # Testing locally is VERY dangerous without this... self.assertTrue(_TEMP_DIR in PLAYLISTS or os.name == "nt", msg="Failing, don't want to delete %s" % PLAYLISTS) try: shutil.rmtree(PLAYLISTS) except OSError: pass mkdir(PLAYLISTS) self.lib = quodlibet.browsers.playlists.library = SongLibrary() self.lib.librarian = SongLibrarian() all_songs = SONGS + [self.ANOTHER_SONG] for af in all_songs: af.sanitize() self.lib.add(all_songs) self.big = pl = FileBackedPlaylist.new(PLAYLISTS, "Big", self.lib) pl.extend(SONGS) pl.write() self.small = pl = FileBackedPlaylist.new(PLAYLISTS, "Small", self.lib) pl.extend([self.ANOTHER_SONG]) pl.write() PlaylistsBrowser.init(self.lib) self.bar = PlaylistsBrowser(self.lib) self.bar.connect('songs-selected', self._expected) self.bar._select_playlist(self.bar.playlists()[0]) self.expected = None
def test_make_dup(self): p1 = FileBackedPlaylist.new(self.temp, "Does not exist") p2 = FileBackedPlaylist.new(self.temp, "Does not exist") self.failUnlessEqual(p1.name, "Does not exist") self.failUnless(p2.name.startswith("Does not exist")) self.failIfEqual(p1.name, p2.name) p1.delete() p2.delete()
def __create_playlist(name, source_dir, files, library): playlist = FileBackedPlaylist.new(PLAYLISTS, name, library=library) print_d("Created playlist %s" % playlist) songs = [] win = WaitLoadWindow( None, len(files), _("Importing playlist.\n\n%(current)d/%(total)d songs added.")) win.show() for i, filename in enumerate(files): if not uri_is_valid(filename): # Plain filename. songs.append(_af_for(filename, library, source_dir)) else: try: filename = uri2fsn(filename) except ValueError: # Who knows! Hand it off to GStreamer. songs.append(formats.remote.RemoteFile(filename)) else: # URI-encoded local filename. songs.append(_af_for(filename, library, source_dir)) if win.step(): break win.destroy() playlist.extend(list(filter(None, songs))) return playlist
def __parse_playlist(name, plfilename, files, library): playlist = FileBackedPlaylist.new(PLAYLISTS, name, library=library) songs = [] win = WaitLoadWindow( None, len(files), _("Importing playlist.\n\n%(current)d/%(total)d songs added.")) win.show() for i, filename in enumerate(files): if not uri_is_valid(filename): # Plain filename. filename = os.path.realpath(os.path.join( os.path.dirname(plfilename), filename)) if library and filename in library: songs.append(library[filename]) else: songs.append(formats.MusicFile(filename)) else: try: filename = uri2fsn(filename) except ValueError: # Who knows! Hand it off to GStreamer. songs.append(formats.remote.RemoteFile(filename)) else: # URI-encoded local filename. filename = os.path.realpath(os.path.join( os.path.dirname(plfilename), filename)) if library and filename in library: songs.append(library[filename]) else: songs.append(formats.MusicFile(filename)) if win.step(): break win.destroy() playlist.extend(filter(None, songs)) return playlist
def __new_playlist(self, activator, library): playlist = FileBackedPlaylist.new(PLAYLISTS, library=library) self.model.append(row=[playlist]) self._select_playlist(playlist, scroll=True) model, iter = self.__selected_playlists() path = model.get_path(iter) GLib.idle_add(self._start_rename, path)
def _on_new_playlist_activate(self, item, songs): parent = get_menu_item_top_parent(item) title = Playlist.suggested_name_for(songs) title = GetPlaylistName(qltk.get_top_parent(parent)).run(title) if title is None: return playlist = FileBackedPlaylist.new(PLAYLISTS, title) playlist.extend(songs) PlaylistsBrowser.changed(playlist)
def __drag_data_received(self, view, ctx, x, y, sel, tid, etime, library): # TreeModelSort doesn't support GtkTreeDragDestDrop. view.emit_stop_by_name('drag-data-received') model = view.get_model() if tid == DND_QL: filenames = qltk.selection_get_filenames(sel) songs = list(filter(None, [library.get(f) for f in filenames])) if not songs: Gtk.drag_finish(ctx, False, False, etime) return try: path, pos = view.get_dest_row_at_pos(x, y) except TypeError: playlist = FileBackedPlaylist.from_songs(PLAYLISTS, songs, library) GLib.idle_add(self._select_playlist, playlist) else: playlist = model[path][0] playlist.extend(songs) self.changed(playlist) Gtk.drag_finish(ctx, True, False, etime) # Cause a refresh to the dragged-to playlist if it is selected # so that the dragged (duplicate) track(s) appears if playlist is self.__get_name_of_current_selected_playlist(): model, plist_iter = self.__selected_playlists() songlist = qltk.get_top_parent(self).songlist self.activate(resort=not songlist.is_sorted()) else: if tid == DND_URI_LIST: uri = sel.get_uris()[0] name = os.path.basename(uri) elif tid == DND_MOZ_URL: data = sel.get_data() uri, name = data.decode('utf16', 'replace').split('\n') else: Gtk.drag_finish(ctx, False, False, etime) return name = _name_for(name or os.path.basename(uri)) try: sock = urlopen(uri) if uri.lower().endswith('.pls'): playlist = parse_pls(sock, name, library=library) elif (uri.lower().endswith('.m3u') or uri.lower().endswith('.m3u8')): playlist = parse_m3u(sock, name, library=library) else: raise IOError library.add(playlist.songs) self.changed(playlist) Gtk.drag_finish(ctx, True, False, etime) except IOError: Gtk.drag_finish(ctx, False, False, etime) qltk.ErrorMessage( qltk.get_top_parent(self), _("Unable to import playlist"), _("Quod Libet can only import playlists in the M3U/M3U8 " "and PLS formats.")).run()
def __drag_data_received(self, view, ctx, x, y, sel, tid, etime, library): # TreeModelSort doesn't support GtkTreeDragDestDrop. view.emit_stop_by_name('drag-data-received') model = view.get_model() if tid == DND_QL: filenames = qltk.selection_get_filenames(sel) songs = filter(None, map(library.get, filenames)) if not songs: Gtk.drag_finish(ctx, False, False, etime) return try: path, pos = view.get_dest_row_at_pos(x, y) except TypeError: playlist = FileBackedPlaylist.from_songs(PLAYLISTS, songs, library) GLib.idle_add(self._select_playlist, playlist) else: playlist = model[path][0] playlist.extend(songs) self.changed(playlist) Gtk.drag_finish(ctx, True, False, etime) else: if tid == DND_URI_LIST: uri = sel.get_uris()[0] name = os.path.basename(uri) elif tid == DND_MOZ_URL: data = sel.get_data() uri, name = data.decode('utf16', 'replace').split('\n') else: Gtk.drag_finish(ctx, False, False, etime) return name = name or os.path.basename(uri) or _("New Playlist") uri = uri.encode('utf-8') try: sock = urlopen(uri) f = NamedTemporaryFile() f.write(sock.read()) f.flush() if uri.lower().endswith('.pls'): playlist = parse_pls(f.name, library=library) elif uri.lower().endswith('.m3u'): playlist = parse_m3u(f.name, library=library) else: raise IOError library.add_filename(playlist) if name: playlist.rename(name) self.changed(playlist) Gtk.drag_finish(ctx, True, False, etime) except IOError: Gtk.drag_finish(ctx, False, False, etime) qltk.ErrorMessage( qltk.get_top_parent(self), _("Unable to import playlist"), _("Quod Libet can only import playlists in the M3U " "and PLS formats.")).run()
def setUp(self): quodlibet.config.init() self.lib = quodlibet.browsers.search.library = FileLibrary() quodlibet.browsers.search.library.librarian = SongLibrarian() for af in self.SONGS: af.sanitize() self.lib.add(self.SONGS) self._dir = mkdtemp() self.pl = FileBackedPlaylist.new(self._dir, "Foobar", self.lib) self.pl.extend(self.SONGS)
def _on_new_playlist_activate(self, item, songs): parent = get_menu_item_top_parent(item) title = Playlist.suggested_name_for(songs) title = self._get_new_name(parent, title) if title is None: return playlist = FileBackedPlaylist.new(PLAYLISTS, title, library=self.librarian) playlist.extend(songs) self._emit_new(playlist)
def test_import(self): pl_name = u"_€3 œufs à Noël" pl = FileBackedPlaylist(_TEMP_DIR, pl_name, None) pl.extend(SONGS) pl.write() new_fn = os.path.splitext(text2fsn(pl.name))[0] + '.m3u' new_path = os.path.join(pl.dir, new_fn) os.rename(pl.filename, new_path) added = self.bar._import_playlists([new_path], self.lib) self.failUnlessEqual(added, 1, msg="Failed to add '%s'" % new_path) os.unlink(new_path) pls = self.bar.playlists() self.failUnlessEqual(len(pls), 3) # Leading underscore makes it always the last entry imported = pls[-1] self.failUnlessEqual(imported.name, pl_name) def fns(songs): return [song('~filename') for song in songs] self.failUnlessEqual(fns(imported.songs), fns(pl.songs))
def reordered(self, songs): model, iter = self.__view.get_selection().get_selected() playlist = None if iter: playlist = model[iter][0] playlist[:] = songs elif songs: playlist = FileBackedPlaylist.from_songs(PLAYLISTS, songs) GLib.idle_add(self._select_playlist, playlist) if playlist: self.changed(playlist, refresh=False)
def init(klass, library): model = klass.__lists.get_model() for playlist in os.listdir(PLAYLISTS): try: playlist = FileBackedPlaylist(PLAYLISTS, FileBackedPlaylist.unquote(playlist), library=library) model.append(row=[playlist]) except EnvironmentError: print_w("Invalid Playlist '%s'" % playlist) pass klass._ids = [ library.connect('removed', klass.__removed), library.connect('added', klass.__added), library.connect('changed', klass.__changed), ] klass.load_pattern()
def test_from_songs(self): pl = FileBackedPlaylist.from_songs(self.temp, NUMERIC_SONGS) self.failUnlessEqual(pl.songs, NUMERIC_SONGS) pl.delete()
def pl(self, name, lib=None): return FileBackedPlaylist(self.temp, name, lib)
def test_remove_no_lib(self): pl = FileBackedPlaylist.new(self._dir, "Foobar") pl.extend(self.SONGS) self.assertTrue(len(pl)) pl.remove_songs(self.SONGS, False) self.assertFalse(len(pl))
def test_old_playlist_removed(self): pl_path = Path(self.library.pl_dir) fn = FileBackedPlaylist.filename_for(PL_NAME) old_path = pl_path / fn assert not old_path.exists(), "Didn't remove old playlist" assert len(self.library) == 1