-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathncm_sync_fav.py
More file actions
executable file
·153 lines (126 loc) · 5.45 KB
/
Copy pathncm_sync_fav.py
File metadata and controls
executable file
·153 lines (126 loc) · 5.45 KB
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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
#!/usr/bin/env python3
import argparse
import os
from pyncm.apis import *
from ncm_login import *
from ncm_download import download
from ncm_upload import upload
def get_songs(song_ids: [int]) -> list:
"""
Get Songs Detail, without the len(song_ids) <= 1000 limit.
"""
songs_dict = []
step = 1000 # the api has a top limit of 1000
i = 0
n = len(song_ids)
while i < n:
tmp_ids = song_ids[i:min(n, i+step)]
songs_dict.extend(track.GetTrackDetail(tmp_ids)['songs'])
i += step
return songs_dict
def sync_fav(nocleanup=False):
"""
Sync favorite songs (first playlist) to cloud disk.
"""
# === get all songs in cloud disk === #
cloud_res = cloud.GetCloudDriveInfo(limit=10000, offset=0)
cCount = cloud_res['count']
cSongs = cloud_res['data']
cSongIds = list(map(lambda _item: _item['songId'], cSongs))
if len(cSongIds) != cCount:
print(f"[ERROR] only got {cSongIds} song ids from {cCount} songs!")
exit(1)
print(f'{cCount} songs in cloud disk.\n')
# songId -> cSong
tmpSongMap = {}
for cs in cSongs:
tmpSongMap[cs['songId']] = cs
res = user.GetUserPlaylists(user_id=0, offset=0, limit=2)
# print(res)
# with open('tmp.json', 'w') as f: f.write(json.dumps(res))
# === get first playlist === #
p = res['playlist'][0]
print("playlist: [%s]" % mask(p['name']))
pInfo = playlist.GetPlaylistInfo(p['id'], total=True, limit=10000)
pList = pInfo['playlist']
# with open('tmp.json', 'w') as f: f.write(json.dumps(pList))
songIds = list(map(lambda item: item['id'], pList['trackIds']))
print(f"{len(songIds)} songs\n")
# songs = pList['tracks'] # tracks has a top limit of 1000.
songs = get_songs(songIds)
if len(songs) != len(songIds):
print(f"[WARN] len(songIds)={len(songIds)}, but len(songs)={len(songs)}. They are expected to be equal!")
print(f"[WARN] Only enumerate first {len(songs)} songs in the playlist.")
# === download, convert, upload to cloud disk, and rectify === #
count = 0
success = 0
fail = 0
fail_list = []
for _, song in enumerate(songs):
songId = song['id']
# check if the song is already uploaded to cloud disk
if songId in cSongIds:
if songId in tmpSongMap:
# print(f"[INFO] deleting {songId} from tmpSongMap ({len(tmpSongMap)})")
del tmpSongMap[songId]
else: # TBD
print(f"[WARN] {songId} does not exist in tmpSongMap! " +
"This can only happen if this song appears more than once in Fav playlist!")
print(f"tmpSongMap: {tmpSongMap}")
# songIds = list(map(lambda _item: _item['id'], songs))
print(f"songIds in Fav: {songIds}")
print(f"In principle this should NOT happen (but actually happened once). Raise the exception!")
raise RuntimeError(f"{songId} appears more than once in Fav playlist??")
continue
# current song is not in cloud disk
count += 1
print(f"\n==================================================")
songName = song['name']
arNames = list(map(lambda item: item['name'], song['ar']))
arNames = list(filter(lambda v: v is not None, arNames))
artist = ','.join(arNames) # arName1,arName2,...
# download
print("[INFO] Downloading [id=%s], [name=%s], [artist=%s]" % (songId, songName, artist))
fileNameWithoutExt = "%s - %s" % (artist, songName)
fileName = download(songId, fileNameWithoutExt)
if fileName is None:
fail += 1
fail_list.append((songId, songName, artist))
continue
print(fileName)
# convert (won't do for now)
if fileName.lower().endswith('.ncm'):
print(f"Found NCM file! [{fileName}]")
exit(1)
# upload
publish_songId = upload(fileName, sleep=0)
# rectify
if publish_songId != songId:
print(f"[INFO] Rectifying song id from [{publish_songId}] to [{songId}]")
result = cloud.SetRectifySongId(publish_songId, songId)
print(result)
if result['code'] != 200:
exit(1)
success += 1
if not nocleanup:
# cleanup download file
print(f"[INFO] (cleanup) Removing downloaded file {fileName}")
os.remove(fileName)
print(f"\n\n==================================================")
print(f"count: {count}, success: {success}, fail: {fail}")
print(f"\n--------- fail list ({len(fail_list)}) ---------")
for cs in fail_list:
print(cs)
if len(tmpSongMap) > 0:
print(f"\n\n--------------------------------------------------")
print(f"[WARN] Found {len(tmpSongMap)} songs that are in cloud disk but missing in Fav playlist!")
for cs in tmpSongMap.values():
print("songId=[%s], songName=[%s], artist=[%s]" % (cs['songId'], cs['songName'], cs['artist']))
# ============================ Main ============================ #
parser = argparse.ArgumentParser(description='Sync favorite songs (first playlist) to cloud disk.')
parser.add_argument("-n", "--nocleanup", action=argparse.BooleanOptionalAction, default=False, help="no cleanup: do not delete downloaded file")
args = parser.parse_args()
nocleanup = args.nocleanup
print(f"nocleanup={nocleanup}")
login()
sync_fav(nocleanup=nocleanup)