From a0a25d64f1e63a896564c1f615383b43714de76b Mon Sep 17 00:00:00 2001 From: Harvey Tindall Date: Fri, 26 Mar 2021 23:13:19 +0000 Subject: [PATCH] rewrite stripmd, fix some typos doesn't work any better, but more efficient and doesn't require eyebleach after viewing. --- README.md | 4 +-- stripmd.go | 69 +++++++++++++++++++------------------------ ts/modules/stripmd.ts | 69 +++++++++++++++++++------------------------ 3 files changed, 62 insertions(+), 80 deletions(-) diff --git a/README.md b/README.md index 0900fed..fd2c53e 100644 --- a/README.md +++ b/README.md @@ -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. * 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. -* ⌛ 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. * 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 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. * 📣 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. diff --git a/stripmd.go b/stripmd.go index 7ea2266..0568067 100644 --- a/stripmd.go +++ b/stripmd.go @@ -6,50 +6,41 @@ import ( stripmd "github.com/writeas/go-strip-markdown" ) -func stripMarkdown(md string) string { - // 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. - foundOpenSquare := false - openSquare := -1 - openBracket := -1 - closeBracket := -1 - openSquares := []int{} - closeBrackets := []int{} - links := []string{} - foundOpen := false - for i, c := range md { - if !foundOpenSquare && !foundOpen && c != '[' && c != ']' { +// StripAltText removes Markdown alt text from links and images and replaces them with just the URL. +// Currently uses the deepest alt text when links/images are nested. +func StripAltText(md string) string { + altTextStart := -1 // Start of alt text (between '[' & ']') + URLStart := -1 // Start of url (between '(' & ')') + URLEnd := -1 + previousURLEnd := -2 + out := "" + for i := range md { + if altTextStart != -1 && URLStart != -1 && md[i] == ')' { + URLEnd = i - 1 + out += md[previousURLEnd+2:altTextStart-1] + md[URLStart:URLEnd+1] + previousURLEnd = URLEnd + altTextStart, URLStart, URLEnd = -1, -1, -1 continue } - if c == '[' && md[i-1] != '!' { - foundOpenSquare = true - openSquare = i - } else if c == ']' { - if md[i+1] == '(' { - foundOpenSquare = false - foundOpen = true - openBracket = i + 1 - continue + if md[i] == '[' && altTextStart == -1 { + altTextStart = i + 1 + if i > 0 && md[i-1] == '!' { + altTextStart-- } - } else if c == ')' { - closeBracket = i - openSquares = append(openSquares, openSquare) - 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)) - for i := range openSquares { - if openSquares[i] != -1 && closeBrackets[i] != -1 { - fullLinks[i] = md[openSquares[i] : closeBrackets[i]+1] + if i > 0 && md[i-1] == ']' && md[i] == '(' && URLStart == -1 { + URLStart = i + 1 } } - for i, _ := range openSquares { - md = strings.Replace(md, fullLinks[i], links[i], 1) + if previousURLEnd+1 != len(md)-1 { + out += md[previousURLEnd+2:] + } + if out == "" { + return md } - return strings.TrimPrefix(strings.TrimSuffix(stripmd.Strip(md), "

"), "

") + return out +} + +func stripMarkdown(md string) string { + return strings.TrimPrefix(strings.TrimSuffix(stripmd.Strip(StripAltText(md)), "

"), "

") } diff --git a/ts/modules/stripmd.ts b/ts/modules/stripmd.ts index cc184cf..39381ab 100644 --- a/ts/modules/stripmd.ts +++ b/ts/modules/stripmd.ts @@ -1,49 +1,40 @@ const removeMd = require("remove-markdown"); -export function stripMarkdown(md: string): string { - let foundOpenSquare = false; - let openSquare = -1; - let openBracket = -1; - let closeBracket = -1; - let openSquares: number[] = []; - let closeBrackets: number[] = []; - let links: string[] = []; - let foundOpen = false; +function stripAltText(md: string): string { + let altStart = -1; // Start of alt text (between '[' & ']') + let urlStart = -1; // Start of url (between '(' & ')') + let urlEnd = -1; + let prevURLEnd = -2; + let out = ""; for (let i = 0; i < md.length; i++) { - const c = md.charAt(i); - if (!foundOpenSquare && !foundOpen && c != '[' && c != ']') { + if (altStart != -1 && urlStart != -1 && md.charAt(i) == ')') { + urlEnd = i - 1; + out += md.substring(prevURLEnd+2, altStart-1) + md.substring(urlStart, urlEnd+1); + prevURLEnd = urlEnd; + altStart = -1; + urlStart = -1; + urlEnd = -1; continue; } - if (c == '[' && md.charAt(i-1) != '!') { - foundOpenSquare = true; - openSquare = i; - } else if (c == ']') { - if (md.charAt(i+1) == '(') { - foundOpenSquare = false; - foundOpen = true; - openBracket = i + 1; - continue; + if (md.charAt(i) == '[' && altStart == -1) { + altStart = i + 1 + if (i > 0 && md.charAt(i-1) == '!') { + altStart-- } - } else if (c == ')') { - closeBracket = i; - openSquares.push(openSquare); - 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); - for (let i = 0; i < openSquares.length; i++) { - if (openSquares[i] != -1 && closeBrackets[i] != -1) { - fullLinks[i] = md.slice(openSquares[i], closeBrackets[i]+1) + if (i > 0 && md.charAt(i-1) == ']' && md.charAt(i) == '(' && urlStart == -1) { + urlStart = i + 1 } } - for (let i = 0; i < openSquares.length; i++) { - md = md.replace(fullLinks[i], links[i]); - } - return removeMd(md); + if (prevURLEnd + 1 != md.length - 1) { + out += md.substring(prevURLEnd+2) + } + if (out == "") { + return md + } + return out +} + +export function stripMarkdown(md: string): string { + return removeMd(stripAltText(md)); }