def main(): fail_list = [] if os.path.exists(LOVE_PLAYLIST_FILE): with open(LOVE_PLAYLIST_FILE, encoding='utf-8') as lpf: love_playlist = json.load(lpf) else: api = NetEase() user = api.login(USERNAME, md5(PASSWORD).hexdigest()) print(user) user_id = user['account']['id'] prase = Parse() ps = prase.playlists(api.user_playlist(user_id)) love_playlist_id = [m for m in ps if m['playlist_name'] == f"{m['creator_name']}喜欢的音乐"][ 0]['playlist_id'] print(love_playlist_id) love_playlist = api.playlist_detail(love_playlist_id) with open(LOVE_PLAYLIST_FILE, mode='w', encoding='utf-8') as lpf: json.dump(love_playlist, lpf) for i, d in enumerate(love_playlist): try: search_and_download_music(d['name'], d['ar'][0]['name'], d['al']['name']) print(f'{i+1}/{len(love_playlist)} {d["name"]} 下载完成') except Exception as e: fail_list.append(d["name"]) print(f'{i+1}/{len(love_playlist)} {d["name"]} 下载失败!!!!:{e}') print('-' * 20, '下载失败的歌曲', '-' * 20) print(fail_list)
class fakePipeline(object): def __init__(self): self.mysession = NetEase() user = "******" pw = "19900119" pw_ = hashlib.md5(pw.encode('utf-8')).hexdigest() self.mysession.login(user, pw_) def fake(self, sid): url = 'http://music.163.com/weapi/feedback/weblog?csrf_token=' text = { 'data': { 'logs': { 'action': "play", 'json': { "type": "song", "wifi": 0, "download": 0, "id": sid, "time": 600, "end": "ui", "source": "list", "sourceId": "576900073" } } } } data = encrypted_request(text) self.mysession.session.post(url=url, data=data) def process_item(self, item, spider): if item.__class__ == Song: self.fake(item["sid"]) return item
def test_api(self): api = NetEase() ids = [347230, 496619464, 405998841, 28012031] print(api.songs_url(ids)) print(api.songs_detail(ids)) print(Parse.song_url(api.songs_detail(ids)[0])) # user = api.login('*****@*****.**', md5(b'').hexdigest()) # user_id = user['account']['id'] # print(user) # api.logout() # print(api.user_playlist(3765346)) # print(api.song_comments(347230)) # print(api.search('海阔天空')['result']['songs']) # print(api.top_songlist()[0]) # print(Parse.song_url(api.top_songlist()[0])) # print(api.djchannels()) # print(api.search('测', 1000)) # print(api.album(38721188)) # print(api.djchannels()[:5]) # print(api.channel_detail([348289113])) # print(api.djprograms(243, True, limit=5)) # print(api.request('POST', '/weapi/djradio/hot/v1', params=dict( # category='旅途|城市', # limit=5, # offset=0 # ))) # print(api.recommend_resource()[0]) print(api.songs_url([561307346]))
def start_download(self): check = self.download_lock.acquire(False) if not check: return False while True: if self.stop: break if not self.enable: break self.check_lock.acquire() if len(self.downloading) <= 0: self.check_lock.release() break data = self.downloading.pop() self.check_lock.release() song_id = data[0] song_name = data[1] artist = data[2] url = data[3] onExit = data[4] output_path = Constant.download_dir output_file = str(artist) + ' - ' + str(song_name) + '.mp3' full_path = os.path.join(output_path, output_file) new_url = NetEase().songs_detail_new_api([song_id])[0]['url'] log.info('Old:{}. New:{}'.format(url, new_url)) try: para = ['aria2c', '--auto-file-renaming=false', '--allow-overwrite=true', '-d', output_path, '-o', output_file, new_url] para[1:1] = self.aria2c_parameters self.aria2c = subprocess.Popen(para, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.aria2c.wait() except OSError as e: log.warning( '{}.\tAria2c is unavailable, fall back to wget'.format(e)) self._mkdir(output_path) para = ['wget', '-O', full_path, new_url] self.wget = subprocess.Popen(para, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE) self.wget.wait() if self._is_cache_successful(): log.debug(str(song_id) + ' Cache OK') onExit(song_id, full_path) self.download_lock.release()
def __init__(self): self.screen = curses.initscr() self.screen.timeout(500) # the screen refresh every 500ms # charactor break buffer curses.cbreak() self.screen.keypad(1) self.netease = NetEase() curses.start_color() curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(2, curses.COLOR_CYAN, curses.COLOR_BLACK) curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLACK) # term resize handling size = terminalsize.get_terminal_size() self.x = max(size[0], 10) self.y = max(size[1], 25) self.startcol = int(float(self.x)/5) self.indented_startcol = max(self.startcol - 3, 0) self.update_space()
def test_api(self): ne = NetEase() self.assertIsInstance( ne.songs_detail_new_api([27902910])[0]['url'], str) self.assertIsNone(ne.songs_detail([405079776])[0]['mp3Url']) # old api
# -*- coding: utf-8 -*- from flask import Flask, render_template, request, abort, redirect, Response, url_for import json import requests import base64 import re from flask import stream_with_context from user_agents import parse from werkzeug.contrib.cache import SimpleCache from NEMbox.api import NetEase, geturl_new_api app = Flask(__name__) ne = NetEase() @app.route("/apcloud/") def hello(): return '''<pre>网易云音乐 APlayer 项目地址:https://github.com/vhyme/APCloud 演示效果可以看我的博客(电脑打开):https://heya.myseu.cn/ Usage: /歌单ID 显示指定歌单播放器 参数: autoplay 是否自动播放(1=true/0=false),默认是 showlrc 是否显示歌词(1=true/0=false),默认是 /歌曲ID.mp3 重定向到该歌曲直链,若有版权问题则返回空音频 /歌曲ID.lrc 下载该歌曲歌词 本播放器可以自适应窗口或iframe的高度,嵌入到iframe中不会出现
def __init__(self): self.mysession = NetEase() user = "******" pw = "19900119" pw_ = hashlib.md5(pw.encode('utf-8')).hexdigest() self.mysession.login(user, pw_)
class Ui: def __init__(self): self.screen = curses.initscr() self.screen.timeout(500) # the screen refresh every 500ms # charactor break buffer curses.cbreak() self.screen.keypad(1) self.netease = NetEase() curses.start_color() curses.init_pair(1, curses.COLOR_GREEN, curses.COLOR_BLACK) curses.init_pair(2, curses.COLOR_CYAN, curses.COLOR_BLACK) curses.init_pair(3, curses.COLOR_RED, curses.COLOR_BLACK) curses.init_pair(4, curses.COLOR_YELLOW, curses.COLOR_BLACK) # term resize handling size = terminalsize.get_terminal_size() self.x = max(size[0], 10) self.y = max(size[1], 25) self.startcol = int(float(self.x)/5) self.indented_startcol = max(self.startcol - 3, 0) self.update_space() def build_playinfo(self, song_name, artist, album_name, quality, start, pause=False): curses.noecho() # refresh top 2 line self.screen.move(1, 1) self.screen.clrtoeol() self.screen.move(2, 1) self.screen.clrtoeol() if pause: self.screen.addstr(1, self.indented_startcol, '_ _ z Z Z ' + quality, curses.color_pair(3)) else: self.screen.addstr(1, self.indented_startcol, '♫ ♪ ♫ ♪ ' + quality, curses.color_pair(3)) self.screen.addstr(1, min(self.indented_startcol + 18, self.x-1), song_name + self.space + artist + ' < ' + album_name + ' >', curses.color_pair(4)) # The following script doesn't work. It is intended to scroll the playinfo # Scrollstring works by determining how long since it is created, but # playinfo is created everytime the screen refreshes (every 500ms), unlike # the menu. Is there a workaround? # name = song_name + self.space + artist + ' < ' + album_name + ' >' # decides whether to scoll # if truelen(name) <= self.x - self.indented_startcol - 18: # self.screen.addstr(1, min(self.indented_startcol + 18, self.x-1), # name, # curses.color_pair(4)) # else: # name = scrollstring(name + ' ', start) # self.screen.addstr(1, min(self.indented_startcol + 18, self.x-1), # str(name), # curses.color_pair(4)) self.screen.refresh() def build_loading(self): self.screen.addstr(6, self.startcol, '享受高品质音乐,loading...', curses.color_pair(1)) self.screen.refresh() # start is the timestamp of this function being called def build_menu(self, datatype, title, datalist, offset, index, step, start): # keep playing info in line 1 curses.noecho() self.screen.move(4, 1) self.screen.clrtobot() self.screen.addstr(4, self.startcol, title, curses.color_pair(1)) if len(datalist) == 0: self.screen.addstr(8, self.startcol, '这里什么都没有 -,-') else: if datatype == 'main': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]) elif datatype == 'songs': iter_range = min(len(datalist), offset + step) for i in range(offset, iter_range): # this item is focus if i == index: self.screen.addstr(i - offset + 8, 0, ' ' * self.startcol) lead = '-> ' + str(i) + '. ' self.screen.addstr(i - offset + 8, self.indented_startcol, lead, curses.color_pair(2)) name = str(datalist[i]['song_name'] + self.space + datalist[i][ 'artist'] + ' < ' + datalist[i]['album_name'] + ' >') # the length decides whether to scoll if truelen(name) < self.x - self.startcol - 1: self.screen.addstr(i - offset + 8, self.indented_startcol + len(lead), name, curses.color_pair(2)) else: name = scrollstring(name + ' ', start) self.screen.addstr(i - offset + 8, self.indented_startcol + len(lead), str(name), curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, 0, ' ' * self.startcol) self.screen.addstr(i - offset + 8, self.startcol, str(str(i) + '. ' + datalist[i]['song_name'] + self.space + datalist[i][ 'artist'] + ' < ' + datalist[i]['album_name'] + ' >')[:int(self.x*2)]) self.screen.addstr(iter_range - offset + 8, 0, ' ' * self.x) elif datatype == 'artists': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i]['artists_name'] + self.space + str( datalist[i]['alias']), curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]['artists_name'] + self.space + datalist[i][ 'alias']) elif datatype == 'albums': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i]['albums_name'] + self.space + datalist[i][ 'artists_name'], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]['albums_name'] + self.space + datalist[i][ 'artists_name']) elif datatype == 'playlists': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i]['title'], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]['title']) elif datatype == 'top_playlists': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i]['playlists_name'] + self.space + datalist[i]['creator_name'], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]['playlists_name'] + self.space + datalist[i][ 'creator_name']) elif datatype == 'toplists': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]) elif datatype == 'playlist_classes' or datatype == 'playlist_class_detail': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]) elif datatype == 'djchannels': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. ' + datalist[i]['song_name'], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. ' + datalist[i]['song_name']) elif datatype == 'search': self.screen.move(4, 1) self.screen.clrtobot() self.screen.timeout(-1) self.screen.addstr(8, self.startcol, '选择搜索类型:', curses.color_pair(1)) for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 10, self.indented_startcol, '-> ' + str(i) + '.' + datalist[i - 1], curses.color_pair(2)) else: self.screen.addstr(i - offset + 10, self.startcol, str(i) + '.' + datalist[i - 1]) self.screen.timeout(500) elif datatype == 'help': for i in range(offset, min(len(datalist), offset + step)): if i == index: self.screen.addstr(i - offset + 8, self.indented_startcol, '-> ' + str(i) + '. \'' + (datalist[i][0].upper() + '\'').ljust(11) + datalist[i][ 1] + ' ' + datalist[i][2], curses.color_pair(2)) else: self.screen.addstr(i - offset + 8, self.startcol, str(i) + '. \'' + (datalist[i][0].upper() + '\'').ljust(11) + datalist[i][1] + ' ' + datalist[i][2]) self.screen.addstr(20, 6, 'NetEase-MusicBox 基于Python,所有版权音乐来源于网易,本地不做任何保存') self.screen.addstr(21, 10, '按 [G] 到 Github 了解更多信息,帮助改进,或者Star表示支持~~') self.screen.addstr(22, self.startcol, 'Build with love to music by omi') self.screen.refresh() def build_search(self, stype): self.screen.timeout(-1) netease = self.netease if stype == 'songs': song_name = self.get_param('搜索歌曲:') try: data = netease.search(song_name, stype=1) song_ids = [] if 'songs' in data['result']: if 'mp3Url' in data['result']['songs']: songs = data['result']['songs'] # if search song result do not has mp3Url # send ids to get mp3Url else: for i in range(0, len(data['result']['songs'])): song_ids.append(data['result']['songs'][i]['id']) songs = netease.songs_detail(song_ids) return netease.dig_info(songs, 'songs') except: return [] elif stype == 'artists': artist_name = self.get_param('搜索艺术家:') try: data = netease.search(artist_name, stype=100) if 'artists' in data['result']: artists = data['result']['artists'] return netease.dig_info(artists, 'artists') except: return [] elif stype == 'albums': artist_name = self.get_param('搜索专辑:') try: data = netease.search(artist_name, stype=10) if 'albums' in data['result']: albums = data['result']['albums'] return netease.dig_info(albums, 'albums') except: return [] elif stype == 'search_playlist': artist_name = self.get_param('搜索网易精选集:') try: data = netease.search(artist_name, stype=1000) if 'playlists' in data['result']: playlists = data['result']['playlists'] return netease.dig_info(playlists, 'top_playlists') except: return [] return [] def build_login(self): self.build_login_bar() local_account = self.get_account().decode('ascii') local_password = hashlib.md5(self.get_password()).hexdigest() login_info = self.netease.login(local_account, local_password) account = [local_account,local_password] if login_info['code'] != 200: x = self.build_login_error() if x == ord('1'): return self.build_login() else: return -1 else: return [login_info, account] def build_login_bar(self): curses.noecho() self.screen.move(4, 1) self.screen.clrtobot() self.screen.addstr(5, self.startcol, '请输入登录信息(支持手机登陆)',curses.color_pair(1)) self.screen.addstr(8, self.startcol, "账号:", curses.color_pair(1)) self.screen.addstr(9, self.startcol, "密码:", curses.color_pair(1)) self.screen.move(8,24) self.screen.refresh() def build_login_error(self): self.screen.move(4, 1) self.screen.timeout(-1) # disable the screen timeout self.screen.clrtobot() self.screen.addstr(8, self.startcol, '艾玛,登录信息好像不对呢 (O_O)#', curses.color_pair(1)) self.screen.addstr(10, self.startcol, '[1] 再试一次') self.screen.addstr(11, self.startcol, '[2] 稍后再试') self.screen.addstr(14, self.startcol, '请键入对应数字:', curses.color_pair(2)) self.screen.refresh() x = self.screen.getch() self.screen.timeout(500) # restore the screen timeout return x def get_account(self): self.screen.timeout(-1) # disable the screen timeout curses.echo() account = self.screen.getstr(8, self.startcol+6,60) self.screen.timeout(500) # restore the screen timeout return account def get_password(self): self.screen.timeout(-1) # disable the screen timeout curses.noecho() password = self.screen.getstr(9, self.startcol+6,60) self.screen.timeout(500) # restore the screen timeout return password def get_param(self, prompt_string): # keep playing info in line 1 curses.echo() self.screen.move(4, 1) self.screen.clrtobot() self.screen.addstr(5, self.startcol, prompt_string, curses.color_pair(1)) self.screen.refresh() info = self.screen.getstr(10, self.startcol, 60) if info.strip() is b'': return self.get_param(prompt_string) else: return info def update_size(self): # get terminal size size = terminalsize.get_terminal_size() self.x = max(size[0], 10) self.y = max(size[1], 25) # update intendations curses.resizeterm(self.y, self.x) self.startcol = int(float(self.x)/5) self.indented_startcol = max(self.startcol - 3, 0) self.update_space() self.screen.clear() self.screen.refresh() def update_space(self): if self.x > 140: self.space = " - " elif self.x > 80: self.space = " - " else: self.space = " - " self.screen.refresh()
def __init__(self): self.api = NetEase() self.storage = Storage() self.storage.load() self.collection = self.storage.database['collections'] self.autologin()
class NetEaseService(object): def __init__(self): self.api = NetEase() self.storage = Storage() self.storage.load() self.collection = self.storage.database['collections'] self.autologin() @property def user(self): return self.storage.database['user'] @property def account(self): return self.user['username'] @property def md5pass(self): return self.user['password'] @property def userid(self): return self.user['user_id'] @property def username(self): return self.user['nickname'] def autologin(self, _account = None, _md5pass = None): if _account is not None and _md5pass is not None: account, md5pass = _account, _md5pass elif self.account and self.md5pass: account, md5pass = self.account, self.md5pass else: return False resp = self.api.login(account, md5pass) print(resp) if resp['code'] == 200: userid = resp['account']['id'] nickname = resp['profile']['nickname'] self.storage.login(account, md5pass, userid, nickname) self.storage.save() return True else: self.storage.logout() return False def login_status(self): result = { "logged_in": True, "username": self.username, "id": self.userid } if not self.account or not self.md5pass: result["logged_in"] = False return result def request_api(self, func, *args): result = func(*args) if result: return result if not self.autologin(): raise Exception("You need to log in") return False return result def get_my_playlists(self): playlists = self.request_api(self.api.user_playlist, self.userid) return self.api.dig_info(playlists, "playlists") def get_playlist(self, playlist_id): songs = self.api.playlist_detail(playlist_id) return self.api.dig_info(songs, "songs") def get_song(self): pass def get_song_lyrics(self, song_id): return self.api.song_lyric(song_id)
def process(local_song_path, save_path="/Users/zhangzhenhu/Music/mymusic"): global g_log_file net = NetEase() local_song = taglib.File(local_song_path) print("") print("========本地歌曲=======") # pprint.pprint(local_song.tags) if 'TITLE' not in local_song.tags or 'ARTIST' not in local_song.tags: return print(local_song.tags['TITLE'], local_song.tags['ARTIST'], local_song.tags.get('ALBUM', "")) title = local_song.tags['TITLE'][0] song_result = net.search(keywords=title, stype=1) if song_result is None or 'songs' not in song_result: print("net_song_not_found", local_song_path, file=g_log_file) return net_song = get_match_song(local_song, song_result['songs']) # pprint.pprint(net_song) if net_song is None: print("net_song_not_match", local_song_path, file=g_log_file) return print("----------网易歌曲--------") print(net_song['id'], net_song['name'], net_song['album']['name'], ','.join([x['name'] for x in net_song['artists']])) g_song_db[net_song['id']] = net_song # 歌手id,只选取第一个 artist_id = net_song['artists'][0]['id'] artist_name = net_song['artists'][0]['name'] # 获取歌手信息 artist_json = net.get_artist_desc(artist_id) # print(artist_desc) if artist_json and artist_json['code'] == 200: artist_info = artist_json['artist'] g_artist_db[artist_id] = artist_info artist_img = artist_info['img1v1Url'] artist_pic = artist_info['picUrl'] else: print("artist_not_found", local_song_path, file=g_log_file) return # 歌曲所属专辑 album_info = net_song['album'] # 包括字段 id name size artist album_name = album_info['name'] # print(album) # 获取歌曲信息 # print("========歌曲信息=======") song_info = net.songs_detail([net_song['id']])[0] album_pic = song_info['al']['picUrl'] # 专辑的图片 # print(song_lyric) # 获取专辑信息 album_tracks = net.album(album_info['id']) g_album_db[album_info['id']] = album_tracks # net_tags = { "ALBUM": album_info['name'], } if artist_info['briefDesc']: net_tags['comment'] = artist_info['briefDesc'] # 专辑发布时间 if 'publishTime' in album_info: publish_time = datetime.fromtimestamp(album_info['publishTime'] // 1000) net_tags['date'] = publish_time.strftime("%Y-%m-%d") net_tags['year'] = publish_time.strftime("%Y") album_year = publish_time.strftime("%Y") else: album_year = None # 专辑歌曲数量,以及本歌曲在第几 if len(album_tracks): net_tags['TRACKTOTAL'] = str(len(album_tracks)) track_number = get_track_number_from_album(net_song['id'], album_tracks) if track_number is not None: net_tags['TRACKNUMBER'] = str(track_number) # 获取歌词 song_lyric = net.song_lyric(net_song['id']) net_tags['Lyrics'] = '\n'.join(song_lyric), net_tags['wangyi'] = [ json.dumps({ 'song_id': net_song['id'], 'artist_id': artist_id, 'ablum_id': album_info['id'], }) ] new_artist_path = os.path.join(save_path, artist_name) if album_name is not None: new_album_path = os.path.join(new_artist_path, album_name) else: new_album_path = new_artist_path if album_year is not None: new_album_path = new_album_path # if not os.path.exists(new_album_path): os.makedirs(new_album_path, exist_ok=True) new_song_path = os.path.join(new_album_path, os.path.split(local_song_path)[-1]) # print(new_song_path) # 保存歌词 save_lrc(new_song_path, song_lyric) # 复制音频文件 if not os.path.exists(new_song_path): # copy_file(local_song_path, new_song_path) shutil.move(local_song_path, new_song_path) download_img(artist_pic, new_artist_path, 'folder') download_img(artist_pic, new_artist_path, 'fanart') download_img(album_pic, new_album_path, 'cover') save_tag(new_song_path, net_tags) # 生成nfo文件 album_nfo = { 'title': album_info['name'], 'artistdesc': artist_info['briefDesc'], 'year': album_year, 'tracks': album_tracks } save_album_nfo(new_album_path, album_nfo) # pprint.pprint(net.search(keywords="那英", stype=100)) # pprint.pprint(album_desc[0]) print("")