def netease_download(music): ''' 从网易云音乐下载 ''' eparams = { 'method': 'POST', 'url': 'http://music.163.com/api/song/enhance/player/url', 'params': { 'ids': [music['id']], 'br': 320000, } } data = {'eparams': encode_netease_data(eparams)} s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) s.headers.update({ 'referer': 'http://music.163.com/', }) if glovar.get_option('proxies'): s.proxies.update(glovar.get_option('proxies')) r = s.post('http://music.163.com/api/linux/forward', data=data) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() if j['code'] != 200: raise ResponseError(j) music['url'] = j['data'][0]['url'] music['rate'] = int(j['data'][0]['br'] / 1000) music['size'] = round(j['data'][0]['size'] / 1048576, 2) music['name'] = '%s - %s.mp3' % (music['singer'], music['title']) music_download(music)
def main(): music_list = [] if not glovar.get_option('keyword'): # 如果未设置关键词 keyword = input('请输入要搜索的歌曲,名称和歌手一起输入可以提高匹配(如 空帆船 朴树):\n > ') glovar.set_option('keyword', keyword) for source in glovar.get_option('source').split(): try: echo.notice(source=source) music_list += addons.get(source).search( glovar.get_option('keyword')) except Exception as e: logger.error('Get %s music list failed.' % source.upper()) logger.error(e) if glovar.get_option('merge'): # 对搜索结果排序和去重 music_list = music_list_merge(music_list) echo.menu(music_list) choices = input('请输入要下载的歌曲序号,多个序号用空格隔开:') downloadByIndexList(choices.split(), music_list) # 下载完后继续搜索 keyword = input('请输入要搜索的歌曲,或Ctrl+C退出:\n > ') glovar.set_option('keyword', keyword) main()
def music_download(music): ''' 下载音乐保存到本地 ''' echo.info(music) outfile = get_unique_outfile(glovar.get_option('outdir'), music['name']) try: r = requests.get(music['url'], stream=True, headers=glovar.WGET_HEADERS, proxies=glovar.get_option('proxies')) total_size = int(r.headers['content-length']) with click.progressbar(length=total_size, label='Downloading...') as bar: with open(outfile, 'wb') as f: for chunk in r.iter_content(chunk_size=1024): if chunk: f.write(chunk) bar.update(len(chunk)) print('已保存到:%s\n' % outfile) except Exception as e: print('') logger.error('下载音乐失败:') logger.error('URL:%s' % music['url']) logger.error('位置:%s\n' % outfile) if glovar.get_option('verbose'): logger.error(e)
def music_search(source, music_list, errors): ''' 音乐搜索,music_list是搜索结果 ''' try: addon = importlib.import_module('.' + source, 'core.extractors') music_list += addon.search(glovar.get_option('keyword')) except (RequestError, ResponseError, DataError) as e: errors.append((source, e)) except Exception as e: err = traceback.format_exc() if glovar.get_option('verbose') else str(e) errors.append((source, err)) finally: # 放在搜索后输出是为了营造出搜索很快的假象 echo.brand(source=source)
def baidu_search(keyword) -> list: ''' 搜索音乐 ''' count = glovar.get_option('count') or 5 params = { 'query': keyword, 'method': 'baidu.ting.search.common', 'format': 'json', 'page_no': 1, 'page_size': count } s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) s.headers.update({'referer': 'http://music.baidu.com/'}) if glovar.get_option('proxies'): s.proxies.update(glovar.get_option('proxies')) music_list = [] r = s.get('http://musicapi.qianqian.com/v1/restserver/ting', params=params) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() for m in j['song_list']: music = { 'title': m['title'].replace('<em>', '').replace('</em>', ''), 'id': m['song_id'], 'singer': m['author'].replace('<em>', '').replace('</em>', ''), 'album': m['album_title'].replace('<em>', '').replace('</em>', ''), 'source': 'baidu' } s.headers.update({'referer': 'http://music.baidu.com/song/' + m['song_id']}) m_params = {'songIds': m['song_id']} mr = s.get('http://music.baidu.com/data/music/links', params=m_params) if mr.status_code != requests.codes.ok: raise RequestError(mr.text) mj = mr.json() if not mj['data']['songList']: continue mj_music = mj['data']['songList'][0] music['duration'] = str(datetime.timedelta(seconds=mj_music['time'])) size = mj_music['size'] or 0 music['size'] = round(size / 1048576, 2) music['rate'] = mj_music['rate'] music['ext'] = mj_music['format'] music['url'] = mj_music['songLink'] music['name'] = '%s - %s.%s' % (mj_music['artistName'], mj_music['songName'], mj_music['format']) music_list.append(music) return music_list
def music_download(music): ''' 下载音乐保存到本地 ''' echo.info(music) outfile = os.path.abspath( os.path.join(glovar.get_option('outdir'), music['name'])) try: wget.download(music['url'], out=outfile) print('\n已保存到:%s\n' % outfile) except Exception as e: print('') logger.error('下载音乐失败:') logger.error('URL:%s' % music['url']) logger.error('位置:%s\n' % outfile) if glovar.get_option('verbose'): logger.error(e)
def xiami_search(keyword) -> list: ''' 搜索音乐 ''' count = glovar.get_option('count') or 5 params = { 'key': keyword, 'v': '2.0', 'app_key': '1', 'r': 'search/songs', 'page': 1, 'limit': count } s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) # 获取cookie s.head('http://m.xiami.com') s.headers.update({'referer': 'http://m.xiami.com/'}) if glovar.get_option('proxies'): s.proxies.update(glovar.get_option('proxies')) music_list = [] r = s.get('http://api.xiami.com/web', params=params) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() thread_pool = [] for m in j['data']['songs']: # 如果无版权则不显示 if not m['listen_file']: continue music = { 'title': m['song_name'], 'id': m['song_id'], 'singer': m['artist_name'], 'album': m['album_name'], 'url': m['listen_file'], 'source': 'xiami' } t = threading.Thread(target=xiami_music_info, args=(music, music_list, s)) thread_pool.append(t) t.start() for t in thread_pool: t.join() return music_list
def music_download(music): ''' 下载音乐保存到本地 ''' echo.info(music) outfile = os.path.abspath( os.path.join(glovar.get_option('outdir'), music['name'])) wget.download(music['url'], out=outfile) print('\n已保存到:%s\n' % outfile)
def info(music): ''' 打印歌曲信息 ''' if not glovar.get_option('verbose'): return s = '\n ------------ \n -> 歌曲:%s\n -> 歌手:%s\n -> 时长: %s\n -> 大小: %s\n -> 比特率: %s\n -> URL: %s\n' % \ (music['title'], music['singer'], music['duration'], music['size'], music['rate'], music['url']) print(s)
def xiami_search(keyword) -> list: ''' 搜索音乐 ''' count = glovar.get_option('count') or 5 params = { 'key': keyword, 'v': '2.0', 'app_key': '1', 'r': 'search/songs', 'page': 1, 'limit': count } s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) # 获取cookie s.get('http://m.xiami.com') s.headers.update({'referer': 'http://m.xiami.com/'}) music_list = [] r = s.get('http://api.xiami.com/web', params=params) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() for m in j['data']['songs']: # 如果无版权则不显示 if not m['listen_file']: continue music = { 'title': m['song_name'], 'id': m['song_id'], 'singer': m['artist_name'], 'album': m['album_name'], 'url': m['listen_file'], 'source': 'xiami' } mr = s.get('http://www.xiami.com/song/playlist/id/%s/type/0/cat/json' % m['song_id']) if mr.status_code != requests.codes.ok: raise RequestError(mr.text) mj = mr.json() mj_music = mj['data']['trackList'][0] music['duration'] = str(datetime.timedelta(seconds=mj_music['length'])) music['rate'] = 128 music['ext'] = 'mp3' music['name'] = '%s - %s.%s' % (music['singer'], music['title'], music['ext']) # 尝试获取虾米高品质音乐(320K) url = music['url'].replace('m128.xiami.net', 'm320.xiami.net') size = content_length(url) if size: music['size'] = round(size / 1048576, 2) music['url'] = url music['rate'] = 320 else: music['size'] = round(content_length(music['url']) / 1048576, 2) music_list.append(music) return music_list
def qq_search(keyword) -> list: ''' 搜索音乐 ''' count = glovar.get_option('count') or 5 params = {'w': keyword, 'format': 'json', 'p': 1, 'n': count} s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) s.headers.update({ 'referer': 'http://m.y.qq.com', 'User-Agent': glovar.IOS_USERAGENT }) if glovar.get_option('proxies'): s.proxies.update(glovar.get_option('proxies')) music_list = [] r = s.get('http://c.y.qq.com/soso/fcgi-bin/search_for_qq_cp', params=params) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() if j['code'] != 0: raise ResponseError(j) for m in j['data']['song']['list']: # 获得歌手名字 singers = [] for singer in m['singer']: singers.append(singer['name']) # size = m['size320'] or m['size128'] size = m['size128'] music = { 'title': m['songname'], 'id': m['songid'], 'mid': m['songmid'], 'duration': str(datetime.timedelta(seconds=m['interval'])), 'singer': '、'.join(singers), 'album': m['albumname'], # 'ext': m['ExtName'], 'size': round(size / 1048576, 2), 'source': 'qq' } music_list.append(music) return music_list
def main(): music_list = [] thread_pool = [] errors = [] if not glovar.get_option('keyword'): # 如果未设置关键词 keyword = input('请输入要搜索的歌曲,名称和歌手一起输入可以提高匹配(如 空帆船 朴树):\n > ') glovar.set_option('keyword', keyword) echo.notice(glovar.get_option('keyword')) for source in glovar.get_option('source').split(): t = threading.Thread(target=music_search, args=(source, music_list, errors)) thread_pool.append(t) t.start() for t in thread_pool: t.join() echo.line() for err in errors: logger.error('Get %s music list failed.' % err[0].upper()) logger.error(err[1]) if glovar.get_option('merge'): # 对搜索结果排序和去重 music_list = music_list_merge(music_list) echo.menu(music_list) choices = input('请输入要下载的歌曲序号,多个序号用空格隔开:') for choice in choices.split(): start, _, end = choice.partition('-') if end: for i in range(int(start), int(end)+1): music_download(i, music_list) else: music_download(start, music_list) # 下载完后继续搜索 keyword = input('请输入要搜索的歌曲,或Ctrl+C退出:\n > ') glovar.set_option('keyword', keyword) main()
def netease_search(keyword) -> list: ''' 从网易云音乐搜索 ''' count = glovar.get_option('count') or 5 eparams = { 'method': 'POST', 'url': 'http://music.163.com/api/cloudsearch/pc', 'params': { 's': keyword, 'type': 1, 'offset': 0, 'limit': count } } data = {'eparams': encode_netease_data(eparams)} s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) s.headers.update({ 'referer': 'http://music.163.com/', }) r = s.post('http://music.163.com/api/linux/forward', data=data) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() if j['code'] != 200: raise ResponseError(j) music_list = [] for m in j['result']['songs']: if m['privilege']['fl'] == 0: # 没有版权 continue # 获得歌手名字 singers = [] for singer in m['ar']: singers.append(singer['name']) # 获得最优音质的文件大小 if m['privilege']['fl'] >= 320000: size = m['h']['size'] elif m['privilege']['fl'] >= 192000: size = m['m']['size'] else: size = m['l']['size'] music = { 'title': m['name'], 'id': m['id'], 'duration': str(datetime.timedelta(seconds=int(m['dt']/1000))), 'singer': '、'.join(singers), 'album': m['al']['name'], 'size': round(size / 1048576, 2), 'source': 'netease' } music_list.append(music) return music_list
def music_search(source, music_list, errors): ''' 音乐搜索,music_list是搜索结果 ''' try: music_list += addons.get(source).search(glovar.get_option('keyword')) except Exception as e: errors.append((source, e)) finally: # 放在搜索后输出是为了营造出搜索很快的假象 echo.brand(source=source)
def music_download(idx, music_list): ''' 音乐下载,music_list是搜索结果 ''' music = music_list[int(idx)] try: addon = importlib.import_module('.' + music['source'], 'core.extractors') addon.download(music) except Exception as e: logger.error('下载音乐失败') err = traceback.format_exc() if glovar.get_option('verbose') else str(e) logger.error(err)
def main(): music_list = [] thread_pool = [] errors = [] if not glovar.get_option('keyword'): # 如果未设置关键词 cli.set_music_keyword('请输入要搜索的歌曲,名称和歌手一起输入可以提高匹配(如 空帆船 朴树):\n > ') echo.notice(glovar.get_option('keyword')) # 多线程搜索 for source in glovar.get_option('source').split(): t = threading.Thread(target=music_search, args=(source, music_list, errors)) thread_pool.append(t) t.start() for t in thread_pool: t.join() # 分割线 echo.line() # 输出错误信息 for err in errors: logger.error('Get %s music list failed.' % err[0].upper()) logger.error(err[1]) if glovar.get_option('merge'): # 对搜索结果排序和去重 music_list = music_list_merge(music_list) echo.menu(music_list) selected = cli.get_music_select() for idx in selected: music_download(idx, music_list) # 下载完后继续搜索 cli.set_music_keyword() main()
def qq_download(music): ''' 根据songmid等信息获得下载链接 ''' # 计算vkey guid = str(random.randrange(1000000000, 10000000000)) params = {'guid': guid, 'format': 'json', 'json': 3} s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) s.headers.update({ 'referer': 'http://y.qq.com', 'User-Agent': glovar.IOS_USERAGENT }) if glovar.get_option('proxies'): s.proxies.update(glovar.get_option('proxies')) r = s.get('http://base.music.qq.com/fcgi-bin/fcg_musicexpress.fcg', params=params) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() if j['code'] != 0: raise ResponseError(j) vkey = j['key'] for prefix in ['M800', 'M500', 'C400']: url = 'http://dl.stream.qqmusic.qq.com/%s%s.mp3?vkey=%s&guid=%s&fromtag=1' % \ (prefix, music['mid'], vkey, guid) size = content_length(url) if size > 0: music['url'] = url music['rate'] = 320 if prefix == 'M800' else 128 music['size'] = round(size / 1048576, 2) break music['name'] = '%s - %s.mp3' % (music['singer'], music['title']) music_download(music)
def kugou_search(keyword) -> list: ''' 搜索音乐 ''' count = glovar.get_option('count') or 5 params = { 'keyword': keyword, 'platform': 'WebFilter', 'format': 'json', 'page': 1, 'pagesize': count } s = requests.Session() s.headers.update(glovar.FAKE_HEADERS) s.headers.update({'referer': 'http://www.kugou.com'}) music_list = [] r = s.get('http://songsearch.kugou.com/song_search_v2', params=params) if r.status_code != requests.codes.ok: raise RequestError(r.text) j = r.json() if j['status'] != 1: raise ResponseError(j) for m in j['data']['lists']: music = { 'title': m['SongName'], 'id': m['Scid'], 'hash': m['FileHash'], 'duration': str(datetime.timedelta(seconds=m['Duration'])), 'singer': m['SingerName'], 'album': m['AlbumName'], # 'ext': m['ExtName'], 'size': round(m['FileSize'] / 1048576, 2), 'source': 'kugou' } # 如果有更高品质的音乐选择高品质(尽管好像没什么卵用) if m['SQFileHash'] and m[ 'SQFileHash'] != '00000000000000000000000000000000': music['hash'] = m['SQFileHash'] elif m['HQFileHash'] and m[ 'HQFileHash'] != '00000000000000000000000000000000': music['hash'] = m['HQFileHash'] music_list.append(music) return music_list