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(listfilter(None, songs)) return playlist
def set_i18n_envvars(): """Set the LANG/LANGUAGE environment variables if not set in case the current platform doesn't use them by default (OS X, Window) """ if os.name == "nt": from quodlibet.util.winapi import GetUserDefaultUILanguage, \ GetSystemDefaultUILanguage langs = listfilter( None, map(locale.windows_locale.get, [GetUserDefaultUILanguage(), GetSystemDefaultUILanguage()])) if langs: environ.setdefault('LANG', langs[0]) environ.setdefault('LANGUAGE', ":".join(langs)) elif sys.platform == "darwin": from AppKit import NSLocale locale_id = NSLocale.currentLocale().localeIdentifier() lang = osx_locale_id_to_lang(locale_id) environ.setdefault('LANG', lang) preferred_langs = NSLocale.preferredLanguages() if preferred_langs: languages = map(bcp47_to_language, preferred_langs) environ.setdefault('LANGUAGE', ":".join(languages)) else: return
def set_i18n_envvars(): """Set the LANG/LANGUAGE environment variables if not set in case the current platform doesn't use them by default (OS X, Window) """ if os.name == "nt": from quodlibet.util.winapi import GetUserDefaultUILanguage, \ GetSystemDefaultUILanguage langs = listfilter(None, map(locale.windows_locale.get, [GetUserDefaultUILanguage(), GetSystemDefaultUILanguage()])) if langs: environ.setdefault('LANG', langs[0]) environ.setdefault('LANGUAGE', ":".join(langs)) elif sys.platform == "darwin": from AppKit import NSLocale locale_id = NSLocale.currentLocale().localeIdentifier() lang = osx_locale_id_to_lang(locale_id) environ.setdefault('LANG', lang) preferred_langs = NSLocale.preferredLanguages() if preferred_langs: languages = map(bcp47_to_language, preferred_langs) environ.setdefault('LANGUAGE', ":".join(languages)) else: return
def get_format_keys(self, song): try: return self.__key_cache[song] except KeyError: # We filter out empty values, so Unknown can be "" self.__key_cache[song] = listfilter(lambda v: v[0], self.config.format(song)) return self.__key_cache[song]
def get_format_keys(self, song): try: return self.__key_cache[song] except KeyError: # We filter out empty values, so Unknown can be "" self.__key_cache[song] = listfilter( lambda v: v[0], self.config.format(song)) return self.__key_cache[song]
def query(self, text, sort=None, star=Query.STAR): """Query the library and return matching songs.""" if isinstance(text, bytes): text = text.decode('utf-8') songs = self.values() if text != "": songs = listfilter(Query(text, star).search, songs) return songs
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 = listfilter(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)) uri = uri.encode('utf-8') try: sock = urlopen(uri) if uri.lower().endswith('.pls'): playlist = parse_pls(sock, name, library=library) elif uri.lower().endswith('.m3u'): 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 " "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 = listfilter(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) 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 Menu(self, library, songs): songs = ListWrapper(songs) attrs = ['plugin_song', 'plugin_songs', 'plugin_album', 'plugin_albums'] if len(songs) == 1: attrs.append('plugin_single_song') last = (songs and songs[-1]) or None for song in songs: if song.album_key != last.album_key: break last = song else: attrs.append('plugin_single_album') items = [] kinds = self.__plugins kinds.sort(key=lambda plugin: plugin.PLUGIN_ID) for Kind in kinds: usable = any(callable(getattr(Kind, s)) for s in attrs) if usable: try: items.append(Kind(songs, library)) except: print_e("Couldn't initialise song plugin %s. Stack trace:" % Kind) print_exc() items = listfilter(lambda i: i.initialized, items) if items: menu = Gtk.Menu() for item in items: try: menu.append(item) args = (library, songs) if item.get_submenu(): for subitem in item.get_submenu().get_children(): subitem.connect( 'activate', self.__on_activate, item, *args) else: item.connect( 'activate', self.__on_activate, item, *args) except: print_exc() item.destroy() menu.append(SeparatorMenuItem()) prefs = Gtk.MenuItem(label=_("Configure Plugins…")) prefs.connect("activate", lambda _: PluginWindow().show()) menu.append(prefs) else: menu = None return menu
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 = listfilter(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'): 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 " "and PLS formats.")).run()
def _properties(app, value=None): library = app.library player = app.player window = app.window if value is not None: value = arg2text(value) if value in library: songs = [library[value]] else: songs = library.query(value) else: songs = [player.song] songs = listfilter(None, songs) if songs: window = SongProperties(library, songs, parent=window) window.show()
def __update_stats(self): all_ = len(self.__songs) results = self.__fp_results.values() to_send = len(listfilter(can_submit, results)) valid_fp = len(results) got_mbid, got_meta = get_stats(results) text = _("Songs either need a <i><b>musicbrainz_trackid</b></i>, " "or <i><b>artist</b></i> / " "<i><b>title</b></i> / <i><b>album</b></i> tags to get submitted.") text += "\n\n" + "<i>%s</i>" % _("Fingerprints:") text += " %d/%d" % (valid_fp, all_) text += "\n" + "<i>%s</i>" % _("Songs with MBIDs:") text += " %d/%d" % (got_mbid, all_) text += "\n" + "<i>%s</i>" % _("Songs with sufficient tags:") text += " %d/%d" % (got_meta, all_) text += "\n" + "<i>%s</i>" % _("Songs to submit:") text += " %d/%d" % (to_send, all_) self.__stats.set_markup(text)
def __update_stats(self): all_ = len(self.__songs) results = self.__fp_results.values() to_send = len(listfilter(can_submit, results)) valid_fp = len(results) got_mbid, got_meta = get_stats(results) text = _( "Songs either need a <i><b>musicbrainz_trackid</b></i>, " "or <i><b>artist</b></i> / " "<i><b>title</b></i> / <i><b>album</b></i> tags to get submitted.") text += "\n\n" + "<i>%s</i>" % _("Fingerprints:") text += " %d/%d" % (valid_fp, all_) text += "\n" + "<i>%s</i>" % _("Songs with MBIDs:") text += " %d/%d" % (got_mbid, all_) text += "\n" + "<i>%s</i>" % _("Songs with sufficient tags:") text += " %d/%d" % (got_meta, all_) text += "\n" + "<i>%s</i>" % _("Songs to submit:") text += " %d/%d" % (to_send, all_) self.__stats.set_markup(text)
def init(): """Import all browsers from this package and from the user directory. After this is called the global `browsers` list will contain all classes sorted by priority. Can be called multiple times. """ global browsers, default # ignore double init (for the test suite) if browsers: return this_dir = util.get_module_dir() load_pyc = util.is_windows() or util.is_osx() modules = load_dir_modules(this_dir, package=__package__, load_compiled=load_pyc) for browser in modules: try: browsers.extend(browser.browsers) except AttributeError: util.print_w("%r doesn't contain any browsers." % browser.__name__) def is_browser(Kind): return isinstance(Kind, type) and issubclass(Kind, Browser) browsers = listfilter(is_browser, browsers) if not browsers: raise SystemExit("No browsers found!") browsers.sort(key=lambda Kind: Kind.priority) try: default = get("SearchBar") except ValueError: raise SystemExit("Default browser not found!")
def calc_replaygain_volume(self, volume): """Returns a new float volume for the given volume. Takes into account the global active replaygain profile list, the user specified replaygain settings and the tags available for that song. Args: volume (float): 0.0..1.0 Returns: float: adjusted volume, can be outside of 0.0..0.1 """ if self.song and config.getboolean("player", "replaygain"): profiles = listfilter(None, self.replaygain_profiles)[0] fb_gain = config.getfloat("player", "fallback_gain") pa_gain = config.getfloat("player", "pre_amp_gain") scale = self.song.replay_gain(profiles, pa_gain, fb_gain) else: scale = 1 return volume * scale
def populate_menu(self, menu, library, browser, playlists): """Appends items onto `menu` for each enabled playlist plugin, separated as necessary. """ attrs = ['plugin_playlist', 'plugin_playlists'] if len(playlists) == 1: attrs.append('plugin_single_playlist') items = [] kinds = self.__plugins kinds.sort(key=lambda plugin: plugin.PLUGIN_ID) print_d("Found %d Playlist plugin(s): %s" % (len(kinds), kinds)) for Kind in kinds: usable = any([callable(getattr(Kind, s)) for s in attrs]) if usable: try: items.append(Kind(playlists, library)) except: print_e("Couldn't initialise playlist plugin %s: " % Kind) print_exc() items = listfilter(lambda i: i.initialized, items) if items: menu.append(SeparatorMenuItem()) for item in items: try: menu.append(item) args = (library, browser, playlists) if item.get_submenu(): for subitem in item.get_submenu().get_children(): subitem.connect( 'activate', self.__on_activate, item, *args) else: item.connect( 'activate', self.__on_activate, item, *args) except: print_exc() item.destroy()
def __changed(self, selector, selection, label): model, rows = selection.get_selected_rows() files = [] if len(rows) < 2: count = len(model or []) else: count = len(rows) label.set_text(numeric_phrase("%d song", "%d songs", count)) for row in rows: filename = model[row][0] if not os.path.exists(filename): pass elif filename in self.__library: song = self.__library[filename] if song("~#mtime") + 1. < mtime(filename): try: song.reload() except AudioFileError: pass files.append(song) else: files.append(formats.MusicFile(filename)) files = listfilter(None, files) if len(files) == 0: self.set_title("Ex Falso") elif len(files) == 1: self.set_title("%s - Ex Falso" % files[0].comma("title")) else: params = ({'title': files[0].comma("title"), 'count': format_int_locale(len(files) - 1)}) self.set_title( "%s - Ex Falso" % (ngettext("%(title)s and %(count)s more", "%(title)s and %(count)s more", len(files) - 1) % params)) self.__library.add(files) self.emit('changed', files)
def __drag_data_get(self, view, ctx, sel, tid, etime): model, rows = view.get_selection().get_selected_rows() dirs = [model[row][0] for row in rows] for songs in self.__find_songs(view.get_selection()): pass if tid == self.TARGET_QL: cant_add = listfilter(lambda s: not s.can_add, songs) if cant_add: qltk.ErrorMessage( qltk.get_top_parent(self), _("Unable to copy songs"), _("The files selected cannot be copied to other " "song lists or the queue.")).run() ctx.drag_abort(etime) return to_add = filter(self.__library.__contains__, songs) self.__add_songs(view, to_add) qltk.selection_set_songs(sel, songs) else: # External target (app) is delivered a list of URIS of songs uris = list({fsn2uri(dir) for dir in dirs}) print_d("Directories to drop: %s" % dirs) sel.set_uris(uris)
def __browser_cb(self, browser, songs, sorted, library, player): if browser.background: bg = background_filter() if bg: songs = listfilter(bg, songs) self.songlist.set_songs(songs, sorted) # After the first time the browser activates, which should always # happen if we start up and restore, restore the playing song. # Because the browser has send us songs we can be sure it has # registered all its libraries. if self.__first_browser_set: self.__first_browser_set = False song = library.librarian.get(config.get("memory", "song")) seek_pos = config.getfloat("memory", "seek", 0) config.set("memory", "seek", 0) if song is not None: player.setup(self.playlist, song, seek_pos) if self.__restore_cb: self.__restore_cb() self.__restore_cb = None
def __drag_data_get(self, view, ctx, sel, tid, etime): model, rows = view.get_selection().get_selected_rows() dirs = [model[row][0] for row in rows] for songs in self.__find_songs(view.get_selection()): pass if tid == self.TARGET_QL: cant_add = listfilter(lambda s: not s.can_add, songs) if cant_add: qltk.ErrorMessage( qltk.get_top_parent(self), _("Unable to copy songs"), _("The files selected cannot be copied to other " "song lists or the queue.")).run() ctx.drag_abort(etime) return to_add = list(filter(self.__library.__contains__, songs)) self.__add_songs(view, to_add) qltk.selection_set_songs(sel, songs) else: # External target (app) is delivered a list of URIS of songs uris = list({fsn2uri(dir) for dir in dirs}) print_d("Directories to drop: %s" % dirs) sel.set_uris(uris)
def __song_added(self, librarian, songs): window = qltk.get_top_parent(self) filter_ = window.browser.active_filter if callable(filter_): self.add_songs(listfilter(filter_, songs))
def realkeys(self): """Returns a list of keys that are not internal, i.e. they don't have '~' in them.""" return listfilter(lambda s: s[:1] != "~", self.keys())
def __browser_cb(self, browser, songs, sorted): if browser.background: bg = background_filter() if bg: songs = listfilter(bg, songs) self.songlist.set_songs(songs, sorted)
def __drag_data_received(self, view, ctx, x, y, sel, info, etime, library): model = view.get_model() if info == DND_QL: filenames = qltk.selection_get_filenames(sel) move = bool(ctx.get_selected_action() & Gdk.DragAction.MOVE) elif info == DND_URI_LIST: def to_filename(s): try: return uri2fsn(s) except ValueError: return None filenames = listfilter(None, map(to_filename, sel.get_uris())) move = False else: Gtk.drag_finish(ctx, False, False, etime) return to_add = [] for filename in filenames: if filename not in library.librarian: library.add_filename(filename) elif filename not in library: to_add.append(library.librarian[filename]) library.add(to_add) songs = listfilter(None, map(library.get, filenames)) if not songs: Gtk.drag_finish(ctx, bool(not filenames), False, etime) return if not self.__drop_by_row: success = self.__drag_data_browser_dropped(songs) Gtk.drag_finish(ctx, success, False, etime) return try: path, position = view.get_dest_row_at_pos(x, y) except TypeError: path = max(0, len(model) - 1) position = Gtk.TreeViewDropPosition.AFTER if move and Gtk.drag_get_source_widget(ctx) == view: iter = model.get_iter(path) # model can't be empty, we're moving if position in (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.INTO_OR_BEFORE): while self.__drag_iters: model.move_before(self.__drag_iters.pop(0), iter) else: while self.__drag_iters: model.move_after(self.__drag_iters.pop(), iter) Gtk.drag_finish(ctx, True, False, etime) else: song = songs.pop(0) try: iter = model.get_iter(path) except ValueError: iter = model.append(row=[song]) # empty model else: if position in (Gtk.TreeViewDropPosition.BEFORE, Gtk.TreeViewDropPosition.INTO_OR_BEFORE): iter = model.insert_before(iter, [song]) else: iter = model.insert_after(iter, [song]) for song in songs: iter = model.insert_after(iter, [song]) Gtk.drag_finish(ctx, True, move, etime)
def __refresh(self, feeds): changed = listfilter(Feed.parse, feeds) AudioFeeds.changed(changed)