Add support for program songs

This commit is contained in:
iceBear67 2022-07-10 15:47:44 +08:00
parent 200d6ab755
commit c7a073cb0c
No known key found for this signature in database
GPG Key ID: DBFD4E7100B6EA59
5 changed files with 109 additions and 31 deletions

View File

@ -4,7 +4,7 @@ import requests
import time
from ncm.encrypt import encrypted_request
from ncm.constants import headers
from ncm.constants import headers, get_program_url, program_download_url
from ncm.constants import song_download_url
from ncm.constants import get_song_url
from ncm.constants import get_album_url
@ -52,9 +52,39 @@ class CloudApi(object):
"""
url = get_song_url(song_id)
result = self.get_request(url)
return result['songs'][0]
def get_program(self, program_id):
"""
Get program info by its id
:param bit_rate:
:param program_id:
:return:
"""
url = get_program_url(program_id)
csrf = ''
result = self.post_request(url, {'id': program_id, 'csrf_token': csrf})
return result['program']
def get_program_url(self, program, encode_type="aac", level="standard"):
"""
Get the download url of the program
:param program:
:param encode_type:
:param level:
:return:
"""
id = program['mainSong']['id']
url = program_download_url
payload = {
'ids': [id],
'csrf_token': '',
'encodeType': encode_type,
'level': level
}
result = self.post_request(url, payload)
return result['data'][0]['url']
def get_album_songs(self, album_id):
"""
Get all album songs info by album id

View File

@ -7,22 +7,26 @@ modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3
nonce = '0CoJUm6Qyw8W8jud'
pub_key = '010001'
headers = {
'Accept': '*/*',
'Host': 'music.163.com',
'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.114 Safari/537.36',
'Referer': 'http://music.163.com',
'Cookie': 'appver=2.0.2; _ntes_nuid={}; NMTID={}'.format(''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32)),
'Cookie': 'appver=2.0.2; _ntes_nuid={}; NMTID={}'.format(
''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32)),
''.join(random.choice(string.ascii_letters + string.digits) for _ in range(32)))
}
song_download_url = 'http://music.163.com/weapi/song/enhance/player/url?csrf_token='
program_download_url = 'https://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='
def get_song_url(song_id):
return 'http://music.163.com/api/song/detail/?ids=[{}]'.format(song_id)
def get_program_url(program_id):
return 'https://music.163.com/weapi/dj/program/detail?csrf_token='
def get_album_url(album_id):
return 'http://music.163.com/api/album/{}/'.format(album_id)

View File

@ -22,11 +22,15 @@ def download_song_by_id(song_id, download_folder, sub_folder=True):
download_song_by_song(song, download_folder, sub_folder)
def download_song_by_song(song, download_folder, sub_folder=True):
def download_song_by_song(song, download_folder, sub_folder=True, program=False):
# get song info
api = CloudApi()
song_id = song['id']
song_name = format_string(song['name'])
if program:
artist_name = format_string(song['dj']['nickname'])
album_name = format_string(song['dj']['brand'])
else:
artist_name = format_string(song['artists'][0]['name'])
album_name = format_string(song['album']['name'])
@ -51,7 +55,11 @@ def download_song_by_song(song, download_folder, sub_folder=True):
song_download_folder = download_folder
# download song
if program:
song_url = api.get_program_url(song)
else:
song_url = api.get_song_url(song_id)
if song_url is None:
print('Song <<{}>> is not available due to copyright issue!'.format(song_name))
return
@ -61,7 +69,11 @@ def download_song_by_song(song, download_folder, sub_folder=True):
return
# download cover
cover_url = song['album']['blurPicUrl']
if program:
cover_url = song['blurCoverUrl']
else:
cover_url = song['album']['coverUrl']
if cover_url is None:
cover_url = song['album']['picUrl']
cover_file_name = 'cover_{}.jpg'.format(song_id)
@ -73,14 +85,13 @@ def download_song_by_song(song, download_folder, sub_folder=True):
# add metadata for song
song_file_path = os.path.join(song_download_folder, song_file_name)
cover_file_path = os.path.join(song_download_folder, cover_file_name)
add_metadata_to_song(song_file_path, cover_file_path, song)
add_metadata_to_song(song_file_path, cover_file_path, song, program)
# delete cover file
os.remove(cover_file_path)
def download_file(file_url, file_name, folder):
if not os.path.exists(folder):
os.makedirs(folder)
file_path = os.path.join(folder, file_name)
@ -113,8 +124,8 @@ class ProgressBar(object):
self.end_str = '\r'
def __get_info(self):
return 'Progress: {:6.2f}%, {:8.2f}KB, [{:.30}]'\
.format(self.count/self.total*100, self.total/1024, self.file_name)
return 'Progress: {:6.2f}%, {:8.2f}KB, [{:.30}]' \
.format(self.count / self.total * 100, self.total / 1024, self.file_name)
def refresh(self, count):
self.count += count

View File

@ -18,7 +18,7 @@ def resize_img(file_path, max_size=(640, 640), quality=90):
img.save(file_path, quality=quality)
def add_metadata_to_song(file_path, cover_path, song):
def add_metadata_to_song(file_path, cover_path, song, is_program = False):
# If no ID3 tags in mp3 file
try:
audio = MP3(file_path, ID3=ID3)
@ -52,12 +52,21 @@ def add_metadata_to_song(file_path, cover_path, song):
)
)
# add artist name
if is_program:
id3.add(
TPE1(
encoding=3,
text=song['dj']['nickname']
)
)
else:
id3.add(
TPE1(
encoding=3,
text=song['artists'][0]['name']
)
)
# add song name
id3.add(
TIT2(
@ -66,6 +75,14 @@ def add_metadata_to_song(file_path, cover_path, song):
)
)
# add album name
if is_program:
id3.add(
TALB(
encoding=3,
text=song['dj']['brand']
)
)
else:
id3.add(
TALB(
encoding=3,
@ -73,10 +90,12 @@ def add_metadata_to_song(file_path, cover_path, song):
)
)
#add track no
if not is_program:
id3.add(
TRCK(
encoding=3,
text="%s/%s" %(song['no'],song['album']['size'])
)
)
# programs doesn't have a valid album info.
id3.save(v2_version=3)

View File

@ -34,6 +34,13 @@ def download_album_songs(album_id):
download_song_by_song(song, folder_path, False)
def download_program(program_id):
program = api.get_program(program_id)
folder_name = format_string(program['dj']['brand']) + ' - album'
folder_path = os.path.join(config.DOWNLOAD_DIR, folder_name)
download_song_by_song(program, folder_path, False, True)
def download_playlist_songs(playlist_id):
songs, playlist_name = api.get_playlist_songs(playlist_id)
folder_name = format_string(playlist_name) + ' - playlist'
@ -62,6 +69,8 @@ def main():
help='Download an artist hot 50 songs by artist_id')
parser.add_argument('-a', metavar='album_id', dest='album_id',
help='Download an album all songs by album_id')
parser.add_argument('-dj', metavar='program_id', dest='program_id',
help='Download a program by program_id')
parser.add_argument('-p', metavar='playlist_id', dest='playlist_id',
help='Download a playlist all songs by playlist_id')
args = parser.parse_args()
@ -76,6 +85,11 @@ def main():
download_album_songs(get_parse_id(args.album_id))
elif args.playlist_id:
download_playlist_songs(get_parse_id(args.playlist_id))
elif args.program_id:
download_program(get_parse_id(args.program_id))
#api.get_program_url(2507672491)
# api.get_program_url(350746079)
# api.get_song(1927252694)
if __name__ == '__main__':