From 59a7489545f620973c10b12e279b1ebcae4d3ff9 Mon Sep 17 00:00:00 2001 From: Cadence Ember Date: Mon, 31 Aug 2020 03:14:05 +1200 Subject: [PATCH] Add subscriptions page --- api/subscriptions.js | 30 +++++++++++ api/utils/getuser.js | 3 +- api/utils/youtube.js | 10 ++++ html/static/images/subscriptions.svg | 76 +++++++++++++++++++++++++++ pug/includes/layout.pug | 2 + pug/includes/video-list-item.pug | 8 +-- pug/subscriptions.pug | 12 +++++ sass/includes/subscriptions-page.sass | 9 ++++ sass/includes/video-list-item.sass | 4 ++ sass/main.sass | 9 +++- server.js | 2 + 11 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 api/subscriptions.js create mode 100644 html/static/images/subscriptions.svg create mode 100644 pug/subscriptions.pug create mode 100644 sass/includes/subscriptions-page.sass diff --git a/api/subscriptions.js b/api/subscriptions.js new file mode 100644 index 0000000..c755f89 --- /dev/null +++ b/api/subscriptions.js @@ -0,0 +1,30 @@ +const {render} = require("pinski/plugins") +const db = require("./utils/db") +const {fetchChannelLatest} = require("./utils/youtube") +const {getUser} = require("./utils/getuser") + +module.exports = [ + { + route: `/subscriptions`, methods: ["GET"], code: async ({req}) => { + const user = getUser(req) + let hasSubscriptions = false + let videos = [] + let channels = [] + if (user.token) { + const subscriptions = user.getSubscriptions() + const channelPrepared = db.prepare("SELECT * FROM Channels WHERE ucid = ?") + channels = subscriptions.map(id => channelPrepared.get(id)).sort((a, b) => { + if (a.name < b.name) return -1 + else if (b.name > a.name) return 1 + else return 0 + }) + if (subscriptions.length) { + hasSubscriptions = true + const all = await Promise.all(subscriptions.map(id => fetchChannelLatest(id))) + videos = all.flat(1).sort((a, b) => b.published - a.published).slice(0, 60) + } + } + return render(200, "pug/subscriptions.pug", {hasSubscriptions, videos, channels}) + } + } +] diff --git a/api/utils/getuser.js b/api/utils/getuser.js index 12e7141..e4476aa 100644 --- a/api/utils/getuser.js +++ b/api/utils/getuser.js @@ -1,6 +1,5 @@ const crypto = require("crypto") const {parse: parseCookie} = require("cookie") - const constants = require("./constants") const db = require("./db") @@ -26,7 +25,7 @@ class User { getSubscriptions() { if (this.token) { - return db.prepare("SELECT ucid FROM Subscriptions WHERE token = ?").pluck().all(ucid) + return db.prepare("SELECT ucid FROM Subscriptions WHERE token = ?").pluck().all(this.token) } else { return [] } diff --git a/api/utils/youtube.js b/api/utils/youtube.js index 85832d6..7a568a3 100644 --- a/api/utils/youtube.js +++ b/api/utils/youtube.js @@ -12,4 +12,14 @@ async function fetchChannel(ucid) { return channel } +function fetchChannelLatest(ucid) { + return fetch(`http://localhost:3000/api/v1/channels/${ucid}/latest`).then(res => res.json()).then(root => { + root.forEach(video => { + video.descriptionHtml = video.descriptionHtml.replace(/ + + + + + + + + + + + image/svg+xml + + + + + + + + + diff --git a/pug/includes/layout.pug b/pug/includes/layout.pug index d8d40fb..19d13a8 100644 --- a/pug/includes/layout.pug +++ b/pug/includes/layout.pug @@ -10,6 +10,8 @@ html body.show-focus nav.main-nav a(href="/").link.home CloudTube + a(href="/subscriptions" title="Subscriptions").link.subscriptions-link + img(src=getStaticURL("html", "/static/images/subscriptions.svg") width=30 height=25 alt="Subscriptions.").subscriptions-icon form(method="get" action="/search").search-form input(type="text" placeholder="Search" name="q" autocomplete="off" value=query).search diff --git a/pug/includes/video-list-item.pug b/pug/includes/video-list-item.pug index f919863..3ca9b09 100644 --- a/pug/includes/video-list-item.pug +++ b/pug/includes/video-list-item.pug @@ -1,14 +1,16 @@ mixin video_list_item(video) - let link = `/watch?v=${video.videoId}` - a(href=link).thumbnail + a(href=link tabindex="-1").thumbnail img(src=`https://i.ytimg.com/vi/${video.videoId}/mqdefault.jpg` width=320 height=180 alt="").image span.duration= video.second__lengthText .info div.title: a(href=link).title-link= video.title div.author-line a(href=`/channel/${video.authorId}`).author= video.author - = ` • ` - span.views= video.viewCountText || video.second__viewCountText + - const views = video.viewCountText || video.second__viewCountText + if views + = ` • ` + span.views= views if video.publishedText = ` • ` span.published= video.publishedText diff --git a/pug/subscriptions.pug b/pug/subscriptions.pug new file mode 100644 index 0000000..213a15e --- /dev/null +++ b/pug/subscriptions.pug @@ -0,0 +1,12 @@ +extends includes/layout.pug + +include includes/video-list-item.pug + +block head + title Subscriptions - CloudTube + +block content + main.subscriptions-page + each video in videos + .subscriptions-video + +video_list_item(video) diff --git a/sass/includes/subscriptions-page.sass b/sass/includes/subscriptions-page.sass new file mode 100644 index 0000000..13b5c8d --- /dev/null +++ b/sass/includes/subscriptions-page.sass @@ -0,0 +1,9 @@ +@use "video-list-item.sass" as * + +.subscriptions-page + padding: 40px 20px 20px + max-width: 900px + margin: 0 auto + +.subscriptions-video + @include subscriptions-video diff --git a/sass/includes/video-list-item.sass b/sass/includes/video-list-item.sass index 810237d..9650dfc 100644 --- a/sass/includes/video-list-item.sass +++ b/sass/includes/video-list-item.sass @@ -59,6 +59,7 @@ grid-template-columns: 240px 1fr margin-bottom: 20px overflow: hidden + max-height: 150px .image width: 240px @@ -94,3 +95,6 @@ @mixin channel-video @include large-item + +@mixin subscriptions-video + @include large-item diff --git a/sass/main.sass b/sass/main.sass index 4f22f46..1b0cf36 100644 --- a/sass/main.sass +++ b/sass/main.sass @@ -5,10 +5,11 @@ @use "includes/search-page.sass" @use "includes/home-page.sass" @use "includes/channel-page.sass" +@use "includes/subscriptions-page.sass" @font-face font-family: "Bariol" - src: url(/static/fonts/bariol.woff) + src: url(/static/fonts/bariol.woff?statichash=1) @mixin button-base appearance: none @@ -74,6 +75,8 @@ text-decoration: none margin: 1px 8px 1px 0px font-size: 20px + display: flex + align-items: center &.home font-weight: bold @@ -98,3 +101,7 @@ &:hover, &:focus border: 1px solid c.$edge-grey margin: 0px + +.subscriptions-link:hover, .subscriptions-link:focus + .subscriptions-icon + filter: brightness(2) diff --git a/server.js b/server.js index 7e1f60c..9721bd1 100644 --- a/server.js +++ b/server.js @@ -20,6 +20,8 @@ const {setInstance} = require("pinski/plugins") server.addStaticHashTableDir("html/static/js") server.addStaticHashTableDir("html/static/js/elemjs") + server.addStaticHashTableDir("html/static/images") + server.addStaticHashTableDir("html/static/fonts") server.addAPIDir("api")