150 lines
4.6 KiB
Python
150 lines
4.6 KiB
Python
# -*- coding: utf-8 -*-
|
|
|
|
import os
|
|
import re
|
|
import requests
|
|
|
|
from ncm import config
|
|
from ncm.api import CloudApi
|
|
from ncm.file_util import add_metadata_to_song
|
|
from ncm.file_util import resize_img
|
|
|
|
|
|
def get_song_info_by_id(song_id):
|
|
api = CloudApi()
|
|
song = api.get_song(song_id)
|
|
return song
|
|
|
|
|
|
def download_song_by_id(song_id, download_folder, sub_folder=True):
|
|
# get song info
|
|
song = get_song_info_by_id(song_id)
|
|
download_song_by_song(song, download_folder, sub_folder)
|
|
|
|
|
|
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'])
|
|
|
|
# update song file name by config
|
|
song_file_name = '{}.mp3'.format(song_name)
|
|
switcher_song = {
|
|
1: song_file_name,
|
|
2: '{} - {}.mp3'.format(artist_name, song_name),
|
|
3: '{} - {}.mp3'.format(song_name, artist_name)
|
|
}
|
|
song_file_name = switcher_song.get(config.SONG_NAME_TYPE, song_file_name)
|
|
|
|
# update song folder name by config, if support sub folder
|
|
if sub_folder:
|
|
switcher_folder = {
|
|
1: download_folder,
|
|
2: os.path.join(download_folder, artist_name),
|
|
3: os.path.join(download_folder, artist_name, album_name),
|
|
}
|
|
song_download_folder = switcher_folder.get(config.SONG_FOLDER_TYPE, download_folder)
|
|
else:
|
|
song_download_folder = download_folder
|
|
|
|
# download song
|
|
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:
|
|
print('Song <<{}>> is not available due to copyright issue! please set cookie.'.format(song_name))
|
|
return
|
|
is_already_download = download_file(song_url, song_file_name, song_download_folder)
|
|
if is_already_download:
|
|
print('Mp3 file already download:', song_file_name)
|
|
return
|
|
|
|
# download cover
|
|
if program:
|
|
cover_url = song['coverUrl']
|
|
else:
|
|
cover_url = song['album']['blurPicUrl']
|
|
|
|
if cover_url is None:
|
|
if program:
|
|
cover_url = song['mainSong']['album']['picUrl']
|
|
else:
|
|
cover_url = song['album']['picUrl']
|
|
cover_file_name = 'cover_{}.jpg'.format(song_id)
|
|
download_file(cover_url, cover_file_name, song_download_folder)
|
|
|
|
# resize cover
|
|
resize_img(os.path.join(song_download_folder, cover_file_name))
|
|
|
|
# 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, 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)
|
|
|
|
response = requests.get(file_url, stream=True)
|
|
length = int(response.headers.get('Content-Length'))
|
|
|
|
# TODO need to improve whether the file exists
|
|
if os.path.exists(file_path) and os.path.getsize(file_path) > length:
|
|
return True
|
|
|
|
progress = ProgressBar(file_name, length)
|
|
|
|
with open(file_path, 'wb') as file:
|
|
for buffer in response.iter_content(chunk_size=1024):
|
|
if buffer:
|
|
file.write(buffer)
|
|
progress.refresh(len(buffer))
|
|
return False
|
|
|
|
|
|
class ProgressBar(object):
|
|
|
|
def __init__(self, file_name, total):
|
|
super().__init__()
|
|
self.file_name = file_name
|
|
self.count = 0
|
|
self.prev_count = 0
|
|
self.total = total
|
|
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)
|
|
|
|
def refresh(self, count):
|
|
self.count += count
|
|
# Update progress if down size > 10k
|
|
if (self.count - self.prev_count) > 10240:
|
|
self.prev_count = self.count
|
|
print(self.__get_info(), end=self.end_str)
|
|
# Finish downloading
|
|
if self.count >= self.total:
|
|
self.end_str = '\n'
|
|
print(self.__get_info(), end=self.end_str)
|
|
|
|
|
|
def format_string(string):
|
|
"""
|
|
Replace illegal character with ' '
|
|
"""
|
|
return re.sub(r'[\\/:*?"<>|\t]', ' ', string)
|