feat: artist pages
This commit is contained in:
parent
d39369bd99
commit
013daa1c82
17 changed files with 390 additions and 130 deletions
75
src/_data/artists.js
Normal file
75
src/_data/artists.js
Normal file
|
@ -0,0 +1,75 @@
|
|||
import { createClient } from '@supabase/supabase-js'
|
||||
|
||||
const SUPABASE_URL = process.env.SUPABASE_URL || 'YOUR_SUPABASE_URL'
|
||||
const SUPABASE_KEY = process.env.SUPABASE_KEY || 'YOUR_SUPABASE_KEY'
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
|
||||
|
||||
const regionNames = new Intl.DisplayNames(['en'], { type: 'region' })
|
||||
const getCountryName = (countryCode) => regionNames.of(countryCode.trim()) || countryCode.trim()
|
||||
|
||||
const parseCountryField = (countryField) => {
|
||||
if (!countryField) return null
|
||||
|
||||
const delimiters = [',', '/', '&', 'and']
|
||||
let countries = [countryField]
|
||||
|
||||
delimiters.forEach(delimiter => {
|
||||
countries = countries.flatMap(country => country.split(delimiter))
|
||||
})
|
||||
|
||||
return countries.map(getCountryName).join(', ')
|
||||
}
|
||||
|
||||
const PAGE_SIZE = 50
|
||||
|
||||
const fetchPaginatedData = async (table, selectFields) => {
|
||||
let data = []
|
||||
let page = 0
|
||||
let hasMoreRecords = true
|
||||
|
||||
while (hasMoreRecords) {
|
||||
const { data: pageData, error } = await supabase
|
||||
.from(table)
|
||||
.select(selectFields)
|
||||
.order('id', { ascending: true })
|
||||
.range(page * PAGE_SIZE, (page + 1) * PAGE_SIZE - 1)
|
||||
|
||||
if (error) {
|
||||
console.error(`Error fetching ${table}:`, error)
|
||||
break
|
||||
}
|
||||
|
||||
data = data.concat(pageData)
|
||||
|
||||
if (pageData.length < PAGE_SIZE) {
|
||||
hasMoreRecords = false
|
||||
} else {
|
||||
page++
|
||||
}
|
||||
}
|
||||
|
||||
return data
|
||||
}
|
||||
|
||||
export default async function () {
|
||||
const artists = await fetchPaginatedData('artists', 'mbid, name_string, image, genre, total_plays, country, description, favorite')
|
||||
const albums = await fetchPaginatedData('albums', 'mbid, name, release_year, artist_mbid, total_plays')
|
||||
|
||||
const albumsByArtist = albums.reduce((acc, album) => {
|
||||
if (!acc[album.artist_mbid]) acc[album.artist_mbid] = []
|
||||
acc[album.artist_mbid].push({
|
||||
id: album.id,
|
||||
name: album.name,
|
||||
release_year: album.release_year,
|
||||
total_plays: album.total_plays > 0 ? album.total_plays : '-'
|
||||
})
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
artists.forEach(artist => {
|
||||
artist.albums = albumsByArtist[artist.mbid]?.sort((a, b) => a['release_year'] - b['release_year']) || []
|
||||
artist.country = parseCountryField(artist.country)
|
||||
})
|
||||
|
||||
return artists
|
||||
}
|
|
@ -51,7 +51,7 @@ export default async function () {
|
|||
lastWatched: item['last_watched'],
|
||||
dateAdded: item['last_watched'],
|
||||
year: item['year'],
|
||||
url: `https://coryd.dev/movies/${item['tmdb_id']}`,
|
||||
url: `https://coryd.dev/watching/movies/${item['tmdb_id']}`,
|
||||
description: `${item['title']} (${item['year']})<br/>Watched at: ${DateTime.fromISO(item['last_watched'], { zone: 'utc' }).setZone('America/Los_Angeles').toFormat('MMMM d, yyyy, h:mma')}`,
|
||||
image: `https://coryd.dev/media/movies/poster-${item['tmdb_id']}.jpg`,
|
||||
backdrop: `https://coryd.dev/media/movies/backdrops/backdrop-${item['tmdb_id']}.jpg`,
|
||||
|
|
|
@ -1,10 +1,32 @@
|
|||
import { createClient } from '@supabase/supabase-js'
|
||||
import { DateTime } from 'luxon'
|
||||
import slugify from 'slugify'
|
||||
|
||||
const SUPABASE_URL = process.env.SUPABASE_URL
|
||||
const SUPABASE_KEY = process.env.SUPABASE_KEY
|
||||
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
|
||||
|
||||
const slugifyString = (str) => slugify(str, {
|
||||
replacement: '-',
|
||||
remove: /[#,&,+()$~%.'":*?<>{}]/g,
|
||||
lower: true,
|
||||
})
|
||||
|
||||
const regionNames = new Intl.DisplayNames(['en'], { type: 'region' })
|
||||
const getCountryName = (countryCode) => regionNames.of(countryCode.trim()) || countryCode.trim()
|
||||
const parseCountryField = (countryField) => {
|
||||
if (!countryField) return null
|
||||
|
||||
const delimiters = [',', '/', '&', 'and']
|
||||
let countries = [countryField]
|
||||
|
||||
delimiters.forEach(delimiter => {
|
||||
countries = countries.flatMap(country => country.split(delimiter))
|
||||
})
|
||||
|
||||
return countries.map(getCountryName).join(', ')
|
||||
}
|
||||
|
||||
const fetchDataForPeriod = async (startPeriod, fields, table) => {
|
||||
const PAGE_SIZE = 1000
|
||||
let rows = []
|
||||
|
@ -68,22 +90,22 @@ const aggregateData = (data, groupByField, groupByType) => {
|
|||
aggregation[key] = {
|
||||
title: item[groupByField],
|
||||
plays: 0,
|
||||
mbid: item['albums']?.mbid || '',
|
||||
url: item['albums']?.mbid ? `https://musicbrainz.org/release/${item['albums'].mbid}` : `https://musicbrainz.org/search?query=${encodeURIComponent(item['album_name'])}&type=release`,
|
||||
image: item['albums']?.image || '',
|
||||
mbid: item['albums']['mbid'],
|
||||
url: `https://coryd.dev/music/artists/${slugifyString(item['artist_name'])}-${slugifyString(parseCountryField(item['artists']['country']))}`,
|
||||
image: item['albums']?.['image'] || '',
|
||||
timestamp: item['listened_at'],
|
||||
type: groupByType,
|
||||
genre: item['artists']?.genre || 'Unknown'
|
||||
genre: item['artists']?.['genre'] || ''
|
||||
}
|
||||
} else {
|
||||
aggregation[key] = {
|
||||
title: item[groupByField],
|
||||
plays: 0,
|
||||
mbid: item[groupByType]?.mbid || '',
|
||||
url: item[groupByType]?.mbid ? `https://musicbrainz.org/${groupByType === 'albums' ? 'release' : 'artist'}/${item[groupByType].mbid}` : `https://musicbrainz.org/search?query=${encodeURIComponent(item[groupByField])}&type=${groupByType === 'albums' ? 'release' : 'artist'}`,
|
||||
mbid: item[groupByType]?.['mbid'] || '',
|
||||
url: `https://coryd.dev/music/artists/${slugifyString(item['artist_name'])}-${slugifyString(parseCountryField(item['artists']['country']))}`,
|
||||
image: item[groupByType]?.image || '',
|
||||
type: groupByType,
|
||||
genre: item['artists']?.genre || 'Unknown'
|
||||
genre: item['artists']?.['genre'] || ''
|
||||
}
|
||||
}
|
||||
if (
|
||||
|
@ -129,7 +151,7 @@ export default async function() {
|
|||
album_name,
|
||||
album_key,
|
||||
listened_at,
|
||||
artists (mbid, image, genre),
|
||||
artists (mbid, image, genre, country),
|
||||
albums (mbid, image)
|
||||
`
|
||||
|
||||
|
|
|
@ -90,7 +90,7 @@ export default async function () {
|
|||
|
||||
showEpisodesMap[showTmdbId].episodes.push({
|
||||
name: showTitle,
|
||||
url: `https://coryd.dev/shows/${showTmdbId}`,
|
||||
url: `https://coryd.dev/watching/shows/${showTmdbId}`,
|
||||
subtext: `${showTitle} • S${seasonNumber}E${episodeNumber}`,
|
||||
episode: episodeNumber,
|
||||
season: seasonNumber,
|
||||
|
@ -114,7 +114,7 @@ export default async function () {
|
|||
if (show.episodes.length > 1) {
|
||||
episodeData.push({
|
||||
name: show.title,
|
||||
url: `https://coryd.dev/shows/${show['tmdbId']}`,
|
||||
url: `https://coryd.dev/watching/shows/${show['tmdbId']}`,
|
||||
subtext: `S${startingSeason}E${startingEpisode} - S${endingSeason}E${endingEpisode}`,
|
||||
startingEpisode,
|
||||
startingSeason,
|
||||
|
@ -140,7 +140,7 @@ export default async function () {
|
|||
|
||||
const favoriteShows = shows.filter(show => show['favorite'])
|
||||
const collectedShows = shows.filter(show => show['collected'])
|
||||
const toWatch = shows.map(show => ({...show, url: `https://coryd.dev/shows/${show['tmdb_id']}`})).filter(show => !show.episodes.some(episode => episode.last_watched_at)).sort((a, b) => a['title'].localeCompare(b['title']))
|
||||
const toWatch = shows.map(show => ({...show, url: `https://coryd.dev/watching/shows/${show['tmdb_id']}`})).filter(show => !show.episodes.some(episode => episode.last_watched_at)).sort((a, b) => a['title'].localeCompare(b['title']))
|
||||
|
||||
return {
|
||||
shows,
|
||||
|
|
Reference in a new issue