Templates mit go-upper
go-upper kann nach jedem Upload automatisch Templates füllen (BBCode, Intelligen‑XML, eigene Textdateien usw.). Hier erfährst du, wie du sie aktivierst, welche Dateien als Beispiel dienen und welche Variablen verfügbar sind.
1) Template-Modul aktivieren
In config/upper.config.yml den Block template anpassen:
template:
enabled: true # Templates generieren?
templates:
default:
- '/pfad/zu/config/templates/bbcode/bbcode_movie_boerse07_hidecx.html'
- '/pfad/zu/config/templates/intelligen/murat/movies.xml'
movie: [] # optional: eigene Liste nur für Movies
game: [] # optional: eigene Liste nur für Games
ebook: [] # optional: eigene Liste nur für EBooks
software: [] # optional: eigene Liste nur für Software/Apps
tv: [] # optional: eigene Liste nur für TV
music: [] # optional: eigene Liste nur für Music
xxx: [] # optional: eigene Liste nur für XXX
saveTo: '/pfad/zum/result/' # optional: Zielordner für fertige Templates
contenttypes: # ordnet Scan-Pfade einem Typ zu
- type: "movie"
path: "/pfad/zur/go-upper-installation/backup/"
So wählt go-upper die Templates:
defaultläuft immer.- Zusätzlich der Typen-Block (
movie,game,ebook,software,tv,music,xxx), falls der Inhaltstyp erkannt wird (übercontenttypesoder XRel). - Wenn
saveToleer ist, nutzt go-upper den Ergebnisordner ausresult/. Bei aktivemresult.json.seperatedlandet jedes Template im eigenen Unterordner des Releases.
2) Beispiel-Templates nutzen
Im Repo findest du fertige Beispiele:
- BBCode:
config/templates/bbcode/…(z. B.bbcode_movie_boerse07_hidecx.html) - Games/Steam:
config/templates/bbcode/bbcode_games_02_steam.htmlnutzt Steam-Metadaten und zusätzliche Sprachvarianten ohne PreDB-Releasewerte;bbcode_games_03_steam_hidecx.htmlübernimmt zusätzlich die Hide.cx-/Backup-Linkdarstellung ohne Movie-/IMDb-/MediaInfo-Block. - Intelligen XML:
config/templates/intelligen/…(z. B.intelligen/murat/movies.xml)
Du kannst diese Pfade direkt in template.templates eintragen oder als Vorlage für eigene Dateien kopieren.
3) Template-Verwaltung in der Upper-UI
Die Upper-UI hat links den Bereich Templates. Beim Start importiert die UI alle lesbaren Dateien aus template.templates einmalig in die SQLite-Datenbank. Bei mehreren verwalteten Upper-Instanzen wird der Import je Instanz ausgeführt; relative Template-Pfade werden dabei relativ zur jeweiligen upper.config.yml aufgelöst. Verwendet die UI selbst dieselbe upper.config.yml wie eine registrierte Instanz, wird diese Config nur für die Instanz importiert und nicht zusätzlich als Global. Leere Template-Listen bleiben leer.
In der UI kannst du Templates:
- nach Titel, Typen (
movie,tv,game,ebook,software,music,xxxoderAlle) und Format (xml,html,bbcode,plaintext) verwalten, - mit Syntax-Highlighting bearbeiten und speichern,
- neu anlegen,
- beim Erstellen und Bearbeiten eine durchsuchbare Liste aller verfügbaren Template-Variablen neben dem Editor anzeigen; ein Klick fügt einfache Variablen direkt mit einer
if-Prüfung beziehungsweise Listen und Maps mit einem passendenrange-Beispiel ein und beim Speichern werden unbekannte Variablen sowie fehlerhafte Syntax abgewiesen, - als Datei exportieren,
- importierte Templates per Sync erneut aus der Quelldatei laden und den gespeicherten UI-Inhalt überschreiben,
- aus der Templates-UI entfernen, ohne die Originaldatei aus der Importquelle zu entfernen,
- mit einer importierten Upload-JSON als Vorschau rendern.
Der normale Import ist idempotent: Bereits importierte Config-Dateien werden pro Instanz nicht erneut überschrieben. Der Sync-Button erscheint bei Templates mit Status importiert; er liest die gespeicherte Quelldatei erneut ein, aktualisiert Format/Typen aus der aktuellen Config, sofern vorhanden, und überschreibt den DB-Inhalt. Entfernst du ein importiertes Template aus der UI, wird nur der gespeicherte UI-Datensatz gelöscht; die Originaldatei bleibt erhalten und kann über Import wieder neu eingelesen werden.
Wird ein UI-Template auf der Upload-Edit-Seite für ein XenForo- oder uCMS-Publishing-Ziel ausgewählt, rendert die Publishing-Warteschlange den gespeicherten UI-Inhalt mit der Config der Upload-Instanz. Bei einer neuen UI-Publishing-Auswahl wird ein zum Inhaltstyp und zur Instanz passendes gespeichertes UI-Template vorausgewählt, wenn template im Mapping leer oder nicht lesbar ist. Ein lesbarer Mapping-Pfad bleibt als bewusst gesetzte Vorauswahl erhalten. Für ein reines UI-Setup darf template leer bleiben; der CLI-Publishing-Ablauf verwendet dagegen weiterhin den Mapping-Template-Pfad.
Unter Text ersetzen (Replace) kannst du finale Plain-Text-Ersetzungen verwalten, die erst nach dem Rendern eines Templates laufen. Dadurch werden zuerst alle Template-Variablen wie {{ .Name }} eingefügt und danach der fertige Text ersetzt, zum Beispiel de,en zu Deutsch,Englisch. Ein Replace mit aktivem Global gilt für alle Upper-Instanzen. Ohne Global gilt er nur für die aktuell ausgewählte Instanz; auf Alle / Global muss deshalb Global aktiv sein. Die Regeln sind case-sensitive, verwenden keine Regex und laufen nach aufsteigender Reihenfolge.
Die Target-Auswahl auf der Upload-Edit-Seite wird bei noch nicht gespeicherten Zielen aus Release-Titel und Inhaltstyp vorausgewählt. Dafür gelten dieselben match-, exclude-, priority- und fallback-Regeln wie beim CLI-Publishing; eine bereits manuell gespeicherte Zielwahl bleibt erhalten.
4) Alle verfügbaren Template-Variablen
Alle Variablen aus der vom Template-Editor verwendeten Variablenliste (Quelle: pkg/utils/template/variables.go):
Top-Level (UploadItem)
{{ .ID }}– interne Queue-ID (UUID){{ .Name }}– Release-Titel{{ .OriginalName }}– ursprünglicher Ordnername{{ .SourceDir }}– Quellpfad{{ .WorkDir }}– Workdir{{ .TargetDir }}– Zielpfad (falls gesetzt){{ .ToUpload }}– Liste der Upload-Dateien{{ .ToUploadStream }}– Liste der Stream-Upload-Dateien{{ .Links }}– Map: Hoster → Direktlinks{{ .CryptedLinks }}– Map: Hoster → Crypter-Link{{ .CryptedLinksBackup }}– Map nach Crypter-Service → Hosterlinks{{ .CryptedLinksStream }}– Map: Streamhoster → Crypter-Link{{ .CryptedLinksStreamBackup }}– Backup für Streamhoster{{ .CryptedLinksStatus }}– Map: Hoster → Status-ID{{ .Size }}– Größe in Bytes{{ .SizeHuman }},{{ .SizeHumanI }},{{ .SizeHumanReal }},{{ .SizeHumanRealI }}– Größen in SI/IEC{{ .NFOPath }}– Pfad zur NFO (falls vorhanden)
General
{{ .General.Release }}– Release-Name{{ .General.Name }}– bereinigter Name (z. B. „Avatar“){{ .General.Year }}– Jahr{{ .General.Size }},{{ .General.SizeI }},{{ .General.SizeReal }},{{ .General.SizeRealI }}– Größen wie oben{{ .General.Type }}– erkannter Typ (movie, tv, game, ebook, software, music, xxx){{ .General.Plot }}– Beschreibung{{ .General.Genre }}– Genre (kommagetrennt){{ .General.Cover }}– Cover-URL{{ .General.IMDBID }}– IMDB-ID{{ .General.IMDBLink }}– IMDB-Link{{ .General.TV.Season }}– TV-Staffel ohne führende Nullen (z. B.1), leer bei Filmen{{ .General.TV.Episode }}– TV-Episode ohne führende Nullen (z. B.8), leer bei Staffel-Packs/Filmen{{ .General.TV.SeasonEpisode }}– kombiniert, z. B.S01E08(nur Staffel:S01){{ .General.TV.SeasonEpisodes }}– Folgen-Range aus Episode-Unterordnern, z. B.E01-E02, E05, E12{{ .General.TV.Episodes }}– Liste der Episode-Unterordnernamen, sortiert nach Folge; perrangeausgeben
Episodes untereinander ausgeben:
{{- range .General.TV.Episodes }}
{{ . }}
{{- end }}
Beispielausgabe:
Show.2011.S01E01.German
Show.2011.S01E02.German
Show.2011.S01E05.German
Die Felder Season, Episode und SeasonEpisode werden aus dem Release-Namen abgeleitet (S01E08, S13 …). SeasonEpisodes und Episodes kommen aus direkten Unterordnern mit SxxEyy (nicht aus Dateien). Alle TV-Werte sind in der Upload-Bearbeitung unter TV editierbar.
ExternalInfo – XRel
{{ .ExternalInfo.XRel.XRelID }}{{ .ExternalInfo.XRel.Release }}{{ .ExternalInfo.XRel.ReleaseLink }}{{ .ExternalInfo.XRel.NFOLink }}{{ .ExternalInfo.XRel.Group }}{{ .ExternalInfo.XRel.Type }}{{ .ExternalInfo.XRel.Title }}{{ .ExternalInfo.XRel.MediaLink }}{{ .ExternalInfo.XRel.Uris }}{{ .ExternalInfo.XRel.ExtInfo.Cover }}{{ .ExternalInfo.XRel.ExtInfo.Plot }}{{ .ExternalInfo.XRel.ExtInfo.IMDBID }}{{ .ExternalInfo.XRel.ExtInfo.IMDBLink }}{{ .ExternalInfo.XRel.ExtInfo.Genre }}{{ .ExternalInfo.XRel.ExtInfo.VideoType }}{{ .ExternalInfo.XRel.ExtInfo.AudioType }}{{ .ExternalInfo.XRel.ExtInfo.ExternalInfoRaw }}
Beispielansicht der XRel-Daten im Ergebnis-JSON:

ExternalInfo – PreDB
{{ .ExternalInfo.PreDB.ID }}{{ .ExternalInfo.PreDB.Pretime }}{{ .ExternalInfo.PreDB.Release }}{{ .ExternalInfo.PreDB.Section }}{{ .ExternalInfo.PreDB.Files }}{{ .ExternalInfo.PreDB.SizeMB }}{{ .ExternalInfo.PreDB.Status }}–0ok,1nuked,2unnuked,3delpre,4undelpre{{ .ExternalInfo.PreDB.Reason }}{{ .ExternalInfo.PreDB.Group }}{{ .ExternalInfo.PreDB.Genre }}{{ .ExternalInfo.PreDB.ReleaseLink }}{{ .ExternalInfo.PreDB.NFOLink }}{{ .ExternalInfo.PreDB.NFOImage }}
ExternalInfo – IMDB
{{ .ExternalInfo.IMDB.ID }}{{ .ExternalInfo.IMDB.Title }}{{ .ExternalInfo.IMDB.Plot }}{{ .ExternalInfo.IMDB.Rating }}{{ .ExternalInfo.IMDB.RatingCount }}{{ .ExternalInfo.IMDB.Year }}{{ .ExternalInfo.IMDB.CoverURLs.Small }}{{ .ExternalInfo.IMDB.CoverURLs.Medium }}{{ .ExternalInfo.IMDB.CoverURLs.Big }}
ExternalInfo – TMDB
{{ .ExternalInfo.TMDB.ID }}{{ .ExternalInfo.TMDB.Title }}{{ .ExternalInfo.TMDB.OriginalTitle }}{{ .ExternalInfo.TMDB.Plot }}{{ .ExternalInfo.TMDB.Rating }}{{ .ExternalInfo.TMDB.RatingCount }}{{ .ExternalInfo.TMDB.RunTime }}{{ .ExternalInfo.TMDB.IMDBID }}{{ .ExternalInfo.TMDB.PosterPath }}{{ .ExternalInfo.TMDB.BackdropPath }}{{ .ExternalInfo.TMDB.CoverURLs.Small }}{{ .ExternalInfo.TMDB.CoverURLs.Medium }}{{ .ExternalInfo.TMDB.CoverURLs.Big }}{{ .ExternalInfo.TMDB.Trailer.Name }}{{ .ExternalInfo.TMDB.Trailer.Trailer }}{{ .ExternalInfo.TMDB.AdditionalLanguages }}– Map: Sprache → lokalisierte TMDB‑Details (nur wenncontentgrabber.tmdb.languagemehrere Codes wie"DE,EN"enthält){{ (index .ExternalInfo.TMDB.AdditionalLanguages "EN").Title }}– englischer TMDB-Titel (wennENkonfiguriert ist){{ (index .ExternalInfo.TMDB.AdditionalLanguages "EN").Plot }}– englische TMDB-Handlung (wennENkonfiguriert ist)
Beispiel: zweite Sprache (EN) im Template nutzen:
{{- with (index .ExternalInfo.TMDB.AdditionalLanguages "EN") }}
EN Titel: {{ .Title }}
EN Plot: {{ .Plot }}
{{- end}}
ExternalInfo – Steam
{{ .ExternalInfo.Steam.ID }}{{ .ExternalInfo.Steam.Name }}{{ .ExternalInfo.Steam.Image }}{{ .ExternalInfo.Steam.Genres }}{{ .ExternalInfo.Steam.Developers }}{{ .ExternalInfo.Steam.Publishers }}{{ .ExternalInfo.Steam.SupportedLanguageSubtitle }}{{ .ExternalInfo.Steam.SupportedLanguageAudio }}{{ .ExternalInfo.Steam.SupportedLanguageSubtitleCodes }}– Untertitelsprachen als kommagetrennte ISO-639-1-Codes, beispielsweiseDE, EN{{ .ExternalInfo.Steam.SupportedLanguageAudioCodes }}– Audiosprachen als kommagetrennte ISO-639-1-Codes, beispielsweiseDE, EN{{ limitCSV .ExternalInfo.Steam.SupportedLanguageAudioCodes 10 }}– nur die ersten 10 Audiosprachcodes (siehe Template-Funktionen){{ limitCSV .ExternalInfo.Steam.SupportedLanguageSubtitleCodes 10 }}– nur die ersten 10 Untertitel-Sprachcodes{{ .ExternalInfo.Steam.ReleaseDate }}{{ .ExternalInfo.Steam.ShortDescription }}{{ .ExternalInfo.Steam.AdditionalLanguages }}– Map: Sprache → lokalisierte Steam‑Details (nur wenncontentgrabber.steam.languagemehrere Codes wie"DE,EN"enthält){{ (index .ExternalInfo.Steam.AdditionalLanguages "EN").Name }}– englischer Steam-Titel (wennENkonfiguriert ist){{ (index .ExternalInfo.Steam.AdditionalLanguages "EN").ShortDescription }}– englische Steam-Kurzbeschreibung (wennENkonfiguriert ist)
Beispiel: zweite Sprache (EN) im Template nutzen:
{{- with (index .ExternalInfo.Steam.AdditionalLanguages "EN") }}
EN Titel: {{ .Name }}
EN Beschreibung: {{ .ShortDescription }}
{{- end}}
Beispielansicht der Steam-Daten im Ergebnis-JSON:

ExternalInfo – YouTube
{{ .ExternalInfo.Youtube.Title }}{{ .ExternalInfo.Youtube.Channel }}{{ .ExternalInfo.Youtube.PublishedAt }}{{ .ExternalInfo.Youtube.Score }}{{ .ExternalInfo.Youtube.WatchURL }}{{ .ExternalInfo.Youtube.EmbedURL }}
Emule
{{ .Emule.File }}{{ .Emule.HashLink }}{{ .Emule.Size }}
MediaInfo / FFProbe
{{ .MediaInfo.FFProbe.FFProbeFirstVideoSteam }}{{ .MediaInfo.FFProbe.FFProbeFirstAudioStream }}{{ .MediaInfo.FFProbe.FFProbeRAWData }}{{ .MediaInfo.MediaInfo.MediaInfoFirstVideoSteam }}{{ .MediaInfo.MediaInfo.MediaInfoFirstAudioStream }}{{ .MediaInfo.MediaInfo.MediaInfoRAWData }}{{ .MediaInfo.MediaInfo.MediaInfoData }}{{ .MediaInfo.MediaInfo.MediaInfoData.RAWString }}{{ .MediaInfo.MediaInfo.HumanValues.VideoRuntime }}{{ .MediaInfo.MediaInfo.HumanValues.VideoFormat }}{{ .MediaInfo.MediaInfo.HumanValues.VideoCodec }}{{ .MediaInfo.MediaInfo.HumanValues.VideoWidth }}{{ .MediaInfo.MediaInfo.HumanValues.VideoHeight }}{{ .MediaInfo.MediaInfo.HumanValues.VideoBitrate }}{{ .MediaInfo.MediaInfo.HumanValues.AudioLanguages }}{{ .MediaInfo.MediaInfo.HumanValues.AudioLanguagesLocalized }}– deutsche Sprachbezeichnungen, z. B.Deutsch, Englisch{{ .MediaInfo.MediaInfo.HumanValues.AudioFormat }}{{ .MediaInfo.MediaInfo.HumanValues.AudioBitrate }}{{ .MediaInfo.MediaInfo.HumanValues.AudioChannel }}{{ .MediaInfo.MediaInfo.HumanValues.SubtitleLanguages }}{{ .MediaInfo.MediaInfo.HumanValues.SubtitleLanguageCodes }}– Untertitelsprachen als eindeutige kommagetrennte ISO-639-1-Codes, beispielsweiseDE, EN{{ limitCSV .MediaInfo.MediaInfo.HumanValues.SubtitleLanguageCodes 10 }}– nur die ersten 10 Untertitel-Sprachcodes
MovieThumbnail
{{ .MovieThumbnail.ThumbnailPath }}{{ .MovieThumbnail.ThumbnailLink }}{{ .MovieThumbnail.InfoTXT }}
NFO / Crypter / Cover (top-level)
{{ .NFO }}– kompletter NFO-Inhalt{{ .Crypter }}– aktiver Crypter-Name{{ .Cover }}– Cover-URL (Fallback auf.General.Cover)
5) Template-Funktionen
Neben den Variablen stehen Hilfsfunktionen zur Verfügung. Sie werden wie eingebaute Go-Template-Funktionen geschrieben.
limitCSV
Kürzt eine kommagetrennte Liste auf die ersten n Einträge. Leere Teile werden übersprungen, die Ausgabe wird immer mit , (Komma + Leerzeichen) zusammengefügt.
{{ limitCSV .ExternalInfo.Steam.SupportedLanguageAudioCodes 10 }}
{{ limitCSV .ExternalInfo.Steam.SupportedLanguageSubtitleCodes 10 }}
{{ limitCSV .MediaInfo.MediaInfo.HumanValues.SubtitleLanguageCodes 10 }}
Beispiel: DE, EN, FR, ES, IT, PT, PL, RU, JA, KO, ZH, NL mit Limit 10 ergibt DE, EN, FR, ES, IT, PT, PL, RU, JA, KO.
Verhalten:
- Weniger Einträge als das Limit: die komplette Liste bleibt unverändert.
- Leerer Wert oder Limit
0/ negativ: leere Ausgabe. DE,EN,FRohne Leerzeichen wird zuDE, EN.- Die Originalvariablen (
SupportedLanguageAudioCodesusw.) bleiben vollständig.limitCSVändert nur die Template-Ausgabe.
Die Zahl ist frei wählbar (5, 10, 15, …). Für Sprachcodes im Forum oder in XML-Feldern ist 10 der übliche Wert.
replace
Ersetzt Text in einem String. Die Signatur entspricht strings.Replace (alt, neu, n; -1 ersetzt alle Vorkommen):
{{ replace .General.Genre "Sci-Fi" "Science Fiction" -1 }}
6) Praktische Beispiele
BBCode-Template (Börse):
template:
enabled: true
templates:
default:
- '/pfad/zur/go-upper-installation/config/templates/bbcode/bbcode_movie_boerse07_hidecx.html'
saveTo: '/pfad/zur/go-upper-installation/result/'
Intelligen-Template:
template:
enabled: true
templates:
movie:
- '/pfad/zur/go-upper-installation/config/templates/intelligen/murat/movies.xml'
saveTo: '/pfad/zur/go-upper-installation/result/'
contenttypes:
- type: "movie"
path: "/pfad/zur/go-upper-installation/backup/"
Variablen nutzen (Mini-Ausschnitt):
[B]Titel:[/B] {{ .Name }}
[B]Größe:[/B] {{ .SizeHuman }}
[B]Hoster:[/B]
{{- range $hoster, $link := .CryptedLinks }}
- {{ $hoster }} → {{ $link }}
{{- end}}
Tipp: Immer mit if/with prüfen, ob Werte existieren, damit die Template-Ausgabe nicht abbricht:
{{- if .ExternalInfo.Youtube.WatchURL }}
Trailer: [url={{ .ExternalInfo.Youtube.WatchURL }}]{{ .ExternalInfo.Youtube.Title }}[/url]
{{- end}}