Skip to content

Commit

Permalink
Merge pull request #32 from Chaphasilor/dev
Browse files Browse the repository at this point in the history
2024 first patch
  • Loading branch information
Chaphasilor authored Jan 1, 2025
2 parents 8dc2426 + b279a5f commit 9e35ae3
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 19 deletions.
1 change: 1 addition & 0 deletions src/delta.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ export async function getFeatureDelta(oldReport, newReport) {
return {
listeningActivityDifference,
favoriteDifference,
year: oldReport.jellyfinRewindReport.year,
}

}
13 changes: 6 additions & 7 deletions src/features.js
Original file line number Diff line number Diff line change
Expand Up @@ -626,7 +626,7 @@ state.features = [
<h3 class="text-2xl font-medium">...compared to last year!</h3>
<div class="mt-24 w-full px-6 flex flex-col items-center gap-2">
<div class="font-semibold text-xl">This year, you played <span class="font-semibold text-3xl text-sky-500 font-quicksand">${() => state.extraFeatures.listeningActivityDifference ? showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource]).toFixed(0)) : `???`}</span> tracks ${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource] >= 0) ? `more` : `less`} than in ${() => state.rewindReport?.year}.</div>
<div class="font-semibold text-xl">This year, you played <span class="font-semibold text-3xl text-sky-500 font-quicksand">${() => state.extraFeatures.listeningActivityDifference ? showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource]).toFixed(0)) : `???`}</span> tracks ${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.totalPlays[state.settings.dataSource] >= 0) ? `more` : `less`} than in ${() => state.rewindReport?.featureDelta?.year}.</div>
</div>
<div class="mt-28 w-full px-10 flex flex-col items-center gap-3">
Expand Down Expand Up @@ -985,11 +985,10 @@ state.features = [
// summary screen
buildFeature(`summary`, html`
<div class="h-full p-4 flex flex-col justify-around">
<h2 class="text-2xl pt-[4.5rem] font-quicksand leading-8 flex flex-col items-center gap-1.5 text-center mt-2 font-semibold text-gray-800 dark:text-gray-200">
<h2 class="text-2xl mt-8 font-quicksand leading-8 flex flex-col items-center gap-1.5 text-center font-semibold text-gray-800 dark:text-gray-200">
<span>${() => state.auth?.config?.user?.name}'s</span>
<div class="w-full flex flex-col items-center">
<img class="h-12" src="${() => state.settings.darkMode ? '/media/jellyfin-banner-dark.svg' : '/media/jellyfin-banner-light.svg'}" alt="Jellyfin Rewind Logo">
<h3 class="-rotate-6 ml-4 -mt-2 text-2xl font-quicksand font-medium text-[#00A4DC]">Rewind</h3>
<img class="h-20" src="${() => state.settings.darkMode ? '/media/banner-dark.svg' : '/media/banner-light.svg'}" alt="Jellyfin Rewind Logo">
</div>
<span>Report</span>
</h2>
Expand Down Expand Up @@ -1052,13 +1051,13 @@ state.features = [
` : null}
<div class="flex flex-row flex-wrap justify-around gap-4">
${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.tracks >= 0) ? html`
<div class="text-center"><span class="text-lg text-[#00A4DC] font-semibold font-quicksand">${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.tracks))}</span> more tracks</div>
<div class="text-center"><span class="text-lg text-[#00A4DC] font-semibold font-quicksand">${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.tracks))}</span><br/>more tracks</div>
` : null}
${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.artists >= 0) ? html`
<div class="text-center"><span class="text-lg text-[#00A4DC] font-semibold font-quicksand">${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.artists))}</span> more artists</div>
<div class="text-center"><span class="text-lg text-[#00A4DC] font-semibold font-quicksand">${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.artists))}</span><br/>more artists</div>
` : null}
${() => (!state.extraFeatures.listeningActivityDifference || state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.albums >= 0) ? html`
<div class="text-center"><span class="text-lg text-[#00A4DC] font-semibold font-quicksand">${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.albums))}</span> more albums</div>
<div class="text-center"><span class="text-lg text-[#00A4DC] font-semibold font-quicksand">${() =>showAsNumber(Math.abs(state.rewindReport?.featureDelta?.listeningActivityDifference?.uniquePlays.albums))}</span><br/>more albums</div>
` : null}
</div>
</div>
Expand Down
12 changes: 9 additions & 3 deletions src/jelly-helper.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down
19 changes: 15 additions & 4 deletions src/offline-import.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { loadItemInfo } from "./rewind";
import { loadItemInfo, loadItemInfoBatched } from "./rewind";

export function importOfflinePlayback(fileHandle) {
return new Promise((resolve, reject) => {
Expand All @@ -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
Expand Down Expand Up @@ -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: {
Expand Down
11 changes: 6 additions & 5 deletions src/onboarding.js
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Expand Down Expand Up @@ -216,7 +216,7 @@ const viewPlaceholder = html`
`

const connectionHelpDialog = html`
<div class="fixed top-0 left-0 w-full h-full px-6 py-16 md:py-32 lg:py-48 xl:py-64">
<div class="fixed top-0 left-0 w-full h-full px-6 py-32 md:py-24 lg:py-28 xl:py-32">
<div @click="${() => state.connectionHelpDialogOpen = false}" class="absolute top-0 left-0 w-full h-full bg-black/20"></div>
<div class="w-full h-full bg-white/80 dark:bg-black/90 dark:text-white pb-20 backdrop-blur dark:backdrop-blur-sm rounded-xl">
<div class="relative w-full flex flex-row justify-center items-center px-2 pt-4 pb-2">
Expand Down Expand Up @@ -247,7 +247,7 @@ const connectionHelpDialog = html`
`

const playbackReportingDialog = html`
<div class="fixed top-0 left-0 w-full h-full px-6 py-16 md:py-32 lg:py-48 xl:py-64">
<div class="fixed top-0 left-0 w-full h-full px-6 py-32 md:py-24 lg:py-28 xl:py-32">
<div @click="${() => state.playbackReportingDialogOpen = false}" class="absolute top-0 left-0 w-full h-full bg-black/20"></div>
<div class="w-full h-full bg-white/80 dark:bg-black/90 dark:text-white pb-20 backdrop-blur dark:backdrop-blur-sm rounded-xl">
<div class="relative w-full flex flex-row justify-center items-center px-2 pt-4 pb-2">
Expand Down Expand Up @@ -299,7 +299,7 @@ const playbackReportingDialog = html`
</div>
`
const finampOfflineExportDialog = html`
<div class="fixed top-0 left-0 w-full h-full px-6 py-16 md:py-32 lg:py-48 xl:py-64">
<div class="fixed top-0 left-0 w-full h-full px-6 py-32 md:py-24 lg:py-28 xl:py-32">
<div @click="${() => state.finampOfflineExportDialogOpen = false}" class="absolute top-0 left-0 w-full h-full bg-black/20"></div>
<div class="w-full h-full bg-white/80 dark:bg-black/90 dark:text-white pb-20 backdrop-blur dark:backdrop-blur-sm rounded-xl">
<div class="relative w-full flex flex-row justify-center items-center px-2 pt-4 pb-2">
Expand Down Expand Up @@ -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) {
Expand Down
20 changes: 20 additions & 0 deletions src/rewind.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down

0 comments on commit 9e35ae3

Please sign in to comment.