feat: scrobbling refinements

This commit is contained in:
Cory Dransfeldt 2024-08-10 07:06:53 -07:00
parent 422c8d151a
commit 068aeed2e6
No known key found for this signature in database
3 changed files with 62 additions and 44 deletions

10
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "21.7.2", "version": "21.8.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "coryd.dev", "name": "coryd.dev",
"version": "21.7.2", "version": "21.8.0",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@cdransf/api-text": "^1.4.0", "@cdransf/api-text": "^1.4.0",
@ -1147,9 +1147,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/electron-to-chromium": { "node_modules/electron-to-chromium": {
"version": "1.5.5", "version": "1.5.6",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.5.tgz", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.6.tgz",
"integrity": "sha512-QR7/A7ZkMS8tZuoftC/jfqNkZLQO779SSW3YuZHP4eXpj3EffGLFcB/Xu9AAZQzLccTiCV+EmUo3ha4mQ9wnlA==", "integrity": "sha512-jwXWsM5RPf6j9dPYzaorcBSUg6AiqocPEyMpkchkvntaH9HGfOOMZwxMJjDY/XEs3T5dM7uyH1VhRMkqUU9qVw==",
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },

View file

@ -1,6 +1,6 @@
{ {
"name": "coryd.dev", "name": "coryd.dev",
"version": "21.7.2", "version": "21.8.0",
"description": "The source for my personal site. Built using 11ty (and other tools).", "description": "The source for my personal site. Built using 11ty (and other tools).",
"type": "module", "type": "module",
"scripts": { "scripts": {

View file

@ -14,7 +14,7 @@ const sanitizeMediaString = (str) => {
}) })
} }
const sendEmail = async (subject, text, authHeader) => { const sendEmail = async (subject, text, authHeader, maxRetries = 3) => {
const emailData = new URLSearchParams({ const emailData = new URLSearchParams({
from: 'hi@admin.coryd.dev', from: 'hi@admin.coryd.dev',
to: 'hi@coryd.dev', to: 'hi@coryd.dev',
@ -22,27 +22,41 @@ const sendEmail = async (subject, text, authHeader) => {
text: text, text: text,
}).toString() }).toString()
try { let attempt = 0
const response = await fetch('https://api.forwardemail.net/v1/emails', { let success = false
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authHeader,
},
body: emailData,
})
const responseText = await response.text() while (attempt < maxRetries && !success) {
attempt++
try {
const response = await fetch('https://api.forwardemail.net/v1/emails', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': authHeader,
},
body: emailData,
})
if (!response.ok) { if (!response.ok) {
console.error('Email API response error:', response.status, responseText) const responseText = await response.text()
throw new Error(`Failed to send email: ${responseText}`) console.error(`Attempt ${attempt}: Email API response error:`, response.status, responseText)
} else { throw new Error(`Failed to send email: ${responseText}`)
console.log('Email sent successfully') }
console.log('Email sent successfully on attempt', attempt)
success = true
} catch (error) {
console.error(`Attempt ${attempt}: Error sending email:`, error.message)
if (attempt < maxRetries) {
console.log(`Retrying email send (attempt ${attempt + 1}/${maxRetries})...`)
} else {
console.error('All attempts to send email failed.')
}
} }
} catch (error) {
console.error('Error sending email:', error.message)
} }
return success
} }
export default { export default {
@ -51,7 +65,6 @@ export default {
const SUPABASE_KEY = env.SUPABASE_KEY const SUPABASE_KEY = env.SUPABASE_KEY
const FORWARDEMAIL_API_KEY = env.FORWARDEMAIL_API_KEY const FORWARDEMAIL_API_KEY = env.FORWARDEMAIL_API_KEY
const ACCOUNT_ID_PLEX = env.ACCOUNT_ID_PLEX const ACCOUNT_ID_PLEX = env.ACCOUNT_ID_PLEX
const supabase = createClient(SUPABASE_URL, SUPABASE_KEY) const supabase = createClient(SUPABASE_URL, SUPABASE_KEY)
const authHeader = 'Basic ' + btoa(`${FORWARDEMAIL_API_KEY}:`) const authHeader = 'Basic ' + btoa(`${FORWARDEMAIL_API_KEY}:`)
const url = new URL(request.url) const url = new URL(request.url)
@ -80,17 +93,17 @@ export default {
const payload = JSON.parse(data.get('payload')) const payload = JSON.parse(data.get('payload'))
if (payload?.event === 'media.scrobble') { if (payload?.event === 'media.scrobble') {
const artist = payload['Metadata']['grandparentTitle'] const artistName = payload['Metadata']['grandparentTitle']
const album = payload['Metadata']['parentTitle'] const albumName = payload['Metadata']['parentTitle']
const track = payload['Metadata']['title'] const trackName = payload['Metadata']['title']
const listenedAt = Math.floor(DateTime.now().toSeconds()) const listenedAt = Math.floor(DateTime.now().toSeconds())
const artistKey = sanitizeMediaString(artist) const artistKey = sanitizeMediaString(artistName)
const albumKey = `${artistKey}-${sanitizeMediaString(album)}` const albumKey = `${artistKey}-${sanitizeMediaString(albumName)}`
let { data: artistData, error: artistError } = await supabase let { data: artistData, error: artistError } = await supabase
.from('artists') .from('artists')
.select('*') .select('*')
.ilike('name_string', artist) .ilike('name_string', artistName)
.single() .single()
if (artistError && artistError.code === 'PGRST116') { if (artistError && artistError.code === 'PGRST116') {
@ -100,14 +113,14 @@ export default {
{ {
mbid: null, mbid: null,
art: '4cef75db-831f-4f5d-9333-79eaa5bb55ee', art: '4cef75db-831f-4f5d-9333-79eaa5bb55ee',
name: artist, name: artistName,
tentative: true, tentative: true,
total_plays: 0, total_plays: 0,
}, },
]) ])
if (insertArtistError) { if (insertArtistError) {
console.error('Error inserting artist:', insertArtistError.message) console.error('Error inserting artist: ', insertArtistError.message)
return new Response( return new Response(
JSON.stringify({ JSON.stringify({
status: 'error', status: 'error',
@ -119,16 +132,18 @@ export default {
await sendEmail( await sendEmail(
'New tentative artist record', 'New tentative artist record',
`A new tentative artist record was inserted:\n\nArtist: ${artist}\nKey: ${artistKey}`, `A new tentative artist record was inserted:\n\nArtist: ${artistName}\nKey: ${artistKey}`,
authHeader authHeader
) )
({ data: artistData, error: artistError } = await supabase ;({ data: artistData, error: artistError } = await supabase
.from('artists') .from('artists')
.select('*') .select('*')
.ilike('name_string', artist) .ilike('name_string', artistName)
.single()) .single())
} else if (artistError) { }
if (artistError) {
console.error('Error fetching artist:', artistError.message) console.error('Error fetching artist:', artistError.message)
return new Response( return new Response(
JSON.stringify({ status: 'error', message: artistError.message }), JSON.stringify({ status: 'error', message: artistError.message }),
@ -150,9 +165,10 @@ export default {
mbid: null, mbid: null,
art: '4cef75db-831f-4f5d-9333-79eaa5bb55ee', art: '4cef75db-831f-4f5d-9333-79eaa5bb55ee',
key: albumKey, key: albumKey,
name: album, name: albumName,
tentative: true, tentative: true,
total_plays: 0, total_plays: 0,
artist: artistData.id,
}, },
]) ])
@ -169,16 +185,18 @@ export default {
await sendEmail( await sendEmail(
'New tentative album record', 'New tentative album record',
`A new tentative album record was inserted:\n\nAlbum: ${album}\nKey: ${albumKey}`, `A new tentative album record was inserted:\n\nAlbum: ${albumName}\nKey: ${albumKey}\nArtist: ${artistName}`,
authHeader authHeader
) )
({ data: albumData, error: albumError } = await supabase ;({ data: albumData, error: albumError } = await supabase
.from('albums') .from('albums')
.select('*') .select('*')
.ilike('key', albumKey) .ilike('key', albumKey)
.single()) .single())
} else if (albumError) { }
if (albumError) {
console.error('Error fetching album:', albumError.message) console.error('Error fetching album:', albumError.message)
return new Response( return new Response(
JSON.stringify({ status: 'error', message: albumError.message }), JSON.stringify({ status: 'error', message: albumError.message }),
@ -188,9 +206,9 @@ export default {
const { error: listenError } = await supabase.from('listens').insert([ const { error: listenError } = await supabase.from('listens').insert([
{ {
artist_name: artist, artist_name: artistData['name_string'] || artistName,
album_name: album, album_name: albumData['name'] || albumName,
track_name: track, track_name: trackName,
listened_at: listenedAt, listened_at: listenedAt,
album_key: albumKey, album_key: albumKey,
}, },