Initial commit

This commit is contained in:
TelepathicWalrus 2023-12-06 17:57:35 +00:00 committed by Bill Thornton
parent 7671d08591
commit e5a55daf55
20 changed files with 46 additions and 56 deletions

12
package-lock.json generated
View file

@ -3611,9 +3611,9 @@
"dev": true "dev": true
}, },
"node_modules/@jellyfin/sdk": { "node_modules/@jellyfin/sdk": {
"version": "0.0.0-unstable.202307130502", "version": "0.0.0-unstable.202312060501",
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202307130502.tgz", "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202312060501.tgz",
"integrity": "sha512-1+GXATaJLP5akFnUrpxYzoshLtTPZXJEdy/ozhY1g/DkULlz4LthLTaTJ2qImF0mb8Ayk7LNbh00n4ATk0JycA==", "integrity": "sha512-4+5xf/mfgcFJjSlMLnmi2saFVEVSuubtJ/QTxK4d4f56tsGbluoDajydOWZPGbx4+Q/iB9ESWIJ1GRXgkEBRZg==",
"peerDependencies": { "peerDependencies": {
"axios": "^1.3.4" "axios": "^1.3.4"
} }
@ -24829,9 +24829,9 @@
"dev": true "dev": true
}, },
"@jellyfin/sdk": { "@jellyfin/sdk": {
"version": "0.0.0-unstable.202307130502", "version": "0.0.0-unstable.202312060501",
"resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202307130502.tgz", "resolved": "https://registry.npmjs.org/@jellyfin/sdk/-/sdk-0.0.0-unstable.202312060501.tgz",
"integrity": "sha512-1+GXATaJLP5akFnUrpxYzoshLtTPZXJEdy/ozhY1g/DkULlz4LthLTaTJ2qImF0mb8Ayk7LNbh00n4ATk0JycA==", "integrity": "sha512-4+5xf/mfgcFJjSlMLnmi2saFVEVSuubtJ/QTxK4d4f56tsGbluoDajydOWZPGbx4+Q/iB9ESWIJ1GRXgkEBRZg==",
"requires": {} "requires": {}
}, },
"@jest/schemas": { "@jest/schemas": {

View file

@ -254,7 +254,7 @@ const UserEdit: FunctionComponent = () => {
user.Policy.SyncPlayAccess = (page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value as SyncPlayUserAccessType; user.Policy.SyncPlayAccess = (page.querySelector('#selectSyncPlayAccess') as HTMLSelectElement).value as SyncPlayUserAccessType;
window.ApiClient.updateUser(user).then(() => ( window.ApiClient.updateUser(user).then(() => (
window.ApiClient.updateUserPolicy(user.Id || '', user.Policy || {}) window.ApiClient.updateUserPolicy(user.Id || '', user.Policy || { PasswordResetProviderId: '', AuthenticationProviderId: '' })
)).then(() => { )).then(() => {
onSaveComplete(); onSaveComplete();
}).catch(err => { }).catch(err => {

View file

@ -11,7 +11,7 @@ import Collections from '@mui/icons-material/Collections';
import Queue from '@mui/icons-material/Queue'; import Queue from '@mui/icons-material/Queue';
import Folder from '@mui/icons-material/Folder'; import Folder from '@mui/icons-material/Folder';
import React, { FC } from 'react'; import React, { FC } from 'react';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
interface LibraryIconProps { interface LibraryIconProps {
item: BaseItemDto item: BaseItemDto

View file

@ -4,7 +4,7 @@ import { useGetGenres } from 'hooks/useFetchItems';
import globalize from 'scripts/globalize'; import globalize from 'scripts/globalize';
import Loading from 'components/loading/LoadingComponent'; import Loading from 'components/loading/LoadingComponent';
import GenresSectionContainer from './GenresSectionContainer'; import GenresSectionContainer from './GenresSectionContainer';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import { ParentId } from 'types/library'; import { ParentId } from 'types/library';
interface GenresItemsContainerProps { interface GenresItemsContainerProps {

View file

@ -11,7 +11,7 @@ import { useGetItems } from 'hooks/useFetchItems';
import Loading from 'components/loading/LoadingComponent'; import Loading from 'components/loading/LoadingComponent';
import { appRouter } from 'components/router/appRouter'; import { appRouter } from 'components/router/appRouter';
import SectionContainer from './SectionContainer'; import SectionContainer from './SectionContainer';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import { ParentId } from 'types/library'; import { ParentId } from 'types/library';
interface GenresSectionContainerProps { interface GenresSectionContainerProps {

View file

@ -2,7 +2,7 @@ import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-ite
import React, { FC } from 'react'; import React, { FC } from 'react';
import GenresItemsContainer from './GenresItemsContainer'; import GenresItemsContainer from './GenresItemsContainer';
import { ParentId } from 'types/library'; import { ParentId } from 'types/library';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
interface GenresViewProps { interface GenresViewProps {
parentId: ParentId; parentId: ParentId;

View file

@ -23,7 +23,7 @@ import ShuffleButton from './ShuffleButton';
import SortButton from './SortButton'; import SortButton from './SortButton';
import GridListViewButton from './GridListViewButton'; import GridListViewButton from './GridListViewButton';
import { LibraryViewSettings, ParentId, ViewMode } from 'types/library'; import { LibraryViewSettings, ParentId, ViewMode } from 'types/library';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import { LibraryTab } from 'types/libraryTab'; import { LibraryTab } from 'types/libraryTab';
import { CardOptions } from 'types/cardOptions'; import { CardOptions } from 'types/cardOptions';

View file

@ -4,7 +4,7 @@ import useCurrentTab from 'hooks/useCurrentTab';
import Page from 'components/Page'; import Page from 'components/Page';
import PageTabContent from '../../components/library/PageTabContent'; import PageTabContent from '../../components/library/PageTabContent';
import { LibraryTab } from 'types/libraryTab'; import { LibraryTab } from 'types/libraryTab';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import { LibraryTabContent, LibraryTabMapping } from 'types/libraryTabContent'; import { LibraryTabContent, LibraryTabMapping } from 'types/libraryTabContent';
import { MovieSuggestionsSectionsView } from 'types/sections'; import { MovieSuggestionsSectionsView } from 'types/sections';

View file

@ -4,7 +4,7 @@ import useCurrentTab from 'hooks/useCurrentTab';
import Page from 'components/Page'; import Page from 'components/Page';
import PageTabContent from '../../components/library/PageTabContent'; import PageTabContent from '../../components/library/PageTabContent';
import { LibraryTab } from 'types/libraryTab'; import { LibraryTab } from 'types/libraryTab';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import { LibraryTabContent, LibraryTabMapping } from 'types/libraryTabContent'; import { LibraryTabContent, LibraryTabMapping } from 'types/libraryTabContent';
import { MusicSuggestionsSectionsView } from 'types/sections'; import { MusicSuggestionsSectionsView } from 'types/sections';

View file

@ -4,7 +4,7 @@ import useCurrentTab from 'hooks/useCurrentTab';
import Page from 'components/Page'; import Page from 'components/Page';
import PageTabContent from '../../components/library/PageTabContent'; import PageTabContent from '../../components/library/PageTabContent';
import { LibraryTab } from 'types/libraryTab'; import { LibraryTab } from 'types/libraryTab';
import { CollectionType } from 'types/collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import { LibraryTabContent, LibraryTabMapping } from 'types/libraryTabContent'; import { LibraryTabContent, LibraryTabMapping } from 'types/libraryTabContent';
import { TvShowSuggestionsSectionsView } from 'types/sections'; import { TvShowSuggestionsSectionsView } from 'types/sections';

View file

@ -1,6 +1,7 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto'; import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client/models/base-item-dto';
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind'; import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client/models/base-item-kind';
import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto'; import type { UserDto } from '@jellyfin/sdk/lib/generated-client/models/user-dto';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import escapeHtml from 'escape-html'; import escapeHtml from 'escape-html';
import type { ApiClient } from 'jellyfin-apiclient'; import type { ApiClient } from 'jellyfin-apiclient';
@ -24,12 +25,12 @@ function getFetchLatestItemsFn(
let limit = 16; let limit = 16;
if (enableOverflow) { if (enableOverflow) {
if (collectionType === 'music') { if (collectionType === CollectionType.Music) {
limit = 30; limit = 30;
} }
} else if (collectionType === 'tvshows') { } else if (collectionType === CollectionType.TvShows) {
limit = 5; limit = 5;
} else if (collectionType === 'music') { } else if (collectionType === CollectionType.Music) {
limit = 9; limit = 9;
} else { } else {
limit = 8; limit = 8;

View file

@ -1,5 +1,6 @@
import { appHost } from './apphost'; import { appHost } from './apphost';
import globalize from '../scripts/globalize'; import globalize from '../scripts/globalize';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
export function getDisplayName(item, options = {}) { export function getDisplayName(item, options = {}) {
if (!item) { if (!item) {
@ -79,7 +80,7 @@ export function supportsAddingToPlaylist(item) {
if (isLocalItem(item)) { if (isLocalItem(item)) {
return false; return false;
} }
if (item.CollectionType === 'livetv') { if (item.CollectionType === CollectionType.LiveTv) {
return false; return false;
} }
@ -230,7 +231,7 @@ export function canConvert (item, user) {
} }
const collectionType = item.CollectionType; const collectionType = item.CollectionType;
if (collectionType === 'livetv') { if (collectionType === CollectionType.LiveTv) {
return false; return false;
} }
@ -249,7 +250,7 @@ export function canConvert (item, user) {
export function canRefreshMetadata (item, user) { export function canRefreshMetadata (item, user) {
if (user.Policy.IsAdministrator) { if (user.Policy.IsAdministrator) {
const collectionType = item.CollectionType; const collectionType = item.CollectionType;
if (collectionType === 'livetv') { if (collectionType === CollectionType.LiveTv) {
return false; return false;
} }

View file

@ -10,6 +10,7 @@ import viewManager from '../viewManager/viewManager';
import ServerConnections from '../ServerConnections'; import ServerConnections from '../ServerConnections';
import alert from '../alert'; import alert from '../alert';
import { ConnectionState } from '../../utils/jellyfin-apiclient/ConnectionState.ts'; import { ConnectionState } from '../../utils/jellyfin-apiclient/ConnectionState.ts';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
export const history = createHashHistory(); export const history = createHashHistory();
@ -623,7 +624,7 @@ class AppRouter {
return '#/details?seriesTimerId=' + id + '&serverId=' + serverId; return '#/details?seriesTimerId=' + id + '&serverId=' + serverId;
} }
if (item.CollectionType == 'livetv') { if (item.CollectionType == CollectionType.LiveTv) {
return '#/livetv.html'; return '#/livetv.html';
} }
@ -662,7 +663,7 @@ class AppRouter {
} }
if (context !== 'folders' && !itemHelper.isLocalItem(item)) { if (context !== 'folders' && !itemHelper.isLocalItem(item)) {
if (item.CollectionType == 'movies') { if (item.CollectionType == 'Movies') {
url = '#/movies.html?topParentId=' + item.Id; url = '#/movies.html?topParentId=' + item.Id;
if (options && options.section === 'latest') { if (options && options.section === 'latest') {
@ -672,7 +673,7 @@ class AppRouter {
return url; return url;
} }
if (item.CollectionType == 'tvshows') { if (item.CollectionType == CollectionType.TvShows) {
url = '#/tv.html?topParentId=' + item.Id; url = '#/tv.html?topParentId=' + item.Id;
if (options && options.section === 'latest') { if (options && options.section === 'latest') {
@ -682,7 +683,7 @@ class AppRouter {
return url; return url;
} }
if (item.CollectionType == 'music') { if (item.CollectionType == CollectionType.Music) {
url = '#/music.html?topParentId=' + item.Id; url = '#/music.html?topParentId=' + item.Id;
if (options?.section === 'latest') { if (options?.section === 'latest') {

View file

@ -1,5 +1,6 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'; import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
import type { ApiClient } from 'jellyfin-apiclient'; import type { ApiClient } from 'jellyfin-apiclient';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import classNames from 'classnames'; import classNames from 'classnames';
import React, { FunctionComponent, useEffect, useState } from 'react'; import React, { FunctionComponent, useEffect, useState } from 'react';
@ -72,7 +73,7 @@ const LiveTVSearchResults: FunctionComponent<LiveTVSearchResultsProps> = ({ serv
setPrograms([]); setPrograms([]);
setChannels([]); setChannels([]);
if (query && collectionType === 'livetv') { if (query && collectionType === CollectionType.LiveTv) {
const apiClient = ServerConnections.getApiClient(serverId); const apiClient = ServerConnections.getApiClient(serverId);
// Movies row // Movies row
@ -138,7 +139,7 @@ const LiveTVSearchResults: FunctionComponent<LiveTVSearchResultsProps> = ({ serv
'searchResults', 'searchResults',
'padded-bottom-page', 'padded-bottom-page',
'padded-top', 'padded-top',
{ 'hide': !query || collectionType !== 'livetv' } { 'hide': !query || collectionType !== CollectionType.LiveTv }
)} )}
> >
<SearchResultsRow <SearchResultsRow

View file

@ -2,6 +2,7 @@ import type { BaseItemDto, BaseItemDtoQueryResult } from '@jellyfin/sdk/lib/gene
import type { ApiClient } from 'jellyfin-apiclient'; import type { ApiClient } from 'jellyfin-apiclient';
import classNames from 'classnames'; import classNames from 'classnames';
import React, { FunctionComponent, useCallback, useEffect, useState } from 'react'; import React, { FunctionComponent, useCallback, useEffect, useState } from 'react';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import globalize from '../../scripts/globalize'; import globalize from '../../scripts/globalize';
import ServerConnections from '../ServerConnections'; import ServerConnections from '../ServerConnections';
@ -20,11 +21,11 @@ const ensureNonNullItems = (result: BaseItemDtoQueryResult) => ({
Items: result.Items || [] Items: result.Items || []
}); });
const isMovies = (collectionType: string) => collectionType === 'movies'; const isMovies = (collectionType: string) => collectionType === CollectionType.Movies;
const isMusic = (collectionType: string) => collectionType === 'music'; const isMusic = (collectionType: string) => collectionType === CollectionType.Music;
const isTVShows = (collectionType: string) => collectionType === 'tvshows' || collectionType === 'tv'; const isTVShows = (collectionType: string) => collectionType === CollectionType.TvShows;
/* /*
* React component to display search result rows for global search and non-live tv library search * React component to display search result rows for global search and non-live tv library search
@ -239,7 +240,7 @@ const SearchResults: FunctionComponent<SearchResultsProps> = ({ serverId = windo
'searchResults', 'searchResults',
'padded-bottom-page', 'padded-bottom-page',
'padded-top', 'padded-top',
{ 'hide': !query || collectionType === 'livetv' } { 'hide': !query || collectionType === CollectionType.LiveTv }
)} )}
> >
{isLoading ? ( {isLoading ? (

View file

@ -12,6 +12,7 @@ import '../elements/emby-itemscontainer/emby-itemscontainer';
import '../elements/emby-scroller/emby-scroller'; import '../elements/emby-scroller/emby-scroller';
import ServerConnections from '../components/ServerConnections'; import ServerConnections from '../components/ServerConnections';
import LibraryMenu from '../scripts/libraryMenu'; import LibraryMenu from '../scripts/libraryMenu';
import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
function getInitialLiveTvQuery(instance, params, startIndex = 0, limit = 300) { function getInitialLiveTvQuery(instance, params, startIndex = 0, limit = 300) {
const query = { const query = {
@ -306,9 +307,9 @@ function getItems(instance, params, item, sortBy, startIndex, limit) {
if (item.Type === 'MusicGenre') { if (item.Type === 'MusicGenre') {
query.IncludeItemTypes = 'MusicAlbum'; query.IncludeItemTypes = 'MusicAlbum';
} else if (item.CollectionType === 'movies') { } else if (item.CollectionType === CollectionType.Movies) {
query.IncludeItemTypes = 'Movie'; query.IncludeItemTypes = 'Movie';
} else if (item.CollectionType === 'tvshows') { } else if (item.CollectionType === CollectionType.TvShows) {
query.IncludeItemTypes = 'Series'; query.IncludeItemTypes = 'Series';
} else if (item.Type === 'Genre') { } else if (item.Type === 'Genre') {
query.IncludeItemTypes = 'Movie,Series,Video'; query.IncludeItemTypes = 'Movie,Series,Video';
@ -605,7 +606,7 @@ class ItemsView {
posterOptions.lines = lines; posterOptions.lines = lines;
posterOptions.items = items; posterOptions.items = items;
if (item && item.CollectionType === 'folders') { if (item && item.CollectionType === CollectionType.Folders) {
posterOptions.context = 'folders'; posterOptions.context = 'folders';
} }
@ -635,7 +636,7 @@ class ItemsView {
function setTitle(item) { function setTitle(item) {
LibraryMenu.setTitle(getTitle(item) || ''); LibraryMenu.setTitle(getTitle(item) || '');
if (item && item.CollectionType === 'playlists') { if (item && item.CollectionType === CollectionType.Playlists) {
hideOrShowAll(view.querySelectorAll('.btnNewItem'), false); hideOrShowAll(view.querySelectorAll('.btnNewItem'), false);
} else { } else {
hideOrShowAll(view.querySelectorAll('.btnNewItem'), true); hideOrShowAll(view.querySelectorAll('.btnNewItem'), true);
@ -865,7 +866,7 @@ class ItemsView {
// Folder, Playlist views // Folder, Playlist views
&& itemType !== 'UserView' && itemType !== 'UserView'
// Only Photo (homevideos) CollectionFolders are supported // Only Photo (homevideos) CollectionFolders are supported
&& !(itemType === 'CollectionFolder' && item?.CollectionType !== 'homevideos') && !(itemType === 'CollectionFolder' && item?.CollectionType !== CollectionType.HomeVideos)
) { ) {
// Show Play All buttons // Show Play All buttons
hideOrShowAll(view.querySelectorAll('.btnPlay'), false); hideOrShowAll(view.querySelectorAll('.btnPlay'), false);
@ -878,7 +879,7 @@ class ItemsView {
// Folder, Playlist views // Folder, Playlist views
&& itemType !== 'UserView' && itemType !== 'UserView'
// Only Photo (homevideos) CollectionFolders are supported // Only Photo (homevideos) CollectionFolders are supported
&& !(itemType === 'CollectionFolder' && item?.CollectionType !== 'homevideos') && !(itemType === 'CollectionFolder' && item?.CollectionType !== CollectionType.HomeVideos)
) { ) {
// Show Shuffle buttons // Show Shuffle buttons
hideOrShowAll(view.querySelectorAll('.btnShuffle'), false); hideOrShowAll(view.querySelectorAll('.btnShuffle'), false);

View file

@ -1,5 +1,5 @@
import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client'; import type { BaseItemDto } from '@jellyfin/sdk/lib/generated-client';
import { CollectionType } from './collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
export interface CardOptions { export interface CardOptions {
itemsContainer?: HTMLElement | null; itemsContainer?: HTMLElement | null;

View file

@ -1,16 +0,0 @@
// NOTE: This should be included in the OpenAPI spec ideally
// https://github.com/jellyfin/jellyfin/blob/47290a8c3665f3adb859bda19deb66f438f2e5d0/MediaBrowser.Model/Entities/CollectionType.cs
export enum CollectionType {
Movies = 'movies',
TvShows = 'tvshows',
Music = 'music',
MusicVideos = 'musicvideos',
Trailers = 'trailers',
HomeVideos = 'homevideos',
BoxSets = 'boxsets',
Books = 'books',
Photos = 'photos',
LiveTv = 'livetv',
Playlists = 'playlists',
Folders = 'folders'
}

View file

@ -1,6 +1,6 @@
import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client'; import { BaseItemKind } from '@jellyfin/sdk/lib/generated-client';
import { LibraryTab } from './libraryTab'; import { LibraryTab } from './libraryTab';
import { CollectionType } from './collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
import { SectionType } from './sections'; import { SectionType } from './sections';
export interface SectionsView { export interface SectionsView {

View file

@ -1,6 +1,6 @@
import { BaseItemDto, SeriesTimerInfoDto } from '@jellyfin/sdk/lib/generated-client'; import { BaseItemDto, SeriesTimerInfoDto } from '@jellyfin/sdk/lib/generated-client';
import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by'; import { ItemSortBy } from '@jellyfin/sdk/lib/models/api/item-sort-by';
import { CollectionType } from './collectionType'; import { CollectionType } from '@jellyfin/sdk/lib/generated-client/';
export interface ListOptions { export interface ListOptions {
items?: BaseItemDto[] | SeriesTimerInfoDto[] | null; items?: BaseItemDto[] | SeriesTimerInfoDto[] | null;