Merge branch 'fork-graveyard/master'
This commit is contained in:
commit
2a5541c126
4 changed files with 41 additions and 12 deletions
|
@ -87,10 +87,15 @@ proc parseVideo(js: JsonNode): Video =
|
||||||
result.description = description.getStr
|
result.description = description.getStr
|
||||||
|
|
||||||
for v in js{"video_info", "variants"}:
|
for v in js{"video_info", "variants"}:
|
||||||
|
let
|
||||||
|
contentType = parseEnum[VideoType](v{"content_type"}.getStr("summary"))
|
||||||
|
url = v{"url"}.getStr
|
||||||
|
|
||||||
result.variants.add VideoVariant(
|
result.variants.add VideoVariant(
|
||||||
contentType: parseEnum[VideoType](v{"content_type"}.getStr("summary")),
|
contentType: contentType,
|
||||||
bitrate: v{"bitrate"}.getInt,
|
bitrate: v{"bitrate"}.getInt,
|
||||||
url: v{"url"}.getStr
|
url: url,
|
||||||
|
resolution: if contentType == mp4: getMp4Resolution(url) else: 0
|
||||||
)
|
)
|
||||||
|
|
||||||
proc parsePromoVideo(js: JsonNode): Video =
|
proc parsePromoVideo(js: JsonNode): Video =
|
||||||
|
|
|
@ -137,6 +137,21 @@ proc getSource*(js: JsonNode): string =
|
||||||
let src = js{"source"}.getStr
|
let src = js{"source"}.getStr
|
||||||
result = src.substr(src.find('>') + 1, src.rfind('<') - 1)
|
result = src.substr(src.find('>') + 1, src.rfind('<') - 1)
|
||||||
|
|
||||||
|
proc getMp4Resolution*(url: string): int =
|
||||||
|
# parses the height out of a URL like this one:
|
||||||
|
# https://video.twimg.com/ext_tw_video/<tweet-id>/pu/vid/720x1280/<random>.mp4
|
||||||
|
const vidSep = "/vid/"
|
||||||
|
let
|
||||||
|
vidIdx = url.find(vidSep) + vidSep.len
|
||||||
|
resIdx = url.find('x', vidIdx) + 1
|
||||||
|
res = url[resIdx ..< url.find("/", resIdx)]
|
||||||
|
|
||||||
|
try:
|
||||||
|
return parseInt(res)
|
||||||
|
except ValueError:
|
||||||
|
# cannot determine resolution (e.g. m3u8/non-mp4 video)
|
||||||
|
return 0
|
||||||
|
|
||||||
proc extractSlice(js: JsonNode): Slice[int] =
|
proc extractSlice(js: JsonNode): Slice[int] =
|
||||||
result = js["indices"][0].getInt ..< js["indices"][1].getInt
|
result = js["indices"][0].getInt ..< js["indices"][1].getInt
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ type
|
||||||
contentType*: VideoType
|
contentType*: VideoType
|
||||||
url*: string
|
url*: string
|
||||||
bitrate*: int
|
bitrate*: int
|
||||||
|
resolution*: int
|
||||||
|
|
||||||
Video* = object
|
Video* = object
|
||||||
durationMs*: int
|
durationMs*: int
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# SPDX-License-Identifier: AGPL-3.0-only
|
# SPDX-License-Identifier: AGPL-3.0-only
|
||||||
import strutils, sequtils, strformat, options
|
import strutils, sequtils, strformat, options, algorithm
|
||||||
import karax/[karaxdsl, vdom, vstyles]
|
import karax/[karaxdsl, vdom, vstyles]
|
||||||
from jester import Request
|
from jester import Request
|
||||||
|
|
||||||
|
@ -62,11 +62,14 @@ proc renderAlbum(tweet: Tweet): VNode =
|
||||||
a(href=getOrigPicUrl(orig), class="still-image", target="_blank"):
|
a(href=getOrigPicUrl(orig), class="still-image", target="_blank"):
|
||||||
genImg(small)
|
genImg(small)
|
||||||
|
|
||||||
proc isPlaybackEnabled(prefs: Prefs; video: Video): bool =
|
proc isPlaybackEnabled(prefs: Prefs; playbackType: VideoType): bool =
|
||||||
case video.playbackType
|
case playbackType
|
||||||
of mp4: prefs.mp4Playback
|
of mp4: prefs.mp4Playback
|
||||||
of m3u8, vmap: prefs.hlsPlayback
|
of m3u8, vmap: prefs.hlsPlayback
|
||||||
|
|
||||||
|
proc hasMp4Url(video: Video): bool =
|
||||||
|
video.variants.anyIt(it.contentType == mp4)
|
||||||
|
|
||||||
proc renderVideoDisabled(video: Video; path: string): VNode =
|
proc renderVideoDisabled(video: Video; path: string): VNode =
|
||||||
buildHtml(tdiv(class="video-overlay")):
|
buildHtml(tdiv(class="video-overlay")):
|
||||||
case video.playbackType
|
case video.playbackType
|
||||||
|
@ -84,9 +87,11 @@ proc renderVideoUnavailable(video: Video): VNode =
|
||||||
p: text "This media is unavailable"
|
p: text "This media is unavailable"
|
||||||
|
|
||||||
proc renderVideo*(video: Video; prefs: Prefs; path: string): VNode =
|
proc renderVideo*(video: Video; prefs: Prefs; path: string): VNode =
|
||||||
let container =
|
let
|
||||||
if video.description.len > 0 or video.title.len > 0: " card-container"
|
container = if video.description.len == 0 and video.title.len == 0: ""
|
||||||
else: ""
|
else: " card-container"
|
||||||
|
playbackType = if not prefs.proxyVideos and video.hasMp4Url: mp4
|
||||||
|
else: video.playbackType
|
||||||
|
|
||||||
buildHtml(tdiv(class="attachments card")):
|
buildHtml(tdiv(class="attachments card")):
|
||||||
tdiv(class="gallery-video" & container):
|
tdiv(class="gallery-video" & container):
|
||||||
|
@ -95,13 +100,16 @@ proc renderVideo*(video: Video; prefs: Prefs; path: string): VNode =
|
||||||
if not video.available:
|
if not video.available:
|
||||||
img(src=thumb)
|
img(src=thumb)
|
||||||
renderVideoUnavailable(video)
|
renderVideoUnavailable(video)
|
||||||
elif not prefs.isPlaybackEnabled(video):
|
elif not prefs.isPlaybackEnabled(playbackType):
|
||||||
img(src=thumb)
|
img(src=thumb)
|
||||||
renderVideoDisabled(video, path)
|
renderVideoDisabled(video, path)
|
||||||
else:
|
else:
|
||||||
let vid = video.variants.filterIt(it.contentType == video.playbackType)
|
let
|
||||||
let source = getVidUrl(vid[0].url)
|
vars = video.variants.filterIt(it.contentType == playbackType)
|
||||||
case video.playbackType
|
vidUrl = vars.sortedByIt(it.resolution)[^1].url
|
||||||
|
source = if prefs.proxyVideos: getVidUrl(vidUrl)
|
||||||
|
else: vidUrl
|
||||||
|
case playbackType
|
||||||
of mp4:
|
of mp4:
|
||||||
if prefs.muteVideos:
|
if prefs.muteVideos:
|
||||||
video(poster=thumb, controls="", muted=""):
|
video(poster=thumb, controls="", muted=""):
|
||||||
|
|
Loading…
Reference in a new issue