mirror of
https://github.com/hrfee/jfa-go.git
synced 2025-04-20 01:52:53 +00:00
Compare commits
9 Commits
9875458b01
...
e449853568
Author | SHA1 | Date | |
---|---|---|---|
|
e449853568 | ||
|
2082e960c2 | ||
|
7b2a083f98 | ||
|
270143a8f6 | ||
|
766b69d95e | ||
|
f5addc4947 | ||
|
55eb59c526 | ||
|
679cac4dbd | ||
a0a25d64f1 |
@ -16,12 +16,12 @@ I chose to rewrite the python [jellyfin-accounts](https://github.com/hrfee/jelly
|
|||||||
* Granular control over invites: Validity period as well as number of uses can be specified.
|
* Granular control over invites: Validity period as well as number of uses can be specified.
|
||||||
* Account profiles: Assign settings profiles to invites so new users have your predefined permissions, homescreen layout, etc. applied to their account on creation.
|
* Account profiles: Assign settings profiles to invites so new users have your predefined permissions, homescreen layout, etc. applied to their account on creation.
|
||||||
* Password validation: Ensure users choose a strong password.
|
* Password validation: Ensure users choose a strong password.
|
||||||
* ⌛ User expiry: Specify a validity period, and new user's accounts will be disabled/deleted after it. The period can be manually extended too.
|
* ⌛ User expiry: Specify a validity period, and new users accounts will be disabled/deleted after it. The period can be manually extended too.
|
||||||
* 🔗 Ombi Integration: Automatically creates Ombi accounts for new users using their email address and login details, and your own defined set of permissions.
|
* 🔗 Ombi Integration: Automatically creates Ombi accounts for new users using their email address and login details, and your own defined set of permissions.
|
||||||
* Account management: Apply settings to your users individually or en masse, and delete users, optionally sending them an email notification with a reason.
|
* Account management: Apply settings to your users individually or en masse, and delete users, optionally sending them an email notification with a reason.
|
||||||
* 📨 Email storage: Add your existing users email addresses through the UI, and jfa-go will ask new users for them on account creation.
|
* 📨 Email storage: Add your existing users email addresses through the UI, and jfa-go will ask new users for them on account creation.
|
||||||
* Email addresses can optionally be used instead of usernames
|
* Email addresses can optionally be used instead of usernames
|
||||||
* 🔑 Password resets: When user's forget their passwords and request a change in Jellyfin, jfa-go reads the PIN from the created file and sends it straight to the user via email.
|
* 🔑 Password resets: When users forget their passwords and request a change in Jellyfin, jfa-go reads the PIN from the created file and sends it straight to the user via email.
|
||||||
* Notifications: Get notified when someone creates an account, or an invite expires.
|
* Notifications: Get notified when someone creates an account, or an invite expires.
|
||||||
* 📣 Announcements: Bulk email your users with announcements about your server.
|
* 📣 Announcements: Bulk email your users with announcements about your server.
|
||||||
* Authentication via Jellyfin: Instead of using separate credentials for jfa-go and Jellyfin, jfa-go can use it as the authentication provider.
|
* Authentication via Jellyfin: Instead of using separate credentials for jfa-go and Jellyfin, jfa-go can use it as the authentication provider.
|
||||||
|
@ -75,7 +75,20 @@
|
|||||||
"announce": "Ankündigen",
|
"announce": "Ankündigen",
|
||||||
"subject": "E-Mail-Betreff",
|
"subject": "E-Mail-Betreff",
|
||||||
"message": "Nachricht",
|
"message": "Nachricht",
|
||||||
"markdownSupported": "Markdown wird unterstützt."
|
"markdownSupported": "Markdown wird unterstützt.",
|
||||||
|
"advancedSettings": "Erweiterte Einstellungen",
|
||||||
|
"search": "Suchen",
|
||||||
|
"userExpiry": "Benutzer Ablaufdatum",
|
||||||
|
"inviteDuration": "Invite Dauer",
|
||||||
|
"enabled": "Aktiviert",
|
||||||
|
"userExpiryDescription": "Eine bestimmte Zeit nach der Anmeldung wird jfa-go das Konto löschen/deaktivieren. Du kannst dieses Verhalten in den Einstellungen ändern.",
|
||||||
|
"disabled": "Deaktiviert",
|
||||||
|
"admin": "Admin",
|
||||||
|
"download": "Herunterladen",
|
||||||
|
"update": "Aktualisieren",
|
||||||
|
"updates": "Aktualisierungen",
|
||||||
|
"expiry": "Ablaufdatum",
|
||||||
|
"extendExpiry": "Ablaufdatum verlängern"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "E-Mail-Adresse von {n} geändert.",
|
"changedEmailAddress": "E-Mail-Adresse von {n} geändert.",
|
||||||
@ -107,7 +120,12 @@
|
|||||||
"errorSendWelcomeEmail": "Fehler beim Senden der Willkommens-E-Mail (überprüfe die Konsole/Logs)",
|
"errorSendWelcomeEmail": "Fehler beim Senden der Willkommens-E-Mail (überprüfe die Konsole/Logs)",
|
||||||
"saveEmail": "E-Mail gespeichert.",
|
"saveEmail": "E-Mail gespeichert.",
|
||||||
"errorSaveEmail": "Fehler beim Speichern der E-Mail.",
|
"errorSaveEmail": "Fehler beim Speichern der E-Mail.",
|
||||||
"sentAnnouncement": "Ankündigung gesendet."
|
"sentAnnouncement": "Ankündigung gesendet.",
|
||||||
|
"updateApplied": "Aktualisierung angewendet, bitte neu starten.",
|
||||||
|
"errorApplyUpdate": "Fehler beim Anwenden der Aktualisierung, versuche es manuell.",
|
||||||
|
"errorCheckUpdate": "Fehler beim Suchen nach Aktualisierungen.",
|
||||||
|
"updateAvailable": "Eine neue Aktualisierung ist verfügbar, überprüfe die Einstellungen.",
|
||||||
|
"noUpdatesAvailable": "Keinen neuen Aktualisierungen verfügbar."
|
||||||
},
|
},
|
||||||
"quantityStrings": {
|
"quantityStrings": {
|
||||||
"modifySettingsFor": {
|
"modifySettingsFor": {
|
||||||
@ -137,6 +155,14 @@
|
|||||||
"announceTo": {
|
"announceTo": {
|
||||||
"singular": "{n} Benutzer mitteilen",
|
"singular": "{n} Benutzer mitteilen",
|
||||||
"plural": "{n} Benutzern mitteilen"
|
"plural": "{n} Benutzern mitteilen"
|
||||||
|
},
|
||||||
|
"extendExpiry": {
|
||||||
|
"singular": "Ablaufdatum für {n} Benutzer verlängern",
|
||||||
|
"plural": "Ablaufdatum für {n} Benutzer verlängern"
|
||||||
|
},
|
||||||
|
"extendedExpiry": {
|
||||||
|
"singular": "Ablaufdatum für {n} Benutzer verlängern.",
|
||||||
|
"plural": "Ablaufdatum für {n} Benutzer verlängern."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -81,13 +81,14 @@
|
|||||||
"inviteDuration": "Duração do Convite",
|
"inviteDuration": "Duração do Convite",
|
||||||
"enabled": "Habilitado",
|
"enabled": "Habilitado",
|
||||||
"admin": "Admin",
|
"admin": "Admin",
|
||||||
"expiry": "Expiração",
|
"expiry": "Expira",
|
||||||
"userExpiry": "Vencimento do Usuário",
|
"userExpiry": "Vencimento do Usuário",
|
||||||
"extendExpiry": "Extender o vencimento",
|
"extendExpiry": "Extender o vencimento",
|
||||||
"updates": "Atualizações",
|
"updates": "Atualizações",
|
||||||
"update": "Atualizar",
|
"update": "Atualizar",
|
||||||
"download": "Download",
|
"download": "Download",
|
||||||
"search": "Procurar"
|
"search": "Procurar",
|
||||||
|
"advancedSettings": "Configurações Avançada"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"changedEmailAddress": "Endereço de e-mail alterado de {n}.",
|
"changedEmailAddress": "Endereço de e-mail alterado de {n}.",
|
||||||
|
@ -55,5 +55,11 @@
|
|||||||
"clickBelow": "Klicke den untenstehenden Link, um deine E-Mail-Adresse zu bestätigen, und fange an, Jellyfin zu benutzen.",
|
"clickBelow": "Klicke den untenstehenden Link, um deine E-Mail-Adresse zu bestätigen, und fange an, Jellyfin zu benutzen.",
|
||||||
"confirmEmail": "E-Mail bestätigen",
|
"confirmEmail": "E-Mail bestätigen",
|
||||||
"name": "Bestätigungs-E-Mail"
|
"name": "Bestätigungs-E-Mail"
|
||||||
|
},
|
||||||
|
"userExpired": {
|
||||||
|
"name": "Benutzer Ablaufdatum",
|
||||||
|
"title": "Dein Konto ist abgelaufen - Jellyfin",
|
||||||
|
"yourAccountHasExpired": "Dein Konto ist abgelaufen.",
|
||||||
|
"contactTheAdmin": "Kontaktiere den Administrator für weitere Informationen."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,8 @@
|
|||||||
"successHeader": "Erfolg!",
|
"successHeader": "Erfolg!",
|
||||||
"successContinueButton": "Weiter",
|
"successContinueButton": "Weiter",
|
||||||
"confirmationRequired": "E-Mail-Bestätigung erforderlich",
|
"confirmationRequired": "E-Mail-Bestätigung erforderlich",
|
||||||
"confirmationRequiredMessage": "Bitte überprüfe dein Posteingang und bestätige deine E-Mail-Adresse."
|
"confirmationRequiredMessage": "Bitte überprüfe dein Posteingang und bestätige deine E-Mail-Adresse.",
|
||||||
|
"yourAccountIsValidUntil": "Dein Konto wird bis am {date} gültig sein."
|
||||||
},
|
},
|
||||||
"validationStrings": {
|
"validationStrings": {
|
||||||
"length": {
|
"length": {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"successContinueButton": "Continuar",
|
"successContinueButton": "Continuar",
|
||||||
"confirmationRequired": "Necessária confirmação de e-mail",
|
"confirmationRequired": "Necessária confirmação de e-mail",
|
||||||
"confirmationRequiredMessage": "Verifique sua caixa de email para finalizar o cadastro.",
|
"confirmationRequiredMessage": "Verifique sua caixa de email para finalizar o cadastro.",
|
||||||
"yourAccountIsValidUntil": "Sua conta é válida até {data}."
|
"yourAccountIsValidUntil": "Sua conta é válida até {date}."
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
"errorUserExists": "Esse usuário já existe.",
|
"errorUserExists": "Esse usuário já existe.",
|
||||||
|
@ -125,5 +125,12 @@
|
|||||||
"successMessageNotice": "Wird angezeigt, wenn ein Benutzer sein Konto erstellt.",
|
"successMessageNotice": "Wird angezeigt, wenn ein Benutzer sein Konto erstellt.",
|
||||||
"emailMessage": "E-Mailnachricht",
|
"emailMessage": "E-Mailnachricht",
|
||||||
"emailMessageNotice": "Wird am Ende von E-Mails angezeigt."
|
"emailMessageNotice": "Wird am Ende von E-Mails angezeigt."
|
||||||
|
},
|
||||||
|
"updates": {
|
||||||
|
"updateChannel": "Aktualisierungskanal",
|
||||||
|
"unstable": "Unstable",
|
||||||
|
"stable": "Stable",
|
||||||
|
"title": "Aktualisierungen",
|
||||||
|
"description": "Aktiviere, um informiert zu werden, wenn neue Aktualisierungen verfügbar sind. jfa-go wird {n} alle 30 Minuten überprüfen. Keine IP-Adressen oder personenbezogene Daten werden gesammelt."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,5 +125,12 @@
|
|||||||
"successMessageNotice": "Getoond wanneer een gebruiker een account aanmaakt.",
|
"successMessageNotice": "Getoond wanneer een gebruiker een account aanmaakt.",
|
||||||
"emailMessage": "E-mailtext",
|
"emailMessage": "E-mailtext",
|
||||||
"emailMessageNotice": "Getoond onderaan e-mails."
|
"emailMessageNotice": "Getoond onderaan e-mails."
|
||||||
|
},
|
||||||
|
"updates": {
|
||||||
|
"unstable": "Instabiel",
|
||||||
|
"updateChannel": "Update kanaal",
|
||||||
|
"stable": "Stabiel",
|
||||||
|
"title": "Updates",
|
||||||
|
"description": "Vink aan om een melding te krijgen wanneer nieuwe updates beschikbaar zijn. jfa-go controleert {n} elke 30 minuten. Er worden geen IPs of persoonsgegevens verzameld."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -125,5 +125,12 @@
|
|||||||
"successMessageNotice": "Exibido quando um usuário cria sua conta.",
|
"successMessageNotice": "Exibido quando um usuário cria sua conta.",
|
||||||
"emailMessage": "Mensagem de Email",
|
"emailMessage": "Mensagem de Email",
|
||||||
"emailMessageNotice": "Exibido na parte inferior dos emails."
|
"emailMessageNotice": "Exibido na parte inferior dos emails."
|
||||||
|
},
|
||||||
|
"updates": {
|
||||||
|
"title": "Atualizações",
|
||||||
|
"description": "Ative para ser notificado quando novas atualizações estiverem disponíveis. jfa-go verificará {n} a cada 30 minutos. Nenhum IP ou informação de identificação pessoal é coletada.",
|
||||||
|
"updateChannel": "Canal de Atualização",
|
||||||
|
"stable": "Estável",
|
||||||
|
"unstable": "Instável"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
69
stripmd.go
69
stripmd.go
@ -6,50 +6,41 @@ import (
|
|||||||
stripmd "github.com/writeas/go-strip-markdown"
|
stripmd "github.com/writeas/go-strip-markdown"
|
||||||
)
|
)
|
||||||
|
|
||||||
func stripMarkdown(md string) string {
|
// StripAltText removes Markdown alt text from links and images and replaces them with just the URL.
|
||||||
// Search for markdown-formatted urls, and replace them with just the url, then use a library to strip any traces of markdown. You'll need some eyebleach after this.
|
// Currently uses the deepest alt text when links/images are nested.
|
||||||
foundOpenSquare := false
|
func StripAltText(md string) string {
|
||||||
openSquare := -1
|
altTextStart := -1 // Start of alt text (between '[' & ']')
|
||||||
openBracket := -1
|
URLStart := -1 // Start of url (between '(' & ')')
|
||||||
closeBracket := -1
|
URLEnd := -1
|
||||||
openSquares := []int{}
|
previousURLEnd := -2
|
||||||
closeBrackets := []int{}
|
out := ""
|
||||||
links := []string{}
|
for i := range md {
|
||||||
foundOpen := false
|
if altTextStart != -1 && URLStart != -1 && md[i] == ')' {
|
||||||
for i, c := range md {
|
URLEnd = i - 1
|
||||||
if !foundOpenSquare && !foundOpen && c != '[' && c != ']' {
|
out += md[previousURLEnd+2:altTextStart-1] + md[URLStart:URLEnd+1]
|
||||||
|
previousURLEnd = URLEnd
|
||||||
|
altTextStart, URLStart, URLEnd = -1, -1, -1
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c == '[' && md[i-1] != '!' {
|
if md[i] == '[' && altTextStart == -1 {
|
||||||
foundOpenSquare = true
|
altTextStart = i + 1
|
||||||
openSquare = i
|
if i > 0 && md[i-1] == '!' {
|
||||||
} else if c == ']' {
|
altTextStart--
|
||||||
if md[i+1] == '(' {
|
|
||||||
foundOpenSquare = false
|
|
||||||
foundOpen = true
|
|
||||||
openBracket = i + 1
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
} else if c == ')' {
|
}
|
||||||
closeBracket = i
|
if i > 0 && md[i-1] == ']' && md[i] == '(' && URLStart == -1 {
|
||||||
openSquares = append(openSquares, openSquare)
|
URLStart = i + 1
|
||||||
closeBrackets = append(closeBrackets, closeBracket)
|
|
||||||
links = append(links, md[openBracket+1:closeBracket])
|
|
||||||
openBracket = -1
|
|
||||||
closeBracket = -1
|
|
||||||
openSquare = -1
|
|
||||||
foundOpenSquare = false
|
|
||||||
foundOpen = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fullLinks := make([]string, len(openSquares))
|
if previousURLEnd+1 != len(md)-1 {
|
||||||
for i := range openSquares {
|
out += md[previousURLEnd+2:]
|
||||||
if openSquares[i] != -1 && closeBrackets[i] != -1 {
|
|
||||||
fullLinks[i] = md[openSquares[i] : closeBrackets[i]+1]
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
for i, _ := range openSquares {
|
if out == "" {
|
||||||
md = strings.Replace(md, fullLinks[i], links[i], 1)
|
return md
|
||||||
}
|
}
|
||||||
return strings.TrimPrefix(strings.TrimSuffix(stripmd.Strip(md), "</p>"), "<p>")
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripMarkdown(md string) string {
|
||||||
|
return strings.TrimPrefix(strings.TrimSuffix(stripmd.Strip(StripAltText(md)), "</p>"), "<p>")
|
||||||
}
|
}
|
||||||
|
@ -1,49 +1,40 @@
|
|||||||
const removeMd = require("remove-markdown");
|
const removeMd = require("remove-markdown");
|
||||||
|
|
||||||
export function stripMarkdown(md: string): string {
|
function stripAltText(md: string): string {
|
||||||
let foundOpenSquare = false;
|
let altStart = -1; // Start of alt text (between '[' & ']')
|
||||||
let openSquare = -1;
|
let urlStart = -1; // Start of url (between '(' & ')')
|
||||||
let openBracket = -1;
|
let urlEnd = -1;
|
||||||
let closeBracket = -1;
|
let prevURLEnd = -2;
|
||||||
let openSquares: number[] = [];
|
let out = "";
|
||||||
let closeBrackets: number[] = [];
|
|
||||||
let links: string[] = [];
|
|
||||||
let foundOpen = false;
|
|
||||||
for (let i = 0; i < md.length; i++) {
|
for (let i = 0; i < md.length; i++) {
|
||||||
const c = md.charAt(i);
|
if (altStart != -1 && urlStart != -1 && md.charAt(i) == ')') {
|
||||||
if (!foundOpenSquare && !foundOpen && c != '[' && c != ']') {
|
urlEnd = i - 1;
|
||||||
|
out += md.substring(prevURLEnd+2, altStart-1) + md.substring(urlStart, urlEnd+1);
|
||||||
|
prevURLEnd = urlEnd;
|
||||||
|
altStart = -1;
|
||||||
|
urlStart = -1;
|
||||||
|
urlEnd = -1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (c == '[' && md.charAt(i-1) != '!') {
|
if (md.charAt(i) == '[' && altStart == -1) {
|
||||||
foundOpenSquare = true;
|
altStart = i + 1
|
||||||
openSquare = i;
|
if (i > 0 && md.charAt(i-1) == '!') {
|
||||||
} else if (c == ']') {
|
altStart--
|
||||||
if (md.charAt(i+1) == '(') {
|
|
||||||
foundOpenSquare = false;
|
|
||||||
foundOpen = true;
|
|
||||||
openBracket = i + 1;
|
|
||||||
continue;
|
|
||||||
}
|
}
|
||||||
} else if (c == ')') {
|
}
|
||||||
closeBracket = i;
|
if (i > 0 && md.charAt(i-1) == ']' && md.charAt(i) == '(' && urlStart == -1) {
|
||||||
openSquares.push(openSquare);
|
urlStart = i + 1
|
||||||
closeBrackets.push(closeBracket);
|
|
||||||
links.push(md.slice(openBracket+1, closeBracket))
|
|
||||||
openBracket = -1;
|
|
||||||
closeBracket = -1;
|
|
||||||
openSquare = -1;
|
|
||||||
foundOpenSquare = false;
|
|
||||||
foundOpen = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let fullLinks: string[] = new Array(openSquares.length);
|
if (prevURLEnd + 1 != md.length - 1) {
|
||||||
for (let i = 0; i < openSquares.length; i++) {
|
out += md.substring(prevURLEnd+2)
|
||||||
if (openSquares[i] != -1 && closeBrackets[i] != -1) {
|
}
|
||||||
fullLinks[i] = md.slice(openSquares[i], closeBrackets[i]+1)
|
if (out == "") {
|
||||||
}
|
return md
|
||||||
}
|
}
|
||||||
for (let i = 0; i < openSquares.length; i++) {
|
return out
|
||||||
md = md.replace(fullLinks[i], links[i]);
|
}
|
||||||
}
|
|
||||||
return removeMd(md);
|
export function stripMarkdown(md: string): string {
|
||||||
|
return removeMd(stripAltText(md));
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user