From 07381db7ea4460e3a0d9be3368df48a47cdf884a Mon Sep 17 00:00:00 2001 From: 1hitsong <3330318+1hitsong@users.noreply.github.com> Date: Tue, 31 Dec 2024 18:59:54 -0500 Subject: [PATCH 1/5] Show top artist images even if no primary tag found Fixes #24 --- src/jelly-helper.js | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/jelly-helper.js b/src/jelly-helper.js index 67f648f..c267993 100644 --- a/src/jelly-helper.js +++ b/src/jelly-helper.js @@ -44,11 +44,17 @@ export default class JellyHelper { }) } - if (primaryTag && (parentItemId || type === `user`)) { - let url = `${this.auth.config.serverInfo.PublicAddress}/Items/${parentItemId}/Images/Primary?tag=${primaryTag}&MaxWidth=${resolution}&MaxHeight=${resolution}` + if (parentItemId || type === `user`) { + let url = `${this.auth.config.serverInfo.PublicAddress}/Items/${parentItemId}/Images/Primary?MaxWidth=${resolution}&MaxHeight=${resolution}` + if (type === `user`) { - url = `${this.auth.config.serverInfo.PublicAddress}/Users/${parentItemId}/Images/Primary?tag=${primaryTag}&MaxWidth=${resolution}&MaxHeight=${resolution}` + url = `${this.auth.config.serverInfo.PublicAddress}/Users/${parentItemId}/Images/Primary?MaxWidth=${resolution}&MaxHeight=${resolution}` + } + + if (primaryTag) { + url += `&tag=${primaryTag}` } + fetch(url, { method: `GET`, headers: { From d1db98f83f9c87f4f7d22e120c5f4b709e6e57c0 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 1 Jan 2025 16:01:44 +0100 Subject: [PATCH 2/5] use batching for offline play import --- src/offline-import.js | 19 +++++++++++++++---- src/onboarding.js | 5 +++-- src/rewind.js | 20 ++++++++++++++++++++ 3 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/offline-import.js b/src/offline-import.js index 6b425c7..f933b0f 100644 --- a/src/offline-import.js +++ b/src/offline-import.js @@ -1,4 +1,4 @@ -import { loadItemInfo } from "./rewind"; +import { loadItemInfo, loadItemInfoBatched } from "./rewind"; export function importOfflinePlayback(fileHandle) { return new Promise((resolve, reject) => { @@ -10,7 +10,7 @@ export function importOfflinePlayback(fileHandle) { console.log(`offlinePlaybackData:`, offlinePlaybackData) // fetch item data to get track durations - const itemInfo = await loadItemInfo(offlinePlaybackData.map(play => play.itemId)) + const itemInfo = await loadItemInfoBatched(offlinePlaybackData.map(play => play.itemId)) console.log(`itemInfo:`, itemInfo) if (itemInfo[`Items`]?.length > 0) { // create map of item ID and duration for reduced time complexity @@ -103,17 +103,28 @@ const uploadOfflinePlaybackQuery = (offlinePlays, auth) => { (DateCreated, UserId, ItemId, ItemType, ItemName, PlaybackMethod, ClientName, DeviceName, PlayDuration) VALUES ${offlinePlays.map(play => - `( '${play.timestamp.toISOString().slice(0, 19).replace(`T`, ` `)}.0000000', '${auth.config.user.id}', '${play.itemId}', 'Audio', '${play.artist.replaceAll(`'`, `''`)} - ${play.title.replaceAll(`'`, `''`)} (${play.album.replaceAll(`'`, `''`)})', 'OfflinePlay', '${play.client.replaceAll(`'`, `''`)}', '${play.device.replaceAll(`'`, `''`)}', ${play.playDuration})` + `( '${play.timestamp.toISOString().slice(0, 19).replace(`T`, ` `)}.0000000', '${auth.config.user.id}', '${play.itemId}', 'Audio', '${play.artist?.replaceAll?.(`'`, `''`)} - ${play.title?.replaceAll?.(`'`, `''`)} (${play.album?.replaceAll?.(`'`, `''`)})', 'OfflinePlay', '${play.client?.replaceAll?.(`'`, `''`)}', '${play.device.replaceAll(`'`, `''`)}', ${play.playDuration ?? 0})` ).join(`,`)} ` } // GROUP BY ItemId -- don't group so that we can filter out wrong durations // LIMIT 200 -export async function uploadOfflinePlayback(offlinePlays, auth) { +export async function uploadOfflinePlaybackBatched(offlinePlays, auth) { console.info(`Importing offline playback to server`) + const batchSize = 100 + for (let batchIndex = 0; batchIndex < Math.ceil(offlinePlays.length / batchSize); batchIndex++) { + console.info(`Importing batch`) + await uploadOfflinePlayback(offlinePlays.slice(batchSize*batchIndex, batchSize*(batchIndex+1)), auth) + } + +} + +async function uploadOfflinePlayback(offlinePlays, auth) { + + console.log(`offlinePlays:`, offlinePlays) const response = await fetch(`${auth.config.baseUrl}/user_usage_stats/submit_custom_query?stamp=${Date.now()}`, { method: 'POST', headers: { diff --git a/src/onboarding.js b/src/onboarding.js index f2c8d3c..cfd8385 100644 --- a/src/onboarding.js +++ b/src/onboarding.js @@ -2,7 +2,7 @@ import { reactive, watch, html, } from '@arrow-js/core' import { connectToServer, generateRewindReport, initializeFeatureStory, loginViaAuthToken, loginViaPassword, restoreAndPrepareRewind, deleteRewind } from './setup'; import { getFeatureDelta, importRewindReport } from './delta'; -import { checkIfOfflinePlaybackImportAvailable, importOfflinePlayback, Play, uploadOfflinePlayback } from './offline-import'; +import { checkIfOfflinePlaybackImportAvailable, importOfflinePlayback, Play, uploadOfflinePlaybackBatched } from './offline-import'; export const state = reactive({ currentView: `start`, @@ -880,9 +880,10 @@ const viewImportOfflinePlayback = html` input.disabled = true state.offlinePlayback = await importOfflinePlayback(e.target.files[0]) console.log(`state.offlinePlayback:`, state.offlinePlayback) + console.log(`missing playDurations:`, state.offlinePlayback.filter(x => !x.playDuration)) // import plays to server - await uploadOfflinePlayback(state.offlinePlayback, state.auth) + await uploadOfflinePlaybackBatched(state.offlinePlayback, state.auth) state.currentView = `importLastYearsReport` } catch (err) { diff --git a/src/rewind.js b/src/rewind.js index 6346749..4535c50 100644 --- a/src/rewind.js +++ b/src/rewind.js @@ -245,6 +245,26 @@ export async function loadItemInfo(items) { } +export async function loadItemInfoBatched(items) { + + let combinedResponse = null + const batchSize = 200 + let response + for (let batchIndex = 0; batchIndex < Math.ceil(items.length / batchSize); batchIndex++) { + console.info(`Fetching item batch info`) + response = await loadItemInfo(items.slice(batchSize*batchIndex, batchSize*(batchIndex+1)), auth) + if (!combinedResponse) { + combinedResponse = response + } else { + combinedResponse.Items.push(...response.Items) + } + console.log(`combinedResponse.Items.length:`, combinedResponse.Items.length) + } + + return combinedResponse + +} + async function loadArtistInfo(items) { const params = { From 8488bc85ece49e5c42553301ea381d3f71633887 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 1 Jan 2025 16:17:23 +0100 Subject: [PATCH 3/5] fix year in delta feature - fixes #27 --- src/delta.js | 1 + src/features.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/delta.js b/src/delta.js index cc80288..8c1d652 100644 --- a/src/delta.js +++ b/src/delta.js @@ -41,6 +41,7 @@ export async function getFeatureDelta(oldReport, newReport) { return { listeningActivityDifference, favoriteDifference, + year: oldReport.jellyfinRewindReport.year, } } diff --git a/src/features.js b/src/features.js index 57add50..055e9dd 100644 --- a/src/features.js +++ b/src/features.js @@ -626,7 +626,7 @@ state.features = [

...compared to last year!

-
This year, you played ${() => state.extraFeatures.listeningActivityDifference ? showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource]).toFixed(0)) : `???`} tracks ${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource] >= 0) ? `more` : `less`} than in ${() => state.rewindReport?.year}.
+
This year, you played ${() => state.extraFeatures.listeningActivityDifference ? showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource]).toFixed(0)) : `???`} tracks ${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource] >= 0) ? `more` : `less`} than in ${() => state.rewindReport?.featureDelta?.year}.
From 58f8505c86c35cf8cdcd89348f9ddbe69806c114 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 1 Jan 2025 16:37:57 +0100 Subject: [PATCH 4/5] fix logo and improve layout on summary feature --- src/features.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/features.js b/src/features.js index 055e9dd..1f06e65 100644 --- a/src/features.js +++ b/src/features.js @@ -985,11 +985,10 @@ state.features = [ // summary screen buildFeature(`summary`, html`
-

+

${() => state.auth?.config?.user?.name}'s
- Jellyfin Rewind Logo -

Rewind

+ Jellyfin Rewind Logo
Report

@@ -1052,13 +1051,13 @@ state.features = [ ` : null}
${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.tracks >= 0) ? html` -
${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.tracks))} more tracks
+
${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.tracks))}
more tracks
` : null} ${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.artists >= 0) ? html` -
${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.artists))} more artists
+
${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.artists))}
more artists
` : null} ${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.albums >= 0) ? html` -
${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.albums))} more albums
+
${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.albums))}
more albums
` : null}
From b279a5f8a3d9b387486b9cc53036379123e68331 Mon Sep 17 00:00:00 2001 From: Chaphasilor Date: Wed, 1 Jan 2025 20:46:26 +0100 Subject: [PATCH 5/5] fix dialog sizing on desktop --- src/onboarding.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/onboarding.js b/src/onboarding.js index cfd8385..59662fa 100644 --- a/src/onboarding.js +++ b/src/onboarding.js @@ -216,7 +216,7 @@ const viewPlaceholder = html` ` const connectionHelpDialog = html` -
+
@@ -247,7 +247,7 @@ const connectionHelpDialog = html` ` const playbackReportingDialog = html` -
+
@@ -299,7 +299,7 @@ const playbackReportingDialog = html`
` const finampOfflineExportDialog = html` -
+