Skip to content
This repository was archived by the owner on Oct 4, 2022. It is now read-only.

Commit 11edd6d

Browse files
committed
增加优酷弹幕下载以及其他改进
1 parent 78083c2 commit 11edd6d

File tree

10 files changed

+258
-39
lines changed

10 files changed

+258
-39
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# 额外
22
.vscode/
33
releases/
4+
test/
45
*.ass
56
methods/calc_danmu_pos.py
67

GetDanMu.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'''
44
# 作者: weimo
55
# 创建日期: 2020-01-04 19:14:39
6-
# 上次编辑时间: 2020-01-05 14:47:53
6+
# 上次编辑时间 : 2020-01-11 17:49:40
77
# 一个人的命运啊,当然要靠自我奋斗,但是...
88
'''
99

@@ -13,6 +13,7 @@
1313

1414
from sites.qq import main as qq
1515
from sites.iqiyi import main as iqiyi
16+
from sites.youku import main as youku
1617
from pfunc.cfunc import check_url_site
1718

1819
# -------------------------------------------
@@ -34,8 +35,9 @@ def main():
3435
parser.add_argument("-vid", "--vid", default="", help="下载vid对应视频的弹幕,支持同时多个vid,需要用逗号隔开")
3536
parser.add_argument("-aid", "--aid", default="", help="下载aid对应视频的弹幕(爱奇艺合集)")
3637
parser.add_argument("-tvid", "--tvid", default="", help="下载tvid对应视频的弹幕,支持同时多个tvid,需要用逗号隔开")
38+
parser.add_argument("-series", "--series", action="store_true", help="尝试通过单集得到合集的全部弹幕")
3739
parser.add_argument("-u", "--url", default="", help="下载视频链接所指向视频的弹幕")
38-
parser.add_argument("-y", "--y", action="store_true", help="覆盖原有弹幕而不提示")
40+
parser.add_argument("-y", "--y", action="store_false", help="默认覆盖原有弹幕而不提示")
3941
args = parser.parse_args()
4042
# print(args.__dict__)
4143
if args.url != "":
@@ -46,6 +48,8 @@ def main():
4648
subtitles = qq(args)
4749
if args.site == "iqiyi":
4850
subtitles = iqiyi(args)
51+
if args.site == "youku":
52+
subtitles = youku(args)
4953

5054
if __name__ == "__main__":
5155
# 打包 --> pyinstaller GetDanMu.spec

README.md

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<!--
22
* @作者: weimo
33
* @创建日期: 2020-01-04 18:45:58
4-
* @上次编辑时间 : 2020-01-05 14:42:42
4+
* @上次编辑时间 : 2020-01-11 17:48:19
55
* @一个人的命运啊,当然要靠自我奋斗,但是...
66
-->
77
# GetDanMu
@@ -13,6 +13,7 @@
1313
| :--: | :-- | :-----: | :-----: | :-----: |
1414
| **腾讯视频** | <https://v.qq.com/> ||| |
1515
| **爱奇艺** | <https://www.iqiyi.com/> ||||
16+
| **优酷** | <https://v.youku.com/> ||||
1617

1718
## 可能存在的问题
1819
- 下载进度接近100%时暂时没有反应
@@ -24,6 +25,12 @@
2425

2526
# 更新日志
2627

28+
## 2020/1/11
29+
- 增加优酷弹幕下载,支持合集,支持通过单集直接下载合集弹幕(暂时仅限优酷)
30+
- 改进去重方式
31+
- 优酷的视频id用vid指代,若下载合集请使用连接或通过`-series`选项下载合集弹幕
32+
- 加入下载进度显示,后续可能改进为单行刷新
33+
2734
## 2020/1/5
2835

2936
- 增加了通过链接下载爱奇艺视频弹幕的方法,支持综艺合集。

basic/ass.py

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'''
44
# 作者: weimo
55
# 创建日期: 2020-01-04 19:14:46
6-
# 上次编辑时间: 2020-01-05 14:45:55
6+
# 上次编辑时间 : 2020-01-11 17:20:21
77
# 一个人的命运啊,当然要靠自我奋斗,但是...
88
'''
99

@@ -62,10 +62,4 @@ def check_font(font):
6262
font_style_name = font
6363
else:
6464
pass
65-
return font_path, font_style_name
66-
67-
def check_content(content: str, comments: list):
68-
content = content.replace(" ", "")
69-
if content in comments:
70-
return
71-
return content
65+
return font_path, font_style_name

pfunc/cfunc.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,24 @@
33
'''
44
# 作者: weimo
55
# 创建日期: 2020-01-05 12:45:18
6-
# 上次编辑时间: 2020-01-05 14:44:42
6+
# 上次编辑时间 : 2020-01-11 17:37:22
77
# 一个人的命运啊,当然要靠自我奋斗,但是...
88
'''
9+
10+
import hashlib
911
from urllib.parse import urlparse
1012

13+
def remove_same_danmu(comments: list):
14+
# 在原有基础上pop会引起索引变化 所以还是采用下面这个方式
15+
contents = []
16+
for comment in comments:
17+
content, color, timepoint = comment
18+
content = content.replace(" ", "")
19+
if content in contents:
20+
continue
21+
else:
22+
contents.append([content, color, timepoint])
23+
return contents
1124

1225
def check_url_site(url):
1326
return urlparse(url).netloc.split(".")[-2]
@@ -21,4 +34,11 @@ def check_url_locale(url):
2134
if urlparse(url).netloc.split(".")[0] == "tw":
2235
return flag["tw"]
2336
else:
24-
return flag["cn"]
37+
return flag["cn"]
38+
39+
def yk_msg_sign(msg: str):
40+
return hashlib.new("md5", bytes(msg + "MkmC9SoIw6xCkSKHhJ7b5D2r51kBiREr", "utf-8")).hexdigest()
41+
42+
def yk_t_sign(token, t, appkey, data):
43+
text = "&".join([token, t, appkey, data])
44+
return hashlib.new('md5', bytes(text, 'utf-8')).hexdigest()

pfunc/dump_to_ass.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,27 @@
33
'''
44
# 作者: weimo
55
# 创建日期: 2020-01-04 19:17:44
6-
# 上次编辑时间: 2020-01-05 14:45:03
6+
# 上次编辑时间 : 2020-01-11 17:25:09
77
# 一个人的命运啊,当然要靠自我奋斗,但是...
88
'''
99
import os
1010

1111
from basic.ass import get_ass_head, check_font
1212
from methods.assbase import ASS
1313
from methods.sameheight import SameHeight
14+
from pfunc.cfunc import remove_same_danmu
1415

1516
def write_one_video_subtitles(file_path, comments, args):
1617
# 对于合集则每次都都得检查一次 也可以放在上一级 放在这里 考虑后面可能特殊指定字体的情况
1718
font_path, font_style_name = check_font(args.font)
1819
ass_head = get_ass_head(font_style_name, args.font_size)
19-
get_xy_obj = SameHeight("那就写这一句作为初始化测试吧!", font_path=font_path, font_size=args.font_size)
20+
get_xy_obj = SameHeight("那就写这一句作为初始化测试吧!", font_path=font_path, font_size=int(args.font_size))
2021
subtitle = ASS(file_path, get_xy_obj, font=font_style_name)
22+
comments = remove_same_danmu(comments)
2123
for comment in comments:
2224
subtitle.create_new_line(comment)
2325
write_lines_to_file(ass_head, subtitle.lines, file_path)
26+
return comments
2427

2528
def write_lines_to_file(ass_head, lines, file_path):
2629
with open(file_path, "a+", encoding="utf-8") as f:

pfunc/request_info.py

Lines changed: 62 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'''
44
# 作者: weimo
55
# 创建日期: 2020-01-04 19:14:43
6-
# 上次编辑时间: 2020-01-05 14:47:16
6+
# 上次编辑时间 : 2020-01-11 17:42:30
77
# 一个人的命运啊,当然要靠自我奋斗,但是...
88
'''
99
import re
@@ -192,4 +192,64 @@ def get_vinfos_by_url(url):
192192
else:
193193
return get_vinfos(aid, locale=locale)
194194

195-
#-------------------------------------------iqiyi--------------------------------------------
195+
#-------------------------------------------iqiyi--------------------------------------------
196+
197+
#-------------------------------------------youku--------------------------------------------
198+
199+
def get_vinfos_by_url_youku(url, isall=False):
200+
vid_patterns = ["[\s\S]+?youku.com/video/id_(/+?)\.html", "[\s\S]+?youku.com/v_show/id_(.+?)\.html"]
201+
video_id = matchit(vid_patterns, url)
202+
show_id_patterns = ["[\s\S]+?youku.com/v_nextstage/id_(/+?)\.html", "[\s\S]+?youku.com/show/id_z(.+?)\.html", "[\s\S]+?youku.com/show_page/id_z(.+?)\.html", "[\s\S]+?youku.com/alipay_video/id_(.+?)\.html"]
203+
show_id = matchit(show_id_patterns, url)
204+
if video_id is None and show_id is None:
205+
return None
206+
if video_id:
207+
return get_vinfos_by_video_id(video_id, isall=isall)
208+
if show_id.__len__() == 20 and show_id == show_id.lower():
209+
return get_vinfos_by_show_id(show_id)
210+
else:
211+
return get_vinfos_by_video_id(show_id, isall=isall)
212+
213+
def get_vinfos_by_video_id(video_id, isall=False):
214+
api_url = "https://openapi.youku.com/v2/videos/show.json?client_id=53e6cc67237fc59a&package=com.huawei.hwvplayer.youku&ext=show&video_id={}".format(video_id)
215+
try:
216+
r = requests.get(api_url, headers=chrome, timeout=5).content.decode("utf-8")
217+
except Exception as e:
218+
print("get_vinfos_by_video_id error info -->", e)
219+
return None
220+
data = json.loads(r)
221+
if isall:
222+
show_id = data["show"]["id"]
223+
return get_vinfos_by_show_id(show_id)
224+
duration = 0
225+
if data.get("duration"):
226+
duration = int(float(data["duration"]))
227+
if data.get("title"):
228+
name = data["title"] + "_" + str(duration)
229+
else:
230+
name = "优酷未知" + "_" + str(duration)
231+
vinfo = [name, duration, video_id]
232+
return [vinfo]
233+
234+
def get_vinfos_by_show_id(show_id):
235+
api_url = "https://openapi.youku.com/v2/shows/videos.json?show_videotype=正片&count=100&client_id=53e6cc67237fc59a&page=1&show_id={}&package=com.huawei.hwvplayer.youku".format(show_id)
236+
try:
237+
r = requests.get(api_url, headers=chrome, timeout=5).content.decode("utf-8")
238+
except Exception as e:
239+
print("get_vinfos_by_show_id error info -->", e)
240+
return None
241+
data = json.loads(r)["videos"]
242+
if data.__len__() == 0:
243+
return None
244+
vinfos = []
245+
for video in data:
246+
duration = 0
247+
if video.get("duration"):
248+
duration = int(float(video["duration"]))
249+
if video.get("title"):
250+
name = video["title"] + "_" + str(duration)
251+
else:
252+
name = "优酷未知_{}".format(video["id"]) + "_" + str(duration)
253+
vinfos.append([name, duration, video["id"]])
254+
return vinfos
255+
#-------------------------------------------youku--------------------------------------------

sites/iqiyi.py

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'''
44
# 作者: weimo
55
# 创建日期: 2020-01-04 19:14:41
6-
# 上次编辑时间: 2020-01-05 14:45:17
6+
# 上次编辑时间 : 2020-01-11 17:23:32
77
# 一个人的命运啊,当然要靠自我奋斗,但是...
88
'''
99

@@ -14,7 +14,6 @@
1414
from xmltodict import parse
1515

1616
from basic.vars import iqiyiplayer
17-
from basic.ass import check_content
1817
from pfunc.dump_to_ass import check_file, write_one_video_subtitles
1918
from pfunc.request_info import get_vinfos, get_vinfos_by_url, get_vinfo_by_tvid
2019

@@ -48,7 +47,6 @@ def get_danmu_by_tvid(name, duration, tvid):
4847
continue
4948
# with open("raw_xml.json", "w", encoding="utf-8") as f:
5049
# f.write(json.dumps(parse(raw_xml), ensure_ascii=False, indent=4))
51-
contents = []
5250
if entry.__class__ != list:
5351
entry = [entry]
5452
for comment in entry:
@@ -58,13 +56,8 @@ def get_danmu_by_tvid(name, duration, tvid):
5856
if bulletInfo.__class__ != list:
5957
bulletInfo = [bulletInfo]
6058
for info in bulletInfo:
61-
content = check_content(info["content"], contents)
62-
if content is None:
63-
continue
64-
else:
65-
contents.append(content)
6659
color = [info["color"]]
67-
comments.append([content, color, int(comment["int"])])
60+
comments.append([info["content"], color, int(comment["int"])])
6861
print("已下载{:.2f}%".format(index * timestamp * 100 / duration))
6962
index += 1
7063
comments = sorted(comments, key=lambda _: _[-1])
@@ -93,8 +86,8 @@ def main(args):
9386
flag, file_path = check_file(name, skip=args.y)
9487
if flag is False:
9588
print("跳过{}".format(name))
96-
return
89+
continue
9790
comments = get_danmu_by_tvid(name, duration, tvid)
98-
write_one_video_subtitles(file_path, comments, args)
91+
comments = write_one_video_subtitles(file_path, comments, args)
9992
subtitles.update({file_path:comments})
10093
return subtitles

sites/qq.py

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
'''
44
# 作者: weimo
55
# 创建日期: 2020-01-04 19:14:37
6-
# 上次编辑时间: 2020-01-05 14:47:36
6+
# 上次编辑时间 : 2020-01-11 17:25:34
77
# 一个人的命运啊,当然要靠自我奋斗,但是...
88
'''
99

@@ -13,7 +13,6 @@
1313
import requests
1414

1515
from basic.vars import qqlive
16-
from basic.ass import check_content
1716
from pfunc.dump_to_ass import check_file, write_one_video_subtitles
1817
from pfunc.request_info import get_all_vids_by_cid as get_vids
1918
from pfunc.request_info import get_danmu_target_id_by_vid as get_target_id
@@ -80,13 +79,7 @@ def get_danmu_by_target_id(vid: str, duration: int, target_id, font="微软雅
8079
# timestamp不变 再试一次
8180
continue
8281
danmu_count = danmu["count"]
83-
contents = []
8482
for comment in danmu["comments"]:
85-
content = check_content(comment["content"], contents)
86-
if content is None:
87-
continue
88-
else:
89-
contents.append(content)
9083
if comment["content_style"]:
9184
style = json.loads(comment["content_style"])
9285
if style.get("gradient_colors"):
@@ -97,7 +90,7 @@ def get_danmu_by_target_id(vid: str, duration: int, target_id, font="微软雅
9790
color = ["ffffff"]
9891
else:
9992
color = ["ffffff"]
100-
comments.append([content, color, comment["timepoint"]])
93+
comments.append([comment["content"], color, comment["timepoint"]])
10194
print("已下载{:.2f}%".format(params["timestamp"]*100/duration))
10295
params["timestamp"] += 30
10396
comments = sorted(comments, key=lambda _: _[-1])
@@ -157,8 +150,11 @@ def main(args):
157150
vinfos = get_video_info_by_vid(vids)
158151
subtitles = {}
159152
for vinfo in vinfos:
160-
comments, file_path = get_one_subtitle_by_vinfo(vinfo, args.font, args.font_size, args.y)
161-
write_one_video_subtitles(file_path, comments, args)
153+
infos = get_one_subtitle_by_vinfo(vinfo, args.font, args.font_size, args.y)
154+
if infos is None:
155+
continue
156+
comments, file_path = infos
157+
comments = write_one_video_subtitles(file_path, comments, args)
162158
subtitles.update({file_path:comments})
163159
return subtitles
164160

0 commit comments

Comments
 (0)