diff --git a/backend/src/Models/ItemDTO.cs b/backend/src/Models/ItemDTO.cs index a339783..b9e26d6 100644 --- a/backend/src/Models/ItemDTO.cs +++ b/backend/src/Models/ItemDTO.cs @@ -28,6 +28,4 @@ public class ItemDTO public string? ParentId { get; set; } public string? ThumbnailUrl { get; set; } public string? ProductionYear { get; set; } - public string[]? SubtitleLanguages { get; set; } - public string[]? AudioLanguages { get; set; } } \ No newline at end of file diff --git a/backend/src/Models/JellyfinApi/Item.cs b/backend/src/Models/JellyfinApi/Item.cs index ab15b28..9d0bc38 100644 --- a/backend/src/Models/JellyfinApi/Item.cs +++ b/backend/src/Models/JellyfinApi/Item.cs @@ -21,6 +21,4 @@ public class Item public string Type { get; set; } = string.Empty; public double PrimaryImageAspectRatio { get; set; } public string? CollectionType { get; set; } - public bool? HasSubtitles { get; set; } - public List? MediaStreams { get; set; } } \ No newline at end of file diff --git a/backend/src/Models/JellyfinApi/MediaStream.cs b/backend/src/Models/JellyfinApi/MediaStream.cs deleted file mode 100644 index 376f217..0000000 --- a/backend/src/Models/JellyfinApi/MediaStream.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace JellyGlass.Models.JellyfinApi; - -public class MediaStream -{ - public string Title { get; set; } - public string DisplayTitle { get; set; } - public string Type { get; set; } - public string? LocalizedDefault { get; set; } - public string Language { get; set; } = "undefined"; -} \ No newline at end of file diff --git a/backend/src/Repositories/JellyfinApiClient.cs b/backend/src/Repositories/JellyfinApiClient.cs index acd6d85..4132ffc 100644 --- a/backend/src/Repositories/JellyfinApiClient.cs +++ b/backend/src/Repositories/JellyfinApiClient.cs @@ -46,31 +46,9 @@ public class JellyfinApiClient return apiResponse!.Items.ToArray(); } - public async Task Search(string searchTerm = "", string itemTypes = "Series,Movie", string limit = "") + public async Task GetItems(string searchTerm = "", string years = "", string itemTypes = "", string limit = "", string parentId = "") { - var request = new HttpRequestMessage(HttpMethod.Get, $"{InstanceUrl}/items?searchTerm={searchTerm}&recursive=true&includeItemTypes={itemTypes}&limit={limit}"); - - var response = await MakeRequest(request); - - var apiResponse = await response.Content.ReadFromJsonAsync(); - - return apiResponse!.Items.ToArray(); - } - - public async Task GetMediaInfoFromTvSeries(string seriesId) - { - var request = new HttpRequestMessage(HttpMethod.Get, $"{InstanceUrl}/items?parentId={seriesId}&recursive=true&includeItemTypes=Episode&fields=MediaStreams"); - - var response = await MakeRequest(request); - - var apiResponse = await response.Content.ReadFromJsonAsync(); - - return apiResponse!.Items.ToArray(); - } - - public async Task GetMediaInfoFromMovie(string movieId) - { - var request = new HttpRequestMessage(HttpMethod.Get, $"{InstanceUrl}/items?ids={movieId}&fields=MediaStreams"); + var request = new HttpRequestMessage(HttpMethod.Get, $"{InstanceUrl}/items?searchTerm={searchTerm}&recursive=true&includeItemTypes=Series,Movie"); var response = await MakeRequest(request); diff --git a/backend/src/Services/ClientService.cs b/backend/src/Services/ClientService.cs index 6f00aec..23d1cc4 100644 --- a/backend/src/Services/ClientService.cs +++ b/backend/src/Services/ClientService.cs @@ -43,23 +43,6 @@ public class ClientService : IClientService return client; } - public async Task GetClientFromJellyfinServerID(string jellyfinServerID) - { - if (!_clients.Any()) - { - await LoadClients(); - } - - var client = _clients.FirstOrDefault(c => c.ID == jellyfinServerID); - - if (client == null) - { - throw new Exception($"Could not find a client with ID of {jellyfinServerID}"); - } - - return client; - } - public async Task LoadNewClient(Server server) { var client = new JellyfinApiClient(server.Url, server.ApiToken); diff --git a/backend/src/Services/IClientService.cs b/backend/src/Services/IClientService.cs index b1edec7..f4d3191 100644 --- a/backend/src/Services/IClientService.cs +++ b/backend/src/Services/IClientService.cs @@ -7,7 +7,6 @@ public interface IClientService { public Task GetClients(); public Task GetClientFromUrl(string url); - public Task GetClientFromJellyfinServerID(string jellyfinServerID); //the ID of the jellyfin server, not the server stored in our db public Task LoadNewClient(Server server); public void UnloadClient(JellyfinApiClient client); } \ No newline at end of file diff --git a/backend/src/Services/SearchService.cs b/backend/src/Services/SearchService.cs index 04af3e8..2632e56 100644 --- a/backend/src/Services/SearchService.cs +++ b/backend/src/Services/SearchService.cs @@ -5,12 +5,12 @@ namespace JellyGlass.Services; public class SearchService : ISearchService { - private ILogger _logger; + private ILibraryService _libraryService; private IClientService _clientService; - public SearchService(ILogger logger, IClientService clientService) + public SearchService(ILibraryService libraryService, IClientService clientService) { - _logger = logger; + _libraryService = libraryService; _clientService = clientService; } @@ -18,60 +18,48 @@ public class SearchService : ISearchService { var client = await _clientService.GetClientFromUrl(serverUrl); - var items = await client.Search(searchTerm: searchTerm); + var items = await client.GetItems(searchTerm: searchTerm); var dtos = new List(); foreach (var item in items) { - var dto = new ItemDTO(item, client.InstanceUrl); - var languages = await GetLanguagesForItem(item); - dto.SubtitleLanguages = languages.Item2; - dto.AudioLanguages = languages.Item1; - dtos.Add(dto); + dtos.Add(new ItemDTO(item, client.InstanceUrl)); } return dtos.ToArray(); } - private async Task> GetLanguagesForItem(Item item) + // public async Task Search2(string searchTerm, int serverId) + // { + // var libraries = await _libraryService.GetLibrariesFromServer(serverId); + + // var foundItems = new List(); + + // foreach (var library in libraries) + // { + // var found = await SearchLibraryForTerm(searchTerm, serverId, library); + + // foundItems.AddRange(found); + // } + + // return foundItems.ToArray(); + // } + + private async Task SearchLibraryForTerm(string searchTerm, string serverUrl, Library library) { - var subtitleLanguages = new List(); - var audioLanguages = new List(); - var client = await _clientService.GetClientFromJellyfinServerID(item.ServerId); + var items = await _libraryService.GetItemsFromLibrary(library.Name, serverUrl); - Item[] infoList; + var foundItems = new List(); - if (item.Type == "Movie") + foreach (var item in items) { - infoList = await client.GetMediaInfoFromMovie(item.Id); - } - else if (item.Type == "Series") - { - infoList = await client.GetMediaInfoFromTvSeries(item.Id); - } - else - { - throw new Exception(); - } - - _logger.LogInformation($"Found {infoList.Count()} items"); - - foreach (var info in infoList) - { - foreach (var mediaStream in info.MediaStreams!) + if (item.Name.Contains(searchTerm, StringComparison.CurrentCultureIgnoreCase)) { - if (mediaStream.Type == "Subtitle" && !subtitleLanguages.Contains(mediaStream.Language)) - { - subtitleLanguages.Add(mediaStream.Language); - } - else if (mediaStream.Type == "Audio" && !audioLanguages.Contains(mediaStream.Language)) - { - audioLanguages.Add(mediaStream.Language); - } + foundItems.Add(item); } } - return new Tuple(audioLanguages.ToArray(), subtitleLanguages.ToArray()); + return foundItems.ToArray(); } } \ No newline at end of file diff --git a/frontend/src/Components/ServerSearch/ServerSearchResult/ServerSearchResult.tsx b/frontend/src/Components/ServerSearch/ServerSearchResult/ServerSearchResult.tsx index 6f378f6..e6882b8 100644 --- a/frontend/src/Components/ServerSearch/ServerSearchResult/ServerSearchResult.tsx +++ b/frontend/src/Components/ServerSearch/ServerSearchResult/ServerSearchResult.tsx @@ -10,24 +10,10 @@ interface ServerSearchResultProps { const ServerSearchResult = ({ searchResult, server }: ServerSearchResultProps) => { const resultUrl = getUrlForSearchResult(searchResult, server); - function getLangs(languages: Array) { - let formattedLangs = languages[0]; - - for (let i = 1; i < languages.length; i++) { - formattedLangs += `, ${languages[i]}`; - } - - return formattedLangs; - } - return ( - <> - -

{searchResult.type} - {searchResult.name} - {searchResult.productionYear}

- - {searchResult.subtitleLanguages.length > 0 &&

Audio Languages: {getLangs(searchResult.audioLanguages)}

} - {searchResult.subtitleLanguages.length > 0 &&

Subtitle Languages: {getLangs(searchResult.subtitleLanguages)}

} - + +

{searchResult.type} - {searchResult.name} - {searchResult.productionYear}

+ ) } diff --git a/frontend/src/Lib/Search.ts b/frontend/src/Lib/Search.ts index 89b17d1..2649ddd 100644 --- a/frontend/src/Lib/Search.ts +++ b/frontend/src/Lib/Search.ts @@ -8,8 +8,6 @@ export interface SearchResult { serverId: string; type: string; productionYear: string; - subtitleLanguages: Array; - audioLanguages: Array; } export const search = async (searchTerm: string, serverUrl: string): Promise> => { diff --git a/frontend/src/Pages/Search/Search.tsx b/frontend/src/Pages/Search/Search.tsx index 256bbf3..33d8c07 100644 --- a/frontend/src/Pages/Search/Search.tsx +++ b/frontend/src/Pages/Search/Search.tsx @@ -1,35 +1,20 @@ -import { useEffect, useReducer } from "react"; +import { useEffect, useState } from "react"; import { getServerList, type Server } from "../../Lib/Servers"; import ServerSearch from "../../Components/ServerSearch/ServerSearch"; import { useNavigate, useSearchParams } from "react-router-dom"; import { Spinner } from "react-bootstrap"; import Cookies from "js-cookie"; -type serverListAction = { type: "CLEAR" } | { type: "SET", payload: Server[] }; - -const serverReducer = (state: Server[], action: serverListAction): Server[] => { - switch (action.type) { - case "CLEAR": - return []; - case "SET": - return action.payload; - default: - return state; - } -} const Search = () => { const [searchParams] = useSearchParams(); - // const [servers, setServers] = useState>([]); - const [servers, serversDispatch] = useReducer(serverReducer, []); + const [servers, setServers] = useState>([]); const navigate = useNavigate(); const sessionCookie = Cookies.get("session"); const searchTerm = searchParams.get("search") || ""; useEffect(() => { - serversDispatch({ type: "CLEAR" }); - if (!sessionCookie) { navigate("/login"); return; @@ -58,11 +43,11 @@ const Search = () => { navigate("/"); } - serversDispatch({ type: "SET", payload: workingServers }); + setServers(workingServers); }).catch(e => { alert(e); }); - }, [searchTerm, navigate, sessionCookie]); + }, [searchTerm, navigate]); return ( <>