mirror of https://github.com/FreeTubeApp/FreeTube
163 lines
4.6 KiB
JavaScript
163 lines
4.6 KiB
JavaScript
import store from '../store/index'
|
|
import { calculatePublishedDate } from './utils'
|
|
|
|
/**
|
|
* Filtering and sort based on user preferences
|
|
* @param {any[]} videos
|
|
*/
|
|
export function updateVideoListAfterProcessing(videos) {
|
|
let videoList = videos
|
|
|
|
if (store.getters.getHideLiveStreams) {
|
|
videoList = videoList.filter(item => {
|
|
return (!item.liveNow && !item.isUpcoming)
|
|
})
|
|
}
|
|
|
|
if (store.getters.getHideUpcomingPremieres) {
|
|
videoList = videoList.filter(item => {
|
|
if (item.isRSS) {
|
|
// viewCount is our only method of detecting premieres in RSS
|
|
// data without sending an additional request.
|
|
// If we ever get a better flag, use it here instead.
|
|
return item.viewCount !== '0'
|
|
}
|
|
// Observed for premieres in Local API Subscriptions.
|
|
return (item.premiereDate == null ||
|
|
// Invidious API
|
|
// `premiereTimestamp` only available on premiered videos
|
|
// https://docs.invidious.io/api/common_types/#videoobject
|
|
item.premiereTimestamp == null
|
|
)
|
|
})
|
|
}
|
|
|
|
if (store.getters.getHideWatchedSubs) {
|
|
const historyCacheById = store.getters.getHistoryCacheById
|
|
|
|
videoList = videoList.filter((video) => {
|
|
return !Object.hasOwn(historyCacheById, video.videoId)
|
|
})
|
|
}
|
|
|
|
// ordered last to show first eligible video from channel
|
|
// if the first one incidentally failed one of the above checks
|
|
if (store.getters.getOnlyShowLatestFromChannel) {
|
|
const authors = new Set()
|
|
videoList = videoList.filter((video) => {
|
|
if (!video.authorId) {
|
|
return true
|
|
} else if (!authors.has(video.authorId)) {
|
|
authors.add(video.authorId)
|
|
return true
|
|
}
|
|
|
|
return false
|
|
})
|
|
}
|
|
|
|
videoList.sort((a, b) => {
|
|
return b.publishedDate - a.publishedDate
|
|
})
|
|
|
|
return videoList
|
|
}
|
|
|
|
/**
|
|
* @param {string} rssString
|
|
* @param {string} channelId
|
|
*/
|
|
export async function parseYouTubeRSSFeed(rssString, channelId) {
|
|
// doesn't need to be asynchronous, but doing it allows us to do the relatively slow DOM querying in parallel
|
|
try {
|
|
const xmlDom = new DOMParser().parseFromString(rssString, 'application/xml')
|
|
const channelName = xmlDom.querySelector('author > name').textContent
|
|
const entries = xmlDom.querySelectorAll('entry')
|
|
|
|
const promises = []
|
|
|
|
for (const entry of entries) {
|
|
promises.push(parseRSSEntry(entry, channelId, channelName))
|
|
}
|
|
|
|
return {
|
|
name: channelName,
|
|
videos: await Promise.all(promises)
|
|
}
|
|
} catch (e) {
|
|
return {
|
|
videos: []
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {Element} entry
|
|
* @param {string} channelId
|
|
* @param {string} channelName
|
|
*/
|
|
async function parseRSSEntry(entry, channelId, channelName) {
|
|
// doesn't need to be asynchronous, but doing it allows us to do the relatively slow DOM querying in parallel
|
|
const published = new Date(entry.querySelector('published').textContent)
|
|
|
|
return {
|
|
authorId: channelId,
|
|
author: channelName,
|
|
// querySelector doesn't support xml namespaces so we have to use getElementsByTagName here
|
|
videoId: entry.getElementsByTagName('yt:videoId')[0].textContent,
|
|
title: entry.querySelector('title').textContent,
|
|
publishedDate: published,
|
|
publishedText: published.toLocaleString(),
|
|
viewCount: entry.getElementsByTagName('media:statistics')[0]?.getAttribute('views') || null,
|
|
type: 'video',
|
|
lengthSeconds: '0:00',
|
|
isRSS: true
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @param {{
|
|
* liveNow: boolean,
|
|
* isUpcoming: boolean,
|
|
* premiereDate: Date,
|
|
* publishedText: string,
|
|
* publishedDate: number
|
|
* }[]} videos publishedDate is added by this function,
|
|
* but adding it to the type definition stops vscode warning that the property doesn't exist
|
|
*/
|
|
export function addPublishedDatesLocal(videos) {
|
|
videos.forEach(video => {
|
|
if (video.liveNow) {
|
|
video.publishedDate = new Date().getTime()
|
|
} else if (video.isUpcoming) {
|
|
video.publishedDate = video.premiereDate
|
|
} else {
|
|
video.publishedDate = calculatePublishedDate(video.publishedText)
|
|
}
|
|
return video
|
|
})
|
|
}
|
|
|
|
/**
|
|
* @param {{
|
|
* liveNow: boolean,
|
|
* isUpcoming: boolean,
|
|
* premiereTimestamp: number,
|
|
* published: number,
|
|
* publishedDate: number
|
|
* }[]} videos publishedDate is added by this function,
|
|
* but adding it to the type definition stops vscode warning that the property doesn't exist
|
|
*/
|
|
export function addPublishedDatesInvidious(videos) {
|
|
videos.forEach(video => {
|
|
if (video.liveNow) {
|
|
video.publishedDate = new Date().getTime()
|
|
} else if (video.isUpcoming) {
|
|
video.publishedDate = new Date(video.premiereTimestamp * 1000)
|
|
} else {
|
|
video.publishedDate = new Date(video.published * 1000)
|
|
}
|
|
return video
|
|
})
|
|
}
|