Add Invidious/Nitter link replacement preferences
This commit is contained in:
parent
93da24be85
commit
7dfbc16f4c
6 changed files with 41 additions and 16 deletions
|
@ -11,6 +11,8 @@ const
|
||||||
usernameRegex = re"(^|[^A-z0-9_?])@([A-z0-9_]+)"
|
usernameRegex = re"(^|[^A-z0-9_?])@([A-z0-9_]+)"
|
||||||
picRegex = re"pic.twitter.com/[^ ]+"
|
picRegex = re"pic.twitter.com/[^ ]+"
|
||||||
ellipsisRegex = re" ?…"
|
ellipsisRegex = re" ?…"
|
||||||
|
ytRegex = re"youtu(be.com|.be)"
|
||||||
|
twRegex = re"twitter.com"
|
||||||
nbsp = $Rune(0x000A0)
|
nbsp = $Rune(0x000A0)
|
||||||
|
|
||||||
proc stripText*(text: string): string =
|
proc stripText*(text: string): string =
|
||||||
|
@ -46,7 +48,7 @@ proc reUsernameToLink*(m: RegexMatch; s: string): string =
|
||||||
|
|
||||||
pretext & toLink("/" & username, "@" & username)
|
pretext & toLink("/" & username, "@" & username)
|
||||||
|
|
||||||
proc linkifyText*(text: string): string =
|
proc linkifyText*(text: string; prefs: Prefs): string =
|
||||||
result = xmltree.escape(stripText(text))
|
result = xmltree.escape(stripText(text))
|
||||||
result = result.replace(ellipsisRegex, "")
|
result = result.replace(ellipsisRegex, "")
|
||||||
result = result.replace(emailRegex, reEmailToLink)
|
result = result.replace(emailRegex, reEmailToLink)
|
||||||
|
@ -55,6 +57,16 @@ proc linkifyText*(text: string): string =
|
||||||
result = result.replace(re"([^\s\(\n%])<a", "$1 <a")
|
result = result.replace(re"([^\s\(\n%])<a", "$1 <a")
|
||||||
result = result.replace(re"</a>\s+([;.,!\)'%]|')", "</a>$1")
|
result = result.replace(re"</a>\s+([;.,!\)'%]|')", "</a>$1")
|
||||||
result = result.replace(re"^\. <a", ".<a")
|
result = result.replace(re"^\. <a", ".<a")
|
||||||
|
if prefs.replaceYouTube.len > 0:
|
||||||
|
result = result.replace(ytRegex, prefs.replaceYouTube)
|
||||||
|
if prefs.replaceTwitter.len > 0:
|
||||||
|
result = result.replace(twRegex, prefs.replaceTwitter)
|
||||||
|
|
||||||
|
proc replaceUrl*(url: string; prefs: Prefs): string =
|
||||||
|
if prefs.replaceYouTube.len > 0:
|
||||||
|
return url.replace(ytRegex, prefs.replaceYouTube)
|
||||||
|
if prefs.replaceTwitter.len > 0:
|
||||||
|
return url.replace(twRegex, prefs.replaceTwitter)
|
||||||
|
|
||||||
proc stripTwitterUrls*(text: string): string =
|
proc stripTwitterUrls*(text: string): string =
|
||||||
result = text
|
result = text
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import asyncdispatch, asyncfile, httpclient, sequtils, strutils, strformat, uri, os
|
import asyncdispatch, asyncfile, httpclient, uri, os
|
||||||
|
import sequtils, strformat, strutils
|
||||||
from net import Port
|
from net import Port
|
||||||
|
|
||||||
import jester, regex
|
import jester, regex
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import asyncdispatch, times, macros, tables
|
import asyncdispatch, times, macros, tables, xmltree
|
||||||
import types
|
import types
|
||||||
|
|
||||||
withCustomDb("prefs.db", "", "", ""):
|
withCustomDb("prefs.db", "", "", ""):
|
||||||
|
@ -25,6 +25,16 @@ type
|
||||||
placeholder*: string
|
placeholder*: string
|
||||||
|
|
||||||
const prefList*: Table[string, seq[Pref]] = {
|
const prefList*: Table[string, seq[Pref]] = {
|
||||||
|
"Privacy": @[
|
||||||
|
Pref(kind: input, name: "replaceTwitter",
|
||||||
|
label: "Replace Twitter links with Nitter (blank to disable)",
|
||||||
|
defaultInput: "nitter.net", placeholder: "Nitter hostname"),
|
||||||
|
|
||||||
|
Pref(kind: input, name: "replaceYouTube",
|
||||||
|
label: "Replace YouTube links with Invidious (blank to disable)",
|
||||||
|
defaultInput: "invidio.us", placeholder: "Invidious hostname")
|
||||||
|
],
|
||||||
|
|
||||||
"Media": @[
|
"Media": @[
|
||||||
Pref(kind: checkbox, name: "videoPlayback",
|
Pref(kind: checkbox, name: "videoPlayback",
|
||||||
label: "Enable hls.js video playback (requires JavaScript)",
|
label: "Enable hls.js video playback (requires JavaScript)",
|
||||||
|
@ -94,7 +104,7 @@ macro genUpdatePrefs*(): untyped =
|
||||||
of checkbox:
|
of checkbox:
|
||||||
result.add quote do: prefs.`ident` = `value` == "on"
|
result.add quote do: prefs.`ident` = `value` == "on"
|
||||||
of input:
|
of input:
|
||||||
result.add quote do: prefs.`ident` = `value`
|
result.add quote do: prefs.`ident` = xmltree.escape(strip(`value`))
|
||||||
of select:
|
of select:
|
||||||
let options = pref.options
|
let options = pref.options
|
||||||
let default = pref.defaultOption
|
let default = pref.defaultOption
|
||||||
|
|
|
@ -43,9 +43,9 @@ db("cache.db", "", "", ""):
|
||||||
thumb*: string
|
thumb*: string
|
||||||
views*: string
|
views*: string
|
||||||
playbackType* {.
|
playbackType* {.
|
||||||
dbType: "STRING",
|
dbType: "STRING"
|
||||||
parseIt: parseEnum[VideoType](it.s),
|
parseIt: parseEnum[VideoType](it.s)
|
||||||
formatIt: $it,
|
formatIt: $it
|
||||||
.}: VideoType
|
.}: VideoType
|
||||||
available* {.dbType: "STRING", parseIt: parseBool(it.s) formatIt: $it.}: bool
|
available* {.dbType: "STRING", parseIt: parseBool(it.s) formatIt: $it.}: bool
|
||||||
|
|
||||||
|
@ -55,6 +55,8 @@ db("cache.db", "", "", ""):
|
||||||
hideTweetStats* {.dbType: "STRING", parseIt: parseBool(it.s), formatIt: $it.}: bool
|
hideTweetStats* {.dbType: "STRING", parseIt: parseBool(it.s), formatIt: $it.}: bool
|
||||||
hideBanner* {.dbType: "STRING", parseIt: parseBool(it.s), formatIt: $it.}: bool
|
hideBanner* {.dbType: "STRING", parseIt: parseBool(it.s), formatIt: $it.}: bool
|
||||||
stickyProfile* {.dbType: "STRING", parseIt: parseBool(it.s), formatIt: $it.}: bool
|
stickyProfile* {.dbType: "STRING", parseIt: parseBool(it.s), formatIt: $it.}: bool
|
||||||
|
replaceYouTube*: string
|
||||||
|
replaceTwitter*: string
|
||||||
|
|
||||||
type
|
type
|
||||||
QueryKind* = enum
|
QueryKind* = enum
|
||||||
|
|
|
@ -11,7 +11,7 @@ proc renderStat(num, class: string; text=""): VNode =
|
||||||
span(class="profile-stat-num"):
|
span(class="profile-stat-num"):
|
||||||
text if num.len == 0: "?" else: num
|
text if num.len == 0: "?" else: num
|
||||||
|
|
||||||
proc renderProfileCard*(profile: Profile): VNode =
|
proc renderProfileCard*(profile: Profile; prefs: Prefs): VNode =
|
||||||
buildHtml(tdiv(class="profile-card")):
|
buildHtml(tdiv(class="profile-card")):
|
||||||
a(class="profile-card-avatar", href=profile.getUserPic().getSigUrl("pic")):
|
a(class="profile-card-avatar", href=profile.getUserPic().getSigUrl("pic")):
|
||||||
genImg(profile.getUserpic("_200x200"))
|
genImg(profile.getUserpic("_200x200"))
|
||||||
|
@ -23,7 +23,7 @@ proc renderProfileCard*(profile: Profile): VNode =
|
||||||
tdiv(class="profile-card-extra"):
|
tdiv(class="profile-card-extra"):
|
||||||
if profile.bio.len > 0:
|
if profile.bio.len > 0:
|
||||||
tdiv(class="profile-bio"):
|
tdiv(class="profile-bio"):
|
||||||
p: verbatim linkifyText(profile.bio)
|
p: verbatim linkifyText(profile.bio, prefs)
|
||||||
|
|
||||||
if profile.location.len > 0:
|
if profile.location.len > 0:
|
||||||
tdiv(class="profile-location"):
|
tdiv(class="profile-location"):
|
||||||
|
@ -76,7 +76,7 @@ proc renderProfile*(profile: Profile; timeline: Timeline;
|
||||||
|
|
||||||
let sticky = if prefs.stickyProfile: "sticky" else: "unset"
|
let sticky = if prefs.stickyProfile: "sticky" else: "unset"
|
||||||
tdiv(class="profile-tab", style={position: sticky}):
|
tdiv(class="profile-tab", style={position: sticky}):
|
||||||
renderProfileCard(profile)
|
renderProfileCard(profile, prefs)
|
||||||
if photoRail.len > 0:
|
if photoRail.len > 0:
|
||||||
renderPhotoRail(profile, photoRail)
|
renderPhotoRail(profile, photoRail)
|
||||||
|
|
||||||
|
|
|
@ -92,7 +92,7 @@ proc renderPoll(poll: Poll): VNode =
|
||||||
proc renderCardImage(card: Card): VNode =
|
proc renderCardImage(card: Card): VNode =
|
||||||
buildHtml(tdiv(class="card-image-container")):
|
buildHtml(tdiv(class="card-image-container")):
|
||||||
tdiv(class="card-image"):
|
tdiv(class="card-image"):
|
||||||
img(src=get(card.image).getSigUrl("pic"))
|
img(src=getSigUrl(get(card.image), "pic"))
|
||||||
if card.kind == player:
|
if card.kind == player:
|
||||||
tdiv(class="card-overlay"):
|
tdiv(class="card-overlay"):
|
||||||
tdiv(class="card-overlay-circle"):
|
tdiv(class="card-overlay-circle"):
|
||||||
|
@ -103,7 +103,7 @@ proc renderCard(card: Card; prefs: Prefs): VNode =
|
||||||
let large = if card.kind in largeCards: " large" else: ""
|
let large = if card.kind in largeCards: " large" else: ""
|
||||||
|
|
||||||
buildHtml(tdiv(class=("card" & large))):
|
buildHtml(tdiv(class=("card" & large))):
|
||||||
a(class="card-container", href=card.url):
|
a(class="card-container", href=replaceUrl(card.url, prefs)):
|
||||||
if card.image.isSome:
|
if card.image.isSome:
|
||||||
renderCardImage(card)
|
renderCardImage(card)
|
||||||
elif card.video.isSome:
|
elif card.video.isSome:
|
||||||
|
@ -147,7 +147,7 @@ proc renderQuoteMedia(quote: Quote): VNode =
|
||||||
tdiv(class="quote-sensitive"):
|
tdiv(class="quote-sensitive"):
|
||||||
icon "attention", class="quote-sensitive-icon"
|
icon "attention", class="quote-sensitive-icon"
|
||||||
|
|
||||||
proc renderQuote(quote: Quote): VNode =
|
proc renderQuote(quote: Quote; prefs: Prefs): VNode =
|
||||||
if not quote.available:
|
if not quote.available:
|
||||||
return buildHtml(tdiv(class="quote unavailable")):
|
return buildHtml(tdiv(class="quote unavailable")):
|
||||||
tdiv(class="unavailable-quote"):
|
tdiv(class="unavailable-quote"):
|
||||||
|
@ -167,7 +167,7 @@ proc renderQuote(quote: Quote): VNode =
|
||||||
renderReply(quote)
|
renderReply(quote)
|
||||||
|
|
||||||
tdiv(class="quote-text"):
|
tdiv(class="quote-text"):
|
||||||
verbatim linkifyText(quote.text)
|
verbatim linkifyText(quote.text, prefs)
|
||||||
|
|
||||||
if quote.hasThread:
|
if quote.hasThread:
|
||||||
a(class="show-thread", href=getLink(quote)):
|
a(class="show-thread", href=getLink(quote)):
|
||||||
|
@ -194,10 +194,10 @@ proc renderTweet*(tweet: Tweet; prefs: Prefs; class="";
|
||||||
renderReply(tweet)
|
renderReply(tweet)
|
||||||
|
|
||||||
tdiv(class="status-content media-body"):
|
tdiv(class="status-content media-body"):
|
||||||
verbatim linkifyText(tweet.text)
|
verbatim linkifyText(tweet.text, prefs)
|
||||||
|
|
||||||
if tweet.quote.isSome:
|
if tweet.quote.isSome:
|
||||||
renderQuote(tweet.quote.get())
|
renderQuote(tweet.quote.get(), prefs)
|
||||||
|
|
||||||
if tweet.card.isSome:
|
if tweet.card.isSome:
|
||||||
renderCard(tweet.card.get(), prefs)
|
renderCard(tweet.card.get(), prefs)
|
||||||
|
|
Loading…
Reference in a new issue