From b09a6f6bb0098cc237e0c5c1c58f2ab6429cf0da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Sun, 25 Jan 2026 13:16:59 +0800 Subject: [PATCH 01/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 20 ++++++++++++++++---- src/README.md | 42 ++++++++++++++++++++---------------------- 2 files changed, 36 insertions(+), 26 deletions(-) diff --git a/.gitignore b/.gitignore index b86d0a41..b4d7b9c8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,25 +1,37 @@ +# Python 和工具缓存 __pycache__ .pytest_cache .mypy_cache .coverage + +# 虚拟环境 .venv -htmlcov + +# 构建输出 dist Annotations2Sub.egg-info + +# 覆盖率报告 +htmlcov + +# 杂项 测试用例/ -src/tests/garbage/* -!src/tests/garbage/stub -report *.mp4 *.mkv *.webm *.xml *.ass + +src/tests/garbage/* +!src/tests/garbage/stub + +report *.lnk *.ps1 *.pyz *.dot *.prof + mypy.ini uv.lock .python-version diff --git a/src/README.md b/src/README.md index f43ed35c..e05ffe54 100644 --- a/src/README.md +++ b/src/README.md @@ -1,22 +1,28 @@ # Annotations2Sub Source Code -## 快速背景 +## 概述 -本仓库是一个用于将旧版 YouTube Annotations 的 XML 文件转换为 ASS 字幕文件的命令行工具. 包的入口点是控制台脚本 `Annotations2Sub`(在 `pyproject.toml` -> `project.scripts` 中定义). 主要代码位于 `src/Annotations2Sub/`, 测试代码位于 `src/tests/`. +Annotations2Sub 是一个将旧版 YouTube Annotations 的 XML 文件转换为 ASS 字幕文件的命令行工具. 入口点是控制台脚本 `Annotations2Sub`. 主要代码位于 `src/Annotations2Sub/`, 测试代码位于 `src/tests/`. -## 组织结构 +## 技术栈 -- 目的: 读取 YouTube Annotations XML 文件并生成 ASS 字幕文件. 用户用法见 `README.md`: `Annotations2Sub `. -- 流程: 解析(`Annotations.py`)、转换(`convert.py`)、输出(`subtitles/*`). +- Python 3.7+ +- 无外部依赖 +- 使用 [uv](https://github.com/astral-sh/uv) 管理工具链, 使用 setuptools 打包, pytest 测试, mypy 类型检查, isort 和 black 进行代码格式化. + +## 架构 + +- 流程: 解析(`Annotations.py`)、转换(`convert.py`)和输出(`subtitles/*`). +- 入口: `src/Annotations2Sub/_main.py` 或 `src/Annotations2Sub/__main__.py`. - 核心模块: - - `src/Annotations2Sub/_main.py` 或 `src/Annotations2Sub/__main__.py` —— 程序入口. - - `src/Annotations2Sub/Annotations.py` —— XML 解析和Annotations数据结构. - - `src/Annotations2Sub/convert.py` —— 主要的转换逻辑和数据变换. - - `src/Annotations2Sub/subtitles/` —— 字幕格式、样式、事件和绘图辅助. + - `src/Annotations2Sub/Annotations.py` : XML 解析和Annotations数据结构. + - `src/Annotations2Sub/convert.py` : 主要转换逻辑. + - `src/Annotations2Sub/subtitles/` : 字幕格式、样式、事件和绘图辅助. +- 测试: `src/tests/` ## 如何运行、测试和代码检查 -- 推荐使用 [uv](https://github.com/astral-sh/uv) 进行依赖管理和运行. +- 使用 [uv](https://github.com/astral-sh/uv) 进行依赖管理. `uv sync` @@ -38,20 +44,12 @@ `black .` -## 项目特有的模式和约定 +## 项目特有的模式 - 测试用例是 Youtube Annotations, 使用 `src/tests/testCase/` 下的 `.test` 文件作为输入, 同时包含以 `.ass.test`、`.transform.ass.test` 等后缀的期望输出文件. -- 添加类型注解并保持 mypy 检查通过. -- 使用 isort 和 black 进行代码格式化. - 本地化: gettext `.po`/`.mo` 文件在 `src/Annotations2Sub/locales/`. 如有用户可见字符串变更, 请更新 `.po` 文件并重新生成 `.mo`. -## 集成点与外部依赖 - -- 无外部依赖. -- 构建/打包使用 setuptools. -- CI 会上传覆盖率到 Codecov. - -## 调试注释行为 +## 调试 Annotations 行为 使用[youtube_annotations_hack](https://github.com/USED255/youtube_annotations_hack)来预览正确的注释行为. @@ -61,7 +59,7 @@ ## 问题咨询 -- 在 GitHub 提 [issue](https://github.com/USED255/Annotations2Sub/issues). +请在 GitHub 提 [issue](https://github.com/USED255/Annotations2Sub/issues). ## 您也可以看看 @@ -71,7 +69,7 @@ - https://github.com/weizhenye/ASS/wiki/ASS-字幕格式规范 - 整理过的关于 ASS 字幕文件的格式以及渲染行为的文档. + 整理好的关于 ASS 字幕文件的格式以及渲染行为的文档. - https://github.com/USED255/youtube_annotations_hack From 5d402092c12fa8aff85534900092016b2be2b95a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Mon, 26 Jan 2026 23:03:44 +0800 Subject: [PATCH 02/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Annotations2Sub/Annotations.py | 45 +++++++----------------------- "\346\226\207\346\241\243.md" | 1 - 2 files changed, 10 insertions(+), 36 deletions(-) diff --git a/src/Annotations2Sub/Annotations.py b/src/Annotations2Sub/Annotations.py index eab090bf..c41e651d 100644 --- a/src/Annotations2Sub/Annotations.py +++ b/src/Annotations2Sub/Annotations.py @@ -2,6 +2,7 @@ import datetime as dt import math +import re from datetime import datetime from typing import List, Optional, Union from xml.etree.ElementTree import Element @@ -193,41 +194,15 @@ def ParseAnnotationColor(colorString: str) -> Color: def ParseTime(timeString: str) -> datetime: def parseFloat(string: str) -> float: - def cleanInt(string: str) -> str: - string = string.replace("s", "") - string = string.replace("-", "") - string = string.replace("%", "") - - if string == "NaN": - return "0" - if string == "aN": - return "0" - if "#" in string: - return "0" - return string - - if string == "": - return 0 - if string == "4294967294": - return 0 - if string == "&": - return 0 - if string == "NaN": - return 0 - - part = string.split(".") - part = list(map(cleanInt, part)) - string = part[0] - if len(part) > 1: - string = string + "." + part[1] - return float(string) - - if timeString == "": - return datetime.strptime("0", "%S") - if timeString == "never": - return datetime.strptime("0", "%S") - if timeString == "undefined": - return datetime.strptime("0", "%S") + match = re.match( + r"[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?", string.lstrip() + ) + if match != None: + number = float(match.group(0)) + if number > 2147483647: + return 0.0 + return number + return 0.0 parts = timeString.split(":") seconds = 0.0 diff --git "a/\346\226\207\346\241\243.md" "b/\346\226\207\346\241\243.md" index f90846d0..8b362c5b 100644 --- "a/\346\226\207\346\241\243.md" +++ "b/\346\226\207\346\241\243.md" @@ -462,7 +462,6 @@ subtitles_string = AnnotationsXmlStringToSubtitlesString(xml_string) with open('output.ass', 'w', encoding='utf-8') as f: f.write(subtitles_string) -# 如果你担心许可证问题, 可以联系我给你其他许可证. ``` ### 与同类软件的对比 From 8cb0b24410f60710f702e4b0e9d782c45a9fa18d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Tue, 27 Jan 2026 01:18:31 +0800 Subject: [PATCH 03/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCUMENTATION.md | 1 - src/README.md | 16 ++++++++++------ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index cbcffaa9..b84ea824 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -461,7 +461,6 @@ subtitles_string = AnnotationsXmlStringToSubtitlesString(xml_string) with open('output.ass', 'w', encoding='utf-8') as f: f.write(subtitles_string) -# If you're concerned about licensing issues, you can contact me for an alternative license. ``` ### Comparison with Similar Software diff --git a/src/README.md b/src/README.md index e05ffe54..a02a3c47 100644 --- a/src/README.md +++ b/src/README.md @@ -18,7 +18,16 @@ Annotations2Sub 是一个将旧版 YouTube Annotations 的 XML 文件转换为 A - `src/Annotations2Sub/Annotations.py` : XML 解析和Annotations数据结构. - `src/Annotations2Sub/convert.py` : 主要转换逻辑. - `src/Annotations2Sub/subtitles/` : 字幕格式、样式、事件和绘图辅助. -- 测试: `src/tests/` + - `src/Annotations2Sub/cli.py` : 用户界面. +- 测试: + - `src/tests/test_Baseline.py` : 回归测试. + - `src/tests/test_cli.py` : 集成测试. + - `src/tests/unittest/` : 其他测试. + +## 项目特有的模式 + +- 测试用例是 Youtube Annotations, 使用 `src/tests/testCase/` 下的 `.test` 文件作为输入, 同时包含以 `.ass.test`、`.transform.ass.test` 等后缀的期望输出文件. +- gettext `.po`/`.mo` 文件在 `src/Annotations2Sub/locales/`. 如有用户可见字符串变更, 请更新 `.po` 文件并重新生成 `.mo`. ## 如何运行、测试和代码检查 @@ -44,11 +53,6 @@ Annotations2Sub 是一个将旧版 YouTube Annotations 的 XML 文件转换为 A `black .` -## 项目特有的模式 - -- 测试用例是 Youtube Annotations, 使用 `src/tests/testCase/` 下的 `.test` 文件作为输入, 同时包含以 `.ass.test`、`.transform.ass.test` 等后缀的期望输出文件. -- 本地化: gettext `.po`/`.mo` 文件在 `src/Annotations2Sub/locales/`. 如有用户可见字符串变更, 请更新 `.po` 文件并重新生成 `.mo`. - ## 调试 Annotations 行为 使用[youtube_annotations_hack](https://github.com/USED255/youtube_annotations_hack)来预览正确的注释行为. From 651e4b7a02fb9fff420d97e910cc5f05b8d3179c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Wed, 28 Jan 2026 17:58:05 +0800 Subject: [PATCH 04/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Annotations2Sub/color.py | 28 ++++--------- src/tests/test_addendum.py | 72 ++++++++++++++++++++++++++++++++ src/tests/unittest/test_Color.py | 14 ------- 3 files changed, 81 insertions(+), 33 deletions(-) create mode 100644 src/tests/test_addendum.py diff --git a/src/Annotations2Sub/color.py b/src/Annotations2Sub/color.py index 81a2e614..0ad4023a 100644 --- a/src/Annotations2Sub/color.py +++ b/src/Annotations2Sub/color.py @@ -1,33 +1,23 @@ # -*- coding: utf-8 -*- +from dataclasses import dataclass + from Annotations2Sub.i18n import _ +@dataclass class Color: - def __init__( - self, - red: int = 0, - green: int = 0, - blue: int = 0, - ): - if red > 255: - raise ValueError(_('"red" 必须在 0-255 之间')) - if green > 255: - raise ValueError(_('"green" 必须在 0-255 之间')) - if blue > 255: - raise ValueError(_('"blue" 必须在 0-255 之间')) - self.red = red - self.green = green - self.blue = blue + red: int = 0 + green: int = 0 + blue: int = 0 +@dataclass class Alpha: - def __init__(self, alpha: int = 0): - if alpha > 255: - raise ValueError(_('"alpha" 必须在 0-255 之间')) - self.alpha = alpha + alpha: int = 0 +@dataclass class Rgba: def __init__(self, color: Color = Color(), alpha: Alpha = Alpha()): self.red = color.red diff --git a/src/tests/test_addendum.py b/src/tests/test_addendum.py new file mode 100644 index 00000000..6f092382 --- /dev/null +++ b/src/tests/test_addendum.py @@ -0,0 +1,72 @@ +import gettext +import os +import sys + +import pytest + +from Annotations2Sub import Annotation, Subtitles +from Annotations2Sub.i18n import internationalization +from Annotations2Sub.subtitles import Event, Style +from Annotations2Sub.utils import Err1, Warn1 + + +def test_internationalization_FileNotFoundError(): + def f(*args, **kwargs): + raise FileNotFoundError + + m = pytest.MonkeyPatch() + m.setattr(gettext, "translation", f) + + assert internationalization() + + m.undo() + + +def test_internationalization_win32(): + m = pytest.MonkeyPatch() + m.setattr(sys, "platform", "win32") + m.setattr(os, "getenv", lambda x: None) + + assert internationalization() + + m.undo() + + +def test_repr_Annotation(): + assert repr(Annotation()) == str(Annotation()) + + +def test_eq_Annotation(): + assert Annotation() == Annotation() + + +def test_repr_Style(): + assert repr(Style()) == str(Style()) + + +def test_eq_Style(): + assert Style() == Style() + + +def test_repr_Event(): + assert repr(Event()) == str(Event()) + + +def test_eq_Event(): + assert Event() == Event() + + +def test_repr_Sub(): + assert repr(Subtitles()) == str(Subtitles()) + + +def test_eq_Sub(): + assert Subtitles() == Subtitles() + + +def test_Err1(): + Err1("Test") + + +def test_Warn1(): + Warn1("Test") diff --git a/src/tests/unittest/test_Color.py b/src/tests/unittest/test_Color.py index 0a1df975..573e5588 100644 --- a/src/tests/unittest/test_Color.py +++ b/src/tests/unittest/test_Color.py @@ -12,25 +12,11 @@ def test_Color(): assert color.blue == 0 -def test_Color_ValueError(): - with pytest.raises(ValueError): - Color(256, 0, 0) - with pytest.raises(ValueError): - Color(0, 256, 0) - with pytest.raises(ValueError): - Color(0, 0, 256) - - def test_Alpha(): alpha = Alpha(0) assert alpha.alpha == 0 -def test_Alpha_ValueError(): - with pytest.raises(ValueError): - Alpha(256) - - def test_Rgba(): rgba = Rgba(Color(0, 0, 0), Alpha(0)) assert rgba.red == 0 From 0d9046f63daf5d59f89dad3f46289106473db3b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Wed, 28 Jan 2026 18:19:30 +0800 Subject: [PATCH 05/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/README.md | 3 ++- src/tests/test_addendum.py | 4 ++++ src/tests/unittest/test_Annotation.py | 8 -------- src/tests/unittest/test_Color.py | 2 -- src/tests/unittest/test_Subtitles.py | 24 ----------------------- src/tests/unittest/test_i18n.py | 28 --------------------------- src/tests/unittest/test_utils.py | 8 -------- 7 files changed, 6 insertions(+), 71 deletions(-) diff --git a/src/README.md b/src/README.md index a02a3c47..9fe1f12c 100644 --- a/src/README.md +++ b/src/README.md @@ -10,7 +10,7 @@ Annotations2Sub 是一个将旧版 YouTube Annotations 的 XML 文件转换为 A - 无外部依赖 - 使用 [uv](https://github.com/astral-sh/uv) 管理工具链, 使用 setuptools 打包, pytest 测试, mypy 类型检查, isort 和 black 进行代码格式化. -## 架构 +## 组织结构 - 流程: 解析(`Annotations.py`)、转换(`convert.py`)和输出(`subtitles/*`). - 入口: `src/Annotations2Sub/_main.py` 或 `src/Annotations2Sub/__main__.py`. @@ -22,6 +22,7 @@ Annotations2Sub 是一个将旧版 YouTube Annotations 的 XML 文件转换为 A - 测试: - `src/tests/test_Baseline.py` : 回归测试. - `src/tests/test_cli.py` : 集成测试. + - `src/tests/test_addendum.py` : 以上两个测试未覆盖的测试. - `src/tests/unittest/` : 其他测试. ## 项目特有的模式 diff --git a/src/tests/test_addendum.py b/src/tests/test_addendum.py index 6f092382..ad1416f7 100644 --- a/src/tests/test_addendum.py +++ b/src/tests/test_addendum.py @@ -1,3 +1,7 @@ +# -*- coding: utf-8 -*- + +# Baseline 和 cli 测试未覆盖的部分 + import gettext import os import sys diff --git a/src/tests/unittest/test_Annotation.py b/src/tests/unittest/test_Annotation.py index 53ecc1cc..9f2023d1 100644 --- a/src/tests/unittest/test_Annotation.py +++ b/src/tests/unittest/test_Annotation.py @@ -21,14 +21,6 @@ def test_str_Annotation(): ) -def test_repr_Annotation(): - assert repr(Annotation()) == str(Annotation()) - - -def test_eq_Annotation(): - assert Annotation() == Annotation() - - def test_Parse(): filePath = os.path.join(testCasePath, "annotations.xml.test") with open(filePath, "r", encoding="utf-8") as f: diff --git a/src/tests/unittest/test_Color.py b/src/tests/unittest/test_Color.py index 573e5588..420f31d4 100644 --- a/src/tests/unittest/test_Color.py +++ b/src/tests/unittest/test_Color.py @@ -1,7 +1,5 @@ # -*- coding: utf-8 -*- -import pytest - from Annotations2Sub.color import Alpha, Color, Rgba diff --git a/src/tests/unittest/test_Subtitles.py b/src/tests/unittest/test_Subtitles.py index fbb4e452..7133eaba 100644 --- a/src/tests/unittest/test_Subtitles.py +++ b/src/tests/unittest/test_Subtitles.py @@ -15,14 +15,6 @@ def test_str_Style(): ) -def test_repr_Style(): - assert repr(Style()) == str(Style()) - - -def test_eq_Style(): - assert Style() == Style() - - def test_Event(): assert Event() @@ -31,14 +23,6 @@ def test_str_Event(): assert str(Event()) == "Dialogue: 0,00:00:00.00,00:00:00.00,Default,,0,0,0,,\n" -def test_repr_Event(): - assert repr(Event()) == str(Event()) - - -def test_eq_Event(): - assert Event() == Event() - - def test_Sub(): assert Subtitles() @@ -61,14 +45,6 @@ def test_str_Sub(): ) -def test_repr_Sub(): - assert repr(Subtitles()) == str(Subtitles()) - - -def test_eq_Sub(): - assert Subtitles() == Subtitles() - - def test_DrawCommand(): assert str(DrawCommand(0, 0, "m")) == "m 0 0 " diff --git a/src/tests/unittest/test_i18n.py b/src/tests/unittest/test_i18n.py index 51a912b4..4c143b50 100644 --- a/src/tests/unittest/test_i18n.py +++ b/src/tests/unittest/test_i18n.py @@ -1,11 +1,5 @@ # -*- coding: utf-8 -*- -import gettext -import os -import sys - -import pytest - from Annotations2Sub.i18n import internationalization @@ -13,28 +7,6 @@ def test_internationalization(): assert internationalization() -def test_internationalization_FileNotFoundError(): - def f(*args, **kwargs): - raise FileNotFoundError - - m = pytest.MonkeyPatch() - m.setattr(gettext, "translation", f) - - assert internationalization() - - m.undo() - - -def test_internationalization_win32(): - m = pytest.MonkeyPatch() - m.setattr(sys, "platform", "win32") - m.setattr(os, "getenv", lambda x: None) - - assert internationalization() - - m.undo() - - def test_gettext(): _ = internationalization() assert _("警告: ") == "警告: " diff --git a/src/tests/unittest/test_utils.py b/src/tests/unittest/test_utils.py index 1e794967..1c7c4743 100644 --- a/src/tests/unittest/test_utils.py +++ b/src/tests/unittest/test_utils.py @@ -38,14 +38,6 @@ def test_Info(): Info("Test") -def test_Err1(): - Err1("Test") - - -def test_Warn1(): - Warn1("Test") - - def test_Err2(): Err2("Test") From e744fba2bf84a78c31468c0d30ab2cc4e102aa63 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Sat, 31 Jan 2026 00:46:54 +0800 Subject: [PATCH 06/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- DOCUMENTATION.md | 4 ++++ "\346\226\207\346\241\243.md" | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index b84ea824..93f71607 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -501,3 +501,7 @@ Metadata database of videos with annotations. [Annotations2Sub-Lite](https://a2s.liutao.page/) A web version made by AI. + +[Ar tonelico 系列 中文字幕 (Rain Shimotsuki 注释字幕还原) 合集](https://www.bilibili.com/video/BV1Ff4y1t7Dj) + +This project is a derivative of this project. diff --git "a/\346\226\207\346\241\243.md" "b/\346\226\207\346\241\243.md" index 8b362c5b..84adc23b 100644 --- "a/\346\226\207\346\241\243.md" +++ "b/\346\226\207\346\241\243.md" @@ -502,3 +502,7 @@ Annotations2Sub: [Annotations2Sub-Lite](https://a2s.liutao.page/) AI 做的网页版本. + +[Ar tonelico 系列 中文字幕 (Rain Shimotsuki 注释字幕还原) 合集](https://www.bilibili.com/video/BV1Ff4y1t7Dj) + +本项目是此项目的衍生项目. From 1ebd101ec49afb60c51d9d262f368cc178aac8d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Sat, 31 Jan 2026 00:59:53 +0800 Subject: [PATCH 07/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/lint-check.yml | 2 -- .github/workflows/python-publish.yml | 2 -- .github/workflows/test-build.yml | 2 -- .github/workflows/test.yml | 2 -- src/Annotations2Sub/__init__.py | 1 + src/tests/unittest/test_Subtitles.py | 5 +---- 6 files changed, 2 insertions(+), 12 deletions(-) diff --git a/.github/workflows/lint-check.yml b/.github/workflows/lint-check.yml index 953ab492..ce714ae4 100644 --- a/.github/workflows/lint-check.yml +++ b/.github/workflows/lint-check.yml @@ -22,8 +22,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v5 - with: - fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v6 diff --git a/.github/workflows/python-publish.yml b/.github/workflows/python-publish.yml index 4e7adf80..d26c0e41 100644 --- a/.github/workflows/python-publish.yml +++ b/.github/workflows/python-publish.yml @@ -16,8 +16,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v5 - with: - fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v6 diff --git a/.github/workflows/test-build.yml b/.github/workflows/test-build.yml index 45d78b75..c127ef1a 100644 --- a/.github/workflows/test-build.yml +++ b/.github/workflows/test-build.yml @@ -23,8 +23,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v5 - with: - fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v6 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index cf900e0c..66ec67dd 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -25,8 +25,6 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v5 - with: - fetch-depth: 0 - name: Set up Python uses: actions/setup-python@v6 diff --git a/src/Annotations2Sub/__init__.py b/src/Annotations2Sub/__init__.py index 4f272a44..808ce750 100644 --- a/src/Annotations2Sub/__init__.py +++ b/src/Annotations2Sub/__init__.py @@ -8,6 +8,7 @@ 此工具可以帮助您将 YouTube 注释转换为 ASS 字幕文件, 您可以播放或添加到视频中. """ + """ xml. etree. diff --git a/src/tests/unittest/test_Subtitles.py b/src/tests/unittest/test_Subtitles.py index 7133eaba..2baf7ccb 100644 --- a/src/tests/unittest/test_Subtitles.py +++ b/src/tests/unittest/test_Subtitles.py @@ -28,9 +28,7 @@ def test_Sub(): def test_str_Sub(): - assert ( - str(Subtitles()) - == """[Script Info] + assert str(Subtitles()) == """[Script Info] ScriptType: v4.00+ Title: Default File @@ -42,7 +40,6 @@ def test_str_Sub(): Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text """ - ) def test_DrawCommand(): From 4bc17377643bc142ee28b9758a5fd40964053ac2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Sat, 31 Jan 2026 01:51:33 +0800 Subject: [PATCH 08/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Annotations2Sub/__init__.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Annotations2Sub/__init__.py b/src/Annotations2Sub/__init__.py index 808ce750..548dc866 100644 --- a/src/Annotations2Sub/__init__.py +++ b/src/Annotations2Sub/__init__.py @@ -98,6 +98,10 @@ 随着时间流逝, 本项目所依赖的外部服务已逐渐变得不可用, 现已移除相关功能. 感谢 Invidious 和 Internet Archive 所提供的帮助. +--- + +又是时光流逝 Vibe Code 已成现实, Agents 已成长的他妈都不认识. + --- - 注释(Annotations): YouTube 的功能 - SSA(Sub Station Alpha): 字幕格式 From 515de0bd30281dca1bd5aea1f79f1d65913c8ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Sat, 31 Jan 2026 17:41:43 +0800 Subject: [PATCH 09/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Annotations2Sub/Annotations.py | 31 ++++++++++++++++++------------ src/tests/test_other.py | 9 ++++++++- 2 files changed, 27 insertions(+), 13 deletions(-) diff --git a/src/Annotations2Sub/Annotations.py b/src/Annotations2Sub/Annotations.py index c41e651d..3225a07e 100644 --- a/src/Annotations2Sub/Annotations.py +++ b/src/Annotations2Sub/Annotations.py @@ -193,29 +193,36 @@ def ParseAnnotationColor(colorString: str) -> Color: return Color(red=r, green=g, blue=b) def ParseTime(timeString: str) -> datetime: + parts = timeString.split(":") + seconds = 0.0 + + for part in parts: + time = ParseFloat(part) + seconds = 60 * seconds + abs(time) + + return datetime.fromtimestamp(seconds, dt.timezone.utc).replace(tzinfo=None) + + def ParseFloat(string: str) -> float: def parseFloat(string: str) -> float: match = re.match( r"[+-]?(\d+(\.\d*)?|\.\d+)([eE][+-]?\d+)?", string.lstrip() ) if match != None: number = float(match.group(0)) - if number > 2147483647: - return 0.0 return number return 0.0 - parts = timeString.split(":") - seconds = 0.0 - - for part in parts: - time = parseFloat(part) - seconds = 60 * seconds + abs(time) + try: + number = float(string) + except ValueError: + number = parseFloat(string) - return datetime.fromtimestamp(seconds, dt.timezone.utc).replace(tzinfo=None) + if math.isnan(number): + return 0.0 + if number > 2147483647: + return 0.0 - def ParseFloat(string: str) -> float: - string = string.replace(",", ".") - return float(string) + return number _id = each.get("id", "") if _id == "": diff --git a/src/tests/test_other.py b/src/tests/test_other.py index 1387d8b1..cac94faa 100644 --- a/src/tests/test_other.py +++ b/src/tests/test_other.py @@ -1,3 +1,10 @@ # -*- coding: utf-8 -*- -# import Annotations2Sub.__main__ +import pytest + +import Annotations2Sub.__main__ + + +def test_main(): + with pytest.raises(SystemExit): + Annotations2Sub.__main__.main() From 4875d7f47df4481e7b06f5ee9bcd0b59ade6253f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Sat, 31 Jan 2026 17:47:07 +0800 Subject: [PATCH 10/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Annotations2Sub/Annotations.py | 2 -- src/tests/test_addendum.py | 6 ++++++ src/tests/test_other.py | 10 ---------- 3 files changed, 6 insertions(+), 12 deletions(-) delete mode 100644 src/tests/test_other.py diff --git a/src/Annotations2Sub/Annotations.py b/src/Annotations2Sub/Annotations.py index 3225a07e..66d07753 100644 --- a/src/Annotations2Sub/Annotations.py +++ b/src/Annotations2Sub/Annotations.py @@ -286,8 +286,6 @@ def parseFloat(string: str) -> float: if w < 0: w = 0 - if math.isnan(w): - w = 0 author = each.get("author", "") diff --git a/src/tests/test_addendum.py b/src/tests/test_addendum.py index ad1416f7..e74ba4b1 100644 --- a/src/tests/test_addendum.py +++ b/src/tests/test_addendum.py @@ -8,6 +8,7 @@ import pytest +import Annotations2Sub.__main__ from Annotations2Sub import Annotation, Subtitles from Annotations2Sub.i18n import internationalization from Annotations2Sub.subtitles import Event, Style @@ -74,3 +75,8 @@ def test_Err1(): def test_Warn1(): Warn1("Test") + + +def test_main(): + with pytest.raises(SystemExit): + Annotations2Sub.__main__.main() diff --git a/src/tests/test_other.py b/src/tests/test_other.py deleted file mode 100644 index cac94faa..00000000 --- a/src/tests/test_other.py +++ /dev/null @@ -1,10 +0,0 @@ -# -*- coding: utf-8 -*- - -import pytest - -import Annotations2Sub.__main__ - - -def test_main(): - with pytest.raises(SystemExit): - Annotations2Sub.__main__.main() From 292fb7e7b2988c542c2196d946d24665f684694e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=88=91=E5=A6=82=E5=A4=A9=E7=BF=BC?= Date: Mon, 2 Feb 2026 00:35:41 +0800 Subject: [PATCH 11/11] =?UTF-8?q?=E6=9B=B4=E6=96=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Annotations2Sub/cli.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Annotations2Sub/cli.py b/src/Annotations2Sub/cli.py index c5fe2f04..8d5d6dcb 100644 --- a/src/Annotations2Sub/cli.py +++ b/src/Annotations2Sub/cli.py @@ -19,7 +19,7 @@ def Run(args=None) -> int: - """命令行应用的实现 + """命令行界面的实现 参数应当是 `list(str)`, 当参数为 `None` 时 `argparse` 会从 `sys.argv` 解析参数.