def __init__(self, songs): keys = {} first = {} all = {} total = len(songs) self.songs = songs for song in songs: self.is_file &= song.is_file self.multiple_values &= song.multiple_values for comment, val in song.iteritems(): keys[comment] = keys.get(comment, 0) + 1 first.setdefault(comment, val) all[comment] = all.get(comment, True) and first[comment] == val # collect comment representations for comment, count in keys.iteritems(): if count < total: if all[comment]: value = self.PartialSharedComment(first[comment]) else: value = self.PartialUnsharedComment(first[comment]) else: decoded = first[comment] if isinstance(decoded, str): decoded = util.decode(decoded) if all[comment]: value = self.SharedComment(decoded) else: value = self.UnsharedComment(decoded) value.have = count value.total = total value.missing = total - count self[comment] = value
def __init__(self, track): super(IPodSong, self).__init__() self.sanitize(gpod.itdb_filename_on_ipod(track)) # String keys for key in ['artist', 'album', 'title', 'genre', 'grouping', 'composer', 'albumartist']: # albumartist since libgpod-0.4.2 value = getattr(track, key, None) if value: self[key] = util.decode(value) # Sort keys (since libgpod-0.5.0) for key in ['artist', 'album', 'albumartist']: value = getattr(track, 'sort_' + key, None) if value: self[key + 'sort'] = util.decode(value) # Numeric keys for key in ['bitrate', 'playcount']: value = getattr(track, key) if value: self['~#'+key] = value try: self["date"] = unicode(track.year) except AttributeError: pass if track.cds: self["discnumber"] = u"%d/%d" % (track.cd_nr, track.cds) elif track.cd_nr: self["discnumber"] = u"%d" % track.cd_nr if track.tracks: self['tracknumber'] = u"%d/%d" % (track.track_nr, track.tracks) elif track.track_nr: self['tracknumber'] = u"%d" % track.track_nr for key, value in { '~#rating': min(1.0, track.rating / 100.0), '~#length': track.tracklen / 1000.0, }.items(): if value != 0: self[key] = value self['~format'] = u"iPod: %s" % track.filetype
def __error(self, player, song, error, librarian): newstr = u"%s: %s\n\n" % ( util.decode(time.asctime(), const.ENCODING), error) self.__errors_in_a_row += 1 if self.__errors_in_a_row > MAX_ERRORS: self.__errors_in_a_row = 0 ErrorMessage(None, _("Too Many Errors"), _("Stopping playback because there were %d errors " "in a row.") % MAX_ERRORS).run() player.go_to(None) player.paused = True song["~errors"] = newstr + song.get("~errors", "")
def parse_gstreamer_taglist(tags): """Takes a GStreamer taglist and returns a dict containing only numeric and unicode values and str keys.""" merged = {} for key in tags.keys(): value = tags[key] # extended-comment sometimes containes a single vorbiscomment or # a list of them ["key=value", "key=value"] if key == "extended-comment": if not isinstance(value, list): value = [value] for val in value: if not isinstance(val, unicode): continue split = val.split("=", 1) sub_key = util.decode(split[0]) val = split[-1] if sub_key in merged: if val not in merged[sub_key].split("\n"): merged[sub_key] += "\n" + val else: merged[sub_key] = val elif isinstance(value, gst.Date): try: value = u"%d-%d-%d" % (value.year, value.month, value.day) except (ValueError, TypeError): continue merged[key] = value elif isinstance(value, list): # there are some lists for id3 containing gst.Buffer (binary data) continue else: if isinstance(value, str): value = util.decode(value) if not isinstance(value, unicode) and \ not isinstance(value, (int, long, float)): value = unicode(value) merged[key] = value return merged
def parse_taglist(data): """Parses a dump file like list of tags and returns a list of IRFiles uri=http://... tag=value1 tag2=value tag=value2 uri=http://... ... """ stations = [] station = None for l in data.split("\n"): key = l.split("=")[0] value = l.split("=", 1)[1] if key == "uri": if station: stations.append(station) station = IRFile(value) continue value = util.decode(value) san = sanitize_tags({key: value}, stream=True).items() if not san: continue key, value = san[0] if isinstance(value, str): value = value.decode("utf-8") if value not in station.list(key): station.add(key, value) else: station[key] = value if station: stations.append(station) return stations
def __init__(self, filename): audio = MP4(filename) self["~#length"] = int(audio.info.length) self["~#bitrate"] = int(audio.info.bitrate / 1000) for key, values in audio.items(): if key in self.__tupletranslate: name = self.__tupletranslate[key] cur, total = values[0] if total: self[name] = u"%d/%d" % (cur, total) else: self[name] = unicode(cur) elif key in self.__translate: name = self.__translate[key] if key == "tmpo": self[name] = "\n".join(map(unicode, values)) elif key.startswith("----"): self[name] = "\n".join( map(lambda v: util.decode(v).strip("\x00"), values)) else: self[name] = "\n".join(values) elif key == "covr": self["~picture"] = "y" self.sanitize(filename)
def __save_files(self, save, revert, model, library): updated = {} deleted = {} added = {} renamed = {} for row in model: if row[EDITED] and not (row[DELETED] or row[RENAMED]): if row[ORIGVALUE] is not None: updated.setdefault(row[TAG], []) updated[row[TAG]].append((util.decode(row[VALUE]), util.decode(row[ORIGVALUE]))) else: added.setdefault(row[TAG], []) added[row[TAG]].append(util.decode(row[VALUE])) if row[EDITED] and row[DELETED]: if row[ORIGVALUE] is not None: deleted.setdefault(row[TAG], []) deleted[row[TAG]].append(util.decode(row[ORIGVALUE])) if row[EDITED] and row[RENAMED] and not row[DELETED]: renamed.setdefault(row[TAG], []) renamed[row[TAG]].append( (util.decode(row[ORIGTAG]), util.decode(row[VALUE]), util.decode(row[ORIGVALUE])) ) was_changed = [] songs = self.__songinfo.songs win = WritingWindow(self, len(songs)) for song in songs: if ( not song.valid() and not qltk.ConfirmAction( self, _("Tag may not be accurate"), _( "<b>%s</b> changed while the program was running. " "Saving without refreshing your library may " "overwrite other changes to the song.\n\n" "Save this song anyway?" ) % util.escape(util.fsdecode(song("~basename"))), ).run() ): break changed = False for key, values in updated.iteritems(): for (new_value, old_value) in values: new_value = util.unescape(new_value) if song.can_change(key): if old_value is None: song.add(key, new_value) else: song.change(key, old_value, new_value) changed = True for key, values in added.iteritems(): for value in values: value = util.unescape(value) if song.can_change(key): song.add(key, value) changed = True for key, values in deleted.iteritems(): for value in values: value = util.unescape(value) if song.can_change(key) and key in song: song.remove(key, value) changed = True save_rename = [] for new_tag, values in renamed.iteritems(): for old_tag, new_value, old_value in values: old_tag = util.unescape(old_tag) old_value = util.unescape(old_value) new_value = util.unescape(new_value) if song.can_change(new_tag) and song.can_change(old_tag) and old_tag in song: if not is_special(new_value): song.remove(old_tag, old_value) save_rename.append((new_tag, new_value)) elif is_missing(new_value): value = strip_missing(old_value) song.remove(old_tag, old_value) save_rename.append((new_tag, new_value)) else: save_rename.append((new_tag, song[old_tag])) song.remove(old_tag, None) changed = True for tag, value in save_rename: song.add(tag, value) if changed: try: song.write() except: util.print_exc() qltk.ErrorMessage( self, _("Unable to save song"), _( "Saving <b>%s</b> failed. The file " "may be read-only, corrupted, or you " "do not have permission to edit it." ) % (util.escape(util.fsdecode(song("~basename")))), ).run() library.reload(song, changed=was_changed) break was_changed.append(song) if win.step(): break win.destroy() library.changed(was_changed) for b in [save, revert]: b.set_sensitive(False)
def test_invalid(self): self.failUnlessEqual( util.decode("fo\xde"), u'fo\ufffd [Invalid Encoding]')
def test_safe(self): self.failUnlessEqual(util.decode("foo!"), "foo!")
def test_empty(self): self.failUnlessEqual(util.decode(""), "")