Compare commits

...

12 Commits

Author SHA1 Message Date
李建国 e9bbb3809f feat(gui): 添加图形化界面和cookie设置功能
- 新增Tkinter图形化界面,支持单曲、歌单、专辑等下载选项
- 添加cookie设置功能,用于解决版权问题
- 更新constants.py,增加add_cookies函数
- 修改downloader.py,完善版权问题提示信息
- 重构start.py,实现图形化界面和相关功能
2025-02-28 17:27:34 +08:00
zhangjixiong 184ce2a3e7
Merge pull request #67 from fernvenue/master
Force Pillow version to 9.5.0.
2024-06-07 20:23:30 +08:00
fernvenue 4dfe7f4ebd
Force Pillow version to 9.5.0.
Related to https://github.com/codezjx/netease-cloud-music-dl/issues/66.
2024-02-28 19:01:24 +08:00
codezjx f6b480a9a6
Merge pull request #59 from aisuneko/master
New feature: option which enables the user to specify an user-agent
2022-07-14 20:35:47 +08:00
codezjx 3c2516f4ed Fix merge error and some code optimization 2022-07-12 22:01:07 +08:00
codezjx cf5cffe60e
Merge pull request #64 from iceBear67/master
Add support for programs
2022-07-12 21:17:31 +08:00
iceBear67 f7b2b251be
Improved quality for programs 2022-07-12 13:18:18 +08:00
iceBear67 5e7aea3fab
Fix: Use HTTP instaed of HTTPS to ensure that UnblockNeteaseMusic Works 2022-07-10 16:57:34 +08:00
iceBear67 4e4dd70bca
Fix: Use standard
手残把调试的代码push上去了
2022-07-10 15:57:53 +08:00
iceBear67 109945c6b3
Fix: Use high-quality cover 2022-07-10 15:57:10 +08:00
aisuneko 263370524c
re-add api initializing 2021-07-10 20:43:29 +08:00
aisuneko c172937fcb
implement custom useragent flag 2021-07-03 07:35:42 +08:00
6 changed files with 155 additions and 84 deletions

View File

@ -69,21 +69,13 @@ class CloudApi(object):
def get_program_url(self, program, encode_type="aac", level="standard"):
"""
Get the download url of the program
:param 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']
return self.get_song_url(id)
def get_album_songs(self, album_id):
"""

View File

@ -12,19 +12,19 @@ headers = {
'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(
'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='
program_download_url = 'http://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='
return 'http://music.163.com/weapi/dj/program/detail?csrf_token='
def get_album_url(album_id):
@ -37,3 +37,8 @@ def get_artist_url(artist_id):
def get_playlist_url(playlist_id):
return 'http://music.163.com/api/v6/playlist/detail?id={}'.format(playlist_id)
def add_cookies(key, value):
cookie = headers.get('Cookie')
cookie += '{}={};'.format(key, value)
print(cookie)
headers['Cookie'] = cookie

View File

@ -56,12 +56,12 @@ def download_song_by_song(song, download_folder, sub_folder=True, program=False)
# download song
if program:
song_url = api.get_program_url(song)
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!'.format(song_name))
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:
@ -70,12 +70,15 @@ def download_song_by_song(song, download_folder, sub_folder=True, program=False)
# download cover
if program:
cover_url = song['blurCoverUrl']
cover_url = song['coverUrl']
else:
cover_url = song['album']['coverUrl']
cover_url = song['album']['blurPicUrl']
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)
download_file(cover_url, cover_file_name, song_download_folder)

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, is_program = False):
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)
@ -53,20 +53,15 @@ def add_metadata_to_song(file_path, cover_path, song, is_program = False):
)
# add artist name
if is_program:
id3.add(
TPE1(
encoding=3,
text=song['dj']['nickname']
)
)
art_name = song['dj']['nickname']
else:
id3.add(
TPE1(
encoding=3,
text=song['artists'][0]['name']
)
art_name = song['artists'][0]['name']
id3.add(
TPE1(
encoding=3,
text=art_name
)
)
# add song name
id3.add(
TIT2(
@ -76,25 +71,21 @@ def add_metadata_to_song(file_path, cover_path, song, is_program = False):
)
# add album name
if is_program:
id3.add(
TALB(
encoding=3,
text=song['dj']['brand']
)
)
album_name = song['dj']['brand']
else:
id3.add(
TALB(
encoding=3,
text=song['album']['name']
)
album_name = song['album']['name']
id3.add(
TALB(
encoding=3,
text=album_name
)
#add track no
)
# add track no
if not is_program:
id3.add(
TRCK(
encoding=3,
text="%s/%s" %(song['no'],song['album']['size'])
text="%s/%s" % (song['no'], song['album']['size'])
)
)
# programs doesn't have a valid album info.

View File

@ -1,20 +1,21 @@
# -*- coding: utf-8 -*-
import argparse
import os
import tkinter as tk
from tkinter import messagebox, ttk
from urllib.parse import urlparse, parse_qs
from ncm import config
from ncm.api import CloudApi
from ncm.downloader import get_song_info_by_id
from ncm.constants import add_cookies
from ncm.constants import headers
from ncm.downloader import download_song_by_id
from ncm.downloader import download_song_by_song
from ncm.downloader import format_string
from ncm.downloader import get_song_info_by_id
# load the config first
config.load_config()
api = CloudApi()
def download_hot_songs(artist_id):
songs = api.get_hot_songs(artist_id)
folder_name = format_string(songs[0]['artists'][0]['name']) + ' - hot50'
@ -24,7 +25,6 @@ def download_hot_songs(artist_id):
print('{}: {}'.format(i + 1, song['name']))
download_song_by_song(song, folder_path, False)
def download_album_songs(album_id):
songs = api.get_album_songs(album_id)
folder_name = format_string(songs[0]['album']['name']) + ' - album'
@ -33,14 +33,12 @@ def download_album_songs(album_id):
print('{}: {}'.format(i + 1, song['name']))
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_name = format_string(program['dj']['brand']) + ' - program'
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'
@ -50,44 +48,126 @@ def download_playlist_songs(playlist_id):
print('{}: {}'.format(i + 1, song_detail['name']))
download_song_by_song(song_detail, folder_path, False)
def get_parse_id(song_id):
# Parse the url
if song_id.startswith('http'):
# Not allow fragments, we just need to parse the query string
return parse_qs(urlparse(song_id, allow_fragments=False).query)['id'][0]
return song_id
def handle_download(option_var):
option = option_var.get()
print("Option:", option)
if option == "song_id":
song_id = song_id_entry.get()
if song_id:
download_song_by_id(get_parse_id(song_id), config.DOWNLOAD_DIR)
elif option == "song_ids":
song_ids = song_ids_entry.get().split()
for sid in song_ids:
download_song_by_id(get_parse_id(sid), config.DOWNLOAD_DIR)
elif option == "artist_id":
artist_id = artist_id_entry.get()
if artist_id:
download_hot_songs(get_parse_id(artist_id))
elif option == "album_id":
album_id = album_id_entry.get()
if album_id:
download_album_songs(get_parse_id(album_id))
elif option == "program_id":
program_id = program_id_entry.get()
if program_id:
download_program(get_parse_id(program_id))
elif option == "playlist_id":
playlist_id = playlist_id_entry.get()
if playlist_id:
download_playlist_songs(get_parse_id(playlist_id))
messagebox.showinfo("完成", "已完成")
def set_cookies(cookies_entry):
cookies = cookies_entry.get().split()
for cookie in cookies:
key, value = cookie.replace("\n", "").replace(" ", "").replace("\t", "").split('=')
add_cookies(key, value)
def open_settings_window():
settings_window = tk.Toplevel(root)
settings_window.title("设置")
# 设置窗口大小
settings_width = 340
settings_height = 110
center_window(settings_window, settings_width, settings_height)
tk.Label(settings_window, text="User-Agent:").grid(row=0, column=0, padx=5, pady=5)
user_agent_entry = tk.Entry(settings_window)
user_agent_entry.grid(row=0, column=1, padx=5, pady=5)
save_button = tk.Button(settings_window, text="设置UA", command=lambda: {'User-Agent': user_agent_entry})
save_button.grid(row=0, column=2, padx=5, pady=10)
tk.Label(settings_window, text="Cookies (k=v):").grid(row=1, column=0, padx=5, pady=5)
cookies_entry = tk.Entry(settings_window)
cookies_entry.grid(row=1, column=1, padx=5, pady=5)
save_button = tk.Button(settings_window, text="设置Cookie", command=lambda: set_cookies(cookies_entry))
save_button.grid(row=1, column=2, padx=5, pady=10)
# 设置焦点到设置窗口
settings_window.focus_force()
def center_window(window, width, height):
screen_width = window.winfo_screenwidth()
screen_height = window.winfo_screenheight()
x = (screen_width - width) // 2
y = (screen_height - height) // 2
window.geometry(f'{width}x{height}+{x}+{y}')
def main():
parser = argparse.ArgumentParser(description='Welcome to netease cloud music downloader!')
parser.add_argument('-s', metavar='song_id', dest='song_id',
help='Download a song by song_id')
parser.add_argument('-ss', metavar='song_ids', dest='song_ids', nargs='+',
help='Download a song list, song_id split by space')
parser.add_argument('-hot', metavar='artist_id', dest='artist_id',
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()
if args.song_id:
download_song_by_id(get_parse_id(args.song_id), config.DOWNLOAD_DIR)
elif args.song_ids:
for song_id in args.song_ids:
download_song_by_id(get_parse_id(song_id), config.DOWNLOAD_DIR)
elif args.artist_id:
download_hot_songs(get_parse_id(args.artist_id))
elif args.album_id:
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))
global root, song_id_entry, song_ids_entry, artist_id_entry, album_id_entry, program_id_entry, playlist_id_entry
root = tk.Tk()
root.title("网易云音乐下载器")
# 设置窗口大小
window_width = 260
window_height = 250
center_window(root, window_width, window_height)
# 下载选项
option_var = tk.StringVar(value="song_id")
options = ["Song ID", "Song IDs", "Artist ID", "Album ID", "Program ID", "Playlist ID"]
for idx, option in enumerate(options):
rb = ttk.Radiobutton(root, text=option, variable=option_var, value=option.lower().replace(" ", "_"))
rb.grid(row=idx+1, column=0, sticky="w", padx=5, pady=5)
# 输入框
song_id_entry = tk.Entry(root)
song_id_entry.grid(row=1, column=1, padx=5, pady=5)
song_ids_entry = tk.Entry(root)
song_ids_entry.grid(row=2, column=1, padx=5, pady=5)
artist_id_entry = tk.Entry(root)
artist_id_entry.grid(row=3, column=1, padx=5, pady=5)
album_id_entry = tk.Entry(root)
album_id_entry.grid(row=4, column=1, padx=5, pady=5)
program_id_entry = tk.Entry(root)
program_id_entry.grid(row=5, column=1, padx=5, pady=5)
playlist_id_entry = tk.Entry(root)
playlist_id_entry.grid(row=6, column=1, padx=5, pady=5)
# 设置页面按钮
settings_button = tk.Button(root, text="设置", command=open_settings_window)
settings_button.grid(row=7, column=0, columnspan=1, pady=10)
# 下载按钮
download_button = tk.Button(root, text="下载", command=lambda: handle_download(option_var))
download_button.grid(row=7, column=1, columnspan=2, pady=10)
root.mainloop()
if __name__ == '__main__':
main()

View File

@ -1,4 +1,4 @@
requests>=2.17.3
pycryptodomex
mutagen>=1.38.0
Pillow>=4.3.0
Pillow==9.5.0