feat: recommend server-generated mixes from Musify and YouTube Music
Mixes are their own concept, not playlists: they live in their own Mixes/MixItems tables, cannot be edited and never show up among the user's playlists. Each item is either a Musify track or a YouTube Music reference, so YouTube songs stream directly instead of being downloaded. A daily Hangfire job seeds the mixes from the listening history: one discovery mix, one daily mix and one per top artist. The per-user YouTube filler query was already in the working tree and rides along here because it shares files with this change.
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import type { PageServerLoad, Actions } from './$types';
|
||||
import { createApiClient, playlistCoverTrackIds, requireUser } from '$lib/server/api';
|
||||
import { fetchYoutubeFiller, shuffle } from '$lib/server/youtube';
|
||||
import { fetchYoutubeFiller } from '$lib/server/youtube';
|
||||
import { shuffle } from '$lib/collections';
|
||||
import { addTrackAction, addYouTubeToPlaylistAction } from '$lib/server/playlistActions';
|
||||
import { HOME_LATEST_PAGE_SIZE, YOUTUBE_FILLER_LIMIT } from '$lib/config';
|
||||
import { pickGreeting } from '$lib/server/greeting';
|
||||
@@ -15,13 +16,15 @@ export const load: PageServerLoad = async ({ locals, url, fetch }) => {
|
||||
const playlistsPromise = api.GET('/playlists/users/{userId}', {
|
||||
params: { path: { userId: user.sub }, query: { pageNumber: 1, pageSize: 12 } }
|
||||
});
|
||||
const mixesPromise = api.GET('/mixes');
|
||||
const recentlyPlayedPromise = api.GET('/users/{id}/listening-history', {
|
||||
params: { path: { id: user.sub } }
|
||||
});
|
||||
|
||||
const [latest, playlists, recentlyPlayed] = await Promise.all([
|
||||
const [latest, playlists, mixes, recentlyPlayed] = await Promise.all([
|
||||
latestPromise,
|
||||
playlistsPromise,
|
||||
mixesPromise,
|
||||
recentlyPlayedPromise
|
||||
]);
|
||||
const playlistItems = playlists.data?.items ?? [];
|
||||
@@ -34,8 +37,15 @@ export const load: PageServerLoad = async ({ locals, url, fetch }) => {
|
||||
greeting: pickGreeting(new Date().getHours()),
|
||||
latest: shuffle((latest.data?.items ?? []).map((track) => ({ kind: 'local' as const, track }))),
|
||||
latestHasNext: Boolean(latest.data?.hasNextPage),
|
||||
youtubeFiller: fetchYoutubeFiller(api, locals.accessToken, YOUTUBE_FILLER_LIMIT),
|
||||
youtubeFiller: fetchYoutubeFiller(
|
||||
api,
|
||||
locals.accessToken,
|
||||
YOUTUBE_FILLER_LIMIT,
|
||||
undefined,
|
||||
user.sub
|
||||
),
|
||||
playlists: playlistItems,
|
||||
mixes: mixes.data ?? [],
|
||||
trackIds,
|
||||
recentlyPlayed: recentlyPlayed.data ?? []
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user