Ejemplo n.º 1
0
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)
Ejemplo n.º 2
0
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
Ejemplo n.º 3
0
 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]))
Ejemplo n.º 4
0
    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()
Ejemplo n.º 5
0
 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()
Ejemplo n.º 6
0
 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
Ejemplo n.º 7
0
# -*- 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中不会出现
Ejemplo n.º 8
0
 def __init__(self):
     self.mysession = NetEase()
     user = "******"
     pw = "19900119"
     pw_ = hashlib.md5(pw.encode('utf-8')).hexdigest()
     self.mysession.login(user, pw_)
Ejemplo n.º 9
0
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()
Ejemplo n.º 10
0
 def __init__(self):
     self.api = NetEase()
     self.storage = Storage()
     self.storage.load()
     self.collection = self.storage.database['collections']
     self.autologin()
Ejemplo n.º 11
0
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)
Ejemplo n.º 12
0
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("")