feat(ads/seo/release): v1.2.0 with live Google Ads, isolated ad profile, ads.txt, and SEO/AEO/GEO optimization

This commit is contained in:
Yun Chan 2026-09-14 00:39:44 +09:00
parent a88aafa1e5
commit 0e568f1f0a
975 changed files with 130593 additions and 16783 deletions

73
build/Paca.wxs Normal file
View file

@ -0,0 +1,73 @@
<Wix xmlns="http://wixtoolset.org/schemas/v4/wxs">
<?if $(var.Arch) = arm64 ?>
<?define UpgradeCode = "2E0ADFC1-2072-4457-8C50-ECFCEDECAD73" ?>
<?define PlatformProgramFiles = "ProgramFiles64Folder" ?>
<?else?>
<?define UpgradeCode = "65393C7D-17DC-4B9F-9D0B-F9911092C449" ?>
<?define PlatformProgramFiles = "ProgramFiles64Folder" ?>
<?endif?>
<Package Name="Paca"
Manufacturer="Paca"
Version="$(var.Version)"
UpgradeCode="$(var.UpgradeCode)"
Scope="perMachine">
<SummaryInformation Description="Paca High Performance Video &amp; Media Downloader" />
<MajorUpgrade DowngradeErrorMessage="A newer version of Paca is already installed." />
<MediaTemplate EmbedCab="yes" CompressionLevel="high" />
<Icon Id="PacaIcon" SourceFile="$(var.SourceDir)\src\Paca.App\Assets\paca.ico" />
<Property Id="ARPPRODUCTICON" Value="PacaIcon" />
<Property Id="ARPHELPLINK" Value="https://paca.pages.dev" />
<Property Id="ARPURLINFOABOUT" Value="https://paca.pages.dev" />
<StandardDirectory Id="$(var.PlatformProgramFiles)">
<Directory Id="INSTALLFOLDER" Name="Paca" />
</StandardDirectory>
<StandardDirectory Id="ProgramMenuFolder">
<Component Id="ApplicationStartMenuShortcut" Guid="B6E09736-1215-46D2-95F8-A5DEBC0F58E9">
<Shortcut Id="StartMenuShortcut"
Name="Paca"
Description="Paca - High Performance Video &amp; Media Downloader"
Target="[INSTALLFOLDER]Paca.exe"
WorkingDirectory="INSTALLFOLDER"
Icon="PacaIcon" />
<RemoveFolder Id="CleanUpStartMenuShortCut" On="uninstall" />
<RegistryValue Root="HKCU" Key="Software\Paca" Name="startMenuShortcut" Type="integer" Value="1" KeyPath="yes" />
</Component>
</StandardDirectory>
<StandardDirectory Id="DesktopFolder">
<Component Id="ApplicationDesktopShortcut" Guid="6A478C21-6A79-4B07-B5BD-D7FE80D9F362">
<Shortcut Id="DesktopShortcut"
Name="Paca"
Description="Paca - High Performance Video &amp; Media Downloader"
Target="[INSTALLFOLDER]Paca.exe"
WorkingDirectory="INSTALLFOLDER"
Icon="PacaIcon" />
<RegistryValue Root="HKCU" Key="Software\Paca" Name="desktopShortcut" Type="integer" Value="1" KeyPath="yes" />
</Component>
</StandardDirectory>
<!-- Custom URL Scheme: paca:// -->
<Component Id="PacaProtocolHandler" Guid="D3F14825-4C3D-4A2B-896B-85FE6AE85112" Directory="INSTALLFOLDER">
<RegistryKey Root="HKCU" Key="Software\Classes\paca">
<RegistryValue Type="string" Value="URL:Paca Protocol" />
<RegistryValue Name="URL Protocol" Type="string" Value="" />
<RegistryKey Key="shell\open\command">
<RegistryValue Type="string" Value="&quot;[INSTALLFOLDER]Paca.exe&quot; &quot;%1&quot;" />
</RegistryKey>
</RegistryKey>
<RegistryValue Root="HKCU" Key="Software\Paca" Name="protocolHandler" Type="integer" Value="1" KeyPath="yes" />
</Component>
<Feature Id="MainFeature" Title="Paca" Level="1">
<Files Directory="INSTALLFOLDER" Include="$(var.PublishDir)\**" />
<ComponentRef Id="ApplicationStartMenuShortcut" />
<ComponentRef Id="ApplicationDesktopShortcut" />
<ComponentRef Id="PacaProtocolHandler" />
</Feature>
</Package>
</Wix>

View file

@ -1,8 +1,8 @@
# MEDIABROWSER 사이트(site/)를 Cloudflare Pages 에 배포한다.
# 사용: ./build/deploy-site.ps1 [-Project mediabrowser]
# Paca 사이트(site/)를 Cloudflare Pages 에 배포한다.
# 사용: ./build/deploy-site.ps1 [-Project Paca]
# 필요: .env 의 CLOUDFLARE_API_TOKEN, CLOUDFLARE_ACCOUNT_ID · node/npx(wrangler)
# 절차: 공개 릴리스 저장소에서 releases.json 생성 → wrangler pages deploy
param([string]$Project = "mediabrowser")
param([string]$Project = $(if ($env:CF_PAGES_PROJECT) { $env:CF_PAGES_PROJECT } else { "mediabrowser" }))
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot

View file

@ -1,10 +1,10 @@
; MediaBrowser(구 VideoDownloader) Windows 설치자 (Inno Setup)
; publish.ps1 이 /DARCH=x64 또는 /DARCH=arm64 로 2회 컴파일 → out/MediaBrowser-Setup-<arch>.exe
; 배포명만 MediaBrowser 로 개명 — AppId(GUID)·실행 파일명·데이터 경로는 유지해 기존 설치 업그레이드 호환.
; Paca(구 Paca) Windows 설치자 (Inno Setup)
; publish.ps1 이 /DARCH=x64 또는 /DARCH=arm64 로 2회 컴파일 → out/Paca-Setup-<arch>.exe
; 배포명만 Paca 로 개명 — AppId(GUID)·실행 파일명·데이터 경로는 유지해 기존 설치 업그레이드 호환.
#define APP_NAME "MediaBrowser"
#define APP_PUBLISHER "MediaBrowser"
#define APP_EXE "VideoDownloader.exe"
#define APP_NAME "Paca"
#define APP_PUBLISHER "Paca"
#define APP_EXE "Paca.exe"
#ifndef APP_VERSION
#define APP_VERSION "1.0.0"
#endif
@ -33,12 +33,12 @@ ArchitecturesInstallIn64BitMode=x64compatible
; arm64 전용(네이티브). x64 머신에선 거부.
ArchitecturesAllowed=arm64
AppId={{2E0ADFC1-2072-4457-8C50-ECFCEDECAD73}
OutputBaseFilename=MediaBrowser-Setup-arm64
OutputBaseFilename=Paca-Setup-arm64
#else
; x64 + arm64(x64 에뮬레이션 폴백) 어디서든 설치 가능한 범용 설치자.
ArchitecturesAllowed=x64compatible
AppId={{65393C7D-17DC-4B9F-9D0B-F9911092C449}
OutputBaseFilename=MediaBrowser-Setup-x64
OutputBaseFilename=Paca-Setup-x64
#endif
[Languages]
@ -47,6 +47,13 @@ Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
Name: "gatewayservice"; Description: "모바일 원클릭 연결용 백그라운드 게이트웨이 서비스 자동 시작 (권장)"; GroupDescription: "원격 연결 설정"; Flags: checkedonce
[Registry]
Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run"; ValueType: string; ValueName: "PacaGatewayDaemon"; ValueData: """{app}\{#APP_EXE}"" --gateway-daemon"; Flags: uninsdeletevalue; Tasks: gatewayservice
Root: HKCU; Subkey: "Software\Classes\paca"; ValueType: string; ValueName: ""; ValueData: "URL:Paca Protocol"; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\paca"; ValueType: string; ValueName: "URL Protocol"; ValueData: ""; Flags: uninsdeletekey
Root: HKCU; Subkey: "Software\Classes\paca\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\{#APP_EXE}"" ""%1"""; Flags: uninsdeletekey
[Files]
; self-contained publish 결과 전체를 앱 디렉터리로 복사

View file

@ -1,8 +1,8 @@
{
{
"//": "Obtainium 원탭 등록용 앱 설정 (DEPLOYMENT_PLAN §3.1) — Forgejo 공개 릴리스 저장소 기준",
"id": "com.companyname.videodownloader.mobile",
"url": "https://git.chanpaca.net/Video-Downloader/releases",
"author": "Video-Downloader",
"name": "MediaBrowser",
"id": "com.companyname.Paca.Mobile",
"url": "https://git.chanpaca.net/Paca/releases",
"author": "Paca",
"name": "Paca",
"additionalSettings": "{\"apkFilterRegEx\":\"apk$\",\"autoApkFilterByArch\":true,\"includePrereleases\":false}"
}

View file

@ -1,33 +1,48 @@
# MediaBrowser(구 VideoDownloader) 다중 아키텍처 설치자 빌드
# 사용: ./build/publish.ps1 [-Config Release] [-Version 1.0.0]
# 결과: out/MediaBrowser-Setup-x64.exe, out/MediaBrowser-Setup-arm64.exe
# Paca 다중 아키텍처 설치자 빌드 (Inno Setup EXE + WiX MSI)
# 사용: ./build/publish.ps1 [-Config Release] [-Version 1.1.0] [-Archs @("x64", "arm64")]
# 결과: out/Paca-Setup-x64.exe, out/Paca-Setup-x64.msi, out/Paca-Setup-arm64.exe, out/Paca-Setup-arm64.msi
param(
[string]$Config = "Release",
[string]$Version = "1.0.0",
[string[]]$Archs = @("x64", "arm64")
[string]$Version = "1.1.0",
[string[]]$Archs = @("x64", "arm64"),
[switch]$SkipExe,
[switch]$SkipMsi
)
$ErrorActionPreference = "Stop"
$root = Split-Path -Parent $PSScriptRoot # 레포 루트
$app = Join-Path $root "VideoDownloader.App\VideoDownloader.App.csproj"
$app = Join-Path $root "src\Paca.App\Paca.App.csproj"
$iss = Join-Path $PSScriptRoot "installer.iss"
$wxs = Join-Path $PSScriptRoot "Paca.wxs"
$outDir = Join-Path $root "out"
# --- ISCC(=Inno Setup 컴파일러) 위치 해결 ---
$iscc = $null
foreach ($cand in @(
"${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe",
"$env:ProgramFiles\Inno Setup 6\ISCC.exe",
"$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe",
"$env:LOCALAPPDATA\Programs\Inno Setup 6.7\ISCC.exe"
)) {
if ($cand -and (Test-Path $cand)) { $iscc = $cand; break }
if (-not $SkipExe) {
foreach ($cand in @(
"${env:ProgramFiles(x86)}\Inno Setup 6\ISCC.exe",
"$env:ProgramFiles\Inno Setup 6\ISCC.exe",
"$env:LOCALAPPDATA\Programs\Inno Setup 6\ISCC.exe",
"$env:LOCALAPPDATA\Programs\Inno Setup 6.7\ISCC.exe"
)) {
if ($cand -and (Test-Path $cand)) { $iscc = $cand; break }
}
if (-not $iscc) { $iscc = (Get-Command ISCC.exe -ErrorAction SilentlyContinue).Source }
if (-not $iscc) {
throw "Inno Setup(ISCC) 를 찾을 수 없습니다. 설치: winget install --id JRSoftware.InnoSetup -e"
}
Write-Host "ISCC: $iscc" -ForegroundColor DarkGray
}
if (-not $iscc) { $iscc = (Get-Command ISCC.exe -ErrorAction SilentlyContinue).Source }
if (-not $iscc) {
throw "Inno Setup(ISCC) 를 찾을 수 없습니다. 설치: winget install --id JRSoftware.InnoSetup -e"
# --- WiX CLI 위치 확인 ---
if (-not $SkipMsi) {
$wixCmd = Get-Command wix -ErrorAction SilentlyContinue
if (-not $wixCmd) {
throw "WiX Toolset CLI(wix) 를 찾을 수 없습니다. 설치: dotnet tool install --global wix --version 5.0.2"
}
Write-Host "WiX: $($wixCmd.Source)" -ForegroundColor DarkGray
}
Write-Host "ISCC: $iscc" -ForegroundColor DarkGray
New-Item -ItemType Directory -Force -Path $outDir | Out-Null
foreach ($arch in $Archs) {
@ -40,13 +55,24 @@ foreach ($arch in $Archs) {
dotnet publish $app -c $Config -r $rid -p:Platform=$arch --self-contained -o $pub
if ($LASTEXITCODE -ne 0) { throw "publish 실패: $rid (exit $LASTEXITCODE). arm64 는 yt-dlp/WebView2 런타임 관련 처음 빌드 시 이슈가 있을 수 있습니다." }
Write-Host "==== [$arch] Inno Setup 컴파일 ====" -ForegroundColor Cyan
& $iscc /Q "/DAPP_VERSION=$Version" "/DARCH=$arch" "/DPUBLISH_DIR=$pub" $iss
if ($LASTEXITCODE -ne 0) { throw "ISCC 실패: $arch (exit $LASTEXITCODE)" }
Write-Host "완료: out\MediaBrowser-Setup-$arch.exe" -ForegroundColor Green
if (-not $SkipExe) {
Write-Host "==== [$arch] Inno Setup 컴파일 (.exe) ====" -ForegroundColor Cyan
& $iscc /Q "/DAPP_VERSION=$Version" "/DARCH=$arch" "/DPUBLISH_DIR=$pub" $iss
if ($LASTEXITCODE -ne 0) { throw "ISCC 실패: $arch (exit $LASTEXITCODE)" }
Write-Host "완료: out\Paca-Setup-$arch.exe" -ForegroundColor Green
}
if (-not $SkipMsi) {
Write-Host "==== [$arch] WiX MSI 컴파일 (.msi) ====" -ForegroundColor Cyan
$msiOut = Join-Path $outDir "Paca-Setup-$arch.msi"
& wix build $wxs -d Version=$Version -d Arch=$arch -d PublishDir=$pub -d SourceDir=$root -arch $arch -o $msiOut
if ($LASTEXITCODE -ne 0) { throw "WiX MSI 실패: $arch (exit $LASTEXITCODE)" }
Write-Host "완료: out\Paca-Setup-$arch.msi" -ForegroundColor Green
}
}
Write-Host ""
Write-Host "설치자 생성 완료:" -ForegroundColor Green
Get-ChildItem (Join-Path $outDir "MediaBrowser-Setup-*.exe") |
Get-ChildItem (Join-Path $outDir "Paca-Setup-*.*") |
Where-Object { $_.Extension -in @(".exe", ".msi") } |
ForEach-Object { Write-Host (" {0,-38} {1:N1} MB" -f $_.Name, ($_.Length / 1MB)) }

View file

@ -1,8 +1,8 @@
# MediaBrowser 원클릭 통합 릴리스 & 사이트 배포 스크립트
# Paca 원클릭 통합 릴리스 & 사이트 배포 스크립트
#
# 동작:
# 1) Windows 설치자(x64, arm64) 빌드 (+ 선택: Android APK, 원격 Linux/macOS 머신 빌드)
# 2) NAS Git(Forgejo)의 공개 릴리스 저장소(Video-Downloader/releases)에 릴리스 생성 및 자산 업로드
# 2) NAS Git(Forgejo)의 공개 릴리스 저장소(Paca/releases)에 릴리스 생성 및 자산 업로드
# 3) (선택: -DeploySite) releases.json 갱신 및 Cloudflare Pages 배포
#
# 사용 예시:
@ -28,7 +28,7 @@ $root = Split-Path -Parent $PSScriptRoot
$outDir = Join-Path $root "out"
Write-Host "======================================================" -ForegroundColor Cyan
Write-Host " MediaBrowser 릴리스 파이프라인 (v$Version)" -ForegroundColor Cyan
Write-Host " Paca 릴리스 파이프라인 (v$Version)" -ForegroundColor Cyan
Write-Host "======================================================" -ForegroundColor Cyan
# ── 1. .env 환경변수 로드 ────────────────────────────────────
@ -57,13 +57,16 @@ if (-not $SkipBuild) {
if ($IncludeAndroid) {
Write-Host "`n[2/4] Android APK 빌드" -ForegroundColor Yellow
$mobileCsproj = Join-Path $root "VideoDownloader.Mobile\VideoDownloader.Mobile.csproj"
$mobileCsproj = Join-Path $root "src\Paca.Mobile\Paca.Mobile.csproj"
$androidOut = Join-Path $outDir "android"
dotnet publish $mobileCsproj -f net10.0-android -c $Config -p:AndroidPackageFormat=apk -p:CiPackArm64Only=true -o $androidOut
if ($LASTEXITCODE -eq 0) {
$apk = Get-ChildItem (Join-Path $androidOut "*.apk") | Select-Object -First 1
$apk = Get-ChildItem (Join-Path $androidOut "*Signed.apk") | Select-Object -First 1
if (-not $apk) {
$apk = Get-ChildItem (Join-Path $androidOut "*.apk") | Select-Object -First 1
}
if ($apk) {
$targetApk = Join-Path $outDir "MediaBrowser-$Version-arm64.apk"
$targetApk = Join-Path $outDir "Paca-$Version-arm64.apk"
Copy-Item $apk.FullName $targetApk -Force
Write-Host "Android APK 생성 완료: $targetApk" -ForegroundColor Green
}
@ -88,9 +91,10 @@ if (-not $SkipBuild) {
# ── 3. 수집된 자산 목록 확인 ──────────────────────────────────
$assetsToUpload = @()
$candPatterns = @(
"MediaBrowser-Setup-*.exe",
"MediaBrowser-*-arm64.apk",
"mediabrowser-*.tar.gz"
"Paca-Setup-*.exe",
"Paca-Setup-*.msi",
"Paca-*-arm64.apk",
"Paca-*.tar.gz"
)
foreach ($pat in $candPatterns) {
@ -137,6 +141,6 @@ Write-Host " 릴리스 완료: $tag" -ForegroundColor Green
if ($Publish) {
Write-Host " 상태: 정식 공개(Published)" -ForegroundColor Green
} else {
Write-Host " 상태: 초안(Draft) — 웹 UI(https://git.chanpaca.net/$Repo/releases)에서 확인 후 공개 가능" -ForegroundColor Yellow
Write-Host " 상태: 초안(Draft) - 웹 UI(https://git.chanpaca.net/$Repo/releases)에서 확인 후 공개 가능" -ForegroundColor Yellow
}
Write-Host "======================================================" -ForegroundColor Green

View file

@ -1,6 +1,6 @@
# MediaBrowser 원격 빌드 수집 스크립트 (PowerShell)
# Paca 원격 빌드 수집 스크립트 (PowerShell)
# 빌드머신(vd-linux / vd-mac)에서 Cli + Avalonia 셸을 RID별 self-contained publish 하고
# 산출물을 out/mediabrowser-<rid>.tar.gz 로 수집한다.
# 산출물을 out/Paca-<rid>.tar.gz 로 수집한다.
#
# 사용: ./build/remote/build-remote.ps1 [-Target mac|linux|all]
param(
@ -13,7 +13,7 @@ $root = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
$outDir = Join-Path $root "out"
New-Item -ItemType Directory -Path $outDir -Force | Out-Null
$remoteDir = "build/videodownloader"
$remoteDir = "build/Paca"
function Push-Source {
param([string]$HostName)
@ -36,16 +36,16 @@ function Build-And-Collect {
param([string]$HostName, [string]$Rid)
Write-Host "==> [$HostName] publish $Rid" -ForegroundColor Cyan
$cmd = "cd $remoteDir && export DOTNET_ROOT=`$HOME/.dotnet && export PATH=`$HOME/.dotnet:`$PATH && " +
"dotnet publish VideoDownloader.Cli -c Release -r $Rid --self-contained -o out/cli-$Rid && " +
"dotnet publish VideoDownloader.Avalonia -c Release -r $Rid --self-contained -o out/avalonia-$Rid && " +
"cd out && tar -czf mediabrowser-$Rid.tar.gz cli-$Rid avalonia-$Rid"
"dotnet publish src/Paca.Cli -c Release -r $Rid --self-contained -o out/cli-$Rid && " +
"dotnet publish src/Paca.Avalonia -c Release -r $Rid --self-contained -o out/avalonia-$Rid && " +
"cd out && tar -czf Paca-$Rid.tar.gz cli-$Rid avalonia-$Rid"
& ssh.exe $HostName $cmd
if ($LASTEXITCODE -ne 0) { throw "[$HostName] 빌드 실패: $Rid" }
$localTarget = Join-Path $outDir "mediabrowser-$Rid.tar.gz"
Write-Host "==> [$HostName] 수집: mediabrowser-$Rid.tar.gz" -ForegroundColor Green
& scp.exe "${HostName}:${remoteDir}/out/mediabrowser-$Rid.tar.gz" $localTarget
$localTarget = Join-Path $outDir "Paca-$Rid.tar.gz"
Write-Host "==> [$HostName] 수집: Paca-$Rid.tar.gz" -ForegroundColor Green
& scp.exe "${HostName}:${remoteDir}/out/Paca-$Rid.tar.gz" $localTarget
if ($LASTEXITCODE -ne 0) { throw "[$HostName] 산출물 수집 실패: $Rid" }
}
@ -62,5 +62,5 @@ if ($Target -eq "linux" -or $Target -eq "all") {
}
Write-Host "`n원격 빌드 및 수집 완료:" -ForegroundColor Green
Get-ChildItem (Join-Path $outDir "mediabrowser-*.tar.gz") |
Get-ChildItem (Join-Path $outDir "Paca-*.tar.gz") |
ForEach-Object { Write-Host (" {0,-35} {1:N1} MB" -f $_.Name, ($_.Length / 1MB)) }

View file

@ -1,14 +1,14 @@
#!/usr/bin/env bash
# 빌드머신(ChanpacaLaptop=linux / Mac mini=macos)에서
# Cli + Avalonia 셸을 RID별 self-contained publish 하고
# 산출물을 로컬 out/mediabrowser-<rid>.tar.gz 로 수집한다.
# 산출물을 로컬 out/Paca-<rid>.tar.gz 로 수집한다.
#
# 사용: bash build/remote/build-remote.sh [linux|mac|all]
set -euo pipefail
cd "$(dirname "$0")/../.."
TARGET="${1:-all}"
REMOTE_DIR="build/videodownloader"
REMOTE_DIR="build/Paca"
mkdir -p out
@ -22,12 +22,12 @@ build_and_collect() { # $1 = ssh 대상, $2 = RID
local rid="$2"
echo "==> [$host] publish $rid"
ssh -o BatchMode=yes "$host" "cd $REMOTE_DIR && export DOTNET_ROOT=\$HOME/.dotnet && export PATH=\$HOME/.dotnet:\$PATH && \
dotnet publish VideoDownloader.Cli -c Release -r $rid --self-contained -o out/cli-$rid && \
dotnet publish VideoDownloader.Avalonia -c Release -r $rid --self-contained -o out/avalonia-$rid && \
cd out && tar -czf mediabrowser-$rid.tar.gz cli-$rid avalonia-$rid"
dotnet publish src/Paca.Cli -c Release -r $rid --self-contained -o out/cli-$rid && \
dotnet publish src/Paca.Avalonia -c Release -r $rid --self-contained -o out/avalonia-$rid && \
cd out && tar -czf Paca-$rid.tar.gz cli-$rid avalonia-$rid"
echo "==> [$host] 수집: out/mediabrowser-$rid.tar.gz"
scp -o BatchMode=yes "$host:$REMOTE_DIR/out/mediabrowser-$rid.tar.gz" "out/mediabrowser-$rid.tar.gz"
echo "==> [$host] 수집: out/Paca-$rid.tar.gz"
scp -o BatchMode=yes "$host:$REMOTE_DIR/out/Paca-$rid.tar.gz" "out/Paca-$rid.tar.gz"
}
if [[ "$TARGET" == "mac" || "$TARGET" == "all" ]]; then
@ -43,4 +43,4 @@ if [[ "$TARGET" == "linux" || "$TARGET" == "all" ]]; then
fi
echo "==> 원격 빌드 완료:"
ls -lh out/mediabrowser-*.tar.gz 2>/dev/null || true
ls -lh out/Paca-*.tar.gz 2>/dev/null || true