Релиз v1.0.0
This commit is contained in:
+18
@@ -0,0 +1,18 @@
|
|||||||
|
# Результаты работы
|
||||||
|
output/*
|
||||||
|
!output/.gitkeep
|
||||||
|
|
||||||
|
# Локальные зависимости
|
||||||
|
tools/*
|
||||||
|
!tools/.gitkeep
|
||||||
|
|
||||||
|
# Временные файлы
|
||||||
|
temp/
|
||||||
|
*.tmp
|
||||||
|
*.part
|
||||||
|
*.ytdl
|
||||||
|
|
||||||
|
# PowerShell / Windows
|
||||||
|
*.log
|
||||||
|
Thumbs.db
|
||||||
|
Desktop.ini
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -0,0 +1,207 @@
|
|||||||
|
# YouTube Tools
|
||||||
|
|
||||||
|
Набор PowerShell-скриптов для Windows для скачивания видео и аудио с YouTube, а также создания видео с закадровым переводом.
|
||||||
|
|
||||||
|
> Используйте утилиты только для контента, который вы имеете право скачивать и обрабатывать.
|
||||||
|
|
||||||
|
## Возможности
|
||||||
|
|
||||||
|
В репозитории находятся три скрипта:
|
||||||
|
|
||||||
|
| Скрипт | Назначение |
|
||||||
|
| ------------------------------- | ------------------------------------------------------------------------------------------------------------ |
|
||||||
|
| `Get-YouTubeAudio.ps1` | Скачивание лучшей аудиодорожки и конвертация в FLAC |
|
||||||
|
| `Get-YouTubeVideo.ps1` | Скачивание видео в максимально доступном качестве |
|
||||||
|
| `Get-YouTubeVideoTranslate.ps1` | Скачивание видео, получение закадрового перевода через `vot-cli` и смешивание перевода с оригинальным звуком |
|
||||||
|
|
||||||
|
Все готовые файлы сохраняются в папку:
|
||||||
|
|
||||||
|
```text
|
||||||
|
output/
|
||||||
|
```
|
||||||
|
|
||||||
|
## Структура проекта
|
||||||
|
|
||||||
|
```text
|
||||||
|
youtube-tools/
|
||||||
|
├── scripts/
|
||||||
|
│ ├── Get-YouTubeAudio.ps1
|
||||||
|
│ ├── Get-YouTubeVideo.ps1
|
||||||
|
│ └── Get-YouTubeVideoTranslate.ps1
|
||||||
|
│
|
||||||
|
├── tools/
|
||||||
|
│ ├── yt-dlp.exe
|
||||||
|
│ ├── ffmpeg.exe
|
||||||
|
│ └── ...
|
||||||
|
│
|
||||||
|
├── output/
|
||||||
|
│ └── .gitkeep
|
||||||
|
│
|
||||||
|
├── README.md
|
||||||
|
├── LICENSE
|
||||||
|
└── .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
Бинарные зависимости в Git не добавляются. Папка `tools` предназначена для локального размещения необходимых программ.
|
||||||
|
|
||||||
|
## Поиск зависимостей
|
||||||
|
|
||||||
|
Каждый скрипт ищет необходимые программы в следующем порядке:
|
||||||
|
|
||||||
|
1. В локальной папке `tools`.
|
||||||
|
2. В системной переменной `PATH`.
|
||||||
|
3. Если программа не найдена нигде, скрипт показывает ошибку и завершает работу.
|
||||||
|
|
||||||
|
Таким образом, можно использовать как локальные версии утилит, так и программы, установленные в Windows.
|
||||||
|
|
||||||
|
## Зависимости
|
||||||
|
|
||||||
|
Скачать всё с облака:
|
||||||
|
|
||||||
|
[Скачать (.zip)] (https://cloud.kolbox.duckdns.org/lib/b5d0b4e0-fd0c-40fe-b799-3ab0015550d0/file/Gitea%20%D1%80%D0%B5%D0%BF%D0%BE%D0%B7%D0%B8%D1%82%D0%BE%D1%80%D0%B8%D0%B8/youtube-tools/tools.zip?dl=1)
|
||||||
|
|
||||||
|
### yt-dlp
|
||||||
|
|
||||||
|
Используется для скачивания видео и аудио с YouTube.
|
||||||
|
|
||||||
|
Последняя версия:
|
||||||
|
|
||||||
|
https://github.com/yt-dlp/yt-dlp/releases/latest
|
||||||
|
|
||||||
|
Для локального использования положите `yt-dlp.exe` в:
|
||||||
|
|
||||||
|
```text
|
||||||
|
tools/yt-dlp.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
### FFmpeg
|
||||||
|
|
||||||
|
Используется для конвертации аудио, объединения потоков и обработки звуковых дорожек.
|
||||||
|
|
||||||
|
Сборка FFmpeg для Windows:
|
||||||
|
|
||||||
|
https://www.gyan.dev/ffmpeg/builds/
|
||||||
|
|
||||||
|
После распаковки архива возьмите из папки `bin` файл:
|
||||||
|
|
||||||
|
```text
|
||||||
|
ffmpeg.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
и положите его в:
|
||||||
|
|
||||||
|
```text
|
||||||
|
tools/ffmpeg.exe
|
||||||
|
```
|
||||||
|
|
||||||
|
`ffprobe.exe` текущим скриптам напрямую не требуется.
|
||||||
|
|
||||||
|
### vot-cli
|
||||||
|
|
||||||
|
Используется только скриптом `Get-YouTubeVideoTranslate.ps1`.
|
||||||
|
|
||||||
|
Репозиторий:
|
||||||
|
|
||||||
|
https://github.com/FOSWLY/vot-cli
|
||||||
|
|
||||||
|
Установка:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
npm install -g vot-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
После установки должна быть доступна команда:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
vot-cli
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт также умеет искать локальный `vot-cli.cmd`, `vot-cli.exe` или `vot-cli.ps1` в папке `tools`.
|
||||||
|
|
||||||
|
### Node.js и npm
|
||||||
|
|
||||||
|
Необходимы для установки и работы `vot-cli`.
|
||||||
|
|
||||||
|
Проверка:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
node --version
|
||||||
|
npm --version
|
||||||
|
```
|
||||||
|
|
||||||
|
Скрипт перевода проверяет `node` и `npm` как в папке `tools`, так и в системном `PATH`.
|
||||||
|
|
||||||
|
## Зависимости по скриптам
|
||||||
|
|
||||||
|
| Скрипт | yt-dlp | FFmpeg | Node.js / npm | vot-cli |
|
||||||
|
| ------------------------------- |:------:|:------:|:-------------:|:-------:|
|
||||||
|
| `Get-YouTubeAudio.ps1` | ✓ | ✓ | — | — |
|
||||||
|
| `Get-YouTubeVideo.ps1` | ✓ | ✓ | — | — |
|
||||||
|
| `Get-YouTubeVideoTranslate.ps1` | ✓ | ✓ | ✓ | ✓ |
|
||||||
|
|
||||||
|
## Использование
|
||||||
|
|
||||||
|
### Скачивание аудио
|
||||||
|
|
||||||
|
Запустите:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\Get-YouTubeAudio.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Введите ссылку на YouTube. Результат будет сохранён в `output` в формате FLAC.
|
||||||
|
|
||||||
|
### Скачивание видео
|
||||||
|
|
||||||
|
Запустите:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\Get-YouTubeVideo.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Введите ссылку на YouTube. Скрипт скачает видео в максимально доступном качестве и сохранит результат в `output`.
|
||||||
|
|
||||||
|
### Видео с закадровым переводом
|
||||||
|
|
||||||
|
Запустите:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
.\scripts\Get-YouTubeVideoTranslate.ps1
|
||||||
|
```
|
||||||
|
|
||||||
|
Можно ввести одну ссылку или несколько ссылок через запятую.
|
||||||
|
|
||||||
|
Скрипт:
|
||||||
|
|
||||||
|
1. скачивает исходное видео;
|
||||||
|
2. получает переведённую дорожку через `vot-cli`;
|
||||||
|
3. уменьшает громкость оригинального звука до `20%`;
|
||||||
|
4. смешивает оригинальный звук с переводом;
|
||||||
|
5. сохраняет итоговый MP4 в `output`;
|
||||||
|
6. удаляет временные файлы.
|
||||||
|
|
||||||
|
## Политика выполнения PowerShell
|
||||||
|
|
||||||
|
Если Windows запрещает запуск `.ps1`, можно разрешить выполнение локальных скриптов для текущего пользователя:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
Set-ExecutionPolicy -Scope CurrentUser RemoteSigned
|
||||||
|
```
|
||||||
|
|
||||||
|
Изменяйте политику выполнения только если понимаете последствия этой настройки.
|
||||||
|
|
||||||
|
## Выходные файлы
|
||||||
|
|
||||||
|
Все результаты находятся в:
|
||||||
|
|
||||||
|
```text
|
||||||
|
youtube-tools/output/
|
||||||
|
```
|
||||||
|
|
||||||
|
Папка создаётся автоматически, если отсутствует.
|
||||||
|
|
||||||
|
Содержимое `output` исключено из Git.
|
||||||
|
|
||||||
|
## Лицензия
|
||||||
|
|
||||||
|
MIT. См. файл `LICENSE`.
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
#requires -Version 5.1
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# Корень проекта определяется независимо от текущей папки PowerShell.
|
||||||
|
$ProjectRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$ToolsDir = Join-Path $ProjectRoot "tools"
|
||||||
|
$OutputDir = Join-Path $ProjectRoot "output"
|
||||||
|
|
||||||
|
if (-not (Test-Path $OutputDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Find-Tool {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Name,
|
||||||
|
|
||||||
|
[string[]]$LocalNames = @()
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($localName in $LocalNames) {
|
||||||
|
$localPath = Join-Path $ToolsDir $localName
|
||||||
|
if (Test-Path $localPath -PathType Leaf) {
|
||||||
|
return (Resolve-Path $localPath).Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = Get-Command $Name -ErrorAction SilentlyContinue
|
||||||
|
if ($command) {
|
||||||
|
return $command.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Require-Tool {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Name,
|
||||||
|
|
||||||
|
[string[]]$LocalNames = @(),
|
||||||
|
|
||||||
|
[string]$InstallHint = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
$tool = Find-Tool -Name $Name -LocalNames $LocalNames
|
||||||
|
|
||||||
|
if (-not $tool) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: не найдена зависимость '$Name'." -ForegroundColor Red
|
||||||
|
Write-Host "Проверены:"
|
||||||
|
Write-Host " 1. Папка: $ToolsDir"
|
||||||
|
Write-Host " 2. Системная переменная PATH"
|
||||||
|
|
||||||
|
if ($InstallHint) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host $InstallHint
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tool
|
||||||
|
}
|
||||||
|
|
||||||
|
$YtDlp = Require-Tool `
|
||||||
|
-Name "yt-dlp" `
|
||||||
|
-LocalNames @("yt-dlp.exe", "yt-dlp.cmd", "yt-dlp.ps1") `
|
||||||
|
-InstallHint "Скачать yt-dlp: https://github.com/yt-dlp/yt-dlp/releases/latest"
|
||||||
|
|
||||||
|
$Ffmpeg = Require-Tool `
|
||||||
|
-Name "ffmpeg" `
|
||||||
|
-LocalNames @("ffmpeg.exe") `
|
||||||
|
-InstallHint "Скачать FFmpeg: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z"
|
||||||
|
|
||||||
|
$FfmpegDir = Split-Path -Parent $Ffmpeg
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "============================================================"
|
||||||
|
Write-Host " СКАЧИВАНИЕ АУДИО С YOUTUBE"
|
||||||
|
Write-Host "============================================================"
|
||||||
|
Write-Host "Результат: $OutputDir"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$Url = Read-Host "Введите URL видео с YouTube"
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($Url)) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: ссылка не введена." -ForegroundColor Red
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$OutputTemplate = Join-Path $OutputDir "%(title)s.%(ext)s"
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Скачивание и конвертация аудио в FLAC..."
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
& $YtDlp `
|
||||||
|
"-f" "ba" `
|
||||||
|
"--extract-audio" `
|
||||||
|
"--audio-format" "flac" `
|
||||||
|
"--audio-quality" "0" `
|
||||||
|
"--ffmpeg-location" $FfmpegDir `
|
||||||
|
"-o" $OutputTemplate `
|
||||||
|
$Url
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: yt-dlp завершил работу с кодом $LASTEXITCODE." -ForegroundColor Red
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Готово." -ForegroundColor Green
|
||||||
|
Write-Host "Файл сохранён в: $OutputDir"
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
#requires -Version 5.1
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# Корень проекта определяется независимо от текущей папки PowerShell.
|
||||||
|
$ProjectRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$ToolsDir = Join-Path $ProjectRoot "tools"
|
||||||
|
$OutputDir = Join-Path $ProjectRoot "output"
|
||||||
|
|
||||||
|
if (-not (Test-Path $OutputDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Find-Tool {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Name,
|
||||||
|
|
||||||
|
[string[]]$LocalNames = @()
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($localName in $LocalNames) {
|
||||||
|
$localPath = Join-Path $ToolsDir $localName
|
||||||
|
if (Test-Path $localPath -PathType Leaf) {
|
||||||
|
return (Resolve-Path $localPath).Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = Get-Command $Name -ErrorAction SilentlyContinue
|
||||||
|
if ($command) {
|
||||||
|
return $command.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Require-Tool {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Name,
|
||||||
|
|
||||||
|
[string[]]$LocalNames = @(),
|
||||||
|
|
||||||
|
[string]$InstallHint = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
$tool = Find-Tool -Name $Name -LocalNames $LocalNames
|
||||||
|
|
||||||
|
if (-not $tool) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: не найдена зависимость '$Name'." -ForegroundColor Red
|
||||||
|
Write-Host "Проверены:"
|
||||||
|
Write-Host " 1. Папка: $ToolsDir"
|
||||||
|
Write-Host " 2. Системная переменная PATH"
|
||||||
|
|
||||||
|
if ($InstallHint) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host $InstallHint
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tool
|
||||||
|
}
|
||||||
|
|
||||||
|
$YtDlp = Require-Tool `
|
||||||
|
-Name "yt-dlp" `
|
||||||
|
-LocalNames @("yt-dlp.exe", "yt-dlp.cmd", "yt-dlp.ps1") `
|
||||||
|
-InstallHint "Скачать yt-dlp: https://github.com/yt-dlp/yt-dlp/releases/latest"
|
||||||
|
|
||||||
|
$Ffmpeg = Require-Tool `
|
||||||
|
-Name "ffmpeg" `
|
||||||
|
-LocalNames @("ffmpeg.exe") `
|
||||||
|
-InstallHint "Скачать FFmpeg: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z"
|
||||||
|
|
||||||
|
$FfmpegDir = Split-Path -Parent $Ffmpeg
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "============================================================"
|
||||||
|
Write-Host " СКАЧИВАНИЕ ВИДЕО С YOUTUBE"
|
||||||
|
Write-Host "============================================================"
|
||||||
|
Write-Host "Результат: $OutputDir"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$Url = Read-Host "Введите URL видео с YouTube"
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($Url)) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: ссылка не введена." -ForegroundColor Red
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$OutputTemplate = Join-Path $OutputDir "%(title)s.%(ext)s"
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Скачивание видео в максимально доступном качестве..."
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
& $YtDlp `
|
||||||
|
"-f" "bv*+ba/b" `
|
||||||
|
"--ffmpeg-location" $FfmpegDir `
|
||||||
|
"-o" $OutputTemplate `
|
||||||
|
$Url
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: yt-dlp завершил работу с кодом $LASTEXITCODE." -ForegroundColor Red
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit $LASTEXITCODE
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Готово." -ForegroundColor Green
|
||||||
|
Write-Host "Файл сохранён в: $OutputDir"
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
@@ -0,0 +1,245 @@
|
|||||||
|
#requires -Version 5.1
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
# Корень проекта определяется независимо от текущей папки PowerShell.
|
||||||
|
$ProjectRoot = Split-Path -Parent $PSScriptRoot
|
||||||
|
$ToolsDir = Join-Path $ProjectRoot "tools"
|
||||||
|
$OutputDir = Join-Path $ProjectRoot "output"
|
||||||
|
|
||||||
|
if (-not (Test-Path $OutputDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Find-Tool {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Name,
|
||||||
|
|
||||||
|
[string[]]$LocalNames = @()
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach ($localName in $LocalNames) {
|
||||||
|
$localPath = Join-Path $ToolsDir $localName
|
||||||
|
if (Test-Path $localPath -PathType Leaf) {
|
||||||
|
return (Resolve-Path $localPath).Path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$command = Get-Command $Name -ErrorAction SilentlyContinue
|
||||||
|
if ($command) {
|
||||||
|
return $command.Source
|
||||||
|
}
|
||||||
|
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
|
function Require-Tool {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$Name,
|
||||||
|
|
||||||
|
[string[]]$LocalNames = @(),
|
||||||
|
|
||||||
|
[string]$InstallHint = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
$tool = Find-Tool -Name $Name -LocalNames $LocalNames
|
||||||
|
|
||||||
|
if (-not $tool) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: не найдена зависимость '$Name'." -ForegroundColor Red
|
||||||
|
Write-Host "Проверены:"
|
||||||
|
Write-Host " 1. Папка: $ToolsDir"
|
||||||
|
Write-Host " 2. Системная переменная PATH"
|
||||||
|
|
||||||
|
if ($InstallHint) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host $InstallHint
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
return $tool
|
||||||
|
}
|
||||||
|
|
||||||
|
$YtDlp = Require-Tool `
|
||||||
|
-Name "yt-dlp" `
|
||||||
|
-LocalNames @("yt-dlp.exe", "yt-dlp.cmd", "yt-dlp.ps1") `
|
||||||
|
-InstallHint "Скачать yt-dlp: https://github.com/yt-dlp/yt-dlp/releases/latest"
|
||||||
|
|
||||||
|
$Ffmpeg = Require-Tool `
|
||||||
|
-Name "ffmpeg" `
|
||||||
|
-LocalNames @("ffmpeg.exe") `
|
||||||
|
-InstallHint "Скачать FFmpeg: https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-full.7z"
|
||||||
|
|
||||||
|
$VotCli = Require-Tool `
|
||||||
|
-Name "vot-cli" `
|
||||||
|
-LocalNames @("vot-cli.cmd", "vot-cli.exe", "vot-cli.ps1") `
|
||||||
|
-InstallHint "Установка vot-cli: npm install -g vot-cli"
|
||||||
|
|
||||||
|
$Node = Require-Tool `
|
||||||
|
-Name "node" `
|
||||||
|
-LocalNames @("node.exe") `
|
||||||
|
-InstallHint "Установите Node.js: https://nodejs.org/"
|
||||||
|
|
||||||
|
$Npm = Require-Tool `
|
||||||
|
-Name "npm" `
|
||||||
|
-LocalNames @("npm.cmd", "npm.exe", "npm.ps1") `
|
||||||
|
-InstallHint "npm устанавливается вместе с Node.js."
|
||||||
|
|
||||||
|
$FfmpegDir = Split-Path -Parent $Ffmpeg
|
||||||
|
|
||||||
|
function Get-SafeFileName {
|
||||||
|
param([string]$Name)
|
||||||
|
|
||||||
|
$invalidChars = [System.IO.Path]::GetInvalidFileNameChars()
|
||||||
|
foreach ($char in $invalidChars) {
|
||||||
|
$Name = $Name.Replace([string]$char, "_")
|
||||||
|
}
|
||||||
|
|
||||||
|
return $Name.Trim()
|
||||||
|
}
|
||||||
|
|
||||||
|
function Process-Video {
|
||||||
|
param(
|
||||||
|
[Parameter(Mandatory = $true)]
|
||||||
|
[string]$VideoLink,
|
||||||
|
|
||||||
|
[double]$OriginalSoundRatio = 0.2
|
||||||
|
)
|
||||||
|
|
||||||
|
$TempRoot = Join-Path ([System.IO.Path]::GetTempPath()) ("youtube-tools-" + [Guid]::NewGuid().ToString("N"))
|
||||||
|
$TempVideoDir = Join-Path $TempRoot "video"
|
||||||
|
$TempAudioDir = Join-Path $TempRoot "audio"
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $TempVideoDir -Force | Out-Null
|
||||||
|
New-Item -ItemType Directory -Path $TempAudioDir -Force | Out-Null
|
||||||
|
|
||||||
|
try {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Получение названия видео..."
|
||||||
|
|
||||||
|
$Title = (& $YtDlp "--get-title" "--no-playlist" $VideoLink | Select-Object -First 1)
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($Title)) {
|
||||||
|
$Title = "YouTubeVideo"
|
||||||
|
}
|
||||||
|
|
||||||
|
$SafeTitle = Get-SafeFileName $Title
|
||||||
|
$TempVideoTemplate = Join-Path $TempVideoDir "%(title)s.%(ext)s"
|
||||||
|
|
||||||
|
Write-Host "Скачивание исходного видео..."
|
||||||
|
|
||||||
|
& $YtDlp `
|
||||||
|
"--no-playlist" `
|
||||||
|
"-f" "bv*+ba/b" `
|
||||||
|
"--ffmpeg-location" $FfmpegDir `
|
||||||
|
"-o" $TempVideoTemplate `
|
||||||
|
$VideoLink
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "yt-dlp завершил работу с кодом $LASTEXITCODE."
|
||||||
|
}
|
||||||
|
|
||||||
|
$VideoFile = Get-ChildItem -Path $TempVideoDir -File |
|
||||||
|
Sort-Object LastWriteTime -Descending |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
|
if (-not $VideoFile) {
|
||||||
|
throw "Не найден скачанный видеофайл."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Получение переведённой аудиодорожки..."
|
||||||
|
|
||||||
|
& $VotCli $VideoLink "--output" $TempAudioDir
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "vot-cli завершил работу с кодом $LASTEXITCODE."
|
||||||
|
}
|
||||||
|
|
||||||
|
$AudioFile = Get-ChildItem -Path $TempAudioDir -File |
|
||||||
|
Sort-Object LastWriteTime -Descending |
|
||||||
|
Select-Object -First 1
|
||||||
|
|
||||||
|
if (-not $AudioFile) {
|
||||||
|
throw "vot-cli не создал аудиофайл."
|
||||||
|
}
|
||||||
|
|
||||||
|
$OutputFile = Join-Path $OutputDir ($SafeTitle + "_перевод.mp4")
|
||||||
|
|
||||||
|
Write-Host "Смешивание оригинального звука и перевода..."
|
||||||
|
|
||||||
|
$Filter = "[0:a]volume=$OriginalSoundRatio[original];[original][1:a]amix=inputs=2:duration=longest[audio_out]"
|
||||||
|
|
||||||
|
& $Ffmpeg `
|
||||||
|
"-hide_banner" `
|
||||||
|
"-i" $VideoFile.FullName `
|
||||||
|
"-i" $AudioFile.FullName `
|
||||||
|
"-c:v" "copy" `
|
||||||
|
"-c:a" "aac" `
|
||||||
|
"-b:a" "128k" `
|
||||||
|
"-filter_complex" $Filter `
|
||||||
|
"-map" "0:v:0" `
|
||||||
|
"-map" "[audio_out]" `
|
||||||
|
"-movflags" "+faststart" `
|
||||||
|
"-y" `
|
||||||
|
$OutputFile
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
throw "FFmpeg завершил работу с кодом $LASTEXITCODE."
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Готово: $OutputFile" -ForegroundColor Green
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (Test-Path $TempRoot) {
|
||||||
|
Remove-Item -Path $TempRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "============================================================"
|
||||||
|
Write-Host " СКАЧИВАНИЕ YOUTUBE С ЗАКАДРОВЫМ ПЕРЕВОДОМ"
|
||||||
|
Write-Host "============================================================"
|
||||||
|
Write-Host "Результат: $OutputDir"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
$VideoLinksInput = Read-Host "Введите ссылку или несколько ссылок через запятую"
|
||||||
|
|
||||||
|
if ([string]::IsNullOrWhiteSpace($VideoLinksInput)) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: ссылки не введены." -ForegroundColor Red
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
$VideoLinks = $VideoLinksInput -split "," |
|
||||||
|
ForEach-Object { $_.Trim() } |
|
||||||
|
Where-Object { -not [string]::IsNullOrWhiteSpace($_) }
|
||||||
|
|
||||||
|
foreach ($VideoLink in $VideoLinks) {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "------------------------------------------------------------"
|
||||||
|
Write-Host "Обработка: $VideoLink"
|
||||||
|
Write-Host "------------------------------------------------------------"
|
||||||
|
|
||||||
|
try {
|
||||||
|
Process-Video -VideoLink $VideoLink -OriginalSoundRatio 0.2
|
||||||
|
}
|
||||||
|
catch {
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "ОШИБКА: $($_.Exception.Message)" -ForegroundColor Red
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "Обработка завершена."
|
||||||
|
Write-Host "Результаты находятся в: $OutputDir"
|
||||||
|
Write-Host ""
|
||||||
|
Read-Host "Нажмите Enter для выхода"
|
||||||
Reference in New Issue
Block a user