~cadence/cloudtube

f62fce4feaf84a8fb3c2625a64db97a382a9b887 — Cadence Ember 1 year, 10 months ago eb111a4
Highlight current chapter in video description
8 files changed, 86 insertions(+), 4 deletions(-)

M html/static/js/channel.js
A html/static/js/chapter-highlight.js
R html/static/js/{mark-watched.js => modules/MarkWatchedButton.js}
R html/static/js/{subscribe.js => modules/SubscribeButton.js}
M html/static/js/player.js
M html/static/js/subscriptions.js
M pug/video.pug
M sass/includes/video-page.sass
M html/static/js/channel.js => html/static/js/channel.js +1 -1
@@ 1,4 1,4 @@
import {q} from "/static/js/elemjs/elemjs.js"
import {SubscribeButton} from "/static/js/subscribe.js"
import {SubscribeButton} from "/static/js/modules/SubscribeButton.js"

new SubscribeButton(q("#subscribe"))

A html/static/js/chapter-highlight.js => html/static/js/chapter-highlight.js +53 -0
@@ 0,0 1,53 @@
import {q, qa, ElemJS} from "./elemjs/elemjs.js"

class Chapter {
	constructor(linkElement) {
		this.link = new ElemJS(linkElement)
		this.time = +linkElement.getAttribute("data-clickable-timestamp")
	}
}

let chapters = [...document.querySelectorAll("[data-clickable-timestamp]")].map(linkElement => new Chapter(linkElement))
chapters.sort((a, b) => a.time - b.time)

function getCurrentChapter(time) {
	const candidates = chapters.filter(chapter => chapter.time <= time)
	if (candidates.length > 0) {
		return candidates[candidates.length - 1]
	} else {
		return null
	}
}

const video = q("#video")
const description = q("#description")
const regularBackground = "var(--regular-background)"
const highlightBackground = "var(--highlight-background)"
const paddingWidth = 4
let lastChapter = null
setInterval(() => {
	const currentChapter = getCurrentChapter(video.currentTime)

	if (currentChapter !== lastChapter) {
		// Style link
		if (lastChapter) {
			lastChapter.link.removeClass("timestamp--active")
		}
		if (currentChapter) {
			currentChapter.link.class("timestamp--active")
		}
		// Style background
		if (currentChapter) {
			const {offsetTop, offsetHeight} = currentChapter.link.element;
			const offsetBottom = offsetTop + offsetHeight
			let gradient = `linear-gradient(to bottom,`
				+ ` ${regularBackground} ${offsetTop - paddingWidth}px, ${highlightBackground} ${offsetTop - paddingWidth}px,`
				+ ` ${highlightBackground} ${offsetBottom + paddingWidth}px, ${regularBackground} ${offsetBottom + paddingWidth}px)`
			console.log(gradient)
			description.style.background = gradient
		} else {
			description.style.background = ""
		}
	}
	lastChapter = currentChapter
}, 1000)

R html/static/js/mark-watched.js => html/static/js/modules/MarkWatchedButton.js +0 -0
R html/static/js/subscribe.js => html/static/js/modules/SubscribeButton.js +0 -0
M html/static/js/player.js => html/static/js/player.js +1 -1
@@ 1,5 1,5 @@
import {q, qa, ElemJS} from "/static/js/elemjs/elemjs.js"
import {SubscribeButton} from "/static/js/subscribe.js"
import {SubscribeButton} from "/static/js/modules/SubscribeButton.js"

const video = q("#video")
const audio = q("#audio")

M html/static/js/subscriptions.js => html/static/js/subscriptions.js +1 -1
@@ 1,5 1,5 @@
import {qa} from "/static/js/elemjs/elemjs.js"
import {MarkWatchedButton} from "/static/js/mark-watched.js"
import {MarkWatchedButton} from "/static/js/modules/MarkWatchedButton.js"

for (const button of qa(".mark-watched__button")) {
	new MarkWatchedButton(button)

M pug/video.pug => pug/video.pug +2 -1
@@ 9,6 9,7 @@ block head
  else
    title Error - CloudTube
  script(type="module" src=getStaticURL("html", "/static/js/player.js"))
  script(type="module" src=getStaticURL("html", "/static/js/chapter-highlight.js"))
  script const data = !{JSON.stringify({...video, continuous})}

block content


@@ 73,7 74,7 @@ block content
          a(href=`https://www.youtube.com/watch?v=${video.videoId}#cloudtube`).border-look YouTube
          a(href=`https://redirect.invidious.io/watch?v=${video.videoId}`).border-look Invidious

        .description!= video.descriptionHtml
        .description#description!= video.descriptionHtml

      //- Standard view
      aside(style=continuous ? "display: none" : "")#standard-related-videos.related-videos

M sass/includes/video-page.sass => sass/includes/video-page.sass +28 -0
@@ 93,13 93,18 @@
      flex-shrink: 0

  .description
    position: relative
    font-size: 17px
    line-height: 1.4
    word-break: break-word
    margin: 16px 4px 4px 4px
    background-color: c.$bg-accent-area
    padding: 12px
    border-radius: 4px

    --regular-background: #{c.$bg-accent-area}
    --highlight-background: #{c.$bg-darker}

.subscribe-form
  display: inline-block



@@ 149,3 154,26 @@

      .actor
        margin: 4px 0px 10px

// Chapter highlights

.timestamp--active
  margin: 4px 0px
  display: inline-block

  &::after
    display: block
    position: absolute
    left: 0
    right: 0
    height: calc(1.4em + 4px)
    transform: translateY(-1.4em) translateY(-4px)

    padding-right: 6px
    text-align: right
    content: "⮜"
    line-height: 1.6
    color: #fff

    border: solid black
    border-width: 2px 0px