From 1c31057b9d5fd90b609a567f34b17d0113381ee4 Mon Sep 17 00:00:00 2001 From: xhlove Date: Fri, 7 Feb 2020 19:05:58 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E5=96=84=E8=AF=B4=E6=98=8E=EF=BC=8C?= =?UTF-8?q?=E7=88=B1=E5=A5=87=E8=89=BA=E6=94=AF=E6=8C=81series=E5=91=BD?= =?UTF-8?q?=E4=BB=A4=EF=BC=8C=E5=A2=9E=E5=8A=A0=E5=BC=B9=E5=B9=95=E5=8C=BA?= =?UTF-8?q?=E9=97=B4=E8=AE=BE=E5=AE=9A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- GetDanMu.py | 7 +++++-- README.md | 48 +++++++++++++++++++++++++++++++++++-------- basic/ass.py | 27 +++++++++++++++++------- basic/vars.py | 2 +- config.json | 8 ++++++++ methods/sameheight.py | 8 ++++---- pfunc/dump_to_ass.py | 4 ++-- pfunc/request_info.py | 31 ++++++++++++++++++++++++---- sites/iqiyi.py | 9 +++++--- sites/mgtv.py | 3 +-- sites/sohu.py | 4 ++-- 11 files changed, 115 insertions(+), 36 deletions(-) create mode 100644 config.json diff --git a/GetDanMu.py b/GetDanMu.py index 7c1201b..0dd2fab 100644 --- a/GetDanMu.py +++ b/GetDanMu.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-04 19:14:39 -# 上次编辑时间 : 2020-01-28 18:39:00 +# 上次编辑时间 : 2020-02-07 18:23:18 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' @@ -18,6 +18,8 @@ from sites.sohu import main as sohu from sites.mgtv import main as mgtv from pfunc.cfunc import check_url_site +from basic.vars import ALLOW_SITES + # ------------------------------------------- # 基本流程 # 1. 根据传入参数确定网站,否则请求输入有关参数或链接。并初始化字幕的基本信息。 @@ -32,7 +34,8 @@ def main(): parser = ArgumentParser(description="视频网站弹幕转换/下载工具,项目地址https://github.com/xhlove/GetDanMu,任何问题请联系vvtoolbox.dev@gmail.com") parser.add_argument("-f", "--font", default="微软雅黑", help="指定输出字幕字体") parser.add_argument("-fs", "--font-size", default=28, help="指定输出字幕字体大小") - parser.add_argument("-s", "--site", default="", help="指定网站") + parser.add_argument("-s", "--site", default="", help=f"使用非url方式下载需指定网站 支持的网站 -> {ALLOW_SITES}") + parser.add_argument("-r", "--range", default="0,720", help="指定弹幕的纵向范围 默认0到720 请用逗号隔开") parser.add_argument("-cid", "--cid", default="", help="下载cid对应视频的弹幕(腾讯 芒果视频合集)") parser.add_argument("-vid", "--vid", default="", help="下载vid对应视频的弹幕,支持同时多个vid,需要用逗号隔开") parser.add_argument("-aid", "--aid", default="", help="下载aid对应视频的弹幕(爱奇艺合集)") diff --git a/README.md b/README.md index 99b9fdd..0ab8ca6 100644 --- a/README.md +++ b/README.md @@ -5,24 +5,43 @@ 项目主页:https://github.com/xhlove/GetDanMu ## 网站支持 -| Site | URL | 单集? | 合集? | 综艺合集? | -| :--: | :-- | :-----: | :-----: | :-----: | +| Site | URL | 单集? | 合集? | 综艺合集? | 支持series? | +| :--: | :-- | :-----: | :-----: | :-----: | :-----: | | **腾讯视频** | |✓|✓| | -| **爱奇艺** | |✓|✓|✓| -| **优酷** | |✓|✓|✓| -| **搜狐视频** | |✓|✓|| -| **芒果TV** | |✓|✓|✓| +| **爱奇艺** | |✓|✓|✓|✓| +| **优酷** | |✓|✓|✓|✓| +| **搜狐视频** | |✓|✓||| +| **芒果TV** | |✓|✓|✓|✓| # 使用示例 - 命令(建议) -> GetDanMu.exe -u https://www.mgtv.com/b/334727/7452407.html +> GetDanMu.exe -s mgtv -r 20,960 -series -u https://www.mgtv.com/b/334727/7452407.html - 双击运行 > 提示逻辑有待完善 +- 选项说明 +> -f或--font 指定输出字幕字体,默认微软雅黑) +> -fs或--font-size 指定输出字幕字体大小,默认28) +> -s或--site 使用非url方式下载需指定网站 支持的网站 -> ["qq", "iqiyi", "youku", "sohu", "mgtv"] +> -r或--range 指定弹幕的纵向范围 默认0到720,请用逗号隔开 +> -cid或--cid 下载cid对应视频的弹幕(腾讯 芒果视频合集) +> -vid或--vid 下载vid对应视频的弹幕,支持同时多个vid,需要用逗号隔开 +> -aid或--aid 下载aid对应视频的弹幕(爱奇艺合集) +> -tvid或--tvid 下载tvid对应视频的弹幕,支持同时多个tvid,需要用逗号隔开 +> -series或--series 尝试通过单集得到合集的全部弹幕 默认不使用 +> -u或--url 下载视频链接所指向视频的弹幕 +> -y或--y 覆盖原有弹幕而不提示 默认不使用 + + # 效果示意(字幕与视频不相关) -[potplayer截屏](http://puui.qpic.cn/vshpic/0/5TLOX3WbgjudEj61IxYZ4tAuf2lFwl-ynf4S5T4sXkdjS9cd_0/0) +![potplayer截屏](http://puui.qpic.cn/vshpic/0/5TLOX3WbgjudEj61IxYZ4tAuf2lFwl-ynf4S5T4sXkdjS9cd_0/0) +[查看使用演示视频点我][2] + +注意有背景音乐 + +演示是直接使用的python命令,使用exe的话把python GetDanMu.py换成GetDanMu.exe即可 ## 可能存在的问题 - 下载进度接近100%时暂时没有反应 @@ -34,6 +53,13 @@ # 更新日志 +## 2020/2/7 +- 完善说明 +- 爱奇艺支持series选项,并完善地区判断 +- 增加字体配置文件,建立字体名称与实际字体文件的映射关系,用于预先设定,方便更准确计算弹幕的分布 +- 增加自定义弹幕区间选项,即-r或--range命令 +- README完善 + ## 2020/1/28 - 增加芒果TV的支持(支持综艺合集、支持series命令) - 爱奇艺bug修复 @@ -54,4 +80,8 @@ - 增加了通过链接下载爱奇艺视频弹幕的方法,支持综艺合集。 - 增加通过链接判断网站 - [1]: https://blog.weimo.info/archives/431/ \ No newline at end of file +[赞助点此][3] + + [1]: https://blog.weimo.info/archives/431/ + [2]: https://alime-customer-upload-cn-hangzhou.oss-cn-hangzhou.aliyuncs.com/customer-upload/1581073011183_8t14dpgg2bdc.mp4 + [3]: https://afdian.net/@vvtoolbox_dev \ No newline at end of file diff --git a/basic/ass.py b/basic/ass.py index 13b2c0f..73fb19c 100644 --- a/basic/ass.py +++ b/basic/ass.py @@ -3,15 +3,14 @@ ''' # 作者: weimo # 创建日期: 2020-01-04 19:14:46 -# 上次编辑时间 : 2020-01-11 17:20:21 +# 上次编辑时间 : 2020-02-07 18:33:14 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' import os - +import json from basic.vars import fonts - ass_script = """[Script Info] ; Script generated by N ScriptType: v4.00+ @@ -30,15 +29,29 @@ ass_events_head = """[Events]\nFormat: Layer, Start, End, Style, Name, MarginL, # 基于当前时间范围,在0~1000ms之间停留在(676.571,506.629)处,在1000~3000ms内从位置1300,600移动到360,600(原点在左上) # ass_baseline = """Dialogue: 0,0:20:08.00,0:20:28.00,Default,,0,0,0,,{\t(1000,3000,\move(1300,600,360,600))\pos(676.571,506.629)}这是字幕内容示意""" +def get_fonts_info(): + fonts_path = r"C:\Windows\Fonts" + if os.path.exists("config.json"): + with open("config.json", "r", encoding="utf-8") as f: + fr = f.read() + try: + config = json.loads(fr) + except Exception as e: + print("get_fonts_info error info ->", e) + else: + fonts_path = config["fonts_base_folder"] + fonts = config["fonts"] + return fonts_path, fonts + def get_ass_head(font_style_name, font_size): ass_head = ass_script + "\n\n" + ass_style_head + "\n" + ass_style_base.format(font=font_style_name, font_size=font_size) + "\n\n" + ass_events_head return ass_head def check_font(font): - win_font_path = r"C:\Windows\Fonts" - maybe_font_path = os.path.join(win_font_path, font) + fonts_path, fonts = get_fonts_info() + maybe_font_path = os.path.join(fonts_path, font) font_style_name = "微软雅黑" - font_path = os.path.join(win_font_path, fonts[font_style_name]) # 默认 + font_path = os.path.join(fonts_path, fonts[font_style_name]) # 默认 if os.path.exists(font): # 字体就在当前文件夹 或 完整路径 if os.path.isfile(font): @@ -58,7 +71,7 @@ def check_font(font): pass elif fonts.get(font): # 别名映射 - font_path = os.path.join(win_font_path, fonts.get(font)) + font_path = os.path.join(fonts_path, fonts.get(font)) font_style_name = font else: pass diff --git a/basic/vars.py b/basic/vars.py index a982ed0..c73647b 100644 --- a/basic/vars.py +++ b/basic/vars.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-04 19:14:35 -# 上次编辑时间 : 2020-01-28 17:43:44 +# 上次编辑时间 : 2020-02-07 17:57:05 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' diff --git a/config.json b/config.json new file mode 100644 index 0000000..7bb3318 --- /dev/null +++ b/config.json @@ -0,0 +1,8 @@ +{ + "fonts_base_folder": "C:/Windows/Fonts", + "fonts": { + "微软雅黑":"msyh.ttc", + "微软雅黑粗体":"msyhbd.ttc", + "微软雅黑细体":"msyhl.ttc" + } +} \ No newline at end of file diff --git a/methods/sameheight.py b/methods/sameheight.py index f60143b..d8af4a5 100644 --- a/methods/sameheight.py +++ b/methods/sameheight.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-04 19:14:47 -# 上次编辑时间: 2020-01-05 14:46:51 +# 上次编辑时间 : 2020-02-07 18:40:42 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' @@ -14,10 +14,10 @@ class SameHeight(object): ''' # 等高弹幕 --> 矩形分割问题? ''' - def __init__(self, text, font_path="msyh.ttc", font_size=14): + def __init__(self, text, ass_range: str, font_path="msyh.ttc", font_size=14): self.font = truetype(font=font_path, size=font_size) self.width, self.height = self.get_danmu_size(text) - self.height_range = [0, 720] + self.height_range = [int(n.strip()) for n in ass_range.split(",")] self.width_range = [0, 1920] self.lines_start_y = list(range(*(self.height_range + [self.height]))) self.lines_width_used = [[y, 0] for y in self.lines_start_y] @@ -49,7 +49,7 @@ class SameHeight(object): def main(): text = "测试" show_time = 13 - sh = SameHeight(text) + sh = SameHeight(text, "0,720") sh.get_xy(text, show_time) diff --git a/pfunc/dump_to_ass.py b/pfunc/dump_to_ass.py index 61f9fd8..8541a42 100644 --- a/pfunc/dump_to_ass.py +++ b/pfunc/dump_to_ass.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-04 19:17:44 -# 上次编辑时间 : 2020-01-16 20:06:23 +# 上次编辑时间 : 2020-02-07 18:17:48 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' import os @@ -17,7 +17,7 @@ def write_one_video_subtitles(file_path, comments, args): # 对于合集则每次都都得检查一次 也可以放在上一级 放在这里 考虑后面可能特殊指定字体的情况 font_path, font_style_name = check_font(args.font) ass_head = get_ass_head(font_style_name, args.font_size) - get_xy_obj = SameHeight("那就写这一句作为初始化测试吧!", font_path=font_path, font_size=int(args.font_size)) + get_xy_obj = SameHeight("那就写这一句作为初始化测试吧!", args.range, font_path=font_path, font_size=int(args.font_size)) subtitle = ASS(file_path, get_xy_obj, font=font_style_name) comments = remove_same_danmu(comments) for comment in comments: diff --git a/pfunc/request_info.py b/pfunc/request_info.py index 5311efb..d719601 100644 --- a/pfunc/request_info.py +++ b/pfunc/request_info.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-04 19:14:43 -# 上次编辑时间 : 2020-01-28 18:38:32 +# 上次编辑时间 : 2020-02-07 17:36:24 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' import re @@ -134,7 +134,7 @@ def get_year_range(aid, locale="zh_cn"): year_end = int(data["latestVideo"]["period"][:4]) return list(range(year_start, year_end + 1)) -def get_vinfo_by_tvid(tvid, locale="zh_cn"): +def get_vinfo_by_tvid(tvid, locale="zh_cn", isall=False): api_url = "https://pcw-api.iqiyi.com/video/video/baseinfo/{}".format(tvid) if locale != "zh_cn": api_url += "?locale=" + locale @@ -146,10 +146,33 @@ def get_vinfo_by_tvid(tvid, locale="zh_cn"): data = json.loads(r)["data"] if data.__class__ != dict: return None + if isall: + aid = data.get("albumId") + if aid is None: + print("通过单集tvid获取合集aid失败,将只下载单集的弹幕") + locale = check_video_area_by_tvid(tvid) + if locale is None: + locale = "zh_cn" + return get_vinfos(aid, locale=locale) name = data["name"] duration = data["durationSec"] return [[name + "_" + str(duration), duration, tvid]] +def check_video_area_by_tvid(tvid): + api_url = "https://pcw-api.iqiyi.com/video/video/playervideoinfo?tvid={}".format(tvid) + try: + r = requests.get(api_url, headers=chrome, timeout=5).content.decode("utf-8") + except Exception as e: + print("check_video_area_by_tvid error info -->", e) + return None + data = json.loads(r)["data"] + intl_flag = data["operation_base"]["is_international"] + langs = [item["language"].lower() for item in data["operation_language_base"]] + locale = "zh_cn" + if intl_flag is False and "zh_tw" in langs: + locale = "zh_tw" + return locale + def get_vinfos_by_year(aid, years: list, cid=6, locale="zh_cn"): api_url = "https://pcw-api.iqiyi.com/album/source/svlistinfo?cid={}&sourceid={}&timelist={}".format(cid, aid, ",".join([str(_) for _ in years.copy()])) if locale != "zh_cn": @@ -171,7 +194,7 @@ def get_vinfos_by_year(aid, years: list, cid=6, locale="zh_cn"): vinfos.append([ep["shortTitle"] + "_" + str(sec), sec, ep["tvId"]]) return vinfos -def get_vinfos_by_url(url): +def get_vinfos_by_url(url, isall=False): locale = check_url_locale(url) patterns = [".+?/w_(\w+?).html", ".+?/v_(\w+?).html", ".+?/a_(\w+?).html", ".+?/lib/m_(\w+?).html"] isw, isep, isas, isms = [re.match(pattern, url) for pattern in patterns] @@ -204,7 +227,7 @@ def get_vinfos_by_url(url): if isep or isw: if tvid is None: return - return get_vinfo_by_tvid(tvid, locale=locale) + return get_vinfo_by_tvid(tvid, locale=locale, isall=isall) if isas or isms: if aid is None: diff --git a/sites/iqiyi.py b/sites/iqiyi.py index d928692..3dab7bb 100644 --- a/sites/iqiyi.py +++ b/sites/iqiyi.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-04 19:14:41 -# 上次编辑时间 : 2020-01-16 19:58:51 +# 上次编辑时间 : 2020-02-07 17:32:10 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' @@ -66,8 +66,11 @@ def get_danmu_by_tvid(name, duration, tvid): def main(args): vinfos = [] + isall = False + if args.series: + isall = True if args.tvid: - vi = get_vinfo_by_tvid(args.tvid) + vi = get_vinfo_by_tvid(args.tvid, isall=isall) if vi: vinfos.append(vi) if args.aid: @@ -77,7 +80,7 @@ def main(args): if args.tvid == "" and args.aid == "" and args.url == "": args.url = input("请输入iqiyi链接:\n") if args.url: - vi = get_vinfos_by_url(args.url) + vi = get_vinfos_by_url(args.url, isall=isall) if vi: vinfos += vi subtitles = {} diff --git a/sites/mgtv.py b/sites/mgtv.py index fd1cf3c..90e6403 100644 --- a/sites/mgtv.py +++ b/sites/mgtv.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-28 15:55:22 -# 上次编辑时间 : 2020-01-28 19:57:57 +# 上次编辑时间 : 2020-02-07 18:32:05 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' import re @@ -155,7 +155,6 @@ def get_vinfos_by_url(url: str, isall: bool): if vinfo is None: return vinfos.append(vinfo) - print("ccc", cid_v1) if cid_v1 or cid_v2: if cid_v2 is None: cid = cid_v1.group(1) diff --git a/sites/sohu.py b/sites/sohu.py index 68d4f18..b0429f5 100644 --- a/sites/sohu.py +++ b/sites/sohu.py @@ -3,7 +3,7 @@ ''' # 作者: weimo # 创建日期: 2020-01-16 17:45:35 -# 上次编辑时间 : 2020-01-16 20:09:22 +# 上次编辑时间 : 2020-02-07 18:43:55 # 一个人的命运啊,当然要靠自我奋斗,但是... ''' import json @@ -99,7 +99,7 @@ def get_vinfos(aid: str): try: r = requests.get(api_url, params=params, headers=chrome, timeout=3).content.decode("gbk") except Exception as e: - print("get sohu (vid -> {}) videolist failed.".format(vid)) + print("get sohu (aid -> {}) videolist failed.".format(aid)) return None data = json.loads(r) if data.get("videos"):