def test_get_cover_many_prefer_embedded(self): # embed one cover, move one to the other dir MP3File(self.file1).set_image(EmbeddedImage.from_path(self.cover1)) os.unlink(self.cover1) self.external_cover = os.path.join(self.dir2, "cover.png") shutil.move(self.cover2, self.external_cover) # move one audio file in each dir shutil.move(self.file1, self.dir1) self.file1 = os.path.join(self.dir1, os.path.basename(self.file1)) shutil.move(self.file2, self.dir2) self.file2 = os.path.join(self.dir2, os.path.basename(self.file2)) song1 = MP3File(self.file1) song2 = MP3File(self.file2) # each should find a cover self.failUnless(self.is_embedded(self.manager.get_cover(song1))) self.failIf(self.is_embedded(self.manager.get_cover(song2))) cover_for = self.manager.get_cover_many # both settings should search both songs before giving up config.set("albumart", "prefer_embedded", True) self.failUnless(self.is_embedded(cover_for([song1, song2]))) self.failUnless(self.is_embedded(cover_for([song2, song1]))) config.set("albumart", "prefer_embedded", False) self.failIf(self.is_embedded(cover_for([song1, song2]))) self.failIf(self.is_embedded(cover_for([song2, song1])))
def test_get_columns_migrated(self): self.failIf(config.get("settings", "headers", None)) columns = "~album,~#replaygain_track_gain,foobar" config.set("settings", "columns", columns) self.failUnlessEqual(get_columns(), ["~album", "~#replaygain_track_gain", "foobar"]) self.failIf(config.get("settings", "headers", None))
def set_band(adj, idx): rounded = int(adj.get_value() * 2) / 2.0 adj.set_value(rounded) levels[idx] = rounded config.set('plugins', 'equalizer_levels', ','.join(str(lv) for lv in levels)) self.apply()
def test_moveart_multi_source(self): self.reset_environment() config.set("rename", "move_art", True) config.set("albumart", "search_filenames", "*.jpg") source, target = \ self.source_target(self.root_path, 'artist', 'album') source2, target2 = \ self.source_target(self.root_path, 'artist', 'album2') self.filenames = ['art.jpg'] self.art_set(source) self.filenames = ['art2.jpg'] self.art_set(source2) song_files, songs = self.song_set(source) song_files2, songs2 = self.song_set(source2) self.renamer.add_songs(songs + songs2) # avoid audio file clashes pattern = os.path.join(target, '[<album>] artist - <title>') self.renamer.rename(pattern, songs + songs2) # album art sets merged count_expected = 2 self.moveart_set() target_files = glob.glob(os.path.join(target, '*.jpg')) count_target = len(target_files) self.failUnlessEqual(count_target, count_expected)
def __visible(self, cb, prop, menu, clear): value = self.get_property('visible') config.set("memory", "queue", str(value)) menu.set_active(value) self.set_expanded(not self.model.is_empty()) cb.set_property('visible', self.get_expanded()) clear.set_property('visible', self.get_expanded())
def bool_changed(widget): """Boolean setting changed.""" if widget.get_active(): setattr(self.configuration, widget.get_name(), True) else: setattr(self.configuration, widget.get_name(), False) config.set("plugins", "autoqueue_%s" % widget.get_name(), widget.get_active() and "true" or "false")
def __changed_entry(self, entry, cbs, label): text = entry.get_text() if text[0:1] == "<" and text[-1:] == ">": parts = text[1:-1].split("~") for cb in cbs: if parts and parts[0] == cb.tag: parts.pop(0) if parts: for cb in cbs: cb.set_inconsistent(True) else: parts = text[1:-1].split("~") for cb in cbs: cb.set_inconsistent(False) cb.set_active(cb.tag in parts) else: for cb in cbs: cb.set_inconsistent(True) if app.player.info is None: text = _("Not playing") else: text = Pattern(entry.get_text()) % app.player.info label.set_text(text) label.get_parent().set_tooltip_text(text) config.set("plugins", "icon_tooltip", entry.get_text())
def test_glob(self): config.set("albumart", "force_filename", str(True)) config.set("albumart", "filename", "foo.*") for fn in ["foo.jpg", "foo.png"]: f = self.add_file(fn) assert path_equal( os.path.abspath(self._find_cover(self.song).name), f)
def setUp(self): config.init() config.set("player", "gst_pipeline", "fakesink") config.set("settings", "xine_driver", "none") module = player.init_backend(self.NAME) lib = library.init() self.player = module.init(lib.librarian) source = PlaylistModel() source.set(FILES) self.events = [] def start_end_handler(player, song, *args): self.events.append((args[-1], song)) self.player.connect("song-started", start_end_handler, "started") self.player.connect("song-ended", start_end_handler, "ended") self.player.setup(source, None, 0) self.signals = [] def handler(type_, *args): self.signals.append(type_) connect_obj(self.player, "unpaused", handler, "unpaused") connect_obj(self.player, "paused", handler, "paused")
def finish_first_session(app_name): """Call on shutdown so that is_first_session() works""" from quodlibet import config from quodlibet import const config.set("memory", "%s_last_active_version" % app_name, const.VERSION)
def setUp(self): self.mod = self.modules[DownloadCoverArt.PLUGIN_ID] self.songs = [A_SONG] config.add_section(PluginManager.CONFIG_SECTION) config.set(PluginManager.CONFIG_SECTION, '%s_preview_size' % DownloadCoverArt.PLUGIN_ID, 200)
def __changed_and_signal_library(self, entry, section, name): config.set(section, name, str(entry.get_value())) print_d("Signalling \"changed\" to entire library. Hold tight...") # Cache over clicks self._songs = self._songs or app.library.values() copool.add(emit_signal, self._songs, funcid="library changed", name=_("Updating for new ratings"))
def test_acquire_prefer_embedded(self): # embed one cover... MP3File(self.file1).set_image(EmbeddedImage.from_path(self.cover1)) os.unlink(self.cover1) self.external_cover = os.path.join(self.dir1, "cover.png") # ...and save a different cover externally shutil.copy(self.cover2, self.external_cover) shutil.move(self.file1, self.dir1) self.file1 = os.path.join(self.dir1, os.path.basename(self.file1)) both_song = MP3File(self.file1) results = [] def acquire(song): def cb(source, result): results.append(result) self.manager.acquire_cover(cb, None, song) def result_was_embedded(): return self.is_embedded(results.pop()) config.set("albumart", "prefer_embedded", True) acquire(both_song) self.failUnless(result_was_embedded(), "Embedded image expected due to prefs") config.set("albumart", "prefer_embedded", False) acquire(both_song) self.failIf(result_was_embedded(), "Got an embedded image despite prefs")
def test_default_email_rating(self): self.song["~#rating"] = 0.2 self.song.write() song = type(self.song)(self.filename) config.set("editing", "save_email", "*****@*****.**") config.set("editing", "save_email", const.EMAIL) self.failUnlessEqual(song["~#rating"], 0.2)
def test_dont_save(self): config.set("editing", "save_to_songs", "false") self.song["~#rating"] = 1.0 self.song.write() song = type(self.song)(self.filename) config.set("editing", "save_to_songs", "true") self.failUnlessEqual(song("~#rating"), const.DEFAULT_RATING)
def test_restore(self): config.set("browsers", "query_text", "foo") self.bar.restore() self.failUnlessEqual(self.bar._get_text(), "foo") self.bar.finalize(True) self._wait() self.failUnlessEqual(self.emit_count, 0)
def _turn_all_options_on(self): for name in ['REMOVE_WHITESPACE', 'REMOVE_DIACRITICS', 'REMOVE_PUNCTUATION', 'CASE_INSENSITIVE']: # Get the actual values, don't hard-code here (kinda) cfg_name = getattr(self.mod.Duplicates, "_CFG_%s" % name) config.set(PM.CONFIG_SECTION, self.kind._get_config_option(cfg_name), True)
def save(self): text = self.__searchbar.get_text().encode("utf-8") config.set("browsers", "query_text", text) selection = self.view.get_selection() model, rows = selection.get_selected_rows() names = filter(None, [model[row][self.KEY] for row in rows]) config.set("browsers", "radio", "\n".join(names))
def __do_save_size_pos(self, width, height): if self.__state & Gdk.WindowState.MAXIMIZED: return value = "%d %d" % (width, height) config.set("memory", self.__conf("size"), value) self.__do_save_pos()
def test_toggle(self): config.set("memory", "bar", "on") c = ConfigCheckMenuItem("dummy", "memory", "bar") c.set_active(True) self.failUnless(config.getboolean("memory", "bar") and c.get_active()) c.set_active(False) while gtk.events_pending(): gtk.main_iteration() self.failIf(config.getboolean("memory", "bar") or c.get_active())
def __cols_changed(self, songlist): headers = [col.header_name for col in songlist.get_columns()] try: headers.remove('~current') except ValueError: pass if len(headers) == len(config.get("settings", "headers").split()): # Not an addition or removal (handled separately) config.set("settings", "headers", " ".join(headers)) SongList.headers = headers
def test_restore_pane_width(self): config.set("browsers", "panes", "artist\talbum") self.bar.set_all_panes() paned = self.bar.multi_paned.get_paned() paned.set_relative(0.8) self.bar.set_all_panes() self.failUnlessAlmostEqual(paned.get_relative(), 0.8)
def _set_buffer_duration(self, duration): """Set the stream buffer duration in msecs""" config.set("player", "gst_buffer", float(duration) / 1000) if self.bin: value = duration * Gst.MSECOND self.bin.set_property('buffer-duration', value)
def test_make_pane_widths_equal(self): config.set("browsers", "panes", "artist\talbum\t~year\t~#track") self.bar.set_all_panes() self.bar.make_pane_widths_equal() paneds = self.bar.multi_paned._get_paneds() self.failUnlessAlmostEqual(paneds[0].get_relative(), 1.0 / 4.0) self.failUnlessAlmostEqual(paneds[1].get_relative(), 1.0 / 3.0) self.failUnlessAlmostEqual(paneds[2].get_relative(), 1.0 / 2.0)
def save(self): config.set("browsers", "query_text", self._get_text()) selected = [] for pane in self._panes: selected.append(pane.get_restore_string()) to_save = u"\n".join(selected).encode("utf-8") config.set("browsers", "pane_selection", to_save)
def save(cls): """See which browser windows are open and save their names so we can restore them on start. """ names = [] for browser in cls.instances(): names.append(browser.name) config.set("memory", "open_browsers", "\n".join(names))
def __do_save_size_pos(self): if self._should_ignore_state(): return width, height = self.get_size() value = "%d %d" % (width, height) config.set("memory", self.__conf("size"), value) self.__do_save_pos()
def test_deletes_rating(self): config.set("editing", "save_email", "*****@*****.**") self.song["~#rating"] = 0.2 self.song.write() self.song["~#rating"] = const.DEFAULT_RATING self.song.write() song = type(self.song)(self.filename) config.set("editing", "save_email", const.EMAIL) self.failUnlessEqual(song("~#rating"), const.DEFAULT_RATING)
def __selection_changed(self, selection, container): model, iter_ = selection.get_selected() if not iter_: container.set_plugin(None) return plugin = model.get_value(iter_) config.set("memory", "plugin_selection", plugin.id) container.set_plugin(plugin)
def __changed(self, selection): model, paths = selection.get_selected_rows() if model and paths: songs = [] for path in paths: model[path][0].changed = False songs.extend(model[path][0]) self.songs_selected(songs, True) config.set("browsers", "audiofeeds", "\t".join([model[path][0].name for path in paths]))
def finalize(self, restore): config.set("browsers", "query_text", "")
def __toggled(self, section, option): config.set(section, option, str(bool(self.get_active())).lower())
def set_port_num(value): return config.set("plugins", "mpdserver_port", str(value))
def __changed_order(self, model, player): Order = ORDERS[self.get_active()] model.order = Order(model) config.set("memory", "order", Order.name) player.replaygain_profiles[2] = Order.replaygain_profiles player.volume = player.volume
def __sort_toggled_cb(self, item, model, num): if item.get_active(): config.set("browsers", "album_sort", str(num)) model.set_sort_column_id(100 + num, Gtk.SortType.ASCENDING)
def pattern_changed(self, entry): self.pattern = entry.get_text() config.set('plugins', self.c_pattern, self.pattern)
def on_queue_visible(qex, param): config.set("memory", "queue", str(qex.get_visible()))
def save_headers(headers): headers = "\n".join(["%s %d" % (t, m) for (t, m) in headers]) config.set("browsers", "collection_headers", headers)
def save(self): model, iter = self.__selected_playlists() name = iter and model[iter][0].name or "" config.set("browsers", "playlist", name) text = self.get_filter_text() config.set("browsers", "query_text", text)
def save(self): selection = self.__view.get_selection() model, iter = selection.get_selected() if iter: config.set('browsers', 'media', model[iter][0]['name'])
def save(self): model, paths = self.view.get_selection().get_selected_rows() paths = "\t".join([" ".join(map(str, path)) for path in paths]) config.set("browsers", "collection", paths)
def statuses_changed(self, b): if b.get_active() and b.get_name() not in self.statuses: self.statuses.append(b.get_name()) elif b.get_active() is False and b.get_name() in self.statuses: self.statuses.remove(b.get_name()) config.set('plugins', self.c_statuses, " ".join(self.statuses))
def __volume_changed(self, button, volume, device): config.set("memory", "volume", str(volume)) device.volume = volume
def paused_changed(self, c): config.set('plugins', self.c_paused, str(c.get_active()))
def on_switch_page(notebook, page, page_num): config.set("memory", "prefs_page", page.name)
def accounts_changed(self, entry): self.accounts = entry.get_text().split() config.set('plugins', self.c_accounts, entry.get_text())
def save_headers(headers): headers = "\t".join(headers) config.set("browsers", "panes", headers)
def __changed(self, combo): index = combo.get_active() name = (index and combo.get_active_text()) or "" config.set("plugins", self.CONFIG_THEME, name) self.__set_theme(name)
def _entry(self, entry, name, section="settings"): config.set(section, name, entry.get_text())
def __changed(self, entry, section, name): config.set(section, name, entry.get_text())
def __window_state_changed(self, window, event): self.__state = event.new_window_state if self.__state & Gdk.WindowState.WITHDRAWN: return maximized = int(self.__state & Gdk.WindowState.MAXIMIZED) config.set("memory", self.__conf("maximized"), maximized)
def __changed(self, adj, section, name): config.set(section, name, str(adj.get_value())) app.player.reset_replaygain()
def __init__(self, library, player, headless=False, restore_cb=None): super(QuodLibetWindow, self).__init__(dialog=False) self.__destroyed = False self.__update_title(player) self.set_default_size(600, 480) main_box = Gtk.VBox() self.add(main_box) self.side_book = qltk.Notebook() # get the playlist up before other stuff self.songlist = MainSongList(library, player) self.songlist.connect("key-press-event", self.__songlist_key_press) self.songlist.connect_after('drag-data-received', self.__songlist_drag_data_recv) self.song_scroller = ScrolledWindow() self.song_scroller.set_policy(Gtk.PolicyType.AUTOMATIC, Gtk.PolicyType.AUTOMATIC) self.song_scroller.set_shadow_type(Gtk.ShadowType.IN) self.song_scroller.add(self.songlist) self.qexpander = QueueExpander(library, player) self.qexpander.set_no_show_all(True) self.qexpander.set_visible(config.getboolean("memory", "queue")) def on_queue_visible(qex, param): config.set("memory", "queue", str(qex.get_visible())) self.qexpander.connect("notify::visible", on_queue_visible) self.playlist = PlaylistMux(player, self.qexpander.model, self.songlist.model) self.__player = player # create main menubar, load/restore accelerator groups self.__library = library ui = self.__create_menu(player, library) accel_group = ui.get_accel_group() self.add_accel_group(accel_group) def scroll_and_jump(*args): self.__jump_to_current(True, None, True) keyval, mod = Gtk.accelerator_parse("<Primary><shift>J") accel_group.connect(keyval, mod, 0, scroll_and_jump) # custom accel map accel_fn = os.path.join(quodlibet.get_user_dir(), "accels") Gtk.AccelMap.load(accel_fn) # save right away so we fill the file with example comments of all # accels Gtk.AccelMap.save(accel_fn) menubar = ui.get_widget("/Menu") # Since https://git.gnome.org/browse/gtk+/commit/?id=b44df22895c79 # toplevel menu items show an empty 16x16 image. While we don't # need image items there UIManager creates them by default. # Work around by removing the empty GtkImages for child in menubar.get_children(): if isinstance(child, Gtk.ImageMenuItem): child.set_image(None) main_box.pack_start(menubar, False, True, 0) top_bar = TopBar(self, player, library) main_box.pack_start(top_bar, False, True, 0) self.top_bar = top_bar self.__browserbox = Align(bottom=3) self.__paned = paned = ConfigRHPaned("memory", "sidebar_pos", 0.25) paned.pack1(self.__browserbox, resize=True) # We'll pack2 when necessary (when the first sidebar plugin is set up) main_box.pack_start(paned, True, True, 0) play_order = PlayOrderWidget(self.songlist.model, player) statusbox = StatusBarBox(play_order, self.qexpander) self.order = play_order self.statusbar = statusbox.statusbar main_box.pack_start(Align(statusbox, border=3, top=-3), False, True, 0) self.songpane = SongListPaned(self.song_scroller, self.qexpander) self.songpane.show_all() try: orders = [] for e in config.getstringlist('memory', 'sortby', []): orders.append((e[1:], int(e[0]))) except ValueError: pass else: self.songlist.set_sort_orders(orders) self.browser = None self.ui = ui main_box.show_all() self._playback_error_dialog = None connect_destroy(player, 'song-started', self.__song_started) connect_destroy(player, 'paused', self.__update_paused, True) connect_destroy(player, 'unpaused', self.__update_paused, False) # make sure we redraw all error indicators before opening # a dialog (blocking the main loop), so connect after default handlers connect_after_destroy(player, 'error', self.__player_error) # connect after to let SongTracker update stats connect_after_destroy(player, "song-ended", self.__song_ended) # set at least the playlist. the song should be restored # after the browser emits the song list player.setup(self.playlist, None, 0) self.__restore_cb = restore_cb self.__first_browser_set = True restore_browser = not headless try: self._select_browser(self, config.get("memory", "browser"), library, player, restore_browser) except: config.set("memory", "browser", browsers.name(browsers.default)) config.save() raise self.songlist.connect('popup-menu', self.__songs_popup_menu) self.songlist.connect('columns-changed', self.__cols_changed) self.songlist.connect('columns-changed', self.__hide_headers) self.songlist.info.connect("changed", self.__set_totals) lib = library.librarian connect_destroy(lib, 'changed', self.__song_changed, player) targets = [("text/uri-list", Gtk.TargetFlags.OTHER_APP, DND_URI_LIST)] targets = [Gtk.TargetEntry.new(*t) for t in targets] self.drag_dest_set(Gtk.DestDefaults.ALL, targets, Gdk.DragAction.COPY) self.connect('drag-data-received', self.__drag_data_received) if not headless: on_first_map(self, self.__configure_scan_dirs, library) if config.getboolean('library', 'refresh_on_start'): self.__rebuild(None, False) self.connect("key-press-event", self.__key_pressed, player) self.connect("destroy", self.__destroy) self.enable_window_tracking("quodlibet")
def __changed_text(self, entry, name): config.set('albumart', name, entry.get_text())
def _changed(self, widget, event, section, option): if self._expander.get_expanded() and self.get_property('position-set'): config.set(section, option, str(self.get_relative()))
def set_cfg(option, value): cfg_option = "%s_%s" % (_PLUGIN_ID, option) if get_cfg(option) != value: config.set("plugins", cfg_option, value)
def _on_volume_changed(self, player, *args): config.set("memory", "volume", str(player.volume))
def save(self): conf = self.__get_config_string() config.set("browsers", "albums", conf) text = self.__search.get_text().encode("utf-8") config.set("browsers", "query_text", text)
def save(self): config.set("browsers", "query_text", self._text.encode('utf-8'))