diff --git a/package-lock.json b/package-lock.json index c280d080d..652a9cc9f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3010,6 +3010,11 @@ "version": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz", "integrity": "sha512-5rjszPzcjFVoDEOarszcbax2WIGT3+fO+W212ZWg9+ylGJgxG1IIcCFjnnBbSdM0lNeIfmMGhhEGovIlr+1yBg==" }, + "classnames": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz", + "integrity": "sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==" + }, "clean-css": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz", diff --git a/package.json b/package.json index 218e2b090..6cc0f8de3 100644 --- a/package.json +++ b/package.json @@ -58,6 +58,7 @@ "@fontsource/noto-sans-sc": "^4.2.1", "blurhash": "^1.1.3", "classlist.js": "https://github.com/eligrey/classList.js/archive/1.2.20180112.tar.gz", + "classnames": "^2.3.1", "core-js": "^3.11.2", "date-fns": "^2.21.1", "epubjs": "^0.3.85", diff --git a/src/components/pages/SearchPage.js b/src/components/pages/SearchPage.js index ea37bfec5..93e277988 100644 --- a/src/components/pages/SearchPage.js +++ b/src/components/pages/SearchPage.js @@ -2,8 +2,9 @@ import PropTypes from 'prop-types'; import React, { useState } from 'react'; import SearchFields from '../search/SearchFields'; -import SearchResults from '../search/SearchResultsComponent'; +import SearchResults from '../search/SearchResults'; import SearchSuggestions from '../search/SearchSuggestions'; +import LiveTVSearchResults from '../search/LiveTVSearchResults'; const SearchPage = ({ serverId, parentId, collectionType }) => { const [ query, setQuery ] = useState(null); @@ -23,6 +24,12 @@ const SearchPage = ({ serverId, parentId, collectionType }) => { collectionType={collectionType} query={query} /> + ); }; diff --git a/src/components/search/LiveTVSearchResults.js b/src/components/search/LiveTVSearchResults.js new file mode 100644 index 000000000..c4ffa6a51 --- /dev/null +++ b/src/components/search/LiveTVSearchResults.js @@ -0,0 +1,195 @@ +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React, { useEffect, useState } from 'react'; + +import globalize from '../../scripts/globalize'; +import ServerConnections from '../ServerConnections'; +import SearchResultsRow from './SearchResultsRow'; + +const CARD_OPTIONS = { + preferThumb: true, + inheritThumb: false, + showParentTitleOrTitle: true, + showTitle: false, + coverImage: true, + overlayMoreButton: true, + showAirTime: true, + showAirDateTime: true, + showChannelName: true +}; + +const LiveTVSearchResults = ({ serverId, parentId, collectionType, query }) => { + const [ apiClient, setApiClient ] = useState(); + const [ movies, setMovies ] = useState([]); + const [ episodes, setEpisodes ] = useState([]); + const [ sports, setSports ] = useState([]); + const [ kids, setKids ] = useState([]); + const [ news, setNews ] = useState([]); + const [ programs, setPrograms ] = useState([]); + const [ videos, setVideos ] = useState([]); + + const getDefaultParameters = () => ({ + ParentId: parentId, + searchTerm: query, + Limit: 24, + Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount', + Recursive: true, + EnableTotalRecordCount: false, + ImageTypeLimit: 1, + IncludePeople: false, + IncludeMedia: false, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false + }); + + // FIXME: This query does not support Live TV filters + const fetchItems = (apiClient, params = {}) => apiClient?.getItems( + apiClient?.getCurrentUserId(), + { + ...getDefaultParameters(), + IncludeMedia: true, + ...params + } + ); + + const isLiveTV = () => collectionType === 'livetv'; + + useEffect(() => { + if (serverId) setApiClient(ServerConnections.getApiClient(serverId)); + }, [ serverId ]); + + useEffect(() => { + // Reset state + setMovies([]); + setEpisodes([]); + setSports([]); + setKids([]); + setNews([]); + setPrograms([]); + setVideos([]); + + if (query && isLiveTV()) { + // Movies row + fetchItems(apiClient, { + IncludeItemTypes: 'LiveTvProgram', + IsMovie: true, + IsSeries: false, + IsSports: false, + IsKids: false, + IsNews: false + }).then(result => setMovies(result.Items)); + // Episodes row + fetchItems(apiClient, { + IncludeItemTypes: 'LiveTvProgram', + IsMovie: false, + IsSeries: true, + IsSports: false, + IsKids: false, + IsNews: false + }).then(result => setEpisodes(result.Items)); + // Sports row + fetchItems(apiClient, { + IncludeItemTypes: 'LiveTvProgram', + IsMovie: false, + IsSeries: false, + IsSports: true, + IsKids: false, + IsNews: false + }).then(result => setSports(result.Items)); + // Kids row + fetchItems(apiClient, { + IncludeItemTypes: 'LiveTvProgram', + IsMovie: false, + IsSeries: false, + IsSports: false, + IsKids: true, + IsNews: false + }).then(result => setKids(result.Items)); + // News row + fetchItems(apiClient, { + IncludeItemTypes: 'LiveTvProgram', + IsMovie: false, + IsSeries: false, + IsSports: false, + IsKids: false, + IsNews: true + }).then(result => setNews(result.Items)); + // Programs row + fetchItems(apiClient, { + IncludeItemTypes: 'LiveTvProgram', + IsMovie: false, + IsSeries: false, + IsSports: false, + IsKids: false, + IsNews: false + }).then(result => setPrograms(result.Items)); + // NOTE: I believe this is supposed to be home videos, but it + // includes TV channels so it should probably be included for Live TV + // Videos row + fetchItems(apiClient, { + MediaTypes: 'Video', + ExcludeItemTypes: 'Movie,Episode' + }).then(result => setVideos(result.Items)); + } + }, [ query ]); + + return ( +
+ + + + + + + +
+ ); +}; + +LiveTVSearchResults.propTypes = { + serverId: PropTypes.string, + parentId: PropTypes.string, + collectionType: PropTypes.string, + query: PropTypes.string +}; + +export default LiveTVSearchResults; diff --git a/src/components/search/SearchResults.js b/src/components/search/SearchResults.js new file mode 100644 index 000000000..daf32d477 --- /dev/null +++ b/src/components/search/SearchResults.js @@ -0,0 +1,258 @@ +import classNames from 'classnames'; +import PropTypes from 'prop-types'; +import React, { useEffect, useState } from 'react'; + +import globalize from '../../scripts/globalize'; +import ServerConnections from '../ServerConnections'; +import SearchResultsRow from './SearchResultsRow'; + +const SearchResultsComponent = ({ serverId, parentId, collectionType, query }) => { + const [ apiClient, setApiClient ] = useState(); + const [ movies, setMovies ] = useState([]); + const [ shows, setShows ] = useState([]); + const [ episodes, setEpisodes ] = useState([]); + const [ programs, setPrograms ] = useState([]); + const [ videos, setVideos ] = useState([]); + const [ playlists, setPlaylists ] = useState([]); + const [ artists, setArtists ] = useState([]); + const [ albums, setAlbums ] = useState([]); + const [ songs, setSongs ] = useState([]); + const [ photoAlbums, setPhotoAlbums ] = useState([]); + const [ photos, setPhotos ] = useState([]); + const [ audioBooks, setAudioBooks ] = useState([]); + const [ books, setBooks ] = useState([]); + const [ people, setPeople ] = useState([]); + + const getDefaultParameters = () => ({ + ParentId: parentId, + searchTerm: query, + Limit: 24, + Fields: 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount', + Recursive: true, + EnableTotalRecordCount: false, + ImageTypeLimit: 1, + IncludePeople: false, + IncludeMedia: false, + IncludeGenres: false, + IncludeStudios: false, + IncludeArtists: false + }); + + const fetchArtists = (apiClient, params = {}) => apiClient?.getArtists( + apiClient?.getCurrentUserId(), + { + ...getDefaultParameters(), + IncludeArtists: true, + ...params + } + ); + + const fetchItems = (apiClient, params = {}) => apiClient?.getItems( + apiClient?.getCurrentUserId(), + { + ...getDefaultParameters(), + IncludeMedia: true, + ...params + } + ); + + const fetchPeople = (apiClient, params = {}) => apiClient?.getPeople( + apiClient?.getCurrentUserId(), + { + ...getDefaultParameters(), + IncludePeople: true, + ...params + } + ); + + const isMovies = () => collectionType === 'movies'; + + const isMusic = () => collectionType === 'music'; + + const isTVShows = () => collectionType === 'tvshows' || collectionType === 'tv'; + + useEffect(() => { + if (serverId) setApiClient(ServerConnections.getApiClient(serverId)); + }, [ serverId ]); + + useEffect(() => { + // Reset state + setMovies([]); + setShows([]); + setEpisodes([]); + setPrograms([]); + setVideos([]); + setPlaylists([]); + setArtists([]); + setAlbums([]); + setSongs([]); + setPhotoAlbums([]); + setPhotos([]); + setAudioBooks([]); + setBooks([]); + setPeople([]); + + if (query) { + // Movie libraries + if (!collectionType || isMovies()) { + // Movies row + fetchItems(apiClient, { IncludeItemTypes: 'Movie' }) + .then(result => setMovies(result.Items)); + } + + // TV Show libraries + if (!collectionType || isTVShows()) { + // Shows row + fetchItems(apiClient, { IncludeItemTypes: 'Series' }) + .then(result => setShows(result.Items)); + // Episodes row + fetchItems(apiClient, { IncludeItemTypes: 'Episode' }) + .then(result => setEpisodes(result.Items)); + } + + // People are included for Movies and TV Shows + if (!collectionType || isMovies() || isTVShows()) { + // People row + fetchPeople(apiClient).then(result => setPeople(result.Items)); + } + + // Music libraries + if (!collectionType || isMusic()) { + // Playlists row + fetchItems(apiClient, { IncludeItemTypes: 'Playlist' }) + .then(results => setPlaylists(results.Items)); + // Artists row + fetchArtists(apiClient).then(result => setArtists(result.Items)); + // Albums row + fetchItems(apiClient, { IncludeItemTypes: 'MusicAlbum' }) + .then(result => setAlbums(result.Items)); + // Songs row + fetchItems(apiClient, { IncludeItemTypes: 'Audio' }) + .then(result => setSongs(result.Items)); + } + + // Other libraries do not support in-library search currently + if (!collectionType) { + // Programs row + fetchItems(apiClient, { IncludeItemTypes: 'LiveTvProgram' }) + .then(result => setPrograms(result.Items)); + // Videos row + fetchItems(apiClient, { + MediaTypes: 'Video', + ExcludeItemTypes: 'Movie,Episode' + }).then(result => setVideos(result.Items)); + // Photo Albums row + fetchItems(apiClient, { IncludeItemTypes: 'PhotoAlbum' }) + .then(results => setPhotoAlbums(results.Items)); + // Photos row + fetchItems(apiClient, { IncludeItemTypes: 'Photo' }) + .then(results => setPhotos(results.Items)); + // Audio Books row + fetchItems(apiClient, { IncludeItemTypes: 'AudioBook' }) + .then(results => setAudioBooks(results.Items)); + // Books row + fetchItems(apiClient, { IncludeItemTypes: 'Book' }) + .then(results => setBooks(results.Items)); + } + } + }, [ query ]); + + return ( +
+ + + + + + + + + + + + + + +
+ ); +}; + +SearchResultsComponent.propTypes = { + serverId: PropTypes.string, + parentId: PropTypes.string, + collectionType: PropTypes.string, + query: PropTypes.string +}; + +export default SearchResultsComponent; diff --git a/src/components/search/SearchResultsComponent.js b/src/components/search/SearchResultsComponent.js deleted file mode 100644 index 925d74987..000000000 --- a/src/components/search/SearchResultsComponent.js +++ /dev/null @@ -1,44 +0,0 @@ -import PropTypes from 'prop-types'; -import React, { useEffect, useRef, useState } from 'react'; - -import SearchResults from './searchresults'; - -const SearchResultsComponent = ({ serverId, parentId, collectionType, query }) => { - const [ searchResults, setSearchResults ] = useState(null); - const searchResultsElement = useRef(null); - - useEffect(() => { - setSearchResults( - new SearchResults({ - element: searchResultsElement.current, - serverId: serverId || ApiClient.serverId(), - parentId, - collectionType - }) - ); - - return () => { - searchResults?.destroy(); - }; - }, []); - - useEffect(() => { - searchResults?.search(query); - }, [ query ]); - - return ( -
- ); -}; - -SearchResultsComponent.propTypes = { - serverId: PropTypes.string, - parentId: PropTypes.string, - collectionType: PropTypes.string, - query: PropTypes.string -}; - -export default SearchResultsComponent; diff --git a/src/components/search/SearchResultsRow.js b/src/components/search/SearchResultsRow.js new file mode 100644 index 000000000..df40154cb --- /dev/null +++ b/src/components/search/SearchResultsRow.js @@ -0,0 +1,48 @@ +import PropTypes from 'prop-types'; +import React, { useEffect, useRef } from 'react'; + +import cardBuilder from '../cardbuilder/cardBuilder'; + +// There seems to be some compatibility issues here between +// React and our legacy web components, so we need to inject +// them as an html string for now =/ +const createScroller = ({ title = '' }) => ({ + __html: `

${title}

+
+
+
` +}); + +const SearchResultsRow = ({ title, items = [], cardOptions = {} }) => { + const element = useRef(null); + + useEffect(() => { + cardBuilder.buildCards(items, { + itemsContainer: element.current?.querySelector('.itemsContainer'), + parentContainer: element.current, + shape: 'autooverflow', + scalable: true, + showTitle: true, + overlayText: false, + centerText: true, + allowBottomPadding: false, + ...cardOptions + }); + }, [ items ]); + + return ( +
+ ); +}; + +SearchResultsRow.propTypes = { + title: PropTypes.string, + items: PropTypes.array, + cardOptions: PropTypes.object +}; + +export default SearchResultsRow; diff --git a/src/components/search/searchresults.js b/src/components/search/searchresults.js deleted file mode 100644 index 263a2b94c..000000000 --- a/src/components/search/searchresults.js +++ /dev/null @@ -1,581 +0,0 @@ -import layoutManager from '../layoutManager'; -import globalize from '../../scripts/globalize'; -import cardBuilder from '../cardbuilder/cardBuilder'; -import '../../elements/emby-scroller/emby-scroller'; -import '../../elements/emby-itemscontainer/emby-itemscontainer'; -import '../../elements/emby-button/emby-button'; -import ServerConnections from '../ServerConnections'; -import template from './searchresults.template.html'; - -function getSearchHints(instance, apiClient, query) { - if (!query.searchTerm) { - return Promise.resolve({ - SearchHints: [] - }); - } - - let allowSearch = true; - - const queryIncludeItemTypes = query.IncludeItemTypes; - - if (instance.options.collectionType === 'tvshows') { - if (query.IncludeArtists) { - allowSearch = false; - } else if (queryIncludeItemTypes === 'Movie' || - queryIncludeItemTypes === 'LiveTvProgram' || - queryIncludeItemTypes === 'MusicAlbum' || - queryIncludeItemTypes === 'Audio' || - queryIncludeItemTypes === 'Book' || - queryIncludeItemTypes === 'AudioBook' || - queryIncludeItemTypes === 'Playlist' || - queryIncludeItemTypes === 'PhotoAlbum' || - query.MediaTypes === 'Video' || - query.MediaTypes === 'Photo') { - allowSearch = false; - } - } else if (instance.options.collectionType === 'movies') { - if (query.IncludeArtists) { - allowSearch = false; - } else if (queryIncludeItemTypes === 'Series' || - queryIncludeItemTypes === 'Episode' || - queryIncludeItemTypes === 'LiveTvProgram' || - queryIncludeItemTypes === 'MusicAlbum' || - queryIncludeItemTypes === 'Audio' || - queryIncludeItemTypes === 'Book' || - queryIncludeItemTypes === 'AudioBook' || - queryIncludeItemTypes === 'Playlist' || - queryIncludeItemTypes === 'PhotoAlbum' || - query.MediaTypes === 'Video' || - query.MediaTypes === 'Photo') { - allowSearch = false; - } - } else if (instance.options.collectionType === 'music') { - if (query.People) { - allowSearch = false; - } else if (queryIncludeItemTypes === 'Series' || - queryIncludeItemTypes === 'Episode' || - queryIncludeItemTypes === 'LiveTvProgram' || - queryIncludeItemTypes === 'Movie') { - allowSearch = false; - } - } else if (instance.options.collectionType === 'livetv') { - if (query.IncludeArtists || query.IncludePeople) { - allowSearch = false; - } else if (queryIncludeItemTypes === 'Series' || - queryIncludeItemTypes === 'Episode' || - queryIncludeItemTypes === 'MusicAlbum' || - queryIncludeItemTypes === 'Audio' || - queryIncludeItemTypes === 'Book' || - queryIncludeItemTypes === 'AudioBook' || - queryIncludeItemTypes === 'PhotoAlbum' || - queryIncludeItemTypes === 'Movie' || - query.MediaTypes === 'Video' || - query.MediaTypes === 'Photo') { - allowSearch = false; - } - } - if (queryIncludeItemTypes === 'NullType') { - allowSearch = false; - } - - if (!allowSearch) { - return Promise.resolve({ - SearchHints: [] - }); - } - - // Convert the search hint query to a regular item query - if (apiClient.isMinServerVersion('3.4.1.31')) { - query.Fields = 'PrimaryImageAspectRatio,CanDelete,BasicSyncInfo,MediaSourceCount'; - query.Recursive = true; - query.EnableTotalRecordCount = false; - query.ImageTypeLimit = 1; - - let methodName = 'getItems'; - - if (!query.IncludeMedia) { - if (query.IncludePeople) { - methodName = 'getPeople'; - } else if (query.IncludeArtists) { - methodName = 'getArtists'; - } - } - - return apiClient[methodName](apiClient.getCurrentUserId(), query); - } - - query.UserId = apiClient.getCurrentUserId(); - - return apiClient.getSearchHints(query); -} - -function search(instance, apiClient, context, value) { - if (value || layoutManager.tv) { - instance.mode = 'search'; - } else { - instance.mode = 'suggestions'; - } - - if (instance.options.collectionType === 'livetv') { - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'LiveTvProgram', - IsMovie: true, - IsKids: false, - IsNews: false - - }, context, '.movieResults', { - - preferThumb: true, - inheritThumb: false, - shape: (enableScrollX() ? 'overflowPortrait' : 'portrait'), - showParentTitleOrTitle: true, - showTitle: false, - centerText: true, - coverImage: true, - overlayText: false, - overlayMoreButton: true, - showAirTime: true, - showAirDateTime: true, - showChannelName: true - }); - } else { - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'Movie' - - }, context, '.movieResults', { - - showTitle: true, - overlayText: false, - centerText: true, - showYear: true - }); - } - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'Series' - - }, context, '.seriesResults', { - - showTitle: true, - overlayText: false, - centerText: true, - showYear: true - }); - - if (instance.options.collectionType === 'livetv') { - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'LiveTvProgram', - IsSeries: true, - IsSports: false, - IsKids: false, - IsNews: false - - }, context, '.episodeResults', { - - preferThumb: true, - inheritThumb: false, - shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), - showParentTitleOrTitle: true, - showTitle: false, - centerText: true, - coverImage: true, - overlayText: false, - overlayMoreButton: true, - showAirTime: true, - showAirDateTime: true, - showChannelName: true - }); - } else { - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'Episode' - - }, context, '.episodeResults', { - - coverImage: true, - showTitle: true, - showParentTitle: true - }); - } - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - // NullType to hide - IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType', - IsSports: true - - }, context, '.sportsResults', { - - preferThumb: true, - inheritThumb: false, - shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), - showParentTitleOrTitle: true, - showTitle: false, - centerText: true, - coverImage: true, - overlayText: false, - overlayMoreButton: true, - showAirTime: true, - showAirDateTime: true, - showChannelName: true - - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - // NullType to hide - IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType', - IsKids: true - - }, context, '.kidsResults', { - - preferThumb: true, - inheritThumb: false, - shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), - showParentTitleOrTitle: true, - showTitle: false, - centerText: true, - coverImage: true, - overlayText: false, - overlayMoreButton: true, - showAirTime: true, - showAirDateTime: true, - showChannelName: true - - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - // NullType to hide - IncludeItemTypes: instance.options.collectionType === 'livetv' ? 'LiveTvProgram' : 'NullType', - IsNews: true - - }, context, '.newsResults', { - - preferThumb: true, - inheritThumb: false, - shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), - showParentTitleOrTitle: true, - showTitle: false, - centerText: true, - coverImage: true, - overlayText: false, - overlayMoreButton: true, - showAirTime: true, - showAirDateTime: true, - showChannelName: true - - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'LiveTvProgram', - IsMovie: instance.options.collectionType === 'livetv' ? false : null, - IsSeries: instance.options.collectionType === 'livetv' ? false : null, - IsSports: instance.options.collectionType === 'livetv' ? false : null, - IsKids: instance.options.collectionType === 'livetv' ? false : null, - IsNews: instance.options.collectionType === 'livetv' ? false : null - - }, context, '.programResults', { - - preferThumb: true, - inheritThumb: false, - shape: (enableScrollX() ? 'overflowBackdrop' : 'backdrop'), - showParentTitleOrTitle: true, - showTitle: false, - centerText: true, - coverImage: true, - overlayText: false, - overlayMoreButton: true, - showAirTime: true, - showAirDateTime: true, - showChannelName: true - - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - MediaTypes: 'Video', - ExcludeItemTypes: 'Movie,Episode' - - }, context, '.videoResults', { - - showParentTitle: true, - showTitle: true, - overlayText: false, - centerText: true - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: true, - IncludeMedia: false, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false - - }, context, '.peopleResults', { - - coverImage: true, - showTitle: true - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: false, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: true - - }, context, '.artistResults', { - coverImage: true, - showTitle: true - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'MusicAlbum' - - }, context, '.albumResults', { - - showParentTitle: true, - showTitle: true, - overlayText: false, - centerText: true - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'Audio' - - }, context, '.songResults', { - - showParentTitle: true, - showTitle: true, - overlayText: false, - centerText: true, - overlayPlayButton: true - - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - MediaTypes: 'Photo' - - }, context, '.photoResults', { - - showParentTitle: false, - showTitle: true, - overlayText: false, - centerText: true - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'PhotoAlbum' - - }, context, '.photoAlbumResults', { - - showTitle: true, - overlayText: false, - centerText: true - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'Book' - - }, context, '.bookResults', { - - showTitle: true, - overlayText: false, - centerText: true - - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'AudioBook' - - }, context, '.audioBookResults', { - - showTitle: true, - overlayText: false, - centerText: true - }); - - searchType(instance, apiClient, { - searchTerm: value, - IncludePeople: false, - IncludeMedia: true, - IncludeGenres: false, - IncludeStudios: false, - IncludeArtists: false, - IncludeItemTypes: 'Playlist' - - }, context, '.playlistResults', { - - showTitle: true, - overlayText: false, - centerText: true - }); -} - -function searchType(instance, apiClient, query, context, section, cardOptions) { - query.Limit = enableScrollX() ? 24 : 16; - query.ParentId = instance.options.parentId; - - getSearchHints(instance, apiClient, query).then(function (result) { - populateResults(result, context, section, cardOptions); - }); -} - -function populateResults(result, context, section, cardOptions) { - section = context.querySelector(section); - - const items = result.Items || result.SearchHints; - - const itemsContainer = section.querySelector('.itemsContainer'); - - cardBuilder.buildCards(items, Object.assign({ - - itemsContainer: itemsContainer, - parentContainer: section, - shape: enableScrollX() ? 'autooverflow' : 'auto', - scalable: true, - overlayText: false, - centerText: true, - allowBottomPadding: !enableScrollX() - - }, cardOptions || {})); -} - -function enableScrollX() { - return true; -} - -function replaceAll(originalString, strReplace, strWith) { - const reg = new RegExp(strReplace, 'ig'); - return originalString.replace(reg, strWith); -} - -function embed(elem, instance) { - let workingTemplate = template; - if (!enableScrollX()) { - workingTemplate = replaceAll(workingTemplate, 'data-horizontal="true"', 'data-horizontal="false"'); - workingTemplate = replaceAll(workingTemplate, 'itemsContainer scrollSlider', 'itemsContainer scrollSlider vertical-wrap'); - } - - const html = globalize.translateHtml(workingTemplate, 'core'); - - elem.innerHTML = html; - - elem.classList.add('searchResults'); - instance.search(''); -} - -class SearchResults { - constructor(options) { - this.options = options; - embed(options.element, this); - } - search(value) { - const apiClient = ServerConnections.getApiClient(this.options.serverId); - - search(this, apiClient, this.options.element, value); - } - destroy() { - const options = this.options; - if (options) { - options.element.classList.remove('searchFields'); - } - this.options = null; - } -} - -export default SearchResults; diff --git a/src/components/search/searchresults.template.html b/src/components/search/searchresults.template.html deleted file mode 100644 index 1deecaca6..000000000 --- a/src/components/search/searchresults.template.html +++ /dev/null @@ -1,145 +0,0 @@ -
- -
-

${Suggestions}

-
- -
-
-
- -
-

${Movies}

- -
-
-
-
- -
-

${Shows}

- -
-
-
-
- -
-

${Episodes}

- -
-
-
-
- -
-

${Sports}

- -
-
-
-
- -
-

${Kids}

- -
-
-
-
- -
-

${News}

- -
-
-
-
- -
-

${Programs}

- -
-
-
-
- -
-

${Videos}

- -
-
-
-
- -
-

${Playlists}

- -
-
-
-
- -
-

${Artists}

- -
-
-
-
- -
-

${Albums}

- -
-
-
-
- -
-

${Songs}

- -
-
-
-
- -
-

${HeaderPhotoAlbums}

- -
-
-
-
- -
-

${Photos}

- -
-
-
-
- -
-

${HeaderAudioBooks}

- -
-
-
-
- -
-

${Books}

- -
-
-
-
- -
-

${People}

- -
-
-
-