def upload_file(self, filepath):
        """
        上传素材 (图片/音频/视频)
        :param filepath: 本地文件路径
        :return: 直接返回上传后的文件 ID (fid)
        :raises NeedLoginError: 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
        :raises ValueError: 参数出错, 错误原因直接打印异常即可 (常见错误内容: ``file not exist``: 找不到本地文件, ``audio too long``: 音频文件过长, ``file invalid type``: 文件格式不正确, 还有其他错误请自行检查)
        """
        self._init_ticket()

        url = 'https://mp.weixin.qq.com/cgi-bin/filetransfer?action=upload_material&f=json&ticket_id={ticket_id}&ticket={ticket}&token={token}&lang=zh_CN'.format(
            ticket_id=self.__ticket_id,
            ticket=self.__ticket,
            token=self.__token,
        )
        try:
            files = {'file': open(filepath, 'rb')}
        except IOError:
            raise ValueError('file not exist')
        payloads = {
            'Filename': filepath,
            'folder': '/cgi-bin/uploads',
            'Upload': 'Submit Query',
        }
        headers = {
            'referer': 'http://mp.weixin.qq.com/cgi-bin/indexpage?t=wxm-upload&lang=zh_CN&type=2&formId=1',
            'cookie': self.__cookies,
        }
        r = requests.post(url, files=files, data=payloads, headers=headers)

        try:
            message = json.loads(r.text)
        except ValueError:
            raise NeedLoginError(r.text)
        try:
            if message['base_resp']['ret'] != 0:
                raise ValueError(message['base_resp']['err_msg'])
        except KeyError:
            raise NeedLoginError(r.text)

        return message['content']
上传素材 (图片/音频/视频)
        :param filepath: 本地文件路径
        :return: 直接返回上传后的文件 ID (fid)
        :raises NeedLoginError: 操作未执行成功, 需要再次尝试登录, 异常内容为服务器返回的错误数据
        :raises ValueError: 参数出错, 错误原因直接打印异常即可 (常见错误内容: ``file not exist``: 找不到本地文件, ``audio too long``: 音频文件过长, ``file invalid type``: 文件格式不正确, 还有其他错误请自行检查)