-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathBackup_And_Convert.ps1
More file actions
352 lines (299 loc) · 15.4 KB
/
Backup_And_Convert.ps1
File metadata and controls
352 lines (299 loc) · 15.4 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
# Настройки путей
$SourcePath = "M:\Music" # Замените на путь к вашей библиотеке
$DestinationPath = "E:\BACKITUP D\MP3_MUSIC_LIBRARY" # Замените на путь назначения
# Опция отображения вывода ffmpeg (измените на $true для отображения вывода)
$ShowFFmpegOutput = $false # Установите $true, чтобы видеть вывод ffmpeg
# Список аудиоформатов для конвертации (без потерь)
$LosslessFormats = @(".flac", ".wav", ".aiff", ".aif", ".ape", ".wv", ".tta", ".m4a", ".dff",".dsf")
# Список аудиоформатов для копирования (с потерями и другие)
$AudioFormats = @(".mp3", ".wma", ".aac", ".mp4", ".ogg", ".opus")
# Создание функции для безопасного получения относительного пути
function Get-RelativePath {
param(
[string]$FullPath,
[string]$BasePath
)
# Нормализация путей
$FullPath = [System.IO.Path]::GetFullPath($FullPath)
$BasePath = [System.IO.Path]::GetFullPath($BasePath)
if ($FullPath.StartsWith($BasePath, [System.StringComparison]::OrdinalIgnoreCase)) {
$RelativePath = $FullPath.Substring($BasePath.Length)
# Удаление начального слэша, если есть
if ($RelativePath.StartsWith([System.IO.Path]::DirectorySeparatorChar)) {
$RelativePath = $RelativePath.Substring(1)
}
return $RelativePath
}
else {
throw "Путь $FullPath не находится внутри $BasePath"
}
}
# Создание функции для проверки существования файла назначения
function Test-DestinationFileExists {
param(
[string]$SourceFile,
[string]$SourceBasePath,
[string]$DestinationBasePath
)
try {
$RelativePath = Get-RelativePath -FullPath $SourceFile -BasePath $SourceBasePath
$DestinationFile = Join-Path $DestinationBasePath $RelativePath
# Для файлов без потерь - проверяем MP3 версию
$Extension = [System.IO.Path]::GetExtension($SourceFile).ToLower()
if ($LosslessFormats -contains $Extension) {
$DestinationFile = [System.IO.Path]::ChangeExtension($DestinationFile, ".mp3")
}
# Нормализация пути
$DestinationFile = [System.IO.Path]::GetFullPath($DestinationFile)
return Test-Path $DestinationFile
}
catch {
Write-Host " Ошибка проверки файла назначения: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
}
# Создание функции для конвертации в MP3 с проверкой
function Convert-ToMP3 {
param(
[string]$InputFile,
[string]$OutputFile
)
try {
# Проверка существования исходного файла с учетом специальных символов
$Item = Get-Item -LiteralPath $InputFile -ErrorAction SilentlyContinue
if ($null -eq $Item -or -not $Item.Exists) {
Write-Host " Исходный файл не найден: $InputFile" -ForegroundColor Red
return $false
}
# Создание директории для выходного файла
$OutputDir = Split-Path $OutputFile -Parent
if (!(Test-Path $OutputDir)) {
New-Item -ItemType Directory -Path $OutputDir -Force | Out-Null
}
# Проверка существования выходного файла
if (Test-Path $OutputFile) {
Write-Host " Файл уже существует, пропуск: $OutputFile" -ForegroundColor Yellow
return $true
}
Write-Host " Конвертация в MP3..." -ForegroundColor Cyan
# Конвертация с использованием ffmpeg
# Экранирование кавычек в путях
$EscapedInputFile = $InputFile -replace '"', '""'
$EscapedOutputFile = $OutputFile -replace '"', '""'
if ($ShowFFmpegOutput) {
# Режим с отображением вывода
Write-Host " Запуск ffmpeg с аргументами: -n -i `"$EscapedInputFile`" -b:a 320k -map_metadata 0 -id3v2_version 3 `"$EscapedOutputFile`"" -ForegroundColor Gray
$process = Start-Process -FilePath "ffmpeg" -ArgumentList "-n", "-i", $EscapedInputFile, "-b:a", "320k", "-map_metadata", "0", "-id3v2_version", "3", $EscapedOutputFile -NoNewWindow -Wait -PassThru
if ($process.ExitCode -eq 0) {
return $true
}
else {
Write-Host " FFmpeg вернул код ошибки: $($process.ExitCode)" -ForegroundColor Red
return $false
}
}
else {
# Режим без вывода - используем асинхронное чтение
$psi = New-Object System.Diagnostics.ProcessStartInfo
$psi.FileName = "ffmpeg"
$psi.Arguments = "-n -i `"$EscapedInputFile`" -b:a 320k -map_metadata 0 -id3v2_version 3 `"$EscapedOutputFile`""
$psi.UseShellExecute = $false
$psi.RedirectStandardOutput = $true
$psi.RedirectStandardError = $true
$psi.CreateNoWindow = $true
$process = [System.Diagnostics.Process]::Start($psi)
# Асинхронное чтение потоков для предотвращения блокировки
$stdoutTask = $process.StandardOutput.ReadToEndAsync()
$stderrTask = $process.StandardError.ReadToEndAsync()
$process.WaitForExit()
# Ожидание завершения чтения потоков
$stdout = $stdoutTask.Result
$stderr = $stderrTask.Result
# Отображаем вывод при ошибке
if ($process.ExitCode -ne 0) {
Write-Host " Вывод ffmpeg (stdout): $stdout" -ForegroundColor Red
Write-Host " Вывод ffmpeg (stderr): $stderr" -ForegroundColor Red
}
if ($process.ExitCode -eq 0) {
return $true
}
else {
Write-Host " FFmpeg вернул код ошибки: $($process.ExitCode)" -ForegroundColor Red
return $false
}
}
}
catch {
Write-Host " Ошибка конвертации: $($_.Exception.Message)" -ForegroundColor Red
return $false
}
}
# Создание функции для копирования файлов с проверкой
function Copy-FileWithStructure {
param(
[System.IO.FileInfo]$SourceFile,
[string]$DestinationBase
)
try {
# Получение относительного пути безопасным способом
$RelativePath = Get-RelativePath -FullPath $SourceFile.FullName -BasePath $SourcePath
# Полный путь назначения
$DestinationFile = Join-Path $DestinationBase $RelativePath
# Нормализация пути назначения
$DestinationFile = [System.IO.Path]::GetFullPath($DestinationFile)
# Проверка существования файла назначения
if (Test-Path $DestinationFile) {
Write-Host " Файл уже существует, пропуск: $DestinationFile" -ForegroundColor Yellow
return $true
}
# Создание директории
$DestinationDir = Split-Path $DestinationFile -Parent
if (!(Test-Path $DestinationDir)) {
New-Item -ItemType Directory -Path $DestinationDir -Force | Out-Null
}
# Копирование файла с использованием LiteralPath для избежания проблем со спецсимволами
Copy-Item -LiteralPath $SourceFile.FullName -Destination $DestinationFile -Force
return $true
}
catch {
Write-Host " Подробная ошибка копирования: $($_.Exception.Message)" -ForegroundColor Red
Write-Host " Исходный файл: $($SourceFile.FullName)" -ForegroundColor Red
return $false
}
}
# Проверка наличия ffmpeg
Write-Host "Проверка наличия FFmpeg..." -ForegroundColor Yellow
try {
$ffmpegTest = Start-Process -FilePath "ffmpeg" -ArgumentList "-version" -NoNewWindow -Wait -PassThru
if ($ffmpegTest.ExitCode -eq 0) {
Write-Host "FFmpeg найден и доступен" -ForegroundColor Green
if ($ShowFFmpegOutput) {
Write-Host "Режим отображения вывода ffmpeg: ВКЛЮЧЕН" -ForegroundColor Cyan
}
else {
Write-Host "Режим отображения вывода ffmpeg: ВЫКЛЮЧЕН" -ForegroundColor Gray
}
}
else {
Write-Host "FFmpeg не найден! Установите FFmpeg и добавьте в PATH" -ForegroundColor Red
exit 1
}
}
catch {
Write-Host "FFmpeg не найден! Установите FFmpeg и добавьте в PATH" -ForegroundColor Red
exit 1
}
Write-Host "`nСовет: Чтобы переключить отображение вывода ffmpeg, установите переменную `$ShowFFmpegOutput" -ForegroundColor Gray
# Основной процесс обработки
Write-Host "Начало обработки музыкальной библиотеки..." -ForegroundColor Green
Write-Host "Источник: $SourcePath"
Write-Host "Назначение: $DestinationPath"
# Проверка существования исходной директории
if (!(Test-Path $SourcePath)) {
Write-Host "Исходная директория не найдена: $SourcePath" -ForegroundColor Red
Write-Host "Проверьте правильность пути и доступность сетевого ресурса" -ForegroundColor Red
exit 1
}
# Создание директории назначения
try {
if (!(Test-Path $DestinationPath)) {
New-Item -ItemType Directory -Path $DestinationPath -Force | Out-Null
}
}
catch {
Write-Host "Ошибка создания директории назначения: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
# Получение всех файлов в исходной директории
Write-Host "Сканирование файлов..." -ForegroundColor Yellow
try {
$AllFiles = Get-ChildItem -Path $SourcePath -Recurse -File -ErrorAction Continue
}
catch {
Write-Host "Ошибка сканирования директории: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
if ($AllFiles.Count -eq 0) {
Write-Host "Файлы не найдены в директории: $SourcePath" -ForegroundColor Yellow
exit 0
}
$TotalFiles = $AllFiles.Count
$ProcessedFiles = 0
$SuccessCount = 0
$ErrorCount = 0
$SkippedCount = 0
Write-Host "Найдено файлов: $TotalFiles" -ForegroundColor Cyan
foreach ($File in $AllFiles) {
$ProcessedFiles++
$Progress = [math]::Round(($ProcessedFiles / $TotalFiles) * 100, 2)
Write-Progress -Activity "Обработка файлов" -Status "Обработано $ProcessedFiles из $TotalFiles" -PercentComplete $Progress
$Extension = $File.Extension.ToLower()
$FileName = $File.Name
Write-Host "Обработка ($Progress%): $FileName" -ForegroundColor Yellow
try {
# Проверка существования файла в назначении
$FileExists = Test-DestinationFileExists -SourceFile $File.FullName -SourceBasePath $SourcePath -DestinationBasePath $DestinationPath
if ($FileExists) {
Write-Host " Файл уже существует в назначении, пропуск" -ForegroundColor Yellow
$SkippedCount++
continue
}
if ($LosslessFormats -contains $Extension) {
# Конвертация файлов без потерь в MP3
$RelativePath = Get-RelativePath -FullPath $File.FullName -BasePath $SourcePath
$OutputFile = Join-Path $DestinationPath $RelativePath
$OutputFile = [System.IO.Path]::ChangeExtension($OutputFile, ".mp3")
# Нормализация пути
$OutputFile = [System.IO.Path]::GetFullPath($OutputFile)
if (Convert-ToMP3 -InputFile $File.FullName -OutputFile $OutputFile) {
Write-Host " ✓ Конвертировано в MP3: $FileName" -ForegroundColor Green
$SuccessCount++
}
else {
Write-Host " ✗ Ошибка конвертации: $FileName" -ForegroundColor Red
$ErrorCount++
}
}
elseif ($AudioFormats -contains $Extension) {
# Копирование аудио файлов
if (Copy-FileWithStructure -SourceFile $File -DestinationBase $DestinationPath) {
Write-Host " ✓ Скопировано: $FileName" -ForegroundColor Cyan
$SuccessCount++
}
else {
Write-Host " ✗ Ошибка копирования: $FileName" -ForegroundColor Red
$ErrorCount++
}
}
else {
# Копирование неаудио файлов (обложки, тексты и т.д.)
if (Copy-FileWithStructure -SourceFile $File -DestinationBase $DestinationPath) {
Write-Host " ✓ Скопирован вспомогательный файл: $FileName" -ForegroundColor Gray
$SuccessCount++
}
else {
Write-Host " ✗ Ошибка копирования вспомогательного файла: $FileName" -ForegroundColor Red
$ErrorCount++
}
}
}
catch {
Write-Host " ✗ Критическая ошибка: $FileName - $($_.Exception.Message)" -ForegroundColor Red
$ErrorCount++
}
}
# Определение цвета для вывода количества ошибок
$ErrorColor = "Green"
if ($ErrorCount -gt 0) {
$ErrorColor = "Red"
}
Write-Host "`nОбработка завершена!" -ForegroundColor Green
Write-Host "========================================" -ForegroundColor Green
Write-Host "Всего файлов: $TotalFiles" -ForegroundColor White
Write-Host "Успешно обработано: $SuccessCount" -ForegroundColor Green
Write-Host "Пропущено (уже существуют): $SkippedCount" -ForegroundColor Yellow
Write-Host "Ошибок: $ErrorCount" -ForegroundColor $ErrorColor
Write-Host "========================================" -ForegroundColor Green
if ($ErrorCount -gt 0) {
Write-Host "Проверьте лог выше для выявления проблемных файлов" -ForegroundColor Yellow
}