Feature Request - Handle favorites

  Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Post Reply
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #1
Add a new namespace to handle favorites :
List / Add / Remove
find quote
Montellese Offline
Team Kodi Developer
Posts: 4,845
Joined: Jan 2009
Reputation: 72
Location: Switzerland
Post: #2
I've never used favourites so I don't really know what can be done with them etc. Are they seperated based on the media type (video, music, pictures) or are they all handled together? Depending on that it might either make sense to add a "Favourites" namespace with the proper methods or to add these methods to the VideoLibrary and AudioLibrary namespaces.

Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #3
Well Favourites are not tied to media type they are global you can put at least 2 type of things :

Quote:<favourites>
<favourite name="5 Centimètres par seconde" thumb="smb://DISKSTATION/Movies/5 Centimètres par seconde (Byôsoku 5 senchimêtoru) [1080p] [2007]/movie.tbn">PlayMedia(&quot;smb://DISKSTATION/Movies/5 Centimètres par seconde (Byôsoku 5 senchimêtoru) [1080p] [2007]/5 Centimètres par seconde.bluray.1080p.2007.mkv&quotWink</favourite>
<favourite name="Auto-Moto">ActivateWindow(10025,&quot;plugin://plugin.video.dailymotion_com/?mode=sortChannels1&amp;url=http%3a%2f%2fwww.dailymotion.com%2f%2fchannel%2fauto%2f1&quotWink</favourite>
</favourites>

I'll need to check a little more Xbmc code about it to see if it's internally handled differently so needs to have a type property or just a value one.

If it's OK to start working on it I'll look more Xbmc internals and propose something.
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #4
Well after some checks the Favorites code is quite simple and limited Smile

https://github.com/xbmc/xbmc/blob/master...urites.cpp

While getting the Favorites and structuring a return would be easy, adding support for add and remove would be quite hacky due to the limitation of the current xml format and code.

Since the need for most of the users is just to get access of their favorites from remotes and not adding / removing them one solution would be to just add a simple :
Application.GetFavourites (Or perhaps Files. but seems less logical)

What do you think ?
find quote
N3MIS15 Offline
Donor
Posts: 546
Joined: Jul 2010
Reputation: 14
Location: Melbourne, VIC
Post: #5
IMO shouldnt be .Files since favorite could be ActivateWindow, PlayMedia (file or addon)

[Image: all-fanart.jpg]
find quote
Montellese Offline
Team Kodi Developer
Posts: 4,845
Joined: Jan 2009
Reputation: 72
Location: Switzerland
Post: #6
What's the problem with Add and Remove support? Is the logic too much tied into the GUI?

IMO if we plan to support Add and Remove in the future, adding the methods to Application or Files doesn't make much sense.

Any idea how to handle the actual value of a favourite? A third-party client can't do much with PlayMedia(foobar) or ActivateWindow(foobar) because it has to translate it into Player.Open or GUI.ActivateWindow. Would be nice if this could already be done in XBMC before passing it on to the client. But we'd have to know about all the possibilities.

Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #7
Yes the logic is tied to the UI since we need to pass Windows ID for the moment the only way to add or remove favorites is via : bool CFavourites::AddOrRemove(CFileItem *item, int contextWindow) that will be hard to handle for external users.

But if all Windows ID are well known ID that don't change, I guess we can just pass a string as path, run the standard item loader to fill database info if present and then passe the item.

For the handling you can use EventServer but yeah not perfect. I was also wondering if we should do the parsing inside JSON, there's only 3 possible case :
PlayFile
ActivateWindow
RunScript

So parsing is not very complicated.

So a proposition would be :

a Favourite object that contain :
String Name
String Thumb
Enum Type
String Path
Int WindowID

Favourites.GetFavourite
Favourites.AddFavourite
Favourites.RemoveFavourite

And why not a Favourites.Execute or Start to simplify things for users to not have to translate the different types to JSON commands ?
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #8
This would lead to something like :

Code:
"Favourite.Fields.Favourite": {
    "extends": "Item.Fields.Base",
    "items": { "type": "string",
      "enum": [ "title", "type", "windowid", "thumbnail", "path" ]
    }
  },
  "Favourite.Details.Favourite": {
    "type": "array",
    "items": { "type": "object",
      "properties": {
        "title": { "type": "string", "required": true },
        "path": { "type": "string", "required": true },
        "windowid": { "type": "integer" },
        "thumbnail": { "type": "string" },
        "type": { "$ref": "Favourite.Type" }
      },
      "additionalProperties": false
    }
  },
  "Favourite.Type": {
    "type": "string",
    "enum": [ "file", "window", "script" ]
  },

Code:
"Favourite.GetFavourite": {
    "type": "method",
    "description": "Retrieve all favourites",
    "transport": "Response",
    "permission": "ReadData",
    "params": [
      { "name": "properties", "$ref": "Favourite.Fields.Favourite" },
      { "name": "filter",
        "type": [
          { "type": "object", "properties": { "type": { "$ref": "Favourite.Type", "required": true } }, "additionalProperties": false }
        ]
      }
    ],
    "returns": {
      "type": "object",
      "properties": {
        "limits": { "$ref": "List.LimitsReturned", "required": true },
        "favourites": { "type": "array",
          "items": { "$ref": "Favourite.Details.Favourite" }
        }
      }
    }
  },
  "Favourite.AddFavourite": {
    "type": "method",
    "description": "Add a new favourite",
    "transport": "Response",
    "permission": "UpdateData",
    "params": [
      { "name": "title", "type": "string", "required": true },
      { "name": "path", "type": "string", "required": true },
      { "name": "thumbnail", "$ref": "Optional.String" },
      { "name": "windowid", "$ref": "Optional.Integer" },
      { "name": "type", "type": [ "null", { "$ref": "Favourite.Type", "required": true } ], "default": null }
    ],
    "returns": "string"
  },
  "Favourite.RemoveFavourite": {
    "type": "method",
    "description": "Remove a favourite",
    "transport": "Response",
    "permission": "UpdateData",
    "params": [
      { "name": "title", "type": "string", "required": true },
      { "name": "path", "type": "string", "required": true },
      { "name": "thumbnail", "$ref": "Optional.String" },
      { "name": "windowid", "$ref": "Optional.Integer" },
      { "name": "type", "type": [ "null", { "$ref": "Favourite.Type", "required": true } ], "default": null }
    ],
    "returns": "string"
  },
  "Favourite.ExecuteFavourite": {
    "type": "method",
    "description": "Remove a favourite",
    "transport": "Response",
    "permission": "??????",
    "params": [
      { "name": "title", "type": "string", "required": true },
      { "name": "path", "type": "string", "required": true },
      { "name": "thumbnail", "$ref": "Optional.String" },
      { "name": "windowid", "$ref": "Optional.Integer" },
      { "name": "type", "type": [ "null", { "$ref": "Favourite.Type", "required": true } ], "default": null }
    ],
    "returns": "string"
  },

The only problem is with Execute permission since it can be either ControlPlayback ExecuteAddon or Navigate
find quote
Montellese Offline
Team Kodi Developer
Posts: 4,845
Joined: Jan 2009
Reputation: 72
Location: Switzerland
Post: #9
The problem with a Favourites.Execute is that you'd need an "easy" way to identify a favourite returned by Favourites.GetFavourites. Well the play command is probably unique but not ideal.

Furthermore I wouldn't limit Favourites.AddFavourite to a path parameter. It might be able to take a Playlist.Item object like Playlist.Add/Insert, Player.Open etc so a client could pass in a specific "movieid" and it would then be added to the list of favourites with the info from the library/database.

Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #10
I'm not sure to understand the first part of your remark. (Well I'm sure to not understand Tongue)
But the Execute part is not really mandatory since users can still choose what to do with the returned item.

For the add / remove the problem would be that the get does not send back a full item so hard to make a link.

Could you show me how you would describe the add to support both a path and a Playlist.Item ?
find quote
Montellese Offline
Team Kodi Developer
Posts: 4,845
Joined: Jan 2009
Reputation: 72
Location: Switzerland
Post: #11
Concerning the first part: Ideally every favourite would have an ID which could then be passed to Favourites.Execute instead of having to pass in the whole favourite object.

Playlist.Item already supports a path with the "file" property. Also for "movieid" etc we could actually determine the windowid etc automatically from the media type. But that's all just guessing, I don't really know how favourites work Wink

Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #12
Hum yes, but as I said Favourites in Xbmc are ultra limited Tongue

All in a 150 line file Tongue

Favourites are just a simple .xml saved in the profile with lines only containing : name / thumb / action the action needs to be parsed to getback a window id Smile

About the window ID, in the favourites they pass it to the functions I have no idea if it's possible to find it by code, and I think some addons can define new window id.

Due to the current Favourites internal implementation it's not really easy to produce a JSON api that would be way better than the underlying favourites code Smile

The whole code can be reduced to :

Get a favourite
Code:
CFileItemPtr item(new CFileItem(name));
        item->SetPath(favourite->FirstChild()->Value());
        if (thumb) item->SetArt("thumb", thumb);
        items.Add(item);

Add / Remove
Code:
CFileItemPtr favourite(new CFileItem(item->GetLabel()));
    if (item->GetLabel().IsEmpty())
      favourite->SetLabel(CUtil::GetTitleFromPath(item->GetPath(), item->m_bIsFolder));
    favourite->SetArt("thumb", item->GetArt("thumb"));
    favourite->SetPath(executePath);
    items.Add(favourite);

Generate the execute path
Code:
if (item->m_bIsFolder && (g_advancedSettings.m_playlistAsFolders ||
                            !(item->IsSmartPlayList() || item->IsPlayList())))
    execute.Format("ActivateWindow(%i,%s)", contextWindow, StringUtils::Paramify(item->GetPath()).c_str());
  else if (item->IsScript())
    execute.Format("RunScript(%s)", StringUtils::Paramify(item->GetPath().Mid(9)).c_str());
  else  // assume a media file
  {
    if (item->IsVideoDb() && item->HasVideoInfoTag())
      execute.Format("PlayMedia(%s)", StringUtils::Paramify(item->GetVideoInfoTag()->m_strFileNameAndPath).c_str());
    else
      execute.Format("PlayMedia(%s)", StringUtils::Paramify(item->GetPath()).c_str());
  }

As you can see implementing Playlist.Item or Favourites Id are quite over the current Xbmc scope.
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #13
Any final thought on what I go with ? Smile
find quote
Montellese Offline
Team Kodi Developer
Posts: 4,845
Joined: Jan 2009
Reputation: 72
Location: Switzerland
Post: #14
I'd say start with Favourites.GetFavourites for now. As already mentioned IMO it would be nice if it wouldn't just return the "PlayMedia(foo?bar)" command but some kind of object that tells the client which (JSON-RPC) method to use and what parameter to pass in.

Always read the online manual (wiki), FAQ (wiki) and search the forum before posting.
Do not e-mail Team Kodi members directly asking for support. Read/follow the forum rules (wiki).
Please read the pages on troubleshooting (wiki) and bug reporting (wiki) before reporting issues.
find quote
Tolriq Offline
Banned
Posts: 3,077
Joined: Jun 2009
Location: France
Post: #15
Ok I'll go with this

The description I posted should cover needs for this and possible future things.
Perhaps just if you think of better names for windowid and window for type I'm not very aware if there's more logical names that describe those.

Code:
"Favourite.Fields.Favourite": {
    "extends": "Item.Fields.Base",
    "items": { "type": "string",
      "enum": [ "title", "type", "windowid", "thumbnail", "path" ]
    }
  },
  "Favourite.Details.Favourite": {
    "type": "array",
    "items": { "type": "object",
      "properties": {
        "title": { "type": "string", "required": true },
        "path": { "type": "string", "required": true },
        "windowid": { "type": "integer" },
        "thumbnail": { "type": "string" },
        "type": { "$ref": "Favourite.Type" }
      },
      "additionalProperties": false
    }
  },
  "Favourite.Type": {
    "type": "string",
    "enum": [ "file", "window", "script" ]
  },
find quote
Post Reply