Jump to content

The children of any BaseItemType in C#; Web Api via C#?


ginjaninja

Recommended Posts

ginjaninja

Before i tried to create  my own horrible custom method with different case statements and banged my head for another day, i just wanted to check there wasn't a built in method that could get the immediate children of any Parent in c#; be the parent a  Boxset, Playlist, Series, Season, Album  ie any Type capable of being a parent? I wonder how many different Types of parent there are, in terms of how their children are determined, maybe i would just need a few cases.

The web api has a single generic method on /items with ParentId. Perhaps If there isnt an inbuilt c# method, is it possible for a plugin to returns items from the web api? does anyone have some precooked code for querying the/a web api from c#? ie returning a list of Baseitems by interpreting the returned json from an API get. (i actually only need a list of InternalIds).

thank you.

 

 

Link to comment
Share on other sites

ginjaninja
On 04/02/2023 at 01:25, Luke said:

The server equivalent would be .GetItems

Thanks Luke, please treat me like a novice. What exposes this method please. Perhaps i should have said im writing a plugin..

Im used to LibraryManager via ILibraryManager and that doesnt have this method. When I look in reference, Getitems is talked about under rest API, should i/can i  use the rest api in a plugin? (FWIW i cant find a method in LibraryManager that works for all parent types).

 

 

Link to comment
Share on other sites

Cheesegeezer
2 hours ago, ginjaninja said:

Thanks Luke, please treat me like a novice. What exposes this method please. Perhaps i should have said im writing a plugin..

Im used to LibraryManager via ILibraryManager and that doesnt have this method. When I look in reference, Getitems is talked about under rest API, should i/can i  use the rest api in a plugin? (FWIW i cant find a method in LibraryManager that works for all parent types).

 

 

Yep you can, you just need to implement the IHTTPClient in Emby or use the .net HTTPClient, return the response in either and deserialise the JSON to a properties class.

Something like this (using built in .net HTTPClient - initialise from the constructor)

public async Task<List<ItemInfoModel>> GetLatestItems(string parentId)
        {
            JsonSerializerOptions _jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true,
                Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }};

            
            List<ItemInfoModel> baseItems = new List<ItemInfoModel>();

            string url = string.Format(_apiCalls.GetLatestItemsApi(parentId));
            
            HttpResponseMessage response = await _httpClient.GetAsync(url);
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadAsStringAsync();
                try
                {
                    baseItems = JsonSerializer.Deserialize<List<ItemInfoModel>>(json, _jsonSerializerOptions);
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e);
                }
            }
            return baseItems;
        }

 

and i also initialise the my APICalls class in the constructor. 

this is just a class that holds all the direct api calls i need to make

	public string BaseApiUrl()
        {
            return string.Format("{0}/emby/", Authentication.EndpointAddress);
        }

        public string UserBasedCall(string request)
        {
            // const url = `${serverAddress}/emby/Users/${userId}/${request}&api_key=${authToken}`;
            var call = BaseApiUrl() + "Users/" + Authentication.CurrentUserId + "/" + request + "api_key=" + Authentication.AuthToken;
            return call;
        }
	public string GetLatestItemsApi(string folderId)
        {
            var request = "Items/Latest?Recursive=true&Limit=20&ParentId=" + folderId + "&EnableImages=true&EnableUserData=true&";
            return string.Format(UserBasedCall(request));
            
        }

 

Edited by Cheesegeezer
Link to comment
Share on other sites

ginjaninja

Thanks @Cheesegeezer this looks very helpful, i will circle back to http method if necessary.

@LukeI have since found .GetItems on ItemRepository, while ItemRepository.GetItems works for eg Series I can not make it work if the parent is a collection (by specifying the parent in the query), similar to how LibraryManager.GetItemList does not work for collections (without structuring the query for collection ids). How sure are you .GetItems should be able to find the children of any parent type, with the same query ie specifying the parent? I was using it thus.

var queryList = new InternalItemsQuery
{
Parent = parentitem
//also tried.
//ParentIds = new[] { parentitem.InternalId  }
};
var children = ItemRepository.GetItems(queryList);

thanks

Edited by ginjaninja
Link to comment
Share on other sites

On 2/7/2023 at 10:39 AM, ginjaninja said:

Thanks @Cheesegeezer this looks very helpful, i will circle back to http method if necessary.

@LukeI have since found .GetItems on ItemRepository, while ItemRepository.GetItems works for eg Series I can not make it work if the parent is a collection (by specifying the parent in the query), similar to how LibraryManager.GetItemList does not work for collections (without structuring the query for collection ids). How sure are you .GetItems should be able to find the children of any parent type, with the same query ie specifying the parent? I was using it thus.

var queryList = new InternalItemsQuery
{
Parent = parentitem
//also tried.
//ParentIds = new[] { parentitem.InternalId  }
};
var children = ItemRepository.GetItems(queryList);

thanks

avoid (never) talking to ItemRepository directly. Get the parent item you need, and then call it's own folder.GetItems method.

Link to comment
Share on other sites

ginjaninja
16 hours ago, Luke said:

avoid (never) talking to ItemRepository directly. Get the parent item you need, and then call it's own folder.GetItems method.

Thanks Luke,

It sounds like each parent item type has its own different GetItems Method and there is not a one size fits all method to get the children of any parent.

 

In that case i may be better off with the HTTP api in this instance, speed and performance are not relevant to my application.

 

 

 

Link to comment
Share on other sites

  • 2 weeks later...
ginjaninja
On 09/02/2023 at 17:06, Luke said:

avoid (never) talking to ItemRepository directly. Get the parent item you need, and then call it's own folder.GetItems method.

Hi Luke, so i have the parent item (Type BaseItem)....how do i access its folder.GetItems method please...?perhaps using Playlist as the parent item as an example?

Spoiler

Do i need to cast it as another type?

i see that the Folder type has method GetChildren and i see the Playlist type has method eg getPlaylistItems ..

 

Link to comment
Share on other sites

On 2/7/2023 at 8:41 AM, Cheesegeezer said:

Yep you can, you just need to implement the IHTTPClient in Emby or use the .net HTTPClient, return the response in either and deserialise the JSON to a properties class.

Something like this (using built in .net HTTPClient - initialise from the constructor)

public async Task<List<ItemInfoModel>> GetLatestItems(string parentId)
        {
            JsonSerializerOptions _jsonSerializerOptions = new() { PropertyNameCaseInsensitive = true,
                Converters = { new JsonStringEnumConverter(JsonNamingPolicy.CamelCase) }};

            
            List<ItemInfoModel> baseItems = new List<ItemInfoModel>();

            string url = string.Format(_apiCalls.GetLatestItemsApi(parentId));
            
            HttpResponseMessage response = await _httpClient.GetAsync(url);
            if (response.IsSuccessStatusCode)
            {
                var json = await response.Content.ReadAsStringAsync();
                try
                {
                    baseItems = JsonSerializer.Deserialize<List<ItemInfoModel>>(json, _jsonSerializerOptions);
                }
                catch (Exception e)
                {
                    Debug.WriteLine(e);
                }
            }
            return baseItems;
        }

 

and i also initialise the my APICalls class in the constructor. 

this is just a class that holds all the direct api calls i need to make

	public string BaseApiUrl()
        {
            return string.Format("{0}/emby/", Authentication.EndpointAddress);
        }

        public string UserBasedCall(string request)
        {
            // const url = `${serverAddress}/emby/Users/${userId}/${request}&api_key=${authToken}`;
            var call = BaseApiUrl() + "Users/" + Authentication.CurrentUserId + "/" + request + "api_key=" + Authentication.AuthToken;
            return call;
        }
	public string GetLatestItemsApi(string folderId)
        {
            var request = "Items/Latest?Recursive=true&Limit=20&ParentId=" + folderId + "&EnableImages=true&EnableUserData=true&";
            return string.Format(UserBasedCall(request));
            
        }

 

Cheese, do you have to lookup the API token each time for these url calls that aren't yet part of the API? 

When you are going to hit an endpoint, and need an API key, what does the method look like to get the saved key? 

 

Link to comment
Share on other sites

ginjaninja
1 hour ago, chef said:

Cheese, do you have to lookup the API token each time for these url calls that aren't yet part of the API? 

When you are going to hit an endpoint, and need an API key, what does the method look like to get the saved key? 

 

@chef my experience from using http api in powershell suggests using an apikey maybe a 'poors mans equivalent' of properly authenticating and getting the auth token and using that as the api key in the URI syntax..i recall (not 100%) there are some user based endpoints of the api that are better used via an auth token then a system api key (ie needed to make them work).. I guess the downside  of a user auth token vs a system api key would be your plugin config would have to allow the user to store an admins un/pw in your plugins config.

@chef do you you know how to go from a baseitem to expose the methods on eg a type Playlist or some other (folder) type by any chance?

Link to comment
Share on other sites

19 minutes ago, ginjaninja said:

@chef my experience from using http api in powershell suggests using an apikey maybe a 'poors mans equivalent' of properly authenticating and getting the auth token and using that as the api key in the URI syntax..i recall (not 100%) there are some user based endpoints of the api that are better used via an auth token then a system api key (ie needed to make them work).. I guess the downside  of a user auth token vs a system api key would be your plugin config would have to allow the user to store an admins un/pw in your plugins config.

@chef do you you know how to go from a baseitem to expose the methods on eg a type Playlist or some other (folder) type by any chance?

Which methods?

There are certain methods on baseItems, like "FindParent<>", and there is a Get method for children (which I believe is referring to file system children), there is also GetMediaSources, or GetMediaStreams.

Is that what you mean? 

Perhaps, when dealing with playlists, you would have to request each playlist item specifically by InternalId.

Select all the InteralIds of your playlist items and use the "Ids[]" parameter of the InternalItemsQuery to get all the baseItem data for those elements.

 

Link to comment
Share on other sites

ginjaninja
2 hours ago, chef said:

Which methods?

There are certain methods on baseItems, like "FindParent<>", and there is a Get method for children (which I believe is referring to file system children), there is also GetMediaSources, or GetMediaStreams.

Is that what you mean? 

Perhaps, when dealing with playlists, you would have to request each playlist item specifically by InternalId.

Select all the InteralIds of your playlist items and use the "Ids[]" parameter of the InternalItemsQuery to get all the baseItem data for those elements.

 

against the overall goal that i am trying to the find the children of any BaseItem, and there doesnt seem to a BaseItem method to find the children of any BaseItem type (eg children of a Playlist) and @Luke's comment " then call it's own folder.GetItems method."

and that objects of type Folder and Playlist have a .GetItems() method .

Do you know how i go from a BaseItem object (which happens to be of type Playlist) to the methods on a Playlist in  c#...(assuming thats what i need to do?)

eg you cant do ....BaseItem.GetItems(InternalItemsQuery);

Spoiler

 

This is a total guess but highlights one idea i had to get to the methods on a Playlist from a BaseItem, it even gets past intellisense but creates an exception on run..is this on the right track?

 

var queryList = new InternalItemsQuery

{
                Parent = parentitem,
                
};

var children = (parentitem as Playlist).GetChildren(queryList);

 

 

 

or in the interests of making 1 bit of progress and asking an even clearer question with a more definite answer...do you know the code to go from a BaseItem (which is a Playlist) to a list of the members of the Playlist - either the BaseItem members or the Ids whatevers easier...)? thanks.

Edited by ginjaninja
Link to comment
Share on other sites

Cheesegeezer

Hey fellas, I’ll get back to you tomorrow, in depth.

but if you are creating your own app or endpoint requirements in c#, then each api call needs to be authenticated to get the info you want you can then store and utilise it.

but if you are already authenticated, like we are for plugins, etc then you should be using emby’s library interfaces or create your own and inject those dependencies to the plugin.

You can also create a apikey in the server to use, so you can add it to a static constants class in your plugin/interface to reuse anywhere in your code, nice and easily.

 

Edited by Cheesegeezer
Link to comment
Share on other sites

ginjaninja
16 hours ago, Luke said:

The playlist will also have a .GetItems method that you can call.

Hi Luke, thanks for your help.. i appreciate this is probably very simple...but i dont know how to go from a BaseItem to a Playlist, please can you give an example of the c# code that would take you from a BaseItem to a Playlist which you could then call .GetItems on?

edit oooh this worked...

var children = (parentitem as Folder).GetItems(queryList);

without an exception.

Spoiler

var children = (parentitem as Playlist).GetItems(queryList);

causes an exception..would love to understand the underlying reasons why...and or wether im doing it right?

 

Edited by ginjaninja
  • Like 1
Link to comment
Share on other sites

Cheesegeezer
1 hour ago, ginjaninja said:

Hi Luke, thanks for your help.. i appreciate this is probably very simple...but i dont know how to go from a BaseItem to a Playlist, please can you give an example of the c# code that would take you from a BaseItem to a Playlist which you could then call .GetItems on?

edit oooh this worked...

var children = (parentitem as Folder).GetItems(queryList);

without an exception.

  Reveal hidden contents

var children = (parentitem as Playlist).GetItems(queryList);

causes an exception..would love to understand the underlying reasons why...and or wether im doing it right?

 

I been playing with this, this morning and failed to figure it out too!! Well done matey

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...