-
Notifications
You must be signed in to change notification settings - Fork 0
/
mpv-clean-priv-frames
executable file
·133 lines (111 loc) · 3.77 KB
/
mpv-clean-priv-frames
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#!/usr/bin/env python3
import json
import subprocess
import typing as t
from pathlib import Path
import click
from more_itertools import unique_everseen, ilen
from my.mpv.history_daemon import all_history, Media, inputs
from mpv_history_daemon.serialize import parse_json_file
disallowed_exact = (
"log",
"ytdl_description",
"md5",
"comment",
"info",
"arcue",
"itunsmpb",
"buycdurl",
"cdtoc",
"encoding",
"encoder",
"major_brand",
"minor_version",
"compatible_brands",
"unsyncedlyrics",
"itunes_cddb",
"acoustid fingerprint",
"notes",
)
disallowed_contains = (
"location",
"id3v2_priv",
"gracenote",
"organization",
"streaming/otf/durations",
)
disallowed_startswith = ("lyrics",)
def _priv_frames(metadata: dict[str, t.Any]) -> t.Iterator[str]:
for k in metadata.keys():
kl = k.lower()
for d in disallowed_exact:
if d == kl:
yield k
for d in disallowed_contains:
if d in kl:
yield k
for d in disallowed_startswith:
if kl.startswith(d):
yield k
def list_broken(mpv: Media) -> t.Iterator[str]:
if ilen(_priv_frames(mpv.metadata)) > 0:
yield mpv.path
def clean_file(jf: Path) -> None:
"""
Removes any disallowed keys from the metadata object, tracked by
https://github.com/seanbreckenridge/mpv-history-daemon
"""
data = parse_json_file(jf)
blobs = [data]
if "mapping" in data:
blobs = data["mapping"].values()
for blob in blobs:
for ts in list(blob):
if "playlist" in blob[ts]:
print(f"Removing {ts} {blob[ts]}")
blob.pop(ts)
continue
if metadata := blob[ts].get("metadata"):
if removed_keys := list(_priv_frames(metadata)):
for rk in removed_keys:
metadata.pop(rk)
print(f"Removed {removed_keys}, fixed {metadata}")
# theres a possibility this is a gz file, so test for that
# and just write back to the JSON file
#
# then, if it was a gz file, use gzip -9 {file} to compress it
# back to a .json.gz file
if jf.suffix == ".gz":
without_gz = jf.with_suffix("")
click.echo(f"Writing to {without_gz}", err=True)
without_gz.write_text(json.dumps(data))
click.echo(f"Compressing {without_gz}", err=True)
subprocess.run(["gzip", "-f", "-9", str(without_gz)], check=True)
assert jf.exists()
else:
jf.write_text(json.dumps(data))
@click.command()
@click.argument("CMD", type=click.Choice(["list", "clean"], case_sensitive=False))
def main(cmd: str) -> None:
"""
Removes private id3 frames from mpv data files, and lets me run
and eyeD3 (ID3) command against any listed files to prevent them
from appearing in metadata files in the future
These are typically big blobs of base64 which increase the size
of the metadata files
Should list, to check if there are any new tracked private tags:
mpv-clean-priv-frames list
Then remove them with a command like:
\b
mpv-clean-priv-frames list | sort -u | exists | tr '\\n' '\\0' | xargs -0 -I {} eyeD3 --remove-frame PRIV --user-text-frame 'GracenoteExtData:' --user-text-frame 'GracenoteFileID:' --user-text-frame 'ORGANIZATION:' --user-text-frame "GRACENOTEFILEID:" --user-text-frame "GRACENOTEEXTDATA:" "{}"
And then run 'mpv-clean-priv-frames clean' to remove the metadata keys from my mpv data files
"""
if cmd == "clean":
for p in inputs():
clean_file(p)
else:
for m in all_history():
for loc in unique_everseen(list_broken(m)):
print(loc)
if __name__ == "__main__":
main()