This commit is contained in:
@@ -0,0 +1,280 @@
|
||||
Set-StrictMode -Version Latest
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$script:RepoRoot = Split-Path -Parent $PSScriptRoot
|
||||
$script:ToolsRoot = Join-Path $script:RepoRoot ".tools"
|
||||
$script:BinRoot = Join-Path $script:ToolsRoot "bin"
|
||||
$script:GoRoot = Join-Path $script:ToolsRoot "go"
|
||||
$script:GoBin = Join-Path $script:GoRoot "bin"
|
||||
$script:FFmpegRoot = Join-Path $script:ToolsRoot "ffmpeg"
|
||||
$script:FFmpegBin = Join-Path $script:FFmpegRoot "bin"
|
||||
$script:VenvRoot = Join-Path $script:RepoRoot ".venv"
|
||||
$script:VenvScripts = Join-Path $script:VenvRoot "Scripts"
|
||||
$script:LocalRoot = Join-Path $script:RepoRoot ".local"
|
||||
$script:GoPathRoot = Join-Path $script:LocalRoot "go"
|
||||
$script:GoModCacheRoot = Join-Path $script:GoPathRoot "pkg\mod"
|
||||
$script:GoBuildCacheRoot = Join-Path $script:LocalRoot "go-build-cache"
|
||||
$script:CredentialFile = Join-Path $script:LocalRoot "git-credentials.psd1"
|
||||
|
||||
function Write-Step {
|
||||
param([string]$Message)
|
||||
Write-Host "[ai-media-hub] $Message"
|
||||
}
|
||||
|
||||
function Invoke-CheckedCommand {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$FilePath,
|
||||
[string[]]$Arguments = @()
|
||||
)
|
||||
|
||||
& $FilePath @Arguments
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$joined = if ($Arguments.Count -gt 0) { " " + ($Arguments -join " ") } else { "" }
|
||||
throw "명령 실행 실패: $FilePath$joined"
|
||||
}
|
||||
}
|
||||
|
||||
function Ensure-Directory {
|
||||
param([Parameter(Mandatory = $true)][string]$Path)
|
||||
if (-not (Test-Path -LiteralPath $Path)) {
|
||||
New-Item -ItemType Directory -Path $Path | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Get-RepoRoot { return $script:RepoRoot }
|
||||
function Get-ToolsRoot { return $script:ToolsRoot }
|
||||
function Get-BinRoot { return $script:BinRoot }
|
||||
function Get-GoRoot { return $script:GoRoot }
|
||||
function Get-GoBin { return $script:GoBin }
|
||||
function Get-FFmpegBin { return $script:FFmpegBin }
|
||||
function Get-VenvRoot { return $script:VenvRoot }
|
||||
function Get-VenvScripts { return $script:VenvScripts }
|
||||
function Get-LocalRoot { return $script:LocalRoot }
|
||||
function Get-GoPathRoot { return $script:GoPathRoot }
|
||||
function Get-GoModCacheRoot { return $script:GoModCacheRoot }
|
||||
function Get-GoBuildCacheRoot { return $script:GoBuildCacheRoot }
|
||||
function Get-CredentialFile { return $script:CredentialFile }
|
||||
|
||||
function Resolve-SystemCommand {
|
||||
param([Parameter(Mandatory = $true)][string]$Name)
|
||||
try {
|
||||
return (Get-Command $Name -ErrorAction Stop).Source
|
||||
} catch {
|
||||
return $null
|
||||
}
|
||||
}
|
||||
|
||||
function Resolve-PythonExe {
|
||||
$candidates = @(
|
||||
(Join-Path $script:VenvScripts "python.exe"),
|
||||
(Resolve-SystemCommand -Name "python")
|
||||
)
|
||||
foreach ($candidate in $candidates) {
|
||||
if ($candidate -and (Test-Path -LiteralPath $candidate)) {
|
||||
return $candidate
|
||||
}
|
||||
}
|
||||
throw "python.exe를 찾을 수 없습니다. Python 3.12+가 필요합니다."
|
||||
}
|
||||
|
||||
function Resolve-BasePythonExe {
|
||||
$all = @(Get-Command python -All -ErrorAction SilentlyContinue)
|
||||
foreach ($item in $all) {
|
||||
if ($item.Source -and $item.Source -notlike "*\.venv\*") {
|
||||
return $item.Source
|
||||
}
|
||||
}
|
||||
$fallback = Resolve-SystemCommand -Name "python"
|
||||
if ($fallback -and $fallback -notlike "*\.venv\*") {
|
||||
return $fallback
|
||||
}
|
||||
throw "시스템 python.exe를 찾지 못했습니다."
|
||||
}
|
||||
|
||||
function Resolve-VenvPythonExe {
|
||||
$pythonExe = Join-Path $script:VenvScripts "python.exe"
|
||||
if (-not (Test-Path -LiteralPath $pythonExe)) {
|
||||
throw ".venv가 아직 준비되지 않았습니다. scripts/setup-dev.ps1를 먼저 실행하세요."
|
||||
}
|
||||
return $pythonExe
|
||||
}
|
||||
|
||||
function Use-LocalTooling {
|
||||
Ensure-Directory -Path $script:ToolsRoot
|
||||
Ensure-Directory -Path $script:BinRoot
|
||||
Ensure-Directory -Path $script:LocalRoot
|
||||
Ensure-Directory -Path $script:GoPathRoot
|
||||
Ensure-Directory -Path $script:GoModCacheRoot
|
||||
Ensure-Directory -Path $script:GoBuildCacheRoot
|
||||
|
||||
$segments = @(
|
||||
$script:BinRoot,
|
||||
$script:GoBin,
|
||||
$script:FFmpegBin,
|
||||
$script:VenvScripts,
|
||||
$env:PATH
|
||||
) | Where-Object { $_ -and $_.Trim() -ne "" }
|
||||
|
||||
$env:PATH = ($segments | Select-Object -Unique) -join ";"
|
||||
$env:GOPATH = $script:GoPathRoot
|
||||
$env:GOMODCACHE = $script:GoModCacheRoot
|
||||
$env:GOCACHE = $script:GoBuildCacheRoot
|
||||
}
|
||||
|
||||
function Ensure-Venv {
|
||||
$venvPython = Join-Path $script:VenvScripts "python.exe"
|
||||
if (Test-Path -LiteralPath $venvPython) {
|
||||
return $venvPython
|
||||
}
|
||||
|
||||
Ensure-Directory -Path $script:LocalRoot
|
||||
$pythonExe = Resolve-SystemCommand -Name "python"
|
||||
if (-not $pythonExe) {
|
||||
throw "시스템 python이 없어 .venv를 만들 수 없습니다."
|
||||
}
|
||||
|
||||
Write-Step ".venv 생성"
|
||||
& $pythonExe -m venv $script:VenvRoot
|
||||
return $venvPython
|
||||
}
|
||||
|
||||
function Install-PythonRequirements {
|
||||
param([switch]$UpgradePip)
|
||||
|
||||
$venvPython = Ensure-Venv
|
||||
$systemPython = Resolve-BasePythonExe
|
||||
|
||||
if ($UpgradePip) {
|
||||
Write-Step "pip 업그레이드"
|
||||
Invoke-CheckedCommand -FilePath $systemPython -Arguments @("-m", "pip", "--python", $venvPython, "install", "--upgrade", "pip")
|
||||
}
|
||||
|
||||
Write-Step "worker requirements 설치"
|
||||
Invoke-CheckedCommand -FilePath $systemPython -Arguments @("-m", "pip", "--python", $venvPython, "install", "-r", (Join-Path $script:RepoRoot "worker\requirements.txt"))
|
||||
}
|
||||
|
||||
function New-CmdShim {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$Path,
|
||||
[Parameter(Mandatory = $true)][string]$Target
|
||||
)
|
||||
|
||||
$content = @(
|
||||
"@echo off",
|
||||
"set SCRIPT_DIR=%~dp0",
|
||||
"`"%SCRIPT_DIR%$Target`" %*"
|
||||
) -join "`r`n"
|
||||
Set-Content -LiteralPath $Path -Value $content -Encoding ASCII
|
||||
}
|
||||
|
||||
function Ensure-CommandShims {
|
||||
Ensure-Directory -Path $script:BinRoot
|
||||
|
||||
$pythonShimTarget = "..\..\ .venv\Scripts\python.exe".Replace(" ", "")
|
||||
New-CmdShim -Path (Join-Path $script:BinRoot "python3.cmd") -Target $pythonShimTarget
|
||||
|
||||
$ytDlpExe = Join-Path $script:VenvScripts "yt-dlp.exe"
|
||||
if (Test-Path -LiteralPath $ytDlpExe) {
|
||||
New-CmdShim -Path (Join-Path $script:BinRoot "yt-dlp.cmd") -Target "..\..\ .venv\Scripts\yt-dlp.exe".Replace(" ", "")
|
||||
}
|
||||
}
|
||||
|
||||
function Test-GoReady {
|
||||
return [bool](Resolve-SystemCommand -Name "go")
|
||||
}
|
||||
|
||||
function Test-FFmpegReady {
|
||||
return [bool](Resolve-SystemCommand -Name "ffmpeg")
|
||||
}
|
||||
|
||||
function Test-YtDlpReady {
|
||||
return [bool](Resolve-SystemCommand -Name "yt-dlp")
|
||||
}
|
||||
|
||||
function Install-LocalGo {
|
||||
param(
|
||||
[string]$Version = "1.24.0",
|
||||
[string]$ArchiveUrl = ""
|
||||
)
|
||||
|
||||
if (Test-Path -LiteralPath (Join-Path $script:GoBin "go.exe")) {
|
||||
Write-Step "로컬 Go 이미 준비됨"
|
||||
return
|
||||
}
|
||||
|
||||
if (-not $ArchiveUrl) {
|
||||
$ArchiveUrl = "https://go.dev/dl/go$Version.windows-amd64.zip"
|
||||
}
|
||||
|
||||
Ensure-Directory -Path $script:ToolsRoot
|
||||
$archivePath = Join-Path $script:LocalRoot "go-$Version.windows-amd64.zip"
|
||||
Write-Step "로컬 Go 다운로드: $ArchiveUrl"
|
||||
Invoke-WebRequest -Uri $ArchiveUrl -OutFile $archivePath
|
||||
|
||||
if (Test-Path -LiteralPath $script:GoRoot) {
|
||||
Remove-Item -Recurse -Force $script:GoRoot
|
||||
}
|
||||
Expand-Archive -LiteralPath $archivePath -DestinationPath $script:ToolsRoot -Force
|
||||
}
|
||||
|
||||
function Install-LocalFFmpeg {
|
||||
param([string]$ArchiveUrl = "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip")
|
||||
|
||||
if (Test-Path -LiteralPath (Join-Path $script:FFmpegBin "ffmpeg.exe")) {
|
||||
Write-Step "로컬 ffmpeg 이미 준비됨"
|
||||
return
|
||||
}
|
||||
|
||||
Ensure-Directory -Path $script:ToolsRoot
|
||||
$archivePath = Join-Path $script:LocalRoot "ffmpeg-release-essentials.zip"
|
||||
Write-Step "로컬 ffmpeg 다운로드: $ArchiveUrl"
|
||||
Invoke-WebRequest -Uri $ArchiveUrl -OutFile $archivePath
|
||||
|
||||
$extractRoot = Join-Path $script:LocalRoot "ffmpeg-extract"
|
||||
if (Test-Path -LiteralPath $extractRoot) {
|
||||
Remove-Item -Recurse -Force $extractRoot
|
||||
}
|
||||
Expand-Archive -LiteralPath $archivePath -DestinationPath $extractRoot -Force
|
||||
|
||||
$binCandidate = Get-ChildItem -Path $extractRoot -Recurse -Filter "ffmpeg.exe" | Select-Object -First 1
|
||||
if (-not $binCandidate) {
|
||||
throw "ffmpeg.exe를 압축 파일에서 찾지 못했습니다."
|
||||
}
|
||||
|
||||
$sourceBin = Split-Path -Parent $binCandidate.FullName
|
||||
if (Test-Path -LiteralPath $script:FFmpegRoot) {
|
||||
Remove-Item -Recurse -Force $script:FFmpegRoot
|
||||
}
|
||||
Ensure-Directory -Path $script:FFmpegBin
|
||||
Copy-Item -Path (Join-Path $sourceBin "*") -Destination $script:FFmpegBin -Recurse -Force
|
||||
}
|
||||
|
||||
function Get-AppEnvironment {
|
||||
param(
|
||||
[Parameter(Mandatory = $true)][string]$WorkspaceRoot,
|
||||
[Parameter(Mandatory = $true)][string]$DownloadsDir,
|
||||
[Parameter(Mandatory = $true)][string]$SqlitePath,
|
||||
[Parameter(Mandatory = $true)][string]$AppAddr,
|
||||
[string]$SearxUrl = "http://127.0.0.1:18080"
|
||||
)
|
||||
|
||||
return @{
|
||||
APP_ROOT = $WorkspaceRoot
|
||||
APP_ADDR = $AppAddr
|
||||
SQLITE_PATH = $SqlitePath
|
||||
DOWNLOADS_DIR = $DownloadsDir
|
||||
FRONTEND_DIR = (Join-Path $WorkspaceRoot "frontend")
|
||||
WORKER_SCRIPT = (Join-Path $WorkspaceRoot "worker\downloader.py")
|
||||
SEARXNG_BASE_URL = $SearxUrl
|
||||
SEARXNG_GOOGLE_VIDEO_ENGINE = "google videos"
|
||||
SEARXNG_WEB_ENGINE = "google"
|
||||
}
|
||||
}
|
||||
|
||||
function Import-GitCredential {
|
||||
$credentialFile = Get-CredentialFile
|
||||
if (-not (Test-Path -LiteralPath $credentialFile)) {
|
||||
throw "git 자격정보 파일이 없습니다: $credentialFile"
|
||||
}
|
||||
return Import-PowerShellDataFile -Path $credentialFile
|
||||
}
|
||||
Reference in New Issue
Block a user