Skip to content

Commit

Permalink
refactor: use parallel fetching when possible (#2547)
Browse files Browse the repository at this point in the history
Signed-off-by: Fernando Fernández <[email protected]>
  • Loading branch information
ferferga authored Dec 29, 2024
1 parent 7a1d35c commit ad81868
Show file tree
Hide file tree
Showing 10 changed files with 221 additions and 195 deletions.
56 changes: 6 additions & 50 deletions frontend/src/components/Item/SeasonTabs.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
:lines="false"
bg-color="transparent">
<VListItem
v-for="episode in seasonEpisodes[season.Id]"
v-for="episode in seasonEpisodes.get(season.Id)"
:key="episode.Id"
:to="getItemDetailsLink(episode)">
<VRow
Expand Down Expand Up @@ -55,65 +55,21 @@
</template>

<script setup lang="ts">
import { type BaseItemDto, ItemFields } from '@jellyfin/sdk/lib/generated-client';
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
import { getTvShowsApi } from '@jellyfin/sdk/lib/utils/api/tv-shows-api';
import { ref, shallowRef, watch } from 'vue';
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
import { shallowRef } from 'vue';
import { getItemDetailsLink } from '@/utils/items';
import { remote } from '@/plugins/remote';
interface TvShowItem {
interface Props {
/**
* Seasons: Stores an array of all seasons
*/
seasons: BaseItemDto[];
/**
* SeasonEpisodes: Stores an array for each season containing all the season episodes
*/
seasonEpisodes: Record<string, BaseItemDto[]>;
seasonEpisodes: Map<BaseItemDto['Id'], BaseItemDto[]>;
}
const { item } = defineProps<{ item: BaseItemDto }>();
const { seasons, seasonEpisodes } = defineProps<Props>();
const currentTab = shallowRef(0);
const seasons = ref<BaseItemDto[] | null | undefined>([]);
const seasonEpisodes = ref<TvShowItem['seasonEpisodes']>({});
/**
* Fetch component data
*/
async function fetch(): Promise<void> {
if (!item.Id) {
return;
}
seasons.value = (
await remote.sdk.newUserApi(getTvShowsApi).getSeasons({
userId: remote.auth.currentUserId.value,
seriesId: item.Id
})
).data.Items;
if (seasons.value) {
for (const season of seasons.value) {
if (season.Id) {
const episodes = (
await remote.sdk.newUserApi(getItemsApi).getItems({
userId: remote.auth.currentUserId.value,
parentId: season.Id,
fields: [ItemFields.Overview, ItemFields.PrimaryImageAspectRatio]
})
).data;
if (episodes.Items) {
seasonEpisodes.value[season.Id] = episodes.Items;
}
}
}
}
}
await fetch();
watch(() => item, async () => {
await fetch();
});
</script>
5 changes: 4 additions & 1 deletion frontend/src/components/Layout/Artist/ArtistTab.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@
v-if="$vuetify.display.mdAndUp"
class="my-2">
<VCol>
<TrackList :item="release" />
<TrackList
:tracks
:item="release" />
</VCol>
</VRow>
</div>
Expand All @@ -47,6 +49,7 @@ import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
import { getItemDetailsLink } from '@/utils/items';
const { releases } = defineProps<{
tracks: BaseItemDto[];
releases: BaseItemDto[];
}>();
</script>
20 changes: 6 additions & 14 deletions frontend/src/components/Playback/TrackList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -115,28 +115,20 @@
</template>

<script setup lang="ts">
import {
SortOrder,
type BaseItemDto
import type {
BaseItemDto
} from '@jellyfin/sdk/lib/generated-client';
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
import { computed } from 'vue';
import { useBaseItem } from '@/composables/apis';
import { playbackManager } from '@/store/playback-manager';
import { getItemDetailsLink } from '@/utils/items';
import { formatTicks } from '@/utils/time';
const { item } = defineProps<{
const { item, tracks } = defineProps<{
item: BaseItemDto;
tracks: BaseItemDto[];
}>();
const { data: tracks } = await useBaseItem(getItemsApi, 'getItems')(() => ({
parentId: item.Id,
sortBy: ['SortName'],
sortOrder: [SortOrder.Ascending]
}));
const tracksPerDisc = computed(() => Object.groupBy(tracks.value, ({ ParentIndexNumber }) => ParentIndexNumber!));
const tracksPerDisc = computed(() => Object.groupBy(tracks, ({ ParentIndexNumber }) => ParentIndexNumber!));
const hasMultipleDiscs = computed(() => {
let loops = 0;
Expand Down Expand Up @@ -164,7 +156,7 @@ function isPlaying(track: BaseItemDto): boolean {
async function playTracks(track: BaseItemDto): Promise<void> {
await playbackManager.play({
item: item,
startFromIndex: tracks.value.indexOf(track),
startFromIndex: tracks.indexOf(track),
initiator: item
});
}
Expand Down
88 changes: 55 additions & 33 deletions frontend/src/pages/artist/[itemId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -75,16 +75,24 @@
v-model="activeTab"
class="bg-transparent">
<VWindowItem :value="0">
<ArtistTab :releases="discography" />
<ArtistTab
:tracks
:releases="discography" />
</VWindowItem>
<VWindowItem :value="1">
<ArtistTab :releases="albums" />
<ArtistTab
:tracks
:releases="albums" />
</VWindowItem>
<VWindowItem :value="2">
<ArtistTab :releases="eps" />
<ArtistTab
:tracks
:releases="eps" />
</VWindowItem>
<VWindowItem :value="3">
<ArtistTab :releases="singles" />
<ArtistTab
:tracks
:releases="singles" />
</VWindowItem>
<VWindowItem :value="4">
<VContainer>
Expand Down Expand Up @@ -167,35 +175,49 @@ const route = useRoute('/artist/[itemId]');
const activeTab = ref(0);
const { data: item } = await useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId: route.params.itemId
}));
const { data: relatedItems } = await useBaseItem(getLibraryApi, 'getSimilarItems')(() => ({
itemId: route.params.itemId,
limit: 5
}));
const { data: discography } = await useBaseItem(getItemsApi, 'getItems')(() => ({
albumArtistIds: [route.params.itemId],
sortBy,
sortOrder: [SortOrder.Descending],
recursive: true,
includeItemTypes: [BaseItemKind.MusicAlbum]
}));
const { data: appearances } = await useBaseItem(getItemsApi, 'getItems')(() => ({
contributingArtistIds: [route.params.itemId],
excludeItemIds: [route.params.itemId],
sortBy,
sortOrder: [SortOrder.Descending],
recursive: true,
includeItemTypes: [BaseItemKind.MusicAlbum]
}));
const { data: musicVideos } = await useBaseItem(getItemsApi, 'getItems')(() => ({
artistIds: [route.params.itemId],
sortBy,
sortOrder: [SortOrder.Descending],
recursive: true,
includeItemTypes: [BaseItemKind.MusicVideo]
}));
const [
{ data: item },
{ data: relatedItems },
{ data: discography },
{ data: appearances },
{ data: musicVideos },
{ data: tracks }
] = await Promise.all([
useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId: route.params.itemId
})),
useBaseItem(getLibraryApi, 'getSimilarItems')(() => ({
itemId: route.params.itemId,
limit: 5
})),
useBaseItem(getItemsApi, 'getItems')(() => ({
albumArtistIds: [route.params.itemId],
sortBy,
sortOrder: [SortOrder.Descending],
recursive: true,
includeItemTypes: [BaseItemKind.MusicAlbum]
})),
useBaseItem(getItemsApi, 'getItems')(() => ({
contributingArtistIds: [route.params.itemId],
excludeItemIds: [route.params.itemId],
sortBy,
sortOrder: [SortOrder.Descending],
recursive: true,
includeItemTypes: [BaseItemKind.MusicAlbum]
})),
useBaseItem(getItemsApi, 'getItems')(() => ({
artistIds: [route.params.itemId],
sortBy,
sortOrder: [SortOrder.Descending],
recursive: true,
includeItemTypes: [BaseItemKind.MusicVideo]
})),
useBaseItem(getItemsApi, 'getItems')(() => ({
parentId: route.params.itemId,
sortBy: ['SortName'],
sortOrder: [SortOrder.Ascending]
}))
]);
const singles = computed<BaseItemDto[]>(() =>
discography.value.filter(
Expand Down
27 changes: 14 additions & 13 deletions frontend/src/pages/genre/[itemId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -65,24 +65,25 @@ const route = useRoute('/genre/[itemId]');
const { itemId } = route.params;
const includeItemTypes = computed<BaseItemKind[]>(() => {
const typesQuery = route.query.type ?? [] as BaseItemKind;
const typesQuery = (route.query.type ?? []) as BaseItemKind[];
return isStr(typesQuery)
? [typesQuery]
? [typesQuery] as BaseItemKind[]
: typesQuery;
});
const { data: genre } = await useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId
}));
const { data: genres } = await useBaseItem(getItemsApi, 'getItems')(() => ({
genreIds: [itemId],
includeItemTypes: includeItemTypes.value,
recursive: true,
sortBy: ['SortName'],
sortOrder: [SortOrder.Ascending]
}));
const [{ data: genre }, { data: genres }] = await Promise.all([
useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId
})),
useBaseItem(getItemsApi, 'getItems')(() => ({
genreIds: [itemId],
includeItemTypes: includeItemTypes.value,
recursive: true,
sortBy: ['SortName'],
sortOrder: [SortOrder.Ascending]
}))
]);
useItemPageTitle(genre);
</script>
Expand Down
27 changes: 17 additions & 10 deletions frontend/src/pages/item/[itemId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -314,19 +314,26 @@ import { useItemPageTitle } from '@/composables/page-title';
const route = useRoute('/genre/[itemId]');
const { data: item } = await useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId: route.params.itemId
}));
const { data: relatedItems } = await useBaseItem(getLibraryApi, 'getSimilarItems')(() => ({
itemId: route.params.itemId,
limit: 12
}));
const [
{ data: item },
{ data: relatedItems },
{ data: childItems }
] = await Promise.all([
useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId: route.params.itemId
})),
useBaseItem(getLibraryApi, 'getSimilarItems')(() => ({
itemId: route.params.itemId,
limit: 12
})),
useBaseItem(getItemsApi, 'getItems')(() => ({
parentId: route.params.itemId
}))
]);
const { data: currentSeries } = await useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId: item.value.SeriesId ?? ''
}));
const { data: childItems } = await useBaseItem(getItemsApi, 'getItems')(() => ({
parentId: item.value.Id
}));
const selectedSource = ref<MediaSourceInfo>();
const currentVideoTrack = ref<number>();
Expand Down
26 changes: 18 additions & 8 deletions frontend/src/pages/musicalbum/[itemId].vue
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,8 @@
<VCol cols="12">
<TrackList
v-if="item.Type === 'MusicAlbum'"
:item="item" />
:item="item"
:tracks />
</VCol>
</VRow>
</template>
Expand All @@ -106,20 +107,29 @@
import { getLibraryApi } from '@jellyfin/sdk/lib/utils/api/library-api';
import { getUserLibraryApi } from '@jellyfin/sdk/lib/utils/api/user-library-api';
import { useRoute } from 'vue-router';
import { getItemsApi } from '@jellyfin/sdk/lib/utils/api/items-api';
import { SortOrder } from '@jellyfin/sdk/lib/generated-client';
import { getItemDetailsLink } from '@/utils/items';
import { useBaseItem } from '@/composables/apis';
import { useItemBackdrop } from '@/composables/backdrop';
import { useItemPageTitle } from '@/composables/page-title';
const route = useRoute('/musicalbum/[itemId]');
const { data: item } = await useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId: route.params.itemId
}));
const { data: relatedItems } = await useBaseItem(getLibraryApi, 'getSimilarItems')(() => ({
itemId: route.params.itemId,
limit: 5
}));
const [{ data: item }, { data: relatedItems }, { data: tracks }] = await Promise.all([
useBaseItem(getUserLibraryApi, 'getItem')(() => ({
itemId: route.params.itemId
})),
useBaseItem(getLibraryApi, 'getSimilarItems')(() => ({
itemId: route.params.itemId,
limit: 5
})),
useBaseItem(getItemsApi, 'getItems')(() => ({
parentId: route.params.itemId,
sortBy: ['SortName'],
sortOrder: [SortOrder.Ascending]
}))
]);
useItemPageTitle(item);
useItemBackdrop(item);
Expand Down
Loading

0 comments on commit ad81868

Please sign in to comment.