feat: host tv + movies
This commit is contained in:
parent
9b1528dda1
commit
f0041e0525
23 changed files with 1282 additions and 166 deletions
|
@ -5,27 +5,49 @@ const SUPABASE_URL = process.env.SUPABASE_URL
|
|||
const SUPABASE_KEY = process.env.SUPABASE_KEY
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
|
||||
|
||||
const PAGE_SIZE = 1000
|
||||
|
||||
const fetchAllMovies = async () => {
|
||||
let movies = []
|
||||
let rangeStart = 0
|
||||
|
||||
while (true) {
|
||||
const { data, error } = await supabase
|
||||
.from('movies')
|
||||
.select(`
|
||||
tmdb_id,
|
||||
slug,
|
||||
last_watched,
|
||||
title,
|
||||
year,
|
||||
collected,
|
||||
plays,
|
||||
favorite
|
||||
`)
|
||||
.order('last_watched', { ascending: false })
|
||||
.range(rangeStart, rangeStart + PAGE_SIZE - 1)
|
||||
|
||||
if (error) {
|
||||
console.error(error)
|
||||
break
|
||||
}
|
||||
|
||||
movies = movies.concat(data)
|
||||
|
||||
if (data.length < PAGE_SIZE) break
|
||||
rangeStart += PAGE_SIZE
|
||||
}
|
||||
|
||||
return movies
|
||||
}
|
||||
|
||||
export default async function () {
|
||||
const { data: movies, error } = await supabase
|
||||
.from('movies')
|
||||
.select(`
|
||||
tmdb_id,
|
||||
slug,
|
||||
last_watched,
|
||||
title,
|
||||
year,
|
||||
collected,
|
||||
plays,
|
||||
favorite
|
||||
`)
|
||||
.order('last_watched', { ascending: false })
|
||||
|
||||
if (error) return []
|
||||
|
||||
const formatMovieData = (movies) => movies.map((item) => {
|
||||
const movies = await fetchAllMovies()
|
||||
const formatMovieData = (movies, watched = true) => movies.map((item) => {
|
||||
const movie = {
|
||||
title: item['title'],
|
||||
dateAdded: item['last_watched'],
|
||||
lastWatched: item['last_watched'],
|
||||
year: item['year'],
|
||||
url: `https://www.themoviedb.org/movie/${item['tmdb_id']}`,
|
||||
description: `<p>${item['title']} (${item['year']})</p><p>Watched at: ${DateTime.fromISO(item['last_watched'], { zone: 'utc' }).setZone('America/Los_Angeles').toFormat('MMMM d, yyyy, h:mma')}</p>`,
|
||||
type: 'movie',
|
||||
|
@ -35,17 +57,18 @@ export default async function () {
|
|||
collected: item['collected'],
|
||||
favorite: item['favorite'],
|
||||
}
|
||||
return movie;
|
||||
})
|
||||
|
||||
return movie
|
||||
}).filter(movie => watched ? movie['lastWatched'] : !movie['lastWatched'])
|
||||
const favoriteMovies = movies.filter(movie => movie['favorite'])
|
||||
const collectedMovies = movies.filter(movie => movie['collected'])
|
||||
const recentlyWatchedMovies = movies.filter(movie => movie['last_watched']).sort((a, b) => new Date(b['last_watched']) - new Date(a['last_watched'])).slice(0, 6)
|
||||
|
||||
return {
|
||||
movies,
|
||||
watchHistory: formatMovieData(movies),
|
||||
recentlyWatched: formatMovieData(movies.slice(0, 6)),
|
||||
favorites: formatMovieData(favoriteMovies),
|
||||
recentlyWatched: formatMovieData(recentlyWatchedMovies),
|
||||
favorites: formatMovieData(favoriteMovies).sort((a, b) => a['title'].localeCompare(b['title'])),
|
||||
collection: formatMovieData(collectedMovies),
|
||||
toWatch: formatMovieData(movies, false).sort((a, b) => a['title'].localeCompare(b['title'])),
|
||||
}
|
||||
}
|
|
@ -32,6 +32,32 @@ const fetchDataForPeriod = async (startPeriod, fields, table) => {
|
|||
return rows
|
||||
}
|
||||
|
||||
const fetchAllTimeData = async (fields, table) => {
|
||||
const PAGE_SIZE = 1000
|
||||
let rows = []
|
||||
let rangeStart = 0
|
||||
|
||||
while (true) {
|
||||
const { data, error } = await supabase
|
||||
.from(table)
|
||||
.select(fields)
|
||||
.order('listened_at', { ascending: false })
|
||||
.range(rangeStart, rangeStart + PAGE_SIZE - 1)
|
||||
|
||||
if (error) {
|
||||
console.error(error)
|
||||
break
|
||||
}
|
||||
|
||||
rows = rows.concat(data)
|
||||
|
||||
if (data.length < PAGE_SIZE) break
|
||||
rangeStart += PAGE_SIZE
|
||||
}
|
||||
|
||||
return rows
|
||||
}
|
||||
|
||||
const aggregateData = (data, groupByField, groupByType, sort = true) => {
|
||||
const aggregation = {}
|
||||
data.forEach(item => {
|
||||
|
@ -65,16 +91,14 @@ const aggregateData = (data, groupByField, groupByType, sort = true) => {
|
|||
aggregation[key].plays++
|
||||
})
|
||||
const aggregatedData = sort ? Object.values(aggregation).sort((a, b) => b.plays - a.plays) : Object.values(aggregation)
|
||||
return aggregatedData
|
||||
return aggregatedData.filter(item => item.plays > 0)
|
||||
}
|
||||
|
||||
|
||||
export default async function() {
|
||||
const periods = {
|
||||
week: DateTime.now().minus({ days: 7 }).startOf('day'), // Last week
|
||||
month: DateTime.now().minus({ days: 30 }).startOf('day'), // Last 30 days
|
||||
threeMonth: DateTime.now().minus({ months: 3 }).startOf('day'), // Last three months
|
||||
year: DateTime.now().minus({ years: 1 }).startOf('day'), // Last 365 days
|
||||
week: DateTime.now().minus({ days: 7 }).startOf('day'), // last week
|
||||
month: DateTime.now().minus({ days: 30 }).startOf('day'), // last 30 days
|
||||
threeMonth: DateTime.now().minus({ months: 3 }).startOf('day'), // last three months
|
||||
}
|
||||
|
||||
const results = {}
|
||||
|
@ -97,15 +121,23 @@ export default async function() {
|
|||
}
|
||||
}
|
||||
|
||||
// Fetch and aggregate all-time data
|
||||
const allTimeData = await fetchAllTimeData(selectFields, 'listens')
|
||||
results['allTime'] = {
|
||||
artists: aggregateData(allTimeData, 'artist_name', 'artists'),
|
||||
albums: aggregateData(allTimeData, 'album_name', 'albums'),
|
||||
tracks: aggregateData(allTimeData, 'track_name', 'track')
|
||||
}
|
||||
|
||||
const recentData = await fetchDataForPeriod(DateTime.now().minus({ days: 7 }), selectFields, 'listens')
|
||||
|
||||
results.recent = {
|
||||
results['recent'] = {
|
||||
artists: aggregateData(recentData, 'artist_name', 'artists'),
|
||||
albums: aggregateData(recentData, 'album_name', 'albums'),
|
||||
tracks: aggregateData(recentData, 'track_name', 'track'),
|
||||
tracksChronological: aggregateData(recentData, 'track_name', 'track', false),
|
||||
}
|
||||
results.nowPlaying = results.recent.tracksChronological[0]
|
||||
results['nowPlaying'] = results['recent']['tracksChronological'][0]
|
||||
|
||||
return results
|
||||
}
|
|
@ -21,7 +21,7 @@ export default async function () {
|
|||
{ name: 'npm', url: 'https://www.npmjs.com/~cdransf', icon: 'brand-npm'},
|
||||
{ name: 'Mastodon', url: 'https://social.lol/@cory', icon: 'brand-mastodon' },
|
||||
{ name: 'ListenBrainz', url: 'https://listenbrainz.org/user/cdransf/', icon: 'brain' },
|
||||
{ name: 'Trakt', url: 'https://trakt.tv/users/cdransf', icon: 'device-tv' },
|
||||
{ name: 'Watching', url: '/watching', icon: 'device-tv' },
|
||||
{ name: 'Instapaper', url: 'https://www.instapaper.com/p/coryd', icon: 'news' },
|
||||
{ name: 'Books', url: '/books', icon: 'books' },
|
||||
{ name: 'Webrings', url: '/webrings', icon: 'heart-handshake' },
|
||||
|
|
|
@ -4,22 +4,45 @@ const SUPABASE_URL = process.env.SUPABASE_URL
|
|||
const SUPABASE_KEY = process.env.SUPABASE_KEY
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
|
||||
|
||||
export default async function () {
|
||||
const { data: shows, error } = await supabase
|
||||
.from('shows')
|
||||
.select(`
|
||||
title,
|
||||
tmdb_id,
|
||||
collected,
|
||||
favorite,
|
||||
episodes (
|
||||
episode_number,
|
||||
season_number,
|
||||
last_watched_at
|
||||
)
|
||||
`)
|
||||
const PAGE_SIZE = 1000
|
||||
|
||||
if (error) return []
|
||||
const fetchAllShows = async () => {
|
||||
let shows = []
|
||||
let rangeStart = 0
|
||||
|
||||
while (true) {
|
||||
const { data, error } = await supabase
|
||||
.from('shows')
|
||||
.select(`
|
||||
title,
|
||||
tmdb_id,
|
||||
collected,
|
||||
favorite,
|
||||
year,
|
||||
episodes (
|
||||
episode_number,
|
||||
season_number,
|
||||
last_watched_at
|
||||
)
|
||||
`)
|
||||
.range(rangeStart, rangeStart + PAGE_SIZE - 1)
|
||||
|
||||
if (error) {
|
||||
console.error(error)
|
||||
break
|
||||
}
|
||||
|
||||
shows = shows.concat(data)
|
||||
|
||||
if (data.length < PAGE_SIZE) break
|
||||
rangeStart += PAGE_SIZE
|
||||
}
|
||||
|
||||
return shows
|
||||
}
|
||||
|
||||
export default async function () {
|
||||
const shows = await fetchAllShows()
|
||||
|
||||
let episodes = []
|
||||
shows.forEach(show => {
|
||||
|
@ -29,14 +52,15 @@ export default async function () {
|
|||
show_title: show['title'],
|
||||
show_tmdb_id: show['tmdb_id'],
|
||||
collected: show['collected'],
|
||||
favorite: show['favorite']
|
||||
favorite: show['favorite'],
|
||||
year: show['year']
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
episodes.sort((a, b) => new Date(b['last_watched_at']) - new Date(a['last_watched_at']))
|
||||
const allEpisodes = episodes
|
||||
episodes = episodes.slice(0, 75)
|
||||
const recentlyWatchedEpisodes = episodes.slice(0, 75)
|
||||
|
||||
const formatEpisodeData = (episodes) => {
|
||||
const episodeData = []
|
||||
|
@ -55,8 +79,9 @@ export default async function () {
|
|||
showEpisodesMap[showTmdbId] = {
|
||||
title: showTitle,
|
||||
tmdbId: showTmdbId,
|
||||
collected: collected,
|
||||
favorite: favorite,
|
||||
collected,
|
||||
favorite,
|
||||
lastWatchedAt,
|
||||
episodes: []
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +96,7 @@ export default async function () {
|
|||
type: 'tv',
|
||||
image: `https://coryd.dev/media/shows/poster-${showTmdbId}.jpg`,
|
||||
backdrop: `https://coryd.dev/media/shows/backdrops/backdrop-${showTmdbId}.jpg`,
|
||||
lastWatchedAt: lastWatchedAt
|
||||
lastWatchedAt
|
||||
})
|
||||
})
|
||||
|
||||
|
@ -101,8 +126,8 @@ export default async function () {
|
|||
})
|
||||
} else {
|
||||
const singleEpisode = show['episodes'][0]
|
||||
singleEpisode.collected = show['collected']
|
||||
singleEpisode.favorite = show['favorite']
|
||||
singleEpisode['collected'] = show['collected']
|
||||
singleEpisode['favorite'] = show['favorite']
|
||||
episodeData.push(singleEpisode)
|
||||
}
|
||||
})
|
||||
|
@ -112,24 +137,26 @@ export default async function () {
|
|||
|
||||
const favoriteShows = shows.filter(show => show['favorite'])
|
||||
const collectedShows = shows.filter(show => show['collected'])
|
||||
const toWatch = shows.filter(show => !show.episodes.some(episode => episode.last_watched_at)).sort((a, b) => a['title'].localeCompare(b['title']))
|
||||
|
||||
return {
|
||||
shows,
|
||||
watchHistory: formatEpisodeData(allEpisodes),
|
||||
recentlyWatched: formatEpisodeData(episodes),
|
||||
recentlyWatched: formatEpisodeData(recentlyWatchedEpisodes),
|
||||
favorites: formatEpisodeData(favoriteShows.flatMap(show => show['episodes'].map(episode => ({
|
||||
...episode,
|
||||
show_title: show['title'],
|
||||
show_tmdb_id: show['tmdb_id'],
|
||||
collected: show['collected'],
|
||||
favorite: show['favorite']
|
||||
})))),
|
||||
})))).sort((a, b) => a['name'].localeCompare(b['name'])),
|
||||
collection: formatEpisodeData(collectedShows.flatMap(show => show['episodes'].map(episode => ({
|
||||
...episode,
|
||||
show_title: show['title'],
|
||||
show_tmdb_id: show['tmdb_id'],
|
||||
collected: show['collected'],
|
||||
favorite: show['favorite']
|
||||
}))))
|
||||
})))),
|
||||
toWatch
|
||||
}
|
||||
}
|
||||
}
|
Reference in a new issue