Browse Source

itunes: set play count tag (ID3 & MP4)

Fabian Peter Hammerle 6 years ago
parent
commit
b0d288e8bd
1 changed files with 54 additions and 6 deletions
  1. 54 6
      symuid

+ 54 - 6
symuid

@@ -1,6 +1,7 @@
 #!/usr/bin/env python3
 # -*- coding: utf-8 -*-
 
+import datetime as dt
 import dateutil.parser
 import mutagen
 import mutagen.id3
@@ -17,6 +18,10 @@ 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()
 
@@ -83,6 +88,41 @@ def get_itunes_dict_value(dict_node, key):
         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)
@@ -100,16 +140,24 @@ def import_itunes_play_count(itunes_library_path, itunes_library_root_url, itune
             play_count = get_itunes_dict_value(track_node, 'Play Count')
         except KeyError:
             play_count = 0
-        if track_url and track_url.startswith(itunes_library_root_url):
+        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):]),
             )
-            if play_count > 0:
-                last_play_dt = get_itunes_dict_value(track_node, 'Play Date UTC')
-            else:
-                last_play_dt = None
-            print(track_path, play_count, last_play_dt)
+            # 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):