├── .github ├── ISSUE_TEMPLATE.md └── workflows │ ├── python-docs.yml │ ├── python-publish.yml │ └── python-test.yml ├── .gitignore ├── .pre-commit-config.yaml ├── LICENSE ├── README.md ├── docs └── source │ ├── conf.py │ ├── index.rst │ └── pyasstosrt │ ├── batch_processing.rst │ ├── cli.rst │ ├── dialogue.rst │ ├── subtitle.rst │ ├── time.rst │ └── troubleshooting.rst ├── pyasstosrt ├── __init__.py ├── batch.py ├── dialogue.py ├── pyasstosrt.py └── time.py ├── pyproject.toml ├── tests ├── conftest.py ├── sub-removing-effects.ass ├── sub.ass ├── sub_standard-removing-effects.srt ├── sub_standard.srt ├── test_batch.py ├── test_batch_import.py ├── test_clearing_effects.py ├── test_export.py ├── test_open.py ├── test_remove_duplicates.py ├── test_text_clearing.py ├── test_time.py └── test_translate.py └── uv.lock /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ### Describe the problem 2 | 3 | Tell us about the problem you're having 4 | 5 | ### Steps to reproduce 6 | 7 | Tell us how to reproduce it 8 | 9 | ### System configuration 10 | 11 | * Python version: 12 | -------------------------------------------------------------------------------- /.github/workflows/python-docs.yml: -------------------------------------------------------------------------------- 1 | name: Build and Deploy Documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | - main 8 | workflow_dispatch: 9 | 10 | permissions: 11 | contents: write 12 | 13 | jobs: 14 | docs: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Check out repository 19 | uses: actions/checkout@v4 20 | 21 | - name: Install uv 22 | uses: astral-sh/setup-uv@v5 23 | with: 24 | version: latest 25 | python-version: '3.13' 26 | enable-cache: true 27 | 28 | - name: Install project dependencies 29 | run: uv sync --all-extras --dev 30 | 31 | - name: Build documentation 32 | run: | 33 | uv run sphinx-build -b html docs/source docs/build/html 34 | 35 | - name: Deploy to GitHub Pages 36 | uses: peaceiris/actions-gh-pages@v4 37 | if: ${{ github.event_name == 'push' && (github.ref == 'refs/heads/master' || github.ref == 'refs/heads/main') || github.event_name == 'workflow_dispatch' }} 38 | with: 39 | github_token: ${{ secrets.GITHUB_TOKEN }} 40 | publish_dir: ./docs/build/html 41 | force_orphan: true 42 | -------------------------------------------------------------------------------- /.github/workflows/python-publish.yml: -------------------------------------------------------------------------------- 1 | name: Upload Python Package 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | deploy: 9 | runs-on: ubuntu-latest 10 | if: github.event_name == 'release' 11 | steps: 12 | - name: Check out repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Get the tag name for the release 16 | id: vars 17 | shell: bash 18 | run: | 19 | tag="${GITHUB_REF#refs/*/}" # refs/tags/1.2.3 -> 1.2.3 20 | echo "tag=$tag" >> $GITHUB_OUTPUT 21 | 22 | - name: Install uv 23 | uses: astral-sh/setup-uv@v5 24 | with: 25 | version: latest 26 | python-version: '3.13' 27 | enable-cache: true 28 | 29 | - name: Install project 30 | run: uv sync --all-extras 31 | 32 | - name: Build and publish 33 | shell: bash 34 | run: | 35 | uv build 36 | uv publish 37 | env: 38 | UV_PUBLISH_TOKEN: ${{ secrets.PYPI_TOKEN }} 39 | -------------------------------------------------------------------------------- /.github/workflows/python-test.yml: -------------------------------------------------------------------------------- 1 | name: Run Python Tests 2 | 3 | on: 4 | pull_request: 5 | push: 6 | 7 | jobs: 8 | test: 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest, macos-latest, windows-latest] 12 | python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13"] 13 | 14 | runs-on: ${{ matrix.os }} 15 | 16 | steps: 17 | - name: Check out repository 18 | uses: actions/checkout@v4 19 | 20 | - name: Install uv 21 | id: setup-uv 22 | uses: astral-sh/setup-uv@v5 23 | with: 24 | version: latest 25 | python-version: ${{ matrix.python-version }} 26 | enable-cache: true 27 | 28 | - name: Install dependencies 29 | run: | 30 | uv sync --all-extras --dev 31 | 32 | - name: List installed packages (uv demonstration) 33 | run: uv pip list 34 | 35 | - name: Run tests and collect coverage 36 | run: | 37 | uv run pytest --cov=pyasstosrt tests/ --cov-report=xml --cov-report=term --junit-xml=./test-results/junit.xml 38 | shell: bash 39 | 40 | - name: Upload coverage to Codecov 41 | uses: codecov/codecov-action@v4 42 | with: 43 | files: ./coverage.xml 44 | env_vars: OS,PYTHON 45 | verbose: true 46 | env: 47 | CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} 48 | OS: ${{ matrix.os }} 49 | PYTHON: ${{ matrix.python-version }} 50 | 51 | - name: Publish Test Report 52 | uses: mikepenz/action-junit-report@v4 53 | if: success() || failure() # always run even if the previous step fails 54 | with: 55 | report_paths: './test-results/junit.xml' 56 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | build/ 14 | develop-eggs/ 15 | dist/ 16 | downloads/ 17 | eggs/ 18 | .eggs/ 19 | lib/ 20 | lib64/ 21 | parts/ 22 | sdist/ 23 | var/ 24 | wheels/ 25 | pip-wheel-metadata/ 26 | share/python-wheels/ 27 | *.egg-info/ 28 | .installed.cfg 29 | *.egg 30 | MANIFEST 31 | 32 | # PyInstaller 33 | # Usually these files are written by a python script from a template 34 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 35 | *.manifest 36 | *.spec 37 | 38 | # Installer logs 39 | pip-log.txt 40 | pip-delete-this-directory.txt 41 | 42 | # Unit test / coverage reports 43 | htmlcov/ 44 | .tox/ 45 | .nox/ 46 | .coverage 47 | .coverage.* 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | *.cover 52 | *.py,cover 53 | .hypothesis/ 54 | .pytest_cache/ 55 | 56 | # Translations 57 | *.mo 58 | *.pot 59 | 60 | # Django stuff: 61 | *.log 62 | local_settings.py 63 | db.sqlite3 64 | db.sqlite3-journal 65 | 66 | # Flask stuff: 67 | instance/ 68 | .webassets-cache 69 | 70 | # Scrapy stuff: 71 | .scrapy 72 | 73 | # Sphinx documentation 74 | docs/_build/ 75 | 76 | # PyBuilder 77 | target/ 78 | 79 | # Jupyter Notebook 80 | .ipynb_checkpoints 81 | 82 | # IPython 83 | profile_default/ 84 | ipython_config.py 85 | 86 | # pyenv 87 | .python-version 88 | 89 | # pipenv 90 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 91 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 92 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 93 | # install all needed dependencies. 94 | #Pipfile.lock 95 | 96 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 97 | __pypackages__/ 98 | 99 | # Celery stuff 100 | celerybeat-schedule 101 | celerybeat.pid 102 | 103 | # SageMath parsed files 104 | *.sage.py 105 | 106 | # Environments 107 | .env 108 | .venv 109 | env/ 110 | venv/ 111 | ENV/ 112 | env.bak/ 113 | venv.bak/ 114 | 115 | # Spyder project settings 116 | .spyderproject 117 | .spyproject 118 | 119 | # Rope project settings 120 | .ropeproject 121 | 122 | # mkdocs documentation 123 | /site 124 | 125 | # mypy 126 | .mypy_cache/ 127 | .dmypy.json 128 | dmypy.json 129 | 130 | # Pyre type checker 131 | .pyre/ 132 | 133 | ### JetBrains template 134 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm 135 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 136 | 137 | # User-specific stuff 138 | .idea/**/workspace.xml 139 | .idea/**/tasks.xml 140 | .idea/**/usage.statistics.xml 141 | .idea/**/dictionaries 142 | .idea/**/shelf 143 | 144 | # Generated files 145 | .idea/**/contentModel.xml 146 | 147 | # Sensitive or high-churn files 148 | .idea/**/dataSources/ 149 | .idea/**/dataSources.ids 150 | .idea/**/dataSources.local.xml 151 | .idea/**/sqlDataSources.xml 152 | .idea/**/dynamic.xml 153 | .idea/**/uiDesigner.xml 154 | .idea/**/dbnavigator.xml 155 | 156 | # Gradle 157 | .idea/**/gradle.xml 158 | .idea/**/libraries 159 | 160 | # Gradle and Maven with auto-import 161 | # When using Gradle or Maven with auto-import, you should exclude module files, 162 | # since they will be recreated, and may cause churn. Uncomment if using 163 | # auto-import. 164 | # .idea/artifacts 165 | # .idea/compiler.xml 166 | # .idea/modules.xml 167 | # .idea/*.iml 168 | # .idea/modules 169 | # *.iml 170 | # *.ipr 171 | 172 | # CMake 173 | cmake-build-*/ 174 | 175 | # Mongo Explorer plugin 176 | .idea/**/mongoSettings.xml 177 | 178 | # File-based project format 179 | *.iws 180 | 181 | # IntelliJ 182 | out/ 183 | 184 | # mpeltonen/sbt-idea plugin 185 | .idea_modules/ 186 | 187 | # JIRA plugin 188 | atlassian-ide-plugin.xml 189 | 190 | # Cursive Clojure plugin 191 | .idea/replstate.xml 192 | 193 | # Crashlytics plugin (for Android Studio and IntelliJ) 194 | com_crashlytics_export_strings.xml 195 | crashlytics.properties 196 | crashlytics-build.properties 197 | fabric.properties 198 | 199 | # Editor-based Rest Client 200 | .idea/httpRequests 201 | 202 | # Android studio 3.1+ serialized cache file 203 | .idea/caches/build_file_checksums.ser 204 | 205 | /.idea/ 206 | /simple.py 207 | /tests/sub.srt 208 | /tests/test/sub.srt 209 | -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | default_stages: [pre-commit] 2 | 3 | repos: 4 | - repo: https://github.com/pre-commit/pre-commit-hooks 5 | rev: v5.0.0 6 | hooks: 7 | - id: trailing-whitespace 8 | exclude: ^tests/.*\.(ass|srt)$ 9 | - id: end-of-file-fixer 10 | exclude: ^tests/.*\.(ass|srt)$ 11 | - id: check-json 12 | - id: check-toml 13 | - id: check-xml 14 | - id: check-yaml 15 | - id: debug-statements 16 | - id: check-builtin-literals 17 | - id: check-case-conflict 18 | - id: check-docstring-first 19 | - id: detect-private-key 20 | 21 | - repo: https://github.com/astral-sh/ruff-pre-commit 22 | rev: v0.11.2 23 | hooks: 24 | - id: ruff 25 | args: [ --fix ] 26 | types_or: [ python, pyi ] 27 | - id: ruff-format 28 | types_or: [ python, pyi ] 29 | 30 | - repo: https://github.com/astral-sh/uv-pre-commit 31 | rev: 0.6.9 32 | hooks: 33 | - id: uv-lock 34 | 35 | # sets up .pre-commit-ci.yaml to ensure pre-commit dependencies stay up to date 36 | ci: 37 | autoupdate_schedule: weekly 38 | skip: [] 39 | submodules: false 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | pyasstosrt 2 | ================================================================================================================================================================================= 3 | 4 | [![Downloads](https://pepy.tech/badge/pyasstosrt)](https://pepy.tech/project/pyasstosrt) [![codecov](https://codecov.io/gh/GitBib/pyasstosrt/branch/master/graph/badge.svg?token=VGTJ3NYHOV)](https://codecov.io/gh/GitBib/pyasstosrt) 5 | 6 | **pyasstosrt** – this tool will help you convert Advanced SubStation Alpha (ASS/SSA) subtitle files to SubRip (SRT) files. 7 | 8 | Support for str path: 9 | ```python 10 | from pyasstosrt import Subtitle 11 | 12 | sub = Subtitle('sub.ass') 13 | sub.export() 14 | ``` 15 | 16 | Support for all Path-like objects, instead of only pathlib's Path: 17 | 18 | ```python 19 | from pathlib import Path 20 | 21 | from pyasstosrt import Subtitle 22 | 23 | path = Path('sub.ass') 24 | sub = Subtitle(path) 25 | sub.export() 26 | ``` 27 | 28 | You can get a sheet with dialogue by specifying output_dialogues. 29 | 30 | ```python 31 | from pathlib import Path 32 | 33 | from pyasstosrt import Subtitle 34 | 35 | path = Path('sub.ass') 36 | sub = Subtitle(path) 37 | sub.export(output_dialogues=True) 38 | ``` 39 | 40 | If you want to remove effects from text, you can use the removing_effects. 41 | 42 | ```python 43 | from pyasstosrt import Subtitle 44 | 45 | sub = Subtitle('sub.ass', removing_effects=True) 46 | sub.export() 47 | ``` 48 | 49 | You can enable the deletion of duplicate lines with the rearrangement of start and end times. 50 | 51 | ```python 52 | from pyasstosrt import Subtitle 53 | 54 | sub = Subtitle('sub.ass', remove_duplicates=True) 55 | sub.export() 56 | ``` 57 | CLI 58 | ------------ 59 | ```bash 60 | pyasstosrt export /Users/user/sub/sub.ass 61 | ``` 62 | 63 | **Optional** You can specify an export folder. 64 | ```bash 65 | pyasstosrt export /Users/user/sub/sub.ass --output-dir /Users/user/sub/srt 66 | ``` 67 | 68 | **Optional** If you want to remove effects from text, you can use the --remove-effects flag. 69 | ```bash 70 | pyasstosrt export /Users/user/sub/sub.ass --remove-effects --output-dir /Users/user/sub/srt 71 | ``` 72 | 73 | **Optional** If you need to remove duplicates, you can use the --remove-duplicates flag. 74 | ```bash 75 | pyasstosrt export /Users/user/sub/sub.ass --remove-duplicates 76 | ``` 77 | 78 | **Optional** You can use the flags together --remove-duplicates --remove-effects 79 | ```bash 80 | pyasstosrt export /Users/user/sub/sub.ass --remove-duplicates --remove-effects 81 | ``` 82 | Installation 83 | ------------ 84 | Most users will want to simply install the latest version, hosted on PyPI: 85 | 86 | $ pip install 'pyasstosrt[cli]' 87 | 88 | If you just want to use it as a library and don't need the CLI, you can omit the `[cli]` extra. 89 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # http://www.sphinx-doc.org/en/master/config 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | 13 | import os 14 | import sys 15 | from datetime import datetime 16 | 17 | import tomli 18 | 19 | sys.path.insert(0, os.path.abspath("../..")) 20 | 21 | 22 | # Read version from pyproject.toml 23 | def get_version_from_pyproject(): 24 | pyproject_path = os.path.join(os.path.abspath("../.."), "pyproject.toml") 25 | if not os.path.exists(pyproject_path): 26 | return "unknown" 27 | 28 | with open(pyproject_path, "rb") as f: 29 | try: 30 | pyproject_data = tomli.load(f) 31 | return pyproject_data.get("project", {}).get("version", "unknown") 32 | except Exception: 33 | return "unknown" 34 | 35 | 36 | # -- Project information ----------------------------------------------------- 37 | 38 | project = "pyasstosrt" 39 | copyright = f"{datetime.now().year}, GitBib" 40 | author = "GitBib" 41 | 42 | # The full version, including alpha/beta/rc tags 43 | release = get_version_from_pyproject() 44 | 45 | 46 | # -- General configuration --------------------------------------------------- 47 | 48 | # Add any Sphinx extension module names here, as strings. They can be 49 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 50 | # ones. 51 | extensions = [ 52 | "sphinx.ext.autodoc", 53 | "sphinx.ext.coverage", 54 | "sphinx.ext.napoleon", 55 | "sphinx_immaterial", 56 | ] 57 | 58 | # Add any paths that contain templates here, relative to this directory. 59 | templates_path = ["_templates"] 60 | 61 | # List of patterns, relative to source directory, that match files and 62 | # directories to ignore when looking for source files. 63 | # This pattern also affects html_static_path and html_extra_path. 64 | exclude_patterns = [] 65 | 66 | master_doc = "index" 67 | 68 | 69 | # -- Options for HTML output ------------------------------------------------- 70 | 71 | # The theme to use for HTML and HTML Help pages. See the documentation for 72 | # a list of builtin themes. 73 | # 74 | html_theme = "sphinx_immaterial" 75 | 76 | # Add any paths that contain custom static files (such as style sheets) here, 77 | # relative to this directory. They are copied after the builtin static files, 78 | # so a file named "default.css" will overwrite the builtin "default.css". 79 | html_static_path = ["_static"] 80 | 81 | 82 | # Material theme options (see theme.conf for more information) 83 | html_theme_options = { 84 | "icon": { 85 | "repo": "fontawesome/brands/github", 86 | "edit": "material/file-edit-outline", 87 | }, 88 | "site_url": "https://gitbib.github.io/pyasstosrt/", 89 | "repo_url": "https://github.com/GitBib/pyasstosrt", 90 | "repo_name": "pyasstosrt", 91 | "edit_uri": "blob/main/docs", 92 | "globaltoc_collapse": True, 93 | "features": [ 94 | "navigation.expand", 95 | "navigation.sections", 96 | "navigation.top", 97 | "search.share", 98 | "toc.follow", 99 | "toc.sticky", 100 | "content.tabs.link", 101 | "announce.dismiss", 102 | ], 103 | "palette": [ 104 | { 105 | "media": "(prefers-color-scheme: light)", 106 | "scheme": "default", 107 | "primary": "light-green", 108 | "accent": "light-blue", 109 | "toggle": { 110 | "icon": "material/lightbulb-outline", 111 | "name": "Switch to dark mode", 112 | }, 113 | }, 114 | { 115 | "media": "(prefers-color-scheme: dark)", 116 | "scheme": "slate", 117 | "primary": "deep-orange", 118 | "accent": "lime", 119 | "toggle": { 120 | "icon": "material/lightbulb", 121 | "name": "Switch to light mode", 122 | }, 123 | }, 124 | ], 125 | "toc_title_is_page_title": True, 126 | "social": [ 127 | { 128 | "icon": "fontawesome/brands/github", 129 | "link": "https://github.com/GitBib/pyasstosrt", 130 | "name": "Source on github.com", 131 | }, 132 | { 133 | "icon": "fontawesome/brands/python", 134 | "link": "https://pypi.org/project/pyasstosrt/", 135 | }, 136 | ], 137 | } 138 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | pyasstosrt 2 | ========== 3 | 4 | Welcome to the pyasstosrt documentation! Here you will find information about the core functionality and examples of how to use the library. 5 | 6 | Overview 7 | -------- 8 | 9 | pyasstosrt is a Python library for converting Advanced SubStation Alpha (ASS/SSA) subtitle files to SubRip (SRT) format. It provides a simple and efficient way to transform subtitle files between these formats. 10 | 11 | Main Features 12 | ------------- 13 | 14 | - Convert ASS/SSA subtitles to SRT format 15 | - Remove effects from subtitle text (optional) 16 | - Remove and merge consecutive duplicate dialogues (optional) 17 | - Support for both string paths and Path-like objects 18 | - Command-line interface (CLI) for easy usage 19 | 20 | Installation 21 | ------------ 22 | 23 | To install pyasstosrt from PyPI, use the following command: 24 | 25 | .. code-block:: bash 26 | 27 | $ pip install 'pyasstosrt[cli]' 28 | 29 | If you don't need the CLI functionality, you can install the library without extras: 30 | 31 | .. code-block:: bash 32 | 33 | $ pip install pyasstosrt 34 | 35 | For development purposes, you can clone the repository and install it in editable mode: 36 | 37 | .. code-block:: bash 38 | 39 | $ git clone https://github.com/GitBib/pyasstosrt.git 40 | $ cd pyasstosrt 41 | $ pip install -e . 42 | 43 | You can also run pyasstosrt without installation using ``uvx``: 44 | 45 | .. code-block:: bash 46 | 47 | $ uvx --from 'pyasstosrt[cli]' pyasstosrt export * --remove-effects --remove-duplicates 48 | 49 | Quick Start 50 | ----------- 51 | 52 | Here's a basic example of how to use pyasstosrt: 53 | 54 | .. code-block:: python 55 | 56 | from pyasstosrt import Subtitle 57 | 58 | # Convert a single file 59 | sub = Subtitle('subtitle.ass') 60 | sub.export() 61 | 62 | # Convert with effects removal 63 | sub = Subtitle('subtitle.ass', removing_effects=True) 64 | sub.export() 65 | 66 | # Convert with duplicate removal 67 | sub = Subtitle('subtitle.ass', remove_duplicates=True) 68 | sub.export() 69 | 70 | # Convert with custom output directory and encoding 71 | sub = Subtitle('subtitle.ass') 72 | sub.export(output_dir='output', encoding='utf-8') 73 | 74 | Command Line Interface 75 | -------------------- 76 | 77 | The library provides a command-line interface for easy usage: 78 | 79 | .. code-block:: bash 80 | 81 | # Convert a single file 82 | pyasstosrt export subtitle.ass 83 | 84 | # Convert multiple files 85 | pyasstosrt export file1.ass file2.ass 86 | 87 | # Convert with effects removal 88 | pyasstosrt export subtitle.ass --remove-effects 89 | 90 | # Convert with duplicate removal 91 | pyasstosrt export subtitle.ass --remove-duplicates 92 | 93 | # Convert with custom output directory 94 | pyasstosrt export subtitle.ass --output-dir ./output 95 | 96 | # Convert with custom encoding 97 | pyasstosrt export subtitle.ass --encoding utf-8 98 | 99 | # Print dialogues to console 100 | pyasstosrt export subtitle.ass --output-dialogues 101 | 102 | # Run without installation using uvx 103 | uvx --from 'pyasstosrt[cli]' pyasstosrt export * --remove-effects --remove-duplicates 104 | 105 | For more details on the CLI, see the :doc:`CLI documentation `. 106 | 107 | Documentation 108 | ------------ 109 | 110 | .. toctree:: 111 | :maxdepth: 2 112 | :caption: User Guide 113 | 114 | pyasstosrt/cli 115 | pyasstosrt/batch_processing 116 | pyasstosrt/troubleshooting 117 | 118 | API Reference 119 | ------------ 120 | 121 | .. toctree:: 122 | :maxdepth: 2 123 | :caption: API Reference 124 | 125 | pyasstosrt/subtitle 126 | pyasstosrt/dialogue 127 | pyasstosrt/time 128 | 129 | Indices and tables 130 | ------------------ 131 | 132 | * :ref:`genindex` 133 | * :ref:`modindex` 134 | * :ref:`search` 135 | -------------------------------------------------------------------------------- /docs/source/pyasstosrt/batch_processing.rst: -------------------------------------------------------------------------------- 1 | Batch Processing 2 | =============== 3 | 4 | PyAssToSrt provides multiple ways to batch process subtitle files. This guide demonstrates various approaches for processing multiple files at once. 5 | 6 | Using the Command Line Interface 7 | -------------------------------- 8 | 9 | The simplest way to process multiple files is using the CLI: 10 | 11 | .. code-block:: bash 12 | 13 | pyasstosrt export file1.ass file2.ass file3.ass 14 | 15 | You can also use glob patterns through your shell: 16 | 17 | .. code-block:: bash 18 | 19 | pyasstosrt export ./subtitles/*.ass 20 | 21 | All CLI options are applied to every file being processed: 22 | 23 | .. code-block:: bash 24 | 25 | pyasstosrt export ./subtitles/*.ass --remove-effects --remove-duplicates --output-dir ./output 26 | 27 | Using Python Script 28 | ------------------ 29 | 30 | For more complex scenarios, you can write a Python script to process files: 31 | 32 | Basic Batch Processing 33 | ~~~~~~~~~~~~~~~~~~~~~ 34 | 35 | .. code-block:: python 36 | 37 | import glob 38 | from pathlib import Path 39 | from pyasstosrt import Subtitle 40 | 41 | # Get all ASS files in a directory 42 | ass_files = glob.glob("./subtitles/*.ass") 43 | 44 | # Process each file 45 | for file_path in ass_files: 46 | try: 47 | sub = Subtitle(file_path) 48 | sub.export(output_dir="./output") 49 | print(f"Converted: {file_path}") 50 | except Exception as e: 51 | print(f"Error converting {file_path}: {e}") 52 | 53 | Advanced Batch Processing 54 | ~~~~~~~~~~~~~~~~~~~~~~~~ 55 | 56 | .. code-block:: python 57 | 58 | import os 59 | from pathlib import Path 60 | from concurrent.futures import ThreadPoolExecutor 61 | from pyasstosrt import Subtitle 62 | 63 | def process_file(file_path, remove_effects=False, remove_duplicates=False): 64 | try: 65 | sub = Subtitle( 66 | file_path, 67 | removing_effects=remove_effects, 68 | remove_duplicates=remove_duplicates 69 | ) 70 | output_path = Path("./output") / Path(file_path).stem 71 | sub.export(output_dir=output_path) 72 | return f"Success: {file_path}" 73 | except Exception as e: 74 | return f"Error: {file_path} - {str(e)}" 75 | 76 | # Get all ASS files recursively 77 | def get_all_ass_files(root_dir): 78 | ass_files = [] 79 | for root, _, files in os.walk(root_dir): 80 | for file in files: 81 | if file.endswith(".ass"): 82 | ass_files.append(os.path.join(root, file)) 83 | return ass_files 84 | 85 | # Process files in parallel 86 | def batch_process(directory, max_workers=4): 87 | ass_files = get_all_ass_files(directory) 88 | os.makedirs("./output", exist_ok=True) 89 | 90 | with ThreadPoolExecutor(max_workers=max_workers) as executor: 91 | results = list(executor.map( 92 | process_file, 93 | ass_files, 94 | [True] * len(ass_files), # remove_effects=True for all files 95 | [True] * len(ass_files) # remove_duplicates=True for all files 96 | )) 97 | 98 | for result in results: 99 | print(result) 100 | 101 | if __name__ == "__main__": 102 | batch_process("./subtitles") 103 | 104 | Custom Processing Logic 105 | ~~~~~~~~~~~~~~~~~~~~~ 106 | 107 | .. code-block:: python 108 | 109 | from pathlib import Path 110 | from pyasstosrt import Subtitle 111 | 112 | def custom_process(file_path, output_dir): 113 | # Read ASS file 114 | sub = Subtitle(file_path) 115 | 116 | # Perform conversion 117 | sub.convert() 118 | 119 | # Custom processing - filter dialogues 120 | filtered_dialogues = [] 121 | for dialogue in sub.dialogues: 122 | # Example: Keep only dialogues longer than 2 seconds 123 | duration = dialogue.end - dialogue.start 124 | if duration > 2.0: 125 | filtered_dialogues.append(dialogue) 126 | 127 | # Replace original dialogues with filtered ones 128 | sub.dialogues = filtered_dialogues 129 | 130 | # Export the result 131 | sub.export(output_dir=output_dir) 132 | 133 | # Process a file with custom logic 134 | custom_process("./subtitles/file.ass", "./output") 135 | 136 | Tips and Best Practices 137 | ---------------------- 138 | 139 | 1. **Error Handling**: Always include error handling to prevent the entire batch from failing if one file has issues. 140 | 141 | 2. **Output Organization**: Consider organizing output files in a structured way, especially for large batches. 142 | 143 | 3. **Progress Reporting**: For large batches, add progress reporting to track the conversion process. 144 | 145 | 4. **Performance**: Use parallel processing for large batches, but be mindful of system resources. 146 | 147 | 5. **Validation**: Consider adding validation of the converted SRT files to ensure they meet your requirements. 148 | -------------------------------------------------------------------------------- /docs/source/pyasstosrt/cli.rst: -------------------------------------------------------------------------------- 1 | Command Line Interface 2 | ===================== 3 | 4 | PyAssToSrt provides a command-line interface (CLI) for easy batch conversion of ASS subtitle files. The CLI is available when you install the package with the `cli` extra: 5 | 6 | .. code-block:: bash 7 | 8 | pip install 'pyasstosrt[cli]' 9 | 10 | Basic Usage 11 | ---------- 12 | 13 | The basic command syntax is: 14 | 15 | .. code-block:: bash 16 | 17 | pyasstosrt export [OPTIONS] FILEPATH... 18 | 19 | Where `FILEPATH...` is one or more paths to ASS subtitle files. 20 | 21 | Options 22 | ------- 23 | 24 | The CLI supports the following options: 25 | 26 | ``--remove-effects, -r`` 27 | Remove effects from subtitles. 28 | 29 | ``--remove-duplicates, -d`` 30 | Remove duplicate subtitles. 31 | 32 | ``--output-dir, -o PATH`` 33 | Output directory for the SRT file(s). 34 | 35 | ``--encoding, -e TEXT`` 36 | Encoding for the output file. Default is "utf8". 37 | 38 | ``--output-dialogues, -p`` 39 | Print dialogues to console. 40 | 41 | ``--version, -v`` 42 | Show version and exit. 43 | 44 | Examples 45 | -------- 46 | 47 | Basic Conversion 48 | ~~~~~~~~~~~~~~~ 49 | 50 | Convert a single ASS file to SRT: 51 | 52 | .. code-block:: bash 53 | 54 | pyasstosrt export subtitle.ass 55 | 56 | Running Without Installation 57 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 58 | 59 | You can run pyasstosrt without installing it using tools like ``uvx``: 60 | 61 | .. code-block:: bash 62 | 63 | uvx --from 'pyasstosrt[cli]' pyasstosrt export * --remove-effects --remove-duplicates 64 | 65 | This command will use all ASS files in the current directory, remove effects and duplicates, and convert them to SRT format. 66 | 67 | Convert Multiple Files 68 | ~~~~~~~~~~~~~~~~~~~~ 69 | 70 | Process multiple files at once: 71 | 72 | .. code-block:: bash 73 | 74 | pyasstosrt export file1.ass file2.ass file3.ass 75 | 76 | Remove Effects 77 | ~~~~~~~~~~~~ 78 | 79 | Convert and remove visual effects from the subtitle text: 80 | 81 | .. code-block:: bash 82 | 83 | pyasstosrt export subtitle.ass --remove-effects 84 | 85 | Remove Duplicates 86 | ~~~~~~~~~~~~~~~ 87 | 88 | Convert and remove/merge consecutive duplicate dialogues: 89 | 90 | .. code-block:: bash 91 | 92 | pyasstosrt export subtitle.ass --remove-duplicates 93 | 94 | Custom Output Directory 95 | ~~~~~~~~~~~~~~~~~~~~ 96 | 97 | Save the converted file(s) to a specific directory: 98 | 99 | .. code-block:: bash 100 | 101 | pyasstosrt export subtitle.ass --output-dir ./output_folder 102 | 103 | Custom Encoding 104 | ~~~~~~~~~~~~~ 105 | 106 | Specify the encoding for the output file: 107 | 108 | .. code-block:: bash 109 | 110 | pyasstosrt export subtitle.ass --encoding utf-16 111 | 112 | Print Dialogues 113 | ~~~~~~~~~~~~~ 114 | 115 | Convert and print the dialogues to the console: 116 | 117 | .. code-block:: bash 118 | 119 | pyasstosrt export subtitle.ass --output-dialogues 120 | 121 | Combine Options 122 | ~~~~~~~~~~~~~ 123 | 124 | You can combine multiple options: 125 | 126 | .. code-block:: bash 127 | 128 | pyasstosrt export subtitle.ass --remove-effects --remove-duplicates --output-dir ./output 129 | -------------------------------------------------------------------------------- /docs/source/pyasstosrt/dialogue.rst: -------------------------------------------------------------------------------- 1 | Dialogue 2 | ======== 3 | 4 | .. currentmodule:: pyasstosrt 5 | 6 | .. autoclass:: Dialogue 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | :inherited-members: 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | :nosignatures: 16 | :toctree: _autosummary 17 | 18 | ~Dialogue.get_timestamp 19 | ~Dialogue.__str__ 20 | 21 | .. rubric:: Attributes 22 | 23 | .. autosummary:: 24 | :nosignatures: 25 | :toctree: _autosummary 26 | 27 | ~Dialogue.index 28 | ~Dialogue.start 29 | ~Dialogue.end 30 | ~Dialogue.text 31 | 32 | .. rubric:: Examples 33 | 34 | Basic usage: 35 | 36 | .. code-block:: python 37 | 38 | from pyasstosrt import Dialogue, Time 39 | 40 | # Create a dialogue entry 41 | dialogue = Dialogue( 42 | index=1, 43 | start="0:00:10.00", 44 | end="0:00:15.00", 45 | text="Hello, world!" 46 | ) 47 | 48 | # Get timestamp 49 | timestamp = dialogue.get_timestamp() 50 | print(timestamp) # 00:00:10,000 --> 00:00:15,000 51 | 52 | # Convert to string (SRT format) 53 | srt_format = str(dialogue) 54 | print(srt_format) 55 | # 1 56 | # 00:00:10,000 --> 00:00:15,000 57 | # Hello, world! 58 | -------------------------------------------------------------------------------- /docs/source/pyasstosrt/subtitle.rst: -------------------------------------------------------------------------------- 1 | Subtitle 2 | ======== 3 | 4 | .. currentmodule:: pyasstosrt 5 | 6 | .. autoclass:: Subtitle 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | :inherited-members: 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | :nosignatures: 16 | :toctree: _autosummary 17 | 18 | ~Subtitle.convert 19 | ~Subtitle.export 20 | ~Subtitle.get_text 21 | ~Subtitle.remove_duplicates 22 | ~Subtitle.subtitle_formatting 23 | ~Subtitle.text_clearing 24 | ~Subtitle.merged_dialogues 25 | 26 | .. rubric:: Attributes 27 | 28 | .. autosummary:: 29 | :nosignatures: 30 | :toctree: _autosummary 31 | 32 | ~Subtitle.filepath 33 | ~Subtitle.file 34 | ~Subtitle.raw_text 35 | ~Subtitle.dialogues 36 | ~Subtitle.removing_effects 37 | ~Subtitle.is_remove_duplicates 38 | 39 | .. rubric:: Examples 40 | 41 | Basic usage: 42 | 43 | .. code-block:: python 44 | 45 | from pyasstosrt import Subtitle 46 | 47 | # Convert a single file 48 | sub = Subtitle('subtitle.ass') 49 | sub.export() 50 | 51 | # Convert with effects removal 52 | sub = Subtitle('subtitle.ass', removing_effects=True) 53 | sub.export() 54 | 55 | # Convert with duplicate removal 56 | sub = Subtitle('subtitle.ass', remove_duplicates=True) 57 | sub.export() 58 | 59 | # Convert with custom output directory and encoding 60 | sub = Subtitle('subtitle.ass') 61 | sub.export(output_dir='output', encoding='utf-8') 62 | 63 | # Get dialogues without exporting 64 | sub = Subtitle('subtitle.ass') 65 | dialogues = sub.export(output_dialogues=True) 66 | 67 | Examples 68 | -------- 69 | 70 | Basic Usage 71 | ---------- 72 | 73 | .. code-block:: python 74 | 75 | from pyasstosrt import Subtitle 76 | 77 | # Convert ASS/SSA file to SRT 78 | sub = Subtitle(filepath='input.ass') 79 | sub.convert() 80 | sub.export() 81 | 82 | # Access dialogues 83 | for dialogue in sub.dialogues: 84 | print(f"{dialogue.start} -> {dialogue.end}: {dialogue.text}") 85 | 86 | Advanced Usage 87 | ------------- 88 | 89 | .. code-block:: python 90 | 91 | from pyasstosrt import Subtitle 92 | 93 | # Convert with options 94 | sub = Subtitle( 95 | filepath='input.ass', 96 | removing_effects=True, 97 | remove_duplicates=True 98 | ) 99 | sub.convert() 100 | sub.export('output/directory', encoding='utf-8') 101 | -------------------------------------------------------------------------------- /docs/source/pyasstosrt/time.rst: -------------------------------------------------------------------------------- 1 | Time 2 | ==== 3 | 4 | .. currentmodule:: pyasstosrt 5 | 6 | .. autoclass:: Time 7 | :members: 8 | :undoc-members: 9 | :show-inheritance: 10 | :inherited-members: 11 | 12 | .. rubric:: Methods 13 | 14 | .. autosummary:: 15 | :nosignatures: 16 | :toctree: _autosummary 17 | 18 | ~Time.__init__ 19 | ~Time.__sub__ 20 | ~Time.__str__ 21 | 22 | .. rubric:: Attributes 23 | 24 | .. autosummary:: 25 | :nosignatures: 26 | :toctree: _autosummary 27 | 28 | ~Time.hour 29 | ~Time.minute 30 | ~Time.second 31 | ~Time.millisecond 32 | 33 | .. rubric:: Examples 34 | 35 | Basic usage: 36 | 37 | .. code-block:: python 38 | 39 | from pyasstosrt import Time 40 | 41 | # Create time objects 42 | time1 = Time("1:23:45.67") 43 | time2 = Time("0:00:10.00") 44 | 45 | # Access components 46 | print(time1.hour) # 1 47 | print(time1.minute) # 23 48 | print(time1.second) # 45 49 | print(time1.millisecond) # 670 50 | 51 | # Calculate duration 52 | duration = time1 - time2 53 | print(duration) # 5023.67 (seconds) 54 | 55 | # Convert to string (SRT format) 56 | print(str(time1)) # 01:23:45,670 57 | print(str(time2)) # 00:00:10,000 58 | -------------------------------------------------------------------------------- /docs/source/pyasstosrt/troubleshooting.rst: -------------------------------------------------------------------------------- 1 | Troubleshooting 2 | ============== 3 | 4 | This guide covers common issues that may arise when using pyasstosrt and how to solve them. 5 | 6 | Installation Issues 7 | ----------------- 8 | 9 | CLI Tools Not Found 10 | ~~~~~~~~~~~~~~~~~ 11 | 12 | **Problem**: After installing pyasstosrt, the CLI command isn't available. 13 | 14 | **Solution**: Make sure you installed the package with the CLI extras: 15 | 16 | .. code-block:: bash 17 | 18 | pip install 'pyasstosrt[cli]' 19 | 20 | If you've already installed without the extras, you can upgrade your installation: 21 | 22 | .. code-block:: bash 23 | 24 | pip install --upgrade 'pyasstosrt[cli]' 25 | 26 | Dependency Conflicts 27 | ~~~~~~~~~~~~~~~~~ 28 | 29 | **Problem**: You encounter dependency conflicts when installing pyasstosrt. 30 | 31 | **Solution**: Try installing in a virtual environment: 32 | 33 | .. code-block:: bash 34 | 35 | python -m venv venv 36 | source venv/bin/activate # On Windows: venv\Scripts\activate 37 | pip install 'pyasstosrt[cli]' 38 | 39 | File Conversion Issues 40 | -------------------- 41 | 42 | File Not Found 43 | ~~~~~~~~~~~~ 44 | 45 | **Problem**: You get a `FileNotFoundError` when trying to convert a file. 46 | 47 | **Solution**: Check that the file path is correct. Use absolute paths or ensure you're in the right directory: 48 | 49 | .. code-block:: python 50 | 51 | from pathlib import Path 52 | import os 53 | 54 | # Using absolute path 55 | abs_path = os.path.abspath("./subtitles/file.ass") 56 | sub = Subtitle(abs_path) 57 | 58 | # Or using pathlib 59 | file_path = Path("./subtitles/file.ass").resolve() 60 | sub = Subtitle(file_path) 61 | 62 | Incorrect Format 63 | ~~~~~~~~~~~~~ 64 | 65 | **Problem**: The converted SRT file has incorrect formatting or timing. 66 | 67 | **Solution**: Check that your ASS file follows the standard format. If the issue persists, try to: 68 | 69 | 1. Open the ASS file in a text editor to verify it has the correct structure 70 | 2. Check for any unusual formatting in the ASS file 71 | 3. Try converting with removing effects enabled: 72 | 73 | .. code-block:: python 74 | 75 | sub = Subtitle("file.ass", removing_effects=True) 76 | sub.export() 77 | 78 | Missing Text 79 | ~~~~~~~~~~ 80 | 81 | **Problem**: Some dialogues are missing in the converted SRT file. 82 | 83 | **Solution**: This might happen if dialogues have empty text or only contain effects. Try: 84 | 85 | 1. Convert without removing effects: 86 | 87 | .. code-block:: python 88 | 89 | sub = Subtitle("file.ass", removing_effects=False) 90 | sub.export() 91 | 92 | 2. Check the original ASS file for empty dialogues 93 | 94 | Encoding Issues 95 | ~~~~~~~~~~~~ 96 | 97 | **Problem**: The converted file has garbled text or incorrect characters. 98 | 99 | **Solution**: Specify the correct encoding for the output file: 100 | 101 | .. code-block:: python 102 | 103 | # For Cyrillic subtitles 104 | sub.export(encoding="utf-8") # or "cp1251" for Windows Cyrillic 105 | 106 | # For other languages 107 | sub.export(encoding="utf-16") # or other appropriate encoding 108 | 109 | If the problem persists, check the encoding of your source ASS file and make sure your system supports the required encodings. 110 | 111 | CLI Specific Issues 112 | ---------------- 113 | 114 | Multiple Files Not Processing 115 | ~~~~~~~~~~~~~~~~~~~~~~~~~~ 116 | 117 | **Problem**: When using glob patterns with the CLI, not all files are processed. 118 | 119 | **Solution**: Your shell might not be expanding the glob pattern correctly. Try either: 120 | 121 | 1. Use quotes around the pattern: 122 | 123 | .. code-block:: bash 124 | 125 | pyasstosrt export "./subtitles/*.ass" 126 | 127 | 2. Or list files explicitly: 128 | 129 | .. code-block:: bash 130 | 131 | pyasstosrt export file1.ass file2.ass file3.ass 132 | 133 | Performance Issues 134 | --------------- 135 | 136 | Slow Batch Processing 137 | ~~~~~~~~~~~~~~~~~~ 138 | 139 | **Problem**: Processing many files is slow. 140 | 141 | **Solution**: Use parallel processing as shown in the batch processing guide: 142 | 143 | .. code-block:: python 144 | 145 | from concurrent.futures import ThreadPoolExecutor 146 | 147 | # Process files in parallel 148 | with ThreadPoolExecutor(max_workers=4) as executor: 149 | executor.map(process_file_function, file_list) 150 | 151 | Debugging 152 | -------- 153 | 154 | Debug Common Issues 155 | ~~~~~~~~~~~~~~~~~ 156 | 157 | When troubleshooting, it's often helpful to add print statements to see what's happening: 158 | 159 | .. code-block:: python 160 | 161 | sub = Subtitle("file.ass") 162 | 163 | # Print raw text from the file 164 | print(sub.raw_text[:500]) # First 500 chars 165 | 166 | # Print found dialogues after conversion 167 | sub.convert() 168 | print(f"Found {len(sub.dialogues)} dialogues") 169 | 170 | # Print the first dialogue 171 | if sub.dialogues: 172 | print(f"First dialogue: {sub.dialogues[0]}") 173 | 174 | Getting Help 175 | ---------- 176 | 177 | If you encounter an issue not covered in this guide: 178 | 179 | 1. Check the project's GitHub repository for open and closed issues 180 | 2. Open a new issue on GitHub with details of your problem 181 | 3. Include sample code and if possible, a sample ASS file to reproduce the issue 182 | -------------------------------------------------------------------------------- /pyasstosrt/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | :authors: GitBib 4 | :license: Apache License, Version 2.0, see LICENSE file 5 | :copyright: (c) 2021 GitBib 6 | """ 7 | 8 | from .dialogue import Dialogue 9 | from .pyasstosrt import Subtitle 10 | from .time import Time 11 | 12 | VERSION = (1, 4, 0) 13 | __version__ = ".".join(map(str, VERSION)) 14 | 15 | __author__ = "GitBib" 16 | __email__ = "pyasstosrt@bnff.website" 17 | 18 | __all__ = ["Subtitle", "Time", "Dialogue"] 19 | -------------------------------------------------------------------------------- /pyasstosrt/batch.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | from typing import List, Optional 3 | 4 | try: 5 | import typer 6 | from rich.console import Console 7 | from rich.panel import Panel 8 | from rich.progress import Progress 9 | except ModuleNotFoundError as e: 10 | raise ImportError( 11 | "pyasstosrt was installed without the cli extra. Please reinstall it with: pip install 'pyasstosrt[cli]'" 12 | ) from e 13 | 14 | from pyasstosrt import Subtitle, __version__ 15 | 16 | app = typer.Typer(help="Convert ASS subtitles to SRT format") 17 | console = Console() 18 | 19 | 20 | def version_callback(value: bool): 21 | if value: 22 | console.print(f"[bold green]PyAssToSrt[/bold green] version: {__version__}") 23 | raise typer.Exit() 24 | 25 | 26 | @app.callback() 27 | def callback( 28 | version: Optional[bool] = typer.Option( 29 | None, "--version", "-v", callback=version_callback, help="Show version and exit" 30 | ), 31 | ): 32 | """ 33 | PyAssToSrt - Convert ASS subtitles to SRT format 34 | """ 35 | pass 36 | 37 | 38 | @app.command() 39 | def export( 40 | filepath: List[Path] = typer.Argument( 41 | ..., 42 | help="Path to the ASS file(s)", 43 | exists=True, 44 | file_okay=True, 45 | dir_okay=False, 46 | readable=True, 47 | ), 48 | removing_effects: bool = typer.Option(False, "--remove-effects", "-r", help="Remove effects from subtitles"), 49 | remove_duplicates: bool = typer.Option(False, "--remove-duplicates", "-d", help="Remove duplicate subtitles"), 50 | output_dir: Optional[Path] = typer.Option( 51 | None, 52 | "--output-dir", 53 | "-o", 54 | help="Output directory for the SRT file(s)", 55 | file_okay=False, 56 | dir_okay=True, 57 | writable=True, 58 | ), 59 | encoding: str = typer.Option("utf8", "--encoding", "-e", help="Encoding for the output file"), 60 | output_dialogues: bool = typer.Option(False, "--output-dialogues", "-p", help="Print dialogues to console"), 61 | ): 62 | """Convert ASS subtitle file(s) to SRT format""" 63 | with Progress() as progress: 64 | task = progress.add_task("[green]Converting...", total=len(filepath)) 65 | 66 | for file in filepath: 67 | progress.console.print(f"\n[bold blue]Processing: {file.name}[/bold blue]") 68 | 69 | try: 70 | sub = Subtitle(file, removing_effects, remove_duplicates) 71 | result = sub.export(output_dir, encoding, output_dialogues) 72 | 73 | if output_dialogues: 74 | progress.console.print(Panel(f"Dialogues for {file.name}:", expand=False)) 75 | for dialogue in result: 76 | progress.console.print(str(dialogue)) 77 | 78 | output_file = Path(output_dir) / f"{file.stem}.srt" if output_dir else file.with_suffix(".srt") 79 | progress.console.print(f"[green]Success:[/green] Converted {file.name} to {output_file}") 80 | except Exception as e: 81 | progress.console.print( 82 | f"[red]Error:[/red] Failed to convert {file.name}. {str(e)}", 83 | style="bold red", 84 | ) 85 | 86 | progress.update(task, advance=1) 87 | 88 | console.print("\n[bold green]Conversion completed![/bold green]") 89 | 90 | 91 | if __name__ == "__main__": 92 | app() 93 | -------------------------------------------------------------------------------- /pyasstosrt/dialogue.py: -------------------------------------------------------------------------------- 1 | from .time import Time 2 | 3 | 4 | class Dialogue: 5 | """ 6 | Represents a dialogue entry in a subtitle file. 7 | 8 | This class encapsulates a single dialogue entry, including its index, 9 | start and end times, and text content. 10 | 11 | :param index: The position of the dialogue in the subtitle file 12 | :type index: int 13 | :param start: The start time of the dialogue 14 | :type start: str 15 | :param end: The end time of the dialogue 16 | :type end: str 17 | :param text: The text content of the dialogue 18 | :type text: str 19 | 20 | :ivar start: The start time of the dialogue 21 | :type start: :class:`~pyasstosrt.time.Time` 22 | :ivar end: The end time of the dialogue 23 | :type end: :class:`~pyasstosrt.time.Time` 24 | :ivar text: The text content of the dialogue 25 | :type text: str 26 | :ivar index: The position of the dialogue in the subtitle file 27 | :type index: int 28 | """ 29 | 30 | def __init__(self, index: int, start: str, end: str, text: str): 31 | """ 32 | Initialize a Dialogue instance. 33 | 34 | :param index: The position of the dialogue in the subtitle file 35 | :type index: int 36 | :param start: The start time of the dialogue 37 | :type start: str 38 | :param end: The end time of the dialogue 39 | :type end: str 40 | :param text: The text content of the dialogue 41 | :type text: str 42 | """ 43 | self.index = index 44 | self.start = Time(start) 45 | self.end = Time(end) 46 | self.text = text 47 | 48 | def get_timestamp(self) -> str: 49 | """ 50 | Format the timestamp for SRT format. 51 | 52 | Generates a formatted string representation of the dialogue's start and end times 53 | in the SRT timestamp format. 54 | 55 | :return: A formatted string representing the start and end times of the dialogue 56 | :rtype: str 57 | """ 58 | return f"{self.start} --> {self.end}" 59 | 60 | def __str__(self) -> str: 61 | """ 62 | Format the dialogue as a string in SRT format. 63 | 64 | :return: A formatted string representation of the dialogue, including index, timestamp, and text 65 | :rtype: str 66 | """ 67 | return f"{self.index}\n{self.get_timestamp()}\n{self.text}\n\n" 68 | -------------------------------------------------------------------------------- /pyasstosrt/pyasstosrt.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | from pathlib import Path 4 | from typing import List, Optional, Tuple, Union 5 | 6 | from .dialogue import Dialogue 7 | 8 | 9 | class Subtitle: 10 | """ 11 | Converting ASS (Advanced SubStation Alpha) subtitles to SRT format. 12 | 13 | This class provides functionality to read an ASS subtitle file, convert its contents 14 | to SRT format, and export the result either as a file or as a list of dialogues. 15 | 16 | :param filepath: Path to a file that contains text in Advanced SubStation Alpha format 17 | :type filepath: Union[str, os.PathLike] 18 | :param removing_effects: Whether to remove effects from the text 19 | :type removing_effects: bool 20 | :param remove_duplicates: Whether to remove and merge consecutive duplicate dialogues 21 | :type remove_duplicates: bool 22 | 23 | :raises FileNotFoundError: If the specified file does not exist 24 | 25 | :ivar filepath: The path to the input ASS file 26 | :type filepath: Path 27 | :ivar file: The stem (filename without extension) of the input file 28 | :type file: str 29 | :ivar raw_text: The raw content of the input file 30 | :type raw_text: str 31 | :ivar dialogues: List of :class:`~pyasstosrt.dialogue.Dialogue` objects representing the subtitles 32 | :type dialogues: List[Dialogue] 33 | :ivar removing_effects: Flag indicating whether to remove effects from the text 34 | :type removing_effects: bool 35 | :ivar is_remove_duplicates: Flag indicating whether to remove and merge consecutive duplicate dialogues 36 | :type is_remove_duplicates: bool 37 | 38 | :Example: 39 | 40 | >>> from pyasstosrt import Subtitle 41 | >>> sub = Subtitle("path/to/subtitle.ass", removing_effects=True, remove_duplicates=True) 42 | >>> sub.convert() 43 | >>> sub.export("output/directory", encoding="utf-8") 44 | """ 45 | 46 | dialog_mask = re.compile(r"Dialogue: \d+?,(\d:\d{2}:\d{2}.\d{2}),(\d:\d{2}:\d{2}.\d{2}),.*?,\d+,\d+,\d+,.*?,(.*)") 47 | effects = re.compile(r"(\s?[ml].+?(-?\d+(\.\d+)?).+?(-?\d+(\.\d+)?).+)") 48 | 49 | def __init__( 50 | self, 51 | filepath: Union[str, os.PathLike], 52 | removing_effects: bool = False, 53 | remove_duplicates: bool = False, 54 | ): 55 | self.filepath = Path(filepath) 56 | if not self.filepath.is_file(): 57 | raise FileNotFoundError(f'"{self.filepath}" does not exist') 58 | self.file: str = self.filepath.stem 59 | self.raw_text: str = self.get_text() 60 | self.dialogues: List[Dialogue] = [] 61 | self.removing_effects: bool = removing_effects 62 | self.is_remove_duplicates: bool = remove_duplicates 63 | 64 | def get_text(self) -> str: 65 | """ 66 | Reads the file and returns the complete contents. 67 | 68 | :return: File contents as a string 69 | :rtype: str 70 | """ 71 | return self.filepath.read_text(encoding="utf8") 72 | 73 | def convert(self): 74 | """ 75 | Convert the ASS subtitles to SRT format. 76 | 77 | This method processes the raw text, applies any necessary filters (like removing effects), 78 | and prepares the dialogues for formatting. 79 | """ 80 | cleaning_old_format = re.compile(r"{.*?}") 81 | dialogs = re.findall(self.dialog_mask, re.sub(cleaning_old_format, "", self.raw_text)) 82 | if self.removing_effects: 83 | dialogs = filter(lambda x: re.sub(self.effects, "", x[2]), dialogs) 84 | dialogs = sorted(list(filter(lambda x: x[2], dialogs))) 85 | 86 | self.subtitle_formatting(dialogs) 87 | 88 | @staticmethod 89 | def text_clearing(raw_text: str) -> str: 90 | """ 91 | Clear the text from unnecessary tags and format line breaks. 92 | 93 | :param raw_text: Dialog text with whitespace characters and ASS format tags 94 | :type raw_text: str 95 | :return: Cleaned dialog text without whitespaces and with proper line breaks 96 | :rtype: str 97 | """ 98 | text = raw_text.replace(r"\h", "\xa0").strip() 99 | line_text = text.split(r"\N") 100 | return "\n".join(item.strip() for item in line_text).strip() 101 | 102 | @staticmethod 103 | def merged_dialogues( 104 | dialogues: List[Tuple[str, str, str]], 105 | ) -> List[Tuple[str, str, str]]: 106 | """ 107 | Group consecutive dialogues with the same text into a single dialogue with a merged time range. 108 | 109 | :param dialogues: List of dialogue tuples (start_time, end_time, text) 110 | :type dialogues: List[Tuple[str, str, str]] 111 | :return: Generator yielding merged dialogues 112 | :rtype: List[Tuple[str, str, str]] 113 | """ 114 | curr_dialogue = None 115 | for start, end, text in dialogues: 116 | if curr_dialogue is None: 117 | curr_dialogue = (start, end, text) 118 | elif text == curr_dialogue[2]: 119 | curr_dialogue = (curr_dialogue[0], end, text) 120 | else: 121 | yield curr_dialogue 122 | curr_dialogue = (start, end, text) 123 | if curr_dialogue is not None: 124 | yield curr_dialogue 125 | 126 | def remove_duplicates(self, dialogues: List[Tuple[str, str, str]]) -> List[Tuple[str, str, str]]: 127 | """ 128 | Remove consecutive duplicate dialogues in the given list and merge their time ranges. 129 | 130 | :param dialogues: A list of dialogues, where each dialogue is a tuple (start, end, text) 131 | :type dialogues: List[Tuple[str, str, str]] 132 | :return: A list of dialogues with consecutive duplicates removed and time ranges merged 133 | :rtype: List[Tuple[str, str, str]] 134 | """ 135 | return list(self.merged_dialogues(dialogues)) 136 | 137 | def subtitle_formatting(self, dialogues: List[Tuple[str, str, str]]): 138 | """ 139 | Format ASS dialogues into SRT format. 140 | 141 | This method processes the dialogues, removes duplicates if necessary, and creates 142 | :class:`~pyasstosrt.dialogue.Dialogue` objects for each subtitle entry. 143 | 144 | :param dialogues: Prepared dialogues as tuples (start_time, end_time, text) 145 | :type dialogues: List[Tuple[str, str, str]] 146 | """ 147 | cleaned_dialogues = self.remove_duplicates(dialogues) if self.is_remove_duplicates else dialogues 148 | 149 | for index, values in enumerate(cleaned_dialogues, start=1): 150 | start, end, text = values 151 | text = self.text_clearing(text.strip()) 152 | dialogue = Dialogue(index, start, end, text) 153 | self.dialogues.append(dialogue) 154 | 155 | def export( 156 | self, 157 | output_dir: Optional[Union[str, os.PathLike]] = None, 158 | encoding: str = "utf8", 159 | output_dialogues: bool = False, 160 | ) -> Optional[List[Dialogue]]: 161 | """ 162 | Export the subtitles either to a file or as a list of dialogues. 163 | 164 | If `output_dialogues` is False, this method exports the subtitles to an SRT file. 165 | Otherwise, it returns a list of :class:`~pyasstosrt.dialogue.Dialogue` objects. 166 | 167 | :param output_dir: Export path for the SRT file (optional) 168 | :type output_dir: Optional[Union[str, os.PathLike]] 169 | :param encoding: Encoding to use when saving the file (default is UTF-8) 170 | :type encoding: str 171 | :param output_dialogues: Whether to return a list of dialogues instead of creating an SRT file 172 | :type output_dialogues: bool 173 | :return: List of :class:`~pyasstosrt.dialogue.Dialogue` objects if `output_dialogues` is True, otherwise None 174 | :rtype: Optional[List[Dialogue]] 175 | """ 176 | self.convert() 177 | 178 | if output_dialogues: 179 | return self.dialogues 180 | 181 | file = f"{self.file}.srt" 182 | if output_dir: 183 | out_path = Path(output_dir) 184 | out_path.mkdir(parents=True, exist_ok=True) 185 | out_path = out_path / file 186 | else: 187 | out_path = self.filepath.parent / file 188 | with open(out_path, encoding=encoding, mode="w") as writer: 189 | for dialogue in self.dialogues: 190 | writer.write(str(dialogue)) 191 | -------------------------------------------------------------------------------- /pyasstosrt/time.py: -------------------------------------------------------------------------------- 1 | class Time: 2 | """ 3 | Represents a time structure for subtitle timestamps. 4 | 5 | Attributes: 6 | hour (int): The hour component of the time. 7 | minute (int): The minute component of the time. 8 | second (int): The second component of the time. 9 | millisecond (int): The millisecond component of the time. 10 | """ 11 | 12 | hour: int 13 | minute: int 14 | second: int 15 | millisecond: int 16 | 17 | def __init__(self, text: str): 18 | """ 19 | Initialize a Time object from a string representation. 20 | 21 | Args: 22 | text (str): A string representing time in the format '0:00:00.00'. 23 | 24 | Example: 25 | >>> time = Time("1:23:45.67") 26 | >>> print(time) 27 | 01:23:45,670 28 | """ 29 | s = text.split(":") 30 | self.hour, self.minute = [int(sr) for sr in s[:-1]] 31 | self.second, self.millisecond = [int(sr) for sr in s[-1].split(".")] 32 | # fix for srt 33 | self.millisecond *= 10 34 | 35 | def __sub__(self, other: "Time") -> float: 36 | """ 37 | Calculate the duration between two :class:`Time` objects. 38 | 39 | Args: 40 | other (:class:`Time`): Another Time object to subtract from this one. 41 | 42 | Returns: 43 | float: The difference in seconds between the two :class:`Time` objects. 44 | 45 | Example: 46 | >>> t1 = Time("0:00:10.00") 47 | >>> t2 = Time("0:00:05.00") 48 | >>> print(t1 - t2) 49 | 5.0 50 | """ 51 | return ( 52 | (self.hour - other.hour) * 3600 53 | + (self.minute - other.minute) * 60 54 | + (self.second - other.second) 55 | + (self.millisecond - other.millisecond) / 1000 56 | ) 57 | 58 | def __str__(self) -> str: 59 | """ 60 | Format the :class:`Time` object as a string for SRT subtitles. 61 | 62 | Returns: 63 | str: A string representation of the time in the format '00:00:00,000'. 64 | 65 | Example: 66 | >>> time = Time("1:23:45.67") 67 | >>> str(time) 68 | '01:23:45,670' 69 | """ 70 | return f"{self.hour:02d}:{self.minute:02d}:{self.second:02d},{self.millisecond:03d}" 71 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [project] 2 | name = "pyasstosrt" 3 | version = "1.4.2" 4 | description = "Convert ASS subtitle to SRT format" 5 | authors = [{ name = "GitBib", email = "me@bnff.website" }] 6 | requires-python = ">=3.8" 7 | readme = "README.md" 8 | license = { text = "Apache License, Version 2.0" } 9 | keywords = [ 10 | "ASS subtitle", 11 | "SRT", 12 | "Convert", 13 | "subtitle", 14 | "subtitles", 15 | "Advanced SubStation Alpha", 16 | "SubRip", 17 | "conversion", 18 | "subtitle conversion", 19 | "caption", 20 | "captions", 21 | "batch conversion", 22 | "video", 23 | "media", 24 | "CLI", 25 | ] 26 | classifiers = [ 27 | "Operating System :: OS Independent", 28 | "Programming Language :: Python", 29 | "Programming Language :: Python :: 3.8", 30 | "Programming Language :: Python :: 3.9", 31 | "Programming Language :: Python :: 3.10", 32 | "Programming Language :: Python :: 3.11", 33 | "Programming Language :: Python :: 3.12", 34 | "Programming Language :: Python :: 3.13", 35 | "Programming Language :: Python :: Implementation :: PyPy", 36 | "Programming Language :: Python :: Implementation :: CPython", 37 | ] 38 | 39 | [project.optional-dependencies] 40 | cli = ["typer>=0.15.2"] 41 | 42 | [project.urls] 43 | Homepage = "https://github.com/GitBib/pyasstosrt" 44 | Repository = "https://github.com/GitBib/pyasstosrt" 45 | Documentation = "https://gitbib.github.io/pyasstosrt/" 46 | 47 | [project.scripts] 48 | pyasstosrt = "pyasstosrt.batch:app" 49 | 50 | [dependency-groups] 51 | dev = [ 52 | "pytest>=7.0.0,<8.0.0 ; python_version < '3.12'", 53 | "pytest>=8.3.5 ; python_version >= '3.12'", 54 | "pytest-cov>=4.1.0,<5.0.0 ; python_version < '3.12'", 55 | "pytest-cov>=5.0.0 ; python_version >= '3.12'", 56 | "ruff>=0.11.1", 57 | "Sphinx>=8.0.2 ; python_version >= '3.12'", 58 | "sphinx-immaterial>=0.13.4 ; python_version >= '3.12'", 59 | "tomli>=2.2.1", 60 | ] 61 | 62 | [tool.hatch.build.targets.sdist] 63 | include = ["pyasstosrt"] 64 | exclude = ["tests", "tests/*"] 65 | 66 | [tool.hatch.build.targets.wheel] 67 | include = ["pyasstosrt"] 68 | exclude = ["tests", "tests/*"] 69 | 70 | [tool.pdm.build] 71 | includes = ["pyasstosrt"] 72 | excludes = ["tests", "tests/*"] 73 | 74 | [build-system] 75 | requires = ["pdm-backend"] 76 | build-backend = "pdm.backend" 77 | 78 | [tool.black] 79 | line-length = 120 80 | include = '\.pyi?$' 81 | 82 | [tool.isort] 83 | profile = "black" 84 | multi_line_output = 3 85 | 86 | [tool.pylint.MESSAGE_CONTROL] 87 | disable = [ 88 | "cyclic-import", 89 | "duplicate-code", 90 | "line-too-long", 91 | "missing-class-docstring", 92 | "missing-module-docstring", 93 | "super-init-not-called", 94 | "too-few-public-methods", 95 | "too-many-ancestors", 96 | "too-many-arguments", 97 | "too-many-branches", 98 | "too-many-instance-attributes", 99 | "too-many-lines", 100 | "too-many-locals", 101 | "too-many-return-statements", 102 | "ungrouped-imports", 103 | "unused-import", 104 | ] 105 | enable = "useless-suppression" 106 | 107 | [tool.pylint.REPORTS] 108 | reports = "no" 109 | 110 | [tool.pylint.FORMAT] 111 | max-line-length = "120" 112 | 113 | [tool.pylint.VARIABLES] 114 | ignored-argument-names = "args|kwargs|_|__" 115 | 116 | [tool.pylint.BASIC] 117 | good-names = "_,__,i,e,k,v,fn,get,post,put,patch,delete,route,asgi,websocket,Dependency,Body,Parameter,HandlerType,ScopeType,Auth,User" 118 | no-docstring-rgx = "(__.*__|main|test.*|.*test|.*Test|^_.*)$" 119 | 120 | [tool.pylint.LOGGING] 121 | # Logging modules to check that the string format arguments are in logging 122 | # function parameter format 123 | logging-modules = ["logging", "picologging"] 124 | 125 | [tool.coverage.run] 126 | omit = ["*/tests/*"] 127 | 128 | [tool.pycln] 129 | all = true 130 | 131 | [tool.pyright] 132 | include = ["pyasstosrt", "tests"] 133 | 134 | [tool.ruff] 135 | target-version = "py38" 136 | line-length = 120 137 | 138 | [tool.ruff.lint] 139 | select = ["E", "F", "B", "I"] 140 | ignore = ["B008"] 141 | exclude = [ 142 | ".git", 143 | ".ruff_cache", 144 | "__pycache__", 145 | "build", 146 | "dist", 147 | ] 148 | 149 | [tool.ruff.lint.isort] 150 | known-first-party = ["pyasstosrt"] 151 | 152 | [tool.ruff.format] 153 | quote-style = "double" 154 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | from pathlib import Path 4 | 5 | import pytest 6 | from typer.testing import CliRunner 7 | 8 | from pyasstosrt import Subtitle 9 | 10 | myPath = os.path.dirname(os.path.abspath(__file__)) 11 | sys.path.insert(0, f"{myPath}/../") 12 | 13 | 14 | @pytest.fixture 15 | def sub(): 16 | return Subtitle("tests/sub.ass") 17 | 18 | 19 | @pytest.fixture 20 | def cli_runner(): 21 | return CliRunner() 22 | 23 | 24 | @pytest.fixture 25 | def test_dir(): 26 | return Path("tests") 27 | 28 | 29 | @pytest.fixture 30 | def test_files(test_dir): 31 | return { 32 | "sub": test_dir / "sub.ass", 33 | "sub_removing_effects": test_dir / "sub-removing-effects.ass", 34 | "sub_standard": test_dir / "sub_standard.srt", 35 | "sub_standard_removing_effects": test_dir / "sub_standard-removing-effects.srt", 36 | } 37 | 38 | 39 | @pytest.fixture 40 | def cleanup_srt_files(test_files): 41 | srt_files = { 42 | "sub": test_files["sub"].with_suffix(".srt"), 43 | "sub_removing_effects": test_files["sub_removing_effects"].with_suffix(".srt"), 44 | } 45 | 46 | for file in srt_files.values(): 47 | if file.exists(): 48 | file.unlink() 49 | 50 | yield 51 | 52 | for file in srt_files.values(): 53 | if file.exists(): 54 | file.unlink() 55 | 56 | 57 | @pytest.fixture 58 | def output_dir(tmp_path): 59 | output_dir = tmp_path / "output" 60 | output_dir.mkdir(exist_ok=True) 61 | return output_dir 62 | 63 | 64 | @pytest.fixture 65 | def invalid_ass_file(tmp_path): 66 | invalid_file = tmp_path / "invalid.ass" 67 | content = "This is not a valid ASS file" 68 | invalid_file.write_text(content, encoding="utf-8") 69 | return invalid_file, content 70 | -------------------------------------------------------------------------------- /tests/sub.ass: -------------------------------------------------------------------------------- 1 | [Script Info] 2 | Title: HorribleSubs 3 | ScriptType: v4.00+ 4 | Collisions: Normal 5 | PlayDepth: 0 6 | WrapStyle: 0 7 | PlayResX: 848 8 | PlayResY: 480 9 | ScaledBorderAndShadow: yes 10 | 11 | [V4+ Styles] 12 | Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding 13 | Style: Default,Open Sans Semibold,36,&H00FFFFFF,&H000000FF,&H00020713,&H00000000,-1,0,0,0,100,100,0,0,1,2.0,0,2,0,0,28,1 14 | 15 | [Events] 16 | Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text 17 | Dialogue: 0,0:00:10.58,0:00:13.04,Default,,0,0,0,,It's time for the main event! 18 | Dialogue: 0,0:00:13.04,0:00:18.25,Default,,0,0,0,,Animal Mask vs. Macadamian Ogre, AKA, MAO! 19 | Dialogue: 0,0:00:18.25,0:00:20.12,Default,,0,0,0,,The masked wrestler, Animal Mask, 20 | Dialogue: 0,0:00:20.12,0:00:24.00,Default,,0,0,0,,will face off against former Judo fighter MAO! 21 | Dialogue: 0,0:00:24.00,0:00:26.95,Default,,0,0,0,,Will this bring an end to their long rivalry? 22 | Dialogue: 0,0:00:26.95,0:00:30.04,Default,,0,0,0,,What kind of match do they\Nhave in store for us tonight? 23 | Dialogue: 0,0:00:33.08,0:00:35.58,Default,,0,0,0,,It's finally time... 24 | Dialogue: 0,0:00:36.83,0:00:40.50,Default,,0,0,0,,Being a pro wrestler was\Nthe first chapter in my life. 25 | Dialogue: 0,0:00:40.50,0:00:44.58,Default,,0,0,0,,And if I can win tonight's\Nworld championship title match, 26 | Dialogue: 0,0:00:44.58,0:00:47.29,Default,,0,0,0,,the second chapter in my life will begin... 27 | Dialogue: 0,0:00:49.04,0:00:51.25,Default,,0,0,0,,It's almost time for the fight! 28 | Dialogue: 0,0:00:51.25,0:00:53.37,Default,,0,0,0,,The world championship title bout! 29 | Dialogue: 0,0:00:53.37,0:00:56.70,Default,,0,0,0,,Big Saigo, I'm monologuing.\NDon't interrupt me. 30 | Dialogue: 0,0:00:56.70,0:00:58.50,Default,,0,0,0,,Oh, I see! 31 | Dialogue: 0,0:00:58.50,0:01:00.45,Default,,0,0,0,,So, what will you do if you win tonight? 32 | Dialogue: 0,0:01:00.45,0:01:02.62,Default,,0,0,0,,There's mountains left for you to climb! 33 | Dialogue: 0,0:01:02.62,0:01:04.91,Default,,0,0,0,,Yes, that's exactly right. 34 | Dialogue: 0,0:01:04.91,0:01:09.29,Default,,0,0,0,,When I win tonight's match,\Nthe second chapter in my life will begin. 35 | Dialogue: 0,0:01:09.29,0:01:11.08,Default,,0,0,0,,Oh, what is it? 36 | Dialogue: 0,0:01:11.08,0:01:12.79,Default,,0,0,0,,You're quitting pro wrestling to do MMA? 37 | Dialogue: 0,0:01:12.79,0:01:15.41,Default,,0,0,0,,No, maybe Muay Thai or Capoeira? 38 | Dialogue: 0,0:01:15.41,0:01:18.33,Default,,0,0,0,,Very well. I'll tell you... I'm going to... 39 | Dialogue: 0,0:01:18.33,0:01:20.20,Default,,0,0,0,,Whoops, looks like we're out of time. 40 | Dialogue: 0,0:01:20.20,0:01:22.00,Default,,0,0,0,,Break a leg and all that. 41 | Dialogue: 0,0:01:22.00,0:01:26.45,Default,,0,0,0,,Go out there and smash up\Nthat Macadamian Ogre guy. 42 | Dialogue: 0,0:01:26.45,0:01:27.87,Default,,0,0,0,,Big Saigo. 43 | Dialogue: 0,0:01:27.87,0:01:30.04,Default,,0,0,0,,He's always in a hurry. 44 | Dialogue: 0,0:01:30.54,0:01:36.54,Default,,0,0,0,,"No Pets!!"\NThe second chapter in my life that will begin\Nwhen I win tonight's title match... 45 | Dialogue: 0,0:01:36.54,0:01:40.29,Default,,0,0,0,,Is when I will live my life\Nsurrounded by the animals I love, 46 | Dialogue: 0,0:01:40.29,0:01:43.20,Default,,0,0,0,,and share the joy of living with animals\Nwith people everywhere! 47 | Dialogue: 0,0:01:45.66,0:01:48.66,Default,,0,0,0,,"Interdimensional Title Match\NAnimal Mask vs MAO"\NLet's go, Hiroyuki. 48 | Dialogue: 0,0:01:51.29,0:01:56.20,Default,,0,0,0,,The Macadamian Ogre! 49 | Dialogue: 0,0:01:56.20,0:01:59.33,Default,,0,0,0,,And now, entering the ring... 50 | Dialogue: 0,0:01:59.33,0:02:01.58,Default,,0,0,0,,The man who loves animals a little too much! 51 | Dialogue: 0,0:02:01.58,0:02:09.12,Default,,0,0,0,,Weighing in at 198 pounds, it's Animal Mask! 52 | Dialogue: 0,0:02:12.29,0:02:13.95,Default,,0,0,0,,It's finally time... 53 | Dialogue: 0,0:02:13.95,0:02:18.62,Default,,0,0,0,,My rival, MAO.\NA worthy opponent for my last match! 54 | Dialogue: 0,0:02:18.62,0:02:23.87,Default,,0,0,0,,The second chapter of my life will begin\Nafter I slam you into the mat... 55 | Dialogue: 0,0:02:25.16,0:02:26.54,Default,,0,0,0,,...and that is! 56 | Dialogue: 0,0:02:27.95,0:02:30.91,Default,,0,0,0,,Opening a pet shop! 57 | Dialogue: 0,0:02:46.41,0:02:49.54,Default,,0,0,0,,Strongest warrior from another world... 58 | Dialogue: 0,0:02:49.54,0:02:52.33,Default,,0,0,0,,You're as strong as ever, Mao! 59 | Dialogue: 0,0:02:52.33,0:02:53.54,Default,,0,0,0,,Impressive! 60 | Dialogue: 0,0:02:53.54,0:02:54.66,Default,,0,0,0,,However! 61 | Dialogue: 0,0:02:55.37,0:02:58.83,Default,,0,0,0,,I pray you answer my call! 62 | Dialogue: 0,0:02:58.83,0:03:03.37,Default,,0,0,0,,Animal Mask has climbed up onto the ropes! 63 | Dialogue: 0,0:03:03.37,0:03:05.83,Default,,0,0,0,,And now he's jumped! 64 | Dialogue: 0,0:03:05.83,0:03:07.58,Default,,0,0,0,,So has Hiroyuki! 65 | Dialogue: 0,0:03:07.58,0:03:10.25,Default,,0,0,0,,Wait! They've started to glow! 66 | Dialogue: 0,0:03:10.25,0:03:12.41,Default,,0,0,0,,What is this? 67 | Dialogue: 0,0:03:12.41,0:03:14.29,Default,,0,0,0,,They disappeared! 68 | Dialogue: 0,0:03:14.29,0:03:16.29,Default,,0,0,0,,What is this? 69 | Dialogue: 0,0:03:16.29,0:03:20.75,Default,,0,0,0,,Animal Mask has disappeared! 70 | Dialogue: 0,0:03:20.75,0:03:23.20,Default,,0,0,0,,Huh? What? 71 | Dialogue: 0,0:03:38.87,0:03:40.87,Default,,0,0,0,,Are you the hero? 72 | Dialogue: 0,0:03:42.08,0:03:43.58,Default,,0,0,0,,I am Animal Mask! 73 | Dialogue: 0,0:03:43.58,0:03:45.54,Default,,0,0,0,,Did the hero-summoning ritual fail? 74 | Dialogue: 0,0:03:45.54,0:03:46.75,Default,,0,0,0,,Why is he in his underwear? 75 | Dialogue: 0,0:03:46.75,0:03:49.04,Default,,0,0,0,,Is he a pervert? 76 | Dialogue: 0,0:03:49.04,0:03:52.41,Default,,0,0,0,,I don't care who you are! 77 | Dialogue: 0,0:03:52.41,0:03:57.87,Default,,0,0,0,,If you've answered our call,\Nthen you are our hero! 78 | Dialogue: 0,0:03:57.87,0:03:59.58,Default,,0,0,0,,What's going on? 79 | Dialogue: 0,0:03:59.58,0:04:02.04,Default,,0,0,0,,Another trick of Big Saigo's? 80 | Dialogue: 0,0:04:02.04,0:04:05.95,Default,,0,0,0,,No... this isn't the arena. 81 | Dialogue: 0,0:04:05.95,0:04:08.54,Default,,0,0,0,,So where am I? 82 | Dialogue: 0,0:04:08.54,0:04:14.25,Default,,0,0,0,,Please, Hero, will you defeat\Nthe evil demon beasts that stalk this land 83 | Dialogue: 0,0:04:14.25,0:04:17.83,Default,,0,0,0,,as well as the Demon King? 84 | Dialogue: 0,0:04:17.83,0:04:19.70,Default,,0,0,0,,Evil demon beasts? 85 | Dialogue: 0,0:04:19.70,0:04:23.45,Default,,0,0,0,,Yes, terrifying animals called monsters... 86 | Dialogue: 0,0:04:23.45,0:04:26.00,Default,,0,0,0,,Exterminate every one of them\Nfrom this land... 87 | Dialogue: 0,0:04:26.95,0:04:28.45,Default,,0,0,0,,Hero? 88 | Dialogue: 0,0:04:28.45,0:04:32.12,Default,,0,0,0,,It appears I heard you right after all. 89 | Dialogue: 0,0:04:33.62,0:04:37.58,Default,,0,0,0,,You're telling me to defeat animals for you? 90 | Dialogue: 0,0:04:37.58,0:04:41.66,Default,,0,0,0,,Yes. They're terrifying and disgusting beasts... 91 | Dialogue: 0,0:04:42.58,0:04:44.54,Default,,0,0,0,,Um, Hero? 92 | Dialogue: 0,0:04:44.54,0:04:47.70,Default,,0,0,0,,We can do that after you\Ndefeat the Demon King... 93 | Dialogue: 0,0:04:47.70,0:04:51.58,Default,,0,0,0,,Or at least when nobody's watching... 94 | Dialogue: 0,0:04:51.58,0:04:55.91,Default,,0,0,0,,Hero... Um, Hero? 95 | Dialogue: 0,0:04:59.54,0:05:01.87,Default,,0,0,0,,{\i1}Hero{\i0}?! 96 | Dialogue: 0,0:05:12.45,0:05:15.50,Default,,0,0,0,,Winner! 97 | Dialogue: 0,0:06:46.75,0:06:49.91,Default,,0,0,0,,{\an8}"Wrestler x Summoning" 98 | Dialogue: 0,0:06:50.91,0:06:53.37,Default,,0,0,0,,The princess's noble butt\Nis being shown to the world! 99 | Dialogue: 0,0:06:53.37,0:06:55.91,Default,,0,0,0,,Somebody, hide her butt! 100 | Dialogue: 0,0:06:55.91,0:06:57.95,Default,,0,0,0,,Defeat animals? 101 | Dialogue: 0,0:06:57.95,0:07:00.00,Default,,0,0,0,,So the blood of an animal lover\Nthat flows through my veins 102 | Dialogue: 0,0:07:00.00,0:07:03.75,Default,,0,0,0,,forced me to give that impudent\Ngirl a German suplex? 103 | Dialogue: 0,0:07:03.75,0:07:05.25,Default,,0,0,0,,You bastard... 104 | Dialogue: 0,0:07:05.25,0:07:09.83,Default,,0,0,0,,Hero, I understand that you're angry\Nabout being summoned like this, 105 | Dialogue: 0,0:07:09.83,0:07:12.83,Default,,0,0,0,,but you can't do that to the princess. 106 | Dialogue: 0,0:07:12.83,0:07:17.16,Default,,0,0,0,,I don't know what you're talking about\Nwith this summoning and hero nonsense! 107 | Dialogue: 0,0:07:17.79,0:07:21.33,Default,,0,0,0,,But... perhaps I went too far. 108 | Dialogue: 0,0:07:21.33,0:07:22.83,Default,,0,0,0,,I know! 109 | Dialogue: 0,0:07:26.33,0:07:27.75,Default,,0,0,0,,Drape. 110 | Dialogue: 0,0:07:34.50,0:07:36.79,Default,,0,0,0,,Stop messing around! 111 | Dialogue: 0,0:07:36.79,0:07:39.41,Default,,0,0,0,,Capture him! 112 | Dialogue: 0,0:07:39.41,0:07:40.25,Default,,0,0,0,,Damn! 113 | Dialogue: 0,0:07:40.25,0:07:42.12,Default,,0,0,0,,I was trying to be a gentleman\Nand help the lady out, 114 | Dialogue: 0,0:07:42.12,0:07:43.20,Default,,0,0,0,,why are they mad? 115 | Dialogue: 0,0:07:43.20,0:07:46.70,Default,,0,0,0,,What kind of lunatic waves\Na sword at someone like that? 116 | Dialogue: 0,0:07:55.25,0:07:57.12,Default,,0,0,0,,This definitely isn't the arena. 117 | Dialogue: 0,0:07:57.12,0:07:59.29,Default,,0,0,0,,It's not even night anymore. 118 | Dialogue: 0,0:07:59.29,0:08:02.08,Default,,0,0,0,,Where am I? 119 | Dialogue: 0,0:08:02.08,0:08:03.08,Default,,0,0,0,,Who is that? 120 | Dialogue: 0,0:08:03.08,0:08:04.16,Default,,0,0,0,,Where are his pants? 121 | Dialogue: 0,0:08:04.16,0:08:05.66,Default,,0,0,0,,Is he a pervert? 122 | Dialogue: 0,0:08:05.66,0:08:07.91,Default,,0,0,0,,We should stay away... 123 | Dialogue: 0,0:08:07.91,0:08:08.79,Default,,0,0,0,,He looked over here. 124 | Dialogue: 0,0:08:08.79,0:08:10.20,Default,,0,0,0,,Don't meet his gaze. 125 | Dialogue: 0,0:08:10.20,0:08:13.33,Default,,0,0,0,,Somebody go call a hunter! 126 | Dialogue: 0,0:08:13.33,0:08:16.75,Default,,0,0,0,,I guess I'll just find someone\Nkind-looking to ask. 127 | Dialogue: 0,0:08:16.75,0:08:19.79,Default,,0,0,0,,Um, excuse me... Can you tell me where I am? 128 | Dialogue: 0,0:08:22.75,0:08:24.12,Default,,0,0,0,,I get it! 129 | Dialogue: 0,0:08:24.12,0:08:28.66,Default,,0,0,0,,It's rude to ask people questions\Nwhile wearing a mask! 130 | Dialogue: 0,0:08:34.91,0:08:38.62,Default,,0,0,0,,The moment I take off my mask,\NI'm no longer Animal Mask-- 131 | Dialogue: 0,0:08:38.62,0:08:41.37,Default,,0,0,0,,I'm an ordinary man named Genzo Shibata. 132 | Dialogue: 0,0:08:41.37,0:08:42.25,Default,,0,0,0,,Now no one will know... 133 | Dialogue: 0,0:08:42.25,0:08:44.20,Default,,0,0,0,,Over there! That's him! 134 | Dialogue: 0,0:08:44.20,0:08:44.58,Default,,0,0,0,,--Watch out! It's a pervert! 135 | Dialogue: 0,0:08:44.58,0:08:47.08,Default,,0,0,0,,--What?\N--Watch out! It's a pervert! 136 | Dialogue: 0,0:08:47.08,0:08:48.50,Default,,0,0,0,,Impossible! 137 | Dialogue: 0,0:08:49.16,0:08:50.50,Default,,0,0,0,,The pervert ran away! 138 | Dialogue: 0,0:08:50.50,0:08:51.75,Default,,0,0,0,,After the pervert! 139 | Dialogue: 0,0:08:51.75,0:08:54.45,Default,,0,0,0,,I'm not a pervert! I'm a pro wrestler! 140 | Dialogue: 0,0:08:58.62,0:09:02.04,Default,,0,0,0,,I have no idea how they figured me out. 141 | Dialogue: 0,0:09:02.04,0:09:04.58,Default,,0,0,0,,But don't worry, Hiroyuki. 142 | Dialogue: 0,0:09:04.58,0:09:07.75,Default,,0,0,0,,I'll figure out a way out of this. 143 | Dialogue: 0,0:09:10.41,0:09:12.12,Default,,0,0,0,,Sorry, Hiroyuki. 144 | Dialogue: 0,0:09:12.12,0:09:14.70,Default,,0,0,0,,Forgive me for being useless... 145 | Dialogue: 0,0:09:16.66,0:09:20.45,Default,,0,0,0,,Hiroyuki! I'm so glad you're here with me! 146 | Dialogue: 0,0:09:20.45,0:09:23.29,Default,,0,0,0,,I don't know what I would've done\Nif I were here by myself. 147 | Dialogue: 0,0:09:23.29,0:09:25.08,Default,,0,0,0,,I don't care about clothes! Not at all! 148 | Dialogue: 0,0:09:25.08,0:09:28.00,Default,,0,0,0,,My goal is to find food for you tonight! 149 | Dialogue: 0,0:09:29.08,0:09:32.50,Default,,0,0,0,,Bro, that pervert looks pretty buff. 150 | Dialogue: 0,0:09:32.50,0:09:34.66,Default,,0,0,0,,We could sell him for a lot. 151 | Dialogue: 0,0:09:34.66,0:09:41.54,Default,,0,0,0,,Yes. And that strange creature\Nwould probably be worth a lot of cash. 152 | Dialogue: 0,0:09:49.95,0:09:52.00,Default,,0,0,0,,You're so cute... 153 | Dialogue: 0,0:09:52.00,0:09:55.04,Default,,0,0,0,,You there, in your underwear. 154 | Dialogue: 0,0:09:55.04,0:09:56.95,Default,,0,0,0,,Wh-What? 155 | Dialogue: 0,0:09:56.95,0:10:00.00,Default,,0,0,0,,Animal ears?! 156 | Dialogue: 0,0:10:05.95,0:10:07.33,Default,,0,0,0,,A-And... 157 | Dialogue: 0,0:10:07.33,0:10:09.37,Default,,0,0,0,,You're hungry, right? 158 | Dialogue: 0,0:10:09.37,0:10:11.45,Default,,0,0,0,,Come with us and we'll give you some food. 159 | Dialogue: 0,0:10:11.45,0:10:13.45,Default,,0,0,0,,An animal! 160 | Dialogue: 0,0:10:13.45,0:10:17.58,Default,,0,0,0,,Do you like my hairy chest and tail? 161 | Dialogue: 0,0:10:19.91,0:10:21.70,Default,,0,0,0,,You've got nowhere to go, right? 162 | Dialogue: 0,0:10:21.70,0:10:24.41,Default,,0,0,0,,Do what he says... 163 | Dialogue: 0,0:10:30.58,0:10:33.58,Default,,0,0,0,,Bro, this guy seems like bad news... 164 | Dialogue: 0,0:10:33.58,0:10:35.25,Default,,0,0,0,,Y-Yeah... 165 | Dialogue: 0,0:10:35.25,0:10:38.20,Default,,0,0,0,,So fluffy! 166 | Dialogue: 0,0:10:38.20,0:10:41.33,Default,,0,0,0,,He's staring at you, not me! 167 | Dialogue: 0,0:10:43.33,0:10:45.37,Default,,0,0,0,,W-We'll be on our way... 168 | Dialogue: 0,0:10:46.66,0:10:48.45,Default,,0,0,0,,What the hell? 169 | Dialogue: 0,0:10:48.45,0:10:49.62,Default,,0,0,0,,Do you want to fight? 170 | Dialogue: 0,0:10:49.62,0:10:52.58,Default,,0,0,0,,You think you can beat a beastman\Nwith your bare hands? 171 | Dialogue: 0,0:10:52.58,0:10:54.58,Default,,0,0,0,,Get 'em, bro! 172 | Dialogue: 0,0:10:54.58,0:10:58.00,Default,,0,0,0,,I see... you're a beastman, huh? 173 | Dialogue: 0,0:10:59.70,0:11:01.29,Default,,0,0,0,,Bro! 174 | Dialogue: 0,0:11:08.45,0:11:12.12,Default,,0,0,0,,Hey, you jerk! Get off my brother! 175 | Dialogue: 0,0:11:12.12,0:11:14.41,Default,,0,0,0,,Stop sniffing him! 176 | Dialogue: 0,0:11:15.45,0:11:17.37,Default,,0,0,0,,Misha, this guy is crazy! 177 | Dialogue: 0,0:11:17.37,0:11:18.79,Default,,0,0,0,,He's crazy! 178 | Dialogue: 0,0:11:18.79,0:11:23.37,Default,,0,0,0,,We're sorry, so stop! Let him go! 179 | Dialogue: 0,0:11:23.37,0:11:26.50,Default,,0,0,0,,If you don't, my bro will... my bro will... 180 | Dialogue: 0,0:11:26.50,0:11:28.12,Default,,0,0,0,,What's this guy's deal? 181 | Dialogue: 0,0:11:28.12,0:11:30.54,Default,,0,0,0,,He's incredibly strong! 182 | Dialogue: 0,0:11:30.54,0:11:34.54,Default,,0,0,0,,Don't worry!\NYou'll start to like it any second! 183 | Dialogue: 0,0:11:34.54,0:11:37.16,Default,,0,0,0,,Oh, you like it when I rub you here, huh? 184 | Dialogue: 0,0:11:37.16,0:11:39.66,Default,,0,0,0,,Stop it! 185 | Dialogue: 0,0:11:39.66,0:11:43.41,Default,,0,0,0,,We'll pay you! Stop it! Please! 186 | Dialogue: 0,0:11:43.41,0:11:47.12,Default,,0,0,0,,See? Feels good, right? Good boy... 187 | Dialogue: 0,0:11:50.16,0:11:52.37,Default,,0,0,0,,Now, you're next... 188 | Dialogue: 0,0:11:54.08,0:11:56.79,Default,,0,0,0,,{\i1}Cat ears{\i0}! 189 | Dialogue: 0,0:11:59.62,0:12:02.79,Default,,0,0,0,,Shigure, give up already! 190 | Dialogue: 0,0:12:04.70,0:12:07.41,Default,,0,0,0,,You're about to be sold! 191 | Dialogue: 0,0:12:07.41,0:12:10.29,Default,,0,0,0,,No! 192 | Dialogue: 0,0:12:10.29,0:12:14.79,Default,,0,0,0,,I don't want to live at some noble's house\Nand get walks and naps and free snacks! 193 | Dialogue: 0,0:12:14.79,0:12:17.12,Default,,0,0,0,,Who said you were being sold to a noble? 194 | Dialogue: 0,0:12:17.12,0:12:20.12,Default,,0,0,0,,If that was the deal I'd go myself. 195 | Dialogue: 0,0:12:20.12,0:12:23.70,Default,,0,0,0,,But if they're willing to feed me\Nfilet mignon every day, 196 | Dialogue: 0,0:12:23.70,0:12:25.29,Default,,0,0,0,,I may be willing to let them sell me. 197 | Dialogue: 0,0:12:25.29,0:12:29.25,Default,,0,0,0,,Nobody will buy a beast girl like that! 198 | Dialogue: 0,0:12:29.25,0:12:30.54,Default,,0,0,0,,Let's go! 199 | Dialogue: 0,0:12:30.54,0:12:30.91,Default,,0,0,0,,--No! 200 | Dialogue: 0,0:12:30.91,0:12:32.75,Default,,0,0,0,,--A poor girl in unfortunate circumstances...\N--No! 201 | Dialogue: 0,0:12:32.75,0:12:34.16,Default,,0,0,0,,Stop whining and let's go! 202 | Dialogue: 0,0:12:34.16,0:12:37.75,Default,,0,0,0,,It's not right for an outsider\Nlike me to get involved. 203 | Dialogue: 0,0:12:37.75,0:12:42.37,Default,,0,0,0,,And not because I'd rather pet the cat ears... 204 | Dialogue: 0,0:12:42.37,0:12:44.79,Default,,0,0,0,,That tail! Those ears! Is that a wolf? 205 | Dialogue: 0,0:12:44.79,0:12:48.45,Default,,0,0,0,,I've had plenty of experience touching\Ncats and dogs, but never a wolf! 206 | Dialogue: 0,0:12:48.45,0:12:50.95,Default,,0,0,0,,A girl with cat ears is a hard thing to pass up, 207 | Dialogue: 0,0:12:50.95,0:12:54.29,Default,,0,0,0,,but my priority now is the wolf ears girl! 208 | Dialogue: 0,0:12:54.29,0:12:57.00,Default,,0,0,0,,Please... 209 | Dialogue: 0,0:12:57.00,0:12:59.95,Default,,0,0,0,,All praise animal ears and animal tails! 210 | Dialogue: 0,0:12:59.95,0:13:01.29,Default,,0,0,0,,That's far enough! 211 | Dialogue: 0,0:13:01.29,0:13:04.20,Default,,0,0,0,,Mind your own business. 212 | Dialogue: 0,0:13:04.20,0:13:05.70,Default,,0,0,0,,I don't know who you think you are, 213 | Dialogue: 0,0:13:05.70,0:13:07.70,Default,,0,0,0,,but try anything and you'll regret it. 214 | Dialogue: 0,0:13:07.70,0:13:09.04,Default,,0,0,0,,Really, who are you? 215 | Dialogue: 0,0:13:09.04,0:13:11.00,Default,,0,0,0,,Edgar, he's dangerous! 216 | Dialogue: 0,0:13:11.00,0:13:13.54,Default,,0,0,0,,He's a super-high-level pervert! 217 | Dialogue: 0,0:13:13.54,0:13:15.95,Default,,0,0,0,,He just had his way with my bro... 218 | Dialogue: 0,0:13:15.95,0:13:17.20,Default,,0,0,0,,What? 219 | Dialogue: 0,0:13:17.20,0:13:19.95,Default,,0,0,0,,What are you doing? 220 | Dialogue: 0,0:13:19.95,0:13:22.20,Default,,0,0,0,,Allow me to first correct\Nyour misunderstanding. 221 | Dialogue: 0,0:13:22.20,0:13:23.95,Default,,0,0,0,,I am not a pervert. 222 | Dialogue: 0,0:13:23.95,0:13:27.16,Default,,0,0,0,,I simply love all animals\Nregardless of gender! 223 | Dialogue: 0,0:13:27.16,0:13:30.25,Default,,0,0,0,,See? He's more dangerous than he looks! 224 | Dialogue: 0,0:13:30.25,0:13:33.12,Default,,0,0,0,,Yeah. The way he dresses,\Nthe things he says... 225 | Dialogue: 0,0:13:33.12,0:13:35.91,Default,,0,0,0,,He's a pervert like none\Nthe world has ever seen! 226 | Dialogue: 0,0:13:35.91,0:13:37.79,Default,,0,0,0,,Why do you fear? 227 | Dialogue: 0,0:13:37.79,0:13:43.00,Default,,0,0,0,,I don't know who you are,\Nor what reasons you may have... 228 | Dialogue: 0,0:13:43.00,0:13:44.70,Default,,0,0,0,,No! Stop it! 229 | Dialogue: 0,0:13:44.70,0:13:49.00,Default,,0,0,0,,If the wolf girl is upset, you are evil! 230 | Dialogue: 0,0:13:53.79,0:13:56.79,Default,,0,0,0,,Damn it! 231 | Dialogue: 0,0:13:56.79,0:13:59.75,Default,,0,0,0,,You pervert! We'll get you yet! 232 | Dialogue: 0,0:14:00.95,0:14:04.91,Default,,0,0,0,,Come to think of it, I hadn't gotten\Nto pet the cat ears yet, had I? 233 | Dialogue: 0,0:14:04.91,0:14:07.45,Default,,0,0,0,,Why did you have to open your mouth?! 234 | Dialogue: 0,0:14:07.45,0:14:10.00,Default,,0,0,0,,You're right! I'm sorry! 235 | Dialogue: 0,0:14:10.00,0:14:11.33,Default,,0,0,0,,Um... 236 | Dialogue: 0,0:14:14.54,0:14:17.58,Default,,0,0,0,,Thank you for saving me! 237 | Dialogue: 0,0:14:17.58,0:14:20.08,Default,,0,0,0,,Now I won't be sold. 238 | Dialogue: 0,0:14:20.08,0:14:22.54,Default,,0,0,0,,Don't worry. I did it because I wanted to. 239 | Dialogue: 0,0:14:22.54,0:14:25.25,Default,,0,0,0,,You were about to be kidnapped\Nby a slaver, right? 240 | Dialogue: 0,0:14:25.25,0:14:30.16,Default,,0,0,0,,No, I'd borrowed money from him, so... 241 | Dialogue: 0,0:14:31.70,0:14:32.66,Default,,0,0,0,,I see. 242 | Dialogue: 0,0:14:32.66,0:14:36.04,Default,,0,0,0,,You were charged absurd amounts of interest\Nand then sold to pay your debts. 243 | Dialogue: 0,0:14:36.04,0:14:39.37,Default,,0,0,0,,No, I'm the one who said\Nthat if I couldn't pay by the deadline 244 | Dialogue: 0,0:14:39.37,0:14:41.33,Default,,0,0,0,,he could sell me instead. 245 | Dialogue: 0,0:14:43.08,0:14:46.33,Default,,0,0,0,,In exchange, I told him to give me a loan\Nwith no interest and no collateral, 246 | Dialogue: 0,0:14:46.33,0:14:51.00,Default,,0,0,0,,and then cried and sobbed\Nin front of his shop until he gave in. 247 | Dialogue: 0,0:14:51.00,0:14:53.83,Default,,0,0,0,,I intended to use that money\Nto start a business and get rich, 248 | Dialogue: 0,0:14:53.83,0:14:56.45,Default,,0,0,0,,but it didn't work out. 249 | Dialogue: 0,0:14:56.45,0:14:59.12,Default,,0,0,0,,She's a loser. 250 | Dialogue: 0,0:15:00.00,0:15:01.58,Default,,0,0,0,,What's that look? 251 | Dialogue: 0,0:15:01.58,0:15:03.70,Default,,0,0,0,,I was making money for a while! 252 | Dialogue: 0,0:15:03.70,0:15:08.20,Default,,0,0,0,,But then humans started copying me. 253 | Dialogue: 0,0:15:10.41,0:15:12.25,Default,,0,0,0,,I am Genzo Shibata. 254 | Dialogue: 0,0:15:12.25,0:15:13.70,Default,,0,0,0,,A pro wrestler. 255 | Dialogue: 0,0:15:13.70,0:15:16.08,Default,,0,0,0,,My name is Shigure. 256 | Dialogue: 0,0:15:16.08,0:15:21.45,Default,,0,0,0,,And this is Hiroyuki. My partner\Nand a mongrel of pure breeding. 257 | Dialogue: 0,0:15:22.75,0:15:25.79,Default,,0,0,0,,Nice to meet you, too! 258 | Dialogue: 0,0:15:25.79,0:15:30.29,Default,,0,0,0,,Um, I'd love to thank you\Nfor saving me, but... 259 | Dialogue: 0,0:15:30.29,0:15:32.29,Default,,0,0,0,,I'm broke. 260 | Dialogue: 0,0:15:32.29,0:15:36.16,Default,,0,0,0,,But from what you said, it sounds\Nless like I've done a good deed 261 | Dialogue: 0,0:15:36.16,0:15:38.75,Default,,0,0,0,,and more like I've committed a felony... 262 | Dialogue: 0,0:15:38.75,0:15:40.16,Default,,0,0,0,,Don't worry! 263 | Dialogue: 0,0:15:40.16,0:15:43.58,Default,,0,0,0,,Remember what I said about\Npeople stealing my business model? 264 | Dialogue: 0,0:15:43.58,0:15:47.00,Default,,0,0,0,,The guy who stole it was Edgar,\Nthe guy you just saw! 265 | Dialogue: 0,0:15:47.00,0:15:50.70,Default,,0,0,0,,See? That makes him evil, right? Right? Right? 266 | Dialogue: 0,0:15:50.70,0:15:56.75,Default,,0,0,0,,Well, I guess I could count that\Nas a good deed, just barely. 267 | Dialogue: 0,0:15:56.75,0:15:58.50,Default,,0,0,0,,So... 268 | Dialogue: 0,0:15:58.50,0:16:00.91,Default,,0,0,0,,You said you were broke, right? 269 | Dialogue: 0,0:16:04.04,0:16:06.29,Default,,0,0,0,,You can pay with your body instead. 270 | Dialogue: 0,0:16:06.29,0:16:08.45,Default,,0,0,0,,He's a loser. 271 | Dialogue: 0,0:16:19.04,0:16:20.91,Default,,0,0,0,,I'll get him... 272 | Dialogue: 0,0:16:22.33,0:16:24.45,Default,,0,0,0,,It's a shame, huh? 273 | Dialogue: 0,0:16:25.58,0:16:26.79,Default,,0,0,0,,You okay? 274 | Dialogue: 0,0:16:26.79,0:16:29.25,Default,,0,0,0,,Damn that bastard. 275 | Dialogue: 0,0:16:29.25,0:16:31.41,Default,,0,0,0,,I won't just give up... 276 | Dialogue: 0,0:16:31.41,0:16:33.87,Default,,0,0,0,,I don't think there's anything you can do. 277 | Dialogue: 0,0:16:33.87,0:16:36.04,Default,,0,0,0,,Got a plan? 278 | Dialogue: 0,0:16:36.04,0:16:40.33,Default,,0,0,0,,Yeah. That strange creature he had. 279 | Dialogue: 0,0:16:40.33,0:16:42.08,Default,,0,0,0,,Oh, that? 280 | Dialogue: 0,0:16:42.08,0:16:43.04,Default,,0,0,0,,What will you do with it? 281 | Dialogue: 0,0:16:43.04,0:16:45.66,Default,,0,0,0,,What else? I'll steal it! 282 | Dialogue: 0,0:16:45.66,0:16:48.08,Default,,0,0,0,,Great idea! Let's do it! 283 | Dialogue: 0,0:16:48.08,0:16:50.12,Default,,0,0,0,,We're gonna do it! 284 | Dialogue: 0,0:16:50.12,0:16:50.95,Default,,0,0,0,,Yeah! 285 | Dialogue: 0,0:16:50.95,0:16:52.83,Default,,0,0,0,,--We'll show that pervert who's boss! 286 | Dialogue: 0,0:16:52.83,0:16:55.29,Default,,0,0,0,,--I have nothing but a bad feeling...\N--We'll show that pervert who's boss! 287 | Dialogue: 0,0:16:57.50,0:16:58.54,Default,,0,0,0,,So this is it? 288 | Dialogue: 0,0:16:58.54,0:17:00.50,Default,,0,0,0,,Yes. The Hunter Guild. 289 | Dialogue: 0,0:17:00.50,0:17:03.95,Default,,0,0,0,,Let's work here for a while\Nto make some money. 290 | Dialogue: 0,0:17:03.95,0:17:06.29,Default,,0,0,0,,You seem to be really strong, 291 | Dialogue: 0,0:17:06.29,0:17:11.16,Default,,0,0,0,,so there's probably lots of great jobs for you. 292 | Dialogue: 0,0:17:11.16,0:17:12.12,Default,,0,0,0,,So you see, 293 | Dialogue: 0,0:17:12.12,0:17:16.00,Default,,0,0,0,,I have complete confidence\Nin my ability to love any animal 294 | Dialogue: 0,0:17:16.00,0:17:20.16,Default,,0,0,0,,regardless of gender, species,\Nor even more specifically 295 | Dialogue: 0,0:17:20.16,0:17:25.29,Default,,0,0,0,,hairiness, long-hair, short-hair,\Neye color, or tail length! 296 | Dialogue: 0,0:17:28.12,0:17:31.20,Default,,0,0,0,,So I'd like to maintain a relationship of love 297 | Dialogue: 0,0:17:31.20,0:17:35.08,Default,,0,0,0,,and caring with animals at all times! 298 | Dialogue: 0,0:17:37.08,0:17:40.70,Default,,0,0,0,,What? What is he talking about? 299 | Dialogue: 0,0:17:40.70,0:17:42.25,Default,,0,0,0,,And... 300 | Dialogue: 0,0:17:42.25,0:17:49.08,Default,,0,0,0,,Even the fiercest, most violent animal will\Nrespond to my overwhelming love for them. 301 | Dialogue: 0,0:17:49.08,0:17:50.04,Default,,0,0,0,,So... 302 | Dialogue: 0,0:17:50.04,0:17:51.12,Default,,0,0,0,,What do I? 303 | Dialogue: 0,0:17:51.12,0:17:53.87,Default,,0,0,0,,What am I supposed to do here? 304 | Dialogue: 0,0:17:55.37,0:17:56.91,Default,,0,0,0,,Trouble, Guild Master! 305 | Dialogue: 0,0:17:56.91,0:17:58.25,Default,,0,0,0,,What's going on? 306 | Dialogue: 0,0:17:58.25,0:17:59.83,Default,,0,0,0,,I'm saved! 307 | Dialogue: 0,0:17:59.83,0:18:02.70,Default,,0,0,0,,Our party was wiped out by a cerberus pack. 308 | Dialogue: 0,0:18:02.70,0:18:04.91,Default,,0,0,0,,What? Perfect. 309 | Dialogue: 0,0:18:04.91,0:18:06.50,Default,,0,0,0,,Will you go too? 310 | Dialogue: 0,0:18:06.50,0:18:08.50,Default,,0,0,0,,Cerberuses are terrifying monsters... 311 | Dialogue: 0,0:18:08.50,0:18:09.33,Default,,0,0,0,,What? 312 | Dialogue: 0,0:18:09.33,0:18:10.16,Default,,0,0,0,,Where are they? 313 | Dialogue: 0,0:18:10.16,0:18:13.08,Default,,0,0,0,,Genzo! Wait! 314 | Dialogue: 0,0:18:13.08,0:18:14.37,Default,,0,0,0,,What? 315 | Dialogue: 0,0:18:14.37,0:18:19.12,Default,,0,0,0,,What sort of man isn't scared of a cerberus\Nand instead runs out to meet them? 316 | Dialogue: 0,0:18:19.12,0:18:22.00,Default,,0,0,0,,What a brave man. 317 | Dialogue: 0,0:18:22.00,0:18:26.33,Default,,0,0,0,,But... I didn't understand\Na word he was saying. 318 | Dialogue: 0,0:18:27.75,0:18:29.08,Default,,0,0,0,,It's deep in this forest! 319 | Dialogue: 0,0:18:29.08,0:18:30.16,Default,,0,0,0,,Okay! 320 | Dialogue: 0,0:18:30.16,0:18:31.58,Default,,0,0,0,,I don't think I've seen you before. 321 | Dialogue: 0,0:18:31.58,0:18:33.00,Default,,0,0,0,,Are you going unarmed? 322 | Dialogue: 0,0:18:33.00,0:18:34.62,Default,,0,0,0,,You can borrow this if you want. 323 | Dialogue: 0,0:18:34.62,0:18:36.04,Default,,0,0,0,,Fool! 324 | Dialogue: 0,0:18:36.04,0:18:39.70,Default,,0,0,0,,Do I look like a wrestler\Nwho uses weapons to you? 325 | Dialogue: 0,0:18:40.95,0:18:42.62,Default,,0,0,0,,He's going to fight them unarmed? 326 | Dialogue: 0,0:18:42.62,0:18:45.16,Default,,0,0,0,,How confident is he? 327 | Dialogue: 0,0:18:45.16,0:18:48.08,Default,,0,0,0,,Um, I'll borrow it... 328 | Dialogue: 0,0:18:48.08,0:18:51.87,Default,,0,0,0,,Listen, we can't let them get near the town! 329 | Dialogue: 0,0:18:51.87,0:18:53.70,Default,,0,0,0,,Stop them here! 330 | Dialogue: 0,0:18:58.95,0:19:00.58,Default,,0,0,0,,This is bad! 331 | Dialogue: 0,0:19:00.58,0:19:02.16,Default,,0,0,0,,So these are cerberuses? 332 | Dialogue: 0,0:19:02.16,0:19:04.79,Default,,0,0,0,,They've got three heads! 333 | Dialogue: 0,0:19:07.33,0:19:10.37,Default,,0,0,0,,That means triple the fun! 334 | Dialogue: 0,0:19:10.37,0:19:12.41,Default,,0,0,0,,So there are animals like this in this world? 335 | Dialogue: 0,0:19:12.41,0:19:14.87,Default,,0,0,0,,Okay, maybe they look a little strange, but... 336 | Dialogue: 0,0:19:16.16,0:19:17.54,Default,,0,0,0,,Are you scared? 337 | Dialogue: 0,0:19:17.54,0:19:19.45,Default,,0,0,0,,Well, calm down. 338 | Dialogue: 0,0:19:19.45,0:19:20.79,Default,,0,0,0,,Hey! 339 | Dialogue: 0,0:19:20.79,0:19:24.66,Default,,0,0,0,,No, let's see how he handles this. 340 | Dialogue: 0,0:19:24.66,0:19:26.70,Default,,0,0,0,,Yes... 341 | Dialogue: 0,0:19:27.37,0:19:30.62,Default,,0,0,0,,Cerberus! 342 | Dialogue: 0,0:19:32.37,0:19:33.95,Default,,0,0,0,,They appear to be a type of dog. 343 | Dialogue: 0,0:19:33.95,0:19:36.87,Default,,0,0,0,,Which means that if I can become\Nfriends with the pack leader, 344 | Dialogue: 0,0:19:36.87,0:19:39.91,Default,,0,0,0,,the others will quickly open up to me as well. 345 | Dialogue: 0,0:19:39.91,0:19:44.16,Default,,0,0,0,,The leader is probably...\Nthe one guarding the rear! 346 | Dialogue: 0,0:19:44.16,0:19:45.37,Default,,0,0,0,,You? 347 | Dialogue: 0,0:19:45.37,0:19:47.45,Default,,0,0,0,,{\i1}Hello{\i0}! 348 | Dialogue: 0,0:19:47.45,0:19:48.37,Default,,0,0,0,,He ran in! 349 | Dialogue: 0,0:19:48.37,0:19:50.87,Default,,0,0,0,,Gotcha! 350 | Dialogue: 0,0:19:50.87,0:19:52.50,Default,,0,0,0,,He dodged them! 351 | Dialogue: 0,0:19:54.79,0:19:58.08,Default,,0,0,0,,Good boy! Let's play! 352 | Dialogue: 0,0:20:01.08,0:20:02.95,Default,,0,0,0,,And now for the leader! 353 | Dialogue: 0,0:20:05.83,0:20:07.79,Default,,0,0,0,,Come here! 354 | Dialogue: 0,0:20:14.45,0:20:15.95,Default,,0,0,0,,He pinned it! 355 | Dialogue: 0,0:20:15.95,0:20:17.41,Default,,0,0,0,,What kind of move is that? 356 | Dialogue: 0,0:20:19.04,0:20:20.41,Default,,0,0,0,,But there are others... 357 | Dialogue: 0,0:20:20.41,0:20:21.33,Default,,0,0,0,,This is bad! 358 | Dialogue: 0,0:20:21.33,0:20:22.58,Default,,0,0,0,,Should we help? 359 | Dialogue: 0,0:20:22.58,0:20:24.83,Default,,0,0,0,,Stay out of this! 360 | Dialogue: 0,0:20:25.58,0:20:28.16,Default,,0,0,0,,He's keeping us out of danger? 361 | Dialogue: 0,0:20:28.16,0:20:30.25,Default,,0,0,0,,What a man! 362 | Dialogue: 0,0:20:31.12,0:20:34.50,Default,,0,0,0,,I think I'm starting to figure him out... 363 | Dialogue: 0,0:20:34.50,0:20:37.54,Default,,0,0,0,,Good boy! Good boy! 364 | Dialogue: 0,0:20:37.54,0:20:40.58,Default,,0,0,0,,You like it here, huh? 365 | Dialogue: 0,0:20:47.58,0:20:50.66,Default,,0,0,0,,Good boy... You're such a good boy... 366 | Dialogue: 0,0:20:50.66,0:20:54.16,Default,,0,0,0,,He really pinned it with his bare hands... 367 | Dialogue: 0,0:20:54.16,0:20:56.16,Default,,0,0,0,,Like you'd pin down a lady... 368 | Dialogue: 0,0:20:56.16,0:20:57.83,Default,,0,0,0,,He's like a lady killer... 369 | Dialogue: 0,0:20:57.83,0:21:00.12,Default,,0,0,0,,No, he's... 370 | Dialogue: 0,0:21:00.12,0:21:02.00,Default,,0,0,0,,...a demon beast killer! 371 | Dialogue: 0,0:21:09.58,0:21:11.66,Default,,0,0,0,,We got enough money from the job\Nto get you some clothes, 372 | Dialogue: 0,0:21:11.66,0:21:13.95,Default,,0,0,0,,as well as pay for an inn for a while. 373 | Dialogue: 0,0:21:13.95,0:21:15.41,Default,,0,0,0,,Yeah. 374 | Dialogue: 0,0:21:15.41,0:21:18.25,Default,,0,0,0,,So, what will you do now? 375 | Dialogue: 0,0:21:18.25,0:21:20.75,Default,,0,0,0,,I've made my decision. 376 | Dialogue: 0,0:21:20.75,0:21:24.04,Default,,0,0,0,,I want people to understand\Nhow wonderful demon beasts are! 377 | Dialogue: 0,0:21:24.04,0:21:26.79,Default,,0,0,0,,Indeed! I'll bring about a world\Nwhere demon beasts and humans 378 | Dialogue: 0,0:21:26.79,0:21:28.25,Default,,0,0,0,,can understand each other! 379 | Dialogue: 0,0:21:28.25,0:21:30.91,Default,,0,0,0,,That's impossible in this country. 380 | Dialogue: 0,0:21:30.91,0:21:31.83,Default,,0,0,0,,No... 381 | Dialogue: 0,0:21:33.45,0:21:35.95,Default,,0,0,0,,I believe I can do it. 382 | Dialogue: 0,0:21:35.95,0:21:38.12,Default,,0,0,0,,So you must believe too. 383 | Dialogue: 0,0:21:40.25,0:21:44.87,Default,,0,0,0,,Genzo, is the reason\Nyou refused to be a hero...? 384 | Dialogue: 0,0:21:44.87,0:21:49.87,Default,,0,0,0,,That princess demanded I defeat animals! 385 | Dialogue: 0,0:21:49.87,0:21:53.33,Default,,0,0,0,,Animals and human,\Nbeast people and humans... 386 | Dialogue: 0,0:21:53.33,0:21:56.62,Default,,0,0,0,,I like it! Let me help, too! 387 | Dialogue: 0,0:21:56.62,0:21:59.25,Default,,0,0,0,,Really? Then let's do this! 388 | Dialogue: 0,0:21:59.25,0:22:05.12,Default,,0,0,0,,Let's do the best with the three of us, no,\Nthe four of us including Hiroyuki! 389 | Dialogue: 0,0:22:06.08,0:22:07.75,Default,,0,0,0,,Yes! 390 | Dialogue: 0,0:22:07.75,0:22:08.91,Default,,0,0,0,,Four? 391 | Dialogue: 0,0:22:13.16,0:22:14.37,Default,,0,0,0,,Who are you? 392 | Dialogue: 0,0:23:45.91,0:23:49.91,Default,,0,0,0,,Next time: "Quest x Demon Beast Killer." 393 | 394 | -------------------------------------------------------------------------------- /tests/sub_standard-removing-effects.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:21,550 --> 00:00:22,580 3 | 辛苦了 4 | 5 | 2 6 | 00:00:23,600 --> 00:00:24,950 7 | 檢修結束了喔 8 | 9 | 3 10 | 00:00:29,600 --> 00:00:33,970 11 | 抱歉 都試了這麼多次還是不行 12 | 13 | 4 14 | 00:00:42,690 --> 00:00:42,730 15 | 已經沒有 16 | 辦法了嗎 17 | 18 | 5 19 | 00:00:42,730 --> 00:00:42,770 20 | 已經沒有 21 | 辦法了嗎 22 | 23 | 6 24 | 00:00:42,770 --> 00:00:42,810 25 | 已經沒有 26 | 辦法了嗎 27 | 28 | 7 29 | 00:00:42,810 --> 00:00:42,850 30 | 已經沒有 31 | 辦法了嗎 32 | 33 | 8 34 | 00:00:42,850 --> 00:00:42,890 35 | 已經沒有 36 | 辦法了嗎 37 | 38 | 9 39 | 00:00:42,890 --> 00:00:42,930 40 | 已經沒有 41 | 辦法了嗎 42 | 43 | 10 44 | 00:00:42,930 --> 00:00:42,980 45 | 已經沒有 46 | 辦法了嗎 47 | 48 | 11 49 | 00:00:42,980 --> 00:00:43,020 50 | 已經沒有 51 | 辦法了嗎 52 | 53 | 12 54 | 00:00:43,020 --> 00:00:43,060 55 | 已經沒有 56 | 辦法了嗎 57 | 58 | 13 59 | 00:00:43,060 --> 00:00:43,100 60 | 已經沒有 61 | 辦法了嗎 62 | 63 | 14 64 | 00:00:43,100 --> 00:00:43,140 65 | 已經沒有 66 | 辦法了嗎 67 | 68 | 15 69 | 00:00:43,140 --> 00:00:43,180 70 | 已經沒有 71 | 辦法了嗎 72 | 73 | 16 74 | 00:00:43,180 --> 00:00:43,230 75 | 已經沒有 76 | 辦法了嗎 77 | 78 | 17 79 | 00:00:43,230 --> 00:00:43,270 80 | 已經沒有 81 | 辦法了嗎 82 | 83 | 18 84 | 00:00:43,270 --> 00:00:43,310 85 | 已經沒有 86 | 辦法了嗎 87 | 88 | 19 89 | 00:00:43,310 --> 00:00:43,350 90 | 已經沒有 91 | 辦法了嗎 92 | 93 | 20 94 | 00:00:43,350 --> 00:00:43,390 95 | 已經沒有 96 | 辦法了嗎 97 | 98 | 21 99 | 00:00:43,390 --> 00:00:43,430 100 | 已經沒有 101 | 辦法了嗎 102 | 103 | 22 104 | 00:00:43,430 --> 00:00:43,480 105 | 已經沒有 106 | 辦法了嗎 107 | 108 | 23 109 | 00:00:43,480 --> 00:00:43,520 110 | 已經沒有 111 | 辦法了嗎 112 | 113 | 24 114 | 00:00:43,520 --> 00:00:43,560 115 | 已經沒有 116 | 辦法了嗎 117 | 118 | 25 119 | 00:00:43,560 --> 00:00:45,150 120 | 已經沒有 121 | 辦法了嗎 122 | 123 | 26 124 | 00:00:46,690 --> 00:00:49,030 125 | 初始化的話是有可能修好的 126 | 127 | 27 128 | 00:00:49,760 --> 00:00:50,920 129 | 但是如果這麼做 130 | 131 | 28 132 | 00:00:51,290 --> 00:00:54,270 133 | 你就會失去所有的記憶 134 | 135 | 29 136 | 00:00:55,950 --> 00:01:02,630 137 | ブ 138 | 139 | 30 140 | 00:00:55,950 --> 00:01:02,630 141 | 馬 142 | 143 | 31 144 | 00:00:55,990 --> 00:01:02,670 145 | リ 146 | 147 | 32 148 | 00:00:55,990 --> 00:01:02,670 149 | 口 150 | 151 | 33 152 | 00:00:56,040 --> 00:01:02,710 153 | キ 154 | 155 | 34 156 | 00:00:56,040 --> 00:01:02,710 157 | 鐵 158 | 159 | 35 160 | 00:00:56,080 --> 00:01:02,750 161 | は 162 | 163 | 36 164 | 00:00:56,080 --> 00:01:02,750 165 | 吱 166 | 167 | 37 168 | 00:00:56,120 --> 00:01:02,790 169 | 吱 170 | 171 | 38 172 | 00:00:56,120 --> 00:01:02,790 173 | 軋 174 | 175 | 39 176 | 00:00:56,160 --> 00:01:02,830 177 | み 178 | 179 | 40 180 | 00:00:56,160 --> 00:01:02,830 181 | 作 182 | 183 | 41 184 | 00:00:56,200 --> 00:01:02,880 185 | 響 186 | 187 | 42 188 | 00:00:56,240 --> 00:01:02,920 189 | 音 190 | 191 | 43 192 | 00:00:56,290 --> 00:01:02,960 193 | を 194 | 195 | 44 196 | 00:00:56,290 --> 00:01:02,960 197 | 化 198 | 199 | 45 200 | 00:00:56,330 --> 00:01:03,000 201 | 作 202 | 203 | 46 204 | 00:00:56,330 --> 00:01:03,000 205 | 奏 206 | 207 | 47 208 | 00:00:56,370 --> 00:01:03,040 209 | で 210 | 211 | 48 212 | 00:00:56,370 --> 00:01:03,040 213 | 樂 214 | 215 | 49 216 | 00:00:56,410 --> 00:01:03,080 217 | た 218 | 219 | 50 220 | 00:00:56,410 --> 00:01:03,080 221 | 聲 222 | 223 | 51 224 | 00:01:02,630 --> 00:01:11,340 225 | 朝 226 | 227 | 52 228 | 00:01:02,630 --> 00:01:11,340 229 | 花 230 | 231 | 53 232 | 00:01:02,630 --> 00:01:11,380 233 | び 234 | 235 | 54 236 | 00:01:02,670 --> 00:01:11,380 237 | 著 238 | 239 | 55 240 | 00:01:02,670 --> 00:01:11,430 241 | ら 242 | 243 | 56 244 | 00:01:02,710 --> 00:01:11,430 245 | 花 246 | 247 | 57 248 | 00:01:02,710 --> 00:01:11,470 249 | の 250 | 251 | 58 252 | 00:01:02,750 --> 00:01:11,470 253 | 瓣 254 | 255 | 59 256 | 00:01:02,750 --> 00:01:11,510 257 | 舞 258 | 259 | 60 260 | 00:01:02,790 --> 00:01:11,510 261 | 飄 262 | 263 | 61 264 | 00:01:02,790 --> 00:01:11,550 265 | う 266 | 267 | 62 268 | 00:01:02,830 --> 00:01:11,550 269 | 落 270 | 271 | 63 272 | 00:01:02,830 --> 00:01:11,590 273 | 季 274 | 275 | 64 276 | 00:01:02,880 --> 00:01:11,590 277 | 節 278 | 279 | 65 280 | 00:01:02,880 --> 00:01:11,630 281 | 的 282 | 283 | 66 284 | 00:01:02,920 --> 00:01:11,630 285 | へ 286 | 287 | 67 288 | 00:01:02,920 --> 00:01:11,630 289 | 季 290 | 291 | 68 292 | 00:01:02,960 --> 00:01:11,680 293 | と 294 | 295 | 69 296 | 00:01:02,960 --> 00:01:11,720 297 | 節 298 | 299 | 70 300 | 00:01:03,000 --> 00:01:11,720 301 | 向 302 | 303 | 71 304 | 00:01:03,000 --> 00:01:11,760 305 | 前 306 | 307 | 72 308 | 00:01:03,040 --> 00:01:11,760 309 | か 310 | 311 | 73 312 | 00:01:03,080 --> 00:01:11,800 313 | う 314 | 315 | 74 316 | 00:01:03,080 --> 00:01:11,800 317 | 行 318 | 319 | 75 320 | 00:01:17,600 --> 00:01:22,230 321 | Nekomoe Kissaten 322 | 323 | 76 324 | 00:01:17,600 --> 00:01:22,230 325 | Prima Doll 326 | 327 | 77 328 | 00:01:17,600 --> 00:01:22,230 329 | 喵萌奶茶屋 330 | 331 | 78 332 | 00:01:17,600 --> 00:01:22,230 333 | 天籟人偶 334 | 335 | 79 336 | 00:01:17,600 --> 00:01:22,230 337 | 本字幕由喵萌奶茶屋製作 僅供交流試看之用 請勿用於商業用途 338 | 339 | 80 340 | 00:01:17,600 --> 00:01:22,230 341 | 翻譯: この世界にiをこめて 時軸: 卡布chino 342 | 特效: 藤原七寶 後期: 王子 繁化: 雨林 WebRip: LoliHouse 343 | 344 | 81 345 | 00:01:22,440 --> 00:01:29,070 346 | 萬 347 | 348 | 82 349 | 00:01:22,440 --> 00:01:29,070 350 | 輪 351 | 352 | 83 353 | 00:01:22,480 --> 00:01:29,150 354 | 廻 355 | 356 | 84 357 | 00:01:22,480 --> 00:01:29,150 358 | 花 359 | 360 | 85 361 | 00:01:22,560 --> 00:01:29,190 362 | す 363 | 364 | 86 365 | 00:01:22,560 --> 00:01:29,190 366 | 筒 367 | 368 | 87 369 | 00:01:22,600 --> 00:01:29,240 370 | る 371 | 372 | 88 373 | 00:01:22,650 --> 00:01:29,280 374 | 巡 375 | 376 | 89 377 | 00:01:22,690 --> 00:01:29,360 378 | 回 379 | 380 | 90 381 | 00:01:22,730 --> 00:01:29,400 382 | 万 383 | 384 | 91 385 | 00:01:22,770 --> 00:01:29,440 386 | 往 387 | 388 | 92 389 | 00:01:22,810 --> 00:01:29,440 390 | 華 391 | 392 | 93 393 | 00:01:22,850 --> 00:01:29,490 394 | 復 395 | 396 | 94 397 | 00:01:22,850 --> 00:01:29,490 398 | 鏡 399 | 400 | 95 401 | 00:01:29,070 --> 00:01:35,660 402 | ず 403 | 404 | 96 405 | 00:01:29,070 --> 00:01:35,660 406 | 一 407 | 408 | 97 409 | 00:01:29,110 --> 00:01:35,700 410 | っ 411 | 412 | 98 413 | 00:01:29,110 --> 00:01:35,700 414 | 直 415 | 416 | 99 417 | 00:01:29,150 --> 00:01:35,740 418 | と 419 | 420 | 100 421 | 00:01:29,150 --> 00:01:35,740 422 | 回 423 | 424 | 101 425 | 00:01:29,190 --> 00:01:35,780 426 | っ 427 | 428 | 102 429 | 00:01:29,190 --> 00:01:35,780 430 | 旋 431 | 432 | 103 433 | 00:01:29,240 --> 00:01:35,830 434 | た 435 | 436 | 104 437 | 00:01:29,240 --> 00:01:35,830 438 | 轉 439 | 440 | 105 441 | 00:01:29,280 --> 00:01:35,870 442 | き 443 | 444 | 106 445 | 00:01:29,280 --> 00:01:35,870 446 | 著 447 | 448 | 107 449 | 00:01:29,320 --> 00:01:35,910 450 | ら 451 | 452 | 108 453 | 00:01:29,360 --> 00:01:35,950 454 | き 455 | 456 | 109 457 | 00:01:29,360 --> 00:01:35,950 458 | 閃 459 | 460 | 110 461 | 00:01:29,400 --> 00:01:35,990 462 | と 463 | 464 | 111 465 | 00:01:29,400 --> 00:01:35,990 466 | ら 467 | 468 | 112 469 | 00:01:29,440 --> 00:01:36,030 470 | 輝 471 | 472 | 113 473 | 00:01:29,440 --> 00:01:36,030 474 | 閃 475 | 476 | 114 477 | 00:01:29,490 --> 00:01:36,080 478 | い 479 | 480 | 115 481 | 00:01:29,490 --> 00:01:36,080 482 | て 483 | 484 | 116 485 | 00:01:29,490 --> 00:01:36,080 486 | 發 487 | 488 | 117 489 | 00:01:29,530 --> 00:01:36,120 490 | た 491 | 492 | 118 493 | 00:01:29,530 --> 00:01:36,120 494 | 光 495 | 496 | 119 497 | 00:01:35,660 --> 00:01:42,370 498 | そ 499 | 500 | 120 501 | 00:01:35,660 --> 00:01:42,370 502 | 這 503 | 504 | 121 505 | 00:01:35,700 --> 00:01:42,410 506 | れ 507 | 508 | 122 509 | 00:01:35,740 --> 00:01:42,410 510 | 就 511 | 512 | 123 513 | 00:01:35,740 --> 00:01:42,460 514 | は 515 | 516 | 124 517 | 00:01:35,780 --> 00:01:42,500 518 | 是 519 | 520 | 125 521 | 00:01:35,780 --> 00:01:42,500 522 | 素 523 | 524 | 126 525 | 00:01:35,830 --> 00:01:42,540 526 | 晴 527 | 528 | 127 529 | 00:01:35,830 --> 00:01:42,540 530 | 美 531 | 532 | 128 533 | 00:01:35,870 --> 00:01:42,580 534 | ら 535 | 536 | 129 537 | 00:01:35,910 --> 00:01:42,620 538 | 好 539 | 540 | 130 541 | 00:01:35,950 --> 00:01:42,620 542 | し 543 | 544 | 131 545 | 00:01:35,990 --> 00:01:42,670 546 | い 547 | 548 | 132 549 | 00:01:35,990 --> 00:01:42,670 550 | 的 551 | 552 | 133 553 | 00:01:36,030 --> 00:01:42,750 554 | 日 555 | 556 | 134 557 | 00:01:36,030 --> 00:01:42,750 558 | 生 559 | 560 | 135 561 | 00:01:36,080 --> 00:01:42,790 562 | 々 563 | 564 | 136 565 | 00:01:36,080 --> 00:01:42,790 566 | 活 567 | 568 | 137 569 | 00:01:36,120 --> 00:01:42,830 570 | で 571 | 572 | 138 573 | 00:01:42,370 --> 00:01:48,210 574 | 散 575 | 576 | 139 577 | 00:01:42,370 --> 00:01:48,210 578 | 眩 579 | 580 | 140 581 | 00:01:42,410 --> 00:01:48,250 582 | し 583 | 584 | 141 585 | 00:01:42,410 --> 00:01:48,250 586 | 發 587 | 588 | 142 589 | 00:01:42,500 --> 00:01:48,300 590 | す 591 | 592 | 143 593 | 00:01:42,500 --> 00:01:48,340 594 | 出 595 | 596 | 144 597 | 00:01:42,540 --> 00:01:48,380 598 | ぎ 599 | 600 | 145 601 | 00:01:42,540 --> 00:01:48,380 602 | 耀 603 | 604 | 146 605 | 00:01:42,580 --> 00:01:48,420 606 | る 607 | 608 | 147 609 | 00:01:42,620 --> 00:01:48,460 610 | ほ 611 | 612 | 148 613 | 00:01:42,620 --> 00:01:48,460 614 | 眼 615 | 616 | 149 617 | 00:01:42,670 --> 00:01:48,500 618 | 的 619 | 620 | 150 621 | 00:01:42,710 --> 00:01:48,550 622 | ど 623 | 624 | 151 625 | 00:01:42,750 --> 00:01:48,590 626 | 光 627 | 628 | 152 629 | 00:01:42,750 --> 00:01:48,590 630 | 光 631 | 632 | 153 633 | 00:01:42,790 --> 00:01:48,630 634 | 芒 635 | 636 | 154 637 | 00:01:42,830 --> 00:01:48,630 638 | る 639 | 640 | 155 641 | 00:01:48,210 --> 00:01:54,800 642 | 思 643 | 644 | 156 645 | 00:01:48,210 --> 00:01:54,800 646 | 當 647 | 648 | 157 649 | 00:01:48,250 --> 00:01:54,840 650 | い 651 | 652 | 158 653 | 00:01:48,250 --> 00:01:54,840 654 | 一 655 | 656 | 159 657 | 00:01:48,250 --> 00:01:54,890 658 | 出 659 | 660 | 160 661 | 00:01:48,300 --> 00:01:54,930 662 | だ 663 | 664 | 161 665 | 00:01:48,300 --> 00:01:54,930 666 | 切 667 | 668 | 162 669 | 00:01:48,380 --> 00:01:54,970 670 | 何 671 | 672 | 163 673 | 00:01:48,380 --> 00:01:54,970 674 | 從 675 | 676 | 164 677 | 00:01:48,420 --> 00:01:55,010 678 | も 679 | 680 | 165 681 | 00:01:48,420 --> 00:01:55,050 682 | 回 683 | 684 | 166 685 | 00:01:48,460 --> 00:01:55,050 686 | か 687 | 688 | 167 689 | 00:01:48,460 --> 00:01:55,090 690 | 憶 691 | 692 | 168 693 | 00:01:48,500 --> 00:01:55,090 694 | も 695 | 696 | 169 697 | 00:01:48,500 --> 00:01:55,140 698 | が 699 | 700 | 170 701 | 00:01:48,550 --> 00:01:55,140 702 | 中 703 | 704 | 171 705 | 00:01:48,550 --> 00:01:55,180 706 | 消 707 | 708 | 172 709 | 00:01:48,590 --> 00:01:55,180 710 | 消 711 | 712 | 173 713 | 00:01:48,590 --> 00:01:55,220 714 | え 715 | 716 | 174 717 | 00:01:48,630 --> 00:01:55,220 718 | 去 719 | 720 | 175 721 | 00:01:48,630 --> 00:01:55,260 722 | 逝 723 | 724 | 176 725 | 00:01:48,670 --> 00:01:55,260 726 | り 727 | 728 | 177 729 | 00:01:54,800 --> 00:02:08,900 730 | 將 731 | 732 | 178 733 | 00:01:54,800 --> 00:02:08,900 734 | 残 735 | 736 | 179 737 | 00:01:54,840 --> 00:02:08,900 738 | さ 739 | 740 | 180 741 | 00:01:54,840 --> 00:02:08,900 742 | 自 743 | 744 | 181 745 | 00:01:54,840 --> 00:02:08,940 746 | れ 747 | 748 | 182 749 | 00:01:54,890 --> 00:02:08,940 750 | た 751 | 752 | 183 753 | 00:01:54,890 --> 00:02:08,940 754 | 己 755 | 756 | 184 757 | 00:01:54,890 --> 00:02:08,980 758 | 土 759 | 760 | 185 761 | 00:01:54,890 --> 00:02:08,980 762 | 獻 763 | 764 | 186 765 | 00:01:54,930 --> 00:02:08,980 766 | に 767 | 768 | 187 769 | 00:01:54,930 --> 00:02:09,020 770 | 給 771 | 772 | 188 773 | 00:01:54,930 --> 00:02:09,020 774 | 芽 775 | 776 | 189 777 | 00:01:54,970 --> 00:02:09,020 778 | 吹 779 | 780 | 190 781 | 00:01:54,970 --> 00:02:09,020 782 | 破 783 | 784 | 191 785 | 00:01:54,970 --> 00:02:09,070 786 | く 787 | 788 | 192 789 | 00:01:55,010 --> 00:02:09,070 790 | 土 791 | 792 | 193 793 | 00:01:55,010 --> 00:02:09,110 794 | 希 795 | 796 | 194 797 | 00:01:55,010 --> 00:02:09,110 798 | 而 799 | 800 | 195 801 | 00:01:55,050 --> 00:02:09,110 802 | 望 803 | 804 | 196 805 | 00:01:55,050 --> 00:02:09,150 806 | 出 807 | 808 | 197 809 | 00:01:55,090 --> 00:02:09,150 810 | の 811 | 812 | 198 813 | 00:01:55,090 --> 00:02:09,150 814 | 代 815 | 816 | 199 817 | 00:01:55,090 --> 00:02:09,150 818 | 命 819 | 820 | 200 821 | 00:01:55,090 --> 00:02:09,190 822 | と 823 | 824 | 201 825 | 00:01:55,140 --> 00:02:09,190 826 | 表 827 | 828 | 202 829 | 00:01:55,140 --> 00:02:09,230 830 | な 831 | 832 | 203 833 | 00:01:55,140 --> 00:02:09,230 834 | 希 835 | 836 | 204 837 | 00:01:55,180 --> 00:02:09,230 838 | る 839 | 840 | 205 841 | 00:01:55,180 --> 00:02:09,230 842 | 望 843 | 844 | 206 845 | 00:01:55,220 --> 00:02:09,280 846 | う 847 | 848 | 207 849 | 00:01:55,220 --> 00:02:09,280 850 | よ 851 | 852 | 208 853 | 00:01:55,220 --> 00:02:09,280 854 | 的 855 | 856 | 209 857 | 00:01:55,260 --> 00:02:09,320 858 | げ 859 | 860 | 210 861 | 00:01:55,260 --> 00:02:09,320 862 | 捧 863 | 864 | 211 865 | 00:01:55,260 --> 00:02:09,320 866 | 生 867 | 868 | 212 869 | 00:01:55,260 --> 00:02:09,360 870 | 命 871 | 872 | 213 873 | 00:01:55,300 --> 00:02:09,360 874 | る 875 | 876 | 214 877 | 00:02:08,900 --> 00:02:15,450 878 | ブ 879 | 880 | 215 881 | 00:02:08,900 --> 00:02:15,450 882 | 身 883 | 884 | 216 885 | 00:02:08,940 --> 00:02:15,490 886 | リ 887 | 888 | 217 889 | 00:02:08,940 --> 00:02:15,490 890 | 體 891 | 892 | 218 893 | 00:02:08,980 --> 00:02:15,530 894 | キ 895 | 896 | 219 897 | 00:02:08,980 --> 00:02:15,570 898 | 吱 899 | 900 | 220 901 | 00:02:09,020 --> 00:02:15,570 902 | は 903 | 904 | 221 905 | 00:02:09,020 --> 00:02:15,610 906 | 吱 907 | 908 | 222 909 | 00:02:09,020 --> 00:02:15,610 910 | 軋 911 | 912 | 223 913 | 00:02:09,070 --> 00:02:15,660 914 | み 915 | 916 | 224 917 | 00:02:09,070 --> 00:02:15,660 918 | 作 919 | 920 | 225 921 | 00:02:09,110 --> 00:02:15,700 922 | 響 923 | 924 | 226 925 | 00:02:09,190 --> 00:02:15,740 926 | 命 927 | 928 | 227 929 | 00:02:09,190 --> 00:02:15,780 930 | 燃 931 | 932 | 228 933 | 00:02:09,230 --> 00:02:15,780 934 | を 935 | 936 | 229 937 | 00:02:09,230 --> 00:02:15,820 938 | 燃 939 | 940 | 230 941 | 00:02:09,230 --> 00:02:15,820 942 | 燒 943 | 944 | 231 945 | 00:02:09,280 --> 00:02:15,870 946 | や 947 | 948 | 232 949 | 00:02:09,280 --> 00:02:15,870 950 | 生 951 | 952 | 233 953 | 00:02:09,320 --> 00:02:15,910 954 | す 955 | 956 | 234 957 | 00:02:09,320 --> 00:02:15,910 958 | 命 959 | 960 | 235 961 | 00:02:15,450 --> 00:02:23,960 962 | 朝 963 | 964 | 236 965 | 00:02:15,450 --> 00:02:23,960 966 | 花 967 | 968 | 237 969 | 00:02:15,490 --> 00:02:24,000 970 | び 971 | 972 | 238 973 | 00:02:15,490 --> 00:02:24,000 974 | 著 975 | 976 | 239 977 | 00:02:15,530 --> 00:02:24,040 978 | ら 979 | 980 | 240 981 | 00:02:15,530 --> 00:02:24,040 982 | 花 983 | 984 | 241 985 | 00:02:15,570 --> 00:02:24,080 986 | の 987 | 988 | 242 989 | 00:02:15,570 --> 00:02:24,080 990 | 瓣 991 | 992 | 243 993 | 00:02:15,610 --> 00:02:24,120 994 | 舞 995 | 996 | 244 997 | 00:02:15,610 --> 00:02:24,120 998 | 飛 999 | 1000 | 245 1001 | 00:02:15,660 --> 00:02:24,170 1002 | う 1003 | 1004 | 246 1005 | 00:02:15,660 --> 00:02:24,170 1006 | 舞 1007 | 1008 | 247 1009 | 00:02:15,700 --> 00:02:24,170 1010 | 季 1011 | 1012 | 248 1013 | 00:02:15,700 --> 00:02:24,210 1014 | 的 1015 | 1016 | 249 1017 | 00:02:15,740 --> 00:02:24,210 1018 | 節 1019 | 1020 | 250 1021 | 00:02:15,740 --> 00:02:24,250 1022 | 季 1023 | 1024 | 251 1025 | 00:02:15,780 --> 00:02:24,250 1026 | へ 1027 | 1028 | 252 1029 | 00:02:15,780 --> 00:02:24,290 1030 | 節 1031 | 1032 | 253 1033 | 00:02:15,820 --> 00:02:24,290 1034 | と 1035 | 1036 | 254 1037 | 00:02:15,820 --> 00:02:24,330 1038 | 前 1039 | 1040 | 255 1041 | 00:02:15,870 --> 00:02:24,330 1042 | 向 1043 | 1044 | 256 1045 | 00:02:15,870 --> 00:02:24,370 1046 | か 1047 | 1048 | 257 1049 | 00:02:15,870 --> 00:02:24,370 1050 | 行 1051 | 1052 | 258 1053 | 00:02:15,910 --> 00:02:24,420 1054 | う 1055 | 1056 | 259 1057 | 00:02:15,910 --> 00:02:24,420 1058 | 吧 1059 | 1060 | 260 1061 | 00:02:25,500 --> 00:02:30,500 1062 | 第3話 星空的鎮魂曲 1063 | 1064 | 261 1065 | 00:02:25,500 --> 00:02:30,500 1066 | 第3話 星空的鎮魂曲 1067 | 1068 | 262 1069 | 00:02:27,860 --> 00:02:30,210 1070 | 好 1 2 3 1071 | 1072 | 263 1073 | 00:02:30,710 --> 00:02:32,620 1074 | 1 2 3 1075 | 1076 | 264 1077 | 00:02:33,170 --> 00:02:35,590 1078 | 沒有翻好 再來一次 1079 | 1080 | 265 1081 | 00:02:35,830 --> 00:02:37,850 1082 | 已經到極限了 1083 | 1084 | 266 1085 | 00:02:45,410 --> 00:02:47,230 1086 | 檢修結束了嗎 1087 | 1088 | 267 1089 | 00:02:47,730 --> 00:02:47,860 1090 | 檢修非常順利 1091 | 1092 | 1093 | 1094 | 我回廚房上工了 1095 | 1096 | 268 1097 | 00:02:47,860 --> 00:02:49,730 1098 | 檢修非常順利 1099 | 1100 | 1101 | 1102 | 我回廚房上工了 1103 | 1104 | 269 1105 | 00:02:51,330 --> 00:02:53,740 1106 | 那這邊可以拜託你嗎 1107 | 1108 | 270 1109 | 00:02:55,470 --> 00:02:57,180 1110 | 什麼都看不見了 1111 | 1112 | 271 1113 | 00:03:11,540 --> 00:03:11,580 1114 | 感覺怎麼樣 1115 | 還好嗎 1116 | 1117 | 272 1118 | 00:03:11,580 --> 00:03:11,620 1119 | 感覺怎麼樣 1120 | 還好嗎 1121 | 1122 | 273 1123 | 00:03:11,620 --> 00:03:11,670 1124 | 感覺怎麼樣 1125 | 還好嗎 1126 | 1127 | 274 1128 | 00:03:11,670 --> 00:03:11,790 1129 | 感覺怎麼樣 1130 | 還好嗎 1131 | 1132 | 275 1133 | 00:03:11,790 --> 00:03:12,920 1134 | 感覺怎麼樣 1135 | 還好嗎 1136 | 1137 | 276 1138 | 00:03:13,210 --> 00:03:16,200 1139 | 對不起 我已經沒事了 1140 | 1141 | 277 1142 | 00:03:17,300 --> 00:03:17,420 1143 | 能請你來 1144 | 幫忙嗎 1145 | 1146 | 278 1147 | 00:03:17,420 --> 00:03:17,550 1148 | 能請你來 1149 | 幫忙嗎 1150 | 1151 | 279 1152 | 00:03:17,550 --> 00:03:19,180 1153 | 能請你來 1154 | 幫忙嗎 1155 | 1156 | 280 1157 | 00:03:19,700 --> 00:03:22,870 1158 | 我來幫忙 1159 | 1160 | 281 1161 | 00:03:28,610 --> 00:03:29,560 1162 | 請坐 1163 | 1164 | 282 1165 | 00:03:32,360 --> 00:03:35,150 1166 | 但是箒星真的很厲害呢 1167 | 1168 | 283 1169 | 00:03:37,090 --> 00:03:38,660 1170 | 不僅擅長做飯 1171 | 1172 | 284 1173 | 00:03:38,910 --> 00:03:40,910 1174 | 還可以隨意操控機械人偶 1175 | 1176 | 285 1177 | 00:03:41,250 --> 00:03:42,460 1178 | 我好羨慕 1179 | 1180 | 286 1181 | 00:03:43,660 --> 00:03:47,040 1182 | 要怎麼樣才能和你一樣厲害呢 1183 | 1184 | 287 1185 | 00:03:47,500 --> 00:03:49,760 1186 | 我很在意你究竟做了什麼樣的練習 1187 | 1188 | 288 1189 | 00:03:50,000 --> 00:03:53,130 1190 | 我想更加了解你 1191 | 1192 | 289 1193 | 00:04:06,060 --> 00:04:07,600 1194 | 射擊目標位置 1195 | 1196 | 290 1197 | 00:04:08,200 --> 00:04:10,470 1198 | 方位角 2920 1199 | 1200 | 291 1201 | 00:04:10,470 --> 00:04:12,140 1202 | 距離 3733 1203 | 1204 | 292 1205 | 00:04:12,460 --> 00:04:14,110 1206 | 海拔 127 1207 | 1208 | 293 1209 | 00:04:14,110 --> 00:04:14,860 1210 | 開火 1211 | 1212 | 294 1213 | 00:04:15,150 --> 00:04:16,070 1214 | 開火 1215 | 1216 | 295 1217 | 00:04:19,430 --> 00:04:20,530 1218 | 擊中點 偏後 1219 | 1220 | 296 1221 | 00:04:21,070 --> 00:04:22,030 1222 | 修正射擊 1223 | 1224 | 297 1225 | 00:04:22,030 --> 00:04:23,000 1226 | 開火 1227 | 1228 | 298 1229 | 00:04:23,000 --> 00:04:23,580 1230 | 開火 1231 | 1232 | 299 1233 | 00:04:24,290 --> 00:04:25,490 1234 | 擊中點 偏右 1235 | 1236 | 300 1237 | 00:04:25,490 --> 00:04:26,540 1238 | 修正射擊 1239 | 1240 | 301 1241 | 00:04:30,790 --> 00:04:32,380 1242 | 擊中點 仍偏右 1243 | 1244 | 302 1245 | 00:04:32,780 --> 00:04:34,170 1246 | 還不能確定嗎 1247 | 1248 | 303 1249 | 00:04:34,730 --> 00:04:35,880 1250 | 修正射擊 1251 | 1252 | 304 1253 | 00:05:00,230 --> 00:05:00,360 1254 | 只有通過 1255 | 不斷練習 1256 | 1257 | 305 1258 | 00:05:00,360 --> 00:05:00,480 1259 | 只有通過 1260 | 不斷練習 1261 | 1262 | 306 1263 | 00:05:00,480 --> 00:05:00,610 1264 | 只有通過 1265 | 不斷練習 1266 | 1267 | 307 1268 | 00:05:00,610 --> 00:05:00,730 1269 | 只有通過 1270 | 不斷練習 1271 | 1272 | 308 1273 | 00:05:00,730 --> 00:05:00,860 1274 | 只有通過 1275 | 不斷練習 1276 | 1277 | 309 1278 | 00:05:00,860 --> 00:05:00,980 1279 | 只有通過 1280 | 不斷練習 1281 | 1282 | 310 1283 | 00:05:00,980 --> 00:05:02,740 1284 | 只有通過 1285 | 不斷練習 1286 | 1287 | 311 1288 | 00:05:05,520 --> 00:05:06,740 1289 | 這次一定要 1290 | 1291 | 312 1292 | 00:05:10,830 --> 00:05:12,960 1293 | 我說 你要練習到什麼時候呢 1294 | 1295 | 313 1296 | 00:05:14,400 --> 00:05:15,350 1297 | 做到了 1298 | 1299 | 314 1300 | 00:05:15,350 --> 00:05:16,470 1301 | 我做到了 1302 | 1303 | 315 1304 | 00:05:19,240 --> 00:05:20,160 1305 | 給你 請喝 1306 | 1307 | 316 1308 | 00:05:20,600 --> 00:05:22,060 1309 | 非常感謝 1310 | 1311 | 317 1312 | 00:05:22,740 --> 00:05:24,350 1313 | 喝完就去休息了喔 1314 | 1315 | 318 1316 | 00:05:29,360 --> 00:05:31,640 1317 | 看來你找到翻蛋捲的竅門了呢 1318 | 1319 | 319 1320 | 00:05:31,640 --> 00:05:31,760 1321 | 只有通過 1322 | 不斷練習 1323 | 1324 | 320 1325 | 00:05:31,760 --> 00:05:31,890 1326 | 只有通過 1327 | 不斷練習 1328 | 1329 | 321 1330 | 00:05:31,890 --> 00:05:32,010 1331 | 只有通過 1332 | 不斷練習 1333 | 1334 | 322 1335 | 00:05:32,010 --> 00:05:32,140 1336 | 只有通過 1337 | 不斷練習 1338 | 1339 | 323 1340 | 00:05:32,140 --> 00:05:34,150 1341 | 只有通過 1342 | 不斷練習 1343 | 1344 | 324 1345 | 00:05:32,350 --> 00:05:34,150 1346 | 多虧了箒星 1347 | 1348 | 325 1349 | 00:05:34,870 --> 00:05:36,620 1350 | 請問 鴉羽 1351 | 1352 | 326 1353 | 00:05:37,250 --> 00:05:40,830 1354 | 箒星為什麼發不出聲音呢 1355 | 1356 | 327 1357 | 00:05:40,830 --> 00:05:41,750 1358 | 這是因為… 1359 | 1360 | 328 1361 | 00:05:42,120 --> 00:05:45,190 1362 | 以前好像還是可以說話的 1363 | 1364 | 329 1365 | 00:05:45,710 --> 00:05:46,940 1366 | 你是怎麼知道的 1367 | 1368 | 330 1369 | 00:05:47,330 --> 00:05:49,980 1370 | 是她告訴我的 她過去的事情 1371 | 1372 | 331 1373 | 00:05:49,980 --> 00:05:52,560 1374 | 喔 和箒星連結了是吧 1375 | 1376 | 332 1377 | 00:05:52,820 --> 00:05:53,480 1378 | 是的 1379 | 1380 | 333 1381 | 00:05:53,920 --> 00:05:57,070 1382 | 像是在腦海裡向我述說一樣 1383 | 1384 | 334 1385 | 00:05:57,070 --> 00:05:58,790 1386 | 非常不可思議 1387 | 1388 | 335 1389 | 00:05:58,790 --> 00:06:00,930 1390 | 同一世代的人偶 1391 | 1392 | 336 1393 | 00:06:01,170 --> 00:06:03,590 1394 | 可以通過連結共享記憶 1395 | 1396 | 337 1397 | 00:06:03,970 --> 00:06:09,180 1398 | 是的 原本她是可以發出聲音的 1399 | 1400 | 338 1401 | 00:06:09,650 --> 00:06:12,430 1402 | 但是發生了很多事情 然後就壞掉了 1403 | 1404 | 339 1405 | 00:06:12,780 --> 00:06:14,170 1406 | 修不好嗎 1407 | 1408 | 340 1409 | 00:06:14,930 --> 00:06:17,310 1410 | 辦法倒是有一個 1411 | 1412 | 341 1413 | 00:06:17,560 --> 00:06:20,190 1414 | 但是 這個辦法有很大的問題 1415 | 1416 | 342 1417 | 00:06:28,390 --> 00:06:32,330 1418 | 箒星 你真的要初始化嗎 1419 | 1420 | 343 1421 | 00:06:33,990 --> 00:06:35,880 1422 | 不行 你不能初始化啊 1423 | 1424 | 344 1425 | 00:06:35,880 --> 00:06:38,790 1426 | 那可是會失去自己珍貴記憶的 1427 | 1428 | 345 1429 | 00:06:38,790 --> 00:06:41,280 1430 | 請…請你三思啊 1431 | 1432 | 346 1433 | 00:06:41,280 --> 00:06:43,930 1434 | 雖然我什麼都做不了 1435 | 1436 | 347 1437 | 00:06:43,930 --> 00:06:45,690 1438 | 但是…就是… 1439 | 1440 | 348 1441 | 00:06:46,500 --> 00:06:48,690 1442 | 對了 我可以唱歌 1443 | 1444 | 349 1445 | 00:06:48,690 --> 00:06:49,880 1446 | 為你打氣 1447 | 1448 | 350 1449 | 00:06:50,470 --> 00:06:54,730 1450 | 在這獨一無二的世間之中 1451 | 1452 | 351 1453 | 00:06:54,730 --> 00:06:58,500 1454 | 尋找著自己誕生的意義 1455 | 1456 | 352 1457 | 00:06:58,500 --> 00:07:04,190 1458 | 讓歌聲響徹吧 劃過天空 直至與你度過的每… 1459 | 1460 | 353 1461 | 00:07:07,280 --> 00:07:08,960 1462 | 是這樣的嗎 1463 | 1464 | 354 1465 | 00:07:09,440 --> 00:07:12,750 1466 | 和大家一起開了這家咖啡店 1467 | 1468 | 355 1469 | 00:07:15,870 --> 00:07:17,080 1470 | 太好了 1471 | 1472 | 356 1473 | 00:07:17,080 --> 00:07:17,200 1474 | 並不是要初始化 1475 | 1476 | 357 1477 | 00:07:17,200 --> 00:07:17,330 1478 | 並不是要初始化 1479 | 1480 | 358 1481 | 00:07:17,330 --> 00:07:17,450 1482 | 並不是要初始化 1483 | 1484 | 359 1485 | 00:07:17,450 --> 00:07:18,830 1486 | 並不是要初始化 1487 | 1488 | 360 1489 | 00:07:18,830 --> 00:07:20,660 1490 | 我還以為一定是要初始化了 1491 | 1492 | 361 1493 | 00:07:22,170 --> 00:07:22,290 1494 | 雖然我也 1495 | 想修好 1496 | 1497 | 362 1498 | 00:07:22,290 --> 00:07:22,420 1499 | 雖然我也 1500 | 想修好 1501 | 1502 | 363 1503 | 00:07:22,420 --> 00:07:22,540 1504 | 雖然我也 1505 | 想修好 1506 | 1507 | 364 1508 | 00:07:22,540 --> 00:07:24,550 1509 | 雖然我也 1510 | 想修好 1511 | 1512 | 365 1513 | 00:07:24,550 --> 00:07:28,890 1514 | 那個…真的是因為戰爭壞掉的嗎 1515 | 1516 | 366 1517 | 00:07:39,930 --> 00:07:40,650 1518 | 這個… 1519 | 1520 | 367 1521 | 00:07:45,880 --> 00:07:49,720 1522 | 不知是從何時起 我的歌成為了軍中的大熱門 1523 | 1524 | 368 1525 | 00:07:50,280 --> 00:07:52,700 1526 | 只要在出擊之前聽了我的歌聲 1527 | 1528 | 369 1529 | 00:07:52,950 --> 00:07:54,690 1530 | 在戰場就不會懼怕死亡 1531 | 1532 | 370 1533 | 00:07:55,120 --> 00:07:56,500 1534 | 這只不過是迷信而已 1535 | 1536 | 371 1537 | 00:07:57,080 --> 00:08:00,040 1538 | 但即便知道是假的 1539 | 1540 | 372 1541 | 00:08:00,040 --> 00:08:01,790 1542 | 大家也想緊握這僅有的希望 1543 | 1544 | 373 1545 | 00:08:02,360 --> 00:08:06,550 1546 | 或許這就是絕望之中為數不多的依靠吧 1547 | 1548 | 374 1549 | 00:08:07,460 --> 00:08:11,240 1550 | 歸還歷 595年7月24日 1551 | 1552 | 375 1553 | 00:08:11,680 --> 00:08:15,990 1554 | 我在戰場上服役了十幾年仍平安無事 1555 | 1556 | 376 1557 | 00:08:15,990 --> 00:08:18,050 1558 | 這都是因為我的職責是後方支援 1559 | 1560 | 377 1561 | 00:08:18,500 --> 00:08:21,560 1562 | 但是如此好運 也無法一直繼續下去的吧 1563 | 1564 | 378 1565 | 00:08:22,860 --> 00:08:25,070 1566 | 打擾了 我是山衛 1567 | 1568 | 379 1569 | 00:08:25,580 --> 00:08:26,800 1570 | 你在寫日記嗎 1571 | 1572 | 380 1573 | 00:08:27,300 --> 00:08:29,820 1574 | 箒星閣下真是好動筆的人啊 1575 | 1576 | 381 1577 | 00:08:30,090 --> 00:08:31,530 1578 | 這只是我的習慣而已 1579 | 1580 | 382 1581 | 00:08:31,530 --> 00:08:34,170 1582 | 寫出來的話 內心也會跟著平靜起來 1583 | 1584 | 383 1585 | 00:08:34,170 --> 00:08:35,070 1586 | 我能理解 1587 | 1588 | 384 1589 | 00:08:35,400 --> 00:08:40,110 1590 | 昨天我也寫了封信給父母和妹妹 1591 | 1592 | 385 1593 | 00:08:40,520 --> 00:08:42,330 1594 | 希望信能平安地送到他們的手裡 1595 | 1596 | 386 1597 | 00:08:42,860 --> 00:08:46,680 1598 | 對了 我是來給箒星閣下做嚮導的 1599 | 1600 | 387 1601 | 00:08:47,020 --> 00:08:49,470 1602 | 做嚮導…都這麼晚了 1603 | 1604 | 388 1605 | 00:08:50,270 --> 00:08:51,900 1606 | 今天是夏日祭典 1607 | 1608 | 389 1609 | 00:08:59,230 --> 00:09:00,960 1610 | 就像燈籠一樣吧 1611 | 1612 | 390 1613 | 00:09:02,200 --> 00:09:04,150 1614 | 你看 那邊還有小攤販 1615 | 1616 | 391 1617 | 00:09:05,110 --> 00:09:07,150 1618 | 是大家自己動手做的嗎 1619 | 1620 | 392 1621 | 00:09:08,070 --> 00:09:10,400 1622 | 雖然長官並不怎麼贊同 1623 | 1624 | 393 1625 | 00:09:11,100 --> 00:09:13,080 1626 | 但明天就是最重要的決戰了 1627 | 1628 | 394 1629 | 00:09:19,460 --> 00:09:24,040 1630 | 我們第525連隊的女神 箒星閣下登場 1631 | 1632 | 395 1633 | 00:09:24,770 --> 00:09:26,550 1634 | 接下來有請她來給我們作戰前動員 1635 | 1636 | 396 1637 | 00:09:27,840 --> 00:09:30,800 1638 | 那…那個 我要做什麼呢 1639 | 1640 | 397 1641 | 00:09:31,400 --> 00:09:33,240 1642 | 希望你能為大家唱首歌 1643 | 1644 | 398 1645 | 00:09:33,240 --> 00:09:34,120 1646 | 唱歌… 1647 | 1648 | 399 1649 | 00:09:34,660 --> 00:09:36,310 1650 | 明天就是決戰了 1651 | 1652 | 400 1653 | 00:09:36,880 --> 00:09:39,470 1654 | 恐怕在座的各位都難以活著回來 1655 | 1656 | 401 1657 | 00:09:41,260 --> 00:09:43,730 1658 | 我們需要不懼死亡的勇氣 1659 | 1660 | 402 1661 | 00:09:46,410 --> 00:09:50,480 1662 | 希望你能為我們送別 1663 | 1664 | 403 1665 | 00:09:59,650 --> 00:10:01,970 1666 | 星導~ホシシルベ~ 1667 | 1668 | 404 1669 | 00:09:59,650 --> 00:10:01,970 1670 | 閃耀於星空中的路標 1671 | 1672 | 405 1673 | 00:10:01,970 --> 00:10:09,830 1674 | いま 有終の笑顔が羽撃きます 1675 | 1676 | 406 1677 | 00:10:01,970 --> 00:10:09,830 1678 | 如今 完成使命露出笑容 展翅高飛 1679 | 1680 | 407 1681 | 00:10:10,030 --> 00:10:12,940 1682 | 儚く強く… 1683 | 1684 | 408 1685 | 00:10:10,030 --> 00:10:12,940 1686 | 面對這虛幻… 1687 | 1688 | 409 1689 | 00:10:16,710 --> 00:10:20,000 1690 | 對不起…我唱不出來… 1691 | 1692 | 410 1693 | 00:10:20,940 --> 00:10:21,940 1694 | 我… 1695 | 1696 | 411 1697 | 00:10:24,670 --> 00:10:28,000 1698 | 我的歌能帶給他們些許勇氣 1699 | 1700 | 412 1701 | 00:10:28,000 --> 00:10:29,740 1702 | 我如此堅信著 為他們歌唱 1703 | 1704 | 413 1705 | 00:10:30,150 --> 00:10:34,110 1706 | 但他們早已做好了準備面對這無法迴避的命運 1707 | 1708 | 414 1709 | 00:10:34,660 --> 00:10:38,250 1710 | 我的職責是給予他們去戰死的勇氣嗎 1711 | 1712 | 415 1713 | 00:10:38,660 --> 00:10:42,030 1714 | 每當想起這個問題 我就再也發不出聲音了 1715 | 1716 | 416 1717 | 00:10:42,660 --> 00:10:48,410 1718 | 也無法目送第525連隊前往他們最後的歸宿 1719 | 1720 | 417 1721 | 00:10:49,360 --> 00:10:51,150 1722 | 他們究竟是全軍覆沒了呢 1723 | 1724 | 418 1725 | 00:10:51,380 --> 00:10:54,040 1726 | 還是有人倖存下來了呢 1727 | 1728 | 419 1729 | 00:10:55,180 --> 00:10:57,690 1730 | 最終 經過許久 1731 | 1732 | 420 1733 | 00:10:57,690 --> 00:11:00,060 1734 | 凪將我修好了 1735 | 1736 | 421 1737 | 00:11:00,480 --> 00:11:02,520 1738 | 可是 別說是唱歌了 1739 | 1740 | 422 1741 | 00:11:02,520 --> 00:11:04,910 1742 | 就連說話我都做不到了 1743 | 1744 | 423 1745 | 00:11:15,250 --> 00:11:16,700 1746 | 那…那個… 1747 | 1748 | 424 1749 | 00:11:16,990 --> 00:11:20,940 1750 | 我認為你並不是壞掉了 1751 | 1752 | 425 1753 | 00:11:20,940 --> 00:11:25,540 1754 | 一定是那時的事情太過於悲傷 所以才發不出聲音了 1755 | 1756 | 426 1757 | 00:11:26,040 --> 00:11:30,560 1758 | 部隊一定有人還活著 1759 | 1760 | 427 1761 | 00:11:30,920 --> 00:11:33,660 1762 | 想要再聽你唱一首歌 1763 | 1764 | 428 1765 | 00:11:33,660 --> 00:11:35,510 1766 | 所以…所以說… 1767 | 1768 | 429 1769 | 00:11:36,090 --> 00:11:36,130 1770 | 只有通過 1771 | 不斷練習 1772 | 1773 | 430 1774 | 00:11:36,130 --> 00:11:36,250 1775 | 只有通過 1776 | 不斷練習 1777 | 1778 | 431 1779 | 00:11:36,250 --> 00:11:36,380 1780 | 只有通過 1781 | 不斷練習 1782 | 1783 | 432 1784 | 00:11:36,380 --> 00:11:36,460 1785 | 只有通過 1786 | 不斷練習 1787 | 1788 | 433 1789 | 00:11:36,460 --> 00:11:36,550 1790 | 只有通過 1791 | 不斷練習 1792 | 1793 | 434 1794 | 00:11:36,550 --> 00:11:36,630 1795 | 只有通過 1796 | 不斷練習 1797 | 1798 | 435 1799 | 00:11:36,630 --> 00:11:36,710 1800 | 只有通過 1801 | 不斷練習 1802 | 1803 | 436 1804 | 00:11:36,710 --> 00:11:36,800 1805 | 只有通過 1806 | 不斷練習 1807 | 1808 | 437 1809 | 00:11:36,800 --> 00:11:36,880 1810 | 只有通過 1811 | 不斷練習 1812 | 1813 | 438 1814 | 00:11:36,880 --> 00:11:36,960 1815 | 只有通過 1816 | 不斷練習 1817 | 1818 | 439 1819 | 00:11:36,960 --> 00:11:37,050 1820 | 只有通過 1821 | 不斷練習 1822 | 1823 | 440 1824 | 00:11:37,050 --> 00:11:37,180 1825 | 只有通過 1826 | 不斷練習 1827 | 1828 | 441 1829 | 00:11:37,180 --> 00:11:39,260 1830 | 只有通過 1831 | 不斷練習 1832 | 1833 | 442 1834 | 00:11:37,420 --> 00:11:39,260 1835 | 我們來練習吧 1836 | 1837 | 443 1838 | 00:11:48,240 --> 00:11:49,960 1839 | 號外號外 1840 | 1841 | 444 1842 | 00:11:50,270 --> 00:11:54,280 1843 | 大陸派遣軍第四批馬上就要回到皇國 1844 | 1845 | 445 1846 | 00:11:58,410 --> 00:12:01,410 1847 | 皇都運動會正在進行 1848 | 1849 | 446 1850 | 00:11:58,410 --> 00:12:01,410 1851 | 第五二五步兵連亦在名冊上 1852 | 1853 | 447 1854 | 00:11:58,410 --> 00:12:01,410 1855 | 第四批即將回到皇都 1856 | 1857 | 448 1858 | 00:12:01,620 --> 00:12:08,670 1859 | 讓歌聲響徹吧 劃過天空 直至與你度過的每一天 1860 | 1861 | 449 1862 | 00:12:08,670 --> 00:12:12,600 1863 | 因那點綴初始的櫻花色 1864 | 1865 | 450 1866 | 00:12:12,610 --> 00:12:14,710 1867 | 那三個人在做什麼呢 1868 | 1869 | 451 1870 | 00:12:14,710 --> 00:12:17,170 1871 | 說是讓箒星再次說出話的練習 1872 | 1873 | 452 1874 | 00:12:17,630 --> 00:12:20,930 1875 | 真是的 早上的工作都沒有做完 1876 | 1877 | 453 1878 | 00:12:21,460 --> 00:12:23,780 1879 | 算了算了 這不是蠻有趣的嗎 1880 | 1881 | 454 1882 | 00:12:23,780 --> 00:12:26,920 1883 | 主人 你太寵灰櫻了 1884 | 1885 | 455 1886 | 00:12:29,370 --> 00:12:31,440 1887 | 月下 你回來啦 1888 | 1889 | 456 1890 | 00:12:32,970 --> 00:12:35,070 1891 | 我買完東西回來了 1892 | 1893 | 457 1894 | 00:12:36,090 --> 00:12:37,030 1895 | 辛苦了 1896 | 1897 | 458 1898 | 00:12:37,300 --> 00:12:38,500 1899 | 一直都是拜託你 抱歉了 1900 | 1901 | 459 1902 | 00:12:39,030 --> 00:12:41,030 1903 | 畢竟我最適合做這件事情 1904 | 1905 | 460 1906 | 00:12:42,520 --> 00:12:43,530 1907 | 怎麼了 1908 | 1909 | 461 1910 | 00:12:46,650 --> 00:12:48,410 1911 | 這樣的話 難道說… 1912 | 1913 | 462 1914 | 00:12:52,850 --> 00:12:56,590 1915 | 第525連隊的人一定還活著 1916 | 1917 | 463 1918 | 00:12:58,190 --> 00:13:01,720 1919 | 大家一定很期待見到你 1920 | 1921 | 464 1922 | 00:13:01,960 --> 00:13:02,090 1923 | 或許他們 1924 | 已經把我忘記了 1925 | 1926 | 465 1927 | 00:13:02,090 --> 00:13:02,210 1928 | 或許他們 1929 | 已經把我忘記了 1930 | 1931 | 466 1932 | 00:13:02,210 --> 00:13:04,220 1933 | 或許他們 1934 | 已經把我忘記了 1935 | 1936 | 467 1937 | 00:13:02,860 --> 00:13:04,220 1938 | 這是不可能的 1939 | 1940 | 468 1941 | 00:13:06,140 --> 00:13:07,350 1942 | 已經開始營業了 1943 | 1944 | 469 1945 | 00:13:07,960 --> 00:13:09,540 1946 | 該去前台接待了 灰櫻 1947 | 1948 | 470 1949 | 00:13:10,100 --> 00:13:11,040 1950 | 好 1951 | 1952 | 471 1953 | 00:13:11,040 --> 00:13:13,970 1954 | 箒星 一定要一起去迎接他們 1955 | 1956 | 472 1957 | 00:13:19,530 --> 00:13:21,910 1958 | 快點快點 他們已經到港了 1959 | 1960 | 473 1961 | 00:13:22,220 --> 00:13:23,910 1962 | 等一等 1963 | 1964 | 474 1965 | 00:13:27,260 --> 00:13:28,660 1966 | 已經這麼多人了呢 1967 | 1968 | 475 1969 | 00:13:32,790 --> 00:13:32,910 1970 | 人好多呢 1971 | 1972 | 476 1973 | 00:13:32,910 --> 00:13:33,040 1974 | 人好多呢 1975 | 1976 | 477 1977 | 00:13:33,040 --> 00:13:34,420 1978 | 人好多呢 1979 | 1980 | 478 1981 | 00:13:34,880 --> 00:13:39,020 1982 | 第一批回國的時候都沒有這麼多人呢 1983 | 1984 | 479 1985 | 00:13:39,020 --> 00:13:41,680 1986 | 大家都迫不及待地想迎接他們歸來了吧 1987 | 1988 | 480 1989 | 00:13:48,360 --> 00:13:52,810 1990 | 接下來 第525連隊凱旋回國 1991 | 1992 | 481 1993 | 00:14:14,540 --> 00:14:15,540 1994 | 為什麼… 1995 | 1996 | 482 1997 | 00:14:15,960 --> 00:14:18,340 1998 | 大家好像都犧牲了 1999 | 2000 | 483 2001 | 00:14:28,880 --> 00:14:30,120 2002 | 箒星 2003 | 2004 | 484 2005 | 00:14:31,570 --> 00:14:32,630 2006 | 箒星… 2007 | 2008 | 485 2009 | 00:14:40,280 --> 00:14:41,700 2010 | 箒星 2011 | 2012 | 486 2013 | 00:14:42,010 --> 00:14:43,730 2014 | 還是忘記了比較好 2015 | 2016 | 487 2017 | 00:14:45,220 --> 00:14:47,530 2018 | 大家都是如此 2019 | 2020 | 488 2021 | 00:14:49,180 --> 00:14:52,290 2022 | 這樣也太悲傷了吧 2023 | 2024 | 489 2025 | 00:14:53,140 --> 00:14:55,790 2026 | 箒星 今天已經可以下班了 2027 | 2028 | 490 2029 | 00:14:56,290 --> 00:14:58,710 2030 | 接下來交給我 你去休息吧 2031 | 2032 | 491 2033 | 00:15:01,290 --> 00:15:03,490 2034 | 那個…箒星 2035 | 2036 | 492 2037 | 00:15:03,490 --> 00:15:05,180 2038 | 就是…練習呢 2039 | 2040 | 493 2041 | 00:15:18,480 --> 00:15:22,960 2042 | 請問 第525連隊的大家真的… 2043 | 2044 | 494 2045 | 00:15:23,320 --> 00:15:26,860 2046 | 最後回到皇國的只有遺骨和連隊旗幟 2047 | 2048 | 495 2049 | 00:15:27,260 --> 00:15:29,960 2050 | 好像歸來就是這麼一回事 2051 | 2052 | 496 2053 | 00:15:29,960 --> 00:15:32,410 2054 | 大家都犧牲了嗎 2055 | 2056 | 497 2057 | 00:15:32,410 --> 00:15:36,270 2058 | 不知道 去靈堂就知道了 2059 | 2060 | 498 2061 | 00:15:37,610 --> 00:15:39,370 2062 | 我這就去 2063 | 2064 | 499 2065 | 00:15:39,370 --> 00:15:40,180 2066 | 現在嗎 2067 | 2068 | 500 2069 | 00:15:41,060 --> 00:15:43,590 2070 | 等一等…灰櫻 2071 | 2072 | 501 2073 | 00:16:03,280 --> 00:16:04,500 2074 | 那邊 那個人 2075 | 2076 | 502 2077 | 00:16:05,650 --> 00:16:10,280 2078 | 我…我想問一下關於第525連隊的事情… 2079 | 2080 | 503 2081 | 00:16:16,390 --> 00:16:17,650 2082 | 我也有對你… 2083 | 2084 | 504 2085 | 00:16:18,030 --> 00:16:21,810 2086 | 不對 有對你們想說的事情 2087 | 2088 | 505 2089 | 00:16:25,050 --> 00:16:28,430 2090 | 灰櫻 2091 | 2092 | 506 2093 | 00:16:28,720 --> 00:16:30,330 2094 | 對不起… 2095 | 2096 | 507 2097 | 00:16:30,330 --> 00:16:31,840 2098 | 我可是很擔心你的 2099 | 2100 | 508 2101 | 00:16:31,840 --> 00:16:33,650 2102 | 就那樣直接跑出去不回來了 2103 | 2104 | 509 2105 | 00:16:33,910 --> 00:16:35,430 2106 | 你昨天晚上住哪裡了 2107 | 2108 | 510 2109 | 00:16:35,690 --> 00:16:38,930 2110 | 好啦好啦 她不是也電話聯繫我們了嗎 2111 | 2112 | 511 2113 | 00:16:39,980 --> 00:16:41,810 2114 | 主人太好說話了 2115 | 2116 | 512 2117 | 00:16:42,290 --> 00:16:45,510 2118 | 總之 讓我們先聽聽灰櫻怎麼說吧 2119 | 2120 | 513 2121 | 00:16:47,650 --> 00:16:51,660 2122 | 然後呢 我在靈堂認識了一個女孩子 2123 | 2124 | 514 2125 | 00:16:51,660 --> 00:16:53,320 2126 | 然後我就去她家了 2127 | 2128 | 515 2129 | 00:16:53,630 --> 00:16:55,100 2130 | 你太好騙了吧 2131 | 2132 | 516 2133 | 00:16:55,380 --> 00:16:56,790 2134 | 才不是 2135 | 2136 | 517 2137 | 00:16:56,790 --> 00:17:01,590 2138 | 那個女孩的哥哥 是第525連隊的軍官 2139 | 2140 | 518 2141 | 00:17:02,040 --> 00:17:02,810 2142 | 名字呢 2143 | 2144 | 519 2145 | 00:17:03,250 --> 00:17:04,340 2146 | 山衛上尉 2147 | 2148 | 520 2149 | 00:17:05,990 --> 00:17:09,550 2150 | 這個是他妹妹華交給我的 2151 | 2152 | 521 2153 | 00:17:10,180 --> 00:17:12,840 2154 | 說是在哥哥遺物中發現的 2155 | 2156 | 522 2157 | 00:17:13,150 --> 00:17:16,920 2158 | 希望我能交給你 2159 | 2160 | 523 2161 | 00:17:19,510 --> 00:17:21,770 2162 | 箒星閣下 你還好嗎 2163 | 2164 | 524 2165 | 00:17:22,400 --> 00:17:24,320 2166 | 如果能活著再見一面就好了 2167 | 2168 | 525 2169 | 00:17:24,560 --> 00:17:26,480 2170 | 我這次沒有這麼好運活下來了吧 2171 | 2172 | 526 2173 | 00:17:27,150 --> 00:17:31,480 2174 | 不過 我堅信著閣下能平安回國 2175 | 2176 | 527 2177 | 00:17:32,000 --> 00:17:36,470 2178 | 這封信是為了向你再一次傳達謝意而寫 2179 | 2180 | 528 2181 | 00:17:37,150 --> 00:17:38,160 2182 | 在夏日祭典的那一天 2183 | 2184 | 529 2185 | 00:17:38,790 --> 00:17:43,030 2186 | 你牽掛著我們的命運 是強忍淚水為我們歌唱的吧 2187 | 2188 | 530 2189 | 00:17:43,880 --> 00:17:46,150 2190 | 我們正是被你的淚水所救贖 2191 | 2192 | 531 2193 | 00:17:46,760 --> 00:17:49,320 2194 | 那份和我們一同承擔痛苦的溫柔 2195 | 2196 | 532 2197 | 00:17:49,620 --> 00:17:51,090 2198 | 讓我們非常開心 2199 | 2200 | 533 2201 | 00:17:51,800 --> 00:17:55,570 2202 | 閣下是如同閃耀於星空中路標般的人 2203 | 2204 | 534 2205 | 00:17:56,360 --> 00:17:58,170 2206 | 現在 我的內心甚是平靜 2207 | 2208 | 535 2209 | 00:17:58,480 --> 00:18:00,750 2210 | 一點都不畏懼命運 2211 | 2212 | 536 2213 | 00:18:01,680 --> 00:18:04,950 2214 | 如果我的遺骨能夠回到內陸的話 2215 | 2216 | 537 2217 | 00:18:05,220 --> 00:18:10,190 2218 | 希望那時候你能用一句「你努力了」來撫慰我 2219 | 2220 | 538 2221 | 00:18:13,050 --> 00:18:14,210 2222 | 箒星 2223 | 2224 | 539 2225 | 00:18:15,590 --> 00:18:17,620 2226 | 不管是山衛上尉 還是其他人 2227 | 2228 | 540 2229 | 00:18:17,960 --> 00:18:19,450 2230 | 大家都沒有責怪你 2231 | 2232 | 541 2233 | 00:18:19,800 --> 00:18:22,460 2234 | 你打從心底為大家著想的事實 2235 | 2236 | 542 2237 | 00:18:22,830 --> 00:18:25,460 2238 | 真的是最好的撫慰了 2239 | 2240 | 543 2241 | 00:18:29,320 --> 00:18:30,900 2242 | 箒星 你… 2243 | 2244 | 544 2245 | 00:18:31,230 --> 00:18:31,970 2246 | 聲音… 2247 | 2248 | 545 2249 | 00:18:39,600 --> 00:18:41,350 2250 | 今日 2251 | 包場 2252 | 2253 | 546 2254 | 00:18:45,650 --> 00:18:48,730 2255 | 謝謝你能來 小華 2256 | 2257 | 547 2258 | 00:18:49,100 --> 00:18:52,300 2259 | 因為烈士家屬會的各位都希望列席參加 2260 | 2261 | 548 2262 | 00:18:52,550 --> 00:18:54,420 2263 | 就覺得這裡正好 2264 | 2265 | 549 2266 | 00:18:54,900 --> 00:18:58,980 2267 | 或許哥哥有點不合適這種時尚的咖啡廳 2268 | 2269 | 550 2270 | 00:19:03,810 --> 00:19:06,010 2271 | 箒星 準備好了嗎 2272 | 2273 | 551 2274 | 00:19:06,830 --> 00:19:09,980 2275 | 廚房就交給我和稻葉吧 2276 | 2277 | 552 2278 | 00:19:09,980 --> 00:19:11,960 2279 | 這才是我最不放心的點 2280 | 2281 | 553 2282 | 00:19:13,900 --> 00:19:15,720 2283 | 時間到了 可以嗎 2284 | 2285 | 554 2286 | 00:19:35,540 --> 00:19:38,110 2287 | 箒星 加油啊 2288 | 2289 | 555 2290 | 00:19:41,030 --> 00:19:42,800 2291 | 我…是… 2292 | 2293 | 556 2294 | 00:19:43,200 --> 00:19:47,870 2295 | 我是箒星 是一個自律人偶 2296 | 2297 | 557 2298 | 00:19:49,260 --> 00:19:53,040 2299 | 居然不用初始化就修好了她的邏輯機關 2300 | 2301 | 558 2302 | 00:19:53,390 --> 00:19:55,130 2303 | 完全沒想到 2304 | 2305 | 559 2306 | 00:19:55,440 --> 00:20:00,290 2307 | 我之前和第525連隊的大家一起行動過 2308 | 2309 | 560 2310 | 00:20:00,600 --> 00:20:01,890 2311 | 所以今天 2312 | 2313 | 561 2314 | 00:20:01,890 --> 00:20:06,870 2315 | 就讓我們聊一聊那些勇敢溫柔 令人敬愛的伙伴們吧 2316 | 2317 | 562 2318 | 00:20:07,140 --> 00:20:10,170 2319 | 那時 我實在是太過於悲傷 2320 | 2321 | 563 2322 | 00:20:10,170 --> 00:20:12,680 2323 | 唱著歌 淚水不斷地從眼裡湧出 2324 | 2325 | 564 2326 | 00:20:13,300 --> 00:20:16,840 2327 | 一直對那件事情耿耿於懷 2328 | 2329 | 565 2330 | 00:20:17,590 --> 00:20:18,810 2331 | 但是 今天 2332 | 2333 | 566 2334 | 00:20:19,160 --> 00:20:24,430 2335 | 我想再一次將這歌聲送給各位 送給烈士們 2336 | 2337 | 567 2338 | 00:20:28,400 --> 00:20:30,710 2339 | 星導~ホシシルベ~ 2340 | 2341 | 568 2342 | 00:20:28,400 --> 00:20:30,710 2343 | 閃耀於星空中的路標 2344 | 2345 | 569 2346 | 00:20:30,710 --> 00:20:38,720 2347 | いま 有終の笑顔が羽撃きます 2348 | 2349 | 570 2350 | 00:20:30,710 --> 00:20:38,720 2351 | 如今 完成使命露出笑容 展翅高飛 2352 | 2353 | 571 2354 | 00:20:38,720 --> 00:20:43,380 2355 | 儚く強く輝いた 2356 | 2357 | 572 2358 | 00:20:38,720 --> 00:20:43,380 2359 | 面對這虛幻的宿命 2360 | 2361 | 573 2362 | 00:20:43,380 --> 00:20:49,230 2363 | 超越那閃耀的命運 2364 | 2365 | 574 2366 | 00:20:43,380 --> 00:20:49,230 2367 | 運命を超えるように 2368 | 2369 | 575 2370 | 00:20:49,630 --> 00:20:51,970 2371 | 將這一切的回憶 2372 | 2373 | 576 2374 | 00:20:49,630 --> 00:20:51,970 2375 | 憶いよ安らかに 2376 | 2377 | 577 2378 | 00:20:51,970 --> 00:20:54,400 2379 | 惜しみなく捧げよう 2380 | 2381 | 578 2382 | 00:20:51,970 --> 00:20:54,400 2383 | 毫無保留地獻出 2384 | 2385 | 579 2386 | 00:20:54,400 --> 00:21:00,150 2387 | 這永遠的歌曲 響徹吧 2388 | 2389 | 580 2390 | 00:20:54,400 --> 00:21:00,150 2391 | 響け、永遠の歌 2392 | 2393 | 581 2394 | 00:20:55,740 --> 00:20:56,880 2395 | 箒星 2396 | 2397 | 582 2398 | 00:20:57,210 --> 00:20:57,780 2399 | 小灰 2400 | 2401 | 583 2402 | 00:20:58,420 --> 00:21:00,150 2403 | 這是我的慰問品 2404 | 2405 | 584 2406 | 00:21:01,820 --> 00:21:03,570 2407 | 謝謝你 2408 | 2409 | 585 2410 | 00:21:05,740 --> 00:21:07,680 2411 | 這都是多虧了小灰 2412 | 2413 | 586 2414 | 00:21:07,970 --> 00:21:10,460 2415 | 怎麼會 我什麼都沒有做 2416 | 2417 | 587 2418 | 00:21:11,040 --> 00:21:13,440 2419 | 信和日記真是好啊 2420 | 2421 | 588 2422 | 00:21:11,640 --> 00:21:16,470 2423 | 花を散らし 渡る風は 2424 | 2425 | 589 2426 | 00:21:11,640 --> 00:21:16,470 2427 | 西風吹謝花成泥 2428 | 2429 | 590 2430 | 00:21:14,410 --> 00:21:17,960 2431 | 可以將自己的心意永遠留存下來 2432 | 2433 | 591 2434 | 00:21:16,760 --> 00:21:21,600 2435 | 次の季節 種子を運ぶ 2436 | 2437 | 592 2438 | 00:21:16,760 --> 00:21:21,600 2439 | 為下個季節播種新生命 2440 | 2441 | 593 2442 | 00:21:20,400 --> 00:21:22,430 2443 | 你也要試著寫一寫嗎 2444 | 2445 | 594 2446 | 00:21:21,920 --> 00:21:27,000 2447 | いのち散らし 逝く星座は 2448 | 2449 | 595 2450 | 00:21:21,920 --> 00:21:27,000 2451 | 生離死別的星座 2452 | 2453 | 596 2454 | 00:21:27,000 --> 00:21:32,400 2455 | 在未來之中閃閃發光 2456 | 2457 | 597 2458 | 00:21:27,000 --> 00:21:32,400 2459 | 未来にきらめく… 2460 | 2461 | 598 2462 | 00:21:28,850 --> 00:21:33,070 2463 | 我還有備用的日記本 和鋼筆一起送給你吧 2464 | 2465 | 599 2466 | 00:21:34,020 --> 00:21:35,110 2467 | 可以嗎 2468 | 2469 | 600 2470 | 00:21:37,160 --> 00:21:40,190 2471 | 請你收下吧 這裡飽含了我的謝意 2472 | 2473 | 601 2474 | 00:21:43,120 --> 00:21:45,300 2475 | 謝謝你 2476 | 2477 | 602 2478 | 00:21:45,300 --> 00:21:47,330 2479 | 那這就來寫今天的日記吧… 2480 | 2481 | 603 2482 | 00:21:50,570 --> 00:21:52,710 2483 | 要怎麼開始寫呢 2484 | 2485 | 604 2486 | 00:21:52,350 --> 00:21:57,300 2487 | 悲劇に報いる 2488 | 2489 | 605 2490 | 00:21:52,350 --> 00:21:57,300 2491 | 悲劇總將迎來新生 2492 | 2493 | 606 2494 | 00:21:54,130 --> 00:21:56,960 2495 | 首先寫下自己的感情就好了 2496 | 2497 | 607 2498 | 00:21:57,560 --> 00:22:00,960 2499 | 不論是開心的事情 還是悲傷的事情 2500 | 2501 | 608 2502 | 00:21:57,590 --> 00:22:04,200 2503 | 由言語所交織而成的旋律 2504 | 2505 | 609 2506 | 00:21:57,590 --> 00:22:04,200 2507 | 言の葉 紡ぐ旋律 2508 | 2509 | 610 2510 | 00:22:04,870 --> 00:22:11,920 2511 | 在慈愛之中漸入夢鄉 2512 | 2513 | 611 2514 | 00:22:04,870 --> 00:22:11,920 2515 | 慈しみ鎮めましょう 2516 | 2517 | 612 2518 | 00:22:09,590 --> 00:22:16,200 2519 | そっと寄り添うように 2520 | 2521 | 613 2522 | 00:22:09,590 --> 00:22:16,200 2523 | 悄悄地緊貼於你 2524 | 2525 | 614 2526 | 00:22:16,130 --> 00:22:23,000 2527 | あなたをずっと忘れない 2528 | 2529 | 615 2530 | 00:22:16,130 --> 00:22:23,000 2531 | 難以將你忘卻 2532 | 2533 | 616 2534 | 00:22:21,770 --> 00:22:26,180 2535 | 在此為你而高歌 2536 | 2537 | 617 2538 | 00:22:21,770 --> 00:22:26,180 2539 | 声の限り詠おう 2540 | 2541 | 618 2542 | 00:22:26,370 --> 00:22:28,340 2543 | 星導~ホシシルベ~ 2544 | 2545 | 619 2546 | 00:22:26,370 --> 00:22:28,340 2547 | 閃耀於星空中的路標 2548 | 2549 | 620 2550 | 00:22:28,340 --> 00:22:36,290 2551 | ただ 幾千の光芒が 灯るように 2552 | 2553 | 621 2554 | 00:22:28,340 --> 00:22:36,290 2555 | 如同無數的光芒點亮了夜空 2556 | 2557 | 622 2558 | 00:22:35,230 --> 00:22:38,420 2559 | 無限へ 2560 | 2561 | 623 2562 | 00:22:35,230 --> 00:22:38,420 2563 | 直至宇宙盡頭 2564 | 2565 | 624 2566 | 00:22:36,550 --> 00:22:39,420 2567 | 尊き人を 2568 | 2569 | 625 2570 | 00:22:36,550 --> 00:22:39,420 2571 | 引領最可愛的人們 2572 | 2573 | 626 2574 | 00:22:39,420 --> 00:22:46,850 2575 | 前往那沒有痛苦的彼方 2576 | 2577 | 627 2578 | 00:22:39,420 --> 00:22:46,850 2579 | 慈しみ彼方へ導くまで 2580 | 2581 | 628 2582 | 00:22:47,250 --> 00:22:49,650 2583 | 將這一切的回憶 2584 | 2585 | 629 2586 | 00:22:47,250 --> 00:22:49,650 2587 | 憶いよ安らかに 2588 | 2589 | 630 2590 | 00:22:49,650 --> 00:22:52,070 2591 | 惜しみなく捧げよう 2592 | 2593 | 631 2594 | 00:22:49,650 --> 00:22:52,070 2595 | 毫無保留地獻出 2596 | 2597 | 632 2598 | 00:22:52,070 --> 00:23:00,240 2599 | 這永遠的歌曲 響徹星空吧 2600 | 2601 | 633 2602 | 00:22:52,070 --> 00:23:00,240 2603 | 響け、永遠の歌 2604 | 2605 | 634 2606 | 00:22:55,460 --> 00:23:00,240 2607 | そっと包みましょう 2608 | 2609 | 635 2610 | 00:22:55,460 --> 00:23:00,240 2611 | 悄悄藏於心底 2612 | 2613 | 636 2614 | 00:23:00,240 --> 00:23:04,700 2615 | そして祈りましょう 2616 | 2617 | 637 2618 | 00:23:00,240 --> 00:23:04,700 2619 | 然後獻上祈禱 2620 | 2621 | 638 2622 | 00:23:04,700 --> 00:23:07,010 2623 | 在那無悔的世界中 2624 | 2625 | 639 2626 | 00:23:04,700 --> 00:23:07,010 2627 | 悔いなき世に 2628 | 2629 | 640 2630 | 00:23:07,010 --> 00:23:11,460 2631 | 咲かせたかった微笑みよ 2632 | 2633 | 641 2634 | 00:23:07,010 --> 00:23:11,460 2635 | 所露出的微笑 2636 | 2637 | 642 2638 | 00:23:11,460 --> 00:23:19,690 2639 | どうか あの日のままに 2640 | 2641 | 643 2642 | 00:23:11,460 --> 00:23:19,690 2643 | 還請如同那一天一樣純真無邪 2644 | 2645 | -------------------------------------------------------------------------------- /tests/sub_standard.srt: -------------------------------------------------------------------------------- 1 | 1 2 | 00:00:10,580 --> 00:00:13,040 3 | It's time for the main event! 4 | 5 | 2 6 | 00:00:13,040 --> 00:00:18,250 7 | Animal Mask vs. Macadamian Ogre, AKA, MAO! 8 | 9 | 3 10 | 00:00:18,250 --> 00:00:20,120 11 | The masked wrestler, Animal Mask, 12 | 13 | 4 14 | 00:00:20,120 --> 00:00:24,000 15 | will face off against former Judo fighter MAO! 16 | 17 | 5 18 | 00:00:24,000 --> 00:00:26,950 19 | Will this bring an end to their long rivalry? 20 | 21 | 6 22 | 00:00:26,950 --> 00:00:30,040 23 | What kind of match do they 24 | have in store for us tonight? 25 | 26 | 7 27 | 00:00:33,080 --> 00:00:35,580 28 | It's finally time... 29 | 30 | 8 31 | 00:00:36,830 --> 00:00:40,500 32 | Being a pro wrestler was 33 | the first chapter in my life. 34 | 35 | 9 36 | 00:00:40,500 --> 00:00:44,580 37 | And if I can win tonight's 38 | world championship title match, 39 | 40 | 10 41 | 00:00:44,580 --> 00:00:47,290 42 | the second chapter in my life will begin... 43 | 44 | 11 45 | 00:00:49,040 --> 00:00:51,250 46 | It's almost time for the fight! 47 | 48 | 12 49 | 00:00:51,250 --> 00:00:53,370 50 | The world championship title bout! 51 | 52 | 13 53 | 00:00:53,370 --> 00:00:56,700 54 | Big Saigo, I'm monologuing. 55 | Don't interrupt me. 56 | 57 | 14 58 | 00:00:56,700 --> 00:00:58,500 59 | Oh, I see! 60 | 61 | 15 62 | 00:00:58,500 --> 00:01:00,450 63 | So, what will you do if you win tonight? 64 | 65 | 16 66 | 00:01:00,450 --> 00:01:02,620 67 | There's mountains left for you to climb! 68 | 69 | 17 70 | 00:01:02,620 --> 00:01:04,910 71 | Yes, that's exactly right. 72 | 73 | 18 74 | 00:01:04,910 --> 00:01:09,290 75 | When I win tonight's match, 76 | the second chapter in my life will begin. 77 | 78 | 19 79 | 00:01:09,290 --> 00:01:11,080 80 | Oh, what is it? 81 | 82 | 20 83 | 00:01:11,080 --> 00:01:12,790 84 | You're quitting pro wrestling to do MMA? 85 | 86 | 21 87 | 00:01:12,790 --> 00:01:15,410 88 | No, maybe Muay Thai or Capoeira? 89 | 90 | 22 91 | 00:01:15,410 --> 00:01:18,330 92 | Very well. I'll tell you... I'm going to... 93 | 94 | 23 95 | 00:01:18,330 --> 00:01:20,200 96 | Whoops, looks like we're out of time. 97 | 98 | 24 99 | 00:01:20,200 --> 00:01:22,000 100 | Break a leg and all that. 101 | 102 | 25 103 | 00:01:22,000 --> 00:01:26,450 104 | Go out there and smash up 105 | that Macadamian Ogre guy. 106 | 107 | 26 108 | 00:01:26,450 --> 00:01:27,870 109 | Big Saigo. 110 | 111 | 27 112 | 00:01:27,870 --> 00:01:30,040 113 | He's always in a hurry. 114 | 115 | 28 116 | 00:01:30,540 --> 00:01:36,540 117 | "No Pets!!" 118 | The second chapter in my life that will begin 119 | when I win tonight's title match... 120 | 121 | 29 122 | 00:01:36,540 --> 00:01:40,290 123 | Is when I will live my life 124 | surrounded by the animals I love, 125 | 126 | 30 127 | 00:01:40,290 --> 00:01:43,200 128 | and share the joy of living with animals 129 | with people everywhere! 130 | 131 | 31 132 | 00:01:45,660 --> 00:01:48,660 133 | "Interdimensional Title Match 134 | Animal Mask vs MAO" 135 | Let's go, Hiroyuki. 136 | 137 | 32 138 | 00:01:51,290 --> 00:01:56,200 139 | The Macadamian Ogre! 140 | 141 | 33 142 | 00:01:56,200 --> 00:01:59,330 143 | And now, entering the ring... 144 | 145 | 34 146 | 00:01:59,330 --> 00:02:01,580 147 | The man who loves animals a little too much! 148 | 149 | 35 150 | 00:02:01,580 --> 00:02:09,120 151 | Weighing in at 198 pounds, it's Animal Mask! 152 | 153 | 36 154 | 00:02:12,290 --> 00:02:13,950 155 | It's finally time... 156 | 157 | 37 158 | 00:02:13,950 --> 00:02:18,620 159 | My rival, MAO. 160 | A worthy opponent for my last match! 161 | 162 | 38 163 | 00:02:18,620 --> 00:02:23,870 164 | The second chapter of my life will begin 165 | after I slam you into the mat... 166 | 167 | 39 168 | 00:02:25,160 --> 00:02:26,540 169 | ...and that is! 170 | 171 | 40 172 | 00:02:27,950 --> 00:02:30,910 173 | Opening a pet shop! 174 | 175 | 41 176 | 00:02:46,410 --> 00:02:49,540 177 | Strongest warrior from another world... 178 | 179 | 42 180 | 00:02:49,540 --> 00:02:52,330 181 | You're as strong as ever, Mao! 182 | 183 | 43 184 | 00:02:52,330 --> 00:02:53,540 185 | Impressive! 186 | 187 | 44 188 | 00:02:53,540 --> 00:02:54,660 189 | However! 190 | 191 | 45 192 | 00:02:55,370 --> 00:02:58,830 193 | I pray you answer my call! 194 | 195 | 46 196 | 00:02:58,830 --> 00:03:03,370 197 | Animal Mask has climbed up onto the ropes! 198 | 199 | 47 200 | 00:03:03,370 --> 00:03:05,830 201 | And now he's jumped! 202 | 203 | 48 204 | 00:03:05,830 --> 00:03:07,580 205 | So has Hiroyuki! 206 | 207 | 49 208 | 00:03:07,580 --> 00:03:10,250 209 | Wait! They've started to glow! 210 | 211 | 50 212 | 00:03:10,250 --> 00:03:12,410 213 | What is this? 214 | 215 | 51 216 | 00:03:12,410 --> 00:03:14,290 217 | They disappeared! 218 | 219 | 52 220 | 00:03:14,290 --> 00:03:16,290 221 | What is this? 222 | 223 | 53 224 | 00:03:16,290 --> 00:03:20,750 225 | Animal Mask has disappeared! 226 | 227 | 54 228 | 00:03:20,750 --> 00:03:23,200 229 | Huh? What? 230 | 231 | 55 232 | 00:03:38,870 --> 00:03:40,870 233 | Are you the hero? 234 | 235 | 56 236 | 00:03:42,080 --> 00:03:43,580 237 | I am Animal Mask! 238 | 239 | 57 240 | 00:03:43,580 --> 00:03:45,540 241 | Did the hero-summoning ritual fail? 242 | 243 | 58 244 | 00:03:45,540 --> 00:03:46,750 245 | Why is he in his underwear? 246 | 247 | 59 248 | 00:03:46,750 --> 00:03:49,040 249 | Is he a pervert? 250 | 251 | 60 252 | 00:03:49,040 --> 00:03:52,410 253 | I don't care who you are! 254 | 255 | 61 256 | 00:03:52,410 --> 00:03:57,870 257 | If you've answered our call, 258 | then you are our hero! 259 | 260 | 62 261 | 00:03:57,870 --> 00:03:59,580 262 | What's going on? 263 | 264 | 63 265 | 00:03:59,580 --> 00:04:02,040 266 | Another trick of Big Saigo's? 267 | 268 | 64 269 | 00:04:02,040 --> 00:04:05,950 270 | No... this isn't the arena. 271 | 272 | 65 273 | 00:04:05,950 --> 00:04:08,540 274 | So where am I? 275 | 276 | 66 277 | 00:04:08,540 --> 00:04:14,250 278 | Please, Hero, will you defeat 279 | the evil demon beasts that stalk this land 280 | 281 | 67 282 | 00:04:14,250 --> 00:04:17,830 283 | as well as the Demon King? 284 | 285 | 68 286 | 00:04:17,830 --> 00:04:19,700 287 | Evil demon beasts? 288 | 289 | 69 290 | 00:04:19,700 --> 00:04:23,450 291 | Yes, terrifying animals called monsters... 292 | 293 | 70 294 | 00:04:23,450 --> 00:04:26,000 295 | Exterminate every one of them 296 | from this land... 297 | 298 | 71 299 | 00:04:26,950 --> 00:04:28,450 300 | Hero? 301 | 302 | 72 303 | 00:04:28,450 --> 00:04:32,120 304 | It appears I heard you right after all. 305 | 306 | 73 307 | 00:04:33,620 --> 00:04:37,580 308 | You're telling me to defeat animals for you? 309 | 310 | 74 311 | 00:04:37,580 --> 00:04:41,660 312 | Yes. They're terrifying and disgusting beasts... 313 | 314 | 75 315 | 00:04:42,580 --> 00:04:44,540 316 | Um, Hero? 317 | 318 | 76 319 | 00:04:44,540 --> 00:04:47,700 320 | We can do that after you 321 | defeat the Demon King... 322 | 323 | 77 324 | 00:04:47,700 --> 00:04:51,580 325 | Or at least when nobody's watching... 326 | 327 | 78 328 | 00:04:51,580 --> 00:04:55,910 329 | Hero... Um, Hero? 330 | 331 | 79 332 | 00:04:59,540 --> 00:05:01,870 333 | Hero?! 334 | 335 | 80 336 | 00:05:12,450 --> 00:05:15,500 337 | Winner! 338 | 339 | 81 340 | 00:06:46,750 --> 00:06:49,910 341 | "Wrestler x Summoning" 342 | 343 | 82 344 | 00:06:50,910 --> 00:06:53,370 345 | The princess's noble butt 346 | is being shown to the world! 347 | 348 | 83 349 | 00:06:53,370 --> 00:06:55,910 350 | Somebody, hide her butt! 351 | 352 | 84 353 | 00:06:55,910 --> 00:06:57,950 354 | Defeat animals? 355 | 356 | 85 357 | 00:06:57,950 --> 00:07:00,000 358 | So the blood of an animal lover 359 | that flows through my veins 360 | 361 | 86 362 | 00:07:00,000 --> 00:07:03,750 363 | forced me to give that impudent 364 | girl a German suplex? 365 | 366 | 87 367 | 00:07:03,750 --> 00:07:05,250 368 | You bastard... 369 | 370 | 88 371 | 00:07:05,250 --> 00:07:09,830 372 | Hero, I understand that you're angry 373 | about being summoned like this, 374 | 375 | 89 376 | 00:07:09,830 --> 00:07:12,830 377 | but you can't do that to the princess. 378 | 379 | 90 380 | 00:07:12,830 --> 00:07:17,160 381 | I don't know what you're talking about 382 | with this summoning and hero nonsense! 383 | 384 | 91 385 | 00:07:17,790 --> 00:07:21,330 386 | But... perhaps I went too far. 387 | 388 | 92 389 | 00:07:21,330 --> 00:07:22,830 390 | I know! 391 | 392 | 93 393 | 00:07:26,330 --> 00:07:27,750 394 | Drape. 395 | 396 | 94 397 | 00:07:34,500 --> 00:07:36,790 398 | Stop messing around! 399 | 400 | 95 401 | 00:07:36,790 --> 00:07:39,410 402 | Capture him! 403 | 404 | 96 405 | 00:07:39,410 --> 00:07:40,250 406 | Damn! 407 | 408 | 97 409 | 00:07:40,250 --> 00:07:42,120 410 | I was trying to be a gentleman 411 | and help the lady out, 412 | 413 | 98 414 | 00:07:42,120 --> 00:07:43,200 415 | why are they mad? 416 | 417 | 99 418 | 00:07:43,200 --> 00:07:46,700 419 | What kind of lunatic waves 420 | a sword at someone like that? 421 | 422 | 100 423 | 00:07:55,250 --> 00:07:57,120 424 | This definitely isn't the arena. 425 | 426 | 101 427 | 00:07:57,120 --> 00:07:59,290 428 | It's not even night anymore. 429 | 430 | 102 431 | 00:07:59,290 --> 00:08:02,080 432 | Where am I? 433 | 434 | 103 435 | 00:08:02,080 --> 00:08:03,080 436 | Who is that? 437 | 438 | 104 439 | 00:08:03,080 --> 00:08:04,160 440 | Where are his pants? 441 | 442 | 105 443 | 00:08:04,160 --> 00:08:05,660 444 | Is he a pervert? 445 | 446 | 106 447 | 00:08:05,660 --> 00:08:07,910 448 | We should stay away... 449 | 450 | 107 451 | 00:08:07,910 --> 00:08:08,790 452 | He looked over here. 453 | 454 | 108 455 | 00:08:08,790 --> 00:08:10,200 456 | Don't meet his gaze. 457 | 458 | 109 459 | 00:08:10,200 --> 00:08:13,330 460 | Somebody go call a hunter! 461 | 462 | 110 463 | 00:08:13,330 --> 00:08:16,750 464 | I guess I'll just find someone 465 | kind-looking to ask. 466 | 467 | 111 468 | 00:08:16,750 --> 00:08:19,790 469 | Um, excuse me... Can you tell me where I am? 470 | 471 | 112 472 | 00:08:22,750 --> 00:08:24,120 473 | I get it! 474 | 475 | 113 476 | 00:08:24,120 --> 00:08:28,660 477 | It's rude to ask people questions 478 | while wearing a mask! 479 | 480 | 114 481 | 00:08:34,910 --> 00:08:38,620 482 | The moment I take off my mask, 483 | I'm no longer Animal Mask-- 484 | 485 | 115 486 | 00:08:38,620 --> 00:08:41,370 487 | I'm an ordinary man named Genzo Shibata. 488 | 489 | 116 490 | 00:08:41,370 --> 00:08:42,250 491 | Now no one will know... 492 | 493 | 117 494 | 00:08:42,250 --> 00:08:44,200 495 | Over there! That's him! 496 | 497 | 118 498 | 00:08:44,200 --> 00:08:44,580 499 | --Watch out! It's a pervert! 500 | 501 | 119 502 | 00:08:44,580 --> 00:08:47,080 503 | --What? 504 | --Watch out! It's a pervert! 505 | 506 | 120 507 | 00:08:47,080 --> 00:08:48,500 508 | Impossible! 509 | 510 | 121 511 | 00:08:49,160 --> 00:08:50,500 512 | The pervert ran away! 513 | 514 | 122 515 | 00:08:50,500 --> 00:08:51,750 516 | After the pervert! 517 | 518 | 123 519 | 00:08:51,750 --> 00:08:54,450 520 | I'm not a pervert! I'm a pro wrestler! 521 | 522 | 124 523 | 00:08:58,620 --> 00:09:02,040 524 | I have no idea how they figured me out. 525 | 526 | 125 527 | 00:09:02,040 --> 00:09:04,580 528 | But don't worry, Hiroyuki. 529 | 530 | 126 531 | 00:09:04,580 --> 00:09:07,750 532 | I'll figure out a way out of this. 533 | 534 | 127 535 | 00:09:10,410 --> 00:09:12,120 536 | Sorry, Hiroyuki. 537 | 538 | 128 539 | 00:09:12,120 --> 00:09:14,700 540 | Forgive me for being useless... 541 | 542 | 129 543 | 00:09:16,660 --> 00:09:20,450 544 | Hiroyuki! I'm so glad you're here with me! 545 | 546 | 130 547 | 00:09:20,450 --> 00:09:23,290 548 | I don't know what I would've done 549 | if I were here by myself. 550 | 551 | 131 552 | 00:09:23,290 --> 00:09:25,080 553 | I don't care about clothes! Not at all! 554 | 555 | 132 556 | 00:09:25,080 --> 00:09:28,000 557 | My goal is to find food for you tonight! 558 | 559 | 133 560 | 00:09:29,080 --> 00:09:32,500 561 | Bro, that pervert looks pretty buff. 562 | 563 | 134 564 | 00:09:32,500 --> 00:09:34,660 565 | We could sell him for a lot. 566 | 567 | 135 568 | 00:09:34,660 --> 00:09:41,540 569 | Yes. And that strange creature 570 | would probably be worth a lot of cash. 571 | 572 | 136 573 | 00:09:49,950 --> 00:09:52,000 574 | You're so cute... 575 | 576 | 137 577 | 00:09:52,000 --> 00:09:55,040 578 | You there, in your underwear. 579 | 580 | 138 581 | 00:09:55,040 --> 00:09:56,950 582 | Wh-What? 583 | 584 | 139 585 | 00:09:56,950 --> 00:10:00,000 586 | Animal ears?! 587 | 588 | 140 589 | 00:10:05,950 --> 00:10:07,330 590 | A-And... 591 | 592 | 141 593 | 00:10:07,330 --> 00:10:09,370 594 | You're hungry, right? 595 | 596 | 142 597 | 00:10:09,370 --> 00:10:11,450 598 | Come with us and we'll give you some food. 599 | 600 | 143 601 | 00:10:11,450 --> 00:10:13,450 602 | An animal! 603 | 604 | 144 605 | 00:10:13,450 --> 00:10:17,580 606 | Do you like my hairy chest and tail? 607 | 608 | 145 609 | 00:10:19,910 --> 00:10:21,700 610 | You've got nowhere to go, right? 611 | 612 | 146 613 | 00:10:21,700 --> 00:10:24,410 614 | Do what he says... 615 | 616 | 147 617 | 00:10:30,580 --> 00:10:33,580 618 | Bro, this guy seems like bad news... 619 | 620 | 148 621 | 00:10:33,580 --> 00:10:35,250 622 | Y-Yeah... 623 | 624 | 149 625 | 00:10:35,250 --> 00:10:38,200 626 | So fluffy! 627 | 628 | 150 629 | 00:10:38,200 --> 00:10:41,330 630 | He's staring at you, not me! 631 | 632 | 151 633 | 00:10:43,330 --> 00:10:45,370 634 | W-We'll be on our way... 635 | 636 | 152 637 | 00:10:46,660 --> 00:10:48,450 638 | What the hell? 639 | 640 | 153 641 | 00:10:48,450 --> 00:10:49,620 642 | Do you want to fight? 643 | 644 | 154 645 | 00:10:49,620 --> 00:10:52,580 646 | You think you can beat a beastman 647 | with your bare hands? 648 | 649 | 155 650 | 00:10:52,580 --> 00:10:54,580 651 | Get 'em, bro! 652 | 653 | 156 654 | 00:10:54,580 --> 00:10:58,000 655 | I see... you're a beastman, huh? 656 | 657 | 157 658 | 00:10:59,700 --> 00:11:01,290 659 | Bro! 660 | 661 | 158 662 | 00:11:08,450 --> 00:11:12,120 663 | Hey, you jerk! Get off my brother! 664 | 665 | 159 666 | 00:11:12,120 --> 00:11:14,410 667 | Stop sniffing him! 668 | 669 | 160 670 | 00:11:15,450 --> 00:11:17,370 671 | Misha, this guy is crazy! 672 | 673 | 161 674 | 00:11:17,370 --> 00:11:18,790 675 | He's crazy! 676 | 677 | 162 678 | 00:11:18,790 --> 00:11:23,370 679 | We're sorry, so stop! Let him go! 680 | 681 | 163 682 | 00:11:23,370 --> 00:11:26,500 683 | If you don't, my bro will... my bro will... 684 | 685 | 164 686 | 00:11:26,500 --> 00:11:28,120 687 | What's this guy's deal? 688 | 689 | 165 690 | 00:11:28,120 --> 00:11:30,540 691 | He's incredibly strong! 692 | 693 | 166 694 | 00:11:30,540 --> 00:11:34,540 695 | Don't worry! 696 | You'll start to like it any second! 697 | 698 | 167 699 | 00:11:34,540 --> 00:11:37,160 700 | Oh, you like it when I rub you here, huh? 701 | 702 | 168 703 | 00:11:37,160 --> 00:11:39,660 704 | Stop it! 705 | 706 | 169 707 | 00:11:39,660 --> 00:11:43,410 708 | We'll pay you! Stop it! Please! 709 | 710 | 170 711 | 00:11:43,410 --> 00:11:47,120 712 | See? Feels good, right? Good boy... 713 | 714 | 171 715 | 00:11:50,160 --> 00:11:52,370 716 | Now, you're next... 717 | 718 | 172 719 | 00:11:54,080 --> 00:11:56,790 720 | Cat ears! 721 | 722 | 173 723 | 00:11:59,620 --> 00:12:02,790 724 | Shigure, give up already! 725 | 726 | 174 727 | 00:12:04,700 --> 00:12:07,410 728 | You're about to be sold! 729 | 730 | 175 731 | 00:12:07,410 --> 00:12:10,290 732 | No! 733 | 734 | 176 735 | 00:12:10,290 --> 00:12:14,790 736 | I don't want to live at some noble's house 737 | and get walks and naps and free snacks! 738 | 739 | 177 740 | 00:12:14,790 --> 00:12:17,120 741 | Who said you were being sold to a noble? 742 | 743 | 178 744 | 00:12:17,120 --> 00:12:20,120 745 | If that was the deal I'd go myself. 746 | 747 | 179 748 | 00:12:20,120 --> 00:12:23,700 749 | But if they're willing to feed me 750 | filet mignon every day, 751 | 752 | 180 753 | 00:12:23,700 --> 00:12:25,290 754 | I may be willing to let them sell me. 755 | 756 | 181 757 | 00:12:25,290 --> 00:12:29,250 758 | Nobody will buy a beast girl like that! 759 | 760 | 182 761 | 00:12:29,250 --> 00:12:30,540 762 | Let's go! 763 | 764 | 183 765 | 00:12:30,540 --> 00:12:30,910 766 | --No! 767 | 768 | 184 769 | 00:12:30,910 --> 00:12:32,750 770 | --A poor girl in unfortunate circumstances... 771 | --No! 772 | 773 | 185 774 | 00:12:32,750 --> 00:12:34,160 775 | Stop whining and let's go! 776 | 777 | 186 778 | 00:12:34,160 --> 00:12:37,750 779 | It's not right for an outsider 780 | like me to get involved. 781 | 782 | 187 783 | 00:12:37,750 --> 00:12:42,370 784 | And not because I'd rather pet the cat ears... 785 | 786 | 188 787 | 00:12:42,370 --> 00:12:44,790 788 | That tail! Those ears! Is that a wolf? 789 | 790 | 189 791 | 00:12:44,790 --> 00:12:48,450 792 | I've had plenty of experience touching 793 | cats and dogs, but never a wolf! 794 | 795 | 190 796 | 00:12:48,450 --> 00:12:50,950 797 | A girl with cat ears is a hard thing to pass up, 798 | 799 | 191 800 | 00:12:50,950 --> 00:12:54,290 801 | but my priority now is the wolf ears girl! 802 | 803 | 192 804 | 00:12:54,290 --> 00:12:57,000 805 | Please... 806 | 807 | 193 808 | 00:12:57,000 --> 00:12:59,950 809 | All praise animal ears and animal tails! 810 | 811 | 194 812 | 00:12:59,950 --> 00:13:01,290 813 | That's far enough! 814 | 815 | 195 816 | 00:13:01,290 --> 00:13:04,200 817 | Mind your own business. 818 | 819 | 196 820 | 00:13:04,200 --> 00:13:05,700 821 | I don't know who you think you are, 822 | 823 | 197 824 | 00:13:05,700 --> 00:13:07,700 825 | but try anything and you'll regret it. 826 | 827 | 198 828 | 00:13:07,700 --> 00:13:09,040 829 | Really, who are you? 830 | 831 | 199 832 | 00:13:09,040 --> 00:13:11,000 833 | Edgar, he's dangerous! 834 | 835 | 200 836 | 00:13:11,000 --> 00:13:13,540 837 | He's a super-high-level pervert! 838 | 839 | 201 840 | 00:13:13,540 --> 00:13:15,950 841 | He just had his way with my bro... 842 | 843 | 202 844 | 00:13:15,950 --> 00:13:17,200 845 | What? 846 | 847 | 203 848 | 00:13:17,200 --> 00:13:19,950 849 | What are you doing? 850 | 851 | 204 852 | 00:13:19,950 --> 00:13:22,200 853 | Allow me to first correct 854 | your misunderstanding. 855 | 856 | 205 857 | 00:13:22,200 --> 00:13:23,950 858 | I am not a pervert. 859 | 860 | 206 861 | 00:13:23,950 --> 00:13:27,160 862 | I simply love all animals 863 | regardless of gender! 864 | 865 | 207 866 | 00:13:27,160 --> 00:13:30,250 867 | See? He's more dangerous than he looks! 868 | 869 | 208 870 | 00:13:30,250 --> 00:13:33,120 871 | Yeah. The way he dresses, 872 | the things he says... 873 | 874 | 209 875 | 00:13:33,120 --> 00:13:35,910 876 | He's a pervert like none 877 | the world has ever seen! 878 | 879 | 210 880 | 00:13:35,910 --> 00:13:37,790 881 | Why do you fear? 882 | 883 | 211 884 | 00:13:37,790 --> 00:13:43,000 885 | I don't know who you are, 886 | or what reasons you may have... 887 | 888 | 212 889 | 00:13:43,000 --> 00:13:44,700 890 | No! Stop it! 891 | 892 | 213 893 | 00:13:44,700 --> 00:13:49,000 894 | If the wolf girl is upset, you are evil! 895 | 896 | 214 897 | 00:13:53,790 --> 00:13:56,790 898 | Damn it! 899 | 900 | 215 901 | 00:13:56,790 --> 00:13:59,750 902 | You pervert! We'll get you yet! 903 | 904 | 216 905 | 00:14:00,950 --> 00:14:04,910 906 | Come to think of it, I hadn't gotten 907 | to pet the cat ears yet, had I? 908 | 909 | 217 910 | 00:14:04,910 --> 00:14:07,450 911 | Why did you have to open your mouth?! 912 | 913 | 218 914 | 00:14:07,450 --> 00:14:10,000 915 | You're right! I'm sorry! 916 | 917 | 219 918 | 00:14:10,000 --> 00:14:11,330 919 | Um... 920 | 921 | 220 922 | 00:14:14,540 --> 00:14:17,580 923 | Thank you for saving me! 924 | 925 | 221 926 | 00:14:17,580 --> 00:14:20,080 927 | Now I won't be sold. 928 | 929 | 222 930 | 00:14:20,080 --> 00:14:22,540 931 | Don't worry. I did it because I wanted to. 932 | 933 | 223 934 | 00:14:22,540 --> 00:14:25,250 935 | You were about to be kidnapped 936 | by a slaver, right? 937 | 938 | 224 939 | 00:14:25,250 --> 00:14:30,160 940 | No, I'd borrowed money from him, so... 941 | 942 | 225 943 | 00:14:31,700 --> 00:14:32,660 944 | I see. 945 | 946 | 226 947 | 00:14:32,660 --> 00:14:36,040 948 | You were charged absurd amounts of interest 949 | and then sold to pay your debts. 950 | 951 | 227 952 | 00:14:36,040 --> 00:14:39,370 953 | No, I'm the one who said 954 | that if I couldn't pay by the deadline 955 | 956 | 228 957 | 00:14:39,370 --> 00:14:41,330 958 | he could sell me instead. 959 | 960 | 229 961 | 00:14:43,080 --> 00:14:46,330 962 | In exchange, I told him to give me a loan 963 | with no interest and no collateral, 964 | 965 | 230 966 | 00:14:46,330 --> 00:14:51,000 967 | and then cried and sobbed 968 | in front of his shop until he gave in. 969 | 970 | 231 971 | 00:14:51,000 --> 00:14:53,830 972 | I intended to use that money 973 | to start a business and get rich, 974 | 975 | 232 976 | 00:14:53,830 --> 00:14:56,450 977 | but it didn't work out. 978 | 979 | 233 980 | 00:14:56,450 --> 00:14:59,120 981 | She's a loser. 982 | 983 | 234 984 | 00:15:00,000 --> 00:15:01,580 985 | What's that look? 986 | 987 | 235 988 | 00:15:01,580 --> 00:15:03,700 989 | I was making money for a while! 990 | 991 | 236 992 | 00:15:03,700 --> 00:15:08,200 993 | But then humans started copying me. 994 | 995 | 237 996 | 00:15:10,410 --> 00:15:12,250 997 | I am Genzo Shibata. 998 | 999 | 238 1000 | 00:15:12,250 --> 00:15:13,700 1001 | A pro wrestler. 1002 | 1003 | 239 1004 | 00:15:13,700 --> 00:15:16,080 1005 | My name is Shigure. 1006 | 1007 | 240 1008 | 00:15:16,080 --> 00:15:21,450 1009 | And this is Hiroyuki. My partner 1010 | and a mongrel of pure breeding. 1011 | 1012 | 241 1013 | 00:15:22,750 --> 00:15:25,790 1014 | Nice to meet you, too! 1015 | 1016 | 242 1017 | 00:15:25,790 --> 00:15:30,290 1018 | Um, I'd love to thank you 1019 | for saving me, but... 1020 | 1021 | 243 1022 | 00:15:30,290 --> 00:15:32,290 1023 | I'm broke. 1024 | 1025 | 244 1026 | 00:15:32,290 --> 00:15:36,160 1027 | But from what you said, it sounds 1028 | less like I've done a good deed 1029 | 1030 | 245 1031 | 00:15:36,160 --> 00:15:38,750 1032 | and more like I've committed a felony... 1033 | 1034 | 246 1035 | 00:15:38,750 --> 00:15:40,160 1036 | Don't worry! 1037 | 1038 | 247 1039 | 00:15:40,160 --> 00:15:43,580 1040 | Remember what I said about 1041 | people stealing my business model? 1042 | 1043 | 248 1044 | 00:15:43,580 --> 00:15:47,000 1045 | The guy who stole it was Edgar, 1046 | the guy you just saw! 1047 | 1048 | 249 1049 | 00:15:47,000 --> 00:15:50,700 1050 | See? That makes him evil, right? Right? Right? 1051 | 1052 | 250 1053 | 00:15:50,700 --> 00:15:56,750 1054 | Well, I guess I could count that 1055 | as a good deed, just barely. 1056 | 1057 | 251 1058 | 00:15:56,750 --> 00:15:58,500 1059 | So... 1060 | 1061 | 252 1062 | 00:15:58,500 --> 00:16:00,910 1063 | You said you were broke, right? 1064 | 1065 | 253 1066 | 00:16:04,040 --> 00:16:06,290 1067 | You can pay with your body instead. 1068 | 1069 | 254 1070 | 00:16:06,290 --> 00:16:08,450 1071 | He's a loser. 1072 | 1073 | 255 1074 | 00:16:19,040 --> 00:16:20,910 1075 | I'll get him... 1076 | 1077 | 256 1078 | 00:16:22,330 --> 00:16:24,450 1079 | It's a shame, huh? 1080 | 1081 | 257 1082 | 00:16:25,580 --> 00:16:26,790 1083 | You okay? 1084 | 1085 | 258 1086 | 00:16:26,790 --> 00:16:29,250 1087 | Damn that bastard. 1088 | 1089 | 259 1090 | 00:16:29,250 --> 00:16:31,410 1091 | I won't just give up... 1092 | 1093 | 260 1094 | 00:16:31,410 --> 00:16:33,870 1095 | I don't think there's anything you can do. 1096 | 1097 | 261 1098 | 00:16:33,870 --> 00:16:36,040 1099 | Got a plan? 1100 | 1101 | 262 1102 | 00:16:36,040 --> 00:16:40,330 1103 | Yeah. That strange creature he had. 1104 | 1105 | 263 1106 | 00:16:40,330 --> 00:16:42,080 1107 | Oh, that? 1108 | 1109 | 264 1110 | 00:16:42,080 --> 00:16:43,040 1111 | What will you do with it? 1112 | 1113 | 265 1114 | 00:16:43,040 --> 00:16:45,660 1115 | What else? I'll steal it! 1116 | 1117 | 266 1118 | 00:16:45,660 --> 00:16:48,080 1119 | Great idea! Let's do it! 1120 | 1121 | 267 1122 | 00:16:48,080 --> 00:16:50,120 1123 | We're gonna do it! 1124 | 1125 | 268 1126 | 00:16:50,120 --> 00:16:50,950 1127 | Yeah! 1128 | 1129 | 269 1130 | 00:16:50,950 --> 00:16:52,830 1131 | --We'll show that pervert who's boss! 1132 | 1133 | 270 1134 | 00:16:52,830 --> 00:16:55,290 1135 | --I have nothing but a bad feeling... 1136 | --We'll show that pervert who's boss! 1137 | 1138 | 271 1139 | 00:16:57,500 --> 00:16:58,540 1140 | So this is it? 1141 | 1142 | 272 1143 | 00:16:58,540 --> 00:17:00,500 1144 | Yes. The Hunter Guild. 1145 | 1146 | 273 1147 | 00:17:00,500 --> 00:17:03,950 1148 | Let's work here for a while 1149 | to make some money. 1150 | 1151 | 274 1152 | 00:17:03,950 --> 00:17:06,290 1153 | You seem to be really strong, 1154 | 1155 | 275 1156 | 00:17:06,290 --> 00:17:11,160 1157 | so there's probably lots of great jobs for you. 1158 | 1159 | 276 1160 | 00:17:11,160 --> 00:17:12,120 1161 | So you see, 1162 | 1163 | 277 1164 | 00:17:12,120 --> 00:17:16,000 1165 | I have complete confidence 1166 | in my ability to love any animal 1167 | 1168 | 278 1169 | 00:17:16,000 --> 00:17:20,160 1170 | regardless of gender, species, 1171 | or even more specifically 1172 | 1173 | 279 1174 | 00:17:20,160 --> 00:17:25,290 1175 | hairiness, long-hair, short-hair, 1176 | eye color, or tail length! 1177 | 1178 | 280 1179 | 00:17:28,120 --> 00:17:31,200 1180 | So I'd like to maintain a relationship of love 1181 | 1182 | 281 1183 | 00:17:31,200 --> 00:17:35,080 1184 | and caring with animals at all times! 1185 | 1186 | 282 1187 | 00:17:37,080 --> 00:17:40,700 1188 | What? What is he talking about? 1189 | 1190 | 283 1191 | 00:17:40,700 --> 00:17:42,250 1192 | And... 1193 | 1194 | 284 1195 | 00:17:42,250 --> 00:17:49,080 1196 | Even the fiercest, most violent animal will 1197 | respond to my overwhelming love for them. 1198 | 1199 | 285 1200 | 00:17:49,080 --> 00:17:50,040 1201 | So... 1202 | 1203 | 286 1204 | 00:17:50,040 --> 00:17:51,120 1205 | What do I? 1206 | 1207 | 287 1208 | 00:17:51,120 --> 00:17:53,870 1209 | What am I supposed to do here? 1210 | 1211 | 288 1212 | 00:17:55,370 --> 00:17:56,910 1213 | Trouble, Guild Master! 1214 | 1215 | 289 1216 | 00:17:56,910 --> 00:17:58,250 1217 | What's going on? 1218 | 1219 | 290 1220 | 00:17:58,250 --> 00:17:59,830 1221 | I'm saved! 1222 | 1223 | 291 1224 | 00:17:59,830 --> 00:18:02,700 1225 | Our party was wiped out by a cerberus pack. 1226 | 1227 | 292 1228 | 00:18:02,700 --> 00:18:04,910 1229 | What? Perfect. 1230 | 1231 | 293 1232 | 00:18:04,910 --> 00:18:06,500 1233 | Will you go too? 1234 | 1235 | 294 1236 | 00:18:06,500 --> 00:18:08,500 1237 | Cerberuses are terrifying monsters... 1238 | 1239 | 295 1240 | 00:18:08,500 --> 00:18:09,330 1241 | What? 1242 | 1243 | 296 1244 | 00:18:09,330 --> 00:18:10,160 1245 | Where are they? 1246 | 1247 | 297 1248 | 00:18:10,160 --> 00:18:13,080 1249 | Genzo! Wait! 1250 | 1251 | 298 1252 | 00:18:13,080 --> 00:18:14,370 1253 | What? 1254 | 1255 | 299 1256 | 00:18:14,370 --> 00:18:19,120 1257 | What sort of man isn't scared of a cerberus 1258 | and instead runs out to meet them? 1259 | 1260 | 300 1261 | 00:18:19,120 --> 00:18:22,000 1262 | What a brave man. 1263 | 1264 | 301 1265 | 00:18:22,000 --> 00:18:26,330 1266 | But... I didn't understand 1267 | a word he was saying. 1268 | 1269 | 302 1270 | 00:18:27,750 --> 00:18:29,080 1271 | It's deep in this forest! 1272 | 1273 | 303 1274 | 00:18:29,080 --> 00:18:30,160 1275 | Okay! 1276 | 1277 | 304 1278 | 00:18:30,160 --> 00:18:31,580 1279 | I don't think I've seen you before. 1280 | 1281 | 305 1282 | 00:18:31,580 --> 00:18:33,000 1283 | Are you going unarmed? 1284 | 1285 | 306 1286 | 00:18:33,000 --> 00:18:34,620 1287 | You can borrow this if you want. 1288 | 1289 | 307 1290 | 00:18:34,620 --> 00:18:36,040 1291 | Fool! 1292 | 1293 | 308 1294 | 00:18:36,040 --> 00:18:39,700 1295 | Do I look like a wrestler 1296 | who uses weapons to you? 1297 | 1298 | 309 1299 | 00:18:40,950 --> 00:18:42,620 1300 | He's going to fight them unarmed? 1301 | 1302 | 310 1303 | 00:18:42,620 --> 00:18:45,160 1304 | How confident is he? 1305 | 1306 | 311 1307 | 00:18:45,160 --> 00:18:48,080 1308 | Um, I'll borrow it... 1309 | 1310 | 312 1311 | 00:18:48,080 --> 00:18:51,870 1312 | Listen, we can't let them get near the town! 1313 | 1314 | 313 1315 | 00:18:51,870 --> 00:18:53,700 1316 | Stop them here! 1317 | 1318 | 314 1319 | 00:18:58,950 --> 00:19:00,580 1320 | This is bad! 1321 | 1322 | 315 1323 | 00:19:00,580 --> 00:19:02,160 1324 | So these are cerberuses? 1325 | 1326 | 316 1327 | 00:19:02,160 --> 00:19:04,790 1328 | They've got three heads! 1329 | 1330 | 317 1331 | 00:19:07,330 --> 00:19:10,370 1332 | That means triple the fun! 1333 | 1334 | 318 1335 | 00:19:10,370 --> 00:19:12,410 1336 | So there are animals like this in this world? 1337 | 1338 | 319 1339 | 00:19:12,410 --> 00:19:14,870 1340 | Okay, maybe they look a little strange, but... 1341 | 1342 | 320 1343 | 00:19:16,160 --> 00:19:17,540 1344 | Are you scared? 1345 | 1346 | 321 1347 | 00:19:17,540 --> 00:19:19,450 1348 | Well, calm down. 1349 | 1350 | 322 1351 | 00:19:19,450 --> 00:19:20,790 1352 | Hey! 1353 | 1354 | 323 1355 | 00:19:20,790 --> 00:19:24,660 1356 | No, let's see how he handles this. 1357 | 1358 | 324 1359 | 00:19:24,660 --> 00:19:26,700 1360 | Yes... 1361 | 1362 | 325 1363 | 00:19:27,370 --> 00:19:30,620 1364 | Cerberus! 1365 | 1366 | 326 1367 | 00:19:32,370 --> 00:19:33,950 1368 | They appear to be a type of dog. 1369 | 1370 | 327 1371 | 00:19:33,950 --> 00:19:36,870 1372 | Which means that if I can become 1373 | friends with the pack leader, 1374 | 1375 | 328 1376 | 00:19:36,870 --> 00:19:39,910 1377 | the others will quickly open up to me as well. 1378 | 1379 | 329 1380 | 00:19:39,910 --> 00:19:44,160 1381 | The leader is probably... 1382 | the one guarding the rear! 1383 | 1384 | 330 1385 | 00:19:44,160 --> 00:19:45,370 1386 | You? 1387 | 1388 | 331 1389 | 00:19:45,370 --> 00:19:47,450 1390 | Hello! 1391 | 1392 | 332 1393 | 00:19:47,450 --> 00:19:48,370 1394 | He ran in! 1395 | 1396 | 333 1397 | 00:19:48,370 --> 00:19:50,870 1398 | Gotcha! 1399 | 1400 | 334 1401 | 00:19:50,870 --> 00:19:52,500 1402 | He dodged them! 1403 | 1404 | 335 1405 | 00:19:54,790 --> 00:19:58,080 1406 | Good boy! Let's play! 1407 | 1408 | 336 1409 | 00:20:01,080 --> 00:20:02,950 1410 | And now for the leader! 1411 | 1412 | 337 1413 | 00:20:05,830 --> 00:20:07,790 1414 | Come here! 1415 | 1416 | 338 1417 | 00:20:14,450 --> 00:20:15,950 1418 | He pinned it! 1419 | 1420 | 339 1421 | 00:20:15,950 --> 00:20:17,410 1422 | What kind of move is that? 1423 | 1424 | 340 1425 | 00:20:19,040 --> 00:20:20,410 1426 | But there are others... 1427 | 1428 | 341 1429 | 00:20:20,410 --> 00:20:21,330 1430 | This is bad! 1431 | 1432 | 342 1433 | 00:20:21,330 --> 00:20:22,580 1434 | Should we help? 1435 | 1436 | 343 1437 | 00:20:22,580 --> 00:20:24,830 1438 | Stay out of this! 1439 | 1440 | 344 1441 | 00:20:25,580 --> 00:20:28,160 1442 | He's keeping us out of danger? 1443 | 1444 | 345 1445 | 00:20:28,160 --> 00:20:30,250 1446 | What a man! 1447 | 1448 | 346 1449 | 00:20:31,120 --> 00:20:34,500 1450 | I think I'm starting to figure him out... 1451 | 1452 | 347 1453 | 00:20:34,500 --> 00:20:37,540 1454 | Good boy! Good boy! 1455 | 1456 | 348 1457 | 00:20:37,540 --> 00:20:40,580 1458 | You like it here, huh? 1459 | 1460 | 349 1461 | 00:20:47,580 --> 00:20:50,660 1462 | Good boy... You're such a good boy... 1463 | 1464 | 350 1465 | 00:20:50,660 --> 00:20:54,160 1466 | He really pinned it with his bare hands... 1467 | 1468 | 351 1469 | 00:20:54,160 --> 00:20:56,160 1470 | Like you'd pin down a lady... 1471 | 1472 | 352 1473 | 00:20:56,160 --> 00:20:57,830 1474 | He's like a lady killer... 1475 | 1476 | 353 1477 | 00:20:57,830 --> 00:21:00,120 1478 | No, he's... 1479 | 1480 | 354 1481 | 00:21:00,120 --> 00:21:02,000 1482 | ...a demon beast killer! 1483 | 1484 | 355 1485 | 00:21:09,580 --> 00:21:11,660 1486 | We got enough money from the job 1487 | to get you some clothes, 1488 | 1489 | 356 1490 | 00:21:11,660 --> 00:21:13,950 1491 | as well as pay for an inn for a while. 1492 | 1493 | 357 1494 | 00:21:13,950 --> 00:21:15,410 1495 | Yeah. 1496 | 1497 | 358 1498 | 00:21:15,410 --> 00:21:18,250 1499 | So, what will you do now? 1500 | 1501 | 359 1502 | 00:21:18,250 --> 00:21:20,750 1503 | I've made my decision. 1504 | 1505 | 360 1506 | 00:21:20,750 --> 00:21:24,040 1507 | I want people to understand 1508 | how wonderful demon beasts are! 1509 | 1510 | 361 1511 | 00:21:24,040 --> 00:21:26,790 1512 | Indeed! I'll bring about a world 1513 | where demon beasts and humans 1514 | 1515 | 362 1516 | 00:21:26,790 --> 00:21:28,250 1517 | can understand each other! 1518 | 1519 | 363 1520 | 00:21:28,250 --> 00:21:30,910 1521 | That's impossible in this country. 1522 | 1523 | 364 1524 | 00:21:30,910 --> 00:21:31,830 1525 | No... 1526 | 1527 | 365 1528 | 00:21:33,450 --> 00:21:35,950 1529 | I believe I can do it. 1530 | 1531 | 366 1532 | 00:21:35,950 --> 00:21:38,120 1533 | So you must believe too. 1534 | 1535 | 367 1536 | 00:21:40,250 --> 00:21:44,870 1537 | Genzo, is the reason 1538 | you refused to be a hero...? 1539 | 1540 | 368 1541 | 00:21:44,870 --> 00:21:49,870 1542 | That princess demanded I defeat animals! 1543 | 1544 | 369 1545 | 00:21:49,870 --> 00:21:53,330 1546 | Animals and human, 1547 | beast people and humans... 1548 | 1549 | 370 1550 | 00:21:53,330 --> 00:21:56,620 1551 | I like it! Let me help, too! 1552 | 1553 | 371 1554 | 00:21:56,620 --> 00:21:59,250 1555 | Really? Then let's do this! 1556 | 1557 | 372 1558 | 00:21:59,250 --> 00:22:05,120 1559 | Let's do the best with the three of us, no, 1560 | the four of us including Hiroyuki! 1561 | 1562 | 373 1563 | 00:22:06,080 --> 00:22:07,750 1564 | Yes! 1565 | 1566 | 374 1567 | 00:22:07,750 --> 00:22:08,910 1568 | Four? 1569 | 1570 | 375 1571 | 00:22:13,160 --> 00:22:14,370 1572 | Who are you? 1573 | 1574 | 376 1575 | 00:23:45,910 --> 00:23:49,910 1576 | Next time: "Quest x Demon Beast Killer." 1577 | 1578 | -------------------------------------------------------------------------------- /tests/test_batch.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import unittest.mock 3 | 4 | from pyasstosrt.batch import app 5 | 6 | 7 | def test_version(cli_runner): 8 | result = cli_runner.invoke(app, ["--version"]) 9 | assert result.exit_code == 0 10 | assert "PyAssToSrt version:" in result.stdout 11 | 12 | 13 | def test_export_help(cli_runner): 14 | result = cli_runner.invoke(app, ["export", "--help"]) 15 | assert result.exit_code == 0 16 | assert "Convert ASS subtitle file(s) to SRT format" in result.stdout 17 | 18 | 19 | def test_export_file_not_exists(cli_runner): 20 | result = cli_runner.invoke(app, ["export", "nonexistent_file.ass"]) 21 | assert result.exit_code != 0 22 | assert "nonexistent_file.ass" in result.stdout 23 | 24 | 25 | def test_export_with_existing_ass_file(cli_runner, test_files, cleanup_srt_files): 26 | test_file = test_files["sub"] 27 | assert test_file.exists(), f"Test file {test_file} not found" 28 | 29 | srt_file = test_file.with_suffix(".srt") 30 | 31 | result = cli_runner.invoke(app, ["export", str(test_file)]) 32 | assert result.exit_code == 0 33 | assert "Success: Converted sub.ass to" in result.stdout 34 | assert srt_file.exists() 35 | 36 | srt_content = srt_file.read_text(encoding="utf-8") 37 | assert "1" in srt_content 38 | assert "It's time for the main event!" in srt_content 39 | 40 | 41 | def test_export_with_output_dir(cli_runner, test_files, output_dir): 42 | test_file = test_files["sub"] 43 | 44 | result = cli_runner.invoke(app, ["export", str(test_file), "--output-dir", str(output_dir)]) 45 | assert result.exit_code == 0 46 | expected_output = output_dir / "sub.srt" 47 | assert expected_output.exists() 48 | 49 | if expected_output.exists(): 50 | expected_output.unlink() 51 | 52 | 53 | def test_export_with_remove_effects(cli_runner, test_files, cleanup_srt_files): 54 | test_file = test_files["sub"] 55 | srt_file = test_file.with_suffix(".srt") 56 | 57 | result = cli_runner.invoke(app, ["export", str(test_file), "--remove-effects"]) 58 | assert result.exit_code == 0 59 | assert srt_file.exists() 60 | 61 | srt_content = srt_file.read_text(encoding="utf-8") 62 | assert "It's time for the main event!" in srt_content 63 | 64 | 65 | def test_export_with_specialized_effects_removal(cli_runner, test_files, cleanup_srt_files): 66 | test_file = test_files["sub_removing_effects"] 67 | standard_srt = test_files["sub_standard_removing_effects"] 68 | 69 | assert test_file.exists(), f"Test file {test_file} not found" 70 | assert standard_srt.exists(), f"Standard SRT file {standard_srt} not found" 71 | 72 | srt_file = test_file.with_suffix(".srt") 73 | 74 | result = cli_runner.invoke(app, ["export", str(test_file), "--remove-effects"]) 75 | assert result.exit_code == 0 76 | assert srt_file.exists() 77 | 78 | generated_content = srt_file.read_text(encoding="utf-8") 79 | 80 | assert len(generated_content) > 0 81 | 82 | 83 | def test_export_with_remove_duplicates(cli_runner, test_files, cleanup_srt_files): 84 | test_file = test_files["sub"] 85 | srt_file = test_file.with_suffix(".srt") 86 | 87 | result = cli_runner.invoke(app, ["export", str(test_file), "--remove-duplicates"]) 88 | assert result.exit_code == 0 89 | assert srt_file.exists() 90 | 91 | 92 | def test_export_with_output_dialogues(cli_runner, test_files, cleanup_srt_files): 93 | test_file = test_files["sub"] 94 | 95 | result = cli_runner.invoke(app, ["export", str(test_file), "--output-dialogues"]) 96 | assert result.exit_code == 0 97 | 98 | assert "Dialogues for sub.ass:" in result.stdout 99 | assert "It's time for the main event!" in result.stdout 100 | 101 | 102 | def test_export_with_custom_encoding(cli_runner, test_files, cleanup_srt_files): 103 | test_file = test_files["sub"] 104 | srt_file = test_file.with_suffix(".srt") 105 | 106 | result = cli_runner.invoke(app, ["export", str(test_file), "--encoding", "utf-8"]) 107 | assert result.exit_code == 0 108 | assert srt_file.exists() 109 | 110 | 111 | def test_export_standard_srt_comparison(cli_runner, test_files, cleanup_srt_files): 112 | test_file = test_files["sub"] 113 | standard_srt = test_files["sub_standard"] 114 | 115 | assert test_file.exists(), f"Test file {test_file} not found" 116 | assert standard_srt.exists(), f"Standard SRT file {standard_srt} not found" 117 | 118 | srt_file = test_file.with_suffix(".srt") 119 | 120 | result = cli_runner.invoke(app, ["export", str(test_file)]) 121 | assert result.exit_code == 0 122 | assert srt_file.exists() 123 | 124 | generated_content = srt_file.read_text(encoding="utf-8") 125 | 126 | assert len(generated_content) > 0 127 | 128 | 129 | def test_export_multiple_files(cli_runner, test_files, cleanup_srt_files): 130 | file1 = test_files["sub"] 131 | file2 = test_files["sub_removing_effects"] 132 | 133 | assert file1.exists(), f"Test file {file1} not found" 134 | assert file2.exists(), f"Test file {file2} not found" 135 | 136 | srt_file1 = file1.with_suffix(".srt") 137 | srt_file2 = file2.with_suffix(".srt") 138 | 139 | result = cli_runner.invoke(app, ["export", str(file1), str(file2)]) 140 | assert result.exit_code == 0 141 | 142 | assert f"Processing: {file1.name}" in result.stdout 143 | assert f"Processing: {file2.name}" in result.stdout 144 | assert f"Success: Converted {file1.name}" in result.stdout 145 | assert f"Success: Converted {file2.name}" in result.stdout 146 | 147 | assert srt_file1.exists() 148 | assert srt_file2.exists() 149 | 150 | 151 | def test_simple_text_file_conversion(cli_runner, invalid_ass_file): 152 | invalid_file, _ = invalid_ass_file 153 | 154 | result = cli_runner.invoke(app, ["export", str(invalid_file)]) 155 | assert result.exit_code == 0 156 | assert f"Success: Converted {invalid_file.name}" in result.stdout 157 | 158 | srt_file = invalid_file.with_suffix(".srt") 159 | assert srt_file.exists() 160 | 161 | if srt_file.exists(): 162 | srt_file.unlink() 163 | 164 | 165 | def test_export_with_subtitle_exception(cli_runner, test_files, monkeypatch): 166 | test_file = test_files["sub"] 167 | 168 | from pyasstosrt import Subtitle as OriginalSubtitle 169 | 170 | def mock_init(*args, **kwargs): 171 | raise ValueError("Test error") 172 | 173 | monkeypatch.setattr(OriginalSubtitle, "__init__", mock_init) 174 | 175 | result = cli_runner.invoke(app, ["export", str(test_file)]) 176 | 177 | assert result.exit_code == 0 178 | assert "Error:" in result.stdout 179 | assert f"Failed to convert {test_file.name}" in result.stdout 180 | assert "Test error" in result.stdout 181 | 182 | 183 | def test_main_entry_point(): 184 | with unittest.mock.patch("pyasstosrt.batch.__name__", "__main__"): 185 | with unittest.mock.patch("pyasstosrt.batch.app"): 186 | with open(sys.modules["pyasstosrt.batch"].__file__, encoding="utf-8") as f: 187 | f.read() 188 | -------------------------------------------------------------------------------- /tests/test_batch_import.py: -------------------------------------------------------------------------------- 1 | import importlib.util 2 | from unittest import mock 3 | 4 | import pytest 5 | 6 | 7 | def test_module_import_error(): 8 | with mock.patch.dict("sys.modules", {"typer": None}): 9 | with pytest.raises(ImportError) as excinfo: 10 | spec = importlib.util.find_spec("pyasstosrt.batch") 11 | module = importlib.util.module_from_spec(spec) 12 | spec.loader.exec_module(module) 13 | 14 | assert "pyasstosrt was installed without the cli extra" in str(excinfo.value) 15 | -------------------------------------------------------------------------------- /tests/test_clearing_effects.py: -------------------------------------------------------------------------------- 1 | import os 2 | from pathlib import Path 3 | 4 | from pyasstosrt import Subtitle 5 | 6 | 7 | def test_removing_effects(): 8 | path = Path("tests/sub-removing-effects.ass") 9 | sub = Subtitle(path, removing_effects=True) 10 | sub.export() 11 | with open("tests/sub-removing-effects.srt", "r", encoding="utf-8") as file: 12 | file1 = open("tests/sub_standard-removing-effects.srt", "r", encoding="utf-8") 13 | assert file.read() == file1.read() 14 | file1.close() 15 | os.remove("tests/sub-removing-effects.srt") 16 | -------------------------------------------------------------------------------- /tests/test_export.py: -------------------------------------------------------------------------------- 1 | import os 2 | from os.path import isfile 3 | 4 | 5 | def test_export_output_dialogues(sub): 6 | assert sub.export(output_dialogues=True) 7 | assert not isfile("tests/sub.srt") 8 | 9 | 10 | def test_export_default(sub): 11 | try: 12 | sub.export() 13 | assert isfile("tests/sub.srt") 14 | finally: 15 | if isfile("tests/sub.srt"): 16 | os.remove("tests/sub.srt") 17 | 18 | 19 | def test_export_output_dir(sub): 20 | try: 21 | sub.export("tests/folder") 22 | assert isfile("tests/folder/sub.srt") 23 | finally: 24 | if isfile("tests/folder/sub.srt"): 25 | os.remove("tests/folder/sub.srt") 26 | 27 | 28 | def test_export_compatibility(sub): 29 | try: 30 | sub.export("tests/folder", "utf8", False) 31 | assert isfile("tests/folder/sub.srt") 32 | finally: 33 | if isfile("tests/folder/sub.srt"): 34 | os.remove("tests/folder/sub.srt") 35 | 36 | 37 | def test_export_output_dialogues_true(sub): 38 | assert sub.export(None, "utf8", True) 39 | assert not isfile("tests/sub.srt") 40 | -------------------------------------------------------------------------------- /tests/test_open.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import pytest 4 | 5 | from pyasstosrt import Subtitle 6 | 7 | 8 | def test_open(): 9 | path = "tests/sub.ass" 10 | sub = Subtitle(path) 11 | assert sub 12 | 13 | 14 | def test_open_use_pathlib(): 15 | path = Path("tests/sub.ass") 16 | sub = Subtitle(path) 17 | assert sub 18 | 19 | 20 | @pytest.mark.parametrize( 21 | "file_path, expected_error", 22 | [ 23 | ("tests/sub.ass", TypeError), 24 | ("tests/", FileNotFoundError), 25 | ("tests/sub1.ass", FileNotFoundError), 26 | ], 27 | ) 28 | def test_open_errors(file_path, expected_error): 29 | if expected_error is TypeError: 30 | with open(file_path, "r") as file: 31 | with pytest.raises(expected_error): 32 | Subtitle(file) 33 | else: 34 | with pytest.raises(expected_error): 35 | Subtitle(file_path) 36 | -------------------------------------------------------------------------------- /tests/test_remove_duplicates.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | def generate_test_cases(): 5 | yield from [ 6 | ( 7 | [ 8 | ("00:00:01,000", "00:00:02,000", "Hello"), 9 | ("00:00:02,000", "00:00:03,000", "Hello"), 10 | ("00:00:03,000", "00:00:04,000", "Hi"), 11 | ("00:00:04,000", "00:00:05,000", "Bye"), 12 | ("00:00:05,000", "00:00:06,000", "Bye"), 13 | ("00:00:06,000", "00:00:07,000", "Bye"), 14 | ("00:00:07,000", "00:00:08,000", "Good"), 15 | ("00:00:08,000", "00:00:09,000", "Luck"), 16 | ("00:00:09,000", "00:00:10,000", "Luck"), 17 | ], 18 | [ 19 | ("00:00:01,000", "00:00:03,000", "Hello"), 20 | ("00:00:03,000", "00:00:04,000", "Hi"), 21 | ("00:00:04,000", "00:00:07,000", "Bye"), 22 | ("00:00:07,000", "00:00:08,000", "Good"), 23 | ("00:00:08,000", "00:00:10,000", "Luck"), 24 | ], 25 | ), 26 | ( 27 | [ 28 | ("00:00:01,000", "00:00:02,000", "Hello"), 29 | ("00:00:02,000", "00:00:03,000", "Hello"), 30 | ("00:00:03,000", "00:00:04,000", "Hello"), 31 | ("00:00:04,000", "00:00:05,000", "Hello"), 32 | ("00:00:05,000", "00:00:06,000", "Hello"), 33 | ("00:00:06,000", "00:00:07,000", "Hello"), 34 | ], 35 | [("00:00:01,000", "00:00:07,000", "Hello")], 36 | ), 37 | ( 38 | [ 39 | ("00:00:01,000", "00:00:02,000", "Hello"), 40 | ("00:00:02,000", "00:00:03,000", "Hi"), 41 | ("00:00:03,000", "00:00:04,000", "Bye"), 42 | ("00:00:04,000", "00:00:05,000", "Good"), 43 | ("00:00:05,000", "00:00:06,000", "Luck"), 44 | ], 45 | [ 46 | ("00:00:01,000", "00:00:02,000", "Hello"), 47 | ("00:00:02,000", "00:00:03,000", "Hi"), 48 | ("00:00:03,000", "00:00:04,000", "Bye"), 49 | ("00:00:04,000", "00:00:05,000", "Good"), 50 | ("00:00:05,000", "00:00:06,000", "Luck"), 51 | ], 52 | ), 53 | ([], []), 54 | ( 55 | [ 56 | ("00:00:01,000", "00:00:02,000", "Hello"), 57 | ("00:00:02,000", "00:00:03,000", "Hello"), 58 | ("00:00:03,000", "00:00:04,000", "Hi"), 59 | ("00:00:04,000", "00:00:05,000", "Bye"), 60 | ("00:00:05,000", "00:00:06,000", "Bye"), 61 | ("00:00:06,000", "00:00:07,000", "Hi"), 62 | ("00:00:07,000", "00:00:08,000", "Hi"), 63 | ("00:00:08,000", "00:00:09,000", "Hi"), 64 | ], 65 | [ 66 | ("00:00:01,000", "00:00:03,000", "Hello"), 67 | ("00:00:03,000", "00:00:04,000", "Hi"), 68 | ("00:00:04,000", "00:00:06,000", "Bye"), 69 | ("00:00:06,000", "00:00:09,000", "Hi"), 70 | ], 71 | ), 72 | ] 73 | 74 | 75 | @pytest.mark.parametrize("input_list, expected_output", generate_test_cases()) 76 | def test_remove_duplicates(sub, input_list, expected_output): 77 | instance = sub 78 | result = instance.remove_duplicates(input_list) 79 | assert result == expected_output 80 | -------------------------------------------------------------------------------- /tests/test_text_clearing.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | 4 | @pytest.mark.parametrize( 5 | "raw_text, expected_text", 6 | [ 7 | (" Hello, world! ", "Hello, world!"), 8 | (r"Hello\hworld!", "Hello\xa0world!"), 9 | (r"Hello\Nworld!", "Hello\nworld!"), 10 | (r" Hello\hworld!\NThis\his\ha\htest. ", "Hello\xa0world!\nThis\xa0is\xa0a\xa0test."), 11 | ], 12 | ) 13 | def test_text_clearing(sub, raw_text, expected_text): 14 | cleared_text = sub.text_clearing(raw_text) 15 | assert cleared_text == expected_text 16 | -------------------------------------------------------------------------------- /tests/test_time.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from pyasstosrt import Time 4 | 5 | 6 | def test_negative_sub_time(): 7 | time_1 = Time("01:23:09.73") 8 | time_2 = Time("01:22:09.73") 9 | sub = time_1 - time_2 10 | assert sub == 60.0 11 | 12 | 13 | def test_same_time_sub(): 14 | time_1 = Time("01:23:09.73") 15 | time_2 = Time("01:23:09.73") 16 | sub = time_2 - time_1 17 | assert sub == 0.0 18 | 19 | 20 | def test_millisecond_sub(): 21 | time_1 = Time("01:23:09.73") 22 | time_2 = Time("01:23:09.75") 23 | sub = time_2 - time_1 24 | assert sub == 0.02 25 | 26 | 27 | @pytest.mark.parametrize( 28 | "input_time, expected_output", 29 | [ 30 | ("0:00:00.00", "00:00:00,000"), 31 | ("0:01:00.00", "00:01:00,000"), 32 | ("1:23:45.67", "01:23:45,670"), 33 | ("12:34:56.78", "12:34:56,780"), 34 | ], 35 | ) 36 | def test_str_conversion(input_time, expected_output): 37 | t = Time(input_time) 38 | assert str(t) == expected_output 39 | -------------------------------------------------------------------------------- /tests/test_translate.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | def test_translate(sub): 5 | sub.export() 6 | with open("tests/sub.srt", "r") as file: 7 | file1 = open("tests/sub_standard.srt", "r") 8 | assert file.read() == file1.read() 9 | file1.close() 10 | os.remove("tests/sub.srt") 11 | --------------------------------------------------------------------------------