Add support for program songs
This commit is contained in:
parent
200d6ab755
commit
c7a073cb0c
34
ncm/api.py
34
ncm/api.py
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
14
ncm/start.py
14
ncm/start.py
|
@ -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__':
|
||||
|
|
Loading…
Reference in New Issue