-
Notifications
You must be signed in to change notification settings - Fork 1
/
json2ytmusic.py
executable file
·93 lines (69 loc) · 3.15 KB
/
json2ytmusic.py
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
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import json
import os
from ytmusicapi import YTMusic
YELLOW = '\033[33m'
GREEN = '\033[32m'
RESET = '\033[0m'
def main():
parser = argparse.ArgumentParser(description='Convert Apple Music playlist to YouTube Music')
parser.add_argument('playlist_id', help='YouTube Music playlist ID')
parser.add_argument('input', nargs='?', type=argparse.FileType('r'), default='-',
help='Apple Music playlist JSON file (default stdin)')
parser.add_argument('-o', '--oauth', default='oauth.json', help='OAuth file (default oauth.json)')
parser.add_argument('-c', '--cache', default='ytmusic-cache.json', help='Cache file (default ytmusic-cache.json)')
args = parser.parse_args()
yt = YTMusic(args.oauth)
cache = {}
if os.path.exists(args.cache):
with open(args.cache, 'r') as f:
cache = json.load(f)
# noinspection PyTypeChecker
dst_playlist = yt.get_playlist(args.playlist_id, limit=None)
author = dst_playlist.get('author', {}).get('name', 'Unknown')
print(f'{YELLOW} Adding new songs to playlist "{dst_playlist["title"]}"{author}{RESET}')
# Read the Apple Music playlist
src_playlist = json.load(args.input)
existing = set()
for song in dst_playlist["tracks"]:
existing.add(song['videoId'])
to_add = []
try:
for song in src_playlist:
title = song['title']
artist = song['artist']
if 'videoId' in song:
cache[f'{title} {artist}'] = song['videoId']
print(f'{GREEN} {title} - {artist} '.ljust(60, ' '), end='')
print(f'-> provided: {song["videoId"]}{RESET}')
to_add.append(song['videoId'])
continue
query = f'{title} {artist}'
if query in cache:
if cache[query] not in existing and cache[query] not in to_add:
print(f'{YELLOW} {title} - {artist} '.ljust(60, ' '), end='')
print(f'-> cached: {cache[query]}{RESET}')
to_add.append(cache[query])
continue
results = yt.search(query, filter='songs', limit=5)
if len(results) == 0:
print(f'\033[31m No results for {query}{RESET}')
continue
# YouTube search is kinda good, so just take the first result
best_result = results[0]
print(f'{GREEN} {title} - {artist} '.ljust(60, ' '), end='')
print(f'-> {best_result["title"]} - {best_result["artists"][0]["name"] if len(best_result["artists"]) else "" }{RESET}')
if best_result['videoId'] not in existing and best_result['videoId'] not in to_add:
to_add.append(best_result['videoId'])
cache[query] = best_result['videoId']
finally:
with open(args.cache, 'w') as f:
json.dump(cache, f, indent=4)
print(f'{YELLOW} Adding {len(to_add)} new songs...{RESET}')
if len(to_add) > 0:
yt.add_playlist_items(args.playlist_id, videoIds=to_add)
print(f'{GREEN} Done!{RESET}')
if __name__ == '__main__':
main()