├── .vscode └── launch.json ├── README.md ├── __pycache__ ├── main2.cpython-38.pyc └── upload.cpython-38.pyc ├── data.txt ├── file ├── bili_upload.exe ├── config.json ├── 分类序号表.txt └── 配置参数.txt ├── main.py ├── main2.py └── upload.py /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // 使用 IntelliSense 了解相关属性。 3 | // 悬停以查看现有属性的描述。 4 | // 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Python: 当前文件", 9 | "type": "python", 10 | "request": "launch", 11 | "program": "${file}", 12 | "console": "integratedTerminal" 13 | } 14 | ] 15 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | bili_upload 2 | -------------------------------------------------------------------------------- /__pycache__/main2.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modifyGB/bili_upload/e3835007dc18fc3308d898dc487cd9d76f9d64ad/__pycache__/main2.cpython-38.pyc -------------------------------------------------------------------------------- /__pycache__/upload.cpython-38.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modifyGB/bili_upload/e3835007dc18fc3308d898dc487cd9d76f9d64ad/__pycache__/upload.cpython-38.pyc -------------------------------------------------------------------------------- /data.txt: -------------------------------------------------------------------------------- 1 | { 2 | copyright: 1 //是否原创(必需) 3 | cover: "" //封面网址(必需) 4 | desc: "" //视频简介(必需) 5 | desc_format_id: 32 //不清楚 6 | dynamic: "" //粉丝动态(必需) 7 | interactive: 0 // 是否为合作视频? 8 | mission_id: 16177 //不清楚 9 | is_360: 1 //是否全景 1,-1 10 | no_reprint: 1 //自制声明(必需) 11 | dtime: 0 //何时发布的时间戳 12 | porder: { 13 | flow_id: 1, //是否有广告 14 | industry_id: 1, 15 | official: 0, 16 | brand_name: "", 17 | show_type: "" 18 | } 19 | subtitle: {(必需) 20 | open: 0,//是否开启字幕投稿(必需) 21 | lan: "zh-CN"//语言(必需) 22 | } 23 | source: "" //转载网址,若不是原创才需要 24 | tag: "tag1,tag2" //标签,用逗号分隔(必需) 25 | tid: 65 //分类id(必需) 26 | title: "测试视频" //视频标题(必需) 27 | up_close_danmu: false //是否关闭弹幕(必需) 28 | up_close_reply: false //是否关闭评论(必需) 29 | videos: [(必需) 30 | { 31 | filename: "", //视频资源id(必需) 32 | title: "", //分p名称(必需) 33 | desc: "", //分p简介?(必需) 34 | cid: 0(必需) 35 | } 36 | ] 37 | } -------------------------------------------------------------------------------- /file/bili_upload.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/modifyGB/bili_upload/e3835007dc18fc3308d898dc487cd9d76f9d64ad/file/bili_upload.exe -------------------------------------------------------------------------------- /file/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "这是一个测试视频", 3 | "tag": "标签1,标签2", 4 | "tid": 65, 5 | "title": "测试视频", 6 | "video_path": "f:\\video.mp4", 7 | "cover_path": "f:\\cover.png", 8 | "cookie": "" 9 | } -------------------------------------------------------------------------------- /file/分类序号表.txt: -------------------------------------------------------------------------------- 1 | { 2 | 生活:{ 3 | 日常:21 4 | 搞笑:138 5 | 运动:163 6 | 汽车:176 7 | 绘画:162 8 | 手工:161 9 | 其他:174 10 | } 11 | 游戏:{ 12 | 单机游戏:17 13 | 网络游戏:65 14 | 手机游戏:172 15 | 电子竞技:171 16 | 桌游棋牌:173 17 | 音游:136 18 | GMV:121 19 | Mugen:19 20 | } 21 | 娱乐:{ 22 | 综艺:71 23 | 明星:137 24 | } 25 | 知识:{ 26 | 科学科普:201 27 | 社科人文:124 28 | 财经:207 29 | 校园学习:208 30 | 职业职场:209 31 | 野生技术协会:122 32 | } 33 | 影视:{ 34 | 短片:85 35 | 影视杂谈:182 36 | 影视剪辑:183 37 | 预告·资讯:184 38 | } 39 | 音乐:{ 40 | 音乐综合:130 41 | 音乐现场:29 42 | 演奏:59 43 | 翻唱:31 44 | MV:193 45 | VOCALOID·UTAU:30 46 | 电音:194 47 | 原创音乐:28 48 | } 49 | 动画:{ 50 | MAD·AMV:24 51 | MMD·3D:25 52 | 综合:27 53 | 短片·手书·配音:47 54 | 手办·模玩:210 55 | 特摄:86 56 | } 57 | 时尚:{ 58 | 美妆:157 59 | 服饰:158 60 | T台:159 61 | 健身:164 62 | 风尚标:192 63 | } 64 | 美食:{ 65 | 美食制作:76 66 | 美食侦探:212 67 | 美食测评:213 68 | 田园美食:214 69 | 美食记录:215 70 | } 71 | 数码:{ 72 | 手机平板:95 73 | 电脑装机:189 74 | 摄影摄像:190 75 | 影音智能:191 76 | } 77 | 动物圈:{ 78 | 喵星人:218 79 | 汪星人:219 80 | 野生动物:221 81 | 爬宠:222 82 | 大熊猫:220 83 | 动物综合:75 84 | } 85 | 舞蹈:{ 86 | 宅舞:20 87 | 舞蹈综合:154 88 | 舞蹈教程:156 89 | 街舞:198 90 | 明星舞蹈:199 91 | 中国舞:200 92 | } 93 | 国创:{ 94 | 国产动画:153 95 | 国产原创相关:168 96 | 布袋戏:169 97 | 资讯:170 98 | 动态漫·广播剧:195 99 | } 100 | 鬼畜:{ 101 | 鬼畜调教:22 102 | 音MAD:26 103 | 人力VOCALOID:126 104 | 鬼畜剧场:216 105 | 教程演示:127 106 | } 107 | 纪录片:{ 108 | 人文·历史:37 109 | 科学·探索·自然:178 110 | 军事:179 111 | 社会·美食·旅行:180 112 | } 113 | 番剧:{ 114 | 资讯:51 115 | 官方延伸:152 116 | } 117 | 电视剧:{ 118 | 国产剧:185 119 | 海外剧:187 120 | } 121 | 电影:{ 122 | 其他国家:83 123 | 欧美电影:145 124 | 日本电影:146 125 | 国产电影:147 126 | } 127 | } -------------------------------------------------------------------------------- /file/配置参数.txt: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "", // 视频简介 3 | "tag": "", // 视频标签,用逗号分隔 4 | "tid": 0, // 视频分类序号 5 | "title": "", // 视频标题 6 | "video_path": "", // 视频资源路径 7 | "cover_path": "", // 封面图片路径 8 | "cookie": "", // cookie 9 | 10 | //下列为非必要参数 11 | "copyright": 0 // 是否原创 12 | "dynamic": "" // 粉丝动态 13 | "no_reprint": 0 // 自制声明 14 | "subtitle": { 15 | "open": 0 // 是否开启字幕投稿 16 | "lan": "" // 字幕语言 17 | } 18 | "up_close_danmu": false // 是否关闭弹幕 19 | "up_close_reply": false // 是否关闭评论 20 | } -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from upload import upload 2 | 3 | config = { 4 | 'desc': '简介', # 视频简介 5 | 'tag': 'tag1,tag2,tag3', # 视频标签,用逗号分隔 6 | 'tid': 65, # 视频分类序号 7 | 'title': '标题', # 视频标题 8 | 'video_path': 'video.mp4', # 视频资源路径 9 | 'cover_path': 'cover.png', # 封面图片路径 10 | 'cookie': '', # cookie 11 | } 12 | 13 | # 运行此文件即可投稿 14 | if __name__ == "__main__": 15 | ul = upload(config) 16 | ul.upload() -------------------------------------------------------------------------------- /main2.py: -------------------------------------------------------------------------------- 1 | from upload import upload 2 | import sys 3 | import json 4 | 5 | if __name__ == "__main__": 6 | if len(sys.argv) > 1: 7 | with open(sys.argv[1],'r+',encoding='utf-8') as file: 8 | ul = upload(json.loads(file.read())) 9 | ul.upload() 10 | else: 11 | print('你没有传配置文件') -------------------------------------------------------------------------------- /upload.py: -------------------------------------------------------------------------------- 1 | import requests 2 | import os 3 | import re 4 | import json 5 | import base64 6 | import sys 7 | 8 | url1 = 'https://member.bilibili.com/preupload?name={}&size={}&r=upos&profile=ugcupos%2Fbup&ssl=0&version=2.8.12&build=2081200&upcdn=qn&probe_version=20200810' 9 | url2 = 'https://upos-sz-upcdnqn.bilivideo.com/ugcboss/{}?uploads&output=json' 10 | url3 = 'https://upos-sz-upcdnqn.bilivideo.com/ugcboss/{}?partNumber={}&uploadId={}&chunk={}&chunks={}&size={}&start={}&end={}&total={}' 11 | url4 = 'https://upos-sz-upcdnqn.bilivideo.com/ugcboss/{}?output=json&name={}&profile=ugcupos%2Fbup&uploadId={}&biz_id={}' 12 | url5 = 'https://member.bilibili.com/x/vu/web/cover/up' 13 | url6 = 'https://member.bilibili.com/x/vu/web/add?csrf={}' 14 | 15 | 16 | class upload: 17 | header = { 18 | 'cookie': '', 19 | 'user-agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/88.0.4324.146 Safari/537.36', 20 | } 21 | 22 | data = { 23 | 'copyright': 1, 24 | 'cover': '', 25 | 'desc': '', 26 | 'desc_format_id': 32, 27 | 'dynamic': '', 28 | 'interactive': 0, 29 | 'mission_id': 16177, 30 | 'no_reprint': 1, 31 | 'subtitle': { 32 | 'open': 0, 33 | 'lan': "" 34 | }, 35 | 'tag': '', 36 | 'tid': 0, 37 | 'title': '', 38 | 'up_close_danmu': False, 39 | 'up_close_reply': False, 40 | 'videos': [ 41 | { 42 | 'filename': '', 43 | 'title': '', 44 | 'desc': '', 45 | 'cid': '' 46 | } 47 | ] 48 | } 49 | 50 | def __init__(self,config = {}) -> None: 51 | self.config = config 52 | self.setconfig() 53 | 54 | def setconfig(self) -> None: 55 | try: 56 | self.header['cookie'] = self.config['cookie'] 57 | if len(re.findall(r'bili_jct=(\S+?);',self.config['cookie'])): 58 | self.bili_jct = re.findall(r'bili_jct=(\S+?);',self.config['cookie'])[0] 59 | else: 60 | self.bili_jct = re.findall(r'bili_jct=(\S+?)$',self.config['cookie'])[0] 61 | except Exception: 62 | print('cookie error') 63 | sys.exit() 64 | 65 | try: 66 | self.video_path = self.config['video_path'] 67 | self.cover_path = self.config['cover_path'] 68 | self.data['desc'] = self.config['desc'] 69 | self.data['tag'] = self.config['tag'] 70 | self.data['tid'] = self.config['tid'] 71 | self.data['title'] = self.config['title'] 72 | if 'copyright' in self.config: 73 | self.data['copyright'] = self.config['copyright'] 74 | if 'dynamic' in self.config: 75 | self.data['dynamic'] = self.config['dynamic'] 76 | if 'no_reprint' in self.config: 77 | self.data['no_reprint'] = self.config['no_reprint'] 78 | if 'subtitle' in self.config: 79 | self.data['subtitle'] = self.config['subtitle'] 80 | if 'up_close_danmu' in self.config: 81 | self.data['up_close_danmu'] = self.config['up_close_danmu'] 82 | if 'up_close_reply' in self.config: 83 | self.data['up_close_reply'] = self.config['up_close_reply'] 84 | except Exception: 85 | print('config error') 86 | sys.exit() 87 | 88 | def picture_upload(self) -> None: 89 | try: 90 | with open(self.cover_path,'rb+') as file: 91 | print('正在上传封面') 92 | code = b'data:image/jpeg;base64,'+base64.b64encode(file.read()) 93 | js = json.loads(requests.post(url5,data={'cover': code,'csrf': self.bili_jct},headers=self.header).text) 94 | self.data['cover'] = js['data']['url'].split(':')[1] 95 | print('封面上传完毕') 96 | except Exception: 97 | print('封面路径无效') 98 | sys.exit() 99 | 100 | def video_upload(self) -> None: 101 | try: 102 | print('正在上传视频') 103 | header = self.header 104 | video_path = self.video_path 105 | video_name = video_path.split('\\')[-1] 106 | size = os.path.getsize(video_path) 107 | js1 = json.loads(requests.get(url1.format(video_name,size),headers=header).text) 108 | header['X-Upos-Auth'] = js1['auth'] 109 | upos_uri = js1['upos_uri'].split('/')[-1] 110 | biz_id = js1['biz_id'] 111 | js2 = json.loads(requests.post(url2.format(upos_uri),headers=header).text) 112 | upload_id = js2['upload_id'] 113 | 114 | with open(video_path,'rb+') as file: 115 | requests.put(url3.format(upos_uri,1,upload_id,0,1,size,0,size,size),headers=header,data=file.read()) 116 | js3 = requests.post(url4.format(upos_uri,video_name,upload_id,biz_id),headers=header).text 117 | if 'OK' in js3: 118 | print('视频上传完毕') 119 | 120 | self.data['videos'][0]['filename'] = upos_uri.split('.')[0] 121 | self.data['videos'][0]['cid'] = biz_id 122 | self.data['videos'][0]['title'] = video_name.split('.')[0] 123 | except IOError: 124 | print('视频路径无效') 125 | except KeyError: 126 | print('视频配置出错') 127 | 128 | def upload(self) -> None: 129 | self.picture_upload() 130 | self.video_upload() 131 | 132 | js = json.loads(requests.post(url6.format(self.bili_jct),headers=self.header,data=json.dumps(self.data).encode('utf-8')).text) 133 | if js['code'] != 0: 134 | print(js['message']) 135 | else: 136 | print('投稿成功') 137 | print('av:{}, bv:{}'.format(js['data']['aid'],js['data']['bvid'])) --------------------------------------------------------------------------------