def __popup_menu(self, view, parent): menu = Gtk.Menu() view.ensure_popup_selection() model, rows = view.get_selection().get_selected_rows() can_change = min([model[path][0].canedit for path in rows]) items = [ SplitDisc, SplitTitle, SplitPerformer, SplitArranger, SplitValues, SplitPerformerFromTitle, SplitOriginalArtistFromTitle ] items.extend(self.handler.plugins) items.sort(key=lambda item: (item._order, item.__name__)) if len(rows) == 1: row = model[rows[0]] entry = row[0] comment = entry.value text = comment.text for Item in items: if Item.tags and entry.tag not in Item.tags: continue try: b = Item(entry.tag, text) except: util.print_exc() else: b.connect('activate', self.__menu_activate, view) if (not min( listmap(self.__songinfo.can_change, b.needs) + [1]) or comment.is_special()): b.set_sensitive(False) menu.append(b) if menu.get_children(): menu.append(SeparatorMenuItem()) b = MenuItem(_("_Remove"), Icons.LIST_REMOVE) b.connect('activate', self.__remove_tag, view) qltk.add_fake_accel(b, "Delete") menu.append(b) menu.show_all() # Setting the menu itself to be insensitive causes it to not # be dismissed; see #473. for c in menu.get_children(): c.set_sensitive(can_change and c.get_property('sensitive')) b.set_sensitive(True) menu.connect('selection-done', lambda m: m.destroy()) # XXX: Keep reference self.__menu = menu return view.popup_menu(menu, 3, Gtk.get_current_event_time())
def __popup_menu(self, view, parent): menu = Gtk.Menu() view.ensure_popup_selection() model, rows = view.get_selection().get_selected_rows() can_change = min([model[path][0].canedit for path in rows]) items = [SplitDisc, SplitTitle, SplitPerformer, SplitArranger, SplitValues, SplitPerformerFromTitle, SplitOriginalArtistFromTitle] items.extend(self.handler.plugins) items.sort(key=lambda item: (item._order, item.__name__)) if len(rows) == 1: row = model[rows[0]] entry = row[0] comment = entry.value text = comment.text for Item in items: if Item.tags and entry.tag not in Item.tags: continue try: b = Item(entry.tag, text) except: util.print_exc() else: b.connect('activate', self.__menu_activate, view) if (not min(listmap(self.__songinfo.can_change, b.needs) + [1]) or comment.is_special()): b.set_sensitive(False) menu.append(b) if menu.get_children(): menu.append(SeparatorMenuItem()) b = MenuItem(_("_Remove"), Icons.LIST_REMOVE) b.connect('activate', self.__remove_tag, view) qltk.add_fake_accel(b, "Delete") menu.append(b) menu.show_all() # Setting the menu itself to be insensitive causes it to not # be dismissed; see #473. for c in menu.get_children(): c.set_sensitive(can_change and c.get_property('sensitive')) b.set_sensitive(True) menu.connect('selection-done', lambda m: m.destroy()) # XXX: Keep reference self.__menu = menu return view.popup_menu(menu, 3, Gtk.get_current_event_time())
def __get_metadata_real(self): """ https://www.freedesktop.org/wiki/Specifications/mpris-spec/metadata/ """ metadata = {} metadata["mpris:trackid"] = self.__get_current_track_id() def ignore_overflow(dbus_type, value): try: return dbus_type(value) except OverflowError: return 0 song = app.player.info if not song: return metadata metadata["mpris:length"] = ignore_overflow( dbus.Int64, song("~#length") * 10 ** 6) if self.__cover is not None: self.__cover.close() self.__cover = None cover = app.cover_manager.get_cover(song) if cover: is_temp = cover.name.startswith(tempfile.gettempdir()) if is_temp: self.__cover = cover metadata["mpris:artUrl"] = fsn2uri(cover.name) # All list values list_val = {"artist": "artist", "albumArtist": "albumartist", "comment": "comment", "composer": "composer", "genre": "genre", "lyricist": "lyricist"} for xesam, tag in iteritems(list_val): vals = song.list(tag) if vals: metadata["xesam:" + xesam] = listmap(unival, vals) # All single values sing_val = {"album": "album", "title": "title", "asText": "~lyrics"} for xesam, tag in iteritems(sing_val): vals = song.comma(tag) if vals: metadata["xesam:" + xesam] = unival(vals) # URI metadata["xesam:url"] = song("~uri") # Integers num_val = {"audioBPM": "bpm", "discNumber": "disc", "trackNumber": "track", "useCount": "playcount"} for xesam, tag in iteritems(num_val): val = song("~#" + tag, None) if val is not None: metadata["xesam:" + xesam] = ignore_overflow(dbus.Int32, val) # Rating metadata["xesam:userRating"] = ignore_overflow( dbus.Double, song("~#rating")) # Dates ISO_8601_format = "%Y-%m-%dT%H:%M:%S" tuple_time = time.gmtime(song("~#lastplayed")) iso_time = time.strftime(ISO_8601_format, tuple_time) metadata["xesam:lastUsed"] = iso_time year = song("~year") if year: try: tuple_time = time.strptime(year, "%Y") iso_time = time.strftime(ISO_8601_format, tuple_time) except ValueError: pass else: metadata["xesam:contentCreated"] = iso_time return metadata
def __get_value(self, key): """This is similar to __call__ in the AudioFile class. All internal tags are changed to represent a collection of songs. """ # Using key:<func> runs the resulting list of values # through the function before returning it. # Numeric keys without a func will default to a reasonable function if key.startswith("~#"): key = key[2:] if key[-4:-3] == ":": func = key[-3:] key = key[:-4] elif key == "tracks": return len(self.songs) elif key == "discs": return len({song("~#disc", 1) for song in self.songs}) elif key == "bitrate": length = self.__get_value("~#length") if not length: return 0 w = lambda s: s("~#bitrate", 0) * s("~#length", 0) return sum(w(song) for song in self.songs) / length else: # Standard or unknown numeric key. # AudioFile will try to cast the values to int, # default to avg func = NUM_DEFAULT_FUNCS.get(key, "avg") key = "~#" + key func = NUM_FUNCS.get(func) if func: # If none of the songs can return a numeric key, # the album returns default values = (song(key) for song in self.songs) values = [v for v in values if v != ""] return func(values) if values else None elif key in NUMERIC_ZERO_DEFAULT: return 0 return None elif key[:1] == "~": key = key[1:] numkey = key.split(":")[0] keys = {"people": {}, "peoplesort": {}} if key in keys: people = keys["people"] peoplesort = keys["peoplesort"] for song in self.songs: # Rank people by "relevance" -- artists before composers # before performers, then by number of appearances. for w, k in enumerate(ELPOEP): persons = song.list(k) for person in persons: people[person] = (people.get(person, 0) - PEOPLE_SCORE[w]) if k in TAG_TO_SORT: persons = song.list(TAG_TO_SORT[k]) or persons for person in persons: peoplesort[person] = (peoplesort.get(person, 0) - PEOPLE_SCORE[w]) # It's cheaper to get people and peoplesort in one go keys["people"] = sorted(people.keys(), key=people.__getitem__)[:100] keys["peoplesort"] = sorted(peoplesort.keys(), key=peoplesort.__getitem__)[:100] ret = keys.pop(key) ret = (ret and "\n".join(ret)) or None other, values = keys.popitem() other = "~" + other if not values: self.__default.add(other) else: if other in self.__used: self.__used.remove(other) self.__used.append(other) self.__cache[other] = "\n".join(values) return ret elif numkey == "length": length = self.__get_value("~#" + key) return None if length is None else util.format_time(length) elif numkey == "long-length": length = self.__get_value("~#" + key[5:]) return (None if length is None else util.format_time_long(length)) elif numkey == "tracks": tracks = self.__get_value("~#" + key) return (None if tracks is None else ngettext("%d track", "%d tracks", tracks) % tracks) elif numkey == "discs": discs = self.__get_value("~#" + key) if discs > 1: return ngettext("%d disc", "%d discs", discs) % discs else: # TODO: check this is correct for discs == 1 return None elif numkey == "rating": rating = self.__get_value("~#" + key) if rating is None: return None return util.format_rating(rating) elif numkey == "filesize": size = self.__get_value("~#" + key) return None if size is None else util.format_size(size) key = "~" + key # Nothing special was found, so just take all values of the songs # and sort them by their number of appearance result = {} for song in self.songs: for value in song.list(key): result[value] = result.get(value, 0) - 1 values = listmap(lambda x: x[0], sorted(result.items(), key=lambda x: (x[1], x[0]))) return "\n".join(values) if values else None
def __get_metadata(self): """http://xmms2.org/wiki/MPRIS_Metadata""" metadata = {} metadata["mpris:trackid"] = self.__get_current_track_id() song = app.player.info if not song: return metadata metadata["mpris:length"] = dbus.Int64(song("~#length") * 10**6) self.__cover = cover = app.cover_manager.get_cover(song) is_temp = False if cover: name = cover.name is_temp = name.startswith(tempfile.gettempdir()) # This doesn't work for embedded images.. the file gets unlinked # after loosing the file handle metadata["mpris:artUrl"] = fsn2uri(name) if not is_temp: self.__cover = None # All list values list_val = { "artist": "artist", "albumArtist": "albumartist", "comment": "comment", "composer": "composer", "genre": "genre", "lyricist": "lyricist" } for xesam, tag in iteritems(list_val): vals = song.list(tag) if vals: metadata["xesam:" + xesam] = listmap(unival, vals) # All single values sing_val = {"album": "album", "title": "title", "asText": "~lyrics"} for xesam, tag in iteritems(sing_val): vals = song.comma(tag) if vals: metadata["xesam:" + xesam] = unival(vals) # URI metadata["xesam:url"] = song("~uri") # Integers num_val = { "audioBPM": "bpm", "discNumber": "disc", "trackNumber": "track", "useCount": "playcount" } for xesam, tag in iteritems(num_val): val = song("~#" + tag, None) if val is not None: metadata["xesam:" + xesam] = int(val) # Rating metadata["xesam:userRating"] = float(song("~#rating")) # Dates ISO_8601_format = "%Y-%m-%dT%H:%M:%S" tuple_time = time.gmtime(song("~#lastplayed")) iso_time = time.strftime(ISO_8601_format, tuple_time) metadata["xesam:lastUsed"] = iso_time year = song("~year") if year: try: tuple_time = time.strptime(year, "%Y") iso_time = time.strftime(ISO_8601_format, tuple_time) except ValueError: pass else: metadata["xesam:contentCreated"] = iso_time return metadata
def __get_metadata(self): """http://xmms2.org/wiki/MPRIS_Metadata""" metadata = {} metadata["mpris:trackid"] = self.__get_current_track_id() song = app.player.info if not song: return metadata metadata["mpris:length"] = dbus.Int64(song("~#length") * 10 ** 6) self.__cover = cover = app.cover_manager.get_cover(song) is_temp = False if cover: name = cover.name is_temp = name.startswith(tempfile.gettempdir()) # This doesn't work for embedded images.. the file gets unlinked # after loosing the file handle metadata["mpris:artUrl"] = fsn2uri(name) if not is_temp: self.__cover = None # All list values list_val = {"artist": "artist", "albumArtist": "albumartist", "comment": "comment", "composer": "composer", "genre": "genre", "lyricist": "lyricist"} for xesam, tag in iteritems(list_val): vals = song.list(tag) if vals: metadata["xesam:" + xesam] = listmap(unival, vals) # All single values sing_val = {"album": "album", "title": "title", "asText": "~lyrics"} for xesam, tag in iteritems(sing_val): vals = song.comma(tag) if vals: metadata["xesam:" + xesam] = unival(vals) # URI metadata["xesam:url"] = song("~uri") # Integers num_val = {"audioBPM": "bpm", "discNumber": "disc", "trackNumber": "track", "useCount": "playcount"} for xesam, tag in iteritems(num_val): val = song("~#" + tag, None) if val is not None: metadata["xesam:" + xesam] = int(val) # Rating metadata["xesam:userRating"] = float(song("~#rating")) # Dates ISO_8601_format = "%Y-%m-%dT%H:%M:%S" tuple_time = time.gmtime(song("~#lastplayed")) iso_time = time.strftime(ISO_8601_format, tuple_time) metadata["xesam:lastUsed"] = iso_time year = song("~year") if year: try: tuple_time = time.strptime(year, "%Y") iso_time = time.strftime(ISO_8601_format, tuple_time) except ValueError: pass else: metadata["xesam:contentCreated"] = iso_time return metadata