Browse Source

split symuid-import-itunes from symuid

Fabian Peter Hammerle 6 years ago
parent
commit
85cc09a1e2
2 changed files with 139 additions and 120 deletions
  1. 1 120
      symuid
  2. 138 0
      symuid-import-itunes

+ 1 - 120
symuid

@@ -1,15 +1,11 @@
 #!/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 subprocess
-import urllib.parse
-import xml.etree.ElementTree
 
 # http://id3.org/id3v2.4.0-frames#4.1.
 TRACK_UUID_ID3_OWNER_ID = 'symuid'
@@ -18,10 +14,6 @@ TRACK_UUID_ID3_OWNER_ID = 'symuid'
 TRACK_UUID_MP4_TAG = '----:symuid:uuid'
 
 
-def generate_play_count_tag_label(player, library_id, dt):
-    return 'symuid:pcnt:{}:{}:{}'.format(player, library_id, int(dt.timestamp()))
-
-
 def generate_uuid():
     return subprocess.check_output(['uuid', '-v', '4', '-F', 'BIN']).strip()
 
@@ -66,107 +58,7 @@ def get_or_assign_uuid_mp4(mp4_file):
     return mp4_file[TRACK_UUID_MP4_TAG][0]
 
 
-def get_itunes_dict_value_node(dict_node, key):
-    assert isinstance(dict_node, xml.etree.ElementTree.Element)
-    assert isinstance(key, str)
-    # WORKAROUND method getnext() is sadly not available
-    for child_idx, child_node in enumerate(dict_node):
-        if child_node.tag == 'key' and child_node.text == key:
-            return dict_node[child_idx + 1]
-    raise KeyError()
-
-
-def get_itunes_dict_value(dict_node, key):
-    value_node = get_itunes_dict_value_node(dict_node, key)
-    if value_node.tag == 'string':
-        return value_node.text
-    elif value_node.tag == 'integer':
-        return int(value_node.text)
-    elif value_node.tag == 'date':
-        return dateutil.parser.parse(value_node.text)
-    else:
-        return value_node
-
-
-def set_play_count_tag(track_path, player, library_id, dt, play_count):
-    tag_label = generate_play_count_tag_label(
-        player=player,
-        library_id=library_id,
-        dt=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 import_itunes_play_count(itunes_library_path, itunes_library_root_url, itunes_library_root_path):
-    itunes_library_root_path = os.path.expanduser(itunes_library_root_path)
-    lib = xml.etree.ElementTree.parse(itunes_library_path)
-    # WORKAROUND find('.//key[.="Library Persistent ID"]')
-    #  -> SyntaxError: invalid predicate
-    lib_root_dict = lib.find('./dict')
-    lib_id = get_itunes_dict_value(lib_root_dict, 'Library Persistent ID')
-    assert isinstance(lib_id, str) and len(lib_id) > 0, lib_id
-    for track_node in get_itunes_dict_value(lib_root_dict, 'Tracks').iterfind('./dict'):
-        try:
-            track_url = get_itunes_dict_value(track_node, 'Location')
-        except KeyError:
-            track_url = None
-        try:
-            play_count = get_itunes_dict_value(track_node, 'Play Count')
-        except KeyError:
-            play_count = 0
-        try:
-            last_play_dt = get_itunes_dict_value(track_node, 'Play Date UTC')
-        except KeyError:
-            last_play_dt = None
-        # TODO create tag if last_play_dt is None
-        if last_play_dt and track_url and track_url.startswith(itunes_library_root_url):
-            track_path = os.path.join(
-                itunes_library_root_path,
-                urllib.parse.unquote(track_url[len(itunes_library_root_url):]),
-            )
-            # TODO dt=dt.datetime.now()
-            set_play_count_tag(
-                track_path=track_path,
-                player='itunes',
-                library_id=lib_id,
-                dt=last_play_dt,
-                play_count=play_count,
-            )
-
-
-def symuid(path, itunes_library_path=None, itunes_library_root_url=None, itunes_library_root_path=None):
-    if itunes_library_path:
-        import_itunes_play_count(
-            itunes_library_path,
-            itunes_library_root_url,
-            itunes_library_root_path,
-        )
+def symuid(path):
     if os.path.isdir(path):
         for dirpath, dirnames, filenames in os.walk(path):
             for filename in filenames:
@@ -190,17 +82,6 @@ def _init_argparser():
     import argparse
     argparser = argparse.ArgumentParser(description=None)
     argparser.add_argument('path')
-    argparser.add_argument('--itunes-library-path')
-    argparser.add_argument(
-        '--itunes-library-root-url',
-        default='file://localhost/',
-        help='(default: %(default)r)',
-    )
-    argparser.add_argument(
-        '--itunes-library-root-path',
-        default='',
-        help='(default: %(default)r)',
-    )
     return argparser
 
 

+ 138 - 0
symuid-import-itunes

@@ -0,0 +1,138 @@
+#!/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 urllib.parse
+import xml.etree.ElementTree
+
+
+def generate_play_count_tag_label(player, library_id, reg_dt):
+    return 'symuid:pcnt:{}:{}:{}'.format(player, library_id, int(reg_dt.timestamp()))
+
+
+def get_itunes_dict_value_node(dict_node, key):
+    assert isinstance(dict_node, xml.etree.ElementTree.Element)
+    assert isinstance(key, str)
+    # WORKAROUND method getnext() is sadly not available
+    for child_idx, child_node in enumerate(dict_node):
+        if child_node.tag == 'key' and child_node.text == key:
+            return dict_node[child_idx + 1]
+    raise KeyError()
+
+
+def get_itunes_dict_value(dict_node, key):
+    value_node = get_itunes_dict_value_node(dict_node, key)
+    if value_node.tag == 'string':
+        return value_node.text
+    elif value_node.tag == 'integer':
+        return int(value_node.text)
+    elif value_node.tag == 'date':
+        return dateutil.parser.parse(value_node.text)
+    else:
+        return value_node
+
+
+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 = xml.etree.ElementTree.parse(xml_library_path)
+    # WORKAROUND find('.//key[.="Library Persistent ID"]')
+    #  -> SyntaxError: invalid predicate
+    lib_root_dict = lib.find('./dict')
+    lib_id = get_itunes_dict_value(lib_root_dict, 'Library Persistent ID')
+    assert isinstance(lib_id, str) and len(lib_id) > 0, lib_id
+    for track_node in get_itunes_dict_value(lib_root_dict, 'Tracks').iterfind('./dict'):
+        try:
+            track_url = get_itunes_dict_value(track_node, 'Location')
+        except KeyError:
+            track_url = None
+        try:
+            play_count = get_itunes_dict_value(track_node, 'Play Count')
+        except KeyError:
+            play_count = 0
+        try:
+            last_play_dt = get_itunes_dict_value(track_node, 'Play Date UTC')
+        except KeyError:
+            last_play_dt = None
+        # TODO create tag if last_play_dt is None
+        if last_play_dt and track_url and track_url.startswith(root_url):
+            track_path = os.path.join(
+                root_path,
+                urllib.parse.unquote(track_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=last_play_dt,
+                play_count=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))