Implement "import history" in import page
This commit is contained in:
@ -15,10 +15,6 @@
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ trackCount }} track(s)
|
||||
</p>
|
||||
<Dot />
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ type }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2" v-if="hasProgress">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
@ -56,7 +52,7 @@
|
||||
</DropdownMenu>
|
||||
</div>
|
||||
|
||||
<Dialog :open="isDialogOpen">
|
||||
<Dialog :open="isDialogOpen" @update:open="toggleDialog">
|
||||
<DialogContent class="max-w-3xl">
|
||||
<DialogHeader>
|
||||
<DialogTitle>Playlist Upload Details</DialogTitle>
|
||||
@ -84,25 +80,19 @@
|
||||
<Label>Track Count</Label>
|
||||
<p class="text-sm">{{ trackCount }} tracks</p>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label>Type</Label>
|
||||
<p class="text-sm">{{ type }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div v-if="playlistProgressData?.ytdlnStdout" class="space-y-4">
|
||||
<div v-if="ytdlnStdout" class="space-y-4">
|
||||
<div class="flex justify-between items-center">
|
||||
<h3 class="text-lg font-semibold">yt-dlp Output</h3>
|
||||
<Button variant="outline" size="sm"
|
||||
@click="copyToClipboard(playlistProgressData.ytdlnStdout)">
|
||||
<Button variant="outline" size="sm" @click="copyToClipboard(ytdlnStdout)">
|
||||
<Copy class="mr-2 h-4 w-4" />
|
||||
Copy
|
||||
</Button>
|
||||
</div>
|
||||
<div class="bg-muted rounded-md p-4">
|
||||
<pre class="text-xs whitespace-pre-wrap overflow-x-auto max-h-60">{{
|
||||
playlistProgressData.ytdlnStdout }}</pre>
|
||||
<pre class="text-xs whitespace-pre-wrap overflow-x-auto max-h-60">{{ ytdlnStdout }}</pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -130,7 +120,6 @@
|
||||
import {
|
||||
CassetteTape,
|
||||
Copy,
|
||||
Dot,
|
||||
EllipsisVertical,
|
||||
Eye,
|
||||
FileQuestionMark,
|
||||
@ -139,22 +128,15 @@ import {
|
||||
Trash2
|
||||
} from 'lucide-vue-next';
|
||||
import { ref } from 'vue';
|
||||
import type { PlaylistProgressAllOfStatus } from '~/composeables/api/models';
|
||||
|
||||
interface Props {
|
||||
title: string
|
||||
trackCount?: number
|
||||
type?: string
|
||||
ytdlnStdout: string
|
||||
status: PlaylistProgressAllOfStatus
|
||||
progress?: number
|
||||
error?: string
|
||||
playlistProgressData?: {
|
||||
playlistId: number
|
||||
trackSourceId: number
|
||||
userId: number
|
||||
timestamp: number
|
||||
ytdlnStdout: string
|
||||
overallProgress: number
|
||||
status: 'LOADING' | 'FINISHED'
|
||||
}
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
@ -167,36 +149,34 @@ const emit = defineEmits<{
|
||||
|
||||
const isDialogOpen = ref(false);
|
||||
|
||||
const hasLoaded = props.trackCount && props.type;
|
||||
const hasLoaded = props.trackCount;
|
||||
const hasProgress = props.progress !== undefined && props.progress > 0;
|
||||
const hasError = props.error;
|
||||
|
||||
const openDialog = () => {
|
||||
isDialogOpen.value = true;
|
||||
console.log(isDialogOpen.value)
|
||||
};
|
||||
|
||||
const toggleDialog = (value: boolean) => {
|
||||
isDialogOpen.value = value;
|
||||
}
|
||||
|
||||
const getStatusColor = () => {
|
||||
if (hasError) return 'bg-destructive';
|
||||
if (props.playlistProgressData?.status === 'FINISHED') return 'bg-green-500';
|
||||
if (props.playlistProgressData?.status === 'LOADING') return 'bg-blue-500';
|
||||
if (props.status === 'FINISHED') return 'bg-green-500';
|
||||
if (props.status === 'LOADING') return 'bg-blue-500';
|
||||
if (hasProgress) return 'bg-amber-500';
|
||||
return 'bg-gray-500';
|
||||
};
|
||||
|
||||
const getStatusText = () => {
|
||||
if (hasError) return 'Error';
|
||||
if (props.playlistProgressData?.status === 'FINISHED') return 'Completed';
|
||||
if (props.playlistProgressData?.status === 'LOADING') return 'Loading';
|
||||
if (props.status === 'FINISHED') return 'Completed';
|
||||
if (props.status === 'LOADING') return 'Loading';
|
||||
if (hasProgress) return 'In Progress';
|
||||
return 'Pending';
|
||||
};
|
||||
|
||||
const formatTimestamp = (timestamp?: number) => {
|
||||
if (!timestamp) return 'N/A';
|
||||
return new Date(timestamp).toLocaleString();
|
||||
};
|
||||
|
||||
const copyToClipboard = async (text: string) => {
|
||||
try {
|
||||
await navigator.clipboard.writeText(text);
|
||||
|
||||
@ -19,10 +19,6 @@
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ format }}
|
||||
</p>
|
||||
<Dot />
|
||||
<p class="text-sm text-muted-foreground">
|
||||
{{ type }}
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex flex-row items-center gap-2" v-if="hasProgress">
|
||||
<p class="text-sm text-muted-foreground">
|
||||
@ -85,10 +81,6 @@
|
||||
<Label>Size</Label>
|
||||
<p class="text-sm">{{ size }}</p>
|
||||
</div>
|
||||
<div class="space-y-2">
|
||||
<Label>Type</Label>
|
||||
<p class="text-sm">{{ type }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -194,7 +186,6 @@ interface Props {
|
||||
title: string
|
||||
size?: string
|
||||
format?: string
|
||||
type?: string
|
||||
progress?: number
|
||||
error?: string
|
||||
trackProgressData?: {
|
||||
@ -219,7 +210,7 @@ const emit = defineEmits<{
|
||||
|
||||
const isDialogOpen = ref(false);
|
||||
|
||||
const hasLoaded = props.size && props.format && props.type;
|
||||
const hasLoaded = props.size && props.format;
|
||||
const hasProgress = props.progress !== undefined && props.progress > 0;
|
||||
const hasError = props.error;
|
||||
|
||||
|
||||
27
app/components/internal/import/uploadentry/UploadEntry.vue
Normal file
27
app/components/internal/import/uploadentry/UploadEntry.vue
Normal file
@ -0,0 +1,27 @@
|
||||
<template>
|
||||
<SingleUploadEntry v-if="entry.type === 'TRACK'" :title="(entry as SingleTrackProgressAllOf).title || ''" :size="''"
|
||||
:format="(entry as SingleTrackProgressAllOf).format || ''" />
|
||||
<PlaylistUploadEntry v-if="entry.type === 'PLAYLIST'" title=""
|
||||
:trackCount="(entry as PlaylistProgressAllOf).trackCount"
|
||||
:ytdlnStdout="(entry as PlaylistProgressAllOf).ytdlnStdout || ''"
|
||||
:status="(entry as PlaylistProgressAllOf).status || 'LOADING'" />
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { PlaylistProgressAllOf, PlaylistProgressAllOfStatus, SingleTrackProgressAllOf, StreamProgress200Item } from '~/composeables/api/models';
|
||||
import SingleUploadEntry from './SingleUploadEntry.vue';
|
||||
import PlaylistUploadEntry from './PlaylistUploadEntry.vue';
|
||||
|
||||
interface Props {
|
||||
entry: StreamProgress200Item
|
||||
}
|
||||
|
||||
const props = withDefaults(defineProps<Props>(), {
|
||||
});
|
||||
|
||||
const emit = defineEmits<{
|
||||
retry: []
|
||||
download: []
|
||||
play: []
|
||||
}>();
|
||||
</script>
|
||||
@ -1,6 +1,12 @@
|
||||
<script setup lang="ts">
|
||||
import { FileMusicIcon } from 'lucide-vue-next';
|
||||
import PlaylistCreateDialog from './PlaylistCreateDialog.vue';
|
||||
import Empty from '@/components/ui/empty/Empty.vue';
|
||||
import EmptyHeader from '@/components/ui/empty/EmptyHeader.vue';
|
||||
import EmptyMedia from '@/components/ui/empty/EmptyMedia.vue';
|
||||
import EmptyTitle from '@/components/ui/empty/EmptyTitle.vue';
|
||||
import EmptyDescription from '@/components/ui/empty/EmptyDescription.vue';
|
||||
import EmptyContent from '@/components/ui/empty/EmptyContent.vue';
|
||||
|
||||
</script>
|
||||
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
import Axios, { type AxiosRequestConfig, type AxiosResponse } from 'axios';
|
||||
export const AXIOS_INSTANCE = Axios.create();
|
||||
|
||||
export const axiosInstance = <T>(
|
||||
const axiosInstance = <T>(
|
||||
config: AxiosRequestConfig,
|
||||
options?: AxiosRequestConfig,
|
||||
): Promise<AxiosResponse<T, any>> => {
|
||||
@ -13,7 +13,7 @@ export const axiosInstance = <T>(
|
||||
...options,
|
||||
baseURL: baseURL,
|
||||
auth: {
|
||||
username: 'user',
|
||||
username: 'user1',
|
||||
password: 'password',
|
||||
}
|
||||
},
|
||||
@ -23,3 +23,4 @@ export const axiosInstance = <T>(
|
||||
return promise;
|
||||
};
|
||||
|
||||
export default axiosInstance;
|
||||
|
||||
94
app/composeables/api/event-source.ts
Normal file
94
app/composeables/api/event-source.ts
Normal file
@ -0,0 +1,94 @@
|
||||
import type { AxiosRequestConfig } from "axios";
|
||||
import { ErrorEvent, EventSource } from 'eventsource'
|
||||
|
||||
type Unarray<T> = T extends Array<infer U> ? U : T;
|
||||
|
||||
export interface EventSourceListener<T> {
|
||||
handle: (callback: (data: T) => void) => EventSourceListener<T>;
|
||||
close: () => void;
|
||||
onError: (callback: (error: ErrorEvent) => void) => EventSourceListener<T>;
|
||||
onOpen: (callback: (event: Event) => void) => EventSourceListener<T>;
|
||||
}
|
||||
|
||||
const eventSource = <T>(
|
||||
config: AxiosRequestConfig,
|
||||
options?: AxiosRequestConfig,
|
||||
): Promise<EventSourceListener<Unarray<T>>> => {
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const baseURL = useRuntimeConfig().public.apiBaseUrl;
|
||||
const endpoint = config.url;
|
||||
const eventSource = new EventSource(baseURL + endpoint, {
|
||||
fetch: (input, init) => fetch(input, {
|
||||
...init,
|
||||
headers: {
|
||||
...init.headers,
|
||||
Authorization: 'Basic ' + btoa('user1' + ":" + 'password'),
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
let messageCallback: ((data: Unarray<T>) => void) | null = null;
|
||||
let errorCallback: ((error: ErrorEvent) => void) | null = null;
|
||||
let openCallback: ((event: Event) => void) | null = null;
|
||||
|
||||
eventSource.addEventListener("message", (event: MessageEvent<any>) => {
|
||||
if (messageCallback) {
|
||||
try {
|
||||
let data = JSON.parse(event.data) as Unarray<T>;
|
||||
messageCallback(data);
|
||||
} catch (error) {
|
||||
console.error('Error parsing EventSource data:', error);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
eventSource.addEventListener('error', (event) => {
|
||||
if (errorCallback) {
|
||||
errorCallback(event);
|
||||
}
|
||||
});
|
||||
|
||||
eventSource.addEventListener('open', (event) => {
|
||||
if (openCallback) {
|
||||
openCallback(event);
|
||||
}
|
||||
});
|
||||
|
||||
const listener: EventSourceListener<Unarray<T>> = {
|
||||
handle: (callback: (data: Unarray<T>) => void) => {
|
||||
messageCallback = callback;
|
||||
return listener;
|
||||
},
|
||||
|
||||
onError: (callback: (error: ErrorEvent) => void) => {
|
||||
errorCallback = callback;
|
||||
return listener;
|
||||
},
|
||||
|
||||
onOpen: (callback: (event: Event) => void) => {
|
||||
openCallback = callback;
|
||||
return listener;
|
||||
},
|
||||
|
||||
close: () => {
|
||||
eventSource.close();
|
||||
messageCallback = null;
|
||||
errorCallback = null;
|
||||
openCallback = null;
|
||||
}
|
||||
};
|
||||
|
||||
resolve(listener);
|
||||
setTimeout(() => {
|
||||
if (eventSource.readyState === EventSource.CLOSED && !errorCallback) {
|
||||
reject(new Error('EventSource connection failed'));
|
||||
}
|
||||
}, 5000);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export default eventSource;
|
||||
16
app/composeables/api/models/baseTrackProgress.ts
Normal file
16
app/composeables/api/models/baseTrackProgress.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
import type { BaseTrackProgressType } from './baseTrackProgressType';
|
||||
|
||||
export interface BaseTrackProgress {
|
||||
id?: string;
|
||||
playlistId?: number;
|
||||
trackSourceId?: number;
|
||||
userId?: number;
|
||||
timestamp?: number;
|
||||
type?: BaseTrackProgressType;
|
||||
}
|
||||
16
app/composeables/api/models/baseTrackProgressType.ts
Normal file
16
app/composeables/api/models/baseTrackProgressType.ts
Normal file
@ -0,0 +1,16 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
|
||||
export type BaseTrackProgressType = typeof BaseTrackProgressType[keyof typeof BaseTrackProgressType];
|
||||
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
||||
export const BaseTrackProgressType = {
|
||||
PLAYLIST: 'PLAYLIST',
|
||||
TRACK: 'TRACK',
|
||||
EXTERNAL_TRACK: 'EXTERNAL_TRACK',
|
||||
} as const;
|
||||
@ -6,14 +6,19 @@
|
||||
*/
|
||||
|
||||
export * from './addLocalTrackRequest';
|
||||
export * from './playlistCreateDTO';
|
||||
export * from './baseTrackProgress';
|
||||
export * from './baseTrackProgressType';
|
||||
export * from './playlistCreateRequest';
|
||||
export * from './playlistReadDTO';
|
||||
export * from './playlistProgress';
|
||||
export * from './playlistProgressAllOf';
|
||||
export * from './playlistProgressAllOfStatus';
|
||||
export * from './playlistReadResponse';
|
||||
export * from './playlistTrackResponse';
|
||||
export * from './readParams';
|
||||
export * from './singleTrackProgress';
|
||||
export * from './singleTrackProgressAllOf';
|
||||
export * from './streamProgress200Item';
|
||||
export * from './trackBulkReorderRequest';
|
||||
export * from './trackReoderAfterRequest';
|
||||
export * from './trackReorderAfterRequest';
|
||||
export * from './trackResponse';
|
||||
export * from './uploadBody';
|
||||
export * from './uploadBody';
|
||||
export * from './youtubeTrackRequest';
|
||||
10
app/composeables/api/models/playlistProgress.ts
Normal file
10
app/composeables/api/models/playlistProgress.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
import type { BaseTrackProgress } from './baseTrackProgress';
|
||||
import type { PlaylistProgressAllOf } from './playlistProgressAllOf';
|
||||
|
||||
export type PlaylistProgress = BaseTrackProgress & PlaylistProgressAllOf;
|
||||
14
app/composeables/api/models/playlistProgressAllOf.ts
Normal file
14
app/composeables/api/models/playlistProgressAllOf.ts
Normal file
@ -0,0 +1,14 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
import type { PlaylistProgressAllOfStatus } from './playlistProgressAllOfStatus';
|
||||
|
||||
export type PlaylistProgressAllOf = {
|
||||
ytdlnStdout?: string;
|
||||
overallProgress?: number;
|
||||
trackCount?: number;
|
||||
status?: PlaylistProgressAllOfStatus;
|
||||
};
|
||||
15
app/composeables/api/models/playlistProgressAllOfStatus.ts
Normal file
15
app/composeables/api/models/playlistProgressAllOfStatus.ts
Normal file
@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
|
||||
export type PlaylistProgressAllOfStatus = typeof PlaylistProgressAllOfStatus[keyof typeof PlaylistProgressAllOfStatus];
|
||||
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-redeclare
|
||||
export const PlaylistProgressAllOfStatus = {
|
||||
LOADING: 'LOADING',
|
||||
FINISHED: 'FINISHED',
|
||||
} as const;
|
||||
@ -1,14 +0,0 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
|
||||
export interface PlaylistReadDTO {
|
||||
id?: number;
|
||||
ownerId?: number;
|
||||
title?: string;
|
||||
createdAt?: string;
|
||||
updatedAt?: string;
|
||||
}
|
||||
10
app/composeables/api/models/singleTrackProgress.ts
Normal file
10
app/composeables/api/models/singleTrackProgress.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
import type { BaseTrackProgress } from './baseTrackProgress';
|
||||
import type { SingleTrackProgressAllOf } from './singleTrackProgressAllOf';
|
||||
|
||||
export type SingleTrackProgress = BaseTrackProgress & SingleTrackProgressAllOf;
|
||||
@ -5,6 +5,7 @@
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
|
||||
export interface PlaylistCreateDTO {
|
||||
export type SingleTrackProgressAllOf = {
|
||||
title?: string;
|
||||
}
|
||||
format?: string;
|
||||
};
|
||||
10
app/composeables/api/models/streamProgress200Item.ts
Normal file
10
app/composeables/api/models/streamProgress200Item.ts
Normal file
@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
import type { PlaylistProgress } from './playlistProgress';
|
||||
import type { SingleTrackProgress } from './singleTrackProgress';
|
||||
|
||||
export type StreamProgress200Item = PlaylistProgress | SingleTrackProgress;
|
||||
@ -10,6 +10,7 @@ export interface TrackResponse {
|
||||
title?: string;
|
||||
artist?: string;
|
||||
audioPath?: string;
|
||||
fileFormat?: string;
|
||||
durationSeconds?: number;
|
||||
fileName?: string;
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
|
||||
export interface TrackReorderAfterRequest {
|
||||
moveTrackId?: number;
|
||||
targetTrackId?: number;
|
||||
export interface YoutubeTrackRequest {
|
||||
youtubeUrl?: string;
|
||||
}
|
||||
@ -32,7 +32,8 @@ import type {
|
||||
PlaylistReadResponse
|
||||
} from '.././models';
|
||||
|
||||
import { axiosInstance } from '.././axios-instance';
|
||||
import createPlaylistMutator from '.././axios-instance';
|
||||
import playlistsMutator from '.././axios-instance';
|
||||
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
@ -41,11 +42,11 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
export const createPlaylist = (
|
||||
playlistCreateRequest: MaybeRef<PlaylistCreateRequest>,
|
||||
options?: SecondParameter<typeof axiosInstance>,signal?: AbortSignal
|
||||
options?: SecondParameter<typeof createPlaylistMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
playlistCreateRequest = unref(playlistCreateRequest);
|
||||
|
||||
return axiosInstance<PlaylistReadResponse>(
|
||||
return createPlaylistMutator<PlaylistReadResponse>(
|
||||
{url: `/playlist`, method: 'POST',
|
||||
headers: {'Content-Type': 'application/json', },
|
||||
data: playlistCreateRequest, signal
|
||||
@ -56,7 +57,7 @@ export const createPlaylist = (
|
||||
|
||||
|
||||
export const getCreatePlaylistMutationOptions = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof createPlaylist>>, TError,{data: PlaylistCreateRequest}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof createPlaylist>>, TError,{data: PlaylistCreateRequest}, TContext>, request?: SecondParameter<typeof createPlaylistMutator>}
|
||||
): UseMutationOptions<Awaited<ReturnType<typeof createPlaylist>>, TError,{data: PlaylistCreateRequest}, TContext> => {
|
||||
|
||||
const mutationKey = ['createPlaylist'];
|
||||
@ -85,7 +86,7 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
export type CreatePlaylistMutationError = unknown
|
||||
|
||||
export const useCreatePlaylist = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof createPlaylist>>, TError,{data: PlaylistCreateRequest}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof createPlaylist>>, TError,{data: PlaylistCreateRequest}, TContext>, request?: SecondParameter<typeof createPlaylistMutator>}
|
||||
, queryClient?: QueryClient): UseMutationReturnType<
|
||||
Awaited<ReturnType<typeof createPlaylist>>,
|
||||
TError,
|
||||
@ -99,11 +100,11 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
}
|
||||
export const playlists = (
|
||||
|
||||
options?: SecondParameter<typeof axiosInstance>,signal?: AbortSignal
|
||||
options?: SecondParameter<typeof playlistsMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
|
||||
|
||||
return axiosInstance<PlaylistReadResponse[]>(
|
||||
return playlistsMutator<PlaylistReadResponse[]>(
|
||||
{url: `/playlists`, method: 'GET', signal
|
||||
},
|
||||
options);
|
||||
@ -119,7 +120,7 @@ export const getPlaylistsQueryKey = () => {
|
||||
}
|
||||
|
||||
|
||||
export const getPlaylistsQueryOptions = <TData = Awaited<ReturnType<typeof playlists>>, TError = unknown>( options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof playlists>>, TError, TData>>, request?: SecondParameter<typeof axiosInstance>}
|
||||
export const getPlaylistsQueryOptions = <TData = Awaited<ReturnType<typeof playlists>>, TError = unknown>( options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof playlists>>, TError, TData>>, request?: SecondParameter<typeof playlistsMutator>}
|
||||
) => {
|
||||
|
||||
const {query: queryOptions, request: requestOptions} = options ?? {};
|
||||
@ -143,7 +144,7 @@ export type PlaylistsQueryError = unknown
|
||||
|
||||
|
||||
export function usePlaylists<TData = Awaited<ReturnType<typeof playlists>>, TError = unknown>(
|
||||
options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof playlists>>, TError, TData>>, request?: SecondParameter<typeof axiosInstance>}
|
||||
options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof playlists>>, TError, TData>>, request?: SecondParameter<typeof playlistsMutator>}
|
||||
, queryClient?: QueryClient
|
||||
): UseQueryReturnType<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
|
||||
|
||||
|
||||
@ -0,0 +1,99 @@
|
||||
/**
|
||||
* Generated by orval v7.16.0 🍺
|
||||
* Do not edit manually.
|
||||
* OpenAPI definition
|
||||
* OpenAPI spec version: v0
|
||||
*/
|
||||
import {
|
||||
useQuery
|
||||
} from '@tanstack/vue-query';
|
||||
import type {
|
||||
DataTag,
|
||||
QueryClient,
|
||||
QueryFunction,
|
||||
QueryKey,
|
||||
UseQueryOptions,
|
||||
UseQueryReturnType
|
||||
} from '@tanstack/vue-query';
|
||||
|
||||
import {
|
||||
computed,
|
||||
unref
|
||||
} from 'vue';
|
||||
import type {
|
||||
MaybeRef
|
||||
} from 'vue';
|
||||
|
||||
import type {
|
||||
StreamProgress200Item
|
||||
} from '.././models';
|
||||
|
||||
import streamProgressMutator from '.././event-source';
|
||||
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
|
||||
|
||||
export const streamProgress = (
|
||||
playlistId: MaybeRef<number>,
|
||||
options?: SecondParameter<typeof streamProgressMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
playlistId = unref(playlistId);
|
||||
|
||||
return streamProgressMutator<StreamProgress200Item[]>(
|
||||
{url: `/importing/stream/${playlistId}`, method: 'GET', signal
|
||||
},
|
||||
options);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
export const getStreamProgressQueryKey = (playlistId?: MaybeRef<number>,) => {
|
||||
return [
|
||||
'importing','stream',playlistId
|
||||
] as const;
|
||||
}
|
||||
|
||||
|
||||
export const getStreamProgressQueryOptions = <TData = Awaited<ReturnType<typeof streamProgress>>, TError = unknown>(playlistId: MaybeRef<number>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof streamProgress>>, TError, TData>>, request?: SecondParameter<typeof streamProgressMutator>}
|
||||
) => {
|
||||
|
||||
const {query: queryOptions, request: requestOptions} = options ?? {};
|
||||
|
||||
const queryKey = getStreamProgressQueryKey(playlistId);
|
||||
|
||||
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof streamProgress>>> = ({ signal }) => streamProgress(playlistId, requestOptions, signal);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return { queryKey, queryFn, enabled: computed(() => !!(unref(playlistId))), ...queryOptions} as UseQueryOptions<Awaited<ReturnType<typeof streamProgress>>, TError, TData>
|
||||
}
|
||||
|
||||
export type StreamProgressQueryResult = NonNullable<Awaited<ReturnType<typeof streamProgress>>>
|
||||
export type StreamProgressQueryError = unknown
|
||||
|
||||
|
||||
|
||||
export function useStreamProgress<TData = Awaited<ReturnType<typeof streamProgress>>, TError = unknown>(
|
||||
playlistId: MaybeRef<number>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof streamProgress>>, TError, TData>>, request?: SecondParameter<typeof streamProgressMutator>}
|
||||
, queryClient?: QueryClient
|
||||
): UseQueryReturnType<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
|
||||
|
||||
const queryOptions = getStreamProgressQueryOptions(playlistId,options)
|
||||
|
||||
const query = useQuery(queryOptions, queryClient) as UseQueryReturnType<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> };
|
||||
|
||||
query.queryKey = unref(queryOptions).queryKey as DataTag<QueryKey, TData, TError>;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@ -32,7 +32,8 @@ import type {
|
||||
UploadBody
|
||||
} from '.././models';
|
||||
|
||||
import { axiosInstance } from '.././axios-instance';
|
||||
import uploadMutator from '.././axios-instance';
|
||||
import readMutator from '.././axios-instance';
|
||||
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
@ -41,13 +42,13 @@ type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
export const upload = (
|
||||
uploadBody: MaybeRef<UploadBody>,
|
||||
options?: SecondParameter<typeof axiosInstance>,signal?: AbortSignal
|
||||
options?: SecondParameter<typeof uploadMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
uploadBody = unref(uploadBody);
|
||||
const formData = new FormData();
|
||||
formData.append(`document`, uploadBody.document)
|
||||
|
||||
return axiosInstance<string>(
|
||||
return uploadMutator<string>(
|
||||
{url: `/upload`, method: 'POST',
|
||||
headers: {'Content-Type': 'multipart/form-data', },
|
||||
data: formData, signal
|
||||
@ -58,7 +59,7 @@ formData.append(`document`, uploadBody.document)
|
||||
|
||||
|
||||
export const getUploadMutationOptions = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof upload>>, TError,{data: UploadBody}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof upload>>, TError,{data: UploadBody}, TContext>, request?: SecondParameter<typeof uploadMutator>}
|
||||
): UseMutationOptions<Awaited<ReturnType<typeof upload>>, TError,{data: UploadBody}, TContext> => {
|
||||
|
||||
const mutationKey = ['upload'];
|
||||
@ -87,7 +88,7 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
export type UploadMutationError = unknown
|
||||
|
||||
export const useUpload = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof upload>>, TError,{data: UploadBody}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof upload>>, TError,{data: UploadBody}, TContext>, request?: SecondParameter<typeof uploadMutator>}
|
||||
, queryClient?: QueryClient): UseMutationReturnType<
|
||||
Awaited<ReturnType<typeof upload>>,
|
||||
TError,
|
||||
@ -101,11 +102,11 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
}
|
||||
export const read = (
|
||||
params: MaybeRef<ReadParams>,
|
||||
options?: SecondParameter<typeof axiosInstance>,signal?: AbortSignal
|
||||
options?: SecondParameter<typeof readMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
params = unref(params);
|
||||
|
||||
return axiosInstance<string>(
|
||||
return readMutator<string>(
|
||||
{url: `/read`, method: 'GET',
|
||||
params: unref(params), signal
|
||||
},
|
||||
@ -122,7 +123,7 @@ export const getReadQueryKey = (params?: MaybeRef<ReadParams>,) => {
|
||||
}
|
||||
|
||||
|
||||
export const getReadQueryOptions = <TData = Awaited<ReturnType<typeof read>>, TError = unknown>(params: MaybeRef<ReadParams>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof read>>, TError, TData>>, request?: SecondParameter<typeof axiosInstance>}
|
||||
export const getReadQueryOptions = <TData = Awaited<ReturnType<typeof read>>, TError = unknown>(params: MaybeRef<ReadParams>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof read>>, TError, TData>>, request?: SecondParameter<typeof readMutator>}
|
||||
) => {
|
||||
|
||||
const {query: queryOptions, request: requestOptions} = options ?? {};
|
||||
@ -146,7 +147,7 @@ export type ReadQueryError = unknown
|
||||
|
||||
|
||||
export function useRead<TData = Awaited<ReturnType<typeof read>>, TError = unknown>(
|
||||
params: MaybeRef<ReadParams>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof read>>, TError, TData>>, request?: SecondParameter<typeof axiosInstance>}
|
||||
params: MaybeRef<ReadParams>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof read>>, TError, TData>>, request?: SecondParameter<typeof readMutator>}
|
||||
, queryClient?: QueryClient
|
||||
): UseQueryReturnType<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
|
||||
|
||||
|
||||
@ -32,27 +32,150 @@ import type {
|
||||
AddLocalTrackRequest,
|
||||
PlaylistTrackResponse,
|
||||
TrackBulkReorderRequest,
|
||||
TrackResponse
|
||||
TrackResponse,
|
||||
YoutubeTrackRequest
|
||||
} from '.././models';
|
||||
|
||||
import { axiosInstance } from '.././axios-instance';
|
||||
import addYoutubeTrackMutator from '.././axios-instance';
|
||||
import addYoutubeTrack1Mutator from '.././axios-instance';
|
||||
import addLocalTrackMutator from '.././axios-instance';
|
||||
import bulkReorderMutator from '.././axios-instance';
|
||||
import getPlaylistTracksMutator from '.././axios-instance';
|
||||
|
||||
|
||||
type SecondParameter<T extends (...args: never) => unknown> = Parameters<T>[1];
|
||||
|
||||
|
||||
|
||||
export const addLocalTrack = (
|
||||
export const addYoutubeTrack = (
|
||||
playlistId: MaybeRef<number>,
|
||||
youtubeTrackRequest: MaybeRef<YoutubeTrackRequest>,
|
||||
options?: SecondParameter<typeof addYoutubeTrackMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
playlistId = unref(playlistId);
|
||||
youtubeTrackRequest = unref(youtubeTrackRequest);
|
||||
|
||||
return addYoutubeTrackMutator<TrackResponse[]>(
|
||||
{url: `/playlist/${playlistId}/track/youtube`, method: 'POST',
|
||||
headers: {'Content-Type': 'application/json', },
|
||||
data: youtubeTrackRequest, signal
|
||||
},
|
||||
options);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const getAddYoutubeTrackMutationOptions = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addYoutubeTrack>>, TError,{playlistId: number;data: YoutubeTrackRequest}, TContext>, request?: SecondParameter<typeof addYoutubeTrackMutator>}
|
||||
): UseMutationOptions<Awaited<ReturnType<typeof addYoutubeTrack>>, TError,{playlistId: number;data: YoutubeTrackRequest}, TContext> => {
|
||||
|
||||
const mutationKey = ['addYoutubeTrack'];
|
||||
const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
|
||||
options
|
||||
: {...options, mutation: {...options.mutation, mutationKey}}
|
||||
: {mutation: { mutationKey, }, request: undefined};
|
||||
|
||||
|
||||
|
||||
|
||||
const mutationFn: MutationFunction<Awaited<ReturnType<typeof addYoutubeTrack>>, {playlistId: number;data: YoutubeTrackRequest}> = (props) => {
|
||||
const {playlistId,data} = props ?? {};
|
||||
|
||||
return addYoutubeTrack(playlistId,data,requestOptions)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return { mutationFn, ...mutationOptions }}
|
||||
|
||||
export type AddYoutubeTrackMutationResult = NonNullable<Awaited<ReturnType<typeof addYoutubeTrack>>>
|
||||
export type AddYoutubeTrackMutationBody = YoutubeTrackRequest
|
||||
export type AddYoutubeTrackMutationError = unknown
|
||||
|
||||
export const useAddYoutubeTrack = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addYoutubeTrack>>, TError,{playlistId: number;data: YoutubeTrackRequest}, TContext>, request?: SecondParameter<typeof addYoutubeTrackMutator>}
|
||||
, queryClient?: QueryClient): UseMutationReturnType<
|
||||
Awaited<ReturnType<typeof addYoutubeTrack>>,
|
||||
TError,
|
||||
{playlistId: number;data: YoutubeTrackRequest},
|
||||
TContext
|
||||
> => {
|
||||
|
||||
const mutationOptions = getAddYoutubeTrackMutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions, queryClient);
|
||||
}
|
||||
export const addYoutubeTrack1 = (
|
||||
playlistId: MaybeRef<number>,
|
||||
sourceId: MaybeRef<number>,
|
||||
options?: SecondParameter<typeof addYoutubeTrack1Mutator>,signal?: AbortSignal
|
||||
) => {
|
||||
playlistId = unref(playlistId);
|
||||
sourceId = unref(sourceId);
|
||||
|
||||
return addYoutubeTrack1Mutator<TrackResponse[]>(
|
||||
{url: `/playlist/${playlistId}/track/youtube/refresh/${sourceId}`, method: 'POST', signal
|
||||
},
|
||||
options);
|
||||
}
|
||||
|
||||
|
||||
|
||||
export const getAddYoutubeTrack1MutationOptions = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addYoutubeTrack1>>, TError,{playlistId: number;sourceId: number}, TContext>, request?: SecondParameter<typeof addYoutubeTrack1Mutator>}
|
||||
): UseMutationOptions<Awaited<ReturnType<typeof addYoutubeTrack1>>, TError,{playlistId: number;sourceId: number}, TContext> => {
|
||||
|
||||
const mutationKey = ['addYoutubeTrack1'];
|
||||
const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
options.mutation && 'mutationKey' in options.mutation && options.mutation.mutationKey ?
|
||||
options
|
||||
: {...options, mutation: {...options.mutation, mutationKey}}
|
||||
: {mutation: { mutationKey, }, request: undefined};
|
||||
|
||||
|
||||
|
||||
|
||||
const mutationFn: MutationFunction<Awaited<ReturnType<typeof addYoutubeTrack1>>, {playlistId: number;sourceId: number}> = (props) => {
|
||||
const {playlistId,sourceId} = props ?? {};
|
||||
|
||||
return addYoutubeTrack1(playlistId,sourceId,requestOptions)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
return { mutationFn, ...mutationOptions }}
|
||||
|
||||
export type AddYoutubeTrack1MutationResult = NonNullable<Awaited<ReturnType<typeof addYoutubeTrack1>>>
|
||||
|
||||
export type AddYoutubeTrack1MutationError = unknown
|
||||
|
||||
export const useAddYoutubeTrack1 = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addYoutubeTrack1>>, TError,{playlistId: number;sourceId: number}, TContext>, request?: SecondParameter<typeof addYoutubeTrack1Mutator>}
|
||||
, queryClient?: QueryClient): UseMutationReturnType<
|
||||
Awaited<ReturnType<typeof addYoutubeTrack1>>,
|
||||
TError,
|
||||
{playlistId: number;sourceId: number},
|
||||
TContext
|
||||
> => {
|
||||
|
||||
const mutationOptions = getAddYoutubeTrack1MutationOptions(options);
|
||||
|
||||
return useMutation(mutationOptions, queryClient);
|
||||
}
|
||||
export const addLocalTrack = (
|
||||
playlistId: MaybeRef<number>,
|
||||
addLocalTrackRequest: MaybeRef<AddLocalTrackRequest>,
|
||||
options?: SecondParameter<typeof axiosInstance>,signal?: AbortSignal
|
||||
options?: SecondParameter<typeof addLocalTrackMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
playlistId = unref(playlistId);
|
||||
addLocalTrackRequest = unref(addLocalTrackRequest);
|
||||
const formData = new FormData();
|
||||
formData.append(`source`, addLocalTrackRequest.source)
|
||||
|
||||
return axiosInstance<TrackResponse>(
|
||||
return addLocalTrackMutator<TrackResponse>(
|
||||
{url: `/playlist/${playlistId}/track/local`, method: 'POST',
|
||||
headers: {'Content-Type': 'multipart/form-data', },
|
||||
data: formData, signal
|
||||
@ -63,7 +186,7 @@ formData.append(`source`, addLocalTrackRequest.source)
|
||||
|
||||
|
||||
export const getAddLocalTrackMutationOptions = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addLocalTrack>>, TError,{playlistId: number;data: AddLocalTrackRequest}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addLocalTrack>>, TError,{playlistId: number;data: AddLocalTrackRequest}, TContext>, request?: SecondParameter<typeof addLocalTrackMutator>}
|
||||
): UseMutationOptions<Awaited<ReturnType<typeof addLocalTrack>>, TError,{playlistId: number;data: AddLocalTrackRequest}, TContext> => {
|
||||
|
||||
const mutationKey = ['addLocalTrack'];
|
||||
@ -92,7 +215,7 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
export type AddLocalTrackMutationError = unknown
|
||||
|
||||
export const useAddLocalTrack = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addLocalTrack>>, TError,{playlistId: number;data: AddLocalTrackRequest}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof addLocalTrack>>, TError,{playlistId: number;data: AddLocalTrackRequest}, TContext>, request?: SecondParameter<typeof addLocalTrackMutator>}
|
||||
, queryClient?: QueryClient): UseMutationReturnType<
|
||||
Awaited<ReturnType<typeof addLocalTrack>>,
|
||||
TError,
|
||||
@ -107,12 +230,12 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
export const bulkReorder = (
|
||||
playlistId: MaybeRef<number>,
|
||||
trackBulkReorderRequest: MaybeRef<TrackBulkReorderRequest>,
|
||||
options?: SecondParameter<typeof axiosInstance>,signal?: AbortSignal
|
||||
options?: SecondParameter<typeof bulkReorderMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
playlistId = unref(playlistId);
|
||||
trackBulkReorderRequest = unref(trackBulkReorderRequest);
|
||||
|
||||
return axiosInstance<void>(
|
||||
return bulkReorderMutator<void>(
|
||||
{url: `/playlist/${playlistId}/bulk-reorder`, method: 'POST',
|
||||
headers: {'Content-Type': 'application/json', },
|
||||
data: trackBulkReorderRequest, signal
|
||||
@ -123,7 +246,7 @@ trackBulkReorderRequest = unref(trackBulkReorderRequest);
|
||||
|
||||
|
||||
export const getBulkReorderMutationOptions = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof bulkReorder>>, TError,{playlistId: number;data: TrackBulkReorderRequest}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof bulkReorder>>, TError,{playlistId: number;data: TrackBulkReorderRequest}, TContext>, request?: SecondParameter<typeof bulkReorderMutator>}
|
||||
): UseMutationOptions<Awaited<ReturnType<typeof bulkReorder>>, TError,{playlistId: number;data: TrackBulkReorderRequest}, TContext> => {
|
||||
|
||||
const mutationKey = ['bulkReorder'];
|
||||
@ -152,7 +275,7 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
export type BulkReorderMutationError = unknown
|
||||
|
||||
export const useBulkReorder = <TError = unknown,
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof bulkReorder>>, TError,{playlistId: number;data: TrackBulkReorderRequest}, TContext>, request?: SecondParameter<typeof axiosInstance>}
|
||||
TContext = unknown>(options?: { mutation?:UseMutationOptions<Awaited<ReturnType<typeof bulkReorder>>, TError,{playlistId: number;data: TrackBulkReorderRequest}, TContext>, request?: SecondParameter<typeof bulkReorderMutator>}
|
||||
, queryClient?: QueryClient): UseMutationReturnType<
|
||||
Awaited<ReturnType<typeof bulkReorder>>,
|
||||
TError,
|
||||
@ -166,11 +289,11 @@ const {mutation: mutationOptions, request: requestOptions} = options ?
|
||||
}
|
||||
export const getPlaylistTracks = (
|
||||
playlistId: MaybeRef<number>,
|
||||
options?: SecondParameter<typeof axiosInstance>,signal?: AbortSignal
|
||||
options?: SecondParameter<typeof getPlaylistTracksMutator>,signal?: AbortSignal
|
||||
) => {
|
||||
playlistId = unref(playlistId);
|
||||
|
||||
return axiosInstance<PlaylistTrackResponse[]>(
|
||||
return getPlaylistTracksMutator<PlaylistTrackResponse[]>(
|
||||
{url: `/playlist/${playlistId}/tracks`, method: 'GET', signal
|
||||
},
|
||||
options);
|
||||
@ -186,7 +309,7 @@ export const getGetPlaylistTracksQueryKey = (playlistId?: MaybeRef<number>,) =>
|
||||
}
|
||||
|
||||
|
||||
export const getGetPlaylistTracksQueryOptions = <TData = Awaited<ReturnType<typeof getPlaylistTracks>>, TError = unknown>(playlistId: MaybeRef<number>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getPlaylistTracks>>, TError, TData>>, request?: SecondParameter<typeof axiosInstance>}
|
||||
export const getGetPlaylistTracksQueryOptions = <TData = Awaited<ReturnType<typeof getPlaylistTracks>>, TError = unknown>(playlistId: MaybeRef<number>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getPlaylistTracks>>, TError, TData>>, request?: SecondParameter<typeof getPlaylistTracksMutator>}
|
||||
) => {
|
||||
|
||||
const {query: queryOptions, request: requestOptions} = options ?? {};
|
||||
@ -210,7 +333,7 @@ export type GetPlaylistTracksQueryError = unknown
|
||||
|
||||
|
||||
export function useGetPlaylistTracks<TData = Awaited<ReturnType<typeof getPlaylistTracks>>, TError = unknown>(
|
||||
playlistId: MaybeRef<number>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getPlaylistTracks>>, TError, TData>>, request?: SecondParameter<typeof axiosInstance>}
|
||||
playlistId: MaybeRef<number>, options?: { query?:Partial<UseQueryOptions<Awaited<ReturnType<typeof getPlaylistTracks>>, TError, TData>>, request?: SecondParameter<typeof getPlaylistTracksMutator>}
|
||||
, queryClient?: QueryClient
|
||||
): UseQueryReturnType<TData, TError> & { queryKey: DataTag<QueryKey, TData, TError> } {
|
||||
|
||||
|
||||
@ -1,9 +1,62 @@
|
||||
<script setup lang="ts">
|
||||
import { Download, Play } from 'lucide-vue-next';
|
||||
import PlaylistUploadEntry from '@/components/internal/import/uploadentry/PlaylistUploadEntry.vue';
|
||||
import SingleUploadEntry from '@/components/internal/import/uploadentry/SingleUploadEntry.vue';
|
||||
import Outline from '@/components/ui/outline/Outline.vue';
|
||||
import SidebarTrigger from '@/components/ui/sidebar/SidebarTrigger.vue';
|
||||
import Empty from '@/components/ui/empty/Empty.vue';
|
||||
import UploadEntry from '@/components/internal/import/uploadentry/UploadEntry.vue';
|
||||
import EmptyHeader from '@/components/ui/empty/EmptyHeader.vue';
|
||||
import EmptyMedia from '@/components/ui/empty/EmptyMedia.vue';
|
||||
import EmptyTitle from '@/components/ui/empty/EmptyTitle.vue';
|
||||
import EmptyDescription from '@/components/ui/empty/EmptyDescription.vue';
|
||||
|
||||
import { Download, MegaphoneOff, Play } from 'lucide-vue-next';
|
||||
import type { EventSourceListener } from '~/composeables/api/event-source';
|
||||
import type { StreamProgress200Item } from '~/composeables/api/models';
|
||||
import { streamProgress } from '~/composeables/api/progress-sse-controller/progress-sse-controller';
|
||||
import { useCurrentPlaylistStore } from '~/stores/use-current-playlist-store';
|
||||
|
||||
const currentPlaylistStore = useCurrentPlaylistStore();
|
||||
const progressEntries = ref<Map<string, StreamProgress200Item>>(new Map());
|
||||
let listener: EventSourceListener<StreamProgress200Item> | null = null;
|
||||
|
||||
const unwatch = watch(() => currentPlaylistStore.id, (newId, oldId) => {
|
||||
if (newId !== -1 && newId !== oldId) {
|
||||
listenImports();
|
||||
} else if (newId === -1) {
|
||||
stopImports();
|
||||
}
|
||||
}, { immediate: true });
|
||||
|
||||
const updateEntryFromProgress = (data: StreamProgress200Item) => {
|
||||
if (!data.trackSourceId)
|
||||
return;
|
||||
progressEntries.value = new Map(progressEntries.value);
|
||||
progressEntries.value.set(data.id!.toString(), data);
|
||||
}
|
||||
|
||||
async function listenImports() {
|
||||
if (listener) {
|
||||
listener.close();
|
||||
}
|
||||
streamProgress(currentPlaylistStore.id).then(listener => {
|
||||
listener.handle(data => {
|
||||
updateEntryFromProgress(data);
|
||||
})
|
||||
}).catch(err => {
|
||||
console.error(err);
|
||||
})
|
||||
}
|
||||
|
||||
function stopImports() {
|
||||
if (listener) {
|
||||
listener.close();
|
||||
listener = null;
|
||||
}
|
||||
}
|
||||
|
||||
onUnmounted(() => {
|
||||
stopImports();
|
||||
unwatch();
|
||||
});
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -38,24 +91,19 @@ import SidebarTrigger from '@/components/ui/sidebar/SidebarTrigger.vue';
|
||||
Uploaded files
|
||||
</h3>
|
||||
<div class="space-y-2">
|
||||
<SingleUploadEntry title="Test" size="3.8 MB" format="mp4" type="file" />
|
||||
<SingleUploadEntry title="Test" :progress="78" />
|
||||
<SingleUploadEntry title="Test" error="Uploading failed, please check your internet" />
|
||||
<PlaylistUploadEntry title="My Playlist" :trackCount="10" type="YouTube" :progress="75"
|
||||
:playlistProgressData="{
|
||||
playlistId: 1,
|
||||
trackSourceId: 2,
|
||||
userId: 3,
|
||||
timestamp: 123456,
|
||||
ytdlnStdout: `[youtube] Extracting URL: https://www.youtube.com/playlist?list=PL1234567890
|
||||
[youtube:playlist] PL1234567890: Downloading 10 videos
|
||||
[download] Destination: My Playlist [PL1234567890].mp3
|
||||
[ExtractAudio] Destination: My Playlist [PL1234567890].mp3
|
||||
[info] Download completed: My Playlist [PL1234567890].mp3
|
||||
[info] 10 files downloaded successfully`,
|
||||
overallProgress: 34,
|
||||
status: 'LOADING'
|
||||
}" />
|
||||
<UploadEntry v-for="entry in Array.from(progressEntries.values())" :key="entry.id"
|
||||
:entry="entry" />
|
||||
<Empty class="border border-dashed" v-if="progressEntries.size === 0">
|
||||
<EmptyHeader>
|
||||
<EmptyMedia variant="icon">
|
||||
<MegaphoneOff />
|
||||
</EmptyMedia>
|
||||
<EmptyTitle>No imports found</EmptyTitle>
|
||||
<EmptyDescription>
|
||||
Upload any track to see their progress.
|
||||
</EmptyDescription>
|
||||
</EmptyHeader>
|
||||
</Empty>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
5
bun.lock
5
bun.lock
@ -17,6 +17,7 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"dotenv": "^17.2.3",
|
||||
"eventsource": "^4.1.0",
|
||||
"lucide-vue-next": "^0.548.0",
|
||||
"nuxt": "^4.2.0",
|
||||
"oidc-client-ts": "^3.3.0",
|
||||
@ -1000,6 +1001,10 @@
|
||||
|
||||
"events-universal": ["events-universal@1.0.1", "", { "dependencies": { "bare-events": "^2.7.0" } }, "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw=="],
|
||||
|
||||
"eventsource": ["eventsource@4.1.0", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-2GuF51iuHX6A9xdTccMTsNb7VO0lHZihApxhvQzJB5A03DvHDd2FQepodbMaztPBmBcE/ox7o2gqaxGhYB9LhQ=="],
|
||||
|
||||
"eventsource-parser": ["eventsource-parser@3.0.6", "", {}, "sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg=="],
|
||||
|
||||
"execa": ["execa@5.1.1", "", { "dependencies": { "cross-spawn": "^7.0.3", "get-stream": "^6.0.0", "human-signals": "^2.1.0", "is-stream": "^2.0.0", "merge-stream": "^2.0.0", "npm-run-path": "^4.0.1", "onetime": "^5.1.2", "signal-exit": "^3.0.3", "strip-final-newline": "^2.0.0" } }, "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg=="],
|
||||
|
||||
"expand-template": ["expand-template@2.0.3", "", {}, "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="],
|
||||
|
||||
@ -26,8 +26,12 @@ export default defineConfig({
|
||||
override: {
|
||||
mutator: {
|
||||
path: './app/composeables/api/axios-instance.ts',
|
||||
name: 'axiosInstance',
|
||||
},
|
||||
operations: {
|
||||
streamProgress: {
|
||||
mutator: './app/composeables/api/event-source.ts',
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@ -22,6 +22,7 @@
|
||||
"class-variance-authority": "^0.7.1",
|
||||
"clsx": "^2.1.1",
|
||||
"dotenv": "^17.2.3",
|
||||
"eventsource": "^4.1.0",
|
||||
"lucide-vue-next": "^0.548.0",
|
||||
"nuxt": "^4.2.0",
|
||||
"oidc-client-ts": "^3.3.0",
|
||||
|
||||
Reference in New Issue
Block a user