feat: scrobbling refinements
This commit is contained in:
parent
422c8d151a
commit
068aeed2e6
3 changed files with 62 additions and 44 deletions
10
package-lock.json
generated
10
package-lock.json
generated
|
@ -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"
|
||||||
},
|
},
|
||||||
|
|
|
@ -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": {
|
||||||
|
|
|
@ -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,
|
||||||
},
|
},
|
||||||
|
|
Reference in a new issue