mirror of
https://git.sr.ht/~cadence/cloudtube
synced 2024-12-22 13:07:00 +00:00
Add subscriptions page
This commit is contained in:
parent
f24e1bb39c
commit
59a7489545
30
api/subscriptions.js
Normal file
30
api/subscriptions.js
Normal file
@ -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})
|
||||
}
|
||||
}
|
||||
]
|
@ -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 []
|
||||
}
|
||||
|
@ -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(/<a /g, '<a tabindex="-1" ')
|
||||
})
|
||||
return root
|
||||
})
|
||||
}
|
||||
|
||||
module.exports.fetchChannel = fetchChannel
|
||||
module.exports.fetchChannelLatest = fetchChannelLatest
|
||||
|
76
html/static/images/subscriptions.svg
Normal file
76
html/static/images/subscriptions.svg
Normal file
@ -0,0 +1,76 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="30"
|
||||
height="24.999874"
|
||||
viewBox="0 0 7.9374998 6.6145502"
|
||||
version="1.1"
|
||||
id="svg27"
|
||||
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
|
||||
sodipodi:docname="subscriptions.svg">
|
||||
<defs
|
||||
id="defs21" />
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#36393f"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1.0"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="22.627417"
|
||||
inkscape:cx="17.632604"
|
||||
inkscape:cy="10.153317"
|
||||
inkscape:document-units="px"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="true"
|
||||
units="px"
|
||||
inkscape:window-width="1440"
|
||||
inkscape:window-height="877"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:snap-bbox="true"
|
||||
inkscape:snap-bbox-edge-midpoints="false"
|
||||
inkscape:snap-text-baseline="false"
|
||||
inkscape:snap-center="false"
|
||||
inkscape:snap-global="false"
|
||||
inkscape:pagecheckerboard="false">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid828"
|
||||
originx="32.014582"
|
||||
originy="-164.3063" />
|
||||
</sodipodi:namedview>
|
||||
<metadata
|
||||
id="metadata24">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title />
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer"
|
||||
id="layer1"
|
||||
transform="translate(32.014583,-126.07915)">
|
||||
<path
|
||||
id="rect15"
|
||||
style="opacity:1;fill:#c4c4c4;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1.05833316;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:fill markers stroke"
|
||||
d="m -29.641547,126.07915 h 3.191429 c 0.288608,0 0.520954,0.23235 0.520954,0.52096 H -30.1625 c 0,-0.28861 0.232345,-0.52096 0.520953,-0.52096 z m -0.90981,0.79375 h 5.011047 c 0.37089,0 0.669473,0.29859 0.669476,0.66948 l 10e-7,0.12427 -6.35,-0.0163 v -0.10799 c 0,-0.37089 0.298586,-0.66948 0.669476,-0.66948 z m -0.404893,1.0583 c -0.586322,0 -1.058333,0.33169 -1.058333,0.91801 v 2.86801 c 0,0.58632 0.472011,0.97648 1.058333,0.97648 h 5.820834 c 0.586321,0 1.058333,-0.39016 1.058333,-0.97648 v -2.86801 c 0,-0.58632 -0.472012,-0.91801 -1.058333,-0.91801 z m 4.241825,2.16468 c 0.167331,0.0992 0.189069,0.27627 0.01203,0.3666 l -2.09776,0.9851 c -0.131847,0.0763 -0.304206,-0.002 -0.302769,-0.19054 v -1.88797 c 0,-0.20313 0.17976,-0.33275 0.340294,-0.24486 z"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ssccscssccsccsssssssssccccccc" />
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.1 KiB |
@ -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
|
||||
|
||||
|
@ -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
|
||||
|
12
pug/subscriptions.pug
Normal file
12
pug/subscriptions.pug
Normal file
@ -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)
|
9
sass/includes/subscriptions-page.sass
Normal file
9
sass/includes/subscriptions-page.sass
Normal file
@ -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
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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")
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user