mirror of
https://github.com/jellyfin/jellyfin-web
synced 2025-03-30 19:56:21 +00:00
Merge pull request #4919 from grafixeyehero/Add-music-view
Add music view
This commit is contained in:
commit
5de2fc40b4
5 changed files with 171 additions and 23 deletions
|
@ -26,6 +26,7 @@ import { CollectionType } from 'types/collectionType';
|
||||||
import { LibraryTab } from 'types/libraryTab';
|
import { LibraryTab } from 'types/libraryTab';
|
||||||
|
|
||||||
import { CardOptions } from 'types/cardOptions';
|
import { CardOptions } from 'types/cardOptions';
|
||||||
|
import { ListOptions } from 'types/listOptions';
|
||||||
|
|
||||||
interface ItemsViewProps {
|
interface ItemsViewProps {
|
||||||
viewType: LibraryTab;
|
viewType: LibraryTab;
|
||||||
|
@ -77,12 +78,33 @@ const ItemsView: FC<ItemsViewProps> = ({
|
||||||
);
|
);
|
||||||
const { data: item } = useGetItem(parentId);
|
const { data: item } = useGetItem(parentId);
|
||||||
|
|
||||||
|
const getListOptions = useCallback(() => {
|
||||||
|
const listOptions: ListOptions = {
|
||||||
|
items: itemsResult?.Items ?? [],
|
||||||
|
context: collectionType
|
||||||
|
};
|
||||||
|
|
||||||
|
if (viewType === LibraryTab.Songs) {
|
||||||
|
listOptions.showParentTitle = true;
|
||||||
|
listOptions.action = 'playallfromhere';
|
||||||
|
listOptions.smallIcon = true;
|
||||||
|
listOptions.artist = true;
|
||||||
|
listOptions.addToListButton = true;
|
||||||
|
} else if (viewType === LibraryTab.Albums) {
|
||||||
|
listOptions.sortBy = libraryViewSettings.SortBy;
|
||||||
|
listOptions.addToListButton = true;
|
||||||
|
} else if (viewType === LibraryTab.Episodes) {
|
||||||
|
listOptions.showParentTitle = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return listOptions;
|
||||||
|
}, [itemsResult?.Items, collectionType, viewType, libraryViewSettings.SortBy]);
|
||||||
|
|
||||||
const getCardOptions = useCallback(() => {
|
const getCardOptions = useCallback(() => {
|
||||||
let shape;
|
let shape;
|
||||||
let preferThumb;
|
let preferThumb;
|
||||||
let preferDisc;
|
let preferDisc;
|
||||||
let preferLogo;
|
let preferLogo;
|
||||||
let lines = libraryViewSettings.ShowTitle ? 2 : 0;
|
|
||||||
|
|
||||||
if (libraryViewSettings.ImageType === ImageType.Banner) {
|
if (libraryViewSettings.ImageType === ImageType.Banner) {
|
||||||
shape = 'banner';
|
shape = 'banner';
|
||||||
|
@ -122,12 +144,9 @@ const ItemsView: FC<ItemsViewProps> = ({
|
||||||
) {
|
) {
|
||||||
cardOptions.showParentTitle = libraryViewSettings.ShowTitle;
|
cardOptions.showParentTitle = libraryViewSettings.ShowTitle;
|
||||||
} else if (viewType === LibraryTab.Artists) {
|
} else if (viewType === LibraryTab.Artists) {
|
||||||
cardOptions.showYear = false;
|
cardOptions.lines = 1;
|
||||||
lines = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
cardOptions.lines = lines;
|
|
||||||
|
|
||||||
return cardOptions;
|
return cardOptions;
|
||||||
}, [
|
}, [
|
||||||
libraryViewSettings.ShowTitle,
|
libraryViewSettings.ShowTitle,
|
||||||
|
@ -142,10 +161,7 @@ const ItemsView: FC<ItemsViewProps> = ({
|
||||||
let html = '';
|
let html = '';
|
||||||
|
|
||||||
if (libraryViewSettings.ViewMode === ViewMode.ListView) {
|
if (libraryViewSettings.ViewMode === ViewMode.ListView) {
|
||||||
html = listview.getListViewHtml({
|
html = listview.getListViewHtml(getListOptions());
|
||||||
items: itemsResult?.Items ?? [],
|
|
||||||
context: collectionType
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
html = cardBuilder.getCardsHtml(
|
html = cardBuilder.getCardsHtml(
|
||||||
itemsResult?.Items ?? [],
|
itemsResult?.Items ?? [],
|
||||||
|
@ -161,13 +177,7 @@ const ItemsView: FC<ItemsViewProps> = ({
|
||||||
}
|
}
|
||||||
|
|
||||||
return html;
|
return html;
|
||||||
}, [
|
}, [libraryViewSettings.ViewMode, itemsResult?.Items, getListOptions, getCardOptions, noItemsMessage]);
|
||||||
libraryViewSettings.ViewMode,
|
|
||||||
itemsResult?.Items,
|
|
||||||
collectionType,
|
|
||||||
getCardOptions,
|
|
||||||
noItemsMessage
|
|
||||||
]);
|
|
||||||
|
|
||||||
const totalRecordCount = itemsResult?.TotalRecordCount ?? 0;
|
const totalRecordCount = itemsResult?.TotalRecordCount ?? 0;
|
||||||
const items = itemsResult?.Items ?? [];
|
const items = itemsResult?.Items ?? [];
|
||||||
|
|
|
@ -6,5 +6,6 @@ export const ASYNC_USER_ROUTES: AsyncRoute[] = [
|
||||||
{ path: 'userprofile.html', page: 'user/userprofile' },
|
{ path: 'userprofile.html', page: 'user/userprofile' },
|
||||||
{ path: 'home.html', page: 'home', type: AsyncRouteType.Experimental },
|
{ path: 'home.html', page: 'home', type: AsyncRouteType.Experimental },
|
||||||
{ path: 'movies.html', page: 'movies', type: AsyncRouteType.Experimental },
|
{ path: 'movies.html', page: 'movies', type: AsyncRouteType.Experimental },
|
||||||
{ path: 'tv.html', page: 'shows', type: AsyncRouteType.Experimental }
|
{ path: 'tv.html', page: 'shows', type: AsyncRouteType.Experimental },
|
||||||
|
{ path: 'music.html', page: 'music', type: AsyncRouteType.Experimental }
|
||||||
];
|
];
|
||||||
|
|
|
@ -19,12 +19,6 @@ export const LEGACY_USER_ROUTES: LegacyRoute[] = [
|
||||||
controller: 'livetv/livetvsuggested',
|
controller: 'livetv/livetvsuggested',
|
||||||
view: 'livetv.html'
|
view: 'livetv.html'
|
||||||
}
|
}
|
||||||
}, {
|
|
||||||
path: 'music.html',
|
|
||||||
pageProps: {
|
|
||||||
controller: 'music/musicrecommended',
|
|
||||||
view: 'music/music.html'
|
|
||||||
}
|
|
||||||
}, {
|
}, {
|
||||||
path: 'mypreferencesmenu.html',
|
path: 'mypreferencesmenu.html',
|
||||||
pageProps: {
|
pageProps: {
|
||||||
|
|
94
src/apps/experimental/routes/music/index.tsx
Normal file
94
src/apps/experimental/routes/music/index.tsx
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
|
||||||
|
import React, { FC } from 'react';
|
||||||
|
import useCurrentTab from 'hooks/useCurrentTab';
|
||||||
|
import Page from 'components/Page';
|
||||||
|
import PageTabContent from '../../components/library/PageTabContent';
|
||||||
|
import { LibraryTab } from 'types/libraryTab';
|
||||||
|
import { CollectionType } from 'types/collectionType';
|
||||||
|
import { LibraryTabContent, LibraryTabMapping } from 'types/libraryTabContent';
|
||||||
|
import { SectionsView } from 'types/suggestionsSections';
|
||||||
|
|
||||||
|
const albumArtistsTabContent: LibraryTabContent = {
|
||||||
|
viewType: LibraryTab.AlbumArtists,
|
||||||
|
collectionType: CollectionType.Music,
|
||||||
|
isBtnSortEnabled: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const albumsTabContent: LibraryTabContent = {
|
||||||
|
viewType: LibraryTab.Albums,
|
||||||
|
collectionType: CollectionType.Music,
|
||||||
|
isBtnPlayAllEnabled: true,
|
||||||
|
isBtnShuffleEnabled: true,
|
||||||
|
itemType: [BaseItemKind.MusicAlbum]
|
||||||
|
};
|
||||||
|
|
||||||
|
const artistsTabContent: LibraryTabContent = {
|
||||||
|
viewType: LibraryTab.Artists,
|
||||||
|
collectionType: CollectionType.Music,
|
||||||
|
isBtnSortEnabled: false
|
||||||
|
};
|
||||||
|
|
||||||
|
const playlistsTabContent: LibraryTabContent = {
|
||||||
|
viewType: LibraryTab.Playlists,
|
||||||
|
isBtnFilterEnabled: false,
|
||||||
|
isBtnGridListEnabled: false,
|
||||||
|
isBtnSortEnabled: false,
|
||||||
|
isAlphabetPickerEnabled: false,
|
||||||
|
itemType: [BaseItemKind.Playlist]
|
||||||
|
};
|
||||||
|
|
||||||
|
const songsTabContent: LibraryTabContent = {
|
||||||
|
viewType: LibraryTab.Songs,
|
||||||
|
isBtnGridListEnabled: false,
|
||||||
|
isAlphabetPickerEnabled: false,
|
||||||
|
itemType: [BaseItemKind.Audio]
|
||||||
|
};
|
||||||
|
|
||||||
|
const suggestionsTabContent: LibraryTabContent = {
|
||||||
|
viewType: LibraryTab.Suggestions,
|
||||||
|
collectionType: CollectionType.Music,
|
||||||
|
sectionsType: {
|
||||||
|
suggestionSectionsView: [
|
||||||
|
SectionsView.LatestMusic,
|
||||||
|
SectionsView.FrequentlyPlayedMusic,
|
||||||
|
SectionsView.RecentlyPlayedMusic
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const genresTabContent: LibraryTabContent = {
|
||||||
|
viewType: LibraryTab.Genres,
|
||||||
|
collectionType: CollectionType.Music,
|
||||||
|
itemType: [BaseItemKind.MusicAlbum]
|
||||||
|
};
|
||||||
|
|
||||||
|
const musicTabMapping: LibraryTabMapping = {
|
||||||
|
0: albumsTabContent,
|
||||||
|
1: suggestionsTabContent,
|
||||||
|
2: albumArtistsTabContent,
|
||||||
|
3: artistsTabContent,
|
||||||
|
4: playlistsTabContent,
|
||||||
|
5: songsTabContent,
|
||||||
|
6: genresTabContent
|
||||||
|
};
|
||||||
|
|
||||||
|
const Music: FC = () => {
|
||||||
|
const { searchParamsParentId, currentTabIndex } = useCurrentTab();
|
||||||
|
const currentTab = musicTabMapping[currentTabIndex];
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Page
|
||||||
|
id='musicPage'
|
||||||
|
className='mainAnimatedPage libraryPage backdropPage collectionEditorPage pageWithAbsoluteTabs withTabs'
|
||||||
|
backDropType='musicartist'
|
||||||
|
>
|
||||||
|
<PageTabContent
|
||||||
|
key={`${currentTab.viewType} - ${searchParamsParentId}`}
|
||||||
|
currentTab={currentTab}
|
||||||
|
parentId={searchParamsParentId}
|
||||||
|
/>
|
||||||
|
</Page>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Music;
|
49
src/types/listOptions.ts
Normal file
49
src/types/listOptions.ts
Normal file
|
@ -0,0 +1,49 @@
|
||||||
|
import { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
|
||||||
|
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
|
||||||
|
import { CollectionType } from './collectionType';
|
||||||
|
|
||||||
|
export interface ListOptions {
|
||||||
|
items?: BaseItemDto[] | null;
|
||||||
|
index?: string;
|
||||||
|
showIndex?: boolean;
|
||||||
|
action?: string | null;
|
||||||
|
imageSize?: string;
|
||||||
|
enableOverview?: boolean;
|
||||||
|
enableSideMediaInfo?: boolean;
|
||||||
|
playlistId?: string | null;
|
||||||
|
collectionId?: string | null;
|
||||||
|
context?: CollectionType;
|
||||||
|
parentId?: string | null;
|
||||||
|
border?: boolean;
|
||||||
|
highlight?: boolean;
|
||||||
|
dragHandle?: boolean;
|
||||||
|
showIndexNumberLeft?: boolean;
|
||||||
|
mediaInfo?: boolean;
|
||||||
|
recordButton?: boolean;
|
||||||
|
image?: boolean;
|
||||||
|
imageSource?: string;
|
||||||
|
defaultCardImageIcon?: string;
|
||||||
|
disableIndicators?: boolean;
|
||||||
|
imagePlayButton?: boolean;
|
||||||
|
showProgramDateTime?: boolean;
|
||||||
|
showProgramTime?: boolean;
|
||||||
|
showChannel?: boolean;
|
||||||
|
showParentTitle?: boolean;
|
||||||
|
showIndexNumber?: boolean;
|
||||||
|
parentTitleWithTitle?: boolean;
|
||||||
|
artist?: boolean;
|
||||||
|
includeParentInfoInTitle?: boolean;
|
||||||
|
addToListButton?: boolean;
|
||||||
|
infoButton?: boolean;
|
||||||
|
enableUserDataButtons?: boolean;
|
||||||
|
moreButton?: boolean;
|
||||||
|
rightButtons?: {
|
||||||
|
icon: string;
|
||||||
|
title: string;
|
||||||
|
id: string;
|
||||||
|
}[];
|
||||||
|
enablePlayedButton?: boolean;
|
||||||
|
enableRatingButton?: boolean;
|
||||||
|
smallIcon?: boolean;
|
||||||
|
sortBy?: ItemSortBy;
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue