├── .github ├── FUNDING.yml ├── dependabot.yml └── workflows │ ├── devskim.yml │ ├── powershell.yml │ ├── push-to-dh-beta.yml │ ├── push-to-dh-dev.yml │ └── push-to-dh.yml ├── .gitignore ├── .vscode ├── PSScriptAnalyzerSettings.psd1 ├── cspell.json ├── extensions.json ├── launch.json ├── settings.json └── vscode-git-graph.json ├── CHANGELOG.MD ├── LICENSE ├── README.en.md ├── README.md ├── TODO.md ├── VERSION ├── bin ├── .gitkeep └── yt-dlp-plugins │ ├── .gitkeep │ └── tver │ ├── .gitkeep │ └── yt_dlp_plugins │ ├── .gitkeep │ └── extractor │ └── .gitkeep ├── conf ├── .gitkeep └── system_setting.ps1 ├── db └── .gitkeep ├── log └── .gitkeep ├── resources ├── b64 │ ├── Icon.b64 │ └── Logo.b64 ├── colab │ └── TVerRec.ipynb ├── crx │ └── TVerRecAssistant │ │ ├── css │ │ └── popup.css │ │ ├── html │ │ ├── error.html │ │ └── popup.html │ │ ├── icon │ │ ├── TVerRec-Icon-128.png │ │ ├── TVerRec-Icon-16.png │ │ ├── TVerRec-Icon-32.png │ │ ├── TVerRec-Icon-48.png │ │ └── TVerRec-Icon-64.png │ │ ├── js │ │ ├── background.js │ │ ├── popup.js │ │ └── tver.js │ │ ├── json │ │ ├── member-rule.json │ │ └── platform-rule.json │ │ └── manifest.json ├── docker │ ├── Dockerfile │ ├── beta │ │ └── Dockerfile │ ├── dev │ │ └── Dockerfile │ └── docker-compose.yaml ├── geoip │ └── jp.csv ├── img │ ├── TVerRec-Icon.png │ ├── TVerRec-Logo-Small.png │ ├── TVerRec-Logo-Social.png │ ├── TVerRec-Logo.png │ ├── TVerRec-Toast-Large.png │ └── TVerRec-Toast.png ├── lang │ └── messages.json ├── lib │ └── win │ │ └── core │ │ ├── Microsoft.Toolkit.Uwp.Notifications.dll │ │ ├── Microsoft.Windows.SDK.NET.dll │ │ ├── README.md │ │ └── WinRT.Runtime.dll ├── lock │ ├── history.lock │ ├── ignore.lock │ └── list.lock ├── sample │ ├── history.sample.csv │ ├── ignore.sample.conf │ ├── keyword.sample.conf │ └── list.sample.csv ├── wsb │ ├── TVerRec.wsb │ └── setup │ │ ├── PowerShellインストール.cmd │ │ ├── setup.cmd │ │ ├── setup.ps1 │ │ └── 日本語化.cmd └── xaml │ ├── TVerRecMain.xaml │ └── TVerRecSetting.xaml ├── src ├── debug_console.ps1 ├── delete_trash.ps1 ├── download_bulk.ps1 ├── download_list.ps1 ├── download_single.ps1 ├── functions │ ├── common_functions.ps1 │ ├── initialize.ps1 │ ├── initialize_child.ps1 │ ├── tver_functions.ps1 │ ├── tverrec_functions.ps1 │ ├── update_ffmpeg.ps1 │ ├── update_tverrec.ps1 │ └── update_youtube-dl.ps1 ├── generate_list.ps1 ├── generate_list_child.ps1 ├── gui │ ├── gui_main.ps1 │ └── gui_setting.ps1 ├── loop.ps1 ├── move_video.ps1 └── validate_video.ps1 ├── test ├── functions │ ├── common_functions.Test.ps1 │ ├── initialize.Test.ps1 │ └── tver_functions.Test.ps1 ├── test_all.ps1 ├── test_target.ps1 └── test_tver.ps1 ├── unix ├── a.download_bulk.sh ├── b.delete_trash.sh ├── c.validate_video.sh ├── d.move_video.sh ├── debug_console.sh ├── start_tverrec.sh ├── stop_tverrec.sh ├── update_tverrec.sh ├── x.generate_list.sh ├── y.download_list.sh └── z.download_single.sh └── win ├── Setting.cmd ├── TVerRec.cmd ├── a.download_bulk.cmd ├── b.delete_trash.cmd ├── c.validate_video.cmd ├── d.move_video.cmd ├── debug_console.cmd ├── start_tverrec.cmd ├── stop_tverrec.cmd ├── update_tverrec.cmd ├── x.generate_list.cmd ├── y.download_list.cmd └── z.download_single.cmd /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: dongaba # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: TVerRec # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 13 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | 4 | # Maintain dependencies for GitHub Actions 5 | - package-ecosystem: "github-actions" 6 | directory: "/" 7 | schedule: 8 | interval: "weekly" 9 | -------------------------------------------------------------------------------- /.github/workflows/devskim.yml: -------------------------------------------------------------------------------- 1 | name: DevSkim 2 | 3 | on: 4 | push: 5 | branches: [master, beta, dev] 6 | pull_request: 7 | branches: [master, beta, dev] 8 | schedule: 9 | - cron: "36 22 * * 4" 10 | 11 | jobs: 12 | lint: 13 | name: DevSkim 14 | runs-on: ubuntu-latest 15 | #runs-on: self-hosted 16 | permissions: 17 | actions: read 18 | contents: read 19 | security-events: write 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | 24 | - name: Run DevSkim scanner 25 | uses: microsoft/DevSkim-Action@v1 26 | 27 | - name: Upload DevSkim scan results to GitHub Security tab 28 | uses: github/codeql-action/upload-sarif@v3 29 | with: 30 | sarif_file: devskim-results.sarif 31 | -------------------------------------------------------------------------------- /.github/workflows/powershell.yml: -------------------------------------------------------------------------------- 1 | name: PSScriptAnalyzer 2 | 3 | on: 4 | push: 5 | branches: [master, beta, dev] 6 | pull_request: 7 | branches: [master, beta, dev] 8 | schedule: 9 | - cron: "32 20 * * 4" 10 | 11 | jobs: 12 | psscriptanalyzer-security-scan: 13 | permissions: 14 | contents: read 15 | security-events: write 16 | actions: read 17 | name: PSScriptAnalyzer 18 | runs-on: ubuntu-latest 19 | #runs-on: self-hosted 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | 24 | - name: Run PSScriptAnalyzer 25 | uses: microsoft/psscriptanalyzer-action@v1.1 26 | with: 27 | path: ./src 28 | includeDefaultRules: true 29 | severity: '"Error", "Warning"' 30 | recurse: true 31 | settings: ./.vscode/PSScriptAnalyzerSettings.psd1 32 | output: pssanalyzer.sarif 33 | 34 | - name: Upload SARIF results file 35 | uses: github/codeql-action/upload-sarif@v3 36 | with: 37 | sarif_file: pssanalyzer.sarif 38 | -------------------------------------------------------------------------------- /.github/workflows/push-to-dh-beta.yml: -------------------------------------------------------------------------------- 1 | name: Push to Docker Hub for Beta 2 | 3 | on: 4 | push: 5 | branches: [beta] 6 | 7 | env: 8 | # Use docker.io for Docker Hub if empty 9 | REGISTRY: docker.io 10 | # github.repository as / 11 | IMAGE_NAME: dongaba/tverrec 12 | 13 | jobs: 14 | push_to_dockerhub: 15 | name: Push Docker image to Docker Hub for Beta 16 | runs-on: ubuntu-latest 17 | #runs-on: self-hosted 18 | steps: 19 | #Set Tag Name 20 | - name: Set Tag Name as Preparation 21 | id: prep 22 | run: | 23 | TAG="beta" 24 | echo "tag=${IMAGE_NAME}:${TAG}" >> $GITHUB_OUTPUT 25 | 26 | #Check out 27 | - name: Check out the repo 28 | uses: actions/checkout@v4 29 | with: 30 | ref: beta 31 | 32 | #Collect metadata 33 | - name: Extract metadata for Docker 34 | id: meta 35 | uses: docker/metadata-action@v5 36 | with: 37 | #images: dongaba/tverrec 38 | images: ${{ env.IMAGE_NAME }} 39 | flavor: latest=false 40 | tags: | 41 | type=ref,event=branch 42 | type=semver,pattern={{version}} 43 | 44 | #Build Preperation 45 | - name: Set up QEMU 46 | uses: docker/setup-qemu-action@v3 47 | - name: Set up Docker Buildx 48 | id: buildx 49 | uses: docker/setup-buildx-action@v3 50 | with: 51 | platforms: linux/amd64,linux/arm64 52 | 53 | #Confirm available platforms 54 | - name: Available platforms 55 | run: echo ${{ steps.buildx.outputs.platforms }} 56 | 57 | #Login to Docker Hub 58 | - name: Log in to Docker Hub 59 | uses: docker/login-action@v3 60 | with: 61 | username: ${{ secrets.DOCKERHUB_USERNAME }} 62 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 63 | 64 | #Build & Push 65 | - name: Build and push Docker image 66 | uses: docker/build-push-action@v6 67 | with: 68 | context: ./resources/docker/beta 69 | platforms: linux/amd64,linux/arm64 70 | push: true 71 | provenance: mode=max 72 | tags: ${{ steps.prep.outputs.tag }} 73 | labels: ${{ steps.meta.outputs.labels }} 74 | -------------------------------------------------------------------------------- /.github/workflows/push-to-dh-dev.yml: -------------------------------------------------------------------------------- 1 | name: Push to Docker Hub for Dev 2 | 3 | on: 4 | push: 5 | branches: [dev] 6 | 7 | env: 8 | # Use docker.io for Docker Hub if empty 9 | REGISTRY: docker.io 10 | # github.repository as / 11 | IMAGE_NAME: dongaba/tverrec 12 | 13 | jobs: 14 | push_to_dockerhub: 15 | name: Push Docker image to Docker Hub for Dev 16 | runs-on: ubuntu-latest 17 | #runs-on: self-hosted 18 | steps: 19 | #Set Tag Name 20 | - name: Set Tag Name as Preparation 21 | id: prep 22 | run: | 23 | TAG="dev" 24 | echo "tag=${IMAGE_NAME}:${TAG}" >> $GITHUB_OUTPUT 25 | 26 | #Check out 27 | - name: Check out the repo 28 | uses: actions/checkout@v4 29 | with: 30 | ref: dev 31 | 32 | #Collect metadata 33 | - name: Extract metadata for Docker 34 | id: meta 35 | uses: docker/metadata-action@v5 36 | with: 37 | #images: dongaba/tverrec 38 | images: ${{ env.IMAGE_NAME }} 39 | flavor: latest=false 40 | tags: | 41 | type=ref,event=branch 42 | type=semver,pattern={{version}} 43 | 44 | #Build Preperation 45 | - name: Set up QEMU 46 | uses: docker/setup-qemu-action@v3 47 | - name: Set up Docker Buildx 48 | id: buildx 49 | uses: docker/setup-buildx-action@v3 50 | with: 51 | platforms: linux/amd64,linux/arm64 52 | 53 | #Confirm available platforms 54 | - name: Available platforms 55 | run: echo ${{ steps.buildx.outputs.platforms }} 56 | 57 | #Login to Docker Hub 58 | - name: Log in to Docker Hub 59 | uses: docker/login-action@v3 60 | with: 61 | username: ${{ secrets.DOCKERHUB_USERNAME }} 62 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 63 | 64 | #Build & Push 65 | - name: Build and push Docker image 66 | uses: docker/build-push-action@v6 67 | with: 68 | context: ./resources/docker/dev 69 | platforms: linux/amd64,linux/arm64 70 | push: true 71 | provenance: mode=max 72 | tags: ${{ steps.prep.outputs.tag }} 73 | labels: ${{ steps.meta.outputs.labels }} 74 | -------------------------------------------------------------------------------- /.github/workflows/push-to-dh.yml: -------------------------------------------------------------------------------- 1 | name: Push to Docker Hub 2 | 3 | on: 4 | push: 5 | branches: [master] 6 | 7 | env: 8 | # Use docker.io for Docker Hub if empty 9 | REGISTRY: docker.io 10 | # github.repository as / 11 | IMAGE_NAME: dongaba/tverrec 12 | 13 | jobs: 14 | push_to_dockerhub: 15 | name: Push Docker image to Docker Hub 16 | runs-on: ubuntu-latest 17 | #runs-on: self-hosted 18 | steps: 19 | #Set Tag Name 20 | - name: Set Tag Name as Preparation 21 | id: prep 22 | run: | 23 | TAG="latest" 24 | echo "tag=${IMAGE_NAME}:${TAG}" >> $GITHUB_OUTPUT 25 | 26 | #Check out 27 | - name: Check out the repo 28 | uses: actions/checkout@v4 29 | with: 30 | ref: master 31 | 32 | #Collect metadata 33 | - name: Extract metadata for Docker 34 | id: meta 35 | uses: docker/metadata-action@v5 36 | with: 37 | #images: dongaba/tverrec 38 | images: ${{ env.IMAGE_NAME }} 39 | flavor: latest=true 40 | tags: | 41 | type=ref,event=branch 42 | type=semver,pattern={{version}} 43 | 44 | #Build Preperation 45 | - name: Set up QEMU 46 | uses: docker/setup-qemu-action@v3 47 | - name: Set up Docker Buildx 48 | id: buildx 49 | uses: docker/setup-buildx-action@v3 50 | with: 51 | platforms: linux/amd64,linux/arm64 52 | 53 | #Confirm available platforms 54 | - name: Available platforms 55 | run: echo ${{ steps.buildx.outputs.platforms }} 56 | 57 | #Login to Docker Hub 58 | - name: Log in to Docker Hub 59 | uses: docker/login-action@v3 60 | with: 61 | username: ${{ secrets.DOCKERHUB_USERNAME }} 62 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 63 | 64 | #Build & Push 65 | - name: Build and push Docker image 66 | uses: docker/build-push-action@v6 67 | with: 68 | context: ./resources/docker 69 | platforms: linux/amd64,linux/arm64 70 | push: true 71 | provenance: mode=max 72 | tags: ${{ steps.prep.outputs.tag }} 73 | labels: ${{ steps.meta.outputs.labels }} 74 | 75 | #Push README.md to Docker Hub 76 | - name: Docker Hub Description 77 | uses: peter-evans/dockerhub-description@v4 78 | with: 79 | username: ${{ secrets.DOCKERHUB_USERNAME }} 80 | password: ${{ secrets.DOCKERHUB_PASSWORD }} 81 | repository: ${{ env.IMAGE_NAME }} 82 | readme-filepath: ./README.md 83 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #一般 2 | .DS_Store 3 | .vs/* 4 | *.lnk 5 | 6 | #debugディレクトリ配下は調査用 7 | /debug 8 | /debug/* 9 | 10 | #アーカイブ 11 | *.7z 12 | *.zip 13 | 14 | #ダウンロードファイル 15 | *.mp4 16 | *.ts 17 | 18 | #実行ファイル 19 | /bin/*.exe 20 | /bin/ff* 21 | /bin/yt-dlp 22 | 23 | 24 | #アップデート作業ディレクトリ 25 | /tverrec-update-temp 26 | 27 | #yt-dlpエクストラクタ 28 | !/bin/yt-dlp-plugins/* 29 | 30 | #開発関連ファイル 31 | /dev 32 | /dev/* 33 | memo.txt 34 | linux-* 35 | mac-* 36 | win-* 37 | *.xlsx 38 | 39 | #テスト用のファイルなど 40 | /TestPath 41 | /TestPath/* 42 | /TestDrive 43 | /TestDrive/* 44 | 45 | #Chrome拡張機能 46 | /resources/crx/TVerRecAssistant/_metadata 47 | /resources/crx/TVerRecAssistant/_metadata/* 48 | /resources/crx/*.pem 49 | /resources/crx/*.crx 50 | 51 | #中間ファイル 52 | *.ytdl 53 | *.jpg 54 | *.webp 55 | *.webm 56 | *.vtt 57 | *temp.mp4 58 | *temp.ts 59 | *.part 60 | *mp4.part-Frag* 61 | *ts.part-Frag* 62 | *pid.txt 63 | pid*.txt 64 | .smb* 65 | brightcovenew* 66 | ffmpeg_error* 67 | ffmpeg_err* 68 | ytdl_out* 69 | ytdl_err* 70 | ignore.conf.* 71 | 72 | #その他雑多な不要ファイル 73 | * - コピー.* 74 | * - Copy.* 75 | * copy.* 76 | * copy *.* 77 | *.bak 78 | 79 | #ローカルの変更をGitHubにアップしないために 80 | /db/* 81 | /log/* 82 | /conf/* 83 | !/bin/.gitkeep 84 | !/db/.gitkeep 85 | !/log/.gitkeep 86 | !/conf/.gitkeep 87 | 88 | #コードカウンタ 89 | .VSCodeCounter 90 | 91 | #yt-dlpエクストラクタ 92 | *__pycache__* 93 | 94 | #Ignore cursor AI rules 95 | .cursor/rules/codacy.mdc 96 | -------------------------------------------------------------------------------- /.vscode/PSScriptAnalyzerSettings.psd1: -------------------------------------------------------------------------------- 1 | @{ 2 | # Use Severity when you want to limit the generated diagnostic records to a 3 | # subset of: Error, Warning and Information. 4 | # Uncomment the following line if you only want Errors and Warnings but 5 | # not Information diagnostic records. 6 | Severity = @('Error', 'Warning') 7 | 8 | # Use IncludeRules when you want to run only a subset of the default rule set. 9 | IncludeRules = @( 10 | 'PSAvoidUsingConvertToSecureStringWithPlainText', 11 | 'PSAvoidAssignmentToAutomaticVariable', 12 | 'PSUseToExportFieldsInManifest', 13 | 'PSMisleadingBacktick', 14 | 'PSAvoidUsingCmdletAliases', 15 | 'PSUseApprovedVerbs', 16 | 'PSAvoidUsingPlainTextForPassword', 17 | 'PSReservedCmdletChar', 18 | 'PSReservedParams', 19 | 'PSShouldProcess', 20 | 'PSMissingModuleManifestField', 21 | 'PSAvoidDefaultValueSwitchParameter', 22 | 'PSUseDeclaredVarsMoreThanAssignments', 23 | 'PSPossibleIncorrectComparisonWithNull', 24 | 'PSAvoidDefaultValueForMandatoryParameter', 25 | 'PSPossibleIncorrectUsageOfRedirectionOperator', 26 | 'PSUseDeclaredVarsMoreThanAssigments' 27 | ) 28 | # Use ExcludeRules when you want to run most of the default set of rules except 29 | # for a few rules you wish to "exclude". Note: if a rule is in both IncludeRules 30 | # and ExcludeRules, the rule will be excluded. 31 | ExcludeRules = @( 32 | 'PSUseProcessBlockForPipelineCommand' 33 | ) 34 | # You can use the following entry to supply parameters to rules that take parameters. 35 | # For instance, the PSAvoidUsingCmdletAliases rule takes a whitelist for aliases you 36 | # want to allow. 37 | #Rules = @{ 38 | # Do not flag 'cd' alias. 39 | # PSAvoidUsingCmdletAliases = @{Whitelist = @('cd')} 40 | 41 | # Check if your script uses cmdlets that are compatible on PowerShell Core, 42 | # version 6.0.0-alpha, on Linux. 43 | # PSUseCompatibleCmdlets = @{Compatibility = @("core-6.0.0-alpha-linux")} 44 | #} 45 | } 46 | -------------------------------------------------------------------------------- /.vscode/cspell.json: -------------------------------------------------------------------------------- 1 | { 2 | "dictionaries": [], 3 | "dictionaryDefinitions": [], 4 | "ignorePaths": [ 5 | "test/*", 6 | "conf/*.conf", 7 | "conf/*.ps1", 8 | ".vscode/settings.json" 9 | ], 10 | "ignoreWords": [ 11 | "armv", 12 | "autoremove", 13 | "dpkg", 14 | "fgiuz", 15 | "libunwind", 16 | "NOPASSWD", 17 | "OPTOUT", 18 | "Ruleset", 19 | "Rulesets", 20 | "tmpfs", 21 | "tzdata", 22 | "brightcovenew", 23 | "chcp", 24 | "Deleter", 25 | "enabledelayedexpansion", 26 | "ERRORLEVEL", 27 | "NOWINGET", 28 | "pwsh", 29 | "setlocal", 30 | "taskkill", 31 | "tasklist", 32 | "WINDOWTITLE", 33 | "ba", 34 | "bv", 35 | "brightcove", 36 | "btndownload", 37 | "btnsave", 38 | "chkbx", 39 | "colab", 40 | "cuda", 41 | "Doceker", 42 | "dongaba", 43 | "dxva", 44 | "epsodes", 45 | "epxxxxxxxx", 46 | "ffprobe", 47 | "ffplay", 48 | "finalizers", 49 | "Focusable", 50 | "geoip", 51 | "getinfo", 52 | "hwaccel", 53 | "Karte", 54 | "Mbps", 55 | "Metatag", 56 | "mshta", 57 | "mylist", 58 | "mypage", 59 | "nohup", 60 | "nontver", 61 | "osascript", 62 | "Paravi", 63 | "pscustomobject", 64 | "psobject", 65 | "Referer", 66 | "specialdetail", 67 | "specialmain", 68 | "subttl", 69 | "texttrackon", 70 | "toppage", 71 | "tverrec", 72 | "uniqued", 73 | "urlset", 74 | "videotoolbox", 75 | "webp", 76 | "winarm", 77 | "winget", 78 | "winsoundevent", 79 | "xerror", 80 | "Youtubedl", 81 | "ytdl", 82 | "zipball" 83 | ], 84 | "import": [], 85 | "version": "0.2", 86 | "words": [] 87 | } 88 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | "recommendations": [ 3 | "usernamehw.errorlens", 4 | "mhutchie.git-graph", 5 | "github.vscode-github-actions", 6 | "github.codespaces", 7 | "github.vscode-pull-request-github", 8 | "genieai.chatgpt-vscode", 9 | "yarimit.directory-configuration-generator", 10 | "henriiik.docker-linter", 11 | "codezombiech.gitignore", 12 | "ms-vscode.hexeditor", 13 | "oderwat.indent-rainbow", 14 | "tylerleonhardt.vscode-inline-values-powershell", 15 | "yzhang.markdown-all-in-one", 16 | "davidanson.vscode-markdownlint", 17 | "alefragnani.project-manager", 18 | "mechatroner.rainbow-csv", 19 | "louiswt.regexp-preview", 20 | "ms-vscode-remote.remote-ssh", 21 | "ms-vscode-remote.remote-ssh-edit", 22 | "ms-vscode.remote-server", 23 | "ms-vscode-remote.vscode-remote-extensionpack", 24 | "pspester.pester-test", 25 | "esbenp.prettier-vscode", 26 | "humao.rest-client", 27 | "richie5um2.vscode-sort-json", 28 | "simonsiefke.svg-preview", 29 | "espresso3389.unicode-normalizer", 30 | "uctakeoff.vscode-counter", 31 | "dunstontc.vscode-docker-syntax", 32 | "redhat.vscode-yaml", 33 | "bierner.markdown-preview-github-styles", 34 | "kisstkondoros.vscode-gutter-preview", 35 | "nickdemayo.vscode-json-editor", 36 | "wakahh.japanese-bracket-highlight", 37 | "ms-vscode.remote-repositories", 38 | "ms-vscode.powershell", 39 | "dbaeumer.vscode-eslint", 40 | "postman.postman-for-vscode", 41 | "rogalmic.vscode-xml-complete", 42 | "dotjoshjohnson.xml", 43 | "ms-dotnettools.vscode-dotnet-runtime", 44 | "aaron-bond.better-comments", 45 | "ms-azuretools.vscode-docker" 46 | ] 47 | } 48 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "attachDotnetDebugger": true, 5 | "createTemporaryIntegratedConsole": true, 6 | "name": "Test", 7 | "request": "launch", 8 | "script": "${workspaceFolder}/test/test_all.ps1", 9 | "type": "PowerShell" 10 | }, 11 | { 12 | "attachDotnetDebugger": true, 13 | "createTemporaryIntegratedConsole": true, 14 | "name": "Test - Target Only", 15 | "request": "launch", 16 | "script": "${workspaceFolder}/test/test_target.ps1", 17 | "type": "PowerShell" 18 | }, 19 | { 20 | "attachDotnetDebugger": true, 21 | "createTemporaryIntegratedConsole": true, 22 | "name": "Test - TVer Only", 23 | "request": "launch", 24 | "script": "${workspaceFolder}/test/test_tver.ps1", 25 | "type": "PowerShell" 26 | }, 27 | { 28 | "cwd": "${workspaceFolder}/src", 29 | "name": "GUI-Main", 30 | "request": "launch", 31 | "script": "${workspaceFolder}/src/gui/gui_main.ps1", 32 | "type": "PowerShell" 33 | }, 34 | { 35 | "cwd": "${workspaceFolder}/src", 36 | "name": "GUI-Setting", 37 | "request": "launch", 38 | "script": "${workspaceFolder}/src/gui/gui_setting.ps1", 39 | "type": "PowerShell" 40 | }, 41 | { 42 | "cwd": "${workspaceFolder}/src", 43 | "name": "Single", 44 | "request": "launch", 45 | "script": "${workspaceFolder}/src/download_single.ps1", 46 | "type": "PowerShell" 47 | }, 48 | { 49 | "cwd": "${workspaceFolder}/src", 50 | "name": "Loop", 51 | "request": "launch", 52 | "script": "${workspaceFolder}/src/loop.ps1", 53 | "type": "PowerShell" 54 | }, 55 | { 56 | "cwd": "${workspaceFolder}/src", 57 | "name": "Bulk", 58 | "request": "launch", 59 | "script": "${workspaceFolder}/src/download_bulk.ps1", 60 | "type": "PowerShell" 61 | }, 62 | { 63 | "cwd": "${workspaceFolder}/src", 64 | "name": "Delete", 65 | "request": "launch", 66 | "script": "${workspaceFolder}/src/delete_trash.ps1", 67 | "type": "PowerShell" 68 | }, 69 | { 70 | "cwd": "${workspaceFolder}/src", 71 | "name": "Validate", 72 | "request": "launch", 73 | "script": "${workspaceFolder}/src/validate_video.ps1", 74 | "type": "PowerShell" 75 | }, 76 | { 77 | "cwd": "${workspaceFolder}/src", 78 | "name": "Move", 79 | "request": "launch", 80 | "script": "${workspaceFolder}/src/move_video.ps1", 81 | "type": "PowerShell" 82 | }, 83 | { 84 | "cwd": "${workspaceFolder}/src", 85 | "name": "List-Gen", 86 | "request": "launch", 87 | "script": "${workspaceFolder}/src/generate_list.ps1", 88 | "type": "PowerShell" 89 | }, 90 | { 91 | "cwd": "${workspaceFolder}/src", 92 | "name": "List-Gen-Child", 93 | "request": "launch", 94 | "script": "${workspaceFolder}/src/generate_list_child.ps1 mypage/fav https://tver.jp/episodes/ep24gq28ft https://tver.jp/episodes/ep293lfdib https://tver.jp/episodes/ep2q8caayu https://tver.jp/episodes/ep31almkcp https://tver.jp/episodes/ep31j5sdfw", 95 | "type": "PowerShell" 96 | }, 97 | { 98 | "cwd": "${workspaceFolder}/src", 99 | "name": "List", 100 | "request": "launch", 101 | "script": "${workspaceFolder}/src/download_list.ps1", 102 | "type": "PowerShell" 103 | }, 104 | { 105 | "cwd": "${workspaceFolder}/src", 106 | "name": "youtube-dl-Up", 107 | "request": "launch", 108 | "script": "${workspaceFolder}/src/functions/update_youtube-dl.ps1", 109 | "type": "PowerShell" 110 | }, 111 | { 112 | "cwd": "${workspaceFolder}/src", 113 | "name": "ffmpeg-Up", 114 | "request": "launch", 115 | "script": "${workspaceFolder}/src/functions/update_ffmpeg.ps1", 116 | "type": "PowerShell" 117 | }, 118 | { 119 | "cwd": "${workspaceFolder}/src", 120 | "name": "Update TVerRec", 121 | "request": "launch", 122 | "script": "${workspaceFolder}/src/functions/update_tverrec.ps1", 123 | "type": "PowerShell" 124 | }, 125 | { 126 | "cwd": "${workspaceFolder}/src", 127 | "name": "Debug Cosole", 128 | "request": "launch", 129 | "script": "${workspaceFolder}/src/debug_console.ps1", 130 | "type": "PowerShell" 131 | } 132 | ], 133 | "version": "0.2.0" 134 | } 135 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "[XAML]": { 3 | "editor.autoIndent": "advanced", 4 | "editor.defaultFormatter": "PrateekMahendrakar.prettyxml" 5 | }, 6 | "[css]": { 7 | "editor.autoIndent": "advanced", 8 | "editor.defaultFormatter": "esbenp.prettier-vscode" 9 | }, 10 | "[dockercompose]": { 11 | "editor.autoIndent": "advanced", 12 | "editor.defaultFormatter": "esbenp.prettier-vscode" 13 | }, 14 | "[github-actions-workflow]": { 15 | "editor.defaultFormatter": "esbenp.prettier-vscode" 16 | }, 17 | "[html]": { 18 | "editor.autoIndent": "advanced", 19 | "editor.defaultFormatter": "esbenp.prettier-vscode" 20 | }, 21 | "[javascript]": { 22 | "editor.autoIndent": "advanced", 23 | "editor.defaultFormatter": "esbenp.prettier-vscode" 24 | }, 25 | "[jsonc]": { 26 | "editor.autoIndent": "advanced", 27 | "editor.defaultFormatter": "esbenp.prettier-vscode" 28 | }, 29 | "[markdown]": { 30 | "editor.autoIndent": "advanced", 31 | "editor.defaultFormatter": "esbenp.prettier-vscode" 32 | }, 33 | "[powershell]": { 34 | "editor.autoIndent": "advanced", 35 | "editor.defaultFormatter": "ms-vscode.powershell" 36 | }, 37 | "[xaml]": { 38 | "editor.autoIndent": "advanced", 39 | "editor.defaultFormatter": "PrateekMahendrakar.prettyxml" 40 | }, 41 | "[yaml]": { 42 | "editor.autoIndent": "advanced" 43 | }, 44 | "diffEditor.codeLens": true, 45 | "diffEditor.experimental.showMoves": true, 46 | "diffEditor.ignoreTrimWhitespace": false, 47 | "editor.autoIndent": "advanced", 48 | "editor.bracketPairColorization.enabled": true, 49 | "editor.defaultFormatter": "ms-vscode.powershell", 50 | "editor.detectIndentation": true, 51 | "editor.foldingImportsByDefault": true, 52 | "editor.formatOnPaste": true, 53 | "editor.formatOnSave": true, 54 | "editor.formatOnType": true, 55 | "editor.insertSpaces": false, 56 | "editor.renderControlCharacters": true, 57 | "editor.renderWhitespace": "all", 58 | "editor.wordWrap": "on", 59 | "files.autoGuessEncoding": true, 60 | "files.autoSave": "afterDelay", 61 | "files.insertFinalNewline": true, 62 | "files.trimFinalNewlines": true, 63 | "gitlens.graph.dimMergeCommits": true, 64 | "notebook.insertFinalNewline": true, 65 | "pester.runTestsInNewProcess": true, 66 | "pester.suppressCodeLensNotice": true, 67 | "powershell.codeFormatting.addWhitespaceAroundPipe": true, 68 | "powershell.codeFormatting.autoCorrectAliases": true, 69 | "powershell.codeFormatting.avoidSemicolonsAsLineTerminators": true, 70 | "powershell.codeFormatting.newLineAfterCloseBrace": false, 71 | "powershell.codeFormatting.newLineAfterOpenBrace": false, 72 | "powershell.codeFormatting.pipelineIndentationStyle": "IncreaseIndentationForFirstPipeline", 73 | "powershell.codeFormatting.useConstantStrings": true, 74 | "powershell.codeFormatting.useCorrectCasing": true, 75 | "powershell.codeFormatting.whitespaceBetweenParameters": true, 76 | "powershell.integratedConsole.suppressStartupBanner": true, 77 | "powershell.pester.useLegacyCodeLens": false, 78 | "powershell.scriptAnalysis.enable": true, 79 | "powershell.scriptAnalysis.settingsPath": "./.vscode/PSScriptAnalyzerSettings.psd1", 80 | "powershell.startAsLoginShell.linux": true, 81 | "prettier.useTabs": true, 82 | "svg.preview.background": "transparent", 83 | "thunder-client.saveToWorkspace": true, 84 | "thunder-client.saveTokenPerEnvironment": true, 85 | "thunder-client.sidebar.defaultTab": "Collections", 86 | "thunder-client.sidebar.showActivityFromCollection": true, 87 | "thunder-client.workspaceRelativePath": "./.vscode/", 88 | "workbench.colorTheme": "MacOS Modern Dark - Xcode Modern", 89 | "workbench.iconTheme": "material-icon-theme", 90 | "workbench.preferredLightColorTheme": "Default Dark+", 91 | "workbench.startupEditor": "newUntitledFile", 92 | "xmlComplete.formattingStyle": "singleLineAttributes" 93 | } 94 | -------------------------------------------------------------------------------- /.vscode/vscode-git-graph.json: -------------------------------------------------------------------------------- 1 | { 2 | "exportedAt": 1712148416150 3 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) dongaba. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /TODO.md: -------------------------------------------------------------------------------- 1 | # ToDo 2 | 3 | ## 便利機能 4 | 5 | - [x] TVer.jpの検索機能を使ってキーワード指定できるようにする 6 | - [x] 削除対象の番組を部分一致で指定できるようにする 7 | - [x] 部分一致したものはダウンロードしない 8 | - [x] ダウンロードされてしまったものでも部分一致で削除する 9 | - [x] プログレスバーの実装 10 | - [ ] メタデータを追加で指定する(タイトルにシリーズ番号、日付、発行者、著作権、トラック番号、エンコーダなど) 11 | - [x] ffmpegのエラーログの古いものを削除 12 | - [x] タレント名で検索してタレントIDを特定し、そこから番組ダウンロード 13 | - [x] 番組名で検索してそこから番組IDを特定し、そこから番組ダウンロード 14 | - [ ] 番組ダウンロード時にジャンルIDの情報を取得し、メタデータとして番組に埋め込む→やり方不明 15 | - [ ] 廃止になったジャンルIDを自動的に削除→タグの一覧取得方法が不明のため対応見込みなし 16 | - [ ] 追加になったジャンルIDを自動的に追加→タグの一覧取得方法が不明のため対応見込みなし 17 | - [x] バージョンアップ通知機能を追加 18 | - [x] ダウンロード先に放送局ごとにディレクトリ分けした上で番組ディレクトリを作るオプションをつける 19 | - [x] 放送局ごとに保存した番組の最終移動先への移動をサポートする→プルリクで対応 20 | - [x] ダウンロード後のチェック処理もスキップするオプションをつける 21 | - [x] 番組検証に速度重視のモードを追加 22 | - [x] ffmpegの自動更新機能を追加 23 | - [x] Windows向け 24 | - [x] mac向け 25 | - [x] Linux向け 26 | - [x] トースト通知機能を追加 27 | - [x] Windows向け 28 | - [x] mac向け 29 | - [x] Linux向け 30 | - [x] バージョンアップ時にダウンロード履歴ファイルがクリアされないようにする 31 | - [x] バージョンアップ時に設定ファイルがクリアされないようにする 32 | - [x] 検索結果をダウンロードせずに番組リストを出力 33 | - [x] 番組リストを使ったダウンロード 34 | - [x] ダウンロード履歴破損時に破損レコードを削除 35 | - [ ] フリーワードで指定で特定のジャンルからのみダウンロード 36 | - [x] コンテナによる仮想化に対応 37 | - [x] Google Colabでuser_setting.ps1を使用するようにする 38 | - [x] Dockerコンテナでuser_setting.ps1を使用するようにする 39 | - [x] Write-Hostを廃止する 40 | - [ ] 並列処理時にToast通知を更新する 41 | - [x] 並列処理時に並列度を指定できるようにする 42 | - [x] 並列処理を行わないオプションを指定できるようにするかも 43 | - [ ] CRLFではなくLFによるファイル書き込みの強制 44 | - [x] ダウンロード対象外リスト 45 | - [x] 設定ファイル 46 | - [ ] CSVファイル 47 | - [x] リストファイル0件時のエラー処理追加 48 | - [ ] GUIの実装 49 | - [x] Windows向け 50 | - [ ] mac向け 51 | - [ ] Linux向け 52 | - [x] 曜日時間帯別稼働制御の実装 53 | 54 | ## youtube-dl制御機能 55 | 56 | - [x] youtube-dlのパラメータ指定を変更して、メタデータを番組に含めるようにする。その際、中間ファイルが増える可能性があるので削除対象に含めるか検討する 57 | - [x] youtube-dlでダウンロードする際に、中間ファイルの出力先を移動先と分ける 58 | - [x] youtube-dlの番組処理について、パフォーマンスチューニングを検討する 59 | 60 | ## 性能改善・安定性向上 61 | 62 | - [x] ハードウェアアクセラレーションの活用。自動判定は難しいので、設定で変更できるようにした。 63 | - [x] ダウンロード履歴ファイルの排他制御を行い、複数PCから同時実行できるようにする 64 | - [x] 変数のスコープを明確にする 65 | - [x] 変数名を実態に合わせる 66 | - [x] 関数の引数チェックを厳密にする 67 | - [x] 関数の汎用化・正規化を行う 68 | - [x] 番組の情報を引き回すためにカスタムオブジェクトを作成する 69 | - [x] プログレスバーの残骸をきれいにする→どうやら無理っぽいので廃止で対応 70 | - [x] 各種コードチェックに引っかからないように修正 71 | - [x] トークンの取得頻度を下げる 72 | 73 | ## 対象環境の拡充 74 | 75 | - [x] Linuxでの動作確認をする。ひとまずPi4では動いた。Ubuntuでも動く。 76 | - [x] Macでも動作確認をする。ひとまずM1 Mac Miniでは動いた。 77 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 3.4.7 2 | -------------------------------------------------------------------------------- /bin/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/bin/.gitkeep -------------------------------------------------------------------------------- /bin/yt-dlp-plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/bin/yt-dlp-plugins/.gitkeep -------------------------------------------------------------------------------- /bin/yt-dlp-plugins/tver/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/bin/yt-dlp-plugins/tver/.gitkeep -------------------------------------------------------------------------------- /bin/yt-dlp-plugins/tver/yt_dlp_plugins/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/bin/yt-dlp-plugins/tver/yt_dlp_plugins/.gitkeep -------------------------------------------------------------------------------- /bin/yt-dlp-plugins/tver/yt_dlp_plugins/extractor/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/bin/yt-dlp-plugins/tver/yt_dlp_plugins/extractor/.gitkeep -------------------------------------------------------------------------------- /conf/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/conf/.gitkeep -------------------------------------------------------------------------------- /db/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/db/.gitkeep -------------------------------------------------------------------------------- /log/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/log/.gitkeep -------------------------------------------------------------------------------- /resources/b64/Icon.b64: -------------------------------------------------------------------------------- 1 | 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 -------------------------------------------------------------------------------- /resources/b64/Logo.b64: -------------------------------------------------------------------------------- 1 | iVBORw0KGgoAAAANSUhEUgAAAK0AAAA+CAYAAABZXZuuAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAA/BSURBVHhe7Z0JcBRVGscfSTjDLQYvPEAODxSQNXJoAFEuBdZSQRAFD7xAhXJhVRCiKLCCgiC64IWCooCACoKRq2QFRBRFLQ4tOUUBDXLlmgn7fi/dodN5PdOZmQRCvV9V1/R0T6a76f/73nf1IAwGg8FgMBgMBoPBYDAYDAaDwXBCKWO9+ubmm2+uuG/fvg7BYDD52LFjtXJzc609BoM/ypcvnyNfNsnXJZLNeVv941u0KSkpCVKog6VIh0qx1rQ2GwxRER8fn5aYmDhIivdHa1NYfIm2S5cuNdLT0+dJsaZYmwyGWJJZuXLlfmlpabOs9yEJK1osbHZ2dppcbcP7uLg4cf3114s2bdqIs88+W5QtW5bNJYIcNOLQoUPihx9+EB9++KHYtWuXtcdwChCoVq1at8WLFy+y3nsSVrQtWrQYKl/GsF6jRg0xduxYcemll/L2hJKTkyMmTJgg5s2bZ20xlHakq7C3Xr16DadPn37A2qQl3nrVct111yVmZWXNLVOmTEX5heKll14Sl1xyibX3xML5tGrVSvz8889i+/bt1lZDaUbOpIlHjhw5uG3btlXWJi1x1quWjIyMzlKwNVjv1KmTuPjii9X2k4lBgwYpARtODWSwf7u16klI90BasvG5ubmDWX/xxRdFcnKy2g5TpkyJ2KeUA0H5wtWrVxd16tRR1rtBgwbKX46EBx98UGzYsMF6ZyjNoI0rrrii2qRJkw5amwoRUrQtW7acKU12L9bnzp0rzjzzTLUd7rrrLrFp0ybrXfTUrFlTdOjQgTxwgeP4YfTo0eLjjz+23hlKO7Vr1244f/78LdbbQoQ0bUTrNtFkCThIvfgyon3ZONGzfLzoK5c+culaLk40S4gTleXQ+euvv8R7770nevTooay69G3y/tgHJZnBMBQ/u3fvttb0RDYf+6SGNPU9pDgnJJYVwyomiN5yvYMUbopc2snln+XixcAK8WKi3D9Y7m8shR0IBMTs2bNFnz59xE8//WR9k8FwnGIRLWERVnRsYoLoKMVZJUxijZNAsAh3qFxqx5URv//+u3jooYfEF198kfchg8Ei5qJFoEOk8LCikUzajaR4R8q/byrdhqysLDFs2DCxdu1aa6/BEGPRIth/S8E1kMKLhgryzwdItyFZCpciwvDhw8P6ObGAyDUhIcF6ZzhZCamuFi1azJQvKnvw0UcfiVq1arGqcGcPcAmY2utHKVgnAbn8JyMgtgaPicsuu0y88sorSlhuxo0bp8q6Ttq3b69SYQR4lH4zMzNFdna2oCuNhdxuxYoVRZUqVUTVqlVFtWrV1LJ48WJV9Zs5c6YKRLH2LPztt99+K9544w3rCMfhOKTsypcvr76zQoUKYt++fWLgwIHWJ4qfe++9V1x11VXq2OXKlVPBKQOQhWslnRgMBsXBgwfFtm3bxJo1a8Snn35apIC3pJBxTcN169ZFlj0oCl2lOxBLwQI2r7+0uFje77//Xnz22Wd5O3xw7rnnijPOOEMVRMgvp6SkUOFTaTUKJfRPXH311aJJkyaibt264rTTTlM3GMvODefvzzvvPCXGxo0bkztU6zrYf+WVV4rLL79cfYa/Peecc6y9JUO9evXERRddJC644ALVE5KUlKTSiAzIxMRENZgqV64szjrrLFKZYvDgwWLOnDni2muvtb6h9BAT0daSgVNnGXgVB7WkZe1cNq/i9eabbxZIw4WCGxYJWCMvFyEjI8NaK4iup5jvKUkOHz5srfmHmeXpp59WA7k0EROldSobp6xicUF+t6K0tjt27BDffPONtTU0jRo1staKBmJnetXhJQydaHXbihOvARUO3C2sLta4tBC1aMkQtJABU3GCYJtbx1i+fLl6DQU3AuHRTEN5d+XKlUL6SNbeguDXkRdetGiRWLFihRoYXqLFH9Shs6olbWnxu9388ccfqjfjvvvuE0OGDFHFG3xzN/j1uEqlhajVhh+LqIqbJpa/vH79evUaClyIO+64Qy0ESY8//rj44IMPrL0Fwa+jAjdq1CjxxBNPiKlTp8bE0nqJFtcD3/eGG24QN910k+pU82vldEGoDb64GwYg6cKNGzeKVatWiUmTJqmStw78eh2nn366aNu2rTrXLl26iPr161t7QsO54l9fc801ol27duqaCRJjQdSipTxbEtSNzzvVnTt3aq1KOHQ3FajAufEqC3tNwTo/2y1kbuKtt94qFixYoLIgDJDHHntMPP/886pvon///gV8aW4wQRIDj5TfjBkzxLRp09Q+gimyBfwtYgLddei2MVPpBhmZDyccg++fP3++ePbZZ9W5Pvnkk2L69OnirbfeCtnx17lzZ/H++++rDMyYMWOUQeCamdWGDh2qgsJoiFq0SSFGfyypLg+D/eMfnGmvqBRFtF7i9GqBpFPNDSkvG9JNI0eOFI8++qhqpHeDQPv27atEYg8YIv1nnnlG3H///SrbgSU8//zzVRpt1qxZol+/fspKY81AZ9n9DCYb0oI2xAOk9vh+nXUnQ4IIW7dubW3Jg+tkgFEQ0mVPGBg33nhj1L0iUYu2UsloVmEfK5Lcok6coLvZv/32m9iypXCakFSRG6Y93Q1ypuewlqTbwkFqDncG9u/fL/bu3avWbSpVqiRuu+22Ahb5zz//VK86MeoGGak+XQso/j8wWMhTkyoLBcJLTU1V6TUbZgsGWCg2b97sGRv4JWrR6sdt8WDbjUj6br18TK8Ums4HRlTkYJ307NnTWjsOQlq2bJlap2cY0TpZunSpKs5gSd0D0NmaiSsUDq8ZBC688EIxYMAA1Xx05513iueee065JW4OHDiQXyrv1auX8mNtOD9miXvuuadQEMw0z3Ygp927d2+1HorVq1dba5ETtWgP+UubRg2D47B1rHBWQIeX0L22p6WlFbJ0fPb224831tuBhhuyEbaYCGKcAQiCJjdKNREfj2nWCdaRwAVsKxqKUFMtBRNE+MADD6gMAg+juq8XC01wZrtEbkuJ/8qsQcfdiBEjxJ49e6w9eVC04Ry6detWyLITexD8MWhxc7jWJUuWWHsjJ2rR7sktGdXuk8fBVhLZU+0pKl4316uQgOjeffdd691xOnbsqIIUwK90+3xkGJwlZfdDoNx0rC9WEJ/RbbmB6hYcPXpUvTpBCJ9//rlqyidNx5PJ4HUdoeD7Ca7sTjosbO3atdW6DQOX66WMTmncbdkZkLgIVBbdTJ48WaXZcD2oaL7zzju+Zo9wRC1a+gJKgi3WcbjZXgFRKLzSWF7bgX4LehecIA6mdoSlK4EiJmdqzNmvAYiYDMLbb7+tAi8yCm5sAer8cKL3p556SowfP15F5V9//bXaHuo6vECs5LBt3OcK+K2kBV999VV1XN0g43x1hoQ0W3EQtWi3Swu432dpNRrWB/O8Z+dzakXBndKx8doONNmQtnGDtcVCua0s/h+RfaSQ+KebjaYdL9zTs40uB0qelidB8LsXLlxobT0ObojbsvqFWODvv/8WX375pfj111+1gWAkA8kPUYsWua7IKd5wbL8cGBsDeQODKSoSvHKDupvthN9VcFtb/EJdmRiBcyOduP1ibjZTJlMnlpISKj4fuU3831tuuUUJwQtdCgp018GgYzpGvPiTbsuNy+T00d3nCvjer7/+urLsDFT8Y86Rc8X/JX9LkEvTvpvu3btba7ElatHCUinag8VobBfI72dYNG/ePD8vWVQisbTAjccXCwfCJqHuBl/OCaIj6MEi45PSIvjLL7+Ipk2bquKBM8jUCdTLNdINSmeljfPTlcCpzBGwAYGfu2+ZXgzbh+bvv/vuO3X+iBWf3sZ2U5yQnmNgIm6OQ6EhXErMDzERbaYU7MwsfUopWjZLX/Z/UrTcQKpAkeJlUcOJFqgKkTcNBb6mrihB6sudl8QnRgTcUKpNWHNeqTKxz6YootVdHwGfE92v8XD9zrQd1+oEX5Vq3Msvv6xSX7zyGURIGs12L/DTdX0NuCAUHEi1kWnR5bqLSkxEC18FcsXyGLsJB+RU+t/MoHJB+EeibzVSvLIHfvwuIvZQ1pYKnftm2+Dn0tvghpvNDWWadQYxTKm0DEK0oqUY4bw+modoAHfDMWmaAdJ1FACccExmAgoTvNqBIt9NSg34NyBYC0ek3XdOYiZamCGt7Vop3liAuzE+IyjSpXApXz7yyCPWnsgoasrLDZbEWZp1Qi4zVJKf3CTC9SpwOOEHUOyCh060Xs01uuvg79057U8++cRaOw7f2bVrV7WOtcTP9vObFpyn8wdbcHnC9TxTOPH7b+5FTEWLXLGMC7Nz86tXkbBTBl6jMgJil3wld8jjNFiNaEBw+HVM4VhOcpRsoxrkB24mwQwWhe9hIXDBx9NF5m6wYHfffbdqf9RNo5wLNxwXyHYn8C9xS3hPbwDH9Oo047Pp6enqcywEhJyrW/hkJrC2zs/yb9CsWTPrE0LtoxgxceJEFcS5YfDhwz788MPqupzgl1OFoxXUPUg5R2YsP4M3FIWHsoOiPCPmpmF8GfU7B3XiQh6iAFlS6Ytz8kSP3aKm/8ILL4R9dEX3jNjJDNMq+U6mZCJ6xB9JE1BJwX3n0SVmKwYN1lXnv7vBZcGy4l5wfQwQP8h/k5J5RswNAdSIowExMTMg1kuXgWBNB5t3SIs6Jzso/nU0R8y3BEt58LXXXivxZ61KAiwtVSIelKTX9WQWLGDtqbxxvlu3bvUlWCDzQg6Xa/UrWD8Um2gBQW4IHBOTpcsw4EiOGK5EHBRT5TJFLqOlCzBQbkfcWFe7j4EmDOrhkfQYGE59Qoo2Li4u3z76HV1e4MXgo26QVne1XNbJhdLsEY0Fxu/BHfFLtOdmOLmoW7duSKc3nKXN/7Viu98yFjRs2FB1sGNN7Y4mJwRKJKLphvIjyFiem+HEIgPHYKNGjUL+Mks4S5vfTaFLlUQKfiqtbPitdilTl5Ii0iXixi/ygpwifpbh1EAGbWtSU1Mzrbdawol2mVS+ykbTvFuUH8soCjQ+k5i2W/6ckJ5BuPSeusEi02VvOHVISEgo/BM+LkKKduXKlQFpAfNb3e2SY6jkcaTw6yjkKXWPMhOF0uWPO4FQgYibZ678JMENpQNpJDfWr18/bKOHryRq69atpwWDwbznKiRUqEhI+03Mu+Hn6ukU0sGAoH/zxx/1/xca/bT0spKktwVsKP3IGf1A1apVW0mXMOyPEvsSrRRY/O7du8dJQVFL9V8tMBh8IP3YnYmJid2XLFni6+eDiiTAli1btpXCTZWrPDtsxGuICukOpEsfdmpSUtLo2bNnF2xEDkFEwpN+Zx1pzv8RCASSvJ6jNxh0SKHSoJMjrevm5OTkr1JTUws3YhgMBoPBYDAYDAaDwWAwGAwGg+EkRoj/AwXRAKXqZGBVAAAAAElFTkSuQmCC -------------------------------------------------------------------------------- /resources/colab/TVerRec.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "metadata": { 7 | "id": "zD46E6i831V3" 8 | }, 9 | "outputs": [], 10 | "source": [ 11 | "# Update the list of packages\n", 12 | "!sudo apt-get update\n", 13 | "# Install pre-requisite packages.\n", 14 | "!sudo apt-get install -y wget apt-transport-https software-properties-common git\n", 15 | "\n", 16 | "# Download the Microsoft repository GPG keys\n", 17 | "!wget -q \"https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb\"\n", 18 | "# Register the Microsoft repository GPG keys\n", 19 | "!sudo dpkg -i packages-microsoft-prod.deb\n", 20 | "!rm -rf packages-microsoft-prod.deb*\n", 21 | "# Update the list of packages after we added packages.microsoft.com\n", 22 | "!sudo apt-get update\n", 23 | "# Install PowerShell\n", 24 | "!sudo apt-get install -y powershell\n", 25 | "# Confirm PowerShell\n", 26 | "!which pwsh\n", 27 | "\n", 28 | "# Version up if available\n", 29 | "!sudo apt-get upgrade\n" 30 | ] 31 | }, 32 | { 33 | "cell_type": "code", 34 | "execution_count": null, 35 | "metadata": { 36 | "id": "Y_i8-YFTTt_H" 37 | }, 38 | "outputs": [], 39 | "source": [ 40 | "# git clone\n", 41 | "!ls -la /content\n", 42 | "!pwd\n", 43 | "!if [ ! -d /content/TVerRec ] ; then git clone https://github.com/dongaba/TVerRec ; else cd /content/TVerRec && git pull && cd - ; fi\n", 44 | "!chmod a+x /content/TVerRec/unix/*.sh\n", 45 | "\n", 46 | "# setting for Colab\n", 47 | "!sed -i -e \"s|\\.\\./src|/content/TVerRec/src|g\" /content/TVerRec/unix/*.sh\n", 48 | "!echo '$script:downloadBaseDir = \"/content/drive/MyDrive/Work\"' >> /content/TVerRec/conf/user_setting.ps1\n", 49 | "!echo '$script:downloadWorkDir = \"/tmp\"' >> /content/TVerRec/conf/user_setting.ps1\n", 50 | "!echo '$script:saveBaseDir = \"/content/drive/MyDrive/Save\"' >> /content/TVerRec/conf/user_setting.ps1\n" 51 | ] 52 | }, 53 | { 54 | "cell_type": "code", 55 | "execution_count": null, 56 | "metadata": { 57 | "id": "krvlPAIjUmKO" 58 | }, 59 | "outputs": [], 60 | "source": [ 61 | "from google.colab import drive\n", 62 | "drive.mount('/content/drive')\n" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": null, 68 | "metadata": { 69 | "id": "Ntt6saViTwH1" 70 | }, 71 | "outputs": [], 72 | "source": [ 73 | "!/content/TVerRec/unix/start_tverrec.sh\n" 74 | ] 75 | } 76 | ], 77 | "metadata": { 78 | "colab": { 79 | "provenance": [] 80 | }, 81 | "kernelspec": { 82 | "display_name": "Python 3", 83 | "name": "python3" 84 | }, 85 | "language_info": { 86 | "name": "python", 87 | "version": "3.11.9" 88 | } 89 | }, 90 | "nbformat": 4, 91 | "nbformat_minor": 0 92 | } 93 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/css/popup.css: -------------------------------------------------------------------------------- 1 | html { 2 | font-family: Helvetica, Arial, Verdana, Tahoma, sans-serif; 3 | font-size: 12px; 4 | width: 800px; 5 | height: 108px; 6 | border-radius: 10px; 7 | background-color: #eee; 8 | } 9 | 10 | .logo { 11 | width: 58px; 12 | height: 58px; 13 | position: absolute; 14 | top: 10px; 15 | left: 10px; 16 | vertical-align: middle; 17 | background: #d8453e; 18 | display: flex; 19 | align-items: center; 20 | border-radius: 10px 0 0 10px; 21 | } 22 | 23 | .message { 24 | width: 722px; 25 | height: 58px; 26 | font-size: 11px; 27 | position: absolute; 28 | top: 10px; 29 | left: 68px; 30 | display: flex; 31 | align-items: center; 32 | justify-content: center; 33 | color: #fff; 34 | background-color: #333; 35 | border-radius: 0 10px 10px 0; 36 | } 37 | 38 | .v-center { 39 | margin: 5px; 40 | flex: 1; 41 | } 42 | 43 | .h-center { 44 | margin: 0 auto; 45 | } 46 | 47 | .button { 48 | position: absolute; 49 | top: 78px; 50 | left: 10px; 51 | width: 780px; 52 | vertical-align: middle; 53 | display: flex; 54 | justify-content: center; 55 | align-items: center; 56 | } 57 | 58 | .refresh-button { 59 | font-size: 14px; 60 | width: 150px; 61 | height: 20px; 62 | text-align: center; 63 | color: #fff; 64 | background-color: #333; 65 | border: none; 66 | border-radius: 10px; 67 | margin: 0 auto; 68 | } 69 | 70 | .refresh-button:hover { 71 | font-size: 14px; 72 | width: 150px; 73 | height: 20px; 74 | text-align: center; 75 | color: #fff; 76 | background: #d8453e; 77 | border-radius: 10px; 78 | } 79 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/html/error.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Popup 8 | 9 | 10 | 11 | 12 |
13 | 18 |
19 |
20 |
このページはTVerのページではありません。
21 |
TVerのページを開いた状態で実行してください。
22 |
23 |
24 |
25 | 28 |
29 |
30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/html/popup.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Popup 8 | 9 | 10 | 11 | 12 |
13 | 18 |
19 |
20 |
platform_uid :
21 |
platform_token :
22 |
member_sid :
23 |
24 |
25 |
26 |
27 | 28 |
29 |
30 |
31 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/icon/TVerRec-Icon-128.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/crx/TVerRecAssistant/icon/TVerRec-Icon-128.png -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/icon/TVerRec-Icon-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/crx/TVerRecAssistant/icon/TVerRec-Icon-16.png -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/icon/TVerRec-Icon-32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/crx/TVerRecAssistant/icon/TVerRec-Icon-32.png -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/icon/TVerRec-Icon-48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/crx/TVerRecAssistant/icon/TVerRec-Icon-48.png -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/icon/TVerRec-Icon-64.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/crx/TVerRecAssistant/icon/TVerRec-Icon-64.png -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/js/background.js: -------------------------------------------------------------------------------- 1 | /*global chrome*/ 2 | 3 | // ルールの有効化 4 | function enablePlatformRule() { 5 | chrome.declarativeNetRequest.updateEnabledRulesets( 6 | { enableRulesetIds: ["platform-rule"] }, 7 | () => {} 8 | ); 9 | console.log("TVerRec Assistant: Platform API Rule Enabled"); 10 | } 11 | function enableMemberRule() { 12 | chrome.declarativeNetRequest.updateEnabledRulesets( 13 | { enableRulesetIds: ["member-rule"] }, 14 | () => {} 15 | ); 16 | console.log("TVerRec Assistant: Member API Rule Enabled"); 17 | } 18 | 19 | // ルールの無効化 20 | function disablePlatformRule() { 21 | chrome.declarativeNetRequest.updateEnabledRulesets( 22 | { disableRulesetIds: ["platform-rule"] }, 23 | () => {} 24 | ); 25 | console.log("TVerRec Assistant: Platform API Rule Disabled"); 26 | } 27 | function disableMemberRule() { 28 | chrome.declarativeNetRequest.updateEnabledRulesets( 29 | { disableRulesetIds: ["member-rule"] }, 30 | () => {} 31 | ); 32 | console.log("TVerRec Assistant: Member API Rule Disabled"); 33 | } 34 | 35 | // 保存処理 36 | function saveStoragePlatform(platform_uid, platform_token) { 37 | chrome.storage.local.set({ 38 | key_uid: platform_uid, 39 | key_token: platform_token, 40 | }); 41 | chrome.storage.local.get(console.log); 42 | } 43 | function saveStorageMember(member_sid) { 44 | chrome.storage.local.set({ 45 | key_sid: member_sid, 46 | }); 47 | chrome.storage.local.get(console.log); 48 | } 49 | 50 | //クエリパラメータの処理 51 | function getSearchParams(search) { 52 | const params = new URLSearchParams(search); 53 | let result = {}; 54 | for (const [key, value] of params) { 55 | result[key] = value; 56 | } 57 | return result; 58 | } 59 | 60 | //ローカルストレージの変更時にコンソールメッセージ 61 | chrome.storage.onChanged.addListener((changes, namespace) => { 62 | for (let [key, { oldValue, newValue }] of Object.entries(changes)) { 63 | console.log( 64 | `TVerRec Assistant: Storage key "${key}" in namespace "${namespace}" changed.`, 65 | `TVerRec Assistant: Old value was "${oldValue}", new value is "${newValue}".` 66 | ); 67 | } 68 | }); 69 | 70 | //アクティブなタブを切り替えたとき 71 | chrome.tabs.onActivated.addListener(function (activeInfo) { 72 | chrome.tabs.get(activeInfo.tabId, function (tab) { 73 | setAction(tab.url); 74 | }); 75 | }); 76 | 77 | //タブの情報に変更があったとき 78 | chrome.tabs.onUpdated.addListener((tabId, change, tab) => { 79 | if (tab.active && change.url) { 80 | setAction(change.url); 81 | } 82 | }); 83 | 84 | //アクティブタブによってポップアップを変える 85 | function setAction(url) { 86 | console.log(`TVerRec Assistant: active page = "${url}"`); 87 | const pattern = /^https:\/\/tver.jp\//; 88 | if (pattern.test(url)) { 89 | chrome.action.setPopup({ popup: "html/popup.html" }); 90 | } else { 91 | chrome.action.setPopup({ popup: "html/error.html" }); 92 | } 93 | } 94 | 95 | //ネットワークリクエストに関するイベントを監視 96 | chrome.declarativeNetRequest.onRuleMatchedDebug.addListener((e) => { 97 | console.log("TVerRec Assistant: Connection Blocked by TVerRec"); 98 | 99 | const url = new URL(e.request.url); 100 | 101 | if (url.host.includes("tver.jp") && !url.host.includes("statics.tver.jp")) { 102 | const excludedExtensions = [ 103 | ".js", 104 | ".css", 105 | ".png", 106 | ".svg", 107 | ".ico", 108 | ".json", 109 | ".html", 110 | ]; 111 | const hasExcludedExtension = excludedExtensions.some((ext) => 112 | url.pathname.endsWith(ext) 113 | ); 114 | 115 | if (!hasExcludedExtension) { 116 | console.log("TVerRec Assistant: URL:", e.request.url); 117 | const searchParams = getSearchParams(url.search); 118 | console.log("TVerRec Assistant: Param Array:", searchParams); 119 | 120 | if ( 121 | searchParams.platform_uid !== undefined && 122 | searchParams.platform_token !== undefined 123 | ) { 124 | console.log("TVerRec Assistant: Add below to user_settings.ps1"); 125 | console.log(` $script:myPlatformUID = '${searchParams.platform_uid}'`); 126 | console.log( 127 | ` $script:myPlatformToken = '${searchParams.platform_token}'` 128 | ); 129 | saveStoragePlatform( 130 | searchParams.platform_uid, 131 | searchParams.platform_token 132 | ); 133 | disablePlatformRule(); // UIDとTOKENを取得したらルールを解除 134 | } 135 | 136 | if (searchParams.member_sid !== undefined) { 137 | console.log("TVerRec Assistant: Add below to user_settings.ps1"); 138 | console.log(` $script:myMemberSID = '${searchParams.member_sid}'`); 139 | saveStorageMember(searchParams.member_sid); 140 | disableMemberRule(); // SIDを取得したらルールを解除 141 | } 142 | } 143 | } 144 | }); 145 | 146 | //メッセージが受信された時にルール有効化 147 | chrome.runtime.onMessage.addListener((message, sender, sendResponse) => { 148 | if (message.action === "enablePlatformRule") { 149 | enablePlatformRule(); 150 | sendResponse({ status: true, data: "Platformルールを有効化しました" }); 151 | } 152 | if (message.action === "enableMemberRule") { 153 | enableMemberRule(); 154 | sendResponse({ status: true, data: "Memberルールを有効化しました" }); 155 | } 156 | }); 157 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/js/popup.js: -------------------------------------------------------------------------------- 1 | /*global chrome*/ 2 | 3 | // ストレージからデータを読み込む関数 4 | function readStorage() { 5 | chrome.storage.local.get(null, (data) => { 6 | const { key_uid, key_token, key_sid } = data; 7 | if ((key_uid && key_token) || key_sid) { 8 | console.log(`TVerRec Assistant: platform_uid = ${key_uid}`); 9 | console.log(`TVerRec Assistant: platform_token = ${key_token}`); 10 | console.log(`TVerRec Assistant: member_sid = ${key_sid}`); 11 | const uidElement = document.getElementById("uid"); 12 | const tokenElement = document.getElementById("token"); 13 | const sidElement = document.getElementById("sid"); 14 | if (uidElement) { 15 | uidElement.innerText = `platform_uid : ${key_uid}`; 16 | } 17 | if (tokenElement) { 18 | tokenElement.innerText = `platform_token : ${key_token}`; 19 | } 20 | if (sidElement) { 21 | sidElement.innerText = `member_sid : ${key_sid}`; 22 | } 23 | } 24 | }); 25 | } 26 | 27 | // ストレージのクリア 28 | function clearStorage() { 29 | chrome.storage.local.clear(); 30 | } 31 | 32 | // ボタンクリック時に実行する処理を定義 33 | document.getElementById("refresh").addEventListener("click", async () => { 34 | clearStorage(); 35 | console.log( 36 | "TVerRec Assistant: platform_uid, platform_token and member_sid cleared" 37 | ); 38 | 39 | //ルールを有効化 40 | chrome.runtime.sendMessage( 41 | { action: "enablePlatformRule", data: "" }, 42 | function () { 43 | window.close(); 44 | } 45 | ); 46 | chrome.runtime.sendMessage( 47 | { action: "enableMemberRule", data: "" }, 48 | function () { 49 | window.close(); 50 | } 51 | ); 52 | 53 | //新規タブでTVerを開く 54 | chrome.tabs.create({ url: "https://tver.jp/mypage/fav" }); 55 | 56 | readStorage(); 57 | }); 58 | 59 | // ストレージからデータを読み込む 60 | readStorage(); 61 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/js/tver.js: -------------------------------------------------------------------------------- 1 | //オブザーバの設定 2 | const config = { attributes: false, childList: true, subtree: true }; 3 | 4 | 5 | 6 | // ミューテーションオブザーバーのコールバック関数 7 | const callback = function (mutationsList, observer) { 8 | for (const mutation of mutationsList) { 9 | if (mutation.type === "childList") { 10 | //通信エラーの閉じるボタン 11 | const button = document.querySelector(".button_button__GOl5m.error-modal_button__fgiuz"); 12 | if (button) { 13 | button.click(); 14 | // 必要ならば監視を解除 15 | observer.disconnect(); 16 | } 17 | } 18 | } 19 | }; 20 | 21 | //MutationObserverのインスタンスを作成 22 | const observer = new MutationObserver(callback); 23 | 24 | //監視を開始 25 | observer.observe(document.body, config); 26 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/json/member-rule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 2, 4 | "priority": 2, 5 | "action": { 6 | "type": "block" 7 | }, 8 | "condition": { 9 | "urlFilter": "*member-api.tver.jp/v2/api/members/info?member_sid*", 10 | "resourceTypes": [ 11 | "xmlhttprequest" 12 | ] 13 | } 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/json/platform-rule.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "id": 1, 4 | "priority": 1, 5 | "action": { 6 | "type": "block" 7 | }, 8 | "condition": { 9 | "urlFilter": "*platform-api.tver.jp*platform_token*", 10 | "resourceTypes": [ 11 | "xmlhttprequest" 12 | ] 13 | } 14 | } 15 | ] 16 | -------------------------------------------------------------------------------- /resources/crx/TVerRecAssistant/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "manifest_version": 3, 3 | "name": "TVerRec Assistant", 4 | "description": "Capture \"platform_uid\" , \"platform_token\" and \"member_sid\" to download your TVer favorites in TVerRec", 5 | "version": "0.1.0", 6 | "author": "dongaba", 7 | "homepage_url": "https://github.com/dongaba/TVerRec", 8 | "incognito": "split", 9 | "icons": { 10 | "16": "icon/TVerRec-Icon-16.png", 11 | "32": "icon/TVerRec-Icon-32.png", 12 | "48": "icon/TVerRec-Icon-48.png", 13 | "128": "icon/TVerRec-Icon-128.png" 14 | }, 15 | "permissions": [ 16 | "activeTab", 17 | "tabs", 18 | "scripting", 19 | "storage", 20 | "declarativeNetRequest", 21 | "declarativeNetRequestFeedback" 22 | ], 23 | "host_permissions": [ 24 | "*://tver.jp/*", 25 | "*://*.tver.jp/*" 26 | ], 27 | "declarative_net_request": { 28 | "rule_resources": [ 29 | { 30 | "id": "platform-rule", 31 | "enabled": true, 32 | "path": "json/platform-rule.json" 33 | }, 34 | { 35 | "id": "member-rule", 36 | "enabled": true, 37 | "path": "json/member-rule.json" 38 | } 39 | ] 40 | }, 41 | "background": { 42 | "service_worker": "js/background.js" 43 | }, 44 | "content_scripts": [ 45 | { 46 | "matches": [ 47 | "*://tver.jp/*", 48 | "*://*.tver.jp/*" 49 | ], 50 | "js": [ 51 | "js/tver.js" 52 | ] 53 | } 54 | ], 55 | "action": { 56 | "default_popup": "html/popup.html" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /resources/docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.10 2 | 3 | ENV POWERSHELL_TELEMETRY_OPTOUT=1 4 | 5 | LABEL org.opencontainers.image.title="TVerRec" \ 6 | org.opencontainers.image.source=https://github.com/dongaba/TVerRec \ 7 | org.opencontainers.image.authors="dongaba" \ 8 | org.opencontainers.image.licenses=MIT 9 | 10 | #必要ソフトのインストール 11 | RUN apt-get update \ 12 | && apt-get install --no-install-recommends -y \ 13 | curl \ 14 | git \ 15 | bash \ 16 | python3-minimal \ 17 | xz-utils \ 18 | wget \ 19 | apt-transport-https \ 20 | software-properties-common \ 21 | jq \ 22 | libssl-dev \ 23 | libunwind8 \ 24 | vim \ 25 | htop \ 26 | sudo \ 27 | tzdata \ 28 | net-tools \ 29 | python3-pycryptodome \ 30 | && apt-get upgrade -y \ 31 | && apt-get autoremove -y \ 32 | && apt-get clean -y \ 33 | && rm -rf /var/lib/apt/lists/* 34 | 35 | #Powershellのダウンロードと配置 36 | RUN /bin/bash -c ' \ 37 | arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/x64/ | sed s/amd64/x64/) && \ 38 | release=$(curl -sL https://api.github.com/repos/PowerShell/PowerShell/releases/latest) && \ 39 | package=$(echo $release | jq -r ".assets[].browser_download_url" | grep "linux-${arch}.tar.gz") && \ 40 | wget $package && \ 41 | mkdir -p /opt/microsoft/powershell && \ 42 | tar -xvf "./${package##*/}" -C /opt/microsoft/powershell && \ 43 | ln -s /opt/microsoft/powershell/pwsh /usr/bin/pwsh && \ 44 | chmod a+x /opt/microsoft/powershell/pwsh && \ 45 | rm -rf "./${package##*/}" \ 46 | ' 47 | 48 | #ディレクトリ準備 49 | RUN mkdir -p -m 777 \ 50 | /app \ 51 | /mnt/Temp \ 52 | /mnt/Work \ 53 | /mnt/Save 54 | 55 | #ユーザ切り替え 56 | RUN echo "ubuntu ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/tverrec 57 | USER ubuntu 58 | 59 | #TVerRecのインストール 60 | WORKDIR /app 61 | RUN git clone https://github.com/dongaba/TVerRec.git 62 | 63 | #コンテナ用修正 64 | WORKDIR /app/TVerRec 65 | RUN sed -i -e "s|'TVerRec'|'TVerRecContainer'|g" ./conf/system_setting.ps1 \ 66 | && sed -i -e "s|\$script:confDir 'keyword.conf'|\$script:containerDir 'keyword.conf'|g" ./src/functions/*.ps1 \ 67 | && sed -i -e "s|\$script:confDir 'ignore.conf'|\$script:containerDir 'ignore.conf'|g" ./src/functions/*.ps1 \ 68 | && sed -i -e "s|\$script:dbDir 'history.csv'|\$script:containerDir 'history.csv'|g" ./src/functions/*.ps1 \ 69 | && sed -i -e "s|\$script:listDir 'list.csv'|\$script:containerDir 'list.csv'|g" ./src/functions/*.ps1 \ 70 | && sed -i -e "s|\$script:confDir 'user_setting.ps1'|\$script:containerDir 'user_setting.ps1'|g" ./src/*.ps1 \ 71 | && sed -i -e "s|\$script:confDir 'user_setting.ps1'|\$script:containerDir 'user_setting.ps1'|g" ./src/*/*.ps1 \ 72 | && mkdir container-data \ 73 | && cp ./resources/sample/keyword.sample.conf ./container-data/keyword.conf \ 74 | && cp ./resources/sample/ignore.sample.conf ./container-data/ignore.conf \ 75 | && cp ./resources/sample/history.sample.csv ./container-data/history.csv \ 76 | && cp ./resources/sample/list.sample.csv ./container-data/list.csv \ 77 | && echo '$script:downloadBaseDir = '\''/mnt/Work'\''' >> ./container-data/user_setting.ps1 \ 78 | && echo '$script:downloadWorkDir = '\''/mnt/Temp'\''' >> ./container-data/user_setting.ps1 \ 79 | && echo '$script:saveBaseDir = '\''/mnt/Save'\''' >> ./container-data/user_setting.ps1 80 | 81 | RUN chmod a+x ./unix/*.sh 82 | 83 | ENV APP_TMP_DATA=/tmp 84 | 85 | WORKDIR /app/TVerRec/unix 86 | ENTRYPOINT ["/bin/bash", "start_tverrec.sh"] 87 | #CMD ["/bin/bash"] 88 | -------------------------------------------------------------------------------- /resources/docker/beta/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.10 2 | 3 | ENV POWERSHELL_TELEMETRY_OPTOUT=1 4 | 5 | LABEL org.opencontainers.image.title="TVerRec" \ 6 | org.opencontainers.image.source=https://github.com/dongaba/TVerRec \ 7 | org.opencontainers.image.authors="dongaba" \ 8 | org.opencontainers.image.licenses=MIT 9 | 10 | #必要ソフトのインストール 11 | RUN apt-get update \ 12 | && apt-get install --no-install-recommends -y \ 13 | curl \ 14 | git \ 15 | bash \ 16 | python3-minimal \ 17 | xz-utils \ 18 | wget \ 19 | apt-transport-https \ 20 | software-properties-common \ 21 | jq \ 22 | libssl-dev \ 23 | libunwind8 \ 24 | vim \ 25 | htop \ 26 | sudo \ 27 | tzdata \ 28 | net-tools \ 29 | python3-pycryptodome \ 30 | && apt-get upgrade -y \ 31 | && apt-get autoremove -y \ 32 | && apt-get clean -y \ 33 | && rm -rf /var/lib/apt/lists/* 34 | 35 | #Powershellのダウンロードと配置 36 | RUN /bin/bash -c ' \ 37 | arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/x64/ | sed s/amd64/x64/) && \ 38 | release=$(curl -sL https://api.github.com/repos/PowerShell/PowerShell/releases/latest) && \ 39 | package=$(echo $release | jq -r ".assets[].browser_download_url" | grep "linux-${arch}.tar.gz") && \ 40 | wget $package && \ 41 | mkdir -p /opt/microsoft/powershell && \ 42 | tar -xvf "./${package##*/}" -C /opt/microsoft/powershell && \ 43 | ln -s /opt/microsoft/powershell/pwsh /usr/bin/pwsh && \ 44 | chmod a+x /opt/microsoft/powershell/pwsh && \ 45 | rm -rf "./${package##*/}" \ 46 | ' 47 | 48 | #ディレクトリ準備 49 | RUN mkdir -p -m 777 \ 50 | /app \ 51 | /mnt/Temp \ 52 | /mnt/Work \ 53 | /mnt/Save 54 | 55 | #ユーザ切り替え 56 | RUN echo "ubuntu ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/tverrec 57 | USER ubuntu 58 | 59 | #TVerRecのインストール 60 | WORKDIR /app 61 | RUN git clone -b beta https://github.com/dongaba/TVerRec.git 62 | 63 | #コンテナ用修正 64 | WORKDIR /app/TVerRec 65 | RUN sed -i -e "s|'TVerRec'|'TVerRecContainer'|g" ./conf/system_setting.ps1 \ 66 | && sed -i -e "s|\$script:confDir 'keyword.conf'|\$script:containerDir 'keyword.conf'|g" ./src/functions/*.ps1 \ 67 | && sed -i -e "s|\$script:confDir 'ignore.conf'|\$script:containerDir 'ignore.conf'|g" ./src/functions/*.ps1 \ 68 | && sed -i -e "s|\$script:dbDir 'history.csv'|\$script:containerDir 'history.csv'|g" ./src/functions/*.ps1 \ 69 | && sed -i -e "s|\$script:listDir 'list.csv'|\$script:containerDir 'list.csv'|g" ./src/functions/*.ps1 \ 70 | && sed -i -e "s|\$script:confDir 'user_setting.ps1'|\$script:containerDir 'user_setting.ps1'|g" ./src/*.ps1 \ 71 | && sed -i -e "s|\$script:confDir 'user_setting.ps1'|\$script:containerDir 'user_setting.ps1'|g" ./src/*/*.ps1 \ 72 | && mkdir container-data \ 73 | && cp ./resources/sample/keyword.sample.conf ./container-data/keyword.conf \ 74 | && cp ./resources/sample/ignore.sample.conf ./container-data/ignore.conf \ 75 | && cp ./resources/sample/history.sample.csv ./container-data/history.csv \ 76 | && cp ./resources/sample/list.sample.csv ./container-data/list.csv \ 77 | && echo '$script:downloadBaseDir = '\''/mnt/Work'\''' >> ./container-data/user_setting.ps1 \ 78 | && echo '$script:downloadWorkDir = '\''/mnt/Temp'\''' >> ./container-data/user_setting.ps1 \ 79 | && echo '$script:saveBaseDir = '\''/mnt/Save'\''' >> ./container-data/user_setting.ps1 80 | 81 | RUN chmod a+x ./unix/*.sh 82 | 83 | ENV APP_TMP_DATA=/tmp 84 | 85 | WORKDIR /app/TVerRec/unix 86 | ENTRYPOINT ["/bin/bash", "start_tverrec.sh"] 87 | #CMD ["/bin/bash"] 88 | -------------------------------------------------------------------------------- /resources/docker/dev/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.10 2 | 3 | ENV POWERSHELL_TELEMETRY_OPTOUT=1 4 | 5 | LABEL org.opencontainers.image.title="TVerRec" \ 6 | org.opencontainers.image.source=https://github.com/dongaba/TVerRec \ 7 | org.opencontainers.image.authors="dongaba" \ 8 | org.opencontainers.image.licenses=MIT 9 | 10 | #必要ソフトのインストール 11 | RUN apt-get update \ 12 | && apt-get install --no-install-recommends -y \ 13 | curl \ 14 | git \ 15 | bash \ 16 | python3-minimal \ 17 | xz-utils \ 18 | wget \ 19 | apt-transport-https \ 20 | software-properties-common \ 21 | jq \ 22 | libssl-dev \ 23 | libunwind8 \ 24 | vim \ 25 | htop \ 26 | sudo \ 27 | tzdata \ 28 | net-tools \ 29 | python3-pycryptodome \ 30 | && apt-get upgrade -y \ 31 | && apt-get autoremove -y \ 32 | && apt-get clean -y \ 33 | && rm -rf /var/lib/apt/lists/* 34 | 35 | #Powershellのダウンロードと配置 36 | RUN /bin/bash -c ' \ 37 | arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/x64/ | sed s/amd64/x64/) && \ 38 | release=$(curl -sL https://api.github.com/repos/PowerShell/PowerShell/releases/latest) && \ 39 | package=$(echo $release | jq -r ".assets[].browser_download_url" | grep "linux-${arch}.tar.gz") && \ 40 | wget $package && \ 41 | mkdir -p /opt/microsoft/powershell && \ 42 | tar -xvf "./${package##*/}" -C /opt/microsoft/powershell && \ 43 | ln -s /opt/microsoft/powershell/pwsh /usr/bin/pwsh && \ 44 | chmod a+x /opt/microsoft/powershell/pwsh && \ 45 | rm -rf "./${package##*/}" \ 46 | ' 47 | 48 | #ディレクトリ準備 49 | RUN mkdir -p -m 777 \ 50 | /app \ 51 | /mnt/Temp \ 52 | /mnt/Work \ 53 | /mnt/Save 54 | 55 | #ユーザ切り替え 56 | RUN echo "ubuntu ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers.d/tverrec 57 | USER ubuntu 58 | 59 | #TVerRecのインストール 60 | WORKDIR /app 61 | RUN git clone -b dev https://github.com/dongaba/TVerRec.git 62 | 63 | #コンテナ用修正 64 | WORKDIR /app/TVerRec 65 | RUN sed -i -e "s|'TVerRec'|'TVerRecContainer'|g" ./conf/system_setting.ps1 \ 66 | && sed -i -e "s|\$script:confDir 'keyword.conf'|\$script:containerDir 'keyword.conf'|g" ./src/functions/*.ps1 \ 67 | && sed -i -e "s|\$script:confDir 'ignore.conf'|\$script:containerDir 'ignore.conf'|g" ./src/functions/*.ps1 \ 68 | && sed -i -e "s|\$script:dbDir 'history.csv'|\$script:containerDir 'history.csv'|g" ./src/functions/*.ps1 \ 69 | && sed -i -e "s|\$script:listDir 'list.csv'|\$script:containerDir 'list.csv'|g" ./src/functions/*.ps1 \ 70 | && sed -i -e "s|\$script:confDir 'user_setting.ps1'|\$script:containerDir 'user_setting.ps1'|g" ./src/*.ps1 \ 71 | && sed -i -e "s|\$script:confDir 'user_setting.ps1'|\$script:containerDir 'user_setting.ps1'|g" ./src/*/*.ps1 \ 72 | && mkdir container-data \ 73 | && cp ./resources/sample/keyword.sample.conf ./container-data/keyword.conf \ 74 | && cp ./resources/sample/ignore.sample.conf ./container-data/ignore.conf \ 75 | && cp ./resources/sample/history.sample.csv ./container-data/history.csv \ 76 | && cp ./resources/sample/list.sample.csv ./container-data/list.csv \ 77 | && echo '$script:downloadBaseDir = '\''/mnt/Work'\''' >> ./container-data/user_setting.ps1 \ 78 | && echo '$script:downloadWorkDir = '\''/mnt/Temp'\''' >> ./container-data/user_setting.ps1 \ 79 | && echo '$script:saveBaseDir = '\''/mnt/Save'\''' >> ./container-data/user_setting.ps1 80 | 81 | RUN chmod a+x ./unix/*.sh 82 | 83 | ENV APP_TMP_DATA=/tmp 84 | 85 | WORKDIR /app/TVerRec/unix 86 | ENTRYPOINT ["/bin/bash", "start_tverrec.sh"] 87 | #CMD ["/bin/bash"] 88 | -------------------------------------------------------------------------------- /resources/docker/docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.8" 2 | 3 | services: 4 | tverrec: 5 | container_name: TVerRec-loop 6 | image: dongaba/tverrec:latest 7 | hostname: "tverrec" 8 | restart: unless-stopped 9 | tty: true 10 | stdin_open: true 11 | 12 | build: 13 | context: . 14 | dockerfile: ./Dockerfile 15 | 16 | environment: 17 | POWERSHELL_TELEMETRY_OPTOUT: 1 18 | 19 | tmpfs: 20 | - /mnt/Temp 21 | 22 | volumes: 23 | - temp:/mnt/Temp 24 | - work:/mnt/Work 25 | - save:/mnt/Save 26 | - container-data:/app/TVerRec/container-data 27 | 28 | volumes: 29 | temp: 30 | work: 31 | save: 32 | container-data: 33 | -------------------------------------------------------------------------------- /resources/img/TVerRec-Icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/img/TVerRec-Icon.png -------------------------------------------------------------------------------- /resources/img/TVerRec-Logo-Small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/img/TVerRec-Logo-Small.png -------------------------------------------------------------------------------- /resources/img/TVerRec-Logo-Social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/img/TVerRec-Logo-Social.png -------------------------------------------------------------------------------- /resources/img/TVerRec-Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/img/TVerRec-Logo.png -------------------------------------------------------------------------------- /resources/img/TVerRec-Toast-Large.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/img/TVerRec-Toast-Large.png -------------------------------------------------------------------------------- /resources/img/TVerRec-Toast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/img/TVerRec-Toast.png -------------------------------------------------------------------------------- /resources/lib/win/core/Microsoft.Toolkit.Uwp.Notifications.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/lib/win/core/Microsoft.Toolkit.Uwp.Notifications.dll -------------------------------------------------------------------------------- /resources/lib/win/core/Microsoft.Windows.SDK.NET.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/lib/win/core/Microsoft.Windows.SDK.NET.dll -------------------------------------------------------------------------------- /resources/lib/win/core/README.md: -------------------------------------------------------------------------------- 1 | Packages/Microsoft.Windows.SDK.NET.Ref.10.0.22000.25/lib 2 | Microsoft.Toolkit.Uwp.Notifications.7.1.2/lib/net5.0-windows10.0.17763 3 | -------------------------------------------------------------------------------- /resources/lib/win/core/WinRT.Runtime.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/lib/win/core/WinRT.Runtime.dll -------------------------------------------------------------------------------- /resources/lock/history.lock: -------------------------------------------------------------------------------- 1 | Do not delete, this is a file manages the lock between multiple instances. 2 | このファイルは複数のインスタンス起動時のロックを管理するファイルなので、削除しないでください。 3 | -------------------------------------------------------------------------------- /resources/lock/ignore.lock: -------------------------------------------------------------------------------- 1 | Do not delete, this is a file manages the lock between multiple instances. 2 | このファイルは複数のインスタンス起動時のロックを管理するファイルなので、削除しないでください。 3 | -------------------------------------------------------------------------------- /resources/lock/list.lock: -------------------------------------------------------------------------------- 1 | Do not delete, this is a file manages the lock between multiple instances. 2 | このファイルは複数のインスタンス起動時のロックを管理するファイルなので、削除しないでください。 3 | -------------------------------------------------------------------------------- /resources/sample/history.sample.csv: -------------------------------------------------------------------------------- 1 | "videoPage","videoSeriesPage","genre","series","season","title","media","broadcastDate","downloadDate","videoDir","videoName","videoPath","videoValidated" 2 | -------------------------------------------------------------------------------- /resources/sample/ignore.sample.conf: -------------------------------------------------------------------------------- 1 | ;;━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2 | ;;ダウンロード対象外番組 3 | ;;━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | ;;---------------------------------------------------------------------- 5 | ;; 「;」でコメントアウト 6 | ;; ジャンル指定や放送局指定でダウンロードする際に、 7 | ;; 明らかにダウンロード不要な番組があれば番組名をここに列記する。 8 | ;; tverrecがダウンロードを試みた際に、番組名がこのリストと一致した際は 9 | ;; ダウンロード履歴に追加した上で、ダウンロードをスキップする。 10 | ;; ダウンロード履歴に追加するのは次回以降に再チェックしないようにするため。 11 | ;;---------------------------------------------------------------------- 12 | -------------------------------------------------------------------------------- /resources/sample/keyword.sample.conf: -------------------------------------------------------------------------------- 1 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 2 | #ダウンロード対象キーワード 3 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 4 | #---------------------------------------------------------------------- 5 | # 「#」でコメントアウト 6 | #---------------------------------------------------------------------- 7 | 8 | #---------------------------------------------------------------------- 9 | #マイページ 10 | # TVerのホームページ登録したお気に入り等 11 | # ※別途「$script:myPlatformUID」と「$script:myPlatformToken」を設定する必要あり 12 | # ※「platform_uid」と「platform_token」は同梱のChrome拡張機能「TVerRec Assistant」を使って取得可能 13 | # ※本機能を利用することで登録済みのTVerIDと紐づくと思われるのご要注意を 14 | #---------------------------------------------------------------------- 15 | #mypage/fav #マイページ > お気に入り (こちらの方が「あなたのお気に入り」より高速だが、どのように抽出されているか不明。多少多かったり少なかったりする) 16 | #mypage/later #マイページ > あとでみる 17 | #mypage/resume #マイページ > 続きから再生 18 | #mypage/favorite #マイページ > あなたのお気に入り 19 | 20 | #---------------------------------------------------------------------- 21 | #番組ID 22 | # TVerで番組ページを検索し、「series/srxxxxxxxx」を指定 23 | #---------------------------------------------------------------------- 24 | #series/srookmi9gb #かまいたちの知らんけど 25 | #series/sruxf2us3b #金田一少年の事件簿 26 | 27 | #---------------------------------------------------------------------- 28 | #タレントID 29 | # TVerでタレントページを検索し、「talents/txxxxxx」を指定 30 | #---------------------------------------------------------------------- 31 | #talents/t0128fe #ムロツヨシ 32 | #talents/t00eae3 #本田翼 33 | #talents/t0223f6 #池上彰 34 | 35 | #---------------------------------------------------------------------- 36 | #ジャンル 37 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 38 | #---------------------------------------------------------------------- 39 | #tag/animal #動物 40 | #tag/anime #アニメ 41 | #tag/baseball #野球 42 | #tag/business #ビジネス 43 | #tag/comedy #コメディ 44 | #tag/culture #教養 45 | #tag/detective #刑事 46 | #tag/documentary #ドキュメンタリー 47 | #tag/digest #ダイジェスト 48 | #tag/drama #ドラマ 49 | #tag/esports #eSports・ゲーム 50 | #tag/family #ファミリー 51 | #tag/fantasy #ファンタジー・SF 52 | #tag/fighting #格闘技 53 | #tag/fishing #釣り 54 | #tag/golf #ゴルフ 55 | #tag/gourmet #グルメ 56 | #tag/health #健康 57 | #tag/history #時代劇 58 | #tag/horror #ホラー 59 | #tag/human #ヒューマン 60 | #tag/kids #キッズ 61 | #tag/living #生活情報 62 | #tag/medical #医療 63 | #tag/music #音楽 64 | #tag/mystery #ミステリー 65 | #tag/news #報道 66 | #tag/news_documentary #報道・ドキュメンタリー 67 | #tag/orglplan #オリジナル企画 68 | #tag/original #オリジナル 69 | #tag/other #その他 70 | #tag/owarai #お笑い・漫才・コント 71 | #tag/quiz #クイズ 72 | #tag/romance #恋愛 73 | #tag/sauna #サウナ 74 | #tag/school #学園 75 | #tag/short #短尺(10分以内) 76 | #tag/soccer #サッカー 77 | #tag/sports #スポーツ 78 | #tag/sports_subgen #スポーツ 79 | #tag/suspence #サスペンス 80 | #tag/talk #トーク・スタジオバラエティ 81 | #tag/teen #青春 82 | #tag/texttrackon #字幕あり 83 | #tag/trailer #予告 84 | #tag/trip #旅行・街ブラ 85 | #tag/variety #バラエティ 86 | #tag/vtr #VTR・ロケ番組 87 | 88 | #---------------------------------------------------------------------- 89 | #地域限定 90 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 91 | #---------------------------------------------------------------------- 92 | #tag/zone1 #関東エリアのご当地番組 93 | #tag/zone2 #関西エリアのご当地番組 94 | #tag/zone3 #中部エリアのご当地番組 95 | #tag/zone4 #北海道・東北エリアのご当地番組 96 | #tag/zone5 #中国・四国エリアのご当地番組 97 | #tag/zone6 #九州・沖縄エリアのご当地番組 98 | 99 | #---------------------------------------------------------------------- 100 | #放送局 101 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 102 | #---------------------------------------------------------------------- 103 | #tag/abc #ABCテレビ 104 | #tag/cx #フジテレビ 105 | #tag/ex #テレビ朝日 106 | #tag/exnetwork #テレビ朝日系 107 | #tag/fns #フジテレビ系 108 | #tag/jnn #TBS系 109 | #tag/ktv #関西テレビ 110 | #tag/mbs #MBS毎日放送 111 | #tag/nhk #NHK 112 | #tag/nhknet #NHK 113 | #tag/nns #日本テレビ系 114 | #tag/ntv #日テレ 115 | #tag/tbs #TBS 116 | #tag/tvo #テレビ大阪 117 | #tag/tx #テレビ東京 118 | #tag/txn #テレビ東京系 119 | #tag/ytv #読売テレビ 120 | #tag/independence #独立局 121 | #tag/bs8 #ビーエスフジ 122 | #tag/bs11 #BS11イレブン 123 | #tag/bs12 #BS12トゥエルビ 124 | 125 | #---------------------------------------------------------------------- 126 | #曜日 127 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 128 | #---------------------------------------------------------------------- 129 | #tag/mon #月 130 | #tag/tue #火 131 | #tag/wed #水 132 | #tag/thu #木 133 | #tag/fri #金 134 | #tag/sat #土 135 | #tag/sun #日 136 | 137 | #---------------------------------------------------------------------- 138 | #その他 139 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 140 | #---------------------------------------------------------------------- 141 | #tag/texttrackon #字幕あり 142 | #tag/short #短尺(10分以内) 143 | #tag/trailer #予告 144 | 145 | #---------------------------------------------------------------------- 146 | #新着 147 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 148 | #---------------------------------------------------------------------- 149 | #new/all #新着すべて 150 | #new/drama #新着ドラマ 151 | #new/variety #新着バラエティ 152 | #new/anime #新着アニメ・ヒーロー 153 | #new/news_documentary #新着報道・ドキュメンタリー 154 | #new/sports #新着スポーツ 155 | #new/other #新着その他 156 | 157 | #---------------------------------------------------------------------- 158 | #まもなく配信終了 159 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 160 | #---------------------------------------------------------------------- 161 | #end/all #まもなく配信終了すべて 162 | #end/drama #まもなく配信終了ドラマ 163 | #end/variety #まもなく配信終了バラエティ 164 | #end/anime #まもなく配信終了アニメ・ヒーロー 165 | #end/news_documentary #まもなく配信終了報道・ドキュメンタリー 166 | #end/sports #まもなく配信終了スポーツ 167 | #end/other #まもなく配信終了その他 168 | 169 | #---------------------------------------------------------------------- 170 | #ランキング 171 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 172 | #---------------------------------------------------------------------- 173 | #ranking/all #総合ランキング 174 | #ranking/drama #ドラマランキング 175 | #ranking/variety #バラエティランキング 176 | #ranking/anime #アニメ・ヒーローランキング 177 | #ranking/news_documentary #報道・ドキュメンタリーランキング 178 | #ranking/sports #スポーツランキング 179 | #ranking/other #その他ランキング 180 | 181 | #---------------------------------------------------------------------- 182 | #トップページ 183 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 184 | #---------------------------------------------------------------------- 185 | #toppage #トップページに表示される番組 186 | 187 | #---------------------------------------------------------------------- 188 | #サイトマップ 189 | # 不要な行は行頭に「#」をつけてコメントアウトするか削除する 190 | #---------------------------------------------------------------------- 191 | #sitemap #配信中全番組 192 | 193 | #---------------------------------------------------------------------- 194 | #フリーワード検索 195 | # キーワード指定(部分一致) 196 | #---------------------------------------------------------------------- 197 | #スペシャル 198 | #みどころ 199 | -------------------------------------------------------------------------------- /resources/sample/list.sample.csv: -------------------------------------------------------------------------------- 1 | episodeID,episodePageURL,episodeNo,episodeName,seriesID,seriesPageURL,seriesName,seasonID,seasonName,media,provider,broadcastDate,endTime,keyword,ignoreWord,descriptionText 2 | -------------------------------------------------------------------------------- /resources/wsb/TVerRec.wsb: -------------------------------------------------------------------------------- 1 | 2 | 2048 3 | Enable 4 | Default 5 | Default 6 | 7 | 8 | ..\..\ 9 | C:\Users\WDAGUtilityAccount\Desktop\TVerRec 10 | 11 | 12 | 13 | C:\Users\WDAGUtilityAccount\Desktop\TVerRec\resources\wsb\setup\setup.cmd 14 | 15 | 16 | -------------------------------------------------------------------------------- /resources/wsb/setup/PowerShellインストール.cmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/wsb/setup/PowerShellインストール.cmd -------------------------------------------------------------------------------- /resources/wsb/setup/setup.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | netsh int tcp set global rsc=disabled 4 | 5 | powershell Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser -Force 6 | 7 | rem Download and Install WinGet & some more packages 8 | powershell "C:\users\WDAGUtilityAccount\Desktop\TVerRec\resources\wsb\setup\setup.ps1" 9 | -------------------------------------------------------------------------------- /resources/wsb/setup/setup.ps1: -------------------------------------------------------------------------------- 1 | Write-Output 'ファイアウォールを無効化します ...' 2 | Set-NetFirewallProfile -Enabled False 3 | 4 | # 日本語化するためのショートカットをデスクトップに配置 5 | $WsShell = New-Object -ComObject WScript.Shell 6 | $Shortcut = $WsShell.CreateShortcut('C:\Users\WDAGUtilityAccount\Desktop\日本語化.lnk') 7 | $Shortcut.TargetPath = 'C:\Users\WDAGUtilityAccount\Desktop\TVerRec\resources\wsb\setup\日本語化.cmd' 8 | $Shortcut.Save() 9 | 10 | # PowerShellインストール用のショートカットをデスクトップに配置 11 | $WsShell = New-Object -ComObject WScript.Shell 12 | $Shortcut = $WsShell.CreateShortcut('C:\Users\WDAGUtilityAccount\Desktop\PowerShellインストール.lnk') 13 | $Shortcut.TargetPath = 'C:\Users\WDAGUtilityAccount\Desktop\TVerRec\resources\wsb\setup\PowerShellインストール.cmd' 14 | $Shortcut.Save() 15 | -------------------------------------------------------------------------------- /resources/wsb/setup/日本語化.cmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dongaba/TVerRec/03988e22cd7631cbc2ec4e8656cdb51c2f74bd94/resources/wsb/setup/日本語化.cmd -------------------------------------------------------------------------------- /src/debug_console.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # TVerRecデバッグコンソールスクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecのデバッグ用対話型コンソール環境を提供するスクリプト 9 | 10 | .DESCRIPTION 11 | TVerRecの開発やトラブルシューティングのためのデバッグ環境を提供します。 12 | 以下の機能を提供します: 13 | 1. 詳細なログ出力の有効化 14 | 2. 現在の設定内容の表示 15 | 3. IPアドレス情報の表示 16 | 4. 全変数の表示 17 | 5. 対話型コマンド実行環境 18 | 19 | .PARAMETER guiMode 20 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 21 | - 指定なし: 通常モードで実行 22 | - 'gui': GUIモードで実行 23 | - その他の値: 通常モードで実行 24 | 25 | .NOTES 26 | 前提条件: 27 | - Windows、Linux、またはmacOS環境で実行する必要があります 28 | - PowerShell 7.0以上を推奨します 29 | - TVerRecの設定ファイルが正しく設定されている必要があります 30 | - 十分なディスク容量が必要です 31 | - インターネット接続が必要です 32 | - TVerのアカウントが必要な場合があります 33 | - 開発者またはトラブルシューティング担当者向けのスクリプトです 34 | 35 | デバッグ環境の特徴: 36 | 1. ログレベルの設定 37 | - エラー時中断 (ErrorActionPreference = 'Stop') 38 | - 警告メッセージ表示 (WarningPreference = 'Continue') 39 | - 詳細メッセージ表示 (VerbosePreference = 'Continue') 40 | - デバッグメッセージ表示 (DebugPreference = 'Continue') 41 | - 情報メッセージ表示 (InformationPreference = 'Continue') 42 | 43 | 2. 表示される情報 44 | - 現在の設定内容 45 | - IPアドレス関連情報 46 | - スクリプト内の全変数 47 | - コマンド使用方法のガイド 48 | 49 | 3. 利用可能な機能 50 | - 対話型コマンド実行 51 | - 設定値の確認 52 | - 環境変数の確認 53 | - 動画ダウンロードのテスト 54 | 55 | .EXAMPLE 56 | # 通常モードで実行 57 | .\debug_console.ps1 58 | 59 | # GUIモードで実行 60 | .\debug_console.ps1 gui 61 | 62 | .OUTPUTS 63 | System.Void 64 | このスクリプトは以下の出力を行います: 65 | - コンソールへのデバッグ情報の表示 66 | - トースト通知による進捗状況の表示 67 | - エラー発生時のエラーメッセージ 68 | - デバッグコマンドの実行結果 69 | - 環境情報の詳細レポート 70 | #> 71 | 72 | Set-StrictMode -Version Latest 73 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 74 | 75 | $ErrorActionPreference = 'Stop' #2エラー時中断 76 | $WarningPreference = 'Continue' #3警告メッセージ 77 | $VerbosePreference = 'Continue' #4詳細メッセージ 78 | $DebugPreference = 'Continue' #5デバッグメッセージ 79 | $InformationPreference = 'Continue' #6情報メッセージ 80 | 81 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 82 | # 環境設定 83 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 84 | try { 85 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 86 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 87 | Set-Location $script:scriptRoot 88 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 89 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 90 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 91 | 92 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 93 | # メイン処理 94 | Invoke-RequiredFileCheck 95 | Suspend-Process 96 | Get-Token 97 | 98 | # GUI起動を判定 99 | if (!$script:guiMode) { $script:guiMode = $false } 100 | 101 | # デバッグモードを設定 102 | $script:debugMode = $true 103 | $ErrorActionPreference = 'Stop' #2エラー時中断 104 | $WarningPreference = 'Continue' #3警告メッセージ 105 | $VerbosePreference = 'Continue' #4詳細メッセージ 106 | $DebugPreference = 'Continue' #5デバッグメッセージ 107 | $InformationPreference = 'Continue' #6情報メッセージ 108 | 109 | Start-Sleep -Seconds 1 110 | 111 | # 設定内容取得 112 | Write-Output '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 設定内容 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' 113 | Get-Setting | Format-Table -HideTableHeaders 114 | 115 | # IPアドレス関連 116 | Write-Output '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ IPアドレス ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' 117 | $script:clientEnvs.GetEnumerator() | Format-Table -HideTableHeaders 118 | 119 | # 全変数 120 | Write-Output '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 変数 ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' 121 | Get-Variable | Format-Table -HideTableHeaders 122 | 123 | # コマンド使用方法 124 | Write-Output '' 125 | Write-Output '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' 126 | Write-Output '以下のようなコマンドが実行できます。' 127 | Write-Output "  - Invoke-VideoDownload -episodeID 'ep12345678'" 128 | Write-Output "  - Get-VideoInfo -episodeID 'ep12345678'" 129 | Write-Output "  - Get-VideoLinksFromKeyword -keyword 'キーワード'" 130 | Write-Output '    キーワードは以下の形式で指定できます:' 131 | Write-Output '      - episodes/{id}: 特定のエピソード' 132 | Write-Output '      - series/{id}: シリーズ' 133 | Write-Output '      - talents/{id}: タレント' 134 | Write-Output '      - tag/{id}: タグ' 135 | Write-Output '      - ranking/{id}: ランキング' 136 | Write-Output '      - new/{id}: 新着' 137 | Write-Output '      - end/{id}: 終了間近' 138 | Write-Output '      - mypage/{page}: マイページ' 139 | Write-Output '      - toppage: トップページ' 140 | Write-Output '      - sitemap: サイトマップ' 141 | Write-Output '━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━' 142 | Write-Output '' 143 | -------------------------------------------------------------------------------- /src/delete_trash.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 不要ファイル削除処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecの不要ファイルとディレクトリを削除するスクリプト 9 | 10 | .DESCRIPTION 11 | ダウンロード処理で生成された不要ファイルやディレクトリを削除します。 12 | 以下の処理を順番に実行します: 13 | 1. 中断されたダウンロードで生成された一時ファイルの削除 14 | 2. ダウンロード対象外の番組の削除 15 | 3. 空ディレクトリの削除 16 | 17 | .PARAMETER guiMode 18 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 19 | - 指定なし: 通常モードで実行 20 | - 'gui': GUIモードで実行 21 | - その他の値: 通常モードで実行 22 | 23 | .NOTES 24 | 前提条件: 25 | - Windows、Linux、またはmacOS環境で実行する必要があります 26 | - PowerShell 7.0以上を推奨します 27 | - TVerRecの設定ファイルが正しく設定されている必要があります 28 | - 十分なディスク容量が必要です 29 | - インターネット接続が必要です 30 | - TVerのアカウントが必要な場合があります 31 | 32 | 削除対象: 33 | 1. 一時ファイル 34 | - ログファイル(半日以上前のもの) 35 | - ダウンロード中断ファイル(*.ytdl, *.part*) 36 | - サムネイル画像(*.jpg, *.webp) 37 | - 字幕ファイル(*.srt, *.vtt) 38 | - その他の一時ファイル 39 | 2. ダウンロード対象外番組 40 | - ignore.confに記載された番組 41 | 3. 空ディレクトリ 42 | - 隠しファイルのみのディレクトリを含む 43 | 44 | 処理の流れ: 45 | 1. 一時ファイルの削除 46 | 1.1 ログディレクトリのクリーンアップ 47 | 1.2 作業ディレクトリのクリーンアップ 48 | 1.3 ダウンロードディレクトリのクリーンアップ 49 | 1.4 保存先ディレクトリのクリーンアップ(設定時) 50 | 2. 対象外番組の削除 51 | 2.1 ignore.confの読み込み 52 | 2.2 対象ディレクトリの特定 53 | 2.3 並列処理による削除 54 | 3. 空ディレクトリの削除 55 | 3.1 空ディレクトリの特定 56 | 3.2 並列処理による削除 57 | 58 | .EXAMPLE 59 | # 通常モードで実行 60 | .\delete_trash.ps1 61 | 62 | # GUIモードで実行 63 | .\delete_trash.ps1 gui 64 | 65 | .OUTPUTS 66 | System.Void 67 | このスクリプトは以下の出力を行います: 68 | - コンソールへの進捗状況の表示 69 | - トースト通知による進捗状況の表示 70 | - エラー発生時のエラーメッセージ 71 | - 処理完了時のサマリー情報 72 | - 削除されたファイルとディレクトリの一覧 73 | #> 74 | 75 | Set-StrictMode -Version Latest 76 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 77 | 78 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79 | # 環境設定 80 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 81 | try { 82 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 83 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 84 | Set-Location $script:scriptRoot 85 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 86 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 87 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 88 | 89 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 90 | # メイン処理 91 | Invoke-RequiredFileCheck 92 | 93 | #====================================================================== 94 | # 1/3ダウンロードが中断した際にできたゴミファイルは削除 95 | Write-Output ('') 96 | Write-Output ($script:msg.LongBoldBorder) 97 | Write-Output ($script:msg.DeleteTrashFiles) 98 | 99 | $toastShowParams = @{ 100 | Text1 = $script:msg.DeleteTrashes 101 | Text2 = $script:msg.DeleteTrashesStep1 102 | WorkDetail = '' 103 | Tag = $script:appName 104 | Silent = $false 105 | Group = 'Delete' 106 | } 107 | Show-ProgressToast @toastShowParams 108 | 109 | if ($script:cleanupDownloadBaseDir -and $script:cleanupSaveBaseDir ) { $totalCleanupSteps = 4 } 110 | elseif ($script:cleanupDownloadBaseDir -or $script:cleanupSaveBaseDir ) { $totalCleanupSteps = 3 } 111 | else { $totalCleanupSteps = 2 } 112 | 113 | # 1日以上前のログファイル・ロックファイルを削除 114 | $toastUpdateParams = @{ 115 | Title = $script:logDir 116 | Rate = [Float]( 1 / $totalCleanupSteps ) 117 | LeftText = '' 118 | RightText = '' 119 | Tag = $script:appName 120 | Group = 'Delete' 121 | } 122 | Update-ProgressToast @toastUpdateParams 123 | $getChildItemParams = @{ 124 | Path = $script:logDir 125 | Include = @('ffmpeg_error_*.log', 'ffmpeg_err_*.log', 'ytdl_out_*.log', 'ytdl_err_*.log') 126 | File = $true 127 | Recurse = $true 128 | ErrorAction = 'SilentlyContinue' 129 | } 130 | Get-ChildItem @getChildItemParams -ErrorAction SilentlyContinue | Remove-File -DelPeriod 1 131 | 132 | # 作業ディレクトリ 133 | $toastUpdateParams.Title = $script:downloadWorkDir 134 | $toastUpdateParams.Rate = [Float]( 2 / $totalCleanupSteps ) 135 | Update-ProgressToast @toastUpdateParams 136 | # リネームに失敗したファイルを削除 137 | Write-Output ($script:msg.DeleteFilesFailedToDownload) 138 | Remove-UnMovedTempFile 139 | $workDirParams = @{ 140 | Path = $script:downloadWorkDir 141 | Include = @('*.ytdl', '*.jpg', '*.webp', '*.srt', '*.vtt', '*.part*', '*.m4a-Frag*', 142 | '*.live_chat.json', '*.temp.mp4', '*.temp.ts', '*.mp4-Frag*', '*.ts-Frag*') 143 | File = $true 144 | Recurse = $true 145 | } 146 | Get-ChildItem @workDirParams -ErrorAction SilentlyContinue | Remove-File -DelPeriod 0 147 | 148 | # ダウンロード先 149 | $toastUpdateParams.Title = $script:downloadBaseDir 150 | $toastUpdateParams.Rate = [Float]( 3 / $totalCleanupSteps ) 151 | Update-ProgressToast @toastUpdateParams 152 | # リネームに失敗したファイルを削除 153 | Write-Output ($script:msg.DeleteFilesFailedToRename) 154 | Remove-UnRenamedTempFile 155 | if ($script:cleanupDownloadBaseDir) { 156 | $downloadDirParams = @{ 157 | Path = $script:downloadBaseDir 158 | Include = @('*.ytdl', '*.jpg', '*.webp', '*.srt', '*.vtt', '*.part*', '*.m4a-Frag*', 159 | '*.live_chat.json', '*.temp.mp4', '*.temp.ts', '*.mp4-Frag*', '*.ts-Frag*') 160 | File = $true 161 | Recurse = $true 162 | ErrorAction = 'SilentlyContinue' 163 | } 164 | Get-ChildItem @downloadDirParams -ErrorAction SilentlyContinue | Remove-File -DelPeriod 0 165 | } 166 | 167 | # 移動先 168 | $toastUpdateParams.Title = $script:saveBaseDir 169 | $toastUpdateParams.Rate = 1 170 | Update-ProgressToast @toastUpdateParams 171 | if ($script:cleanupSaveBaseDir -and $script:saveBaseDir) { 172 | $script:saveDirArray = $script:saveBaseDirArray.ToArray() 173 | $saveDirArray | ForEach-Object { 174 | $saveDir = $_ 175 | $saveDirParams = @{ 176 | Path = $saveDir 177 | Include = @('*.ytdl', '*.jpg', '*.webp', '*.srt', '*.vtt', '*.part*', '*.m4a-Frag*', 178 | '*.live_chat.json', '*.temp.mp4', '*.temp.ts', '*.mp4-Frag*', '*.ts-Frag*') 179 | File = $true 180 | Recurse = $true 181 | } 182 | Get-ChildItem @saveDirParams | Remove-File -DelPeriod 0 183 | } 184 | } 185 | 186 | #====================================================================== 187 | # 2/3ダウンロード対象外に入っている番組は削除 188 | Write-Output ('') 189 | Write-Output ($script:msg.MediumBoldBorder) 190 | Write-Output ($script:msg.DeleteExcludeFiles) 191 | 192 | $toastShowParams.Text2 = $script:msg.DeleteTrashesStep2 193 | Show-ProgressToast @toastShowParams 194 | 195 | # 個別ダウンロードが強制モードの場合にはスキップ 196 | if ($script:forceSingleDownload) { 197 | Write-Warning ($script:msg.DisclaimerForForceDownloadFlag) 198 | } else { 199 | # ダウンロード先にディレクトリがない場合はスキップ 200 | $workDirEntities = @(Get-ChildItem -LiteralPath $script:downloadBaseDir) 201 | if ($workDirEntities.Count -eq 0) { return } 202 | 203 | # ダウンロード対象外番組が登録されていない場合はスキップ 204 | $ignoreTitles = @(Read-IgnoreList) 205 | $ignoreDirs = New-Object System.Collections.Generic.List[Object] 206 | if ($ignoreTitles.Count -eq 0) { return } 207 | 208 | # 削除対象の特定 209 | foreach ($ignoreTitleRaw in $ignoreTitles) { 210 | $ignoreTitle = $ignoreTitleRaw.Normalize([Text.NormalizationForm]::FormC) 211 | $filteredDirs = $workDirEntities.Where({ $_.Name.Normalize([Text.NormalizationForm]::FormC) -like "*${ignoreTitle}*" }) 212 | foreach ($filteredDir in $filteredDirs) { 213 | $ignoreDirs.Add($filteredDir) 214 | Update-IgnoreList $ignoreTitle 215 | } 216 | } 217 | 218 | #---------------------------------------------------------------------- 219 | if ($ignoreDirs.Count -ne 0) { 220 | if ($script:enableMultithread) { 221 | Write-Debug ('Multithread Processing Enabled') 222 | # 並列化が有効の場合は並列化 223 | $ignoreDirs | ForEach-Object -Parallel { 224 | $ignoreNum = ([Array]::IndexOf($using:ignoreDirs, $_)) + 1 225 | $ignoreTotal = $using:ignoreDirs.Count 226 | Write-Output (' {0}/{1} - {2}' -f $ignoreNum, $ignoreTotal, $_.Name) 227 | try { Remove-Item -LiteralPath $_ -Recurse -Force | Out-Null } 228 | catch { Write-Warning ($script:msg.FileCannotBeDeleted) } 229 | } -ThrottleLimit $script:multithreadNum 230 | } else { 231 | # 並列化が無効の場合は従来型処理 232 | $ignoreNum = 0 233 | $ignoreTotal = $ignoreDirs.Count 234 | $totalStartTime = Get-Date 235 | foreach ($ignoreDir in $ignoreDirs) { 236 | $ignoreNum++ 237 | # 処理時間の推計 238 | $secElapsed = (Get-Date) - $totalStartTime 239 | $secRemaining = -1 240 | if ($ignoreNum -ne 1) { 241 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $ignoreNum) * ($ignoreTotal - $ignoreNum)) 242 | $minRemaining = ($script:msg.MinRemaining -f ([Int][Math]::Ceiling($secRemaining / 60))) 243 | $progressRate = [Float]($ignoreNum / $ignoreTotal) 244 | } else { $minRemaining = '' ; $progressRate = 0 } 245 | 246 | $toastUpdateParams.Title = $ignoreDir.Name 247 | $toastUpdateParams.Rate = $progressRate 248 | $toastUpdateParams.LeftText = ('{0}/{1}' -f $ignoreNum, $ignoreTotal) 249 | $toastUpdateParams.RightText = $minRemaining 250 | Update-ProgressToast @toastUpdateParams 251 | 252 | Write-Output (' {0}/{1} - {2}' -f $ignoreNum, $ignoreTotal, $ignoreDir.Name) 253 | try { Remove-Item -LiteralPath $ignoreDir -Recurse -Force | Out-Null } 254 | catch { Write-Warning ($script:msg.FileCannotBeDeleted) } 255 | } 256 | } 257 | } 258 | } 259 | 260 | #---------------------------------------------------------------------- 261 | 262 | #====================================================================== 263 | # 3/3空ディレクトリと隠しファイルしか入っていないディレクトリを一気に削除 264 | Write-Output ('') 265 | Write-Output ($script:msg.MediumBoldBorder) 266 | Write-Output ($script:msg.DeleteEmptyDirs) 267 | 268 | $toastShowParams.Text2 = $script:msg.DeleteTrashesStep3 269 | Show-ProgressToast @toastShowParams 270 | 271 | if ($script:emptyDownloadBaseDir) { 272 | try { 273 | $emptyDirs = New-Object System.Collections.Generic.List[String] 274 | foreach ($dir in (Get-ChildItem -Path $script:downloadBaseDir -Directory -Recurse -ErrorAction SilentlyContinue)) { 275 | $files = $dir.GetFileSystemInfos() 276 | $visibleFiles = @($files | Where-Object { -not $_.Attributes.HasFlag([System.IO.FileAttributes]::Hidden) }) 277 | if ($visibleFiles.Count -eq 0) { $emptyDirs.Add($dir.FullName) } 278 | } 279 | } catch { $emptyDirs = @() } 280 | $emptyDirTotal = $emptyDirs.Count 281 | 282 | #---------------------------------------------------------------------- 283 | if ($emptyDirTotal -ne 0) { 284 | if ($script:enableMultithread) { 285 | Write-Debug ('Multithread Processing Enabled') 286 | # 並列化が有効の場合は並列化 287 | $emptyDirs | ForEach-Object -Parallel { 288 | $emptyDirNum = ([Array]::IndexOf($using:emptyDirs, $_)) + 1 289 | $emptyDirTotal = $using:emptyDirs.Count 290 | Write-Output (' {0}/{1} - {2}' -f $emptyDirNum, $emptyDirTotal, $_) 291 | try { Remove-Item -LiteralPath $_ -Recurse -Force | Out-Null } 292 | catch { Write-Warning ($script:msg.DeleteEmptyDirsFailed -f $_) } 293 | } -ThrottleLimit $script:multithreadNum 294 | } else { 295 | # 並列化が無効の場合は従来型処理 296 | $emptyDirNum = 0 297 | $emptyDirTotal = $emptyDirs.Count 298 | $totalStartTime = Get-Date 299 | foreach ($dir in $emptyDirs) { 300 | $emptyDirNum++ 301 | # 処理時間の推計 302 | $secElapsed = (Get-Date) - $totalStartTime 303 | $secRemaining = -1 304 | if ($emptyDirNum -ne 1) { 305 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $emptyDirNum) * ($emptyDirTotal - $emptyDirNum)) 306 | $minRemaining = ($script:msg.MinRemaining -f ([Int][Math]::Ceiling($secRemaining / 60))) 307 | $progressRate = [Float]($emptyDirNum / $emptyDirTotal) 308 | } else { $minRemaining = '' ; $progressRate = 0 } 309 | 310 | $toastUpdateParams.Title = $dir 311 | $toastUpdateParams.Rate = $progressRate 312 | $toastUpdateParams.LeftText = ('{0}/{1}' -f $emptyDirNum, $emptyDirTotal) 313 | $toastUpdateParams.RightText = $minRemaining 314 | Update-ProgressToast @toastUpdateParams 315 | 316 | Write-Output (' {0}/{1} - {2}' -f $emptyDirNum, $emptyDirTotal, $dir) 317 | try { Remove-Item -LiteralPath $dir -Recurse -Force -ErrorAction SilentlyContinue | Out-Null } 318 | catch { Write-Warning ($script:msg.DeleteEmptyDirsFailed -f $dir) } 319 | } 320 | } 321 | } 322 | #---------------------------------------------------------------------- 323 | } 324 | 325 | $toastUpdateParams.Title = $script:msg.DeleteTrash 326 | $toastUpdateParams.Rate = 1 327 | $toastUpdateParams.LeftText = '' 328 | $toastUpdateParams.RightText = $script:msg.Completed 329 | Update-ProgressToast @toastUpdateParams 330 | 331 | Remove-Variable -Name args, toastShowParams, toastUpdateParams, saveDir, workDirEntities, ignoreTitles, ignoreDirs, ignoreTitle, filteredDirs, filteredDir, ignoreNum, ignoreTotal, totalStartTime, ignoreDir, secElapsed, secRemaining, minRemaining, progressRate, emptyDirs, emptyDirTotal, emptyDirNum, dir -ErrorAction SilentlyContinue 332 | 333 | Invoke-GarbageCollection 334 | 335 | Write-Output ('') 336 | Write-Output ($script:msg.LongBoldBorder) 337 | Write-Output ($script:msg.DeleteTrashCompleted) 338 | Write-Output ($script:msg.LongBoldBorder) 339 | -------------------------------------------------------------------------------- /src/download_bulk.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 一括ダウンロード処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecの一括ダウンロード処理を実行するスクリプト 9 | 10 | .DESCRIPTION 11 | TVerRecの一括ダウンロード処理を実行するスクリプトです。 12 | 以下の処理を順番に実行します: 13 | 1. キーワードリストの読み込み 14 | 2. 各キーワードに対する動画検索 15 | 3. ダウンロード履歴との照合 16 | 4. 動画のダウンロード処理 17 | 5. リネームに失敗したファイルの削除 18 | 19 | .PARAMETER guiMode 20 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 21 | - 指定なし: 通常モードで実行 22 | - 'gui': GUIモードで実行 23 | - その他の値: 通常モードで実行 24 | 25 | .NOTES 26 | 前提条件: 27 | - Windows、Linux、またはmacOS環境で実行する必要があります 28 | - PowerShell 7.0以上を推奨します 29 | - TVerRecの設定ファイルが正しく設定されている必要があります 30 | - 十分なディスク容量が必要です 31 | - インターネット接続が必要です 32 | - TVerのアカウントが必要な場合があります 33 | - キーワードリストファイルが存在する必要があります 34 | 35 | 処理の流れ: 36 | 1. 環境設定の読み込み 37 | 2. キーワードリストの読み込み 38 | 3. 各キーワードに対する処理 39 | 3.1 動画リンクの取得 40 | 3.2 ダウンロード履歴との照合 41 | 3.3 動画のダウンロード 42 | 4. ダウンロード完了待機 43 | 5. リネーム失敗ファイルの削除 44 | 45 | .EXAMPLE 46 | # 通常モードで実行 47 | .\download_bulk.ps1 48 | 49 | # GUIモードで実行 50 | .\download_bulk.ps1 gui 51 | 52 | .OUTPUTS 53 | System.Void 54 | このスクリプトは以下の出力を行います: 55 | - コンソールへの進捗状況の表示 56 | - トースト通知による進捗状況の表示 57 | - エラー発生時のエラーメッセージ 58 | - 処理完了時のサマリー情報 59 | - ダウンロードした動画ファイル 60 | #> 61 | 62 | Set-StrictMode -Version Latest 63 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 64 | 65 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 66 | # 環境設定 67 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 68 | try { 69 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 70 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 71 | Set-Location $script:scriptRoot 72 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 73 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 74 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 75 | 76 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 77 | # メイン処理 78 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79 | try { 80 | # 必須ファイルのチェックとトークンの取得 81 | Invoke-RequiredFileCheck 82 | Suspend-Process 83 | Get-Token 84 | 85 | # キーワードリストの読み込み 86 | $keywords = @(Read-KeywordList) 87 | if ($keywords.Count -eq 0) { throw 'キーワードリストが空です。処理を中断します。' } 88 | else { $keywordTotal = $keywords.Count } 89 | $keywordNum = 0 90 | 91 | # 進捗表示の初期化 92 | $toastShowParams = @{ 93 | Text1 = $script:msg.BulkDownloading 94 | Text2 = $script:msg.ExtractAndDownloadVideoFromKeywords 95 | WorkDetail = $script:msg.Loading 96 | Tag = $script:appName 97 | Silent = $false 98 | Group = 'Bulk' 99 | } 100 | Show-ProgressToast @toastShowParams 101 | 102 | # ジョブ管理の初期化 103 | $script:jobList = @() 104 | Register-EngineEvent PowerShell.Exiting -Action { 105 | foreach ($jobId in $script:jobList) { 106 | Stop-Job -Id $jobId -Force -ErrorAction SilentlyContinue 107 | Remove-Job -Id $jobId -Force -ErrorAction SilentlyContinue 108 | } 109 | } | Out-Null 110 | 111 | #====================================================================== 112 | # ビデオリンクの収集 113 | #====================================================================== 114 | $linkCollectionStartTime = Get-Date 115 | $uniqueEpisodeIDs = [System.Collections.Generic.HashSet[string]]::new() 116 | $videoKeywordMap = @{} 117 | 118 | Write-Output ($script:msg.LongBoldBorder) 119 | Write-Output ($script:msg.ExtractingVideoFromKeywords) 120 | 121 | foreach ($keyword in $keywords) { 122 | $keywordNum++ 123 | $keyword = Remove-TabSpace($keyword) 124 | 125 | Write-Output ('') 126 | Write-Output ($script:msg.MediumBoldBorder) 127 | Write-Output ('{0}' -f $keyword) 128 | 129 | # 進捗情報の更新 130 | $secElapsed = (Get-Date) - $linkCollectionStartTime 131 | if ($keywordNum -ne 0) { 132 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $keywordNum) * ($keywordTotal - $keywordNum)) 133 | $minRemaining = ('{0}分' -f ([Int][Math]::Ceiling($secRemaining / 60))) 134 | } else { $minRemaining = '' } 135 | 136 | $toastUpdateParams = @{ 137 | Title = (Remove-TabSpace ($keyword)) 138 | Rate = [Float]($keywordNum / $keywordTotal) 139 | LeftText = ('{0}/{1}' -f $keywordNum, $keywordTotal) 140 | RightText = $minRemaining 141 | Tag = $script:appName 142 | Group = 'Bulk' 143 | } 144 | Update-ProgressToast @toastUpdateParams 145 | 146 | # キーワードの正規化とビデオリンク取得 147 | $keyword = Get-ContentWoComment($keyword.Replace('https://tver.jp/', '').Trim()) 148 | $resultLinks = @(Get-VideoLinksFromKeyword $keyword) 149 | 150 | # 履歴チェックと重複排除 151 | if ($resultLinks.Count -ne 0) { 152 | $episodeIDs, $processedCount = Invoke-HistoryMatchCheck $resultLinks 153 | foreach ($link in $episodeIDs) {if ($uniqueEpisodeIDs.Add($link)) { $videoKeywordMap[$link] = $keyword } } 154 | } else { $episodeIDs = @() ; $processedCount = 0 } 155 | 156 | $videoCount = $episodeIDs.Count 157 | if ($videoCount -eq 0) { Write-Output ($script:msg.VideoCountWhenZero -f $videoCount, $processedCount) } 158 | else { Write-Output ($script:msg.VideoCountNonZero -f $videoCount, $processedCount) } 159 | } 160 | 161 | #====================================================================== 162 | # ビデオのダウンロード 163 | #====================================================================== 164 | $downloadStartTime = Get-Date 165 | $videoTotal = $uniqueEpisodeIDs.Count 166 | $videoNum = 0 167 | 168 | Write-Output ('') 169 | Write-Output ($script:msg.LongBoldBorder) 170 | Write-Output ($script:msg.DownloadingVideo) 171 | 172 | foreach ($episodeID in $uniqueEpisodeIDs) { 173 | $videoNum++ 174 | $keyword = $videoKeywordMap[$episodeID] 175 | 176 | # ディレクトリの存在確認 177 | if (!(Test-Path $script:downloadBaseDir -PathType Container)) { throw $script:msg.DownloadDirNotAccessible } 178 | 179 | # 空き容量少ないときは中断 180 | if ((Get-RemainingCapacity $script:downloadWorkDir) -lt $script:minDownloadWorkDirCapacity ) { Write-Warning ($script:msg.NoEnoughCapacity -f $script:downloadWorkDir ) ; break } 181 | if ((Get-RemainingCapacity $script:downloadBaseDir) -lt $script:minDownloadBaseDirCapacity ) { Write-Warning ($script:msg.NoEnoughCapacity -f $script:downloadBaseDir ) ; break } 182 | 183 | # 進捗率の計算 184 | $secElapsed = (Get-Date) - $downloadStartTime 185 | if ($videoNum -ne 0) { 186 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $videoNum) * ($videoTotal - $videoNum)) 187 | $minRemaining = ('{0}分' -f ([Int][Math]::Ceiling($secRemaining / 60))) 188 | } else { $minRemaining = '' } 189 | 190 | # 進捗情報の更新 191 | $toastUpdateParams = @{ 192 | Title = $episodeID 193 | Rate = [Float]($videoNum / $videoTotal) 194 | LeftText = ('{0}/{1}' -f $videoNum, $videoTotal) 195 | RightText = $minRemaining 196 | Tag = $script:appName 197 | Group = 'Bulk' 198 | } 199 | Update-ProgressToast @toastUpdateParams 200 | 201 | Write-Output ($script:msg.ShortBoldBorder) 202 | Write-Output ('{0}/{1} - {2}' -f $videoNum, $videoTotal, $episodeID) 203 | 204 | # ダウンロードプロセスの制御 205 | Wait-YtdlProcess $script:parallelDownloadFileNum 206 | Suspend-Process 207 | 208 | # ビデオのダウンロード 209 | Invoke-VideoDownload -Keyword $keyword -episodeID $episodeID -Force $false 210 | } 211 | 212 | #====================================================================== 213 | # 後処理 214 | #====================================================================== 215 | # youtube-dlのプロセスが終わるまで待機 216 | Write-Output ('') 217 | Write-Output ($script:msg.WaitingDownloadCompletion) 218 | Wait-DownloadCompletion 219 | 220 | # リネームに失敗したファイルを削除 221 | Write-Output ('') 222 | Write-Output ($script:msg.DeleteFilesFailedToRename) 223 | Remove-UnRenamedTempFile 224 | 225 | # 最終進捗表示 226 | $toastUpdateParams = @{ 227 | Title = $script:msg.BulkDownloading 228 | Rate = 1 229 | LeftText = '' 230 | RightText = $script:msg.Completed 231 | Tag = $script:appName 232 | Group = 'Bulk' 233 | } 234 | Update-ProgressToast @toastUpdateParams 235 | 236 | # 完了メッセージ 237 | Write-Output ('') 238 | Write-Output ($script:msg.LongBoldBorder) 239 | Write-Output ($script:msg.BulkDownloadCompleted) 240 | Write-Output ($script:msg.LongBoldBorder) 241 | } catch { 242 | Write-Error "Error occurred: $($_.Exception.Message)" 243 | Write-Error "Stack trace: $($_.ScriptStackTrace)" 244 | throw 245 | } finally { 246 | # 変数のクリーンアップ 247 | Remove-Variable -Name args, keywords, keywordTotal, keywordNum, toastShowParams, 248 | totalStartTime, keyword, resultLinks, processedCount, videoLinks, videoCount, 249 | secElapsed, secRemaining, videoLink, toastUpdateParams, videoProcessed, 250 | uniqueVideoLinks, videoKeywordMap, errorCount, maxErrors -ErrorAction SilentlyContinue 251 | 252 | # ガベージコレクション 253 | Invoke-GarbageCollection 254 | } 255 | -------------------------------------------------------------------------------- /src/download_list.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # リストダウンロード処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecのダウンロードリストから番組をダウンロードするスクリプト 9 | 10 | .DESCRIPTION 11 | list.csvに記載された番組URLを順次ダウンロードします。 12 | 以下の処理を順番に実行します: 13 | 1. ダウンロードリストの読み込み 14 | 2. ダウンロード履歴との照合 15 | 3. 番組の一括ダウンロード 16 | 4. 一時ファイルの削除 17 | 18 | .PARAMETER guiMode 19 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 20 | - 指定なし: 通常モードで実行 21 | - 'gui': GUIモードで実行 22 | - その他の値: 通常モードで実行 23 | 24 | .NOTES 25 | 前提条件: 26 | - Windows、Linux、またはmacOS環境で実行する必要があります 27 | - PowerShell 7.0以上を推奨します 28 | - TVerRecの設定ファイルが正しく設定されている必要があります 29 | - list.csvにダウンロードしたい番組のURLが記載されている必要があります 30 | - 十分なディスク容量が必要です 31 | - インターネット接続が必要です 32 | - TVerのアカウントが必要な場合があります 33 | 34 | 処理の流れ: 35 | 1. 初期設定 36 | 1.1 環境チェック 37 | 1.2 トークンの取得 38 | 2. ダウンロードリストの処理 39 | 2.1 リストファイルの読み込み 40 | 2.2 ダウンロード履歴との照合 41 | 2.3 ダウンロード対象の特定 42 | 3. ダウンロード処理 43 | 3.1 空き容量のチェック 44 | 3.2 並列ダウンロードの制御 45 | 3.3 個別番組のダウンロード 46 | 4. 後処理 47 | 4.1 ダウンロード完了の待機 48 | 4.2 一時ファイルの削除 49 | 50 | .EXAMPLE 51 | # 通常モードで実行 52 | .\download_list.ps1 53 | 54 | # GUIモードで実行 55 | .\download_list.ps1 gui 56 | 57 | .OUTPUTS 58 | System.Void 59 | このスクリプトは以下の出力を行います: 60 | - コンソールへの進捗状況の表示 61 | - トースト通知による進捗状況の表示 62 | - エラー発生時のエラーメッセージ 63 | - 処理完了時のサマリー情報 64 | #> 65 | 66 | Set-StrictMode -Version Latest 67 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 68 | 69 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 70 | # 環境設定 71 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 72 | try { 73 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 74 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 75 | Set-Location $script:scriptRoot 76 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 77 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 78 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 79 | 80 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 81 | # メイン処理 82 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 83 | try { 84 | # 必須ファイルのチェックとトークンの取得 85 | Invoke-RequiredFileCheck 86 | Suspend-Process 87 | Get-Token 88 | 89 | # ダウンロードリストを読み込み 90 | $resultLinks = @(Get-LinkFromDownloadList) 91 | if ($null -eq $resultLinks) { Write-Warning ($script:msg.DownloadListZero) ; exit 0 } 92 | $resultLinks = $resultLinks -ne '' 93 | $keyword = $script:msg.KeywordForListDownload 94 | 95 | # 履歴チェックと重複排除 96 | if ($resultLinks.Count -ne 0) { $episodeIDs, $processedCount = Invoke-HistoryMatchCheck $resultLinks } 97 | else { $episodeIDs = @() ; $processedCount = 0 } 98 | $videoTotal = $episodeIDs.Count 99 | Write-Output ('') 100 | if ($videoTotal -eq 0) { Write-Output ($script:msg.VideoCountWhenZero -f $videoTotal, $processedCount) } 101 | else { Write-Output ($script:msg.VideoCountNonZero -f $videoTotal, $processedCount) } 102 | 103 | # 処理時間の推計 104 | $totalStartTime = Get-Date 105 | $secRemaining = -1 106 | 107 | $toastShowParams = @{ 108 | Text1 = $script:msg.ListDownloading 109 | Text2 = $script:msg.ExtractAndDownloadVideoFromLists 110 | WorkDetail = $script:msg.Loading 111 | Tag = $script:appName 112 | Silent = $false 113 | Group = 'List' 114 | } 115 | Show-ProgressToast @toastShowParams 116 | 117 | # ジョブを管理 118 | $script:jobList = @() 119 | 120 | # スクリプト終了時にジョブを停止 121 | Register-EngineEvent PowerShell.Exiting -Action { 122 | foreach ($jobId in $script:jobList) { 123 | Stop-Job -Id $jobId -Force -ErrorAction SilentlyContinue 124 | Remove-Job -Id $jobId -Force -ErrorAction SilentlyContinue 125 | } 126 | } | Out-Null 127 | 128 | #---------------------------------------------------------------------- 129 | # 個々の番組ダウンロードここから 130 | $videoNum = 0 131 | foreach ($episodeID in $episodeIDs) { 132 | $videoNum++ 133 | # ディレクトリの存在確認 134 | if (!(Test-Path $script:downloadBaseDir -PathType Container)) { throw $script:msg.DownloadDirNotAccessible } 135 | 136 | # 空き容量少ないときは中断 137 | if ((Get-RemainingCapacity $script:downloadWorkDir) -lt $script:minDownloadWorkDirCapacity ) { Write-Warning ($script:msg.NoEnoughCapacity -f $script:downloadWorkDir ) ; break } 138 | if ((Get-RemainingCapacity $script:downloadBaseDir) -lt $script:minDownloadBaseDirCapacity ) { Write-Warning ($script:msg.NoEnoughCapacity -f $script:downloadBaseDir ) ; break } 139 | 140 | # 進捗率の計算 141 | $secElapsed = (Get-Date) - $totalStartTime 142 | if ($videoNum -ne 0) { 143 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $videoNum) * ($videoTotal - $videoNum)) 144 | $minRemaining = ('{0}分' -f ([Int][Math]::Ceiling($secRemaining / 60))) 145 | } else { $minRemaining = '' } 146 | 147 | # 進捗情報の更新 148 | $toastUpdateParams = @{ 149 | Title = $script:msg.ListDownloading 150 | Rate = [Float]($videoNum / $videoTotal) 151 | LeftText = ('{0}/{1}' -f $videoNum, $videoTotal) 152 | RightText = $minRemaining 153 | Tag = $script:appName 154 | Group = 'List' 155 | } 156 | Update-ProgressToast @toastUpdateParams 157 | 158 | Write-Output ($script:msg.ShortBoldBorder) 159 | Write-Output ('{0}/{1} - {2}' -f $videoNum, $videoTotal, $episodeID) 160 | 161 | # ダウンロードプロセスの制御 162 | Wait-YtdlProcess $script:parallelDownloadFileNum 163 | Suspend-Process 164 | 165 | # TVer番組ダウンロードのメイン処理 166 | Invoke-VideoDownload -Keyword $keyword -episodeID $episodeID -Force $false 167 | } 168 | #---------------------------------------------------------------------- 169 | 170 | # youtube-dlのプロセスが終わるまで待機 171 | Write-Output ('') 172 | Write-Output ($script:msg.WaitingDownloadCompletion) 173 | Wait-DownloadCompletion 174 | 175 | # リネームに失敗したファイルを削除 176 | Write-Output ('') 177 | Write-Output ($script:msg.DeleteFilesFailedToRename) 178 | Remove-UnRenamedTempFile 179 | 180 | $toastUpdateParams = @{ 181 | Title = $script:msg.ListDownloading 182 | Rate = '1' 183 | LeftText = '' 184 | RightText = $script:msg.Completed 185 | Tag = $script:appName 186 | Group = 'List' 187 | } 188 | Update-ProgressToast @toastUpdateParams 189 | 190 | Write-Output ('') 191 | Write-Output ($script:msg.LongBoldBorder) 192 | Write-Output ($script:msg.ListDownloadCompleted) 193 | Write-Output ($script:msg.LongBoldBorder) 194 | } catch { 195 | Write-Error "Error occurred: $($_.Exception.Message)" 196 | Write-Error "Stack trace: $($_.ScriptStackTrace)" 197 | throw 198 | } finally { 199 | # 変数のクリーンアップ 200 | Remove-Variable -Name args, listLinks, keyword, videoLinks, processedCount, videoTotal, 201 | totalStartTime, secRemaining, toastShowParams, videoNum, videoLink, secElapsed, 202 | minRemaining, toastUpdateParams -ErrorAction SilentlyContinue 203 | 204 | # ガベージコレクション 205 | Invoke-GarbageCollection 206 | } 207 | -------------------------------------------------------------------------------- /src/download_single.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 個別ダウンロード処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecで個別の番組URLをダウンロードするスクリプト 9 | 10 | .DESCRIPTION 11 | 指定されたURLの番組を個別にダウンロードします。 12 | 以下の機能を提供します: 13 | 1. TVer番組の個別ダウンロード 14 | 2. 複数URLの一括ダウンロード 15 | 3. GUI/CUIでのURL入力 16 | 4. TVer以外のサイトからのダウンロード対応 17 | 18 | .PARAMETER guiMode 19 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 20 | - 指定なし: CUIモードで実行(コンソールでURL入力) 21 | - 'gui': GUIモードで実行(ダイアログでURL入力) 22 | - その他の値: CUIモードで実行 23 | 24 | .NOTES 25 | 前提条件: 26 | - Windows、Linux、またはmacOS環境で実行する必要があります 27 | - PowerShell 7.0以上を推奨します 28 | - TVerRecの設定ファイルが正しく設定されている必要があります 29 | - GUIモードの場合、Windows Formsが利用可能である必要があります(Windowsのみ) 30 | - 十分なディスク容量が必要です 31 | - インターネット接続が必要です 32 | - TVerのアカウントが必要な場合があります 33 | 34 | 処理の流れ: 35 | 1. 初期設定 36 | 1.1 環境チェック 37 | 1.2 トークンの取得 38 | 1.3 GUI/CUIモードの判定 39 | 2. URL入力処理 40 | 2.1 GUIモード: ダイアログでの入力 41 | 2.2 CUIモード: コンソールでの入力 42 | 3. ダウンロード処理 43 | 3.1 URLの種類判定(TVer/その他) 44 | 3.2 並列ダウンロードの制御 45 | 3.3 個別番組のダウンロード 46 | 4. 後処理 47 | 4.1 ダウンロード完了の待機 48 | 4.2 一時ファイルの削除 49 | 50 | 対応URL: 51 | - TVer: https://tver.jp/で始まるURL 52 | - その他: youtube-dlでサポートされているサイトのURL 53 | 54 | .EXAMPLE 55 | # 通常モードで実行(CUI) 56 | .\download_single.ps1 57 | 58 | # GUIモードで実行 59 | .\download_single.ps1 gui 60 | 61 | .OUTPUTS 62 | System.Void 63 | このスクリプトは以下の出力を行います: 64 | - コンソールへの進捗状況の表示 65 | - GUIモードの場合、URL入力ダイアログの表示 66 | - エラー発生時のエラーメッセージ 67 | - 処理完了時のサマリー情報 68 | - ダウンロードした動画ファイル 69 | #> 70 | 71 | Set-StrictMode -Version Latest 72 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 73 | 74 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 75 | # 関数定義 76 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 77 | function Show-UrlInputDialog { 78 | try { 79 | # アセンブリの読み込み 80 | Add-Type -AssemblyName System.Windows.Forms | Out-Null 81 | Add-Type -AssemblyName System.Drawing | Out-Null 82 | 83 | # フォームの作成 84 | $inputForm = New-Object System.Windows.Forms.Form -Property @{ 85 | Text = $script:msg.SingleDownloadFormTitle 86 | Size = New-Object System.Drawing.Size(520, 300) 87 | StartPosition = 'CenterScreen' 88 | MaximizeBox = $False 89 | MinimizeBox = $False 90 | FormBorderStyle = 'Fixed3D' 91 | KeyPreview = $True 92 | TopLevel = $true 93 | ShowIcon = $False 94 | } 95 | $inputForm.Add_KeyDown({ if ($_.KeyCode -eq 'Escape') { $inputForm.Close() } }) 96 | $inputForm.Add_Shown({ $inputForm.Activate() }) 97 | 98 | # ボタンの作成 99 | $okButton = New-Object System.Windows.Forms.Button -Property @{ 100 | Location = New-Object System.Drawing.Size(415, 10) 101 | Size = New-Object System.Drawing.Size(75, 20) 102 | Text = $script:msg.SingleDownloadGUIOkButton 103 | } 104 | $okButton.Add_Click({ $script:videoPageList = @($inputTextBox.Text.Split("`r`n").Split()) ; $inputForm.Close() }) 105 | $inputForm.Controls.Add($okButton) 106 | 107 | # テキストラベルの作成 108 | $inputTextLabel = New-Object System.Windows.Forms.Label -Property @{ 109 | Location = New-Object System.Drawing.Size(10, 10) 110 | Size = New-Object System.Drawing.Size(480, 20) 111 | Text = $script:msg.SingleDownloadGUIMessage 112 | } 113 | $inputForm.Controls.Add($inputTextLabel) 114 | 115 | # テキストボックスの作成 116 | $inputTextBox = New-Object System.Windows.Forms.TextBox -Property @{ 117 | Location = New-Object System.Drawing.Size(10, 40) 118 | Size = New-Object System.Drawing.Size(480, 200) 119 | Multiline = $true 120 | ScrollBars = [System.Windows.Forms.ScrollBars]::Vertical 121 | } 122 | $inputForm.Controls.Add($inputTextBox) 123 | 124 | # ダイアログの表示 125 | $inputForm.ShowDialog() | Out-Null 126 | 127 | return $script:videoPageList 128 | } catch { 129 | Write-Error "URL入力ダイアログの表示中にエラーが発生しました: $($_.Exception.Message)" 130 | Write-Error "Stack trace: $($_.ScriptStackTrace)" 131 | throw 132 | } 133 | } 134 | 135 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 136 | # 環境設定 137 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 138 | try { 139 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 140 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 141 | Set-Location $script:scriptRoot 142 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 143 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 144 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 145 | 146 | # 実行モードの設定 147 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 148 | 149 | # ジョブ管理の初期化 150 | $script:jobList = @() 151 | Register-EngineEvent PowerShell.Exiting -Action { 152 | foreach ($jobId in $script:jobList) { 153 | Stop-Job -Id $jobId -Force -ErrorAction SilentlyContinue 154 | Remove-Job -Id $jobId -Force -ErrorAction SilentlyContinue 155 | } 156 | } | Out-Null 157 | 158 | 159 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 160 | # メイン処理 161 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 162 | try { 163 | # 必須ファイルのチェックとトークンの取得 164 | Invoke-RequiredFileCheck 165 | Suspend-Process 166 | Get-Token 167 | 168 | # キーワードの設定 169 | $keyword = $script:msg.KeywordForSingleDownload 170 | 171 | # GUIモードの判定 172 | if (!$script:guiMode) { $script:guiMode = $false } 173 | 174 | # ジョブ管理の初期化 175 | $script:jobList = @() 176 | Register-EngineEvent PowerShell.Exiting -Action { 177 | foreach ($jobId in $script:jobList) { 178 | Stop-Job -Id $jobId -Force -ErrorAction SilentlyContinue 179 | Remove-Job -Id $jobId -Force -ErrorAction SilentlyContinue 180 | } 181 | } | Out-Null 182 | 183 | #---------------------------------------------------------------------- 184 | # 無限ループ 185 | while ($true) { 186 | # 初期化 187 | $videoLink = '' 188 | $script:videoPageList = @() 189 | 190 | # ディレクトリの存在確認 191 | if (!(Test-Path $script:downloadBaseDir -PathType Container)) { throw $script:msg.DownloadDirNotAccessible } 192 | 193 | # youtube-dlプロセスの制御 194 | Wait-YtdlProcess $script:parallelDownloadFileNum 195 | Suspend-Process 196 | 197 | # URL入力処理 198 | if (!$script:guiMode) { 199 | # CUIモードでの入力 200 | $script:videoPageList = @((Read-Host $script:msg.SingleDownloadCUIMessage).Trim().Split()) 201 | } else { 202 | # GUIモードでの入力 203 | $script:videoPageList = Show-UrlInputDialog 204 | } 205 | 206 | # 入力の検証 207 | $script:videoPageList = $script:videoPageList.where({ $_ -ne '' }) 208 | if (-not $script:videoPageList) { break } 209 | 210 | # ダウンロード処理 211 | foreach ($videoLink in $script:videoPageList) { 212 | # プロセス制御 213 | Wait-YtdlProcess $script:parallelDownloadFileNum 214 | Suspend-Process 215 | 216 | # URLの種類に応じた処理 217 | switch -Regex ($videoLink) { 218 | '^https://tver.jp/(/?.*)' { 219 | # TVer番組のダウンロード 220 | Write-Output ('') 221 | Write-Output ($script:msg.MediumBoldBorder) 222 | Write-Output ('{0}: {1}' -f $script:msg.SingleDownloadTVerURL, $videoLink) 223 | Invoke-VideoDownload -Keyword $keyword -episodeID $videoLink.Replace('https://tver.jp/episodes/', '') -Force $script:forceSingleDownload 224 | break 225 | } 226 | '^.*://' { 227 | # その他のサイトのダウンロード 228 | Write-Output ('') 229 | Write-Output ($script:msg.MediumBoldBorder) 230 | Write-Output ('{0}: {1}' -f $script:msg.SingleDownloadNonTVerURL, $videoLink) 231 | Invoke-NonTverYtdl $videoLink 232 | Start-Sleep -Seconds 1 233 | break 234 | } 235 | default { 236 | Write-Warning ('{0}: {1}' -f $script:msg.SingleDownloadNotURL, $videoLink) 237 | } 238 | } 239 | } 240 | } 241 | 242 | # ダウンロード完了待機 243 | Write-Output ('') 244 | Write-Output ($script:msg.WaitingDownloadCompletion) 245 | Wait-DownloadCompletion 246 | 247 | # リネーム失敗ファイルの削除 248 | Write-Output ('') 249 | Write-Output ($script:msg.DeleteFilesFailedToRename) 250 | Remove-UnRenamedTempFile 251 | 252 | } catch { 253 | Write-Error "Error occurred: $($_.Exception.Message)" 254 | Write-Error "Stack trace: $($_.ScriptStackTrace)" 255 | throw 256 | } finally { 257 | # 変数のクリーンアップ 258 | Remove-Variable -Name args, keyword, videoPageURL -ErrorAction SilentlyContinue 259 | Invoke-GarbageCollection 260 | 261 | # 完了メッセージ 262 | Write-Output ('') 263 | Write-Output ($script:msg.LongBoldBorder) 264 | Write-Output ($script:msg.SingleDownloadCompleted) 265 | Write-Output ($script:msg.LongBoldBorder) 266 | } 267 | -------------------------------------------------------------------------------- /src/functions/initialize.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 関数読み込みスクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecの初期化処理を行うスクリプトです。 9 | 10 | .DESCRIPTION 11 | TVerRecアプリケーションの起動時に必要な初期化処理を実行します。 12 | 主に以下の5つのカテゴリの初期化を行います: 13 | 14 | 1. 基本設定の初期化 15 | - ロゴデータの設定 16 | - 言語設定の読み込み 17 | - メッセージリソースの初期化 18 | 19 | 2. 設定ファイルの読み込み 20 | - システム設定ファイルの読み込み 21 | - ユーザー設定ファイルの読み込み 22 | - 開発環境用設定の読み込み 23 | 24 | 3. 関数ファイルの読み込み 25 | - 共通関数の読み込み 26 | - TVer固有関数の読み込み 27 | - TVerRec固有関数の読み込み 28 | 29 | 4. パスの初期化 30 | - 各種設定ファイルのパス設定 31 | - ログファイルのパス設定 32 | - 実行ファイルのパス設定 33 | 34 | 5. 環境設定の初期化 35 | - HTTPヘッダーの設定 36 | - GeoIP情報の設定 37 | - ロックファイル用変数の初期化 38 | 39 | .NOTES 40 | 前提条件: 41 | - Windows、Linux、またはmacOS環境で実行する必要があります 42 | - PowerShell 7.0以上を推奨します 43 | - TVerRecの設定ファイルが正しく設定されている必要があります 44 | - 十分なディスク容量が必要です 45 | - インターネット接続が必要です 46 | - TVerのアカウントが必要な場合があります 47 | 48 | 主要な機能: 49 | - アプリケーションの初期設定 50 | - 設定ファイルの管理 51 | - 関数ライブラリの読み込み 52 | - パス設定の初期化 53 | - 実行環境の設定 54 | 55 | .LINK 56 | https://github.com/dongaba/TVerRec 57 | #> 58 | 59 | Set-StrictMode -Version Latest 60 | Write-Debug ('{0}' -f $MyInvocation.MyCommand.Name) 61 | try { $launchMode = [String]$args[0] } catch { $launchMode = '' } 62 | 63 | # ロゴデータ 64 | $script:logoLines = @( 65 | '⣴⠟⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦', 66 | '⣿⠀⠀⣿⣿⣿⣿⡿⠟⠛⠛⠛⠛⠳⢦⣄⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿', 67 | '⣿⠀⠀⣿⣿⡟⠁⠀⠀⠀⠀⠀⠀⠀⠀⠈⢳⣄⠀⠀⠀⣿⣿⣿⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⠙⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿', 68 | '⣿⠀⠀⣿⠏⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠹⣆⠀⠀⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣿⣦⠀⠈⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿', 69 | '⣿⠀⠀⣿⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣿⠀⠀⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⠀⠀⣿⡟⠁⣀⣀⠈⢻⣿⠀⠋⢀⣀⡀⠙⣿⠀⠀⣿⣿⣿⠟⠀⢀⣿⡟⠁⣀⣀⠈⢻⣿⡟⠁⣀⣀⠈⢻⣿⣿⣿⣿', 70 | '⣿⠀⠀⣿⣆⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⠏⠀⠀⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⠀⠀⣿⠀⠾⠿⠿⠷⠀⣿⠀⣾⣿⣿⣿⣿⣿⠀⠀⠀⠀⠀⠀⣠⣿⣿⠀⠾⠿⠿⠷⠀⣿⠀⣾⣿⣿⣿⣿⣿⣿⣿⣿', 71 | '⣿⠀⠀⣿⣿⣧⡀⠀⠀⠀⠀⠀⠀⠀⠀⢀⡼⠋⠀⠀⠀⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⣦⡀⠈⠻⠟⠁⢀⣴⣿⠀⢶⣶⣶⣶⣶⣿⠀⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣧⠀⠘⣿⣿⠀⢶⣶⣶⣶⣶⣿⠀⢿⣿⣿⣿⣿⣿⣿⣿⣿', 72 | '⣿⠀⠀⣿⣿⣿⣿⣷⣦⣤⣤⣤⣤⣴⣾⠋⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣿⣿⣿⣿⣦⡀⢀⣴⣿⣿⣿⣧⡀⠉⠉⢀⣼⣿⠀⣿⣿⣿⣿⣿⣿⠀⠀⣿⣿⣿⣧⠀⠘⣿⣧⡀⠉⠉⢀⣼⣿⣧⡀⠉⠉⢀⣼⣿⣿⣿⣿', 73 | '⣿⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⠀⠀⠙⢷⣄⠀⠀⠀⠀⠀⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿', 74 | '⠻⣦⣤⣿⣿⣿⣿⣿⣿⣿⣿⣤⣤⣤⣤⣽⣷⣤⣤⣤⣴⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟' 75 | ) 76 | 77 | $script:confDir = Convert-Path (Join-Path $script:scriptRoot '../conf') 78 | $script:devDir = Join-Path $script:scriptRoot '../dev' 79 | 80 | #---------------------------------------------------------------------- 81 | # メッセージファイル読み込み 82 | $script:langDir = Convert-Path (Join-Path $scriptRoot '../resources/lang') 83 | $script:uiCulture = [System.Globalization.CultureInfo]::CurrentUICulture.Name 84 | Write-Debug "Current Language: $script:uiCulture" 85 | $script:langFile = Get-Content -Path (Join-Path $script:langDir 'messages.json') | ConvertFrom-Json 86 | $script:msg = if (($script:langFile | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name).Contains($script:uiCulture)) { $script:langFile.$script:uiCulture } 87 | else { $defaultLang = 'en-US'; $script:langFile.$defaultLang } 88 | Write-Debug "Message Table Loaded: $script:uiCulture" 89 | 90 | #---------------------------------------------------------------------- 91 | # 設定ファイル読み込み 92 | if ( Test-Path (Join-Path $script:confDir 'system_setting.ps1') ) { 93 | try { . (Convert-Path (Join-Path $script:confDir 'system_setting.ps1')) } 94 | catch { throw ($script:msg.LoadSystemSettingFailed) } 95 | } else { throw ($script:msg.SystemSettingNotFound) } 96 | 97 | if ( Test-Path (Join-Path $script:confDir 'user_setting.ps1') ) { 98 | try { . (Convert-Path (Join-Path $script:confDir 'user_setting.ps1')) } 99 | catch { throw ($script:msg.LoadUserSettingFailed) } 100 | } elseif ($IsWindows) { 101 | Write-Output ($script:msg.UserSettingNeedsToBeCreated) 102 | try { & 'gui/gui_setting.ps1' } 103 | catch { throw ($script:msg.LoadSettingGUIFailed) } 104 | if ( Test-Path (Join-Path $script:confDir 'user_setting.ps1') ) { 105 | try { . (Convert-Path (Join-Path $script:confDir 'user_setting.ps1')) } 106 | catch { throw ($script:msg.LoadUserSettingFailed) } 107 | } else { throw ($script:msg.UserSettingNotCompleted) } 108 | } else { throw ($script:msg.UserSettingNotCompleted) } 109 | if ($script:preferredLanguage) { 110 | $script:msg = if (($script:langFile | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name).Contains($script:preferredLanguage)) { $script:langFile.$script:preferredLanguage } 111 | else { $defaultLang = 'en-US'; $script:langFile.$defaultLang } 112 | } 113 | 114 | #---------------------------------------------------------------------- 115 | # 外部関数ファイルの読み込み 116 | try { . (Convert-Path (Join-Path $script:scriptRoot 'functions/common_functions.ps1')) } 117 | catch { throw ($script:msg.LoadCommonFuncFailed) } 118 | try { . (Convert-Path (Join-Path $script:scriptRoot 'functions/tver_functions.ps1')) } 119 | catch { throw ($script:msg.LoadTVerFuncFailed) } 120 | try { . (Convert-Path (Join-Path $script:scriptRoot 'functions/tverrec_functions.ps1')) } 121 | catch { throw ($script:msg.LoadTVerRecFuncFailed) } 122 | 123 | #---------------------------------------------------------------------- 124 | # 開発環境用に設定上書き 125 | try { 126 | $devFunctionFile = Join-Path $script:devDir 'dev_functions.ps1' 127 | $devConfFile = Join-Path $script:devDir 'dev_setting.ps1' 128 | if (Test-Path $devConfFile) { . $devConfFile ; Write-Output ($script:msg.DevConfLoaded) } 129 | if (Test-Path $devFunctionFile) { . $devFunctionFile ; Write-Output ($script:msg.DevFuncLoaded) } 130 | Remove-Variable -Name devFunctionFile, devConfFile -ErrorAction SilentlyContinue 131 | } catch { throw ($script:msg.LoadDevFilesFailed) } 132 | 133 | #---------------------------------------------------------------------- 134 | # 連続実行時は以降の処理は不要なのでexit 135 | # 不要な理由はloop.ps1は「.」ではなく「&」で各処理を呼び出ししているので各種変数が不要なため 136 | if ($launchMode -eq 'loop') { Remove-Variable -Name launchMode -ErrorAction SilentlyContinue ; exit 0 } 137 | 138 | #---------------------------------------------------------------------- 139 | # アップデータのアップデート(アップデート後の実行時にアップデータを更新) 140 | if (Test-Path (Join-Path $script:scriptRoot '../log/updater_update.txt')) { 141 | try { 142 | Invoke-WebRequest ` 143 | -Uri 'https://raw.githubusercontent.com/dongaba/TVerRec/master/unix/update_tverrec.sh' ` 144 | -OutFile (Join-Path $script:scriptRoot '../unix/update_tverrec.sh') ` 145 | -TimeoutSec $script:timeoutSec 146 | Invoke-WebRequest ` 147 | -Uri 'https://raw.githubusercontent.com/dongaba/TVerRec/master/win/update_tverrec.cmd' ` 148 | -OutFile (Join-Path $script:scriptRoot '../win/update_tverrec.cmd') ` 149 | -TimeoutSec $script:timeoutSec 150 | Remove-Item (Join-Path $script:scriptRoot '../log/updater_update.txt') -Force | Out-Null 151 | } catch { Write-Warning ($script:msg.UpdateUpdaterFailed) } 152 | } 153 | 154 | # TVerRecの最新化チェック 155 | Invoke-TVerRecUpdateCheck 156 | if (!$?) { Write-Warning ($script:msg.TVerRecVersionCheckFailed) } 157 | 158 | #---------------------------------------------------------------------- 159 | # ダウンロード対象キーワードのパス 160 | $script:keywordFileSamplePath = Join-Path $script:sampleDir 'keyword.sample.conf' 161 | $script:keywordFilePath = Join-Path $script:confDir 'keyword.conf' 162 | 163 | # ダウンロード対象外番組のパス 164 | $script:ignoreFileSamplePath = Join-Path $script:sampleDir 'ignore.sample.conf' 165 | $script:ignoreFilePath = Join-Path $script:confDir 'ignore.conf' 166 | $script:ignoreLockFilePath = Join-Path $script:lockDir 'ignore.lock' 167 | 168 | # ダウンロード履歴のパス 169 | $script:histFilePath = Join-Path $script:dbDir 'history.csv' 170 | $script:histFileSamplePath = Join-Path $script:sampleDir 'history.sample.csv' 171 | $script:histLockFilePath = Join-Path $script:lockDir 'history.lock' 172 | 173 | # ダウンロードリストのパス 174 | $script:listFilePath = Join-Path $script:listDir 'list.csv' 175 | $script:listFileSamplePath = Join-Path $script:sampleDir 'list.sample.csv' 176 | $script:listLockFilePath = Join-Path $script:lockDir 'list.lock' 177 | 178 | # ffmpegで番組検証時のエラーファイルのパス 179 | $script:ffmpegErrorLogPath = Join-Path $script:logDir ('ffmpeg_err_{0}.log' -f $PID) 180 | 181 | # youtube-dlでダウンロードするときのログファイルのパス 182 | $script:ytdlStdOutLogPath = Join-Path $script:logDir ('ytdl_out_{0}.log' -f $PID) 183 | $script:ytdlStdErrLogPath = Join-Path $script:logDir ('ytdl_err_{0}.log' -f $PID) 184 | 185 | # youtube-dlのパス 186 | if ($IsWindows) { $script:ytdlPath = Join-Path $script:binDir 'yt-dlp.exe' } 187 | else { $script:ytdlPath = Join-Path $script:binDir 'yt-dlp' } 188 | 189 | # ffmpegのパス 190 | if ($IsWindows) { $script:ffmpegPath = Join-Path $script:binDir 'ffmpeg.exe' } 191 | else { $script:ffmpegPath = Join-Path $script:binDir 'ffmpeg' } 192 | 193 | # ffprobeのパス 194 | if ($IsWindows) { $script:ffprobePath = Join-Path $script:binDir 'ffprobe.exe' } 195 | else { $script:ffprobePath = Join-Path $script:binDir 'ffprobe' } 196 | 197 | # 進捗表示 198 | if ($script:detailedProgress) { $InformationPreference = 'Continue' } 199 | else { $InformationPreference = 'SilentlyContinue' } 200 | 201 | # Geo IPのパス 202 | $script:jpIPList = Join-Path $script:geoIPDir 'jp.csv' 203 | 204 | # GUI起動を判定 205 | if ( $myInvocation.ScriptName.Contains('gui')) { 206 | } else { 207 | # Logo表示 208 | if (!$script:guiMode) { Show-Logo } 209 | # youtube-dl/ffmpegの最新化チェック 210 | try { if (!$script:disableUpdateYoutubedl) { Invoke-ToolUpdateCheck -scriptName 'update_youtube-dl.ps1' -targetName $script:preferredYoutubedl } } 211 | catch { Write-Warning ($script:msg.YoutubeDLVersionCheckFailed) } 212 | try { if (!$script:disableUpdateFfmpeg) { Invoke-ToolUpdateCheck -scriptName 'update_ffmpeg.ps1' -targetName 'ffmpeg' } } 213 | catch { Write-Warning ($script:msg.FfmpegVersionCheckFailed) } 214 | } 215 | 216 | # 共通HTTPヘッダ 217 | $script:jpIP = Get-JpIP 218 | Write-Output ('') 219 | Write-Output ($script:msg.JpIPFound -f $script:jpIP) 220 | $script:commonHttpHeader = @{ 221 | 'x-tver-platform-type' = 'web' 222 | 'Origin' = 'https://tver.jp' 223 | 'Referer' = 'https://tver.jp/' 224 | 'Forwarded' = $script:jpIP 225 | 'Forwarded-For' = $script:jpIP 226 | 'X-Forwarded' = $script:jpIP 227 | 'X-Forwarded-For' = $script:jpIP 228 | } 229 | 230 | # ロックファイル用 231 | $script:fileInfo = @{} 232 | $script:fileStream = @{} 233 | 234 | Remove-Variable -Name launchMode -ErrorAction SilentlyContinue 235 | -------------------------------------------------------------------------------- /src/functions/initialize_child.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 関数読み込みスクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecの子プロセス用初期化処理を行うスクリプトです。 9 | 10 | .DESCRIPTION 11 | TVerRecアプリケーションの子プロセスで必要な初期化処理を実行します。 12 | メインの初期化処理よりも軽量な処理を行い、主に以下の4つのカテゴリの初期化を実行します: 13 | 14 | 1. 基本設定の初期化 15 | - 言語設定の読み込み 16 | - メッセージリソースの初期化 17 | - 設定ディレクトリの設定 18 | 19 | 2. 設定ファイルの読み込み 20 | - システム設定ファイルの読み込み 21 | - ユーザー設定ファイルの読み込み 22 | - 開発環境用設定の読み込み 23 | 24 | 3. パスの初期化 25 | - 各種設定ファイルのパス設定 26 | - ログファイルのパス設定 27 | - 実行ファイルのパス設定 28 | 29 | 4. 環境設定の初期化 30 | - HTTPヘッダーの設定 31 | - GeoIP情報の設定 32 | - ロックファイル用変数の初期化 33 | 34 | .NOTES 35 | 前提条件: 36 | - Windows、Linux、またはmacOS環境で実行する必要があります 37 | - PowerShell 7.0以上を推奨します 38 | - TVerRecの設定ファイルが正しく設定されている必要があります 39 | - 十分なディスク容量が必要です 40 | - インターネット接続が必要です 41 | - TVerのアカウントが必要な場合があります 42 | 43 | 主要な機能: 44 | - 子プロセス用の軽量な初期設定 45 | - 必要最小限の設定ファイル読み込み 46 | - パス設定の初期化 47 | - 実行環境の基本設定 48 | 49 | 特徴: 50 | - メイン処理(initialize.ps1)より軽量 51 | - アップデートチェックなどの重い処理を省略 52 | - 子プロセスに必要な最小限の設定のみを実行 53 | 54 | .LINK 55 | https://github.com/dongaba/TVerRec 56 | #> 57 | 58 | Set-StrictMode -Version Latest 59 | Write-Debug ('{0}' -f $MyInvocation.MyCommand.Name) 60 | 61 | #---------------------------------------------------------------------- 62 | # メッセージファイル読み込み 63 | $script:langDir = Convert-Path (Join-Path $scriptRoot '../resources/lang') 64 | $script:uiCulture = [System.Globalization.CultureInfo]::CurrentUICulture.Name 65 | Write-Debug "Current Language: $script:uiCulture" 66 | $script:langFile = Get-Content -Path (Join-Path $script:langDir 'messages.json') | ConvertFrom-Json 67 | $script:msg = if (($script:langFile | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name).Contains($script:uiCulture)) { $script:langFile.$script:uiCulture } 68 | else { $defaultLang = 'en-US'; $script:langFile.$defaultLang } 69 | Write-Debug "Message Table Loaded: $script:uiCulture" 70 | 71 | #---------------------------------------------------------------------- 72 | # 設定ファイル読み込み 73 | $script:confDir = Convert-Path (Join-Path $script:scriptRoot '../conf') 74 | $script:devDir = Join-Path $script:scriptRoot '../dev' 75 | 76 | if ( Test-Path (Join-Path $script:confDir 'system_setting.ps1') ) { 77 | try { . (Convert-Path (Join-Path $script:confDir 'system_setting.ps1')) } 78 | catch { throw ($script:msg.LoadSystemSettingFailed) } 79 | } else { throw ($script:msg.SystemSettingNotFound) } 80 | 81 | if ( Test-Path (Join-Path $script:confDir 'user_setting.ps1') ) { 82 | try { . (Convert-Path (Join-Path $script:confDir 'user_setting.ps1')) } 83 | catch { throw ($script:msg.LoadUserSettingFailed) } 84 | } else { throw ($script:msg.UserSettingNotCompleted) } 85 | if ($script:preferredLanguage) { 86 | $script:msg = if (($script:langFile | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name).Contains($script:preferredLanguage)) { $script:langFile.$script:preferredLanguage } 87 | else { $defaultLang = 'en-US'; $script:langFile.$defaultLang } 88 | } 89 | 90 | #---------------------------------------------------------------------- 91 | # 外部関数ファイルの読み込み 92 | try { . (Convert-Path (Join-Path $script:scriptRoot 'functions/common_functions.ps1')) } 93 | catch { throw ($script:msg.LoadCommonFuncFailed) } 94 | try { . (Convert-Path (Join-Path $script:scriptRoot 'functions/tver_functions.ps1')) } 95 | catch { throw ($script:msg.LoadTVerFuncFailed) } 96 | try { . (Convert-Path (Join-Path $script:scriptRoot 'functions/tverrec_functions.ps1')) } 97 | catch { throw ($script:msg.LoadTVerRecFuncFailed) } 98 | 99 | #---------------------------------------------------------------------- 100 | # 開発環境用に設定上書き 101 | try { 102 | $devFunctionFile = Join-Path $script:devDir 'dev_functions.ps1' 103 | $devConfFile = Join-Path $script:devDir 'dev_setting.ps1' 104 | if (Test-Path $devConfFile) { . $devConfFile ; Write-Output ($script:msg.DevConfLoaded) } 105 | if (Test-Path $devFunctionFile) { . $devFunctionFile ; Write-Output ($script:msg.DevFuncLoaded) } 106 | Remove-Variable -Name devFunctionFile, devConfFile -ErrorAction SilentlyContinue 107 | } catch { throw ($script:msg.LoadDevFilesFailed) } 108 | 109 | #---------------------------------------------------------------------- 110 | # ダウンロード対象キーワードのパス 111 | $script:keywordFileSamplePath = Join-Path $script:sampleDir 'keyword.sample.conf' 112 | $script:keywordFilePath = Join-Path $script:confDir 'keyword.conf' 113 | 114 | # ダウンロード対象外番組のパス 115 | $script:ignoreFileSamplePath = Join-Path $script:sampleDir 'ignore.sample.conf' 116 | $script:ignoreFilePath = Join-Path $script:confDir 'ignore.conf' 117 | $script:ignoreLockFilePath = Join-Path $script:lockDir 'ignore.lock' 118 | 119 | # ダウンロード履歴のパス 120 | $script:histFilePath = Join-Path $script:dbDir 'history.csv' 121 | $script:histFileSamplePath = Join-Path $script:sampleDir 'history.sample.csv' 122 | $script:histLockFilePath = Join-Path $script:lockDir 'history.lock' 123 | 124 | # ダウンロードリストのパス 125 | $script:listFilePath = Join-Path $script:listDir 'list.csv' 126 | $script:listFileSamplePath = Join-Path $script:sampleDir 'list.sample.csv' 127 | $script:listLockFilePath = Join-Path $script:lockDir 'list.lock' 128 | 129 | # ffmpegで番組検証時のエラーファイルのパス 130 | $script:ffmpegErrorLogPath = Join-Path $script:logDir ('ffmpeg_err_{0}.log' -f $PID) 131 | 132 | # youtube-dlでダウンロードするときのログファイルのパス 133 | $script:ytdlStdOutLogPath = Join-Path $script:logDir ('ytdl_out_{0}.log' -f $PID) 134 | $script:ytdlStdErrLogPath = Join-Path $script:logDir ('ytdl_err_{0}.log' -f $PID) 135 | 136 | # youtube-dlのパス 137 | if ($IsWindows) { $script:ytdlPath = Join-Path $script:binDir 'yt-dlp.exe' } 138 | else { $script:ytdlPath = Join-Path $script:binDir 'yt-dlp' } 139 | 140 | # ffmpegのパス 141 | if ($IsWindows) { $script:ffmpegPath = Join-Path $script:binDir 'ffmpeg.exe' } 142 | else { $script:ffmpegPath = Join-Path $script:binDir 'ffmpeg' } 143 | 144 | # ffprobeのパス 145 | if ($IsWindows) { $script:ffprobePath = Join-Path $script:binDir 'ffprobe.exe' } 146 | else { $script:ffprobePath = Join-Path $script:binDir 'ffprobe' } 147 | 148 | # 進捗表示 149 | if ($script:detailedProgress) { $InformationPreference = 'Continue' } 150 | else { $InformationPreference = 'SilentlyContinue' } 151 | 152 | # Geo IPのパス 153 | $script:jpIPList = Join-Path $script:geoIPDir 'jp.csv' 154 | 155 | # 共通HTTPヘッダ 156 | $script:jpIP = Get-JpIP 157 | Write-Output ('') 158 | Write-Output ($script:msg.JpIPFound -f $script:jpIP) 159 | $script:commonHttpHeader = @{ 160 | 'x-tver-platform-type' = 'web' 161 | 'Origin' = 'https://tver.jp' 162 | 'Referer' = 'https://tver.jp' 163 | 'Forwarded' = $script:jpIP 164 | 'Forwarded-For' = $script:jpIP 165 | 'X-Forwarded' = $script:jpIP 166 | 'X-Forwarded-For' = $script:jpIP 167 | 'X-Originating-IP' = $script:jpIP 168 | } 169 | 170 | # ロックファイル用 171 | $script:fileInfo = @{} 172 | $script:fileStream = @{} 173 | -------------------------------------------------------------------------------- /src/functions/update_youtube-dl.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # Windows用youtube-dl最新化処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecで使用するyt-dlpを最新バージョンに更新するスクリプト 9 | 10 | .DESCRIPTION 11 | yt-dlpの最新バージョンをダウンロードし、インストールします。 12 | 複数のソースから選択してダウンロードできます: 13 | - yt-dlp(標準版) 14 | - ytdl-patched(パッチ適用版) 15 | - yt-dlp-nightly(開発版) 16 | 17 | .NOTES 18 | 前提条件: 19 | - Windows、Linux、またはmacOS環境で実行する必要があります 20 | - PowerShell 7.0以上を推奨です 21 | - インターネット接続が必要です 22 | - TVerRecの設定ファイルが正しく設定されている必要があります 23 | - 設定ファイルでpreferredYoutubedlが正しく設定されている必要があります 24 | - 十分なディスク容量が必要です 25 | - 管理者権限が必要な場合があります 26 | 27 | 対応ソース: 28 | 1. yt-dlp (yt-dlp/yt-dlp) 29 | - 安定版 30 | - 一般利用向け 31 | 2. ytdl-patched (ytdl-patched/ytdl-patched) 32 | - パッチ適用版 33 | - 追加機能対応 34 | 3. yt-dlp-nightly (yt-dlp/yt-dlp-nightly-builds) 35 | - 開発版 36 | - 最新機能テスト用 37 | 38 | 処理の流れ: 39 | 1. 現在の環境確認 40 | 1.1 設定の読み込み 41 | 1.2 現在のバージョン確認 42 | 2. 最新版の確認 43 | 2.1 ソースの選択 44 | 2.2 最新バージョンの取得 45 | 3. 更新処理 46 | 3.1 ダウンロード 47 | 3.2 実行ファイルの配置 48 | 4. 検証 49 | 4.1 実行権限の設定 50 | 4.2 バージョン確認 51 | 52 | .EXAMPLE 53 | # スクリプトの実行(デフォルトのソース) 54 | .\update_youtube-dl.ps1 55 | 56 | .OUTPUTS 57 | System.Void 58 | このスクリプトは以下の出力を行います: 59 | - 現在のyt-dlpのバージョン 60 | - 利用可能な最新バージョン 61 | - ダウンロードの進捗状況 62 | - 更新処理の結果 63 | - エラー発生時のエラーメッセージ 64 | - デバッグ情報(設定時) 65 | 66 | .LINK 67 | https://github.com/dongaba/TVerRec 68 | #> 69 | 70 | Set-StrictMode -Version Latest 71 | Add-Type -AssemblyName System.IO.Compression.FileSystem | Out-Null 72 | 73 | #---------------------------------------------------------------------- 74 | # Zipファイルを解凍 75 | #---------------------------------------------------------------------- 76 | function Expand-Zip { 77 | [CmdletBinding()] 78 | [OutputType([Void])] 79 | Param ( 80 | [Parameter(Mandatory = $true)][String]$path, 81 | [Parameter(Mandatory = $true)][String]$destination 82 | ) 83 | Write-Debug ('{0} - {1}' -f $MyInvocation.MyCommand.Name, $path) 84 | if (Test-Path -Path $path) { 85 | Write-Verbose ('Extracting {0} into {1}' -f $path, $destination) 86 | [System.IO.Compression.ZipFile]::ExtractToDirectory($path, $destination, $true) 87 | Write-Verbose ('Extracted {0}' -f $path) 88 | } else { throw ($script:msg.FileNotFound -f $path) } 89 | Remove-Variable -Name path, destination -ErrorAction SilentlyContinue 90 | } 91 | 92 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 93 | # 環境設定 94 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 95 | try { 96 | if ($myInvocation.MyCommand.CommandType -eq 'ExternalScript') { $scriptRoot = Split-Path -Parent -Path (Split-Path -Parent -Path $myInvocation.MyCommand.Definition) } 97 | else { $scriptRoot = Convert-Path .. } 98 | Set-Location $script:scriptRoot 99 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 100 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 101 | 102 | #---------------------------------------------------------------------- 103 | # メッセージファイル読み込み 104 | $script:langDir = Convert-Path (Join-Path $scriptRoot '../resources/lang') 105 | $script:uiCulture = [System.Globalization.CultureInfo]::CurrentUICulture.Name 106 | Write-Debug "Current Language: $script:uiCulture" 107 | $script:langFile = Get-Content -Path (Join-Path $script:langDir 'messages.json') | ConvertFrom-Json 108 | $script:msg = if (($script:langFile | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name).Contains($script:uiCulture)) { $script:langFile.$script:uiCulture } 109 | else { $defaultLang = 'en-US'; $script:langFile.$defaultLang } 110 | Write-Debug "Message Table Loaded: $script:uiCulture" 111 | 112 | #---------------------------------------------------------------------- 113 | # 設定ファイル読み込み 114 | $script:confDir = Convert-Path (Join-Path $script:scriptRoot '../conf') 115 | if ( Test-Path (Join-Path $script:confDir 'system_setting.ps1') ) { 116 | try { . (Convert-Path (Join-Path $script:confDir 'system_setting.ps1')) } 117 | catch { throw ($script:msg.LoadSystemSettingFailed) } 118 | } else { throw ($script:msg.SystemSettingNotFound) } 119 | if ( Test-Path (Join-Path $script:confDir 'user_setting.ps1') ) { 120 | try { . (Convert-Path (Join-Path $script:confDir 'user_setting.ps1')) } 121 | catch { throw ($script:msg.LoadUserSettingFailed) } 122 | } elseif ($IsWindows) { 123 | Write-Output ($script:msg.UserSettingNeedsToBeCreated) 124 | try { & 'gui/gui_setting.ps1' } 125 | catch { throw ($script:msg.LoadSettingGUIFailed) } 126 | if ( Test-Path (Join-Path $script:confDir 'user_setting.ps1') ) { 127 | try { . (Convert-Path (Join-Path $script:confDir 'user_setting.ps1')) } 128 | catch { throw ($script:msg.LoadUserSettingFailed) } 129 | } else { throw ($script:msg.UserSettingNotCompleted) } 130 | } else { throw ($script:msg.UserSettingNotCompleted) } 131 | if ($script:preferredLanguage) { 132 | $script:msg = if (($script:langFile | Get-Member -MemberType NoteProperty | Select-Object -ExpandProperty Name).Contains($script:preferredLanguage)) { $script:langFile.$script:preferredLanguage } 133 | else { $defaultLang = 'en-US'; $script:langFile.$defaultLang } 134 | } 135 | 136 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 137 | # メイン処理 138 | 139 | # youtube-dl移動先相対Path 140 | if ($IsWindows) { $ytdlPath = Join-Path $script:binDir 'yt-dlp.exe' } 141 | else { $ytdlPath = Join-Path $script:binDir 'yt-dlp' } 142 | 143 | # githubの設定 144 | $lookupTable = @{ 145 | 'yt-dlp' = 'yt-dlp/yt-dlp' 146 | 'ytdl-patched' = 'ytdl-patched/ytdl-patched' 147 | 'yt-dlp-nightly' = 'yt-dlp/yt-dlp-nightly-builds' 148 | } 149 | if ($lookupTable.ContainsKey($script:preferredYoutubedl)) { $repo = $lookupTable[$script:preferredYoutubedl] } 150 | else { Write-Warning ($script:msg.ToolInvalidSource -f $script:preferredYoutubedl) ; return } 151 | $releases = ('https://api.github.com/repos/{0}/releases' -f $repo) 152 | 153 | # youtube-dlのバージョン取得 154 | try { 155 | if (Test-Path $ytdlPath -PathType Leaf) { $currentVersion = (& $ytdlPath --version) } 156 | else { $currentVersion = '' } 157 | } catch { $currentVersion = '' } 158 | 159 | # youtube-dlの最新バージョン取得 160 | try { $latestVersion = (Invoke-RestMethod -Uri $releases -Method 'GET' -TimeoutSec $script:timeoutSec)[0].Tag_Name } 161 | catch { Write-Warning ($script:msg.ToolLatestNotIdentified -f $script:preferredYoutubedl) ; return } 162 | 163 | # youtube-dlのダウンロード 164 | if ($latestVersion -eq $currentVersion) { 165 | Write-Output ('') 166 | Write-Output ($script:msg.ToolUpToDate -f $script:preferredYoutubedl) 167 | Write-Output ($script:msg.ToolLocalVersion -f $currentVersion) 168 | Write-Output ($script:msg.ToolRemoteVersion -f $latestVersion) 169 | } else { 170 | Write-Output ('') 171 | Write-Warning ($script:msg.ToolOutdated -f $script:preferredYoutubedl) 172 | Write-Output ($script:msg.ToolLocalVersion -f $currentVersion) 173 | Write-Output ($script:msg.ToolRemoteVersion -f $latestVersion) 174 | if ($script:preferredYoutubedl -eq 'yt-dlp-nightly') { $downloadFileName = 'yt-dlp' } 175 | else { $downloadFileName = $script:preferredYoutubedl } 176 | if (!$IsWindows) { $fileBeforeRename = $downloadFileName ; $fileAfterRename = 'yt-dlp' } 177 | else { $fileBeforeRename = ('{0}.exe' -f $downloadFileName) ; $fileAfterRename = 'yt-dlp.exe' } 178 | Write-Output ($script:msg.ToolDownload -f $script:preferredYoutubedl, [String]([System.Runtime.InteropServices.RuntimeInformation]::OSDescription).split()[0..1]) 179 | try { 180 | #ダウンロード 181 | $tag = (Invoke-RestMethod -Uri $releases -Method 'GET' -TimeoutSec $script:timeoutSec)[0].Tag_Name 182 | $downloadURL = ('https://github.com/{0}/releases/download/{1}/{2}' -f $repo, $tag, $fileBeforeRename) 183 | $ytdlFileLocation = Join-Path $script:binDir $fileAfterRename 184 | Invoke-WebRequest -Uri $downloadURL -Out $ytdlFileLocation -TimeoutSec $script:timeoutSec 185 | } catch { Write-Warning ($script:msg.ToolDownloadFailed -f $script:preferredYoutubedl) ; return } 186 | if (!$IsWindows) { (& chmod a+x $ytdlFileLocation) } 187 | 188 | # バージョンチェック 189 | try { 190 | $currentVersion = (& $ytdlPath --version) 191 | Write-Output ($script:msg.ToolUpdated -f $script:preferredYoutubedl, $currentVersion) 192 | } catch { Write-Warning $script:msg.ToolVersionCheckFailed ; return } 193 | 194 | } 195 | 196 | Remove-Variable -Name lookupTable, releases, ytdlPath, currentVersion, latestVersion, file, fileAfterRename, fileBeforeRename, tag, downloadURL, ytdlFileLocation -ErrorAction SilentlyContinue 197 | -------------------------------------------------------------------------------- /src/generate_list.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 番組リストファイル出力処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecのダウンロードリストを生成するスクリプト 9 | 10 | .DESCRIPTION 11 | キーワードリストから番組を検索し、ダウンロードリストを生成します。 12 | 以下の処理を順番に実行します: 13 | 1. キーワードリストの読み込み 14 | 2. 各キーワードでの番組検索 15 | 3. ダウンロード履歴との照合 16 | 4. ダウンロードリストの生成 17 | 18 | .PARAMETER guiMode 19 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 20 | - 指定なし: 通常モードで実行 21 | - 'gui': GUIモードで実行 22 | - その他の値: 通常モードで実行 23 | 24 | .NOTES 25 | 前提条件: 26 | - Windows、Linux、またはmacOS環境で実行する必要があります 27 | - PowerShell 7.0以上を推奨します 28 | - TVerRecの設定ファイルが正しく設定されている必要があります 29 | - keyword.confにキーワードが記載されている必要があります 30 | - インターネット接続が必要です 31 | - TVerのアカウントが必要な場合があります 32 | 33 | 処理の流れ: 34 | 1. 初期設定 35 | 1.1 環境チェック 36 | 1.2 キーワードリストの読み込み 37 | 1.3 トークンの取得 38 | 2. キーワード処理 39 | 2.1 各キーワードでの番組検索 40 | 2.2 ダウンロード履歴との照合 41 | 2.3 重複チェック 42 | 3. 並列処理 43 | 3.1 マルチスレッド有効時は処理を分割 44 | 3.2 子プロセスでの番組情報取得 45 | 3.3 結果の統合 46 | 4. リスト生成 47 | 4.1 番組情報の整理 48 | 4.2 ダウンロードリストの出力 49 | 50 | .EXAMPLE 51 | # 通常モードで実行 52 | .\generate_list.ps1 53 | 54 | # GUIモードで実行 55 | .\generate_list.ps1 gui 56 | 57 | .OUTPUTS 58 | System.Void 59 | このスクリプトは以下の出力を行います: 60 | - コンソールへの進捗状況の表示 61 | - トースト通知による進捗状況の表示 62 | - エラー発生時のエラーメッセージ 63 | - 処理完了時のサマリー情報 64 | #> 65 | 66 | Set-StrictMode -Version Latest 67 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 68 | 69 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 70 | # 環境設定 71 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 72 | try { 73 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 74 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 75 | Set-Location $script:scriptRoot 76 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 77 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 78 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 79 | 80 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 81 | # メイン処理 82 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 83 | try { 84 | # 必須ファイルのチェックとトークンの取得 85 | Invoke-RequiredFileCheck 86 | Suspend-Process 87 | Get-Token 88 | 89 | # キーワードリストの読み込み 90 | $keywords = @(Read-KeywordList) 91 | if ($keywords.Count -eq 0) { throw 'キーワードリストが空です。処理を中断します。' } 92 | else { $keywordTotal = $keywords.Count } 93 | $keywordNum = 0 94 | 95 | # 進捗表示の初期化 96 | $toastShowParams = @{ 97 | Text1 = $script:msg.ListCreation 98 | Text2 = $script:msg.ExtractAndCreateListFromKeywords 99 | WorkDetail = $script:msg.Loading 100 | Tag = $script:appName 101 | Silent = $false 102 | Group = 'ListGen' 103 | } 104 | Show-ProgressToast @toastShowParams 105 | 106 | #====================================================================== 107 | # ビデオリンクの収集 108 | #====================================================================== 109 | $totalStartTime = Get-Date 110 | $allEpisodeIDs = @() 111 | 112 | foreach ($keyword in $keywords) { 113 | $keywordNum++ 114 | $keyword = Remove-TabSpace($keyword) 115 | 116 | Write-Output ('') 117 | Write-Output ($script:msg.MediumBoldBorder) 118 | Write-Output ('{0}' -f $keyword) 119 | 120 | # 進捗情報の更新 121 | $secElapsed = (Get-Date) - $totalStartTime 122 | if ($keywordNum -ne 0) { 123 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $keywordNum) * ($keywordTotal - $keywordNum)) 124 | $minRemaining = ('{0}分' -f ([Int][Math]::Ceiling($secRemaining / 60))) 125 | } else { $minRemaining = '' } 126 | 127 | $toastUpdateParams = @{ 128 | Title = (Remove-TabSpace ($keyword)) 129 | Rate = [Float]($keywordNum / $keywordTotal) 130 | LeftText = ('{0}/{1}' -f $keywordNum, $keywordTotal) 131 | RightText = $minRemaining 132 | Tag = $script:appName 133 | Group = 'ListGen' 134 | } 135 | Update-ProgressToast @toastUpdateParams 136 | 137 | $keyword = Get-ContentWoComment($keyword.Replace('https://tver.jp/', '').Trim()) 138 | $resultLinks = @(Get-VideoLinksFromKeyword $keyword) 139 | 140 | # 履歴チェックと重複排除 141 | if ($resultLinks.Count -ne 0) { 142 | if ($script:listGenHistoryCheck) { $episodeIDs, $processedCount = Invoke-HistoryAndListMatchCheck $resultLinks } 143 | else { $episodeIDs, $processedCount = Invoke-ListMatchCheck $resultLinks } 144 | } else { $episodeIDs = @() ; $processedCount = 0 } 145 | 146 | $videoCount = $episodeIDs.Count 147 | if ($videoCount -eq 0) { Write-Output ($script:msg.VideoCountWhenZero -f $videoCount, $processedCount) } 148 | else { Write-Output ($script:msg.VideoCountNonZero -f $videoCount, $processedCount) } 149 | 150 | $allEpisodeIDs += $episodeIDs 151 | } 152 | 153 | $allEpisodeIDs = $allEpisodeIDs | Sort-Object -Unique 154 | 155 | #====================================================================== 156 | # 個々の番組の情報の取得 157 | #====================================================================== 158 | # if ($script:enableMultithread) { 159 | # Write-Debug ('Multithread Processing Enabled') 160 | # # 並列化が有効の場合は並列化 161 | # if ($allEpisodeIDs -ne 0) { 162 | # # 配列を分割 163 | # $partitions = @{} 164 | # $totalCount = $allEpisodeIDs.Count 165 | # $partitionSize = [math]::Ceiling($totalCount / $script:multithreadNum) 166 | # for ($i = 0 ; $i -lt $script:multithreadNum ; $i++) { 167 | # $startIndex = $i * $partitionSize 168 | # $endIndex = [math]::Min(($i + 1) * $partitionSize, $totalCount) 169 | # if ($startIndex -lt $totalCount) { $partitions[$i] = $allEpisodeIDs[$startIndex..($endIndex - 1)] } 170 | # } 171 | 172 | # $paraJobSBs = @{} 173 | # $paraJobDefs = @{} 174 | # $paraJobs = @{} 175 | # Write-Output ($script:msg.DisclaimerForMultithread) 176 | # for ($i = 0 ; $i -lt $partitions.Count ; $i++) { 177 | # $links = [String]$partitions[$i] 178 | # $paraJobSBs[$i] = ("& ./generate_list_child.ps1 $keyword $links") 179 | # $paraJobDefs[$i] = [ScriptBlock]::Create($paraJobSBs[$i]) 180 | # $paraJobs[$i] = Start-ThreadJob -ScriptBlock $paraJobDefs[$i] 181 | # } 182 | # do { 183 | # $completedJobs = Get-Job -State Completed 184 | # foreach ($job in $completedJobs) { Write-Output (Receive-Job -Job $job) ; Remove-Job -Job $job } 185 | # Remove-Job -State Failed, Stopped, Suspended, Disconnected 186 | # $remainingJobs = Get-Job 187 | # Start-Sleep -Milliseconds 500 188 | # } while ($remainingJobs) 189 | # } 190 | # } else { 191 | # 並列化が無効の場合は従来型処理 192 | $listGenStartTime = Get-Date 193 | $videoTotal = $allEpisodeIDs.Count 194 | $videoNum = 0 195 | foreach ($episodeID in $allEpisodeIDs) { 196 | $videoNum++ 197 | 198 | # 進捗率の計算 199 | $secElapsed = (Get-Date) - $listGenStartTime 200 | if ($videoNum -ne 0) { 201 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $videoNum) * ($videoTotal - $videoNum)) 202 | $minRemaining = ('{0}分' -f ([Int][Math]::Ceiling($secRemaining / 60))) 203 | } else { $minRemaining = '' } 204 | 205 | $toastUpdateParams = @{ 206 | Title = $episodeID 207 | Rate = [Float]($videoNum / $videoTotal) 208 | LeftText = ('{0}/{1}' -f $videoNum, $videoTotal) 209 | RightText = $minRemaining 210 | Tag = $script:appName 211 | Group = 'ListGen' 212 | } 213 | Update-ProgressToast @toastUpdateParams 214 | 215 | Write-Output (' {0}/{1} - {2}' -f $videoNum, $videoTotal, $episodeID) 216 | # TVer番組ダウンロードのメイン処理 217 | Update-VideoList -Keyword $keyword -EpisodeID $episodeID 218 | } 219 | # } 220 | #---------------------------------------------------------------------- 221 | 222 | 223 | #====================================================================== 224 | # 後処理 225 | #====================================================================== 226 | $toastUpdateParams = @{ 227 | Title = $script:msg.ExtractingVideoFromKeywords 228 | Rate = 1 229 | LeftText = '' 230 | RightText = $script:msg.Completed 231 | Tag = $script:appName 232 | Group = 'ListGen' 233 | } 234 | Update-ProgressToast @toastUpdateParams 235 | 236 | Write-Output ('') 237 | Write-Output ($script:msg.LongBoldBorder) 238 | Write-Output ($script:msg.ListCreationCompleted) 239 | Write-Output ($script:msg.ListCreationCompletionMessage1) 240 | Write-Output ($script:msg.ListCreationCompletionMessage2 -f $script:listFilePath) 241 | Write-Output ($script:msg.LongBoldBorder) 242 | } catch { 243 | Write-Error "Error occurred: $($_.Exception.Message)" 244 | Write-Error "Stack trace: $($_.ScriptStackTrace)" 245 | throw 246 | } finally { 247 | # 変数のクリーンアップ 248 | Remove-Variable -Name args, keywords, keywordNum, keywordTotal, toastShowParams, totalStartTime, keyword, listLinks, videoLinks, processedCount, videoTotal, secElapsed, secRemaining1, toastUpdateParams, partitions, totalCount, partitionSize, i, startIndex, endIndex, videoNum, paraJobSBs, paraJobDefs, paraJobs, links, completedJobs, job, remainingJobs, videoLink -ErrorAction SilentlyContinue 249 | 250 | # ガベージコレクション 251 | Invoke-GarbageCollection 252 | } 253 | -------------------------------------------------------------------------------- /src/generate_list_child.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 番組リストファイル出力処理 - 再帰呼び出し子スレッド用スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecのダウンロードリスト生成の子プロセス処理スクリプト 9 | 10 | .DESCRIPTION 11 | generate_list.ps1から呼び出される子プロセス用スクリプトです。 12 | マルチスレッド処理時に並列で番組情報を取得します。 13 | 以下の機能を提供します: 14 | 1. キーワードに基づく番組情報の取得 15 | 2. 複数URLの並列処理 16 | 3. リストファイルの更新 17 | 18 | .PARAMETER args 19 | 必須パラメータ。以下の順序で指定します: 20 | 1. キーワード(String) 21 | 2. 番組URL(String配列) 22 | 23 | .NOTES 24 | 前提条件: 25 | - Windows、Linux、またはmacOS環境で実行する必要があります 26 | - PowerShell 7.0以上を推奨します 27 | - TVerRecの設定ファイルが正しく設定されている必要があります 28 | - generate_list.ps1から呼び出される必要があります 29 | - 必要なパラメータが正しく渡される必要があります 30 | - インターネット接続が必要です 31 | - TVerのアカウントが必要な場合があります 32 | 33 | 処理の流れ: 34 | 1. 初期設定 35 | 1.1 環境チェック 36 | 1.2 パラメータの検証 37 | 1.3 トークンの取得 38 | 2. 番組情報処理 39 | 2.1 各URLの処理 40 | 2.2 番組情報の取得 41 | 2.3 リストの更新 42 | 43 | .EXAMPLE 44 | # 直接実行は想定されていません 45 | # generate_list.ps1から以下の形式で呼び出されます 46 | .\generate_list_child.ps1 "キーワード" "URL1" "URL2" ... 47 | 48 | .OUTPUTS 49 | System.Void 50 | このスクリプトは以下の出力を行います: 51 | - コンソールへの進捗状況の表示 52 | - エラー発生時のエラーメッセージ 53 | - 処理完了時のサマリー情報 54 | - 更新されたリストファイル 55 | #> 56 | 57 | Set-StrictMode -Version Latest 58 | Write-Debug ('{0}' -f $MyInvocation.MyCommand.Name) 59 | 60 | if ($args.Count -ge 2) { 61 | $keyword = [String]$args[0] 62 | $episodeIDs = $args[1..($args.Count - 1)] 63 | } else { throw ('❌️ 子プロセスの引数が不足しています。Arguments for child process are missing') } 64 | 65 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 66 | # 環境設定 67 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 68 | try { 69 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 70 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 71 | Set-Location $script:scriptRoot 72 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 73 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 74 | try { 75 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize_child.ps1')) 76 | } catch { throw ('❌️ 関数の読み込みに失敗しました。Failed to load function.') } 77 | 78 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79 | # メイン処理 80 | Get-Token 81 | foreach ($episodeID in $episodeIDs) { 82 | Write-Output (' {0}' -f $episodeID) 83 | Update-VideoList -Keyword $keyword -EpisodeID $episodeID 84 | } 85 | 86 | Remove-Variable -Name keyword, videoLinks, videoLink -ErrorAction SilentlyContinue 87 | -------------------------------------------------------------------------------- /src/loop.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # ループ処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecのメインループ処理を実行するスクリプト 9 | 10 | .DESCRIPTION 11 | TVerRecの主要な処理を定期的に実行するループスクリプトです。 12 | 以下の処理を順番に実行します: 13 | 1. 一括ダウンロード処理 14 | 2. ゴミ箱の削除処理 15 | 3. 動画の検証処理 16 | 4. 動画の移動処理 17 | 各処理の間には指定された待機時間が設定されています。 18 | 19 | .PARAMETER guiMode 20 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 21 | - 指定なし: 通常モードで実行 22 | - 'gui': GUIモードで実行 23 | - その他の値: 通常モードで実行 24 | 25 | .NOTES 26 | 前提条件: 27 | - Windows、Linux、またはmacOS環境で実行する必要があります 28 | - PowerShell 7.0以上を推奨します 29 | - TVerRecの設定ファイルが正しく設定されている必要があります 30 | - 十分なディスク容量が必要です 31 | - インターネット接続が必要です 32 | - TVerのアカウントが必要な場合があります 33 | 34 | 処理の流れ: 35 | 1. 環境設定の読み込み 36 | 2. メインループの開始 37 | 3. 各処理の実行 38 | 4. 待機時間のカウントダウン表示 39 | 5. 次のループへ 40 | 41 | .EXAMPLE 42 | # 通常モードで実行 43 | .\loop.ps1 44 | 45 | # GUIモードで実行 46 | .\loop.ps1 gui 47 | 48 | .OUTPUTS 49 | System.Void 50 | このスクリプトは以下の出力を行います: 51 | - コンソールへの進捗状況の表示 52 | - トースト通知による進捗状況の表示 53 | - エラー発生時のエラーメッセージ 54 | - 処理完了時のサマリー情報 55 | - 各処理の実行結果 56 | #> 57 | 58 | Set-StrictMode -Version Latest 59 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 60 | 61 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 62 | # 環境設定 63 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 64 | try { 65 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 66 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 67 | Set-Location $script:scriptRoot 68 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 69 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 70 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 'loop' 71 | 72 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 73 | # メイン処理 74 | #---------------------------------------------------------------------- 75 | while ($true) { 76 | & ('{0}/download_bulk.ps1' -f $script:scriptRoot) $script:guiMode 77 | & ('{0}/delete_trash.ps1' -f $script:scriptRoot) $script:guiMode 78 | & ('{0}/validate_video.ps1' -f $script:scriptRoot) $script:guiMode 79 | & ('{0}/move_video.ps1' -f $script:scriptRoot) $script:guiMode 80 | Invoke-GarbageCollection 81 | Write-Output ('') 82 | Write-Output ($script:msg.SecWaiting -f $script:loopCycle) 83 | $remainingWaitTime = $script:loopCycle 84 | while ($remainingWaitTime -ge 100) { 85 | Start-Sleep -Second 100 86 | $remainingWaitTime -= 100 87 | $progressRatio = [Int]($remainingWaitTime / $script:loopCycle * 100 / 2 ) 88 | Write-Output ($script:msg.SecWaitRemaining -f $('█' * $(50 - $progressRatio)), $('▁' * $progressRatio), $remainingWaitTime) 89 | Invoke-GarbageCollection 90 | } 91 | } 92 | #---------------------------------------------------------------------- 93 | 94 | Remove-Variable -Name args, remainingWaitTime, progressRatio -ErrorAction SilentlyContinue 95 | 96 | Invoke-GarbageCollection 97 | -------------------------------------------------------------------------------- /src/move_video.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 番組移動処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecでダウンロードした番組を指定のディレクトリに移動するスクリプト 9 | 10 | .DESCRIPTION 11 | ダウンロードした番組を指定の保存先ディレクトリに移動し、空のディレクトリを削除します。 12 | 以下の処理を順番に実行します: 13 | 1. 移動先ディレクトリの一覧取得 14 | 2. ダウンロードディレクトリの一覧取得 15 | 3. 番組ファイルの移動 16 | 4. 空ディレクトリの削除 17 | 18 | .PARAMETER guiMode 19 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 20 | - 指定なし: 通常モードで実行 21 | - 'gui': GUIモードで実行 22 | - その他の値: 通常モードで実行 23 | 24 | .NOTES 25 | 前提条件: 26 | - Windows、Linux、またはmacOS環境で実行する必要があります 27 | - PowerShell 7.0以上を推奨します 28 | - TVerRecの設定ファイルが正しく設定されている必要があります 29 | - 保存先ディレクトリが設定されている必要があります 30 | - 十分なディスク容量が必要です 31 | - インターネット接続が必要です 32 | 33 | 処理の流れ: 34 | 1. 移動先ディレクトリの処理 35 | 1.1 保存先ディレクトリ配下のディレクトリ一覧を取得 36 | 1.2 ジャンクションやシンボリックリンクを解決 37 | 2. ダウンロードディレクトリの処理 38 | 2.1 動画ファイルを含むディレクトリを特定 39 | 2.2 移動先ディレクトリと名前が一致するものを抽出 40 | 3. ファイル移動の処理 41 | 3.1 同名ディレクトリ間でファイルを移動 42 | 3.2 エラー発生時は警告を表示 43 | 4. クリーンアップ処理 44 | 4.1 空ディレクトリを特定 45 | 4.2 並列処理による空ディレクトリの削除 46 | 47 | .EXAMPLE 48 | # 通常モードで実行 49 | .\move_video.ps1 50 | 51 | # GUIモードで実行 52 | .\move_video.ps1 gui 53 | 54 | .OUTPUTS 55 | System.Void 56 | このスクリプトは以下の出力を行います: 57 | - コンソールへの進捗状況の表示 58 | - トースト通知による進捗状況の表示 59 | - エラー発生時のエラーメッセージ 60 | - 処理完了時のサマリー情報 61 | - 移動したファイルの一覧 62 | #> 63 | 64 | Set-StrictMode -Version Latest 65 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 66 | 67 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 68 | # 環境設定 69 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 70 | try { 71 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 72 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 73 | Set-Location $script:scriptRoot 74 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 75 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 76 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 77 | 78 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 79 | # メイン処理 80 | Invoke-RequiredFileCheck 81 | Suspend-Process 82 | 83 | #====================================================================== 84 | # 1/3移動先ディレクトリを起点として、配下のディレクトリを取得 85 | Write-Output ('') 86 | Write-Output ($script:msg.MediumBoldBorder) 87 | Write-Output ($script:msg.ListUpDestinationDirs) 88 | 89 | $toastShowParams = @{ 90 | Text1 = $script:msg.MoveVideos 91 | Text2 = $script:msg.MoveVideosStep1 92 | WorkDetail = '' 93 | Tag = $script:appName 94 | Silent = $false 95 | Group = 'Move' 96 | } 97 | Show-ProgressToast @toastShowParams 98 | 99 | # プラットフォームに応じたディレクトリ一覧を取得する関数 100 | function Get-DirectoriesWithPlatformCheck { 101 | Param ([String[]]$paths) 102 | $results = New-Object System.Collections.Generic.List[String] 103 | if ($IsWindows) { 104 | # PowerShellではジャンクションの展開ができないので、cmd.exeを使ってジャンクションを解決する 105 | foreach ($path in $paths) { 106 | $dirCmd = "dir `"$path`" /s /b /a:d" 107 | $resultTemp = [String[]](& cmd /c $dirCmd) 108 | if ($resultTemp) { $results.AddRange($resultTemp ) } 109 | } 110 | } else { 111 | # 念の為、Linux/Macでもfindを使う 112 | foreach ($path in $paths) { 113 | $findCmd = "find `"$path`" -type d" 114 | $resultTemp = [String[]](& sh -c $findCmd) 115 | if ($resultTemp) { $results.AddRange($resultTemp ) } 116 | } 117 | } 118 | return $results 119 | } 120 | 121 | # 移動先ディレクトリ配下のディレクトリ一覧 122 | $moveToPathsHash = @{} 123 | if ($script:saveBaseDir) { 124 | $script:saveBaseDirArray = $script:saveBaseDir.Split(';').Trim() 125 | $saveBaseDirs = Get-DirectoriesWithPlatformCheck -paths $script:saveBaseDirArray 126 | foreach ($saveBaseDir in $saveBaseDirs) { 127 | $saveBaseDirLeaf = Split-Path -Leaf $saveBaseDir 128 | $moveToPathsHash[$saveBaseDirLeaf] = $saveBaseDir 129 | } 130 | } 131 | 132 | # ダウンロードディレクトリ配下のディレクトリ一覧 133 | Write-Output ('') 134 | Write-Output ($script:msg.MediumBoldBorder) 135 | Write-Output ($script:msg.ListUpSourceDirs) 136 | $moveFromPathsHash = @{} 137 | if ($script:saveBaseDir) { 138 | $moveFromFiles = Get-ChildItem -LiteralPath $script:downloadBaseDir -Include @('*.mp4', '*.ts') -Recurse -File -Force -ErrorAction SilentlyContinue 139 | foreach ($moveFromFile in $moveFromFiles) { 140 | $moveFromDirName = $moveFromFile.Directory.Name 141 | if (-not $moveFromPathsHash.ContainsKey($moveFromDirName)) { $moveFromPathsHash[$moveFromDirName] = $moveFromFile.Directory.FullName } 142 | } 143 | } 144 | 145 | # 移動先ディレクトリとダウンロードディレクトリの一致を抽出 146 | Write-Output ('') 147 | Write-Output ($script:msg.MediumBoldBorder) 148 | Write-Output ($script:msg.MatchingTargetAndSource) 149 | if ($moveToPathsHash.Count -gt 0) { 150 | $moveDirs = New-Object System.Collections.Generic.List[Object] 151 | foreach ($item in Compare-Object -ReferenceObject @($moveToPathsHash.Keys) -DifferenceObject @($moveFromPathsHash.Keys) -IncludeEqual -ExcludeDifferent) { 152 | $moveDirs.Add($item.InputObject) 153 | } 154 | } else { $moveDirs = $null } 155 | 156 | #====================================================================== 157 | # 2/3移動先ディレクトリと同名のディレクトリ配下の番組を移動 158 | Write-Output ('') 159 | Write-Output ($script:msg.MediumBoldBorder) 160 | Write-Output ($script:msg.MovingVideos) 161 | 162 | $toastShowParams.Text2 = $script:msg.MoveVideosStep2 163 | Show-ProgressToast @toastShowParams 164 | 165 | #---------------------------------------------------------------------- 166 | $totalStartTime = Get-Date 167 | if ($moveDirs) { 168 | $dirNum = 0 169 | $dirTotal = $moveDirs.Count 170 | foreach ($dir in $moveDirs) { 171 | # 処理時間の推計 172 | $secElapsed = (Get-Date) - $totalStartTime 173 | $secRemaining = -1 174 | if ($dirNum -ne 0) { 175 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $dirNum) * ($dirTotal - $dirNum)) 176 | $minRemaining = ($script:msg.MinRemaining -f ([Int][Math]::Ceiling($secRemaining / 60))) 177 | $progressRate = [Float]($dirNum / $dirTotal) 178 | } else { $minRemaining = '' ; $progressRate = 0 } 179 | $dirNum++ 180 | 181 | $toastUpdateParams = @{ 182 | Title = $dir 183 | Rate = $progressRate 184 | LeftText = ('{0}/{1}' -f $dirNum, $dirTotal) 185 | RightText = $minRemaining 186 | Tag = $script:appName 187 | Group = 'Move' 188 | } 189 | Update-ProgressToast @toastUpdateParams 190 | 191 | # .Normalize([Text.NormalizationForm]::FormC) 192 | $moveFromPath = $moveFromPathsHash[$dir] ?? $moveFromPathsHash[$dir.Normalize([Text.NormalizationForm]::FormC)] 193 | $moveToPath = $moveToPathsHash[$dir] ?? $moveToPathsHash[$dir.Normalize([Text.NormalizationForm]::FormC)] 194 | 195 | # 同名ディレクトリが存在する場合は配下のファイルを移動 196 | if ((Test-Path -LiteralPath $moveFromPath) -and (Test-Path -LiteralPath $moveToPath)) { 197 | Write-Output (' {0}\* -> {1}' -f $moveFromPath, $moveToPath) 198 | try { Get-ChildItem -LiteralPath $moveFromPath -File | Move-Item -Destination $moveToPath -Force | Out-Null } 199 | catch { Write-Warning ($script:msg.MoveFileFailed -f $moveFromPath) } 200 | } else { Write-Warning ($script:msg.MoveFileNotAccessible -f $moveFromPath) } 201 | } 202 | } 203 | #---------------------------------------------------------------------- 204 | 205 | #====================================================================== 206 | # 3/3空ディレクトリと隠しファイルしか入っていないディレクトリを一気に削除 207 | Write-Output ('') 208 | Write-Output ($script:msg.MediumBoldBorder) 209 | Write-Output ($script:msg.DeleteEmptyDirs) 210 | 211 | $toastShowParams.Text2 = $script:msg.MoveVideosStep3 212 | Show-ProgressToast @toastShowParams 213 | 214 | if ($script:emptyDownloadBaseDir) { 215 | try { 216 | $emptyDirs = New-Object System.Collections.Generic.List[String] 217 | foreach ($dir in (Get-ChildItem -Path $script:downloadBaseDir -Directory -Recurse -ErrorAction SilentlyContinue)) { 218 | $files = $dir.GetFileSystemInfos() 219 | $visibleFiles = @($files | Where-Object { -not $_.Attributes.HasFlag([System.IO.FileAttributes]::Hidden) }) 220 | if ($visibleFiles.Count -eq 0) { $emptyDirs.Add($dir.FullName) } 221 | } 222 | } catch { $emptyDirs = @() } 223 | $emptyDirTotal = $emptyDirs.Count 224 | 225 | #---------------------------------------------------------------------- 226 | if ($emptyDirTotal -ne 0) { 227 | if ($script:enableMultithread) { 228 | Write-Debug ('Multithread Processing Enabled') 229 | # 並列化が有効の場合は並列化 230 | $emptyDirs | ForEach-Object -Parallel { 231 | $emptyDirNum = ([Array]::IndexOf($using:emptyDirs, $_)) + 1 232 | $emptyDirTotal = $using:emptyDirs.Count 233 | Write-Output (' {0}/{1} - {2}' -f $emptyDirNum, $emptyDirTotal, $_) 234 | try { Remove-Item -LiteralPath $_ -Recurse -Force | Out-Null } 235 | catch { Write-Warning ($script:msg.DeleteEmptyDirsFailed -f $_) } 236 | } -ThrottleLimit $script:multithreadNum 237 | } else { 238 | # 並列化が無効の場合は従来型処理 239 | $emptyDirNum = 0 240 | $emptyDirTotal = $emptyDirs.Count 241 | $totalStartTime = Get-Date 242 | foreach ($dir in $emptyDirs) { 243 | $emptyDirNum++ 244 | # 処理時間の推計 245 | $secElapsed = (Get-Date) - $totalStartTime 246 | $secRemaining = -1 247 | if ($emptyDirNum -ne 1) { 248 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $emptyDirNum) * ($emptyDirTotal - $emptyDirNum)) 249 | $minRemaining = ($script:msg.MinRemaining -f ([Int][Math]::Ceiling($secRemaining / 60))) 250 | $progressRate = [Float]($emptyDirNum / $emptyDirTotal) 251 | } else { $minRemaining = '' ; $progressRate = 0 } 252 | 253 | $toastUpdateParams.Title = $dir 254 | $toastUpdateParams.Rate = $progressRate 255 | $toastUpdateParams.LeftText = ('{0}/{1}' -f $emptyDirNum, $emptyDirTotal) 256 | $toastUpdateParams.RightText = $minRemaining 257 | Update-ProgressToast @toastUpdateParams 258 | 259 | Write-Output (' {0}/{1} - {2}' -f $emptyDirNum, $emptyDirTotal, $dir) 260 | try { Remove-Item -LiteralPath $dir -Recurse -Force -ErrorAction SilentlyContinue | Out-Null 261 | } catch { Write-Warning ($script:msg.DeleteEmptyDirsFailed -f $dir) } 262 | } 263 | } 264 | } 265 | #---------------------------------------------------------------------- 266 | } 267 | 268 | $toastUpdateParams = @{ 269 | Title = $script:msg.MoveVideo 270 | Rate = 1 271 | LeftText = '' 272 | RightText = $script:msg.Completed 273 | Tag = $script:appName 274 | Group = 'Move' 275 | } 276 | Update-ProgressToast @toastUpdateParams 277 | 278 | Remove-Variable -Name args, toastShowParams, moveToPathsHash, moveFromPathsHash, moveDirs, moveDir, totalStartTime, dirNum, dirTotal, dir, secElapsed, secRemaining, minRemaining, progressRate, toastUpdateParams, targetFolderName, moveFromPath, moveToPath, emptyDirs, emptyDirTotal, emptyDirNum -ErrorAction SilentlyContinue 279 | 280 | Invoke-GarbageCollection 281 | 282 | Write-Output ('') 283 | Write-Output ($script:msg.LongBoldBorder) 284 | Write-Output ($script:msg.MoveVideoCompleted) 285 | Write-Output ($script:msg.LongBoldBorder) 286 | -------------------------------------------------------------------------------- /src/validate_video.ps1: -------------------------------------------------------------------------------- 1 | ################################################################################### 2 | # 3 | # 番組整合性チェック処理スクリプト 4 | # 5 | ################################################################################### 6 | <# 7 | .SYNOPSIS 8 | TVerRecでダウンロードした番組の整合性をチェックするスクリプト 9 | 10 | .DESCRIPTION 11 | ダウンロードした番組ファイルの整合性チェックとダウンロード履歴の管理を行います。 12 | 以下の処理を順番に実行します: 13 | 1. ダウンロード履歴のクリーンアップ 14 | 2. 古い履歴レコードの削除 15 | 3. 重複レコードの削除 16 | 4. 番組ファイルの整合性チェック 17 | 5. 未検証ファイルの再チェック 18 | 19 | .PARAMETER guiMode 20 | オプションのパラメータ。GUIモードで実行するかどうかを指定します。 21 | - 指定なし: 通常モードで実行 22 | - 'gui': GUIモードで実行 23 | - その他の値: 通常モードで実行 24 | 25 | .NOTES 26 | 前提条件: 27 | - Windows、Linux、またはmacOS環境で実行する必要があります 28 | - PowerShell 7.0以上を推奨します 29 | - TVerRecの設定ファイルが正しく設定されている必要があります 30 | - ffmpegがインストールされている必要があります 31 | - ダウンロード履歴ファイルが存在する必要があります 32 | - 十分なディスク容量が必要です 33 | - インターネット接続が必要です 34 | 35 | 処理の流れ: 36 | 1. 履歴ファイルの管理 37 | 1.1 破損レコードの削除 38 | 1.2 古いレコードの削除(設定された保持期間に基づく) 39 | 1.3 重複レコードの削除 40 | 2. 整合性チェック 41 | 2.1 未検証ファイルの特定 42 | 2.2 ffmpegによる動画ファイルの検証 43 | 2.3 検証結果の記録 44 | 3. 再検証処理 45 | 3.1 検証中断ファイルの状態リセット 46 | 3.2 未検証ファイルの再チェック 47 | 4. 最終クリーンアップ 48 | 4.1 履歴ファイルの最適化 49 | 4.2 結果の確認 50 | 51 | 検証内容: 52 | - 動画ファイルの存在確認 53 | - ffmpegによる動画ファイルのデコード確認 54 | - ファイルサイズの確認 55 | - 動画の再生時間確認 56 | 57 | .EXAMPLE 58 | # 通常モードで実行 59 | .\validate_video.ps1 60 | 61 | # GUIモードで実行 62 | .\validate_video.ps1 gui 63 | 64 | .OUTPUTS 65 | System.Void 66 | このスクリプトは以下の出力を行います: 67 | - コンソールへの進捗状況の表示 68 | - トースト通知による進捗状況の表示 69 | - エラー発生時のエラーメッセージ 70 | - 処理完了時のサマリー情報 71 | - 検証結果の詳細レポート 72 | #> 73 | 74 | Set-StrictMode -Version Latest 75 | $script:guiMode = if ($args) { [String]$args[0] } else { '' } 76 | 77 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 78 | # 環境設定 79 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 80 | try { 81 | if ($myInvocation.MyCommand.CommandType -ne 'ExternalScript') { $script:scriptRoot = Convert-Path . } 82 | else { $script:scriptRoot = Split-Path -Parent -Path $myInvocation.MyCommand.Definition } 83 | Set-Location $script:scriptRoot 84 | } catch { throw '❌️ カレントディレクトリの設定に失敗しました。Failed to set current directory.' } 85 | if ($script:scriptRoot.Contains(' ')) { throw '❌️ TVerRecはスペースを含むディレクトリに配置できません。TVerRec cannot be placed in directories containing space' } 86 | . (Convert-Path (Join-Path $script:scriptRoot '../src/functions/initialize.ps1')) 87 | 88 | #━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 89 | # メイン処理 90 | Invoke-RequiredFileCheck 91 | Suspend-Process 92 | 93 | #====================================================================== 94 | # ダウンロード履歴ファイルのクリーンアップ 95 | Write-Output ('') 96 | Write-Output ($script:msg.MediumBoldBorder) 97 | Write-Output ($script:msg.DeleteCorruptedRecords) 98 | 99 | $toastShowParams = @{ 100 | Text1 = $script:msg.CheckingIntegrity 101 | Text2 = $script:msg.IntegrityCheckStep1 102 | WorkDetail = '' 103 | Tag = $script:appName 104 | Silent = $false 105 | Group = 'Validate' 106 | } 107 | Show-ProgressToast @toastShowParams 108 | 109 | # ダウンロード履歴の破損レコード削除 110 | Optimize-HistoryFile 111 | 112 | Write-Output ('') 113 | Write-Output ($script:msg.MediumBoldBorder) 114 | Write-Output ($script:msg.DeleteOldRecords) 115 | 116 | $toastShowParams.Text2 = ($script:msg.IntegrityCheckStep2 -f $script:histRetentionPeriod) 117 | Show-ProgressToast @toastShowParams 118 | 119 | # 指定日以上前に処理したものはダウンロード履歴から削除 120 | Limit-HistoryFile -RetentionPeriod $script:histRetentionPeriod 121 | 122 | Write-Output ('') 123 | Write-Output ($script:msg.MediumBoldBorder) 124 | Write-Output ($script:msg.RemoveDuplicates) 125 | 126 | $toastShowParams.Text2 = $script:msg.IntegrityCheckStep3 127 | Show-ProgressToast @toastShowParams 128 | 129 | # ダウンロード履歴の重複削除 130 | Repair-HistoryFile 131 | 132 | if ($script:disableValidation) { Write-Warning ($script:msg.DisclaimerForNotValidating) ; exit 0 } 133 | 134 | #====================================================================== 135 | # 未検証のファイルが0になるまでループ 136 | if (Test-Path $script:histFilePath -PathType Leaf) { 137 | # videoPageごとに最新のdownloadDateを持つレコードを取得 138 | $latestHists = Get-LatestHistory 139 | # videoValidatedが「0:未チェック」のものをカウント 140 | $videoNotValidatedNum = ($latestHists.Where({ ($_.videoPath -ne '-- IGNORED --') -and ($_.videoValidated -eq '0') })).Count 141 | } else { $videoNotValidatedNum = 0 } 142 | 143 | while ($videoNotValidatedNum -ne 0) { 144 | #====================================================================== 145 | # ダウンロード履歴から番組チェックが終わっていないものを読み込み 146 | Write-Output ('') 147 | Write-Output ($script:msg.MediumBoldBorder) 148 | Write-Output ($script:msg.IntegrityCheck) 149 | 150 | $latestHists = Get-LatestHistory 151 | $videoHists = $latestHists.Where({ $_.videoPath -ne '-- IGNORED --' }).Where({ $_.videoValidated -eq '0' }) 152 | 153 | if (($null -eq $videoHists) -or ($videoHists.Count -eq 0)) { 154 | # チェックする番組なし 155 | Write-Output ($script:msg.AllValidated) 156 | Write-Output ('') 157 | } else { 158 | # ダウンロードファイルをチェック 159 | $validateTotal = 0 160 | $validateTotal = $videoHists.Count 161 | # ffmpegのデコードオプションの設定 162 | if ($script:forceSoftwareDecodeFlag) { $decodeOption = '' } 163 | else { 164 | if ($script:ffmpegDecodeOption) { 165 | Write-Output ($script:msg.MediumBoldBorder) 166 | Write-Output ($script:msg.NotifyFfmpegOptions1) 167 | Write-Output ('   {0}' -f $ffmpegDecodeOption) 168 | Write-Output ($script:msg.NotifyFfmpegOptions2) 169 | Write-Output ($script:msg.NotifyFfmpegOptions3) 170 | Write-Output ($script:msg.NotifyFfmpegOptions4) 171 | Write-Output ($script:msg.MediumBoldBorder) 172 | } 173 | $decodeOption = $script:ffmpegDecodeOption 174 | } 175 | 176 | $toastShowParams.Text2 = $script:msg.IntegrityCheckStep4 177 | $toastShowParams.WorkDetail = $script:msg.CalculatingRemainingTime 178 | Show-ProgressToast @toastShowParams 179 | 180 | #---------------------------------------------------------------------- 181 | $totalStartTime = Get-Date 182 | $validateNum = 0 183 | foreach ($videoHist in $videoHists) { 184 | # 処理時間の推計 185 | $secElapsed = (Get-Date) - $totalStartTime 186 | $secRemaining = -1 187 | if ($validateNum -ne 0) { 188 | $secRemaining = [Int][Math]::Ceiling(($secElapsed.TotalSeconds / $validateNum) * ($validateTotal - $validateNum)) 189 | $minRemaining = ($script:msg.MinRemaining -f ([Int][Math]::Ceiling($secRemaining / 60))) 190 | $progressRate = [Float]($validateNum / $validateTotal) 191 | } else { $minRemaining = '' ; $progressRate = 0 } 192 | $validateNum++ 193 | 194 | $toastUpdateParams = @{ 195 | Title = $videoHist.videoName 196 | Rate = $progressRate 197 | LeftText = ('{0}/{1}' -f $validateNum, $validateTotal) 198 | RightText = $minRemaining 199 | Tag = $script:appName 200 | Group = 'Validate' 201 | } 202 | Update-ProgressToast @toastUpdateParams 203 | 204 | if (!(Test-Path $script:downloadBaseDir -PathType Container)) { throw ($script:msg.DownloadDirNotAccessible) } 205 | # 番組の整合性チェック 206 | Write-Output ('{0}/{1} - {2}' -f $validateNum, $validateTotal, $videoHist.videoPath) 207 | Invoke-IntegrityCheck -VideoHist $videoHist -DecodeOption $decodeOption 208 | Suspend-Process 209 | Start-Sleep -Seconds 1 210 | } 211 | #---------------------------------------------------------------------- 212 | } 213 | 214 | #====================================================================== 215 | # ダウンロード履歴から整合性検証が終わっていないもののステータスを初期化 216 | Write-Output ('') 217 | Write-Output ($script:msg.MediumBoldBorder) 218 | Write-Output ($script:msg.ClearValidationStatus) 219 | 220 | $toastShowParams.Text2 = $script:msg.IntegrityCheckStep5 221 | $toastShowParams.WorkDetail = '' 222 | Show-ProgressToast @toastShowParams 223 | 224 | if (Test-Path $script:histFilePath -PathType Leaf) { 225 | # videoPageごとに最新のdownloadDateを持つレコードを取得 226 | $latestHists = Get-LatestHistory 227 | # videoValidatedが「2:チェック中」のものをフィルタリングして、「0:未チェック」のレコード追加 228 | $newRecords = $latestHists.Where({ $_.videoValidated -eq '2' }).ForEach({ 229 | $_.videoValidated = '0' 230 | $_.downloadDate = Get-TimeStamp 231 | $_ 232 | }) 233 | while (-not (Lock-File $script:histLockFilePath).result) { Write-Information ($script:msg.WaitingLock) ; Start-Sleep -Seconds 1 } 234 | try { $newRecords | Export-Csv -LiteralPath $script:histFilePath -Encoding UTF8 -Append ; Start-Sleep -Seconds 1 } 235 | catch { throw ($script:msg.UpdateFailed -f $script:msg.HistFile) } 236 | finally { Unlock-File $script:histLockFilePath | Out-Null } 237 | # videoPageごとに最新のdownloadDateを持つレコードを取得 238 | $latestHists = Get-LatestHistory 239 | # videoValidatedが「0:未チェック」のものをカウント 240 | $videoNotValidatedNum = ($latestHists.Where({ ($_.videoPath -ne '-- IGNORED --') -and ($_.videoValidated -eq '0') -and ($_.videoValidated -ne '3') })).Count 241 | } else { $videoNotValidatedNum = 0 } 242 | } 243 | 244 | # ダウンロード履歴の重複削除 245 | Repair-HistoryFile 246 | 247 | #====================================================================== 248 | # 完了処理 249 | $toastUpdateParams = @{ 250 | Title = $script:msg.ValidateVideo 251 | Rate = '1' 252 | LeftText = '' 253 | RightText = $script:msg.Completed 254 | Tag = $script:appName 255 | Group = 'Validate' 256 | } 257 | Update-ProgressToast @toastUpdateParams 258 | 259 | Remove-Variable -Name args, toastShowParams, videoNotValidatedNum, videoHists, videoHist, uncheckedVideo, validateTotal, decodeOption, totalStartTime, validateNum, secElapsed, secRemaining, minRemaining, progressRate, toastUpdateParams -ErrorAction SilentlyContinue 260 | 261 | Invoke-GarbageCollection 262 | 263 | Write-Output ('') 264 | Write-Output ($script:msg.LongBoldBorder) 265 | Write-Output ($script:msg.IntegrityCheckCompleted) 266 | Write-Output ($script:msg.LongBoldBorder) 267 | -------------------------------------------------------------------------------- /test/functions/initialize.Test.ps1: -------------------------------------------------------------------------------- 1 | Import-Module Pester -MinimumVersion 5.0 2 | 3 | # region BeforeAll 4 | 5 | #---------------------------------------------------------------------- 6 | # テスト対象ファイルの読み込み 7 | #---------------------------------------------------------------------- 8 | BeforeAll { 9 | Write-Host ('テストスクリプト: {0}' -f $PSCommandPath) 10 | $targetFile = $PSCommandPath.Replace('test', 'src').Replace('.Test.ps1', '.ps1') 11 | Write-Host (' テスト対象: {0}' -f $targetFile) 12 | $script:scriptRoot = Convert-Path ./src 13 | Set-Location $script:scriptRoot 14 | $script:guiMode = $null 15 | . $targetFile 16 | Write-Host (' テスト対象の読み込みを行いました') 17 | } 18 | 19 | # endregion BeforeAll 20 | 21 | Describe '関数読み込みスクリプトテスト' { 22 | It '設定ファイルが存在するか確認' { 23 | # 設定ファイルのパスを定義 24 | $systemSettingPath = Join-Path $script:confDir 'system_setting.ps1' 25 | $userSettingPath = Join-Path $script:confDir 'user_setting.ps1' 26 | 27 | # 設定ファイルが存在するかテスト 28 | Test-Path $systemSettingPath | Should -BeTrue 29 | Test-Path $userSettingPath | Should -BeTrue 30 | } 31 | 32 | It '外部関数ファイルが読み込まれるか確認' { 33 | # 外部関数ファイルのパスを定義 34 | $commonFunctionsPath = Join-Path $script:scriptRoot 'functions/common_functions.ps1' 35 | $tverFunctionsPath = Join-Path $script:scriptRoot 'functions/tver_functions.ps1' 36 | $tverrecFunctionsPath = Join-Path $script:scriptRoot 'functions/tverrec_functions.ps1' 37 | 38 | # 外部関数ファイルが読み込まれているかテスト 39 | { . $commonFunctionsPath } | Should -Not -Throw 40 | { . $tverFunctionsPath } | Should -Not -Throw 41 | { . $tverrecFunctionsPath } | Should -Not -Throw 42 | } 43 | 44 | It '開発環境用設定が正しく上書きされるか確認' { 45 | # 開発環境用設定ファイルのパスを定義 46 | $devConfFile = Join-Path $script:devDir 'dev_setting.ps1' 47 | 48 | # 開発環境用設定ファイルがある場合のみテスト 49 | if (Test-Path $devConfFile) { 50 | { . $devConfFile } | Should -Not -Throw 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /test/test_all.ps1: -------------------------------------------------------------------------------- 1 | Invoke-Pester ./test/functions/initialize.Test.ps1 -Output Detailed 2 | Invoke-Pester ./test/functions/common_functions.Test.ps1 -Output Detailed 3 | Invoke-Pester ./test/functions/tver_functions.Test.ps1 -Output Detailed 4 | -------------------------------------------------------------------------------- /test/test_target.ps1: -------------------------------------------------------------------------------- 1 | Invoke-Pester ./test/functions/initialize.Test.ps1 -Output Detailed -Tag 'Target' 2 | Invoke-Pester ./test/functions/common_functions.Test.ps1 -Output Detailed -Tag 'Target' 3 | Invoke-Pester ./test/functions/tver_functions.Test.ps1 -Output Detailed -Tag 'Target' 4 | -------------------------------------------------------------------------------- /test/test_tver.ps1: -------------------------------------------------------------------------------- 1 | Invoke-Pester ./test/functions/initialize.Test.ps1 -Output Detailed -Tag 'TVer' 2 | Invoke-Pester ./test/functions/common_functions.Test.ps1 -Output Detailed -Tag 'TVer' 3 | Invoke-Pester ./test/functions/tver_functions.Test.ps1 -Output Detailed -Tag 'TVer' 4 | -------------------------------------------------------------------------------- /unix/a.download_bulk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 一括ダウンロード処理スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Video File Bulk Downloader\007" 11 | 12 | pwsh -NoProfile "../src/download_bulk.ps1" 13 | 14 | echo "Completed ..." 15 | -------------------------------------------------------------------------------- /unix/b.delete_trash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # ダウンロード対象外番組削除処理スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Video File Deleter\007" 11 | 12 | pwsh -NoProfile "../src/delete_trash.ps1" 13 | 14 | echo "Completed ..." 15 | -------------------------------------------------------------------------------- /unix/c.validate_video.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 番組チェック処理スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Video File Checker\007" 11 | 12 | pwsh -NoProfile "../src/validate_video.ps1" 13 | 14 | echo "Completed ..." 15 | -------------------------------------------------------------------------------- /unix/d.move_video.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 番組移動処理スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Video File Mover\007" 11 | 12 | pwsh -NoProfile "../src/move_video.ps1" 13 | 14 | echo "Completed ..." 15 | -------------------------------------------------------------------------------- /unix/debug_console.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 個別ダウンロードスクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Debug Console\007" 11 | 12 | pwsh -NoProfile -NoExit "../src/debug_console.ps1" 13 | 14 | echo "Debug Console Closed ..." 15 | -------------------------------------------------------------------------------- /unix/start_tverrec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 一括ダウンロード処理開始スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec\007" 11 | 12 | export HostName="$(hostname)" 13 | export PIDFile="pid-$HostName.txt" 14 | 15 | echo $PPID > "$PIDFile" 16 | 17 | pwsh -NoProfile "../src/loop.ps1" 18 | 19 | echo "Completed ..." 20 | -------------------------------------------------------------------------------- /unix/stop_tverrec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 一括ダウンロード処理停止スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec\007" 11 | 12 | export HostName="$(hostname)" 13 | export PIDFile="pid-$HostName.txt" 14 | 15 | if [ -e "$PIDFile" ] ; then 16 | export targetPPID=$(pgrep -P $(cat "$PIDFile")) 17 | export targetPID=$(pgrep -P "$targetPPID") 18 | kill -9 "$targetPID" 19 | kill -9 "$targetPPID" 20 | rm -f "$PIDFile" 21 | else 22 | rm -f "$PIDFile" 23 | fi 24 | -------------------------------------------------------------------------------- /unix/update_tverrec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # TVerRec自動アップデート処理スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Updater\007" 11 | 12 | pwsh -NoProfile -Command "Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/dongaba/TVerRec/master/src/functions/update_tverrec.ps1' -OutFile '..\src\functions\update_tverrec.ps1'" 13 | 14 | pwsh -NoProfile "../src/functions/update_tverrec.ps1" 15 | 16 | echo "Completed ..." 17 | -------------------------------------------------------------------------------- /unix/x.generate_list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 個別ダウンロードスクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Video File List Generator\007" 11 | 12 | pwsh -NoProfile "../src/generate_list.ps1" 13 | 14 | echo "Completed ..." 15 | -------------------------------------------------------------------------------- /unix/y.download_list.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # リストダウンロード処理スクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec List Based Video File Downloader\007" 11 | 12 | pwsh -NoProfile "../src/download_list.ps1" 13 | 14 | echo "Completed ..." 15 | -------------------------------------------------------------------------------- /unix/z.download_single.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ################################################################################### 4 | # TVerRec : TVerダウンローダ 5 | # 6 | # 個別ダウンロードスクリプト 7 | # 8 | ################################################################################### 9 | 10 | echo -en "\033];TVerRec Video File Downloader\007" 11 | 12 | pwsh -NoProfile "../src/download_single.ps1" 13 | 14 | echo "Completed ..." 15 | -------------------------------------------------------------------------------- /win/Setting.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # TVerRec GUI 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\gui\gui_setting.ps1" 24 | 25 | exit 26 | 27 | :INSTALL 28 | where /Q winget 29 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 30 | echo. 31 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 32 | echo. 33 | pause 34 | winget install --id Microsoft.Powershell --source winget 35 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 36 | echo. 37 | pause 38 | exit 39 | 40 | :NOWINGET 41 | echo. 42 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 43 | echo. 44 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 45 | echo. 46 | pause 47 | exit 48 | -------------------------------------------------------------------------------- /win/TVerRec.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # TVerRec GUI 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\gui\gui_main.ps1" 24 | 25 | exit 26 | 27 | :INSTALL 28 | where /Q winget 29 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 30 | echo. 31 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 32 | echo. 33 | pause 34 | winget install --id Microsoft.Powershell --source winget 35 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 36 | echo. 37 | pause 38 | exit 39 | 40 | :NOWINGET 41 | echo. 42 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 43 | echo. 44 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 45 | echo. 46 | pause 47 | exit 48 | -------------------------------------------------------------------------------- /win/a.download_bulk.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 一括ダウンロード処理スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Video File Bulk Downloader 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\download_bulk.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | -------------------------------------------------------------------------------- /win/b.delete_trash.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # ダウンロード対象外番組削除処理スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Video File Deleter 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\delete_trash.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | -------------------------------------------------------------------------------- /win/c.validate_video.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 番組チェック処理スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Video File Checker 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\validate_video.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | -------------------------------------------------------------------------------- /win/d.move_video.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 番組移動処理スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Video File Mover 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\move_video.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | -------------------------------------------------------------------------------- /win/debug_console.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 個別ダウンロードスクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Debug Console 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted -NoExit "..\src\debug_console.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | -------------------------------------------------------------------------------- /win/start_tverrec.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 一括ダウンロード処理開始スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | for /f %%i in ('hostname') do set HostName=%%i 21 | set PIDFile=pid-%HostName%.txt 22 | 23 | rem Zone Identifierの削除 24 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 25 | 26 | rem PIDファイルを作成するする 27 | for /f "tokens=2" %%i in ('tasklist /FI "WINDOWTITLE eq TVerRec" /NH') do set myPID=%%i 28 | echo %myPID% > %PIDFile% 2> nul 29 | 30 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\loop.ps1" 31 | 32 | pause 33 | exit 34 | 35 | :INSTALL 36 | where /Q winget 37 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 38 | echo. 39 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 40 | echo. 41 | pause 42 | winget install --id Microsoft.Powershell --source winget 43 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 44 | echo. 45 | pause 46 | exit 47 | 48 | :NOWINGET 49 | echo. 50 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 51 | echo. 52 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 53 | echo. 54 | pause 55 | exit 56 | -------------------------------------------------------------------------------- /win/stop_tverrec.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 一括ダウンロード処理停止スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | for /f %%i in ('hostname') do set HostName=%%i 16 | set PIDFile=pid-%HostName%.txt 17 | 18 | if exist %PIDFile% ( 19 | set /p targetPID=<%PIDFile% 20 | tasklist /fi "PID eq !targetPID!" > nul 2> nul 21 | if not ERRORLEVEL 1 ( 22 | goto :RUNNING 23 | ) else ( 24 | del %PIDFile% 25 | goto :NOT_RUNNING 26 | ) 27 | ) else ( 28 | goto :NOT_RUNNING 29 | ) 30 | 31 | :RUNNING 32 | echo kill process: !targetPID! 33 | taskkill /F /T /PID !targetPID! 2> nul 34 | del !PIDFile! 2> nul 35 | goto :END 36 | 37 | :NOT_RUNNING 38 | echo not running 39 | del !PIDFile! 2> nul 40 | goto :END 41 | 42 | :END 43 | exit 44 | -------------------------------------------------------------------------------- /win/update_tverrec.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # TVerRec自動アップデート処理スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Updater 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | pwsh -NoProfile -ExecutionPolicy Unrestricted -Command "Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/dongaba/TVerRec/master/src/functions/update_tverrec.ps1' -OutFile '..\src\functions\update_tverrec.ps1'" 21 | 22 | rem Zone Identifierの削除 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 24 | 25 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\functions\update_tverrec.ps1" 26 | 27 | pause 28 | exit 29 | 30 | :INSTALL 31 | where /Q winget 32 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 33 | echo. 34 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 35 | echo. 36 | pause 37 | winget install --id Microsoft.Powershell --source winget 38 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 39 | echo. 40 | pause 41 | exit 42 | 43 | :NOWINGET 44 | echo. 45 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 46 | echo. 47 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 48 | echo. 49 | pause 50 | exit 51 | -------------------------------------------------------------------------------- /win/x.generate_list.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 番組リストファイル出力処理スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Video File List Generator 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\generate_list.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | -------------------------------------------------------------------------------- /win/y.download_list.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # リストダウンロード処理スクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec List Based Video File Downloader 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\download_list.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | -------------------------------------------------------------------------------- /win/z.download_single.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | rem ################################################################################### 3 | rem # TVerRec : TVerダウンローダ 4 | rem # 5 | rem # 個別ダウンロードスクリプト 6 | rem # 7 | rem ################################################################################### 8 | 9 | rem 文字コードをUTF8に 10 | chcp 65001 > nul 11 | 12 | setlocal enabledelayedexpansion 13 | cd /d %~dp0 14 | 15 | title TVerRec Video File Downloader 16 | 17 | where /Q pwsh 18 | if %ERRORLEVEL% neq 0 (goto :INSTALL) 19 | 20 | rem Zone Identifierの削除 21 | pwsh -Command "Get-ChildItem ..\ -Recurse | Unblock-File" 22 | 23 | pwsh -NoProfile -ExecutionPolicy Unrestricted "..\src\download_single.ps1" 24 | 25 | pause 26 | exit 27 | 28 | :INSTALL 29 | where /Q winget 30 | if %ERRORLEVEL% neq 0 (goto :NOWINGET) 31 | echo. 32 | echo PowerShell Coreをインストールします。インストールしたくない場合はこのままウィンドウを閉じてください。 33 | echo. 34 | pause 35 | winget install --id Microsoft.Powershell --source winget 36 | echo PowerShell Coreをインストールしました。TVerRecを再実行してください。 37 | echo. 38 | pause 39 | exit 40 | 41 | :NOWINGET 42 | echo. 43 | echo PowerShell Coreを自動インストールするにはアプリインストーラーをインストールする必要があります。 44 | echo. 45 | echo https://apps.microsoft.com/detail/9NBLGGH4NNS1 に移動してアプリインストーラーをインストールしてください。 46 | echo. 47 | pause 48 | exit 49 | --------------------------------------------------------------------------------