backend/controller/video.js

200 lines
5.9 KiB
JavaScript

const { PrismaClient } = require('@prisma/client')
const prisma = new PrismaClient()
const DOMPurify = require('isomorphic-dompurify')
const rtm = require('readable-to-ms')
const metadata = require('../utils/metadata.js')
const redis = require('../utils/redis.js')
exports.getVideo = async (req, res) => {
let info
const cached = await redis.get(`video:${req.params.id}`)
if (cached) {
info = JSON.parse(cached)
} else {
info = await prisma.videos.findFirst({
where: {
id: req.params.id
},
select: {
title: true,
description: true,
thumbnail: true,
source: true,
published: true,
archived: true,
channel: true,
channelId: true,
channelAvatar: true,
channelVerified: true,
disabled: true,
hasBeenReported: true
}
})
if (!info) return res.json({ error: '404' })
await redis.set(`video:${req.params.id}`, JSON.stringify(info), 'EX', 3600)
}
res.json({
...info,
description: DOMPurify.sanitize(info.description),
})
}
exports.getChannel = async (req, res) => {
const cached = await redis.get(`channel:${req.params.id}`)
if (cached) return res.json(JSON.parse(cached))
const [videos, channel] = await Promise.all([
metadata.getChannelVideos(req.params.id),
metadata.getChannel(req.params.id)
])
if (!videos || !channel || videos.error || channel.error) {
return res.json({ error: '404' });
}
const archived = await prisma.videos.findMany({
where: {
channelId: req.params.id
},
select: {
id: true,
title: true,
thumbnail: true,
published: true,
archived: true
}
})
const processedVideos = videos.map(video => {
const date = !isNaN(new Date(video.published.text).getTime()) ? new Date(video.published.text) : new Date((new Date()).getTime() - rtm(video.published.text).ms); // life is great.
return {
id: video.id,
title: video.title.text,
thumbnail: video.thumbnails[0].url,
published: new Date(date).toISOString().slice(0, 10)
}
});
archived.forEach(v => {
const existingVideoIndex = processedVideos.findIndex(video => video.id === v.id);
if (existingVideoIndex !== -1) {
processedVideos[existingVideoIndex] = v;
} else {
processedVideos.push({ ...v, deleted: undefined });
}
});
processedVideos.sort((a, b) => new Date(b.published) - new Date(a.published));
const json = {
name: channel.metadata.title,
avatar: channel.metadata.avatar[0].url,
verified: channel.header.author.is_verified,
videos: processedVideos
}
await redis.set(`channel:${req.params.id}`, JSON.stringify(json), 'EX', 3600)
res.json(json)
}
exports.getOnlyChannelVideos = async (req, res) => {
const cached = await redis.get(`channelVideos:${req.params.id}`)
if (cached) return res.json(JSON.parse(cached))
const archived = await prisma.videos.findMany({
where: {
channelId: req.params.id
},
select: {
id: true,
title: true,
thumbnail: true,
published: true,
archived: true
},
orderBy: {
published: 'desc'
}
})
const json = {
videos: archived
}
await redis.set(`channelVideos:${req.params.id}`, JSON.stringify(json), 'EX', 3600)
res.json(json)
}
exports.getPlaylist = async (req, res) => {
const cached = await redis.get(`playlist:${req.params.id}`)
if (cached) return res.json(JSON.parse(cached))
const playlist = await metadata.getPlaylistVideos(req.params.id)
if (!playlist || playlist.error) return res.json({ error: '404' })
const playlistArchived = await prisma.videos.findMany({
where: {
playlist: req.params.id
},
select: {
id: true,
title: true,
thumbnail: true,
published: true,
archived: true
}
})
const allVideos = playlist.relatedStreams.map(video => ({
id: video.url.replace('/watch?v=', ''),
published: new Date(video.uploaded).toISOString().slice(0, 10),
...video
}));
await Promise.all(playlistArchived.map(async (v) => {
const allVideo = allVideos.find(o => o.id == v.id);
if (allVideo) {
const index = allVideos.findIndex(o => o.id == v.id);
allVideos[index] = v;
} else {
const live = await metadata.getVideoMetadata(v.id);
allVideos.push({
...v,
deleted: live.error ? true : false
});
}
}));
await Promise.all(allVideos.filter(v => !v.archived).map(async (v) => {
const video = await prisma.videos.findFirst({
where: {
id: v.id
},
select: {
id: true,
title: true,
thumbnail: true,
published: true,
archived: true
}
});
if (video) {
const index = allVideos.findIndex(o => o.id == v.id);
allVideos[index] = video;
}
}));
allVideos.sort((a, b) => new Date(b.published) - new Date(a.published));
const json = {
name: playlist.name,
channel: playlist.uploader,
url: playlist.uploaderUrl,
avatar: playlist.uploaderAvatar,
videos: allVideos
}
await redis.set(`playlist:${req.params.id}`, JSON.stringify(json), 'EX', 3600)
res.json(json)
}