Design Prot Merge #1

Merged
NotS1mp merged 217 commits from design-prot into master 2026-09-21 15:48:16 +00:00
12 changed files with 505 additions and 24 deletions
Showing only changes of commit 9cd916c098 - Show all commits
+484 -9
View File
@@ -4,6 +4,111 @@
*/ */
export interface paths { export interface paths {
"/albums": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Get Paginated Albums. */
get: operations["GetAlbums"];
put?: never;
/** Create A New Album. */
post: operations["CreateAlbum"];
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/albums/{id}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Get An Album By Id. */
get: operations["GetAlbumById"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/albums/users/{userId}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Get Paginated Albums For A User. */
get: operations["GetAlbumsByUserId"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/albums/{albumId}/tracks": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
/** Get The Tracks Of An Album Ordered By Track Number. */
get: operations["GetAlbumTracks"];
put?: never;
post?: never;
delete?: never;
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/albums/{albumId}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
/** Update An Album. */
put: operations["UpdateAlbum"];
post?: never;
/** Delete An Album. */
delete: operations["DeleteAlbum"];
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/albums/{albumId}/tracks/{trackId}": {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
get?: never;
put?: never;
/** Add One Of Your Uploaded Tracks To An Album. */
post: operations["AddTrackToAlbum"];
/** Remove A Track From An Album. */
delete: operations["RemoveTrackFromAlbum"];
options?: never;
head?: never;
patch?: never;
trace?: never;
};
"/playlists": { "/playlists": {
parameters: { parameters: {
query?: never; query?: never;
@@ -372,11 +477,31 @@ export interface components {
schemas: { schemas: {
AddYouTubeTrackRequest: { AddYouTubeTrackRequest: {
videoId: string; videoId: string;
};
AlbumApplicationResponse: {
/** Format: uuid */
id: string;
title: string; title: string;
artist: string; description: null | string;
/** Format: int32 */ /** Format: int32 */
durationSeconds: number | string; releaseYear: null | number | string;
thumbnailUrl: string; /** Format: int64 */
ownerUserId: number | string;
/** Format: int32 */
trackCount: number | string;
smallImageKeyName: null | string;
mediumImageKeyName: null | string;
largeImageKeyName: null | string;
/** Format: date-time */
createdAt: string;
/** Format: date-time */
updatedAt: string;
};
CreateAlbumRequest: {
title: string;
description: null | string;
/** Format: int32 */
releaseYear: null | number | string;
}; };
CreatePlayListRequest: { CreatePlayListRequest: {
name: string; name: string;
@@ -409,6 +534,19 @@ export interface components {
[key: string]: string[]; [key: string]: string[];
}; };
}; };
PaginatedResponseOfAlbumApplicationResponse: {
items: components["schemas"]["AlbumApplicationResponse"][];
/** Format: int32 */
pageNumber: number | string;
/** Format: int32 */
pageSize: number | string;
/** Format: int32 */
pageCount: number | string;
/** Format: int32 */
totalItemCount: number | string;
hasNextPage: boolean;
hasPreviousPage: boolean;
};
PaginatedResponseOfPlayListApplicationResponse: { PaginatedResponseOfPlayListApplicationResponse: {
items: components["schemas"]["PlayListApplicationResponse"][]; items: components["schemas"]["PlayListApplicationResponse"][];
/** Format: int32 */ /** Format: int32 */
@@ -452,10 +590,10 @@ export interface components {
/** Format: uuid */ /** Format: uuid */
id: string; id: string;
name: string; name: string;
description: string; description: null | string;
smallImageKeyName: string; smallImageKeyName: null | string;
mediumImageKeyName: string; mediumImageKeyName: null | string;
largeImageKeyName: string; largeImageKeyName: null | string;
/** Format: date-time */ /** Format: date-time */
createdAt: string; createdAt: string;
/** Format: date-time */ /** Format: date-time */
@@ -494,14 +632,16 @@ export interface components {
/** Format: uuid */ /** Format: uuid */
id: string; id: string;
title: string; title: string;
artist: string; artist: null | string;
source: components["schemas"]["TrackSource"]; source: components["schemas"]["TrackSource"];
externalId: string; externalId: null | string;
audioStatus: components["schemas"]["ProcessingStatus"]; audioStatus: components["schemas"]["ProcessingStatus"];
/** Format: int32 */ /** Format: int32 */
duration: number | string; duration: number | string;
/** Format: int32 */ /** Format: int32 */
listensCount: number | string; listensCount: number | string;
/** Format: int64 */
ownerUserId: null | number | string;
/** Format: date-time */ /** Format: date-time */
createdAt: string; createdAt: string;
/** Format: date-time */ /** Format: date-time */
@@ -532,6 +672,12 @@ export interface components {
/** Format: int32 */ /** Format: int32 */
expiresInSeconds: number | string; expiresInSeconds: number | string;
}; };
UpdateAlbumRequest: {
newTitle: string;
newDescription: null | string;
/** Format: int32 */
newReleaseYear: null | number | string;
};
UpdatePlayListRequest: { UpdatePlayListRequest: {
newName: null | string; newName: null | string;
newDescription: null | string; newDescription: null | string;
@@ -550,6 +696,10 @@ export interface components {
/** Format: date-time */ /** Format: date-time */
updatedAt: string; updatedAt: string;
}; };
YouTubeArtistRef: {
id: null | string;
name: string;
};
YouTubeSearchResult: { YouTubeSearchResult: {
items: components["schemas"]["YouTubeSongResult"][]; items: components["schemas"]["YouTubeSongResult"][];
continuationToken: string; continuationToken: string;
@@ -563,6 +713,7 @@ export interface components {
durationSeconds: number | string; durationSeconds: number | string;
thumbnailUrl: string; thumbnailUrl: string;
isExplicit: boolean; isExplicit: boolean;
artists: components["schemas"]["YouTubeArtistRef"][];
}; };
/** @enum {unknown} */ /** @enum {unknown} */
YouTubeStreamMode: "Server" | "YouTube"; YouTubeStreamMode: "Server" | "YouTube";
@@ -584,6 +735,330 @@ export interface components {
} }
export type $defs = Record<string, never>; export type $defs = Record<string, never>;
export interface operations { export interface operations {
GetAlbums: {
parameters: {
query?: {
title?: string;
pageNumber?: number | string;
pageSize?: number | string;
};
header?: never;
path?: never;
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["PaginatedResponseOfAlbumApplicationResponse"];
};
};
};
};
CreateAlbum: {
parameters: {
query?: never;
header?: never;
path?: never;
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["CreateAlbumRequest"];
};
};
responses: {
/** @description Created */
201: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AlbumApplicationResponse"];
};
};
/** @description Bad Request */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/problem+json": components["schemas"]["HttpValidationProblemDetails"];
};
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
GetAlbumById: {
parameters: {
query?: never;
header?: never;
path: {
id: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AlbumApplicationResponse"];
};
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
GetAlbumsByUserId: {
parameters: {
query?: {
pageNumber?: number | string;
pageSize?: number | string;
};
header?: never;
path: {
userId: number | string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["PaginatedResponseOfAlbumApplicationResponse"];
};
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
GetAlbumTracks: {
parameters: {
query?: {
pageNumber?: number | string;
pageSize?: number | string;
};
header?: never;
path: {
albumId: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["PaginatedResponseOfTrackApplicationResponse"];
};
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
UpdateAlbum: {
parameters: {
query?: never;
header?: never;
path: {
albumId: string;
};
cookie?: never;
};
requestBody: {
content: {
"application/json": components["schemas"]["UpdateAlbumRequest"];
};
};
responses: {
/** @description OK */
200: {
headers: {
[name: string]: unknown;
};
content: {
"application/json": components["schemas"]["AlbumApplicationResponse"];
};
};
/** @description Bad Request */
400: {
headers: {
[name: string]: unknown;
};
content: {
"application/problem+json": components["schemas"]["HttpValidationProblemDetails"];
};
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
DeleteAlbum: {
parameters: {
query?: never;
header?: never;
path: {
albumId: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description No Content */
204: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
AddTrackToAlbum: {
parameters: {
query?: never;
header?: never;
path: {
albumId: string;
trackId: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description No Content */
204: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Conflict */
409: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
RemoveTrackFromAlbum: {
parameters: {
query?: never;
header?: never;
path: {
albumId: string;
trackId: string;
};
cookie?: never;
};
requestBody?: never;
responses: {
/** @description No Content */
204: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Unauthorized */
401: {
headers: {
[name: string]: unknown;
};
content?: never;
};
/** @description Not Found */
404: {
headers: {
[name: string]: unknown;
};
content?: never;
};
};
};
GetPlayLists: { GetPlayLists: {
parameters: { parameters: {
query?: { query?: {
@@ -7,8 +7,8 @@
interface Props { interface Props {
id: string | number; id: string | number;
title: string; title: string;
artist?: string; artist?: string | null;
coverSrc?: string; coverSrc?: string | null;
coverSize?: 'small' | 'medium' | 'large'; coverSize?: 'small' | 'medium' | 'large';
hue: number; hue: number;
explicit?: boolean; explicit?: boolean;
@@ -7,7 +7,7 @@
trackId: string | number; trackId: string | number;
hue: number; hue: number;
size?: 'small' | 'medium' | 'large'; size?: 'small' | 'medium' | 'large';
src?: string; src?: string | null;
alt?: string; alt?: string;
class?: string; class?: string;
children?: Snippet; children?: Snippet;
@@ -5,7 +5,9 @@
value?: string; value?: string;
id?: string; id?: string;
name?: string; name?: string;
type?: 'text' | 'search'; type?: 'text' | 'search' | 'number';
min?: number;
max?: number;
placeholder?: string; placeholder?: string;
maxlength?: number; maxlength?: number;
required?: boolean; required?: boolean;
@@ -20,6 +22,8 @@
id, id,
name, name,
type = 'text', type = 'text',
min,
max,
placeholder, placeholder,
maxlength, maxlength,
required = false, required = false,
@@ -40,6 +44,8 @@
{id} {id}
{name} {name}
{type} {type}
{min}
{max}
{placeholder} {placeholder}
{maxlength} {maxlength}
{required} {required}
@@ -5,7 +5,7 @@
interface Props { interface Props {
id: string; id: string;
name: string; name: string;
description?: string; description?: string | null;
trackIds: (string | number)[]; trackIds: (string | number)[];
updatedAt: string; updatedAt: string;
index?: number; index?: number;
@@ -6,8 +6,8 @@
interface Props { interface Props {
trackId: string | number; trackId: string | number;
title: string; title: string;
artist?: string; artist?: string | null;
coverSrc?: string; coverSrc?: string | null;
coverSize?: string; coverSize?: string;
hue: number; hue: number;
explicit?: boolean; explicit?: boolean;
+3 -3
View File
@@ -34,9 +34,9 @@ export interface QueueItem {
export interface ApiTrackLike { export interface ApiTrackLike {
id: string | number; id: string | number;
title: string; title: string;
artist?: string; artist?: string | null;
source?: 'Local' | 'YouTube'; source?: 'Local' | 'YouTube';
externalId?: string; externalId?: string | null;
audioStatus?: 'Pending' | 'Processing' | 'Completed' | 'Failed'; audioStatus?: 'Pending' | 'Processing' | 'Completed' | 'Failed';
isExplicit?: boolean; isExplicit?: boolean;
} }
@@ -63,7 +63,7 @@ export function toQueueItems(tracks: ApiTrackLike[]): QueueItem[] {
return { return {
id: queueIdForTrack(track), id: queueIdForTrack(track),
title: track.title, title: track.title,
artist: track.artist, artist: track.artist ?? undefined,
source: youTube ? 'youtube' : 'local', source: youTube ? 'youtube' : 'local',
coverUrl: youTube coverUrl: youTube
? isPendingYouTubeTrack(track) && track.externalId ? isPendingYouTubeTrack(track) && track.externalId
+1 -1
View File
@@ -19,7 +19,7 @@ export function targetTitle(target: TrackTarget): string {
} }
export function targetArtist(target: TrackTarget): string | undefined { export function targetArtist(target: TrackTarget): string | undefined {
return target.kind === 'youtube' ? target.song.artist : target.track.artist; return (target.kind === 'youtube' ? target.song.artist : target.track.artist) ?? undefined;
} }
export function targetExplicit(target: TrackTarget): boolean { export function targetExplicit(target: TrackTarget): boolean {
@@ -41,7 +41,7 @@ export const load: PageServerLoad = async ({ params, locals, url, fetch }) => {
const alreadyLinked = new Set( const alreadyLinked = new Set(
tracks.filter((t) => t.source === 'YouTube' && t.externalId).map((t) => t.externalId) tracks.filter((t) => t.source === 'YouTube' && t.externalId).map((t) => t.externalId)
); );
const seeds = [...new Set(tracks.map((t) => t.artist).filter((a) => !!a))]; const seeds = [...new Set(tracks.map((t) => t.artist).filter((a): a is string => !!a))];
const seed = seeds.length > 0 ? shuffle(seeds)[0] : undefined; const seed = seeds.length > 0 ? shuffle(seeds)[0] : undefined;
const youtube = fetchYoutubeFiller( const youtube = fetchYoutubeFiller(
@@ -66,7 +66,7 @@
<PlaylistForm <PlaylistForm
action="?/rename" action="?/rename"
initialName={playlist.name} initialName={playlist.name}
initialDescription={playlist.description} initialDescription={playlist.description ?? ''}
coverFallbackUrl="/api/playlists/{playlist.id}/cover?size=medium&v={encodeURIComponent( coverFallbackUrl="/api/playlists/{playlist.id}/cover?size=medium&v={encodeURIComponent(
playlist.updatedAt playlist.updatedAt
)}" )}"
@@ -11,7 +11,7 @@
interface Props { interface Props {
id: string; id: string;
name: string; name: string;
description?: string; description?: string | null;
trackIds: (string | number)[]; trackIds: (string | number)[];
updatedAt: string; updatedAt: string;
playing: boolean; playing: boolean;
@@ -71,7 +71,7 @@
: { : {
id: queueIdForTrack(item.track), id: queueIdForTrack(item.track),
title: item.track.title, title: item.track.title,
artist: item.track.artist, artist: item.track.artist ?? undefined,
source: 'local', source: 'local',
coverUrl: `/api/tracks/${item.track.id}/cover?size=small` coverUrl: `/api/tracks/${item.track.id}/cover?size=small`
}; };