Playtube: eigenstaendiger YouTube/YouTube-Music-Player mit Discord RPC und Auto-Update
- PySide6/QtWebEngine mit persistentem Login-Profil (YouTube + YouTube Music Tabs) - Google-Login-Fix per Sec-CH-UA-Headern + Chrome-JS-Shim - Discord Rich Presence (eigener Thread, Titel/Fortschritt/Buttons) - Eigenes Branding (Taskmanager/Taskleiste) per AppUserModelID + PyInstaller-Packaging - Auto-Update ueber GitHub Releases (fojadrachi/Playtube) Co-Authored-By: Claude Sonnet 5 <[email protected]>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# Baut Playtube.exe mit PyInstaller und sorgt dafuer, dass auch der QtWebEngine-
|
||||
# Hilfsprozess (der eigentlich den Ton ausgibt) den Namen "Playtube" traegt, damit er
|
||||
# im Taskmanager und - so weit von der jeweiligen Windows-Version respektiert - im
|
||||
# Lautstaerkemixer nicht als "QtWebEngineProcess" auftaucht.
|
||||
#
|
||||
# Aufruf (im Projekt-Root, mit aktivierter venv):
|
||||
# powershell -ExecutionPolicy Bypass -File packaging\build.ps1
|
||||
#
|
||||
# Optional: rcedit (https://github.com/electron/rcedit) im PATH oder unter
|
||||
# packaging\rcedit.exe ablegen, dann werden Icon + Versionsinfo des umbenannten
|
||||
# Hilfsprozesses ebenfalls auf "Playtube" gesetzt (sonst bleibt intern "QtWebEngineProcess"
|
||||
# stehen, nur der Dateiname aendert sich - Windows zeigt dann meist trotzdem den
|
||||
# Dateinamen "PlaytubeHelper" an).
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
Set-Location $root
|
||||
|
||||
Write-Host "==> Baue Playtube.exe mit PyInstaller ..." -ForegroundColor Cyan
|
||||
pyinstaller packaging\playtube.spec --noconfirm --distpath dist --workpath build
|
||||
if ($LASTEXITCODE -ne 0) { throw "PyInstaller-Build fehlgeschlagen." }
|
||||
|
||||
$distDir = Join-Path $root "dist\Playtube"
|
||||
$internalDir = Join-Path $distDir "_internal"
|
||||
$searchRoot = if (Test-Path $internalDir) { $internalDir } else { $distDir }
|
||||
|
||||
$engineProcess = Get-ChildItem -Path $searchRoot -Recurse -Filter "QtWebEngineProcess.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if (-not $engineProcess) {
|
||||
Write-Warning "QtWebEngineProcess.exe wurde im Build nicht gefunden - Audio-/Taskmanager-Branding des Hilfsprozesses wird uebersprungen."
|
||||
} else {
|
||||
$helperPath = Join-Path $engineProcess.Directory.FullName "PlaytubeHelper.exe"
|
||||
Copy-Item $engineProcess.FullName $helperPath -Force
|
||||
Write-Host "==> Hilfsprozess kopiert nach $helperPath" -ForegroundColor Cyan
|
||||
|
||||
$rcedit = Get-Command rcedit -ErrorAction SilentlyContinue
|
||||
$rceditLocal = Join-Path $PSScriptRoot "rcedit.exe"
|
||||
if ($rcedit) {
|
||||
$rceditExe = $rcedit.Source
|
||||
} elseif (Test-Path $rceditLocal) {
|
||||
$rceditExe = $rceditLocal
|
||||
} else {
|
||||
$rceditExe = $null
|
||||
}
|
||||
|
||||
if ($rceditExe) {
|
||||
Write-Host "==> Patche Icon/Versionsinfo des Hilfsprozesses mit rcedit ..." -ForegroundColor Cyan
|
||||
& $rceditExe $helperPath --set-icon "$root\assets\icon.ico"
|
||||
& $rceditExe $helperPath --set-version-string "FileDescription" "Playtube"
|
||||
& $rceditExe $helperPath --set-version-string "ProductName" "Playtube"
|
||||
& $rceditExe $helperPath --set-version-string "CompanyName" "Playtube"
|
||||
& $rceditExe $helperPath --set-version-string "OriginalFilename" "PlaytubeHelper.exe"
|
||||
} else {
|
||||
Write-Host "Hinweis: rcedit nicht gefunden - Hilfsprozess heisst jetzt 'PlaytubeHelper.exe'," -ForegroundColor Yellow
|
||||
Write-Host "seine interne Versionsinfo/Icon bleibt aber 'QtWebEngineProcess'. Fuer volles" -ForegroundColor Yellow
|
||||
Write-Host "Branding: rcedit von https://github.com/electron/rcedit/releases laden und" -ForegroundColor Yellow
|
||||
Write-Host "als packaging\rcedit.exe ablegen, dann dieses Skript erneut ausfuehren." -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Fertig! Die App liegt unter dist\Playtube\Playtube.exe" -ForegroundColor Green
|
||||
@@ -0,0 +1,51 @@
|
||||
# PyInstaller-Spec fuer Playtube.
|
||||
# Bauen mit: pyinstaller packaging/playtube.spec --noconfirm
|
||||
# (aus dem Projekt-Root ausfuehren, oder packaging/build.ps1 benutzen)
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
block_cipher = None
|
||||
|
||||
ROOT = Path(SPECPATH).resolve().parent
|
||||
|
||||
a = Analysis(
|
||||
[str(ROOT / "main.py")],
|
||||
pathex=[str(ROOT)],
|
||||
binaries=[],
|
||||
datas=[
|
||||
(str(ROOT / "assets"), "assets"),
|
||||
(str(ROOT / "config.json"), "."),
|
||||
],
|
||||
hiddenimports=["pypresence"],
|
||||
hookspath=[],
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
)
|
||||
|
||||
pyz = PYZ(a.pure, a.zipped_data, cipher=block_cipher)
|
||||
|
||||
exe = EXE(
|
||||
pyz,
|
||||
a.scripts,
|
||||
[],
|
||||
exclude_binaries=True,
|
||||
name="Playtube",
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=False,
|
||||
console=False,
|
||||
icon=str(ROOT / "assets" / "icon.ico"),
|
||||
version=str(ROOT / "packaging" / "version_info.txt"),
|
||||
)
|
||||
|
||||
coll = COLLECT(
|
||||
exe,
|
||||
a.binaries,
|
||||
a.zipfiles,
|
||||
a.datas,
|
||||
strip=False,
|
||||
upx=False,
|
||||
name="Playtube",
|
||||
)
|
||||
@@ -0,0 +1,77 @@
|
||||
# Baut eine neue Playtube-Version, taggt und veroeffentlicht sie als GitHub Release
|
||||
# unter https://github.com/fojadrachi/Playtube - Playtube.exe erkennt neue Releases
|
||||
# danach automatisch (siehe playtube/updater.py) und bietet dem Nutzer die Installation
|
||||
# per Update-Dialog an.
|
||||
#
|
||||
# Aufruf (im Projekt-Root, mit aktivierter venv):
|
||||
# powershell -ExecutionPolicy Bypass -File packaging\release.ps1 -Version 1.1.0
|
||||
#
|
||||
# Voraussetzungen:
|
||||
# - git remote "origin" zeigt auf https://github.com/fojadrachi/Playtube
|
||||
# - Entweder die GitHub-CLI "gh" ist installiert und eingeloggt (gh auth login),
|
||||
# oder die Umgebungsvariable GITHUB_TOKEN enthaelt ein Personal Access Token mit
|
||||
# "repo"-Rechten (dann wird die GitHub REST API direkt per curl angesprochen).
|
||||
|
||||
param(
|
||||
[Parameter(Mandatory = $true)]
|
||||
[string]$Version,
|
||||
[string]$Notes = ""
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$root = Split-Path -Parent $PSScriptRoot
|
||||
Set-Location $root
|
||||
|
||||
if ($Version -notmatch '^\d+\.\d+\.\d+$') {
|
||||
throw "Version muss im Format X.Y.Z angegeben werden, z.B. 1.1.0"
|
||||
}
|
||||
$tag = "v$Version"
|
||||
|
||||
Write-Host "==> Setze Version auf $Version in playtube/__init__.py" -ForegroundColor Cyan
|
||||
$initFile = Join-Path $root "playtube\__init__.py"
|
||||
(Get-Content $initFile) -replace '__version__ = ".*"', "__version__ = `"$Version`"" | Set-Content $initFile -Encoding utf8
|
||||
|
||||
Write-Host "==> Baue Playtube.exe ..." -ForegroundColor Cyan
|
||||
& (Join-Path $PSScriptRoot "build.ps1")
|
||||
|
||||
$distDir = Join-Path $root "dist\Playtube"
|
||||
if (-not (Test-Path $distDir)) { throw "Build fehlgeschlagen: $distDir nicht gefunden." }
|
||||
|
||||
$zipName = "Playtube-$tag-win64.zip"
|
||||
$zipPath = Join-Path $root "dist\$zipName"
|
||||
if (Test-Path $zipPath) { Remove-Item $zipPath -Force }
|
||||
|
||||
Write-Host "==> Packe $zipName ..." -ForegroundColor Cyan
|
||||
Compress-Archive -Path $distDir -DestinationPath $zipPath
|
||||
|
||||
Write-Host "==> Commit + Tag $tag ..." -ForegroundColor Cyan
|
||||
git add -A
|
||||
git commit -m "Release $tag" --allow-empty
|
||||
git tag -a $tag -m "Playtube $tag"
|
||||
|
||||
Write-Host "==> Push zu origin ..." -ForegroundColor Cyan
|
||||
git push origin HEAD
|
||||
git push origin $tag
|
||||
|
||||
$gh = Get-Command gh -ErrorAction SilentlyContinue
|
||||
if ($gh) {
|
||||
Write-Host "==> Erstelle GitHub Release mit gh CLI ..." -ForegroundColor Cyan
|
||||
if ([string]::IsNullOrWhiteSpace($Notes)) { $Notes = "Playtube $tag" }
|
||||
gh release create $tag $zipPath --title "Playtube $Version" --notes $Notes
|
||||
} elseif ($env:GITHUB_TOKEN) {
|
||||
Write-Host "==> Erstelle GitHub Release ueber die REST API ..." -ForegroundColor Cyan
|
||||
$repo = "fojadrachi/Playtube"
|
||||
$body = @{ tag_name = $tag; name = "Playtube $Version"; body = $(if ($Notes) { $Notes } else { "Playtube $tag" }) } | ConvertTo-Json
|
||||
$headers = @{ Authorization = "Bearer $($env:GITHUB_TOKEN)"; Accept = "application/vnd.github+json" }
|
||||
$release = Invoke-RestMethod -Uri "https://api.github.com/repos/$repo/releases" -Method Post -Headers $headers -Body $body -ContentType "application/json"
|
||||
$uploadUrl = $release.upload_url -replace '\{\?name,label\}', "?name=$zipName"
|
||||
Invoke-RestMethod -Uri $uploadUrl -Method Post -Headers ($headers + @{ "Content-Type" = "application/zip" }) -InFile $zipPath | Out-Null
|
||||
Write-Host "Release veroeffentlicht: $($release.html_url)" -ForegroundColor Green
|
||||
} else {
|
||||
Write-Warning "Weder 'gh' CLI noch GITHUB_TOKEN gefunden - Tag wurde gepusht, aber kein GitHub Release erstellt."
|
||||
Write-Warning "Entweder 'winget install GitHub.cli' + 'gh auth login' ausfuehren und dieses Skript erneut starten,"
|
||||
Write-Warning "oder manuell unter https://github.com/fojadrachi/Playtube/releases/new ein Release fuer Tag '$tag' anlegen und '$zipPath' als Asset anhaengen."
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Fertig." -ForegroundColor Green
|
||||
@@ -0,0 +1,32 @@
|
||||
# UTF-8
|
||||
# Windows-Versionsressource fuer PyInstaller (--version-file).
|
||||
# Legt fest, wie die gebaute Playtube.exe im Explorer, Taskmanager und (soweit von
|
||||
# Windows respektiert) im Lautstaerkemixer benannt wird: "Playtube" statt "python".
|
||||
VSVersionInfo(
|
||||
ffi=FixedFileInfo(
|
||||
filevers=(1, 0, 0, 0),
|
||||
prodvers=(1, 0, 0, 0),
|
||||
mask=0x3F,
|
||||
flags=0x0,
|
||||
OS=0x40004,
|
||||
fileType=0x1,
|
||||
subtype=0x0,
|
||||
date=(0, 0)
|
||||
),
|
||||
kids=[
|
||||
StringFileInfo(
|
||||
[
|
||||
StringTable(
|
||||
u'040704B0',
|
||||
[StringStruct(u'CompanyName', u'Playtube'),
|
||||
StringStruct(u'FileDescription', u'Playtube'),
|
||||
StringStruct(u'FileVersion', u'1.0.0.0'),
|
||||
StringStruct(u'InternalName', u'Playtube'),
|
||||
StringStruct(u'LegalCopyright', u''),
|
||||
StringStruct(u'OriginalFilename', u'Playtube.exe'),
|
||||
StringStruct(u'ProductName', u'Playtube'),
|
||||
StringStruct(u'ProductVersion', u'1.0.0.0')])
|
||||
]),
|
||||
VarFileInfo([VarStruct(u'Translation', [1031, 1200])])
|
||||
]
|
||||
)
|
||||
Reference in New Issue
Block a user