Refactor images to use an Image type to supply alt text
This commit is contained in:
parent
f2cac5190a
commit
8042c65ce3
@ -250,7 +250,9 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull()): Tweet =
|
|||||||
let name = jsCard{"name"}.getStr
|
let name = jsCard{"name"}.getStr
|
||||||
if "poll" in name:
|
if "poll" in name:
|
||||||
if "image" in name:
|
if "image" in name:
|
||||||
result.photos.add jsCard{"binding_values", "image_large"}.getImageVal
|
result.photos.add Image(
|
||||||
|
url: jsCard{"binding_values", "image_large"}.getImageVal
|
||||||
|
)
|
||||||
|
|
||||||
result.poll = some parsePoll(jsCard)
|
result.poll = some parsePoll(jsCard)
|
||||||
elif name == "amplify":
|
elif name == "amplify":
|
||||||
@ -264,7 +266,10 @@ proc parseTweet(js: JsonNode; jsCard: JsonNode = newJNull()): Tweet =
|
|||||||
for m in jsMedia:
|
for m in jsMedia:
|
||||||
case m{"type"}.getStr
|
case m{"type"}.getStr
|
||||||
of "photo":
|
of "photo":
|
||||||
result.photos.add m{"media_url_https"}.getImageStr
|
result.photos.add Image(
|
||||||
|
url: m{"media_url_https"}.getImageStr,
|
||||||
|
description: m{"ext_alt_text"}.getStr,
|
||||||
|
)
|
||||||
of "video":
|
of "video":
|
||||||
result.video = some(parseVideo(m))
|
result.video = some(parseVideo(m))
|
||||||
with user, m{"additional_media_info", "source_user"}:
|
with user, m{"additional_media_info", "source_user"}:
|
||||||
@ -418,7 +423,7 @@ proc parsePhotoRail*(js: JsonNode): PhotoRail =
|
|||||||
for tweet in js:
|
for tweet in js:
|
||||||
let
|
let
|
||||||
t = parseTweet(tweet, js{"tweet_card"})
|
t = parseTweet(tweet, js{"tweet_card"})
|
||||||
url = if t.photos.len > 0: t.photos[0]
|
url = if t.photos.len > 0: t.photos[0].url
|
||||||
elif t.video.isSome: get(t.video).thumb
|
elif t.video.isSome: get(t.video).thumb
|
||||||
elif t.gif.isSome: get(t.gif).thumb
|
elif t.gif.isSome: get(t.gif).thumb
|
||||||
elif t.card.isSome: get(t.card).image
|
elif t.card.isSome: get(t.card).image
|
||||||
|
|||||||
@ -45,8 +45,8 @@ proc createActivityPubRouter*(cfg: Config) =
|
|||||||
var media: seq[JsonNode] = @[]
|
var media: seq[JsonNode] = @[]
|
||||||
|
|
||||||
if tweet.photos.len > 0:
|
if tweet.photos.len > 0:
|
||||||
for url in tweet.photos:
|
for imageObj in tweet.photos:
|
||||||
let image = getUrlPrefix(cfg) & getPicUrl(url)
|
let image = getUrlPrefix(cfg) & getPicUrl(imageObj.url)
|
||||||
var mediaObj = newJObject()
|
var mediaObj = newJObject()
|
||||||
|
|
||||||
mediaObj["id"] = %"150745989836308480" # idk if discord even parses this snowflake, but its my user id why not
|
mediaObj["id"] = %"150745989836308480" # idk if discord even parses this snowflake, but its my user id why not
|
||||||
@ -56,7 +56,7 @@ proc createActivityPubRouter*(cfg: Config) =
|
|||||||
mediaObj["remote_url"] = %image
|
mediaObj["remote_url"] = %image
|
||||||
mediaObj["preview_remote_url"] = %image
|
mediaObj["preview_remote_url"] = %image
|
||||||
mediaObj["text_url"] = newJNull()
|
mediaObj["text_url"] = newJNull()
|
||||||
mediaObj["description"] = newJNull() # FIXME this requires refactoring images
|
mediaObj["description"] = %imageObj.description
|
||||||
# FIXME but this probably isnt used by discord
|
# FIXME but this probably isnt used by discord
|
||||||
mediaObj["meta"] = newJObject()
|
mediaObj["meta"] = newJObject()
|
||||||
|
|
||||||
|
|||||||
@ -123,7 +123,7 @@ proc createStatusRouter*(cfg: Config) =
|
|||||||
|
|
||||||
if tweet.video.isSome():
|
if tweet.video.isSome():
|
||||||
let videoObj = get(tweet.video)
|
let videoObj = get(tweet.video)
|
||||||
images = @[videoObj.thumb]
|
images = @[Image(url:videoObj.thumb)]
|
||||||
|
|
||||||
let vars = videoObj.variants.filterIt(it.contentType == mp4)
|
let vars = videoObj.variants.filterIt(it.contentType == mp4)
|
||||||
# idk why this wont sort when it sorts everywhere else
|
# idk why this wont sort when it sorts everywhere else
|
||||||
@ -131,7 +131,7 @@ proc createStatusRouter*(cfg: Config) =
|
|||||||
video = vars[^1].url
|
video = vars[^1].url
|
||||||
elif tweet.gif.isSome():
|
elif tweet.gif.isSome():
|
||||||
let gif = get(tweet.gif)
|
let gif = get(tweet.gif)
|
||||||
images = @[gif.thumb]
|
images = @[Image(url:gif.thumb)]
|
||||||
video = getUrlPrefix(cfg) & getPicUrl(gif.url)
|
video = getUrlPrefix(cfg) & getPicUrl(gif.url)
|
||||||
#elif tweet.card.isSome():
|
#elif tweet.card.isSome():
|
||||||
# let card = tweet.card.get()
|
# let card = tweet.card.get()
|
||||||
|
|||||||
@ -96,7 +96,7 @@ proc showTimeline*(request: Request; query: Query; cfg: Config; prefs: Prefs;
|
|||||||
|
|
||||||
let pHtml = renderProfile(profile, cfg, prefs, getPath())
|
let pHtml = renderProfile(profile, cfg, prefs, getPath())
|
||||||
result = renderMain(pHtml, request, cfg, prefs, pageTitle(u), pageDesc(u),
|
result = renderMain(pHtml, request, cfg, prefs, pageTitle(u), pageDesc(u),
|
||||||
rss=rss, images = @[u.getUserPic("_400x400")],
|
rss=rss, images = @[Image(url: u.getUserPic("_400x400"))],
|
||||||
banner=u.banner)
|
banner=u.banner)
|
||||||
|
|
||||||
template respTimeline*(timeline: typed) =
|
template respTimeline*(timeline: typed) =
|
||||||
|
|||||||
@ -48,6 +48,19 @@
|
|||||||
margin: 0;
|
margin: 0;
|
||||||
max-height: 530px;
|
max-height: 530px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alt {
|
||||||
|
position: relative;
|
||||||
|
bottom: 15px;
|
||||||
|
left: 4px;
|
||||||
|
padding: 4px;
|
||||||
|
background: #101010;
|
||||||
|
color: white;
|
||||||
|
border-radius: 4px;
|
||||||
|
pointer-events: none;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.gallery-gif video {
|
.gallery-gif video {
|
||||||
|
|||||||
@ -123,6 +123,10 @@ type
|
|||||||
playbackType*: VideoType
|
playbackType*: VideoType
|
||||||
variants*: seq[VideoVariant]
|
variants*: seq[VideoVariant]
|
||||||
|
|
||||||
|
Image* = object
|
||||||
|
url*: string
|
||||||
|
description*: string
|
||||||
|
|
||||||
QueryKind* = enum
|
QueryKind* = enum
|
||||||
posts, replies, media, users, tweets, userList, favorites
|
posts, replies, media, users, tweets, userList, favorites
|
||||||
|
|
||||||
@ -228,7 +232,7 @@ type
|
|||||||
poll*: Option[Poll]
|
poll*: Option[Poll]
|
||||||
gif*: Option[Gif]
|
gif*: Option[Gif]
|
||||||
video*: Option[Video]
|
video*: Option[Video]
|
||||||
photos*: seq[string]
|
photos*: seq[Image]
|
||||||
birdwatch*: Option[BirdwatchNote]
|
birdwatch*: Option[BirdwatchNote]
|
||||||
|
|
||||||
Tweets* = seq[Tweet]
|
Tweets* = seq[Tweet]
|
||||||
|
|||||||
@ -15,7 +15,7 @@ proc renderVideoEmbed*(tweet: Tweet; cfg: Config; req: Request): string =
|
|||||||
let vidUrl = vars.sortedByIt(it.bitrate)[^1].url
|
let vidUrl = vars.sortedByIt(it.bitrate)[^1].url
|
||||||
let prefs = Prefs(hlsPlayback: true, mp4Playback: true)
|
let prefs = Prefs(hlsPlayback: true, mp4Playback: true)
|
||||||
let node = buildHtml(html(lang="en")):
|
let node = buildHtml(html(lang="en")):
|
||||||
renderHead(prefs, cfg, req, video=vidUrl, images=(@[thumb]))
|
renderHead(prefs, cfg, req, video=vidUrl, images=(@[Image(url:thumb)]))
|
||||||
|
|
||||||
body:
|
body:
|
||||||
tdiv(class="embed-video"):
|
tdiv(class="embed-video"):
|
||||||
|
|||||||
@ -37,7 +37,7 @@ proc renderNavbar(cfg: Config; req: Request; rss, canonical: string): VNode =
|
|||||||
icon "cog", title="Preferences", href=("/settings?referer=" & encodeUrl(path))
|
icon "cog", title="Preferences", href=("/settings?referer=" & encodeUrl(path))
|
||||||
|
|
||||||
proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
|
proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
|
||||||
video=""; images: seq[string] = @[]; banner=""; ogTitle="";
|
video=""; images: seq[Image] = @[]; banner=""; ogTitle="";
|
||||||
rss=""; canonical=""; avatar=""; context=""; contextUrl="";
|
rss=""; canonical=""; avatar=""; context=""; contextUrl="";
|
||||||
id=""; time: Option[DateTime] = none(DateTime)): VNode =
|
id=""; time: Option[DateTime] = none(DateTime)): VNode =
|
||||||
var theme = prefs.theme.toTheme
|
var theme = prefs.theme.toTheme
|
||||||
@ -120,13 +120,16 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
|
|||||||
link(rel="preload", type="image/png", href=bannerUrl, `as`="image")
|
link(rel="preload", type="image/png", href=bannerUrl, `as`="image")
|
||||||
|
|
||||||
if images.len > 0:
|
if images.len > 0:
|
||||||
for url in images:
|
for imageObj in images:
|
||||||
let preloadUrl = if "400x400" in url: getPicUrl(url)
|
let
|
||||||
|
url = imageObj.url
|
||||||
|
preloadUrl = if "400x400" in url: getPicUrl(url)
|
||||||
else: getSmallPic(url)
|
else: getSmallPic(url)
|
||||||
link(rel="preload", type="image/png", href=preloadUrl, `as`="image")
|
link(rel="preload", type="image/png", href=preloadUrl, `as`="image")
|
||||||
|
|
||||||
let image = getUrlPrefix(cfg) & getPicUrl(url)
|
let image = getUrlPrefix(cfg) & getPicUrl(url)
|
||||||
meta(property="og:image", content=image)
|
meta(property="og:image", content=image)
|
||||||
|
meta(property="og:image:alt", content=imageObj.description)
|
||||||
if video.len == 0:
|
if video.len == 0:
|
||||||
meta(property="twitter:image:src", content=image)
|
meta(property="twitter:image:src", content=image)
|
||||||
meta(property="twitter:card", content="summary_large_image")
|
meta(property="twitter:card", content="summary_large_image")
|
||||||
@ -172,7 +175,7 @@ proc renderHead*(prefs: Prefs; cfg: Config; req: Request; titleText=""; desc="";
|
|||||||
|
|
||||||
proc renderMain*(body: VNode; req: Request; cfg: Config; prefs=defaultPrefs;
|
proc renderMain*(body: VNode; req: Request; cfg: Config; prefs=defaultPrefs;
|
||||||
titleText=""; desc=""; ogTitle=""; rss=""; video="";
|
titleText=""; desc=""; ogTitle=""; rss=""; video="";
|
||||||
images: seq[string] = @[]; banner=""; avatar=""; context="";
|
images: seq[Image] = @[]; banner=""; avatar=""; context="";
|
||||||
contextUrl=""; id=""; time: Option[DateTime] = none(DateTime)
|
contextUrl=""; id=""; time: Option[DateTime] = none(DateTime)
|
||||||
): string =
|
): string =
|
||||||
|
|
||||||
|
|||||||
@ -38,10 +38,10 @@ proc getActivityStream*(tweet: Tweet, cfg: Config, prefs: Prefs): JsonNode =
|
|||||||
var media: seq[JsonNode] = @[]
|
var media: seq[JsonNode] = @[]
|
||||||
|
|
||||||
if tweet.photos.len > 0:
|
if tweet.photos.len > 0:
|
||||||
for url in tweet.photos:
|
for imageObj in tweet.photos:
|
||||||
let
|
let
|
||||||
image = getUrlPrefix(cfg) & getPicUrl(url)
|
image = getUrlPrefix(cfg) & getPicUrl(imageObj.url)
|
||||||
splitUrl = url.split('.')
|
splitUrl = imageObj.url.split('.')
|
||||||
var filetype = splitUrl[^1]
|
var filetype = splitUrl[^1]
|
||||||
if filetype == "jpg":
|
if filetype == "jpg":
|
||||||
filetype = "jpeg"
|
filetype = "jpeg"
|
||||||
@ -50,7 +50,7 @@ proc getActivityStream*(tweet: Tweet, cfg: Config, prefs: Prefs): JsonNode =
|
|||||||
mediaObj["type"] = %"Document"
|
mediaObj["type"] = %"Document"
|
||||||
mediaObj["mediaType"] = %("image/" & filetype)
|
mediaObj["mediaType"] = %("image/" & filetype)
|
||||||
mediaObj["url"] = %image
|
mediaObj["url"] = %image
|
||||||
mediaObj["name"] = newJNull() # FIXME a11y
|
mediaObj["name"] = %imageObj.description
|
||||||
|
|
||||||
media.add(mediaObj)
|
media.add(mediaObj)
|
||||||
|
|
||||||
|
|||||||
@ -89,9 +89,9 @@ proc genDate*(pref, state: string): VNode =
|
|||||||
input(name=pref, `type`="date", value=state)
|
input(name=pref, `type`="date", value=state)
|
||||||
icon "calendar"
|
icon "calendar"
|
||||||
|
|
||||||
proc genImg*(url: string; class=""): VNode =
|
proc genImg*(url: string; alt=""; class=""): VNode =
|
||||||
buildHtml():
|
buildHtml():
|
||||||
img(src=getPicUrl(url), class=class, alt="")
|
img(src=getPicUrl(url), class=class, alt=alt)
|
||||||
|
|
||||||
proc getTabClass*(query: Query; tab: QueryKind): string =
|
proc getTabClass*(query: Query; tab: QueryKind): string =
|
||||||
if query.kind == tab: "tab-item active"
|
if query.kind == tab: "tab-item active"
|
||||||
|
|||||||
@ -49,12 +49,15 @@ proc renderAlbum(tweet: Tweet): VNode =
|
|||||||
let margin = if i > 0: ".25em" else: ""
|
let margin = if i > 0: ".25em" else: ""
|
||||||
tdiv(class="gallery-row", style={marginTop: margin}):
|
tdiv(class="gallery-row", style={marginTop: margin}):
|
||||||
for photo in photos:
|
for photo in photos:
|
||||||
tdiv(class="attachment image"):
|
tdiv(class="attachment image", title=photo.description):
|
||||||
let
|
let
|
||||||
named = "name=" in photo
|
url = photo.url
|
||||||
small = if named: photo else: photo & smallWebp
|
named = "name=" in url
|
||||||
a(href=getOrigPicUrl(photo), class="still-image", target="_blank"):
|
small = if named: url else: url & smallWebp
|
||||||
genImg(small)
|
a(href=getOrigPicUrl(url), class="still-image", target="_blank", data-caption=photo.description):
|
||||||
|
genImg(small, alt=photo.description)
|
||||||
|
if photo.description.len > 0:
|
||||||
|
span(class="alt"): text "ALT"
|
||||||
|
|
||||||
proc isPlaybackEnabled(prefs: Prefs; playbackType: VideoType): bool =
|
proc isPlaybackEnabled(prefs: Prefs; playbackType: VideoType): bool =
|
||||||
case playbackType
|
case playbackType
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user