Add clip-id based Suno library sync
This commit is contained in:
+108
-16
@@ -1,8 +1,10 @@
|
||||
param(
|
||||
[string]$ManifestPath = "",
|
||||
[string]$OutputRoot = "\\VaultOfData\AKAMedia\음악\처리됨\SUNO",
|
||||
[string]$OutputRoot = "\\VaultOfData\AKAMedia\음악\처리됨",
|
||||
[string]$ArtistName = "SUNO",
|
||||
[string]$FfmpegPath = "",
|
||||
[switch]$KeepWorkFiles
|
||||
[switch]$KeepWorkFiles,
|
||||
[switch]$Force
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
@@ -64,6 +66,70 @@ function ConvertTo-SafeName {
|
||||
return $name
|
||||
}
|
||||
|
||||
function Get-ShortId {
|
||||
param([string]$Id)
|
||||
|
||||
if (-not $Id) { return "unknown-id" }
|
||||
if ($Id.Length -le 12) { return $Id }
|
||||
return $Id.Substring(0, 12)
|
||||
}
|
||||
|
||||
function Get-TrackFolder {
|
||||
param(
|
||||
[string]$Root,
|
||||
[string]$Title,
|
||||
[string]$Id
|
||||
)
|
||||
|
||||
$safeTitle = ConvertTo-SafeName $Title $Id
|
||||
$shortId = Get-ShortId $Id
|
||||
return Join-Path $Root ("{0} [{1}]" -f $safeTitle, $shortId)
|
||||
}
|
||||
|
||||
function Get-AlbumTitle {
|
||||
param(
|
||||
[string]$Title,
|
||||
[string]$Id
|
||||
)
|
||||
|
||||
return "{0} [{1}]" -f (ConvertTo-SafeName $Title $Id), (Get-ShortId $Id)
|
||||
}
|
||||
|
||||
function Resolve-LibraryRoot {
|
||||
param(
|
||||
[string]$Root,
|
||||
[string]$Artist
|
||||
)
|
||||
|
||||
$trimmed = $Root.TrimEnd("\", "/")
|
||||
if ((Split-Path -Leaf $trimmed) -ieq $Artist) {
|
||||
return $trimmed
|
||||
}
|
||||
return Join-Path $trimmed $Artist
|
||||
}
|
||||
|
||||
function Test-ExistingTrack {
|
||||
param(
|
||||
[string]$Root,
|
||||
[string]$Id
|
||||
)
|
||||
|
||||
if (-not $Id -or -not (Test-Path -LiteralPath $Root)) { return $false }
|
||||
|
||||
$metadataHit = Get-ChildItem -LiteralPath $Root -Recurse -Filter "*metadata.json" -File -ErrorAction SilentlyContinue |
|
||||
Where-Object {
|
||||
try {
|
||||
$json = Get-Content -LiteralPath $_.FullName -Raw | ConvertFrom-Json
|
||||
"$($json.id)" -eq $Id
|
||||
} catch {
|
||||
$false
|
||||
}
|
||||
} |
|
||||
Select-Object -First 1
|
||||
|
||||
return [bool]$metadataHit
|
||||
}
|
||||
|
||||
function Get-ObjectValues {
|
||||
param($Value)
|
||||
|
||||
@@ -167,13 +233,13 @@ if (-not $tracks.Count) {
|
||||
throw "manifest에 tracks 배열이 없어."
|
||||
}
|
||||
|
||||
$dateFolder = Get-Date -Format "yyyy-MM-dd"
|
||||
$targetRoot = Join-Path $OutputRoot $dateFolder
|
||||
$workRoot = Join-Path $targetRoot "_work"
|
||||
New-Item -ItemType Directory -Force -Path $targetRoot, $workRoot | Out-Null
|
||||
$libraryRoot = Resolve-LibraryRoot $OutputRoot $ArtistName
|
||||
New-Item -ItemType Directory -Force -Path $libraryRoot | Out-Null
|
||||
$workRoot = Join-Path $libraryRoot "_work"
|
||||
New-Item -ItemType Directory -Force -Path $workRoot | Out-Null
|
||||
|
||||
Write-Host "Manifest: $manifestFile"
|
||||
Write-Host "Output: $targetRoot"
|
||||
Write-Host "Output: $libraryRoot"
|
||||
Write-Host "ffmpeg: $ffmpeg"
|
||||
Write-Host "Tracks: $($tracks.Count)"
|
||||
|
||||
@@ -183,8 +249,18 @@ foreach ($track in $tracks) {
|
||||
|
||||
$id = if ($track.id) { "$($track.id)" } else { "" }
|
||||
$title = if ($track.title) { "$($track.title)" } else { $id }
|
||||
if (-not $Force -and (Test-ExistingTrack $libraryRoot $id)) {
|
||||
Write-Host ""
|
||||
Write-Host "[$index/$($tracks.Count)] 이미 있음, 건너뜀: $title [$id]"
|
||||
continue
|
||||
}
|
||||
|
||||
$albumTitle = Get-AlbumTitle $title $id
|
||||
$trackFolder = Get-TrackFolder $libraryRoot $title $id
|
||||
New-Item -ItemType Directory -Force -Path $trackFolder | Out-Null
|
||||
$safeTitle = ConvertTo-SafeName $title $id
|
||||
$prefix = "{0:D3} - {1}" -f $index, $safeTitle
|
||||
$shortId = Get-ShortId $id
|
||||
$prefix = "{0} [{1}]" -f $safeTitle, $shortId
|
||||
|
||||
$lyrics = Get-DeepValue $track @("prompt", "lyrics", "lyric", "text")
|
||||
$style = Get-DeepValue $track @("gpt_description_prompt", "style", "tags", "description")
|
||||
@@ -199,9 +275,10 @@ foreach ($track in $tracks) {
|
||||
$imageUrl = if ($track.imageUrl) { "$($track.imageUrl)" } else { Get-DeepValue $track @("image_url", "imageUrl", "image_large_url", "cover_url") }
|
||||
|
||||
$inputAudio = Join-Path $workRoot "$prefix.input.wav"
|
||||
$coverFile = Join-Path $workRoot "$prefix.cover.$(Get-UrlExtension $imageUrl 'jpg')"
|
||||
$metadataFile = Join-Path $targetRoot "$prefix.metadata.json"
|
||||
$flacFile = Join-Path $targetRoot "$prefix.flac"
|
||||
$rawCoverFile = Join-Path $workRoot "$prefix.cover.$(Get-UrlExtension $imageUrl 'jpg')"
|
||||
$coverFile = Join-Path $trackFolder "cover.jpg"
|
||||
$metadataFile = Join-Path $trackFolder "metadata.json"
|
||||
$flacFile = Join-Path $trackFolder ("01 {0}.flac" -f $safeTitle)
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "[$index/$($tracks.Count)] $title"
|
||||
@@ -219,7 +296,15 @@ foreach ($track in $tracks) {
|
||||
|
||||
$coverOk = $false
|
||||
if ($imageUrl) {
|
||||
$coverOk = Invoke-Download $imageUrl $coverFile
|
||||
$coverDownloaded = Invoke-Download $imageUrl $rawCoverFile
|
||||
if ($coverDownloaded) {
|
||||
& $ffmpeg -hide_banner -y -i $rawCoverFile -frames:v 1 $coverFile
|
||||
$coverOk = ($LASTEXITCODE -eq 0) -and (Test-Path -LiteralPath $coverFile)
|
||||
if (-not $coverOk) {
|
||||
Copy-Item -LiteralPath $rawCoverFile -Destination $coverFile -Force
|
||||
$coverOk = Test-Path -LiteralPath $coverFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$track | ConvertTo-Json -Depth 50 | Set-Content -LiteralPath $metadataFile -Encoding UTF8
|
||||
@@ -240,21 +325,28 @@ foreach ($track in $tracks) {
|
||||
$argsList.Add("attached_pic")
|
||||
$argsList.Add("-c:v")
|
||||
$argsList.Add("copy")
|
||||
$argsList.Add("-metadata:s:v")
|
||||
$argsList.Add("comment=Cover (front)")
|
||||
}
|
||||
$argsList.Add("-c:a")
|
||||
$argsList.Add("flac")
|
||||
$argsList.Add("-compression_level")
|
||||
$argsList.Add("8")
|
||||
Add-MetadataArg $argsList "title" $title
|
||||
Add-MetadataArg $argsList "artist" "SUNO"
|
||||
Add-MetadataArg $argsList "album" "SUNO"
|
||||
Add-MetadataArg $argsList "artist" $ArtistName
|
||||
Add-MetadataArg $argsList "album" $albumTitle
|
||||
Add-MetadataArg $argsList "album_artist" $ArtistName
|
||||
Add-MetadataArg $argsList "ARTISTS" $ArtistName
|
||||
Add-MetadataArg $argsList "track" "1/1"
|
||||
Add-MetadataArg $argsList "disc" "1/1"
|
||||
Add-MetadataArg $argsList "genre" $style
|
||||
Add-MetadataArg $argsList "lyrics" $lyrics
|
||||
Add-MetadataArg $argsList "lyrics-XXX" $lyrics
|
||||
Add-MetadataArg $argsList "description" $style
|
||||
Add-MetadataArg $argsList "comment" "Suno clip id: $id"
|
||||
Add-MetadataArg $argsList "date" $createdAt
|
||||
Add-MetadataArg $argsList "encoder" "Codex SUNO helper"
|
||||
Add-MetadataArg $argsList "suno_model" $model
|
||||
Add-MetadataArg $argsList "TMED" "Digital Media"
|
||||
$argsList.Add($flacFile)
|
||||
|
||||
& $ffmpeg @argsList
|
||||
@@ -271,4 +363,4 @@ if (-not $KeepWorkFiles -and (Test-Path -LiteralPath $workRoot)) {
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "처리 완료: $targetRoot"
|
||||
Write-Host "처리 완료: $libraryRoot"
|
||||
|
||||
Reference in New Issue
Block a user