diff --git a/src/parser.nim b/src/parser.nim index 1a7c073..fc8dc3b 100644 --- a/src/parser.nim +++ b/src/parser.nim @@ -87,10 +87,15 @@ proc parseVideo(js: JsonNode): Video = result.description = description.getStr for v in js{"video_info", "variants"}: + let + contentType = parseEnum[VideoType](v{"content_type"}.getStr("summary")) + url = v{"url"}.getStr + resolution = getMp4Resolution(url) # only available if contentType == mp4 result.variants.add VideoVariant( - contentType: parseEnum[VideoType](v{"content_type"}.getStr("summary")), + contentType: contentType, bitrate: v{"bitrate"}.getInt, - url: v{"url"}.getStr + url: url, + resolution: resolution ) proc parsePromoVideo(js: JsonNode): Video = diff --git a/src/parserutils.nim b/src/parserutils.nim index 4929c2a..51ccea5 100644 --- a/src/parserutils.nim +++ b/src/parserutils.nim @@ -137,6 +137,21 @@ proc getSource*(js: JsonNode): string = let src = js{"source"}.getStr 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//pu/vid/720x1280/.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] = result = js["indices"][0].getInt ..< js["indices"][1].getInt diff --git a/src/types.nim b/src/types.nim index 98433aa..061ec8a 100644 --- a/src/types.nim +++ b/src/types.nim @@ -75,6 +75,7 @@ type contentType*: VideoType url*: string bitrate*: int + resolution*: int Video* = object durationMs*: int diff --git a/src/views/tweet.nim b/src/views/tweet.nim index 73548a1..d07ca06 100644 --- a/src/views/tweet.nim +++ b/src/views/tweet.nim @@ -1,5 +1,5 @@ # SPDX-License-Identifier: AGPL-3.0-only -import strutils, sequtils, strformat, options +import strutils, sequtils, strformat, options, algorithm import karax/[karaxdsl, vdom, vstyles] from jester import Request @@ -105,8 +105,11 @@ proc renderVideo*(video: Video; prefs: Prefs; path: string): VNode = img(src=thumb) renderVideoDisabled(video, path) else: - let vid = video.variants.filterIt(it.contentType == playbackType) - let source = if prefs.proxyVideos: getVidUrl(vid[0].url) else: vid[0].url + let + vars = video.variants.filterIt(it.contentType == playbackType) + vidUrl = vars.sortedByIt(it.resolution)[^1].url + source = if prefs.proxyVideos: getVidUrl(vidUrl) + else: vidUrl case playbackType of mp4: if prefs.muteVideos: