Merge pull request #64 from iceBear67/master

Add support for programs
This commit is contained in:
codezjx 2022-07-12 21:17:31 +08:00 committed by GitHub
commit cf5cffe60e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 102 additions and 32 deletions

View File

@ -4,7 +4,7 @@ import requests
import time import time
from ncm.encrypt import encrypted_request 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 song_download_url
from ncm.constants import get_song_url from ncm.constants import get_song_url
from ncm.constants import get_album_url from ncm.constants import get_album_url
@ -52,9 +52,31 @@ class CloudApi(object):
""" """
url = get_song_url(song_id) url = get_song_url(song_id)
result = self.get_request(url) result = self.get_request(url)
return result['songs'][0] 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']
return self.get_song_url(id)
def get_album_songs(self, album_id): def get_album_songs(self, album_id):
""" """
Get all album songs info by album id Get all album songs info by album id

View File

@ -7,22 +7,26 @@ modulus = '00e0b509f6259df8642dbc35662901477df22677ec152b5ff68ace615bb7b725152b3
nonce = '0CoJUm6Qyw8W8jud' nonce = '0CoJUm6Qyw8W8jud'
pub_key = '010001' pub_key = '010001'
headers = { headers = {
'Accept': '*/*', 'Accept': '*/*',
'Host': 'music.163.com', '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', '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', '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)),
''.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=' song_download_url = 'http://music.163.com/weapi/song/enhance/player/url?csrf_token='
program_download_url = 'http://music.163.com/weapi/song/enhance/player/url/v1?csrf_token='
def get_song_url(song_id): def get_song_url(song_id):
return 'http://music.163.com/api/song/detail/?ids=[{}]'.format(song_id) return 'http://music.163.com/api/song/detail/?ids=[{}]'.format(song_id)
def get_program_url(program_id):
return 'http://music.163.com/weapi/dj/program/detail?csrf_token='
def get_album_url(album_id): def get_album_url(album_id):
return 'http://music.163.com/api/album/{}/'.format(album_id) return 'http://music.163.com/api/album/{}/'.format(album_id)

View File

@ -22,13 +22,17 @@ def download_song_by_id(song_id, download_folder, sub_folder=True):
download_song_by_song(song, download_folder, sub_folder) 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 # get song info
api = CloudApi() api = CloudApi()
song_id = song['id'] song_id = song['id']
song_name = format_string(song['name']) song_name = format_string(song['name'])
artist_name = format_string(song['artists'][0]['name']) if program:
album_name = format_string(song['album']['name']) 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'])
# update song file name by config # update song file name by config
song_file_name = '{}.mp3'.format(song_name) song_file_name = '{}.mp3'.format(song_name)
@ -51,7 +55,11 @@ def download_song_by_song(song, download_folder, sub_folder=True):
song_download_folder = download_folder song_download_folder = download_folder
# download song # download song
song_url = api.get_song_url(song_id) if program:
song_url = api.get_program_url(song, level="standard")
else:
song_url = api.get_song_url(song_id)
if song_url is None: if song_url is None:
print('Song <<{}>> is not available due to copyright issue!'.format(song_name)) print('Song <<{}>> is not available due to copyright issue!'.format(song_name))
return return
@ -61,9 +69,16 @@ def download_song_by_song(song, download_folder, sub_folder=True):
return return
# download cover # download cover
cover_url = song['album']['blurPicUrl'] if program:
cover_url = song['coverUrl']
else:
cover_url = song['album']['coverUrl']
if cover_url is None: if cover_url is None:
cover_url = song['album']['picUrl'] if program:
cover_url = song['mainSong']['album']['picUrl']
else:
cover_url = song['album']['picUrl']
cover_file_name = 'cover_{}.jpg'.format(song_id) cover_file_name = 'cover_{}.jpg'.format(song_id)
download_file(cover_url, cover_file_name, song_download_folder) download_file(cover_url, cover_file_name, song_download_folder)
@ -73,14 +88,13 @@ def download_song_by_song(song, download_folder, sub_folder=True):
# add metadata for song # add metadata for song
song_file_path = os.path.join(song_download_folder, song_file_name) song_file_path = os.path.join(song_download_folder, song_file_name)
cover_file_path = os.path.join(song_download_folder, cover_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 # delete cover file
os.remove(cover_file_path) os.remove(cover_file_path)
def download_file(file_url, file_name, folder): def download_file(file_url, file_name, folder):
if not os.path.exists(folder): if not os.path.exists(folder):
os.makedirs(folder) os.makedirs(folder)
file_path = os.path.join(folder, file_name) file_path = os.path.join(folder, file_name)
@ -113,8 +127,8 @@ class ProgressBar(object):
self.end_str = '\r' self.end_str = '\r'
def __get_info(self): def __get_info(self):
return 'Progress: {:6.2f}%, {:8.2f}KB, [{:.30}]'\ return 'Progress: {:6.2f}%, {:8.2f}KB, [{:.30}]' \
.format(self.count/self.total*100, self.total/1024, self.file_name) .format(self.count / self.total * 100, self.total / 1024, self.file_name)
def refresh(self, count): def refresh(self, count):
self.count += 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) 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 # If no ID3 tags in mp3 file
try: try:
audio = MP3(file_path, ID3=ID3) audio = MP3(file_path, ID3=ID3)
@ -52,12 +52,21 @@ def add_metadata_to_song(file_path, cover_path, song):
) )
) )
# add artist name # add artist name
id3.add( if is_program:
TPE1( id3.add(
encoding=3, TPE1(
text=song['artists'][0]['name'] encoding=3,
text=song['dj']['nickname']
)
) )
) else:
id3.add(
TPE1(
encoding=3,
text=song['artists'][0]['name']
)
)
# add song name # add song name
id3.add( id3.add(
TIT2( TIT2(
@ -66,17 +75,27 @@ def add_metadata_to_song(file_path, cover_path, song):
) )
) )
# add album name # add album name
id3.add( if is_program:
TALB( id3.add(
encoding=3, TALB(
text=song['album']['name'] encoding=3,
text=song['dj']['brand']
)
)
else:
id3.add(
TALB(
encoding=3,
text=song['album']['name']
)
) )
)
#add track no #add track no
id3.add( if not is_program:
TRCK( id3.add(
encoding=3, TRCK(
text="%s/%s" %(song['no'],song['album']['size']) encoding=3,
text="%s/%s" %(song['no'],song['album']['size'])
)
) )
) # programs doesn't have a valid album info.
id3.save(v2_version=3) 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) 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): def download_playlist_songs(playlist_id):
songs, playlist_name = api.get_playlist_songs(playlist_id) songs, playlist_name = api.get_playlist_songs(playlist_id)
folder_name = format_string(playlist_name) + ' - playlist' folder_name = format_string(playlist_name) + ' - playlist'
@ -62,6 +69,8 @@ def main():
help='Download an artist hot 50 songs by artist_id') help='Download an artist hot 50 songs by artist_id')
parser.add_argument('-a', metavar='album_id', dest='album_id', parser.add_argument('-a', metavar='album_id', dest='album_id',
help='Download an album all songs by 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', parser.add_argument('-p', metavar='playlist_id', dest='playlist_id',
help='Download a playlist all songs by playlist_id') help='Download a playlist all songs by playlist_id')
args = parser.parse_args() args = parser.parse_args()
@ -76,6 +85,8 @@ def main():
download_album_songs(get_parse_id(args.album_id)) download_album_songs(get_parse_id(args.album_id))
elif args.playlist_id: elif args.playlist_id:
download_playlist_songs(get_parse_id(args.playlist_id)) download_playlist_songs(get_parse_id(args.playlist_id))
elif args.program_id:
download_program(get_parse_id(args.program_id))
if __name__ == '__main__': if __name__ == '__main__':