Initial hls video playback support
This commit is contained in:
parent
bce76ab8d1
commit
f5fef0ff3a
6 changed files with 45 additions and 13 deletions
|
@ -297,7 +297,7 @@ video, .video-container img {
|
||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
background-color: #000000bd;
|
background-color: #0000008d;
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-overlay p {
|
.video-overlay p {
|
||||||
|
@ -309,6 +309,15 @@ video, .video-container img {
|
||||||
font-size: 20px;
|
font-size: 20px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.video-overlay div {
|
||||||
|
position: relative;
|
||||||
|
z-index: 0;
|
||||||
|
top: calc(50% - 20px);
|
||||||
|
margin: 0 auto;
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
.still-image {
|
.still-image {
|
||||||
max-height: 379.5px;
|
max-height: 379.5px;
|
||||||
max-width: 533px;
|
max-width: 533px;
|
||||||
|
|
2
public/js/hls.light.min.js
vendored
Normal file
2
public/js/hls.light.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
15
public/js/hlsPlayback.js
Normal file
15
public/js/hlsPlayback.js
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
function playVideo(overlay) {
|
||||||
|
const video = overlay.parentElement.querySelector('video');
|
||||||
|
video.setAttribute("controls", "");
|
||||||
|
overlay.style.display = "none";
|
||||||
|
|
||||||
|
const url = video.getAttribute("data-url");
|
||||||
|
var hls = new Hls({autoStartLoad: false});
|
||||||
|
hls.loadSource(url);
|
||||||
|
hls.attachMedia(video);
|
||||||
|
hls.on(Hls.Events.MANIFEST_PARSED, function () {
|
||||||
|
hls.loadLevel = hls.levels.length - 1;
|
||||||
|
hls.startLoad();
|
||||||
|
video.play();
|
||||||
|
});
|
||||||
|
}
|
|
@ -37,7 +37,7 @@ proc showSingleTimeline(name, after, agent: string; query: Option[Query];
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
let profileHtml = renderProfile(profile, timeline, await railFut, prefs)
|
let profileHtml = renderProfile(profile, timeline, await railFut, prefs)
|
||||||
return renderMain(profileHtml, cfg.title, pageTitle(profile), pageDesc(profile))
|
return renderMain(profileHtml, prefs, cfg.title, pageTitle(profile), pageDesc(profile))
|
||||||
|
|
||||||
proc showMultiTimeline(names: seq[string]; after, agent: string; query: Option[Query];
|
proc showMultiTimeline(names: seq[string]; after, agent: string; query: Option[Query];
|
||||||
prefs: Prefs): Future[string] {.async.} =
|
prefs: Prefs): Future[string] {.async.} =
|
||||||
|
@ -50,7 +50,7 @@ proc showMultiTimeline(names: seq[string]; after, agent: string; query: Option[Q
|
||||||
var timeline = renderMulti(await getTimelineSearch(get(q), after, agent),
|
var timeline = renderMulti(await getTimelineSearch(get(q), after, agent),
|
||||||
names.join(","), prefs)
|
names.join(","), prefs)
|
||||||
|
|
||||||
return renderMain(timeline, cfg.title, "Multi")
|
return renderMain(timeline, prefs, cfg.title, "Multi")
|
||||||
|
|
||||||
proc showTimeline(name, after: string; query: Option[Query];
|
proc showTimeline(name, after: string; query: Option[Query];
|
||||||
prefs: Prefs): Future[string] {.async.} =
|
prefs: Prefs): Future[string] {.async.} =
|
||||||
|
@ -79,7 +79,7 @@ settings:
|
||||||
|
|
||||||
routes:
|
routes:
|
||||||
get "/":
|
get "/":
|
||||||
resp renderMain(renderSearch(), cfg.title)
|
resp renderMain(renderSearch(), Prefs(), cfg.title)
|
||||||
|
|
||||||
post "/search":
|
post "/search":
|
||||||
if @"query".len == 0:
|
if @"query".len == 0:
|
||||||
|
@ -104,7 +104,8 @@ routes:
|
||||||
if refUri.path.len > 0 and "/settings" notin refUri.path: refUri.path
|
if refUri.path.len > 0 and "/settings" notin refUri.path: refUri.path
|
||||||
else: "/"
|
else: "/"
|
||||||
if refUri.query.len > 0: path &= &"?{refUri.query}"
|
if refUri.query.len > 0: path &= &"?{refUri.query}"
|
||||||
resp renderMain(renderPreferences(cookiePrefs(), path), cfg.title, "Preferences")
|
let prefs = cookiePrefs()
|
||||||
|
resp renderMain(renderPreferences(prefs, path), prefs, cfg.title, "Preferences")
|
||||||
|
|
||||||
get "/@name/?":
|
get "/@name/?":
|
||||||
cond '.' notin @"name"
|
cond '.' notin @"name"
|
||||||
|
@ -141,15 +142,15 @@ routes:
|
||||||
if conversation.tweet.video.isSome():
|
if conversation.tweet.video.isSome():
|
||||||
let thumb = get(conversation.tweet.video).thumb
|
let thumb = get(conversation.tweet.video).thumb
|
||||||
let vidUrl = getVideoEmbed(conversation.tweet.id)
|
let vidUrl = getVideoEmbed(conversation.tweet.id)
|
||||||
resp renderMain(html, cfg.title, title, desc, images = @[thumb],
|
resp renderMain(html, prefs, cfg.title, title, desc, images = @[thumb],
|
||||||
`type`="video", video=vidUrl)
|
`type`="video", video=vidUrl)
|
||||||
elif conversation.tweet.gif.isSome():
|
elif conversation.tweet.gif.isSome():
|
||||||
let thumb = get(conversation.tweet.gif).thumb
|
let thumb = get(conversation.tweet.gif).thumb
|
||||||
let vidUrl = getVideoEmbed(conversation.tweet.id)
|
let vidUrl = getVideoEmbed(conversation.tweet.id)
|
||||||
resp renderMain(html, cfg.title, title, desc, images = @[thumb],
|
resp renderMain(html, prefs, cfg.title, title, desc, images = @[thumb],
|
||||||
`type`="video", video=vidUrl)
|
`type`="video", video=vidUrl)
|
||||||
else:
|
else:
|
||||||
resp renderMain(html, cfg.title, title, desc, images=conversation.tweet.photos)
|
resp renderMain(html, prefs, cfg.title, title, desc, images=conversation.tweet.photos)
|
||||||
|
|
||||||
get "/pic/@sig/@url":
|
get "/pic/@sig/@url":
|
||||||
cond "http" in @"url"
|
cond "http" in @"url"
|
||||||
|
|
|
@ -17,13 +17,17 @@ proc renderNavbar*(title: string): VNode =
|
||||||
icon "info-circled", title="About", href="/about"
|
icon "info-circled", title="About", href="/about"
|
||||||
icon "cog-2", title="Preferences", href="/settings"
|
icon "cog-2", title="Preferences", href="/settings"
|
||||||
|
|
||||||
proc renderMain*(body: VNode; title="Nitter"; titleText=""; desc="";
|
proc renderMain*(body: VNode; prefs: Prefs; title="Nitter"; titleText=""; desc="";
|
||||||
`type`="article"; video=""; images: seq[string] = @[]): string =
|
`type`="article"; video=""; images: seq[string] = @[]): string =
|
||||||
let node = buildHtml(html(lang="en")):
|
let node = buildHtml(html(lang="en")):
|
||||||
head:
|
head:
|
||||||
link(rel="stylesheet", `type`="text/css", href="/css/style.css")
|
link(rel="stylesheet", `type`="text/css", href="/css/style.css")
|
||||||
link(rel="stylesheet", `type`="text/css", href="/css/fontello.css")
|
link(rel="stylesheet", `type`="text/css", href="/css/fontello.css")
|
||||||
|
|
||||||
|
if prefs.hlsPlayback:
|
||||||
|
script(src="/js/hls.light.min.js")
|
||||||
|
script(src="/js/hlsPlayback.js")
|
||||||
|
|
||||||
title:
|
title:
|
||||||
if titleText.len > 0:
|
if titleText.len > 0:
|
||||||
text titleText & " | " & title
|
text titleText & " | " & title
|
||||||
|
@ -63,4 +67,4 @@ proc renderError*(error: string): VNode =
|
||||||
span: text error
|
span: text error
|
||||||
|
|
||||||
proc showError*(error, title: string): string =
|
proc showError*(error, title: string): string =
|
||||||
renderMain(renderError(error), title, "Error")
|
renderMain(renderError(error), Prefs(), title, "Error")
|
||||||
|
|
|
@ -76,9 +76,10 @@ proc renderVideo(video: Video; prefs: Prefs): VNode =
|
||||||
video(poster=thumb, controls=""):
|
video(poster=thumb, controls=""):
|
||||||
source(src=source, `type`="video/mp4")
|
source(src=source, `type`="video/mp4")
|
||||||
of m3u8, vmap:
|
of m3u8, vmap:
|
||||||
video(poster=thumb)
|
video(poster=thumb, data-url=source, data-autoload="false")
|
||||||
tdiv(class="video-overlay"):
|
verbatim "<div class=\"video-overlay\" onclick=\"playVideo(this)\">"
|
||||||
p: text "Video playback not supported yet"
|
verbatim "<div class=\"card-overlay-circle\">"
|
||||||
|
verbatim "<span class=\"card-overlay-triangle\"</span></div></div>"
|
||||||
else:
|
else:
|
||||||
renderVideoDisabled(video)
|
renderVideoDisabled(video)
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue