From b5445515c8d6f82c4b074969dce411bacc7c916c Mon Sep 17 00:00:00 2001 From: Jacob Weiss Date: Sat, 27 Apr 2024 15:03:51 -0400 Subject: [PATCH 1/4] Modified legacy routes and added books controller to start working toward multi-part AudioBook support --- src/apps/stable/routes/legacyRoutes/user.ts | 6 + src/components/router/appRouter.js | 5 + src/controllers/books/books.html | 58 + src/controllers/books/booksmain.js | 1185 +++++++++++++++++++ 4 files changed, 1254 insertions(+) create mode 100644 src/controllers/books/books.html create mode 100644 src/controllers/books/booksmain.js diff --git a/src/apps/stable/routes/legacyRoutes/user.ts b/src/apps/stable/routes/legacyRoutes/user.ts index 19b87c7cd85..6ad1e8a5aee 100644 --- a/src/apps/stable/routes/legacyRoutes/user.ts +++ b/src/apps/stable/routes/legacyRoutes/user.ts @@ -67,6 +67,12 @@ export const LEGACY_USER_ROUTES: LegacyRoute[] = [ controller: 'user/subtitles/index', view: 'user/subtitles/index.html' } + }, { + path: 'books.html', + pageProps: { + controller: 'books/booksmain', + view: 'books/books.html' + } }, { path: 'tv.html', pageProps: { diff --git a/src/components/router/appRouter.js b/src/components/router/appRouter.js index de6b3c68715..4e516a22695 100644 --- a/src/components/router/appRouter.js +++ b/src/components/router/appRouter.js @@ -692,6 +692,11 @@ class AppRouter { return url; } + if (item.CollectionType == CollectionType.Books) { + let urlForList = '#/books.html?topParentId=' + item.Id; + + return urlForList; + } } const itemTypes = ['Playlist', 'TvChannel', 'Program', 'BoxSet', 'MusicAlbum', 'MusicGenre', 'Person', 'Recording', 'MusicArtist']; diff --git a/src/controllers/books/books.html b/src/controllers/books/books.html new file mode 100644 index 00000000000..a755ad1c9b3 --- /dev/null +++ b/src/controllers/books/books.html @@ -0,0 +1,58 @@ +
+
+
+
+
+
+ + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
diff --git a/src/controllers/books/booksmain.js b/src/controllers/books/booksmain.js new file mode 100644 index 00000000000..3ea6496f44c --- /dev/null +++ b/src/controllers/books/booksmain.js @@ -0,0 +1,1185 @@ +import globalize from '../../scripts/globalize'; +import listView from '../../components/listview/listview'; +import * as userSettings from '../../scripts/settings/userSettings'; +import focusManager from '../../components/focusManager'; +import cardBuilder from '../../components/cardbuilder/cardBuilder'; +import loading from '../../components/loading/loading'; +import AlphaNumericShortcuts from '../../scripts/alphanumericshortcuts'; +import libraryBrowser from '../../scripts/libraryBrowser'; +import { playbackManager } from '../../components/playback/playbackmanager'; +import AlphaPicker from '../../components/alphaPicker/alphaPicker'; +import '../../elements/emby-itemscontainer/emby-itemscontainer'; +import '../../elements/emby-scroller/emby-scroller'; +import ServerConnections from '../../components/ServerConnections'; +import LibraryMenu from '../../scripts/libraryMenu'; +import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type'; +import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by'; + + +function modifyQueryWithFilters(instance, query) { + const sortValues = instance.getSortValues(); + + if (!query.SortBy) { + query.SortBy = sortValues.sortBy; + query.SortOrder = sortValues.sortOrder; + } + + query.Fields = query.Fields ? query.Fields + ',PrimaryImageAspectRatio' : 'PrimaryImageAspectRatio'; + query.ImageTypeLimit = 1; + let hasFilters; + const queryFilters = []; + const filters = instance.getFilters(); + + if (filters.IsPlayed) { + queryFilters.push('IsPlayed'); + hasFilters = true; + } + + if (filters.IsUnplayed) { + queryFilters.push('IsUnplayed'); + hasFilters = true; + } + + if (filters.IsFavorite) { + queryFilters.push('IsFavorite'); + hasFilters = true; + } + + if (filters.IsResumable) { + queryFilters.push('IsResumable'); + hasFilters = true; + } + + if (filters.VideoTypes) { + hasFilters = true; + query.VideoTypes = filters.VideoTypes; + } + + if (filters.GenreIds) { + hasFilters = true; + query.GenreIds = filters.GenreIds; + } + + if (filters.Is4K) { + query.Is4K = true; + hasFilters = true; + } + + if (filters.IsHD) { + query.IsHD = true; + hasFilters = true; + } + + if (filters.IsSD) { + query.IsHD = false; + hasFilters = true; + } + + if (filters.Is3D) { + query.Is3D = true; + hasFilters = true; + } + + if (filters.HasSubtitles) { + query.HasSubtitles = true; + hasFilters = true; + } + + if (filters.HasTrailer) { + query.HasTrailer = true; + hasFilters = true; + } + + if (filters.HasSpecialFeature) { + query.HasSpecialFeature = true; + hasFilters = true; + } + + if (filters.HasThemeSong) { + query.HasThemeSong = true; + hasFilters = true; + } + + if (filters.HasThemeVideo) { + query.HasThemeVideo = true; + hasFilters = true; + } + + query.Filters = queryFilters.length ? queryFilters.join(',') : null; + instance.setFilterStatus(hasFilters); + + if (instance.alphaPicker) { + const newValue = instance.alphaPicker.value(); + if (newValue === '#') { + query.NameLessThan = 'A'; + delete query.NameStartsWith; + } else { + query.NameStartsWith = newValue; + delete query.NameLessThan; + } + } + + return query; +} + +function setSortButtonIcon(btnSortIcon, icon) { + btnSortIcon.classList.remove('arrow_downward'); + btnSortIcon.classList.remove('arrow_upward'); + btnSortIcon.classList.add(icon); +} + +function updateSortText(instance) { + const btnSortText = instance.btnSortText; + + if (btnSortText) { + const options = instance.getSortMenuOptions(); + const values = instance.getSortValues(); + const sortBy = values.sortBy; + + for (const option of options) { + if (sortBy === option.value) { + btnSortText.innerHTML = globalize.translate('SortByValue', option.name); + break; + } + } + + const btnSortIcon = instance.btnSortIcon; + + if (btnSortIcon) { + setSortButtonIcon(btnSortIcon, values.sortOrder === 'Descending' ? 'arrow_downward' : 'arrow_upward'); + } + } +} + +function updateItemsContainerForViewType(instance) { + if (instance.getViewSettings().imageType === 'list') { + instance.itemsContainer.classList.remove('vertical-wrap'); + instance.itemsContainer.classList.add('vertical-list'); + } else { + instance.itemsContainer.classList.add('vertical-wrap'); + instance.itemsContainer.classList.remove('vertical-list'); + } +} + +function updateAlphaPickerState(instance) { + if (instance.alphaPicker) { + const alphaPicker = instance.alphaPickerElement; + + if (alphaPicker) { + const values = instance.getSortValues(); + + if (values.sortBy.indexOf(ItemSortBy.SortName) !== -1) { + alphaPicker.classList.remove('hide'); + instance.itemsContainer.parentNode.classList.add('padded-right-withalphapicker'); + } else { + alphaPicker.classList.add('hide'); + instance.itemsContainer.parentNode.classList.remove('padded-right-withalphapicker'); + } + } + } +} + +function getItems(instance, params, item, sortBy, startIndex, limit) { + const apiClient = ServerConnections.currentApiClient(); + + instance.queryRecursive = false; + + if (!item) { + // console.log("I dont think this is right"); + instance.queryRecursive = true; + + return apiClient['getItems'](apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { + StartIndex: startIndex, + Limit: limit, + Fields: 'PrimaryImageAspectRatio,SortName', + ImageTypeLimit: 1, + IncludeItemTypes: 'AudioBook,Book', + Recursive: true, + IsFavorite: params.IsFavorite === 'true' || null, + ArtistIds: params.artistId || null, + SortBy: sortBy + })); + } + + return apiClient.getItems(apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { + StartIndex: startIndex, + Limit: limit, + Fields: 'PrimaryImageAspectRatio,SortName,Path,ChildCount,MediaSourceCount', + ImageTypeLimit: 1, + ParentId: item.Id, + SortBy: sortBy, + // IncludeItemTypes: 'AudioBook'? + })); +} + +function getItem(params) { + if (params.type === 'Recordings' || params.type === 'Programs' || params.type === 'nextup') { + return Promise.resolve(null); + } + + const apiClient = ServerConnections.currentApiClient(); + const itemId = params.genreId || params.musicGenreId || params.studioId || params.personId || params.parentId; + + if (itemId) { + return apiClient.getItem(apiClient.getCurrentUserId(), itemId); + } + + return Promise.resolve(null); +} + +function showViewSettingsMenu() { + const instance = this; + + import('../../components/viewSettings/viewSettings').then(({ default: ViewSettings }) => { + new ViewSettings().show({ + settingsKey: instance.getSettingsKey(), + settings: instance.getViewSettings(), + visibleSettings: instance.getVisibleViewSettings() + }).then(function () { + updateItemsContainerForViewType(instance); + instance.itemsContainer.refreshItems(); + }); + }); +} + +function showFilterMenu() { + const instance = this; + + import('../../components/filtermenu/filtermenu').then(({ default: FilterMenu }) => { + new FilterMenu().show({ + settingsKey: instance.getSettingsKey(), + settings: instance.getFilters(), + visibleSettings: instance.getVisibleFilters(), + onChange: instance.itemsContainer.refreshItems.bind(instance.itemsContainer), + parentId: instance.params.parentId, + itemTypes: instance.getItemTypes(), + serverId: instance.params.serverId, + filterMenuOptions: instance.getFilterMenuOptions() + }).then(function () { + instance.itemsContainer.refreshItems(); + }); + }); +} + +function showSortMenu() { + const instance = this; + + import('../../components/sortmenu/sortmenu').then(({ default: SortMenu }) => { + new SortMenu().show({ + settingsKey: instance.getSettingsKey(), + settings: instance.getSortValues(), + onChange: instance.itemsContainer.refreshItems.bind(instance.itemsContainer), + serverId: instance.params.serverId, + sortOptions: instance.getSortMenuOptions() + }).then(function () { + updateSortText(instance); + updateAlphaPickerState(instance); + instance.itemsContainer.refreshItems(); + }); + }); +} + +function onNewItemClick() { + const instance = this; + + import('../../components/playlisteditor/playlisteditor').then(({ default: PlaylistEditor }) => { + const playlistEditor = new PlaylistEditor(); + playlistEditor.show({ + items: [], + serverId: instance.params.serverId + }).catch(() => { + // Dialog closed + }); + }).catch(err => { + console.error('[onNewItemClick] failed to load playlist editor', err); + }); +} + +function hideOrShowAll(elems, hide) { + for (const elem of elems) { + if (hide) { + elem.classList.add('hide'); + } else { + elem.classList.remove('hide'); + } + } +} + +function bindAll(elems, eventName, fn) { + for (const elem of elems) { + elem.addEventListener(eventName, fn); + } +} + +class BooksView { + constructor(view, params) { + const query = { + StartIndex: 0, + Limit: undefined + }; + + if (userSettings.libraryPageSize() > 0) { + query['Limit'] = userSettings.libraryPageSize(); + } + + let isLoading = false; + + function onNextPageClick() { + if (!isLoading && query.Limit > 0) { + query.StartIndex += query.Limit; + self.itemsContainer.refreshItems().then(() => { + window.scrollTo(0, 0); + autoFocus(); + }); + } + } + + function onPreviousPageClick() { + if (!isLoading && query.Limit > 0) { + query.StartIndex = Math.max(0, query.StartIndex - query.Limit); + self.itemsContainer.refreshItems().then(() => { + window.scrollTo(0, 0); + autoFocus(); + }); + } + } + + function updatePaging(startIndex, totalRecordCount, limit) { + const pagingHtml = libraryBrowser.getQueryPagingHtml({ + startIndex, + limit, + totalRecordCount, + showLimit: false, + updatePageSizeSetting: false, + addLayoutButton: false, + sortButton: false, + filterButton: false + }); + + for (const elem of view.querySelectorAll('.paging')) { + elem.innerHTML = pagingHtml; + } + + for (const elem of view.querySelectorAll('.btnNextPage')) { + elem.addEventListener('click', onNextPageClick); + } + + for (const elem of view.querySelectorAll('.btnPreviousPage')) { + elem.addEventListener('click', onPreviousPageClick); + } + } + + function fetchData() { + isLoading = true; + + return getItems(self, params, self.currentItem, null, query.StartIndex, query.Limit).then(function (result) { + if (self.totalItemCount == null) { + self.totalItemCount = result.Items ? result.Items.length : result.length; + } + + updateAlphaPickerState(self); + updatePaging(result.StartIndex, result.TotalRecordCount, query.Limit); + return result; + }).finally(() => { + isLoading = false; + }); + } + + function getItemsHtml(items) { + const settings = self.getViewSettings(); + + if (settings.imageType === 'list') { + return listView.getListViewHtml({ + items: items + }); + } + + let shape; + let preferThumb; + let preferDisc; + let preferLogo; + let defaultShape; + const item = self.currentItem; + let lines = settings.showTitle ? 2 : 0; + + if (settings.imageType === 'banner') { + shape = 'banner'; + } else if (settings.imageType === 'disc') { + shape = 'square'; + preferDisc = true; + } else if (settings.imageType === 'logo') { + shape = 'backdrop'; + preferLogo = true; + } else if (settings.imageType === 'thumb') { + shape = 'backdrop'; + preferThumb = true; + } else if (params.type === 'nextup') { + shape = 'backdrop'; + preferThumb = settings.imageType === 'thumb'; + } else if (params.type === 'Programs' || params.type === 'Recordings') { + shape = params.IsMovie === 'true' ? 'portrait' : 'autoVertical'; + preferThumb = params.IsMovie !== 'true' ? 'auto' : false; + defaultShape = params.IsMovie === 'true' ? 'portrait' : 'backdrop'; + } else { + shape = 'autoVertical'; + } + + let posterOptions = { + shape: shape, + showTitle: settings.showTitle, + showYear: settings.showTitle, + centerText: true, + coverImage: true, + preferThumb: preferThumb, + preferDisc: preferDisc, + preferLogo: preferLogo, + overlayPlayButton: false, + overlayMoreButton: true, + overlayText: !settings.showTitle, + defaultShape: defaultShape, + action: params.type === 'Audio' ? 'playallfromhere' : null + }; + + if (params.type === 'nextup') { + posterOptions.showParentTitle = settings.showTitle; + } else if (params.type === 'Person') { + posterOptions.showYear = false; + posterOptions.showParentTitle = false; + lines = 1; + } else if (params.type === 'Audio') { + posterOptions.showParentTitle = settings.showTitle; + } else if (params.type === 'MusicAlbum') { + posterOptions.showParentTitle = settings.showTitle; + } else if (params.type === 'Episode') { + posterOptions.showParentTitle = settings.showTitle; + } else if (params.type === 'MusicArtist') { + posterOptions.showYear = false; + lines = 1; + } else if (params.type === 'Programs') { + lines = settings.showTitle ? 1 : 0; + const showParentTitle = settings.showTitle && params.IsMovie !== 'true'; + + if (showParentTitle) { + lines++; + } + + const showAirTime = settings.showTitle && params.type !== 'Recordings'; + + if (showAirTime) { + lines++; + } + + const showYear = settings.showTitle && params.IsMovie === 'true' && params.type === 'Recordings'; + + if (showYear) { + lines++; + } + + posterOptions = Object.assign(posterOptions, { + inheritThumb: params.type === 'Recordings', + context: 'livetv', + showParentTitle: showParentTitle, + showAirTime: showAirTime, + showAirDateTime: showAirTime, + overlayPlayButton: false, + overlayMoreButton: true, + showYear: showYear, + coverImage: true + }); + } else { + posterOptions.showParentTitle = settings.showTitle; + } + + posterOptions.lines = lines; + posterOptions.items = items; + + if (item && item.CollectionType === CollectionType.Folders) { + posterOptions.context = 'folders'; + } + + return cardBuilder.getCardsHtml(posterOptions); + } + + function initAlphaPicker() { + self.scroller = view.querySelector('.scrollFrameY'); + const alphaPickerElement = self.alphaPickerElement; + + alphaPickerElement.classList.add('alphaPicker-fixed-right'); + alphaPickerElement.classList.add('focuscontainer-right'); + self.itemsContainer.parentNode.classList.add('padded-right-withalphapicker'); + + self.alphaPicker = new AlphaPicker({ + element: alphaPickerElement, + valueChangeEvent: 'click' + }); + self.alphaPicker.on('alphavaluechanged', onAlphaPickerValueChanged); + } + + function onAlphaPickerValueChanged() { + query.StartIndex = 0; + self.itemsContainer.refreshItems(); + } + + function setTitle(item) { + LibraryMenu.setTitle(getTitle(item) || ''); + + if (item && item.CollectionType === CollectionType.Playlists) { + hideOrShowAll(view.querySelectorAll('.btnNewItem'), false); + } else { + hideOrShowAll(view.querySelectorAll('.btnNewItem'), true); + } + } + + function getTitle(item) { + if (params.type === 'Recordings') { + return globalize.translate('Recordings'); + } + + if (params.type === 'Programs') { + if (params.IsMovie === 'true') { + return globalize.translate('Movies'); + } + + if (params.IsSports === 'true') { + return globalize.translate('Sports'); + } + + if (params.IsKids === 'true') { + return globalize.translate('HeaderForKids'); + } + + if (params.IsAiring === 'true') { + return globalize.translate('HeaderOnNow'); + } + + if (params.IsSeries === 'true') { + return globalize.translate('Shows'); + } + + if (params.IsNews === 'true') { + return globalize.translate('News'); + } + + return globalize.translate('Programs'); + } + + if (params.type === 'nextup') { + return globalize.translate('NextUp'); + } + + if (params.type === 'favoritemovies') { + return globalize.translate('FavoriteMovies'); + } + + if (item) { + return item.Name; + } + + if (params.type === 'Movie') { + return globalize.translate('Movies'); + } + + if (params.type === 'Series') { + return globalize.translate('Shows'); + } + + if (params.type === 'Season') { + return globalize.translate('Seasons'); + } + + if (params.type === 'Episode') { + return globalize.translate('Episodes'); + } + + if (params.type === 'MusicArtist') { + return globalize.translate('Artists'); + } + + if (params.type === 'MusicAlbum') { + return globalize.translate('Albums'); + } + + if (params.type === 'Audio') { + return globalize.translate('Songs'); + } + + if (params.type === 'Video') { + return globalize.translate('Videos'); + } + } + + function play() { + const currentItem = self.currentItem; + + if (currentItem && !self.hasFilters) { + const values = self.getSortValues(); + playbackManager.play({ + items: [currentItem], + queryOptions: { + SortBy: values.sortBy, + SortOrder: values.sortOrder + }, + autoplay: true + }); + } else { + getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { + playbackManager.play({ + items: result.Items, + autoplay: true + }); + }); + } + } + + function queue() { + const currentItem = self.currentItem; + + if (currentItem && !self.hasFilters) { + playbackManager.queue({ + items: [currentItem] + }); + } else { + getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { + playbackManager.queue({ + items: result.Items + }); + }); + } + } + + function shuffle() { + const currentItem = self.currentItem; + + if (currentItem && !self.hasFilters) { + playbackManager.shuffle(currentItem); + } else { + getItems(self, self.params, currentItem, 'Random', 0, 300).then(function (result) { + playbackManager.play({ + items: result.Items, + autoplay: true + }); + }); + } + } + + function autoFocus() { + import('../../components/autoFocuser').then(({ default: autoFocuser }) => { + autoFocuser.autoFocus(view); + }); + } + + const self = this; + self.params = params; + this.itemsContainer = view.querySelector('.itemsContainer'); + + if (params.parentId) { + this.itemsContainer.setAttribute('data-parentid', params.parentId); + } else if (params.type === 'nextup') { + this.itemsContainer.setAttribute('data-monitor', 'videoplayback'); + } else if (params.type === 'favoritemovies') { + this.itemsContainer.setAttribute('data-monitor', 'markfavorite'); + } else if (params.type === 'Programs') { + this.itemsContainer.setAttribute('data-refreshinterval', '300000'); + } + + const btnViewSettings = view.querySelectorAll('.btnViewSettings'); + + for (const btnViewSetting of btnViewSettings) { + btnViewSetting.addEventListener('click', showViewSettingsMenu.bind(this)); + } + + const filterButtons = view.querySelectorAll('.btnFilter'); + this.filterButtons = filterButtons; + const hasVisibleFilters = this.getVisibleFilters().length; + + for (const btnFilter of filterButtons) { + btnFilter.addEventListener('click', showFilterMenu.bind(this)); + + if (hasVisibleFilters) { + btnFilter.classList.remove('hide'); + } else { + btnFilter.classList.add('hide'); + } + } + + const sortButtons = view.querySelectorAll('.btnSort'); + + this.sortButtons = sortButtons; + for (const sortButton of sortButtons) { + sortButton.addEventListener('click', showSortMenu.bind(this)); + + if (params.type !== 'nextup') { + sortButton.classList.remove('hide'); + } + } + + this.btnSortText = view.querySelector('.btnSortText'); + this.btnSortIcon = view.querySelector('.btnSortIcon'); + bindAll(view.querySelectorAll('.btnNewItem'), 'click', onNewItemClick.bind(this)); + this.alphaPickerElement = view.querySelector('.alphaPicker'); + self.itemsContainer.fetchData = fetchData; + self.itemsContainer.getItemsHtml = getItemsHtml; + view.addEventListener('viewshow', function (e) { + const isRestored = e.detail.isRestored; + + if (!isRestored) { + loading.show(); + updateSortText(self); + updateItemsContainerForViewType(self); + } + + setTitle(null); + getItem(params).then(function (item) { + setTitle(item); + self.currentItem = item; + const refresh = !isRestored; + self.itemsContainer.resume({ + refresh: refresh + }).then(function () { + loading.hide(); + + if (refresh) { + focusManager.autoFocus(self.itemsContainer); + } + }); + + if (!isRestored && item && item.Type !== 'PhotoAlbum') { + initAlphaPicker(); + } + + const itemType = item ? item.Type : null; + + if ((itemType === 'MusicGenre' || params.type !== 'Programs' && itemType !== 'Channel') + // Folder, Playlist views + && itemType !== 'UserView' + // Only Photo (homevideos) CollectionFolders are supported + && !(itemType === 'CollectionFolder' && item?.CollectionType !== CollectionType.Homevideos) + ) { + // Show Play All buttons + hideOrShowAll(view.querySelectorAll('.btnPlay'), false); + } else { + // Hide Play All buttons + hideOrShowAll(view.querySelectorAll('.btnPlay'), true); + } + + if ((itemType === 'MusicGenre' || params.type !== 'Programs' && params.type !== 'nextup' && itemType !== 'Channel') + // Folder, Playlist views + && itemType !== 'UserView' + // Only Photo (homevideos) CollectionFolders are supported + && !(itemType === 'CollectionFolder' && item?.CollectionType !== CollectionType.Homevideos) + ) { + // Show Shuffle buttons + hideOrShowAll(view.querySelectorAll('.btnShuffle'), false); + } else { + // Hide Shuffle buttons + hideOrShowAll(view.querySelectorAll('.btnShuffle'), true); + } + + if (item && playbackManager.canQueue(item)) { + // Show Queue button + hideOrShowAll(view.querySelectorAll('.btnQueue'), false); + } else { + // Hide Queue button + hideOrShowAll(view.querySelectorAll('.btnQueue'), true); + } + }); + + if (!isRestored) { + bindAll(view.querySelectorAll('.btnPlay'), 'click', play); + bindAll(view.querySelectorAll('.btnQueue'), 'click', queue); + bindAll(view.querySelectorAll('.btnShuffle'), 'click', shuffle); + } + + self.alphaNumericShortcuts = new AlphaNumericShortcuts({ + itemsContainer: self.itemsContainer + }); + }); + view.addEventListener('viewhide', function () { + const itemsContainer = self.itemsContainer; + + if (itemsContainer) { + itemsContainer.pause(); + } + + const alphaNumericShortcuts = self.alphaNumericShortcuts; + + if (alphaNumericShortcuts) { + alphaNumericShortcuts.destroy(); + self.alphaNumericShortcuts = null; + } + }); + view.addEventListener('viewdestroy', function () { + if (self.listController) { + self.listController.destroy(); + } + + if (self.alphaPicker) { + self.alphaPicker.off('alphavaluechanged', onAlphaPickerValueChanged); + self.alphaPicker.destroy(); + } + + self.currentItem = null; + self.scroller = null; + self.itemsContainer = null; + self.filterButtons = null; + self.sortButtons = null; + self.btnSortText = null; + self.btnSortIcon = null; + self.alphaPickerElement = null; + }); + } + + getFilters() { + const basekey = this.getSettingsKey(); + return { + IsPlayed: userSettings.getFilter(basekey + '-filter-IsPlayed') === 'true', + IsUnplayed: userSettings.getFilter(basekey + '-filter-IsUnplayed') === 'true', + IsFavorite: userSettings.getFilter(basekey + '-filter-IsFavorite') === 'true', + IsResumable: userSettings.getFilter(basekey + '-filter-IsResumable') === 'true', + Is4K: userSettings.getFilter(basekey + '-filter-Is4K') === 'true', + IsHD: userSettings.getFilter(basekey + '-filter-IsHD') === 'true', + IsSD: userSettings.getFilter(basekey + '-filter-IsSD') === 'true', + Is3D: userSettings.getFilter(basekey + '-filter-Is3D') === 'true', + VideoTypes: userSettings.getFilter(basekey + '-filter-VideoTypes'), + SeriesStatus: userSettings.getFilter(basekey + '-filter-SeriesStatus'), + HasSubtitles: userSettings.getFilter(basekey + '-filter-HasSubtitles'), + HasTrailer: userSettings.getFilter(basekey + '-filter-HasTrailer'), + HasSpecialFeature: userSettings.getFilter(basekey + '-filter-HasSpecialFeature'), + HasThemeSong: userSettings.getFilter(basekey + '-filter-HasThemeSong'), + HasThemeVideo: userSettings.getFilter(basekey + '-filter-HasThemeVideo'), + GenreIds: userSettings.getFilter(basekey + '-filter-GenreIds') + }; + } + + getSortValues() { + const basekey = this.getSettingsKey(); + return userSettings.getSortValuesLegacy(basekey, this.getDefaultSortBy()); + } + + getDefaultSortBy() { + const sortNameOption = this.getNameSortOption(this.params); + + if (this.params.type) { + return sortNameOption.value; + } + + return `${ItemSortBy.IsFolder},${sortNameOption.value}`; + } + + getSortMenuOptions() { + const sortBy = []; + + if (this.params.type === 'Programs') { + sortBy.push({ + name: globalize.translate('AirDate'), + value: [ItemSortBy.StartDate, ItemSortBy.SortName].join(',') + }); + } + + let option = this.getNameSortOption(this.params); + + if (option) { + sortBy.push(option); + } + + option = this.getCommunityRatingSortOption(); + + if (option) { + sortBy.push(option); + } + + option = this.getCriticRatingSortOption(); + + if (option) { + sortBy.push(option); + } + + if (this.params.type !== 'Programs') { + sortBy.push({ + name: globalize.translate('DateAdded'), + value: [ItemSortBy.DateCreated, ItemSortBy.SortName].join(',') + }); + } + + option = this.getDatePlayedSortOption(); + + if (option) { + sortBy.push(option); + } + + if (!this.params.type) { + option = this.getNameSortOption(this.params); + sortBy.push({ + name: globalize.translate('Folders'), + value: `${ItemSortBy.IsFolder},${option.value}` + }); + } + + sortBy.push({ + name: globalize.translate('ParentalRating'), + value: [ItemSortBy.OfficialRating, ItemSortBy.SortName].join(',') + }); + option = this.getPlayCountSortOption(); + + if (option) { + sortBy.push(option); + } + + sortBy.push({ + name: globalize.translate('ReleaseDate'), + value: [ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName].join(',') + }); + sortBy.push({ + name: globalize.translate('Runtime'), + value: [ItemSortBy.Runtime, ItemSortBy.SortName].join(',') + }); + return sortBy; + } + + getNameSortOption(params) { + if (params.type === 'Episode') { + return { + name: globalize.translate('Name'), + value: [ItemSortBy.SeriesSortName, ItemSortBy.SortName].join(',') + }; + } + + return { + name: globalize.translate('Name'), + value: ItemSortBy.SortName + }; + } + + getPlayCountSortOption() { + if (this.params.type === 'Programs') { + return null; + } + + return { + name: globalize.translate('PlayCount'), + value: [ItemSortBy.PlayCount, ItemSortBy.SortName].join(',') + }; + } + + getDatePlayedSortOption() { + if (this.params.type === 'Programs') { + return null; + } + + return { + name: globalize.translate('DatePlayed'), + value: [ItemSortBy.DatePlayed, ItemSortBy.SortName].join(',') + }; + } + + getCriticRatingSortOption() { + if (this.params.type === 'Programs') { + return null; + } + + return { + name: globalize.translate('CriticRating'), + value: [ItemSortBy.CriticRating, ItemSortBy.SortName].join(',') + }; + } + + getCommunityRatingSortOption() { + return { + name: globalize.translate('CommunityRating'), + value: [ItemSortBy.CommunityRating, ItemSortBy.SortName].join(',') + }; + } + + getVisibleFilters() { + const filters = []; + const params = this.params; + + if (params.type !== 'nextup') { + if (params.type === 'Programs') { + filters.push('Genres'); + } else { + filters.push('IsUnplayed'); + filters.push('IsPlayed'); + + if (!params.IsFavorite) { + filters.push('IsFavorite'); + } + + filters.push('IsResumable'); + filters.push('VideoType'); + filters.push('HasSubtitles'); + filters.push('HasTrailer'); + filters.push('HasSpecialFeature'); + filters.push('HasThemeSong'); + filters.push('HasThemeVideo'); + } + } + + return filters; + } + + setFilterStatus(hasFilters) { + this.hasFilters = hasFilters; + const filterButtons = this.filterButtons; + + if (filterButtons.length) { + for (const btnFilter of filterButtons) { + let bubble = btnFilter.querySelector('.filterButtonBubble'); + + if (!bubble) { + if (!hasFilters) { + continue; + } + + btnFilter.insertAdjacentHTML('afterbegin', '
!
'); + btnFilter.classList.add('btnFilterWithBubble'); + bubble = btnFilter.querySelector('.filterButtonBubble'); + } + + if (hasFilters) { + bubble.classList.remove('hide'); + } else { + bubble.classList.add('hide'); + } + } + } + } + + getFilterMenuOptions() { + const params = this.params; + return { + IsAiring: params.IsAiring, + IsMovie: params.IsMovie, + IsSports: params.IsSports, + IsKids: params.IsKids, + IsNews: params.IsNews, + IsSeries: params.IsSeries, + Recursive: this.queryRecursive + }; + } + + getVisibleViewSettings() { + const item = this.currentItem; + const fields = ['showTitle']; + + if (!item || item.Type !== 'PhotoAlbum' && item.Type !== 'ChannelFolderItem') { + fields.push('imageType'); + } + + fields.push('viewType'); + return fields; + } + + getViewSettings() { + const basekey = this.getSettingsKey(); + const params = this.params; + const item = this.currentItem; + let showTitle = userSettings.get(basekey + '-showTitle'); + + if (showTitle === 'true') { + showTitle = true; + } else if (showTitle === 'false') { + showTitle = false; + } else if (params.type === 'Programs' || params.type === 'Recordings' || params.type === 'Person' || params.type === 'nextup' || params.type === 'Audio' || params.type === 'MusicAlbum' || params.type === 'MusicArtist') { + showTitle = true; + } else if (item && item.Type !== 'PhotoAlbum') { + showTitle = true; + } + + let imageType = userSettings.get(basekey + '-imageType'); + + if (!imageType && params.type === 'nextup') { + if (userSettings.useEpisodeImagesInNextUpAndResume()) { + imageType = 'primary'; + } else { + imageType = 'thumb'; + } + } + + return { + showTitle: showTitle, + showYear: userSettings.get(basekey + '-showYear') !== 'false', + imageType: imageType || 'primary', + viewType: userSettings.get(basekey + '-viewType') || 'images' + }; + } + + getItemTypes() { + const params = this.params; + + if (params.type === 'nextup') { + return ['Episode']; + } + + if (params.type === 'Programs') { + return ['Program']; + } + + return []; + } + + getSettingsKey() { + const values = []; + values.push('items'); + const params = this.params; + + if (params.type) { + values.push(params.type); + } else if (params.parentId) { + values.push(params.parentId); + } + + if (params.IsAiring) { + values.push('IsAiring'); + } + + if (params.IsMovie) { + values.push('IsMovie'); + } + + if (params.IsKids) { + values.push('IsKids'); + } + + if (params.IsSports) { + values.push('IsSports'); + } + + if (params.IsNews) { + values.push('IsNews'); + } + + if (params.IsSeries) { + values.push('IsSeries'); + } + + if (params.IsFavorite) { + values.push('IsFavorite'); + } + + if (params.genreId) { + values.push('Genre'); + } + + if (params.musicGenreId) { + values.push('MusicGenre'); + } + + if (params.studioId) { + values.push('Studio'); + } + + if (params.personId) { + values.push('Person'); + } + + if (params.parentId) { + values.push('Folder'); + } + + return values.join('-'); + } +} + +export default BooksView; + From 29b7071be732358f498a6c9f166c43d531ee89be Mon Sep 17 00:00:00 2001 From: Jacob Weiss Date: Mon, 29 Apr 2024 16:46:27 -0400 Subject: [PATCH 2/4] Saving notes, moving computers --- src/components/playback/playbackmanager.js | 9 ++++++ src/controllers/books/booksmain.js | 36 +--------------------- 2 files changed, 10 insertions(+), 35 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index bb295422eba..f6bd8c4d7cc 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -685,6 +685,7 @@ class PlaybackManager { constructor() { const self = this; + // The list of players const players = []; let currentTargetInfo; let currentPairingId = null; @@ -835,6 +836,7 @@ class PlaybackManager { return ServerConnections.currentApiClient().getCurrentUser().then(function (user) { const targets = []; + // Is this relevant? targets.push({ name: globalize.translate('HeaderMyDevice'), id: 'localplayer', @@ -1977,9 +1979,12 @@ class PlaybackManager { self.translateItemsForPlayback = translateItemsForPlayback; self.getItemsForPlayback = getItemsForPlayback; + // This is the exposed function called to manage item media playback self.play = function (options) { normalizePlayOptions(options); + console.debug('playing'); + // I think this class *is* the "localpalyer", others are plugins or chromecast if (self._currentPlayer) { if (options.enableRemotePlayers === false && !self._currentPlayer.isLocalPlayer) { return Promise.reject(); @@ -1990,11 +1995,13 @@ class PlaybackManager { } } + console.debug('using "localplayer" (*wink*)'); if (options.fullscreen) { loading.show(); } if (options.items) { + console.debug('playing from options.items'); return translateItemsForPlayback(options.items, options) .then((items) => getAdditionalParts(items)) .then(function (allItems) { @@ -2002,6 +2009,7 @@ class PlaybackManager { return playWithIntros(flattened, options); }); } else { + console.debug('calling getItemsForPlayback'); if (!options.serverId) { throw new Error('serverId required!'); } @@ -3420,6 +3428,7 @@ class PlaybackManager { }; } + // Add a player to the list of players and associate callbacks function initMediaPlayer(player) { players.push(player); players.sort(function (a, b) { diff --git a/src/controllers/books/booksmain.js b/src/controllers/books/booksmain.js index 3ea6496f44c..f5737b91f45 100644 --- a/src/controllers/books/booksmain.js +++ b/src/controllers/books/booksmain.js @@ -531,46 +531,11 @@ class BooksView { } function getTitle(item) { - if (params.type === 'Recordings') { - return globalize.translate('Recordings'); - } - - if (params.type === 'Programs') { - if (params.IsMovie === 'true') { - return globalize.translate('Movies'); - } - - if (params.IsSports === 'true') { - return globalize.translate('Sports'); - } - - if (params.IsKids === 'true') { - return globalize.translate('HeaderForKids'); - } - - if (params.IsAiring === 'true') { - return globalize.translate('HeaderOnNow'); - } - - if (params.IsSeries === 'true') { - return globalize.translate('Shows'); - } - - if (params.IsNews === 'true') { - return globalize.translate('News'); - } - - return globalize.translate('Programs'); - } if (params.type === 'nextup') { return globalize.translate('NextUp'); } - if (params.type === 'favoritemovies') { - return globalize.translate('FavoriteMovies'); - } - if (item) { return item.Name; } @@ -622,6 +587,7 @@ class BooksView { autoplay: true }); } else { + // This is the call we can use for resume playback getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { playbackManager.play({ items: result.Items, From 3226eef67ed88d034f376e3fd23ade960af14682 Mon Sep 17 00:00:00 2001 From: Samson50 Date: Wed, 8 May 2024 00:51:19 -0400 Subject: [PATCH 3/4] Playback continuation and AudioBook playlist/queue now working as desired after minor modifications to playbackmanager.js --- src/components/playback/playbackmanager.js | 13 ++++++++----- src/components/router/appRouter.js | 4 +--- src/controllers/books/booksmain.js | 1 - 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index f6bd8c4d7cc..0fedc0ef899 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -1969,6 +1969,9 @@ class PlaybackManager { if (promise) { return promise.then(function (result) { + if (firstItem.Type === 'AudioBook') { + options.startIndex = result.StartIndex; + } return result ? result.Items : items; }); } else { @@ -1982,9 +1985,7 @@ class PlaybackManager { // This is the exposed function called to manage item media playback self.play = function (options) { normalizePlayOptions(options); - console.debug('playing'); - // I think this class *is* the "localpalyer", others are plugins or chromecast if (self._currentPlayer) { if (options.enableRemotePlayers === false && !self._currentPlayer.isLocalPlayer) { return Promise.reject(); @@ -1995,13 +1996,11 @@ class PlaybackManager { } } - console.debug('using "localplayer" (*wink*)'); if (options.fullscreen) { loading.show(); } if (options.items) { - console.debug('playing from options.items'); return translateItemsForPlayback(options.items, options) .then((items) => getAdditionalParts(items)) .then(function (allItems) { @@ -2009,7 +2008,6 @@ class PlaybackManager { return playWithIntros(flattened, options); }); } else { - console.debug('calling getItemsForPlayback'); if (!options.serverId) { throw new Error('serverId required!'); } @@ -2238,6 +2236,10 @@ class PlaybackManager { } function playInternal(item, playOptions, onPlaybackStartedFn, prevSource) { + if (item.Type === 'AudioBookFile') { + playOptions.startPositionTicks = item.UserData.PlaybackPositionTicks; + } + if (item.IsPlaceHolder) { loading.hide(); showPlaybackInfoErrorMessage(self, 'PlaybackErrorPlaceHolder'); @@ -2499,6 +2501,7 @@ class PlaybackManager { } return Promise.all([promise, player.getDeviceProfile(item)]).then(function (responses) { + // TODO: Why does this skip the first entry? const deviceProfile = responses[1]; const apiClient = ServerConnections.getApiClient(item.ServerId); diff --git a/src/components/router/appRouter.js b/src/components/router/appRouter.js index 4e516a22695..31530edaec4 100644 --- a/src/components/router/appRouter.js +++ b/src/components/router/appRouter.js @@ -693,9 +693,7 @@ class AppRouter { return url; } if (item.CollectionType == CollectionType.Books) { - let urlForList = '#/books.html?topParentId=' + item.Id; - - return urlForList; + return '#/books.html?parentId=' + id + '&serverId=' + serverId + '&topParentId=' + item.Id; } } diff --git a/src/controllers/books/booksmain.js b/src/controllers/books/booksmain.js index f5737b91f45..2cde5e18312 100644 --- a/src/controllers/books/booksmain.js +++ b/src/controllers/books/booksmain.js @@ -185,7 +185,6 @@ function getItems(instance, params, item, sortBy, startIndex, limit) { instance.queryRecursive = false; if (!item) { - // console.log("I dont think this is right"); instance.queryRecursive = true; return apiClient['getItems'](apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { From 4c5394afee17975cc6f49ead2e597e23f69bc2a8 Mon Sep 17 00:00:00 2001 From: Samson50 <> Date: Thu, 9 May 2024 18:59:03 -0400 Subject: [PATCH 4/4] Removed books controller and associated routes --- src/apps/stable/routes/legacyRoutes/user.ts | 6 - src/components/playback/playbackmanager.js | 4 - src/components/router/appRouter.js | 3 - src/controllers/books/books.html | 58 - src/controllers/books/booksmain.js | 1150 ------------------- 5 files changed, 1221 deletions(-) delete mode 100644 src/controllers/books/books.html delete mode 100644 src/controllers/books/booksmain.js diff --git a/src/apps/stable/routes/legacyRoutes/user.ts b/src/apps/stable/routes/legacyRoutes/user.ts index 6ad1e8a5aee..19b87c7cd85 100644 --- a/src/apps/stable/routes/legacyRoutes/user.ts +++ b/src/apps/stable/routes/legacyRoutes/user.ts @@ -67,12 +67,6 @@ export const LEGACY_USER_ROUTES: LegacyRoute[] = [ controller: 'user/subtitles/index', view: 'user/subtitles/index.html' } - }, { - path: 'books.html', - pageProps: { - controller: 'books/booksmain', - view: 'books/books.html' - } }, { path: 'tv.html', pageProps: { diff --git a/src/components/playback/playbackmanager.js b/src/components/playback/playbackmanager.js index 0fedc0ef899..02c5e7ece93 100644 --- a/src/components/playback/playbackmanager.js +++ b/src/components/playback/playbackmanager.js @@ -685,7 +685,6 @@ class PlaybackManager { constructor() { const self = this; - // The list of players const players = []; let currentTargetInfo; let currentPairingId = null; @@ -836,7 +835,6 @@ class PlaybackManager { return ServerConnections.currentApiClient().getCurrentUser().then(function (user) { const targets = []; - // Is this relevant? targets.push({ name: globalize.translate('HeaderMyDevice'), id: 'localplayer', @@ -1982,7 +1980,6 @@ class PlaybackManager { self.translateItemsForPlayback = translateItemsForPlayback; self.getItemsForPlayback = getItemsForPlayback; - // This is the exposed function called to manage item media playback self.play = function (options) { normalizePlayOptions(options); @@ -2501,7 +2498,6 @@ class PlaybackManager { } return Promise.all([promise, player.getDeviceProfile(item)]).then(function (responses) { - // TODO: Why does this skip the first entry? const deviceProfile = responses[1]; const apiClient = ServerConnections.getApiClient(item.ServerId); diff --git a/src/components/router/appRouter.js b/src/components/router/appRouter.js index 31530edaec4..de6b3c68715 100644 --- a/src/components/router/appRouter.js +++ b/src/components/router/appRouter.js @@ -692,9 +692,6 @@ class AppRouter { return url; } - if (item.CollectionType == CollectionType.Books) { - return '#/books.html?parentId=' + id + '&serverId=' + serverId + '&topParentId=' + item.Id; - } } const itemTypes = ['Playlist', 'TvChannel', 'Program', 'BoxSet', 'MusicAlbum', 'MusicGenre', 'Person', 'Recording', 'MusicArtist']; diff --git a/src/controllers/books/books.html b/src/controllers/books/books.html deleted file mode 100644 index a755ad1c9b3..00000000000 --- a/src/controllers/books/books.html +++ /dev/null @@ -1,58 +0,0 @@ -
-
-
-
-
-
- - - - - - - - - - - - - - - -
-
-
-
-
-
-
-
diff --git a/src/controllers/books/booksmain.js b/src/controllers/books/booksmain.js deleted file mode 100644 index 2cde5e18312..00000000000 --- a/src/controllers/books/booksmain.js +++ /dev/null @@ -1,1150 +0,0 @@ -import globalize from '../../scripts/globalize'; -import listView from '../../components/listview/listview'; -import * as userSettings from '../../scripts/settings/userSettings'; -import focusManager from '../../components/focusManager'; -import cardBuilder from '../../components/cardbuilder/cardBuilder'; -import loading from '../../components/loading/loading'; -import AlphaNumericShortcuts from '../../scripts/alphanumericshortcuts'; -import libraryBrowser from '../../scripts/libraryBrowser'; -import { playbackManager } from '../../components/playback/playbackmanager'; -import AlphaPicker from '../../components/alphaPicker/alphaPicker'; -import '../../elements/emby-itemscontainer/emby-itemscontainer'; -import '../../elements/emby-scroller/emby-scroller'; -import ServerConnections from '../../components/ServerConnections'; -import LibraryMenu from '../../scripts/libraryMenu'; -import { CollectionType } from '@jellyfin/sdk/lib/generated-client/models/collection-type'; -import { ItemSortBy } from '@jellyfin/sdk/lib/generated-client/models/item-sort-by'; - - -function modifyQueryWithFilters(instance, query) { - const sortValues = instance.getSortValues(); - - if (!query.SortBy) { - query.SortBy = sortValues.sortBy; - query.SortOrder = sortValues.sortOrder; - } - - query.Fields = query.Fields ? query.Fields + ',PrimaryImageAspectRatio' : 'PrimaryImageAspectRatio'; - query.ImageTypeLimit = 1; - let hasFilters; - const queryFilters = []; - const filters = instance.getFilters(); - - if (filters.IsPlayed) { - queryFilters.push('IsPlayed'); - hasFilters = true; - } - - if (filters.IsUnplayed) { - queryFilters.push('IsUnplayed'); - hasFilters = true; - } - - if (filters.IsFavorite) { - queryFilters.push('IsFavorite'); - hasFilters = true; - } - - if (filters.IsResumable) { - queryFilters.push('IsResumable'); - hasFilters = true; - } - - if (filters.VideoTypes) { - hasFilters = true; - query.VideoTypes = filters.VideoTypes; - } - - if (filters.GenreIds) { - hasFilters = true; - query.GenreIds = filters.GenreIds; - } - - if (filters.Is4K) { - query.Is4K = true; - hasFilters = true; - } - - if (filters.IsHD) { - query.IsHD = true; - hasFilters = true; - } - - if (filters.IsSD) { - query.IsHD = false; - hasFilters = true; - } - - if (filters.Is3D) { - query.Is3D = true; - hasFilters = true; - } - - if (filters.HasSubtitles) { - query.HasSubtitles = true; - hasFilters = true; - } - - if (filters.HasTrailer) { - query.HasTrailer = true; - hasFilters = true; - } - - if (filters.HasSpecialFeature) { - query.HasSpecialFeature = true; - hasFilters = true; - } - - if (filters.HasThemeSong) { - query.HasThemeSong = true; - hasFilters = true; - } - - if (filters.HasThemeVideo) { - query.HasThemeVideo = true; - hasFilters = true; - } - - query.Filters = queryFilters.length ? queryFilters.join(',') : null; - instance.setFilterStatus(hasFilters); - - if (instance.alphaPicker) { - const newValue = instance.alphaPicker.value(); - if (newValue === '#') { - query.NameLessThan = 'A'; - delete query.NameStartsWith; - } else { - query.NameStartsWith = newValue; - delete query.NameLessThan; - } - } - - return query; -} - -function setSortButtonIcon(btnSortIcon, icon) { - btnSortIcon.classList.remove('arrow_downward'); - btnSortIcon.classList.remove('arrow_upward'); - btnSortIcon.classList.add(icon); -} - -function updateSortText(instance) { - const btnSortText = instance.btnSortText; - - if (btnSortText) { - const options = instance.getSortMenuOptions(); - const values = instance.getSortValues(); - const sortBy = values.sortBy; - - for (const option of options) { - if (sortBy === option.value) { - btnSortText.innerHTML = globalize.translate('SortByValue', option.name); - break; - } - } - - const btnSortIcon = instance.btnSortIcon; - - if (btnSortIcon) { - setSortButtonIcon(btnSortIcon, values.sortOrder === 'Descending' ? 'arrow_downward' : 'arrow_upward'); - } - } -} - -function updateItemsContainerForViewType(instance) { - if (instance.getViewSettings().imageType === 'list') { - instance.itemsContainer.classList.remove('vertical-wrap'); - instance.itemsContainer.classList.add('vertical-list'); - } else { - instance.itemsContainer.classList.add('vertical-wrap'); - instance.itemsContainer.classList.remove('vertical-list'); - } -} - -function updateAlphaPickerState(instance) { - if (instance.alphaPicker) { - const alphaPicker = instance.alphaPickerElement; - - if (alphaPicker) { - const values = instance.getSortValues(); - - if (values.sortBy.indexOf(ItemSortBy.SortName) !== -1) { - alphaPicker.classList.remove('hide'); - instance.itemsContainer.parentNode.classList.add('padded-right-withalphapicker'); - } else { - alphaPicker.classList.add('hide'); - instance.itemsContainer.parentNode.classList.remove('padded-right-withalphapicker'); - } - } - } -} - -function getItems(instance, params, item, sortBy, startIndex, limit) { - const apiClient = ServerConnections.currentApiClient(); - - instance.queryRecursive = false; - - if (!item) { - instance.queryRecursive = true; - - return apiClient['getItems'](apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { - StartIndex: startIndex, - Limit: limit, - Fields: 'PrimaryImageAspectRatio,SortName', - ImageTypeLimit: 1, - IncludeItemTypes: 'AudioBook,Book', - Recursive: true, - IsFavorite: params.IsFavorite === 'true' || null, - ArtistIds: params.artistId || null, - SortBy: sortBy - })); - } - - return apiClient.getItems(apiClient.getCurrentUserId(), modifyQueryWithFilters(instance, { - StartIndex: startIndex, - Limit: limit, - Fields: 'PrimaryImageAspectRatio,SortName,Path,ChildCount,MediaSourceCount', - ImageTypeLimit: 1, - ParentId: item.Id, - SortBy: sortBy, - // IncludeItemTypes: 'AudioBook'? - })); -} - -function getItem(params) { - if (params.type === 'Recordings' || params.type === 'Programs' || params.type === 'nextup') { - return Promise.resolve(null); - } - - const apiClient = ServerConnections.currentApiClient(); - const itemId = params.genreId || params.musicGenreId || params.studioId || params.personId || params.parentId; - - if (itemId) { - return apiClient.getItem(apiClient.getCurrentUserId(), itemId); - } - - return Promise.resolve(null); -} - -function showViewSettingsMenu() { - const instance = this; - - import('../../components/viewSettings/viewSettings').then(({ default: ViewSettings }) => { - new ViewSettings().show({ - settingsKey: instance.getSettingsKey(), - settings: instance.getViewSettings(), - visibleSettings: instance.getVisibleViewSettings() - }).then(function () { - updateItemsContainerForViewType(instance); - instance.itemsContainer.refreshItems(); - }); - }); -} - -function showFilterMenu() { - const instance = this; - - import('../../components/filtermenu/filtermenu').then(({ default: FilterMenu }) => { - new FilterMenu().show({ - settingsKey: instance.getSettingsKey(), - settings: instance.getFilters(), - visibleSettings: instance.getVisibleFilters(), - onChange: instance.itemsContainer.refreshItems.bind(instance.itemsContainer), - parentId: instance.params.parentId, - itemTypes: instance.getItemTypes(), - serverId: instance.params.serverId, - filterMenuOptions: instance.getFilterMenuOptions() - }).then(function () { - instance.itemsContainer.refreshItems(); - }); - }); -} - -function showSortMenu() { - const instance = this; - - import('../../components/sortmenu/sortmenu').then(({ default: SortMenu }) => { - new SortMenu().show({ - settingsKey: instance.getSettingsKey(), - settings: instance.getSortValues(), - onChange: instance.itemsContainer.refreshItems.bind(instance.itemsContainer), - serverId: instance.params.serverId, - sortOptions: instance.getSortMenuOptions() - }).then(function () { - updateSortText(instance); - updateAlphaPickerState(instance); - instance.itemsContainer.refreshItems(); - }); - }); -} - -function onNewItemClick() { - const instance = this; - - import('../../components/playlisteditor/playlisteditor').then(({ default: PlaylistEditor }) => { - const playlistEditor = new PlaylistEditor(); - playlistEditor.show({ - items: [], - serverId: instance.params.serverId - }).catch(() => { - // Dialog closed - }); - }).catch(err => { - console.error('[onNewItemClick] failed to load playlist editor', err); - }); -} - -function hideOrShowAll(elems, hide) { - for (const elem of elems) { - if (hide) { - elem.classList.add('hide'); - } else { - elem.classList.remove('hide'); - } - } -} - -function bindAll(elems, eventName, fn) { - for (const elem of elems) { - elem.addEventListener(eventName, fn); - } -} - -class BooksView { - constructor(view, params) { - const query = { - StartIndex: 0, - Limit: undefined - }; - - if (userSettings.libraryPageSize() > 0) { - query['Limit'] = userSettings.libraryPageSize(); - } - - let isLoading = false; - - function onNextPageClick() { - if (!isLoading && query.Limit > 0) { - query.StartIndex += query.Limit; - self.itemsContainer.refreshItems().then(() => { - window.scrollTo(0, 0); - autoFocus(); - }); - } - } - - function onPreviousPageClick() { - if (!isLoading && query.Limit > 0) { - query.StartIndex = Math.max(0, query.StartIndex - query.Limit); - self.itemsContainer.refreshItems().then(() => { - window.scrollTo(0, 0); - autoFocus(); - }); - } - } - - function updatePaging(startIndex, totalRecordCount, limit) { - const pagingHtml = libraryBrowser.getQueryPagingHtml({ - startIndex, - limit, - totalRecordCount, - showLimit: false, - updatePageSizeSetting: false, - addLayoutButton: false, - sortButton: false, - filterButton: false - }); - - for (const elem of view.querySelectorAll('.paging')) { - elem.innerHTML = pagingHtml; - } - - for (const elem of view.querySelectorAll('.btnNextPage')) { - elem.addEventListener('click', onNextPageClick); - } - - for (const elem of view.querySelectorAll('.btnPreviousPage')) { - elem.addEventListener('click', onPreviousPageClick); - } - } - - function fetchData() { - isLoading = true; - - return getItems(self, params, self.currentItem, null, query.StartIndex, query.Limit).then(function (result) { - if (self.totalItemCount == null) { - self.totalItemCount = result.Items ? result.Items.length : result.length; - } - - updateAlphaPickerState(self); - updatePaging(result.StartIndex, result.TotalRecordCount, query.Limit); - return result; - }).finally(() => { - isLoading = false; - }); - } - - function getItemsHtml(items) { - const settings = self.getViewSettings(); - - if (settings.imageType === 'list') { - return listView.getListViewHtml({ - items: items - }); - } - - let shape; - let preferThumb; - let preferDisc; - let preferLogo; - let defaultShape; - const item = self.currentItem; - let lines = settings.showTitle ? 2 : 0; - - if (settings.imageType === 'banner') { - shape = 'banner'; - } else if (settings.imageType === 'disc') { - shape = 'square'; - preferDisc = true; - } else if (settings.imageType === 'logo') { - shape = 'backdrop'; - preferLogo = true; - } else if (settings.imageType === 'thumb') { - shape = 'backdrop'; - preferThumb = true; - } else if (params.type === 'nextup') { - shape = 'backdrop'; - preferThumb = settings.imageType === 'thumb'; - } else if (params.type === 'Programs' || params.type === 'Recordings') { - shape = params.IsMovie === 'true' ? 'portrait' : 'autoVertical'; - preferThumb = params.IsMovie !== 'true' ? 'auto' : false; - defaultShape = params.IsMovie === 'true' ? 'portrait' : 'backdrop'; - } else { - shape = 'autoVertical'; - } - - let posterOptions = { - shape: shape, - showTitle: settings.showTitle, - showYear: settings.showTitle, - centerText: true, - coverImage: true, - preferThumb: preferThumb, - preferDisc: preferDisc, - preferLogo: preferLogo, - overlayPlayButton: false, - overlayMoreButton: true, - overlayText: !settings.showTitle, - defaultShape: defaultShape, - action: params.type === 'Audio' ? 'playallfromhere' : null - }; - - if (params.type === 'nextup') { - posterOptions.showParentTitle = settings.showTitle; - } else if (params.type === 'Person') { - posterOptions.showYear = false; - posterOptions.showParentTitle = false; - lines = 1; - } else if (params.type === 'Audio') { - posterOptions.showParentTitle = settings.showTitle; - } else if (params.type === 'MusicAlbum') { - posterOptions.showParentTitle = settings.showTitle; - } else if (params.type === 'Episode') { - posterOptions.showParentTitle = settings.showTitle; - } else if (params.type === 'MusicArtist') { - posterOptions.showYear = false; - lines = 1; - } else if (params.type === 'Programs') { - lines = settings.showTitle ? 1 : 0; - const showParentTitle = settings.showTitle && params.IsMovie !== 'true'; - - if (showParentTitle) { - lines++; - } - - const showAirTime = settings.showTitle && params.type !== 'Recordings'; - - if (showAirTime) { - lines++; - } - - const showYear = settings.showTitle && params.IsMovie === 'true' && params.type === 'Recordings'; - - if (showYear) { - lines++; - } - - posterOptions = Object.assign(posterOptions, { - inheritThumb: params.type === 'Recordings', - context: 'livetv', - showParentTitle: showParentTitle, - showAirTime: showAirTime, - showAirDateTime: showAirTime, - overlayPlayButton: false, - overlayMoreButton: true, - showYear: showYear, - coverImage: true - }); - } else { - posterOptions.showParentTitle = settings.showTitle; - } - - posterOptions.lines = lines; - posterOptions.items = items; - - if (item && item.CollectionType === CollectionType.Folders) { - posterOptions.context = 'folders'; - } - - return cardBuilder.getCardsHtml(posterOptions); - } - - function initAlphaPicker() { - self.scroller = view.querySelector('.scrollFrameY'); - const alphaPickerElement = self.alphaPickerElement; - - alphaPickerElement.classList.add('alphaPicker-fixed-right'); - alphaPickerElement.classList.add('focuscontainer-right'); - self.itemsContainer.parentNode.classList.add('padded-right-withalphapicker'); - - self.alphaPicker = new AlphaPicker({ - element: alphaPickerElement, - valueChangeEvent: 'click' - }); - self.alphaPicker.on('alphavaluechanged', onAlphaPickerValueChanged); - } - - function onAlphaPickerValueChanged() { - query.StartIndex = 0; - self.itemsContainer.refreshItems(); - } - - function setTitle(item) { - LibraryMenu.setTitle(getTitle(item) || ''); - - if (item && item.CollectionType === CollectionType.Playlists) { - hideOrShowAll(view.querySelectorAll('.btnNewItem'), false); - } else { - hideOrShowAll(view.querySelectorAll('.btnNewItem'), true); - } - } - - function getTitle(item) { - - if (params.type === 'nextup') { - return globalize.translate('NextUp'); - } - - if (item) { - return item.Name; - } - - if (params.type === 'Movie') { - return globalize.translate('Movies'); - } - - if (params.type === 'Series') { - return globalize.translate('Shows'); - } - - if (params.type === 'Season') { - return globalize.translate('Seasons'); - } - - if (params.type === 'Episode') { - return globalize.translate('Episodes'); - } - - if (params.type === 'MusicArtist') { - return globalize.translate('Artists'); - } - - if (params.type === 'MusicAlbum') { - return globalize.translate('Albums'); - } - - if (params.type === 'Audio') { - return globalize.translate('Songs'); - } - - if (params.type === 'Video') { - return globalize.translate('Videos'); - } - } - - function play() { - const currentItem = self.currentItem; - - if (currentItem && !self.hasFilters) { - const values = self.getSortValues(); - playbackManager.play({ - items: [currentItem], - queryOptions: { - SortBy: values.sortBy, - SortOrder: values.sortOrder - }, - autoplay: true - }); - } else { - // This is the call we can use for resume playback - getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { - playbackManager.play({ - items: result.Items, - autoplay: true - }); - }); - } - } - - function queue() { - const currentItem = self.currentItem; - - if (currentItem && !self.hasFilters) { - playbackManager.queue({ - items: [currentItem] - }); - } else { - getItems(self, self.params, currentItem, null, 0, 300).then(function (result) { - playbackManager.queue({ - items: result.Items - }); - }); - } - } - - function shuffle() { - const currentItem = self.currentItem; - - if (currentItem && !self.hasFilters) { - playbackManager.shuffle(currentItem); - } else { - getItems(self, self.params, currentItem, 'Random', 0, 300).then(function (result) { - playbackManager.play({ - items: result.Items, - autoplay: true - }); - }); - } - } - - function autoFocus() { - import('../../components/autoFocuser').then(({ default: autoFocuser }) => { - autoFocuser.autoFocus(view); - }); - } - - const self = this; - self.params = params; - this.itemsContainer = view.querySelector('.itemsContainer'); - - if (params.parentId) { - this.itemsContainer.setAttribute('data-parentid', params.parentId); - } else if (params.type === 'nextup') { - this.itemsContainer.setAttribute('data-monitor', 'videoplayback'); - } else if (params.type === 'favoritemovies') { - this.itemsContainer.setAttribute('data-monitor', 'markfavorite'); - } else if (params.type === 'Programs') { - this.itemsContainer.setAttribute('data-refreshinterval', '300000'); - } - - const btnViewSettings = view.querySelectorAll('.btnViewSettings'); - - for (const btnViewSetting of btnViewSettings) { - btnViewSetting.addEventListener('click', showViewSettingsMenu.bind(this)); - } - - const filterButtons = view.querySelectorAll('.btnFilter'); - this.filterButtons = filterButtons; - const hasVisibleFilters = this.getVisibleFilters().length; - - for (const btnFilter of filterButtons) { - btnFilter.addEventListener('click', showFilterMenu.bind(this)); - - if (hasVisibleFilters) { - btnFilter.classList.remove('hide'); - } else { - btnFilter.classList.add('hide'); - } - } - - const sortButtons = view.querySelectorAll('.btnSort'); - - this.sortButtons = sortButtons; - for (const sortButton of sortButtons) { - sortButton.addEventListener('click', showSortMenu.bind(this)); - - if (params.type !== 'nextup') { - sortButton.classList.remove('hide'); - } - } - - this.btnSortText = view.querySelector('.btnSortText'); - this.btnSortIcon = view.querySelector('.btnSortIcon'); - bindAll(view.querySelectorAll('.btnNewItem'), 'click', onNewItemClick.bind(this)); - this.alphaPickerElement = view.querySelector('.alphaPicker'); - self.itemsContainer.fetchData = fetchData; - self.itemsContainer.getItemsHtml = getItemsHtml; - view.addEventListener('viewshow', function (e) { - const isRestored = e.detail.isRestored; - - if (!isRestored) { - loading.show(); - updateSortText(self); - updateItemsContainerForViewType(self); - } - - setTitle(null); - getItem(params).then(function (item) { - setTitle(item); - self.currentItem = item; - const refresh = !isRestored; - self.itemsContainer.resume({ - refresh: refresh - }).then(function () { - loading.hide(); - - if (refresh) { - focusManager.autoFocus(self.itemsContainer); - } - }); - - if (!isRestored && item && item.Type !== 'PhotoAlbum') { - initAlphaPicker(); - } - - const itemType = item ? item.Type : null; - - if ((itemType === 'MusicGenre' || params.type !== 'Programs' && itemType !== 'Channel') - // Folder, Playlist views - && itemType !== 'UserView' - // Only Photo (homevideos) CollectionFolders are supported - && !(itemType === 'CollectionFolder' && item?.CollectionType !== CollectionType.Homevideos) - ) { - // Show Play All buttons - hideOrShowAll(view.querySelectorAll('.btnPlay'), false); - } else { - // Hide Play All buttons - hideOrShowAll(view.querySelectorAll('.btnPlay'), true); - } - - if ((itemType === 'MusicGenre' || params.type !== 'Programs' && params.type !== 'nextup' && itemType !== 'Channel') - // Folder, Playlist views - && itemType !== 'UserView' - // Only Photo (homevideos) CollectionFolders are supported - && !(itemType === 'CollectionFolder' && item?.CollectionType !== CollectionType.Homevideos) - ) { - // Show Shuffle buttons - hideOrShowAll(view.querySelectorAll('.btnShuffle'), false); - } else { - // Hide Shuffle buttons - hideOrShowAll(view.querySelectorAll('.btnShuffle'), true); - } - - if (item && playbackManager.canQueue(item)) { - // Show Queue button - hideOrShowAll(view.querySelectorAll('.btnQueue'), false); - } else { - // Hide Queue button - hideOrShowAll(view.querySelectorAll('.btnQueue'), true); - } - }); - - if (!isRestored) { - bindAll(view.querySelectorAll('.btnPlay'), 'click', play); - bindAll(view.querySelectorAll('.btnQueue'), 'click', queue); - bindAll(view.querySelectorAll('.btnShuffle'), 'click', shuffle); - } - - self.alphaNumericShortcuts = new AlphaNumericShortcuts({ - itemsContainer: self.itemsContainer - }); - }); - view.addEventListener('viewhide', function () { - const itemsContainer = self.itemsContainer; - - if (itemsContainer) { - itemsContainer.pause(); - } - - const alphaNumericShortcuts = self.alphaNumericShortcuts; - - if (alphaNumericShortcuts) { - alphaNumericShortcuts.destroy(); - self.alphaNumericShortcuts = null; - } - }); - view.addEventListener('viewdestroy', function () { - if (self.listController) { - self.listController.destroy(); - } - - if (self.alphaPicker) { - self.alphaPicker.off('alphavaluechanged', onAlphaPickerValueChanged); - self.alphaPicker.destroy(); - } - - self.currentItem = null; - self.scroller = null; - self.itemsContainer = null; - self.filterButtons = null; - self.sortButtons = null; - self.btnSortText = null; - self.btnSortIcon = null; - self.alphaPickerElement = null; - }); - } - - getFilters() { - const basekey = this.getSettingsKey(); - return { - IsPlayed: userSettings.getFilter(basekey + '-filter-IsPlayed') === 'true', - IsUnplayed: userSettings.getFilter(basekey + '-filter-IsUnplayed') === 'true', - IsFavorite: userSettings.getFilter(basekey + '-filter-IsFavorite') === 'true', - IsResumable: userSettings.getFilter(basekey + '-filter-IsResumable') === 'true', - Is4K: userSettings.getFilter(basekey + '-filter-Is4K') === 'true', - IsHD: userSettings.getFilter(basekey + '-filter-IsHD') === 'true', - IsSD: userSettings.getFilter(basekey + '-filter-IsSD') === 'true', - Is3D: userSettings.getFilter(basekey + '-filter-Is3D') === 'true', - VideoTypes: userSettings.getFilter(basekey + '-filter-VideoTypes'), - SeriesStatus: userSettings.getFilter(basekey + '-filter-SeriesStatus'), - HasSubtitles: userSettings.getFilter(basekey + '-filter-HasSubtitles'), - HasTrailer: userSettings.getFilter(basekey + '-filter-HasTrailer'), - HasSpecialFeature: userSettings.getFilter(basekey + '-filter-HasSpecialFeature'), - HasThemeSong: userSettings.getFilter(basekey + '-filter-HasThemeSong'), - HasThemeVideo: userSettings.getFilter(basekey + '-filter-HasThemeVideo'), - GenreIds: userSettings.getFilter(basekey + '-filter-GenreIds') - }; - } - - getSortValues() { - const basekey = this.getSettingsKey(); - return userSettings.getSortValuesLegacy(basekey, this.getDefaultSortBy()); - } - - getDefaultSortBy() { - const sortNameOption = this.getNameSortOption(this.params); - - if (this.params.type) { - return sortNameOption.value; - } - - return `${ItemSortBy.IsFolder},${sortNameOption.value}`; - } - - getSortMenuOptions() { - const sortBy = []; - - if (this.params.type === 'Programs') { - sortBy.push({ - name: globalize.translate('AirDate'), - value: [ItemSortBy.StartDate, ItemSortBy.SortName].join(',') - }); - } - - let option = this.getNameSortOption(this.params); - - if (option) { - sortBy.push(option); - } - - option = this.getCommunityRatingSortOption(); - - if (option) { - sortBy.push(option); - } - - option = this.getCriticRatingSortOption(); - - if (option) { - sortBy.push(option); - } - - if (this.params.type !== 'Programs') { - sortBy.push({ - name: globalize.translate('DateAdded'), - value: [ItemSortBy.DateCreated, ItemSortBy.SortName].join(',') - }); - } - - option = this.getDatePlayedSortOption(); - - if (option) { - sortBy.push(option); - } - - if (!this.params.type) { - option = this.getNameSortOption(this.params); - sortBy.push({ - name: globalize.translate('Folders'), - value: `${ItemSortBy.IsFolder},${option.value}` - }); - } - - sortBy.push({ - name: globalize.translate('ParentalRating'), - value: [ItemSortBy.OfficialRating, ItemSortBy.SortName].join(',') - }); - option = this.getPlayCountSortOption(); - - if (option) { - sortBy.push(option); - } - - sortBy.push({ - name: globalize.translate('ReleaseDate'), - value: [ItemSortBy.ProductionYear, ItemSortBy.PremiereDate, ItemSortBy.SortName].join(',') - }); - sortBy.push({ - name: globalize.translate('Runtime'), - value: [ItemSortBy.Runtime, ItemSortBy.SortName].join(',') - }); - return sortBy; - } - - getNameSortOption(params) { - if (params.type === 'Episode') { - return { - name: globalize.translate('Name'), - value: [ItemSortBy.SeriesSortName, ItemSortBy.SortName].join(',') - }; - } - - return { - name: globalize.translate('Name'), - value: ItemSortBy.SortName - }; - } - - getPlayCountSortOption() { - if (this.params.type === 'Programs') { - return null; - } - - return { - name: globalize.translate('PlayCount'), - value: [ItemSortBy.PlayCount, ItemSortBy.SortName].join(',') - }; - } - - getDatePlayedSortOption() { - if (this.params.type === 'Programs') { - return null; - } - - return { - name: globalize.translate('DatePlayed'), - value: [ItemSortBy.DatePlayed, ItemSortBy.SortName].join(',') - }; - } - - getCriticRatingSortOption() { - if (this.params.type === 'Programs') { - return null; - } - - return { - name: globalize.translate('CriticRating'), - value: [ItemSortBy.CriticRating, ItemSortBy.SortName].join(',') - }; - } - - getCommunityRatingSortOption() { - return { - name: globalize.translate('CommunityRating'), - value: [ItemSortBy.CommunityRating, ItemSortBy.SortName].join(',') - }; - } - - getVisibleFilters() { - const filters = []; - const params = this.params; - - if (params.type !== 'nextup') { - if (params.type === 'Programs') { - filters.push('Genres'); - } else { - filters.push('IsUnplayed'); - filters.push('IsPlayed'); - - if (!params.IsFavorite) { - filters.push('IsFavorite'); - } - - filters.push('IsResumable'); - filters.push('VideoType'); - filters.push('HasSubtitles'); - filters.push('HasTrailer'); - filters.push('HasSpecialFeature'); - filters.push('HasThemeSong'); - filters.push('HasThemeVideo'); - } - } - - return filters; - } - - setFilterStatus(hasFilters) { - this.hasFilters = hasFilters; - const filterButtons = this.filterButtons; - - if (filterButtons.length) { - for (const btnFilter of filterButtons) { - let bubble = btnFilter.querySelector('.filterButtonBubble'); - - if (!bubble) { - if (!hasFilters) { - continue; - } - - btnFilter.insertAdjacentHTML('afterbegin', '
!
'); - btnFilter.classList.add('btnFilterWithBubble'); - bubble = btnFilter.querySelector('.filterButtonBubble'); - } - - if (hasFilters) { - bubble.classList.remove('hide'); - } else { - bubble.classList.add('hide'); - } - } - } - } - - getFilterMenuOptions() { - const params = this.params; - return { - IsAiring: params.IsAiring, - IsMovie: params.IsMovie, - IsSports: params.IsSports, - IsKids: params.IsKids, - IsNews: params.IsNews, - IsSeries: params.IsSeries, - Recursive: this.queryRecursive - }; - } - - getVisibleViewSettings() { - const item = this.currentItem; - const fields = ['showTitle']; - - if (!item || item.Type !== 'PhotoAlbum' && item.Type !== 'ChannelFolderItem') { - fields.push('imageType'); - } - - fields.push('viewType'); - return fields; - } - - getViewSettings() { - const basekey = this.getSettingsKey(); - const params = this.params; - const item = this.currentItem; - let showTitle = userSettings.get(basekey + '-showTitle'); - - if (showTitle === 'true') { - showTitle = true; - } else if (showTitle === 'false') { - showTitle = false; - } else if (params.type === 'Programs' || params.type === 'Recordings' || params.type === 'Person' || params.type === 'nextup' || params.type === 'Audio' || params.type === 'MusicAlbum' || params.type === 'MusicArtist') { - showTitle = true; - } else if (item && item.Type !== 'PhotoAlbum') { - showTitle = true; - } - - let imageType = userSettings.get(basekey + '-imageType'); - - if (!imageType && params.type === 'nextup') { - if (userSettings.useEpisodeImagesInNextUpAndResume()) { - imageType = 'primary'; - } else { - imageType = 'thumb'; - } - } - - return { - showTitle: showTitle, - showYear: userSettings.get(basekey + '-showYear') !== 'false', - imageType: imageType || 'primary', - viewType: userSettings.get(basekey + '-viewType') || 'images' - }; - } - - getItemTypes() { - const params = this.params; - - if (params.type === 'nextup') { - return ['Episode']; - } - - if (params.type === 'Programs') { - return ['Program']; - } - - return []; - } - - getSettingsKey() { - const values = []; - values.push('items'); - const params = this.params; - - if (params.type) { - values.push(params.type); - } else if (params.parentId) { - values.push(params.parentId); - } - - if (params.IsAiring) { - values.push('IsAiring'); - } - - if (params.IsMovie) { - values.push('IsMovie'); - } - - if (params.IsKids) { - values.push('IsKids'); - } - - if (params.IsSports) { - values.push('IsSports'); - } - - if (params.IsNews) { - values.push('IsNews'); - } - - if (params.IsSeries) { - values.push('IsSeries'); - } - - if (params.IsFavorite) { - values.push('IsFavorite'); - } - - if (params.genreId) { - values.push('Genre'); - } - - if (params.musicGenreId) { - values.push('MusicGenre'); - } - - if (params.studioId) { - values.push('Studio'); - } - - if (params.personId) { - values.push('Person'); - } - - if (params.parentId) { - values.push('Folder'); - } - - return values.join('-'); - } -} - -export default BooksView; -