feat(files): API tokens in Settings, the Hub folder in Files, a notice before a token runs out

Settings gains an API tokens tab: a row per token (name and prefix; each
folder with its rights; last use and expiry, "expires soon" marked),
revoked from its menu behind a confirm. A new token is the Hub exchange in
one click, or folders and rights picked per folder (no Write where an
upload cannot land); expiry 30/90 days, 1 year or never (warned). The
token shows once in the same dialog, with Copy and a ready curl line.

The Hub folder closes the Sources in the Files rail, takes uploads and
moved-in files. A token about to run out warns its user once, a week
before (the Files GC's sixth pass); the notice opens the tokens tab.
This commit is contained in:
2026-10-14 23:33:34 +02:00
parent 4f58d15d3f
commit db56f25387
39 changed files with 1759 additions and 26 deletions
+4
View File
@@ -110,6 +110,10 @@
"rename": "Couldn't rename the folder",
"retention": "Couldn't change how long the folder keeps its files",
"delete": "Couldn't delete the folder"
},
"apiToken": {
"create": "Couldn't create the token",
"revoke": "Couldn't revoke the token"
}
},
"ok": "OK",
+1
View File
@@ -75,6 +75,7 @@
"menu": "Folder actions",
"new": "New folder",
"newName": "Folder name",
"hub": "Hub",
"rename": "Rename",
"retention": "Keeps files",
"forever": "Until I delete them",
+5
View File
@@ -15,6 +15,7 @@
"andMore_other": "and {{count}} more",
"openScheduler": "Open Scheduler",
"openFile": "Open the file",
"openTokens": "Open API tokens",
"revertFailed": "Couldn't undo that — please try again",
"downloadDone": {
"title": "Download ready"
@@ -46,6 +47,10 @@
"downloadExpiring": {
"title": "A download expires soon"
},
"apiTokenExpiring": {
"title": "An API token expires soon",
"body": "“{{name}}” stops working on {{date}}."
},
"downloadExpired": {
"title": "A download expired and was removed"
},
@@ -145,6 +145,7 @@
"evicted": "evicted",
"reaped": "cleaned up",
"swept": "swept",
"tokens_warned": "tokens warned",
"libraries": "libraries",
"movies": "movies",
"shows": "shows",
+51 -1
View File
@@ -5,7 +5,8 @@
"notifications": "Notifications",
"account": "Account",
"diagnostics": "Diagnostics",
"downloads": "Downloads"
"downloads": "Downloads",
"tokens": "API tokens"
},
"plexSync": {
"title": "Plex watch sync",
@@ -235,5 +236,54 @@
"downloads": {
"formats": "Download formats",
"formatsIntro": "The choices the download dialog offers. The built-in ones are fixed; duplicate one to make your own."
},
"tokens": {
"intro": "A token gives one machine a key to the folders you pick in your Files library — and to nothing else.",
"new": "New token",
"empty": "No tokens yet. Make one for your hub or for a script of yours.",
"rowMenu": "Token actions",
"expiring": "Expires soon",
"expired": "Expired",
"lastUsed": "Last used",
"neverUsed": "Never used",
"expiresOn": "Expires {{date}}",
"expiredOn": "Expired {{date}}",
"neverExpires": "Never expires",
"revoke": "Revoke…",
"revokeTitle": "Revoke “{{name}}”?",
"revokeBody": "The machine that uses it loses access at its next request. This is final: a new token has to be made in its place.",
"revokeAction": "Revoke",
"rights": {
"list": "List",
"read": "Read",
"write": "Write",
"delete": "Delete"
},
"newTitle": "New API token",
"kind": "Kind of token",
"hubTitle": "Hub exchange",
"hubText": "One shared Hub folder; the token may do anything in it.",
"hubName": "Hub exchange",
"customTitle": "Custom",
"customText": "You pick the folders and the rights.",
"name": "Name",
"folders": "Folders and rights",
"noFolders": "You have no folders yet.",
"expiry": "Expires",
"expiryOption": {
"30": "30 days",
"90": "90 days",
"365": "1 year",
"never": "Never"
},
"neverWarning": "A token that never expires opens its folders until you revoke it.",
"create": "Create",
"madeTitle": "Your token is ready",
"once": "This is the only time you see it: only its fingerprint is kept. If you lose it, make a new one.",
"token": "Token",
"tryIt": "Try it (curl)",
"copy": "Copy",
"copied": "Copied",
"done": "Done"
}
}
+4
View File
@@ -110,6 +110,10 @@
"rename": "Nem sikerült átnevezni a mappát",
"retention": "Nem sikerült módosítani a mappa megőrzési idejét",
"delete": "Nem sikerült törölni a mappát"
},
"apiToken": {
"create": "Nem sikerült létrehozni a tokent",
"revoke": "Nem sikerült visszavonni a tokent"
}
},
"ok": "OK",
+1
View File
@@ -75,6 +75,7 @@
"menu": "Mappa műveletei",
"new": "Új mappa",
"newName": "Mappa neve",
"hub": "Hub",
"rename": "Átnevezés",
"retention": "Fájlok megőrzése",
"forever": "Amíg ki nem törlöm",
+5
View File
@@ -15,6 +15,7 @@
"andMore_other": "és még {{count}}",
"openScheduler": "Ütemező megnyitása",
"openFile": "Fájl megnyitása",
"openTokens": "API-tokenek megnyitása",
"revertFailed": "Nem sikerült visszavonni — próbáld újra",
"downloadDone": {
"title": "Letöltés kész"
@@ -46,6 +47,10 @@
"downloadExpiring": {
"title": "Hamarosan lejár egy letöltés"
},
"apiTokenExpiring": {
"title": "Hamarosan lejár egy API-token",
"body": "„{{name}}” lejár: {{date}}."
},
"downloadExpired": {
"title": "Egy letöltés lejárt, és törlődött"
},
@@ -145,6 +145,7 @@
"evicted": "helyhiány miatt törölve",
"reaped": "eltakarítva",
"swept": "kisöpörve",
"tokens_warned": "token figyelmeztetve",
"libraries": "könyvtár",
"movies": "film",
"shows": "sorozat",
+51 -1
View File
@@ -5,7 +5,8 @@
"notifications": "Értesítések",
"account": "Fiók",
"diagnostics": "Diagnosztika",
"downloads": "Letöltések"
"downloads": "Letöltések",
"tokens": "API-tokenek"
},
"plexSync": {
"title": "Plex nézettség-szinkron",
@@ -235,5 +236,54 @@
"downloads": {
"formats": "Letöltési formátumok",
"formatsIntro": "Ezek közül választhatsz a letöltés ablakában. A beépítettek nem módosíthatók; másold le valamelyiket, ha sajátot szeretnél."
},
"tokens": {
"intro": "Egy token egy gépnek ad kulcsot a Fájlok könyvtár általad kijelölt mappáihoz — semmi máshoz.",
"new": "Új token",
"empty": "Még nincs tokened. Csinálj egyet a hubodnak vagy egy saját szkriptnek.",
"rowMenu": "Token műveletei",
"expiring": "Hamarosan lejár",
"expired": "Lejárt",
"lastUsed": "Utoljára használva:",
"neverUsed": "Még nem használták",
"expiresOn": "Lejár: {{date}}",
"expiredOn": "Lejárt: {{date}}",
"neverExpires": "Nem jár le",
"revoke": "Visszavonás…",
"revokeTitle": "Visszavonod: „{{name}}”?",
"revokeBody": "Az a gép, amelyik használja, a következő kérésénél elveszíti a hozzáférést. Ez végleges: helyette új tokent kell csinálni.",
"revokeAction": "Visszavonás",
"rights": {
"list": "Lista",
"read": "Olvasás",
"write": "Írás",
"delete": "Törlés"
},
"newTitle": "Új API-token",
"kind": "A token fajtája",
"hubTitle": "Hub csere",
"hubText": "Egy közös Hub mappa; a token mindent tehet benne.",
"hubName": "Hub csere",
"customTitle": "Egyedi",
"customText": "Te választod a mappákat és a jogokat.",
"name": "Név",
"folders": "Mappák és jogok",
"noFolders": "Még nincs mappád.",
"expiry": "Lejárat",
"expiryOption": {
"30": "30 nap",
"90": "90 nap",
"365": "1 év",
"never": "Soha"
},
"neverWarning": "Egy soha le nem járó token addig nyitja a mappáit, amíg vissza nem vonod.",
"create": "Létrehozás",
"madeTitle": "A token elkészült",
"once": "Most látod utoljára: csak a lenyomatát őrizzük. Ha elveszik, csinálj újat.",
"token": "Token",
"tryIt": "Kipróbálás (curl)",
"copy": "Másolás",
"copied": "Másolva",
"done": "Kész"
}
}