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 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 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()
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)