#!/usr/bin/env python3 # -*- coding: utf-8 -*- import datetime as dt import dateutil.parser import mutagen import mutagen.id3 import mutagen.mp4 import os import symuid.library.itunes import urllib.parse def generate_play_count_tag_label(player, library_id, reg_dt): return 'symuid:pcnt:{}:{}:{}'.format(player, library_id, int(reg_dt.timestamp())) def set_play_count_tag(track_path, player, library_id, reg_dt, play_count): assert isinstance(reg_dt, dt.datetime), reg_dt tag_label = generate_play_count_tag_label( player=player, library_id=library_id, reg_dt=reg_dt, ) track = mutagen.File(filename=track_path) if isinstance(track.tags, mutagen.id3.ID3): tag_label_id3 = 'TXXX:' + tag_label if not tag_label_id3 in track.tags: # mutagen.id3._specs.EncodedTextSpec.write encodes # 'desc' and 'text' tag = mutagen.id3.TXXX( encoding=mutagen.id3.Encoding.LATIN1, desc=tag_label, text=[str(play_count)], ) track.tags.add(tag) track.save() print('{!r}: set ID3 tag {!r}'.format(track_path, tag)) elif isinstance(track.tags, mutagen.mp4.MP4Tags): tag_label_mp4 = '----:' + tag_label if not tag_label_mp4 in track.tags: track.tags[tag_label_mp4] = tag = mutagen.mp4.MP4FreeForm( # "a signed big-endian integer with length one of { 1,2,3,4,8 } bytes" # TODO set byte length properly data=play_count.to_bytes(1, byteorder='big'), dataformat=mutagen.mp4.AtomDataType.INTEGER, ) track.save() print('{!r}: set MP4 tag {!r}'.format(track_path, tag)) else: raise Exception(track_path) def symuid_import_itunes(xml_library_path, root_url, root_path): root_path = os.path.expanduser(root_path) lib = symuid.library.itunes.XmlLibrary(xml_library_path) for track in lib.tracks: # TODO create tag if last_play_dt is None if track.last_play_dt and track.location_url and track.location_url.startswith(root_url): track_path = os.path.join( root_path, urllib.parse.unquote(track.location_url[len(root_url):]), ) # TODO dt=dt.datetime.now() set_play_count_tag( track_path=track_path, player='itunes', library_id=lib.id, reg_dt=track.last_play_dt, play_count=track.play_count, ) def _init_argparser(): import argparse argparser = argparse.ArgumentParser(description=None) argparser.add_argument('xml_library_path') argparser.add_argument( '--root-url', default='file://localhost/', help='(default: %(default)r)', ) argparser.add_argument( '--root-path', default='', help='(default: %(default)r)', ) return argparser def main(argv): argparser = _init_argparser() args = argparser.parse_args(argv[1:]) symuid_import_itunes(**vars(args)) return 0 if __name__ == "__main__": import sys sys.exit(main(sys.argv))