GSOC Proposal: mobile mode
#1
Hi,

so here is my newest up-to-date proposal:

Short description: I propose a feature that allows the user to take his content with him on mobile devices (phones/tablets/laptops). The user should be able to decide what content should be locally available manually, or he could use a "sync policy" - a service plugin that automatically decides what files to make locally available.

How will I achieve this:
  • Design a system that can associate a local file to a mobile one and prefer the local one if available. If done right, users should be able to copy files outside of xbmc or use already existing files (like the local iTunes music).
  • expose a new context menu "make locally available" and "remove local copy" that triggers a file copy.
  • For copying I will reuse the file management features already in xbmc. One addition I will make, is to implement the Import-/ExportRessource() UPnP features, so we can copy files from any UPnP Device supporting those
  • Extend the python API to allow service plugins to programmatically decide when a file should be locally available.
    What will the project focus on: One crucial part will be the layout of the local filesystem and how we associate them to the online counterparts.

Benefits: With XBMC now running on iOS and Android, user will now be able to really use xbmc away from home.

What does it touch in XBMC:
  • implement Import/exportRessource() functions in our UPnP server
  • extension of Python-Bindings and JSON-RPC. Since i will only add things, I expect backwards compatibility.
  • My proposal will probably touch a lot of xbmc's subsystems with mostly small changes: the player should prefer a local file over an online one, Expose a "isOfflineAvailable" flag to skinners, store "isOffline" in the db, so we don't hit the HDD all the time...

Requirements: C/C++ for the core parts, python for the sync policies

Possible mentors: Place to add possible mentors (Team-XBMC will add this).

forum/contact name: Fice
Reply
#2
Nice - the germans again ;) - well if you ask me i would prefer step 1 (cause it seems it would fullfill a major part of the so often upcoming feature request). But lets see what the db gurus think about it.
Reply
#3
I think step 1 would be a rather nice addition to xbmc if done right. Perhaps even extend it so that it will precache the movie you watch also. I.e if I start to watch a show of big bang it will download (not in an over prioritized way) so even if the client or the server Vanishes from the network its OK to continue to watch the show.
This could even be used to have nas sleep after the movie has downloaded to allow for more eco friendly distribution Smile

Personally I think step 3 is probably a great addition but to vast as a subproject. I think it could potentially be to big as a standalone project even. Probably better to first redesign the database and the add that feature.

Cheers,
Tobias
If you have problems please read this before posting

Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.

Image

"Well Im gonna download the code and look at it a bit but I'm certainly not a really good C/C++ programer but I'd help as much as I can, I mostly write in C#."
Reply
#4
I think a watched-flag synchronization and a "mobile" database are not needed. The db-sync is out of the scope of this project (we already have plans/a concept that we'd like for this, see GSOC13 wiki page) - so I'd really only stick to the basics here and do the rest once we have the distributed client/server thingy.

As for the mobile database: I'd simply replicate the folder structure of the source/remote filesystem on the local device and check "on playback start" if there is a cached version and use that one instead. If there are issues with replicating the folder structure on the mobile device (protocols in folder names), I'd probably use the hashed version of the file path as folder name (which would make it a bit more difficult to create/copy those cached files manually). Using a shares name is IMO not secure enough and could lead to duplicates in the cache. That's at least how I would start, but haven't thought too much about it, so there might be some downsides with this.
Reply
#5
Step 1 it is then ^^

da-anda Wrote:I'd simply replicate the folder structure of the source/remote filesystem on the local device and check "on playback start" if there is a cached version and use that one instead.
Yes, that's my goal

Perhaps I should explain a bit more how I envisioned it:
So we have a file at smb://{IP}/movies/avatar/avatar.mkv
This file item would belong the source folder: smb://{IP}/movies
My idea for generating the local file path is:
remove the source path of the file... so smb://{IP}/movies/avatar/avatar.mkv would become avatar/avatar.mkv
Now I would add the local folder path (e.g. "C:/movies") at the front of this path, so it would become C:/movies/avatar/avatar.mkv

The problem with this approach could be, that if the user has two folders added to a source:
- smb://{IP1}/movies
- smb://{IP2}/movies
and those folder contain the files:
smb://{IP1}/movies/avatar/avatar.mkv
smb://{IP2}/movies/avatar/avatar.mkv
There would be a problem when the user wants both locally available...
I feel that this is pretty much an edge case? especially since xbmc doesn't (natively) support several versions of the same movie.
da-anda Wrote:If there are issues with replicating the folder structure on the mobile device (protocols in folder names), I'd probably use the hashed version of the file path as folder name (which would make it a bit more difficult to create/copy those cached files manually). Using a shares name is IMO not secure enough and could lead to duplicates in the cache
Could you give me an example for protocols in folder names? You are talking about rar's, right? Unfortunately I have no movies in rar's so can't test myself right now...

topfs2 Wrote:Perhaps even extend it so that it will precache the movie you watch also. I.e if I start to watch a show of big bang it will download (not in an over prioritized way) so even if the client or the server Vanishes from the network its OK to continue to watch the show.
This could even be used to have nas sleep after the movie has downloaded to allow for more eco friendly distribution
I like the idea and since it seems i will only be working on step 1, I will add it to my proposal. (Will do a rewrite once I have some more feedback)

topfs2 Wrote:Personally I think step 3 is probably a great addition but to vast as a subproject. I think it could potentially be to big as a standalone project even. Probably better to first redesign the database and the add that feature.
Just out of curiosity, wouldn't the gsoc idea '3.1 Focus on a distributed model' also require some sort merge conflict resolution?
Reply
#6
The basic idea was that the client would just combine listings (with duplicates removed/replaced as required) post-listing. There could well be a local database holding that information, but it wouldn't be at the database level, rather an aggregation of remote databases.

i.e. each machine would simply advertise what it has (via JSON-RPC, UPnP etc.) and the other machines would aggregate those listings into their local cache for listing/searching. Duplicate resolving would be critical, as you want to play the local version if it exists.

Your idea of being able to duplicate content from one machine to the other would ofcourse be able to come into this - I'd suggest making it reasonably generic, in that you can choose content based on some VFS entry (or database query via smartplaylists) and duplicate that onto the local client. I expect much of the sync might be doable using an add-on (i.e. not really much core code required).
Always read the XBMC online-manual, FAQ and search the forum before posting.
Do not e-mail XBMC-Team members directly asking for support. Read/follow the forum rules.
For troubleshooting and bug reporting please make sure you read this first.


Image
Reply
#7
(2013-03-31, 19:09)Fice Wrote: Perhaps I should explain a bit more how I envisioned it:
So we have a file at smb://{IP}/movies/avatar/avatar.mkv
This file item would belong the source folder: smb://{IP}/movies
My idea for generating the local file path is:
remove the source path of the file... so smb://{IP}/movies/avatar/avatar.mkv would become avatar/avatar.mkv
Now I would add the local folder path (e.g. "C:/movies") at the front of this path, so it would become C:/movies/avatar/avatar.mkv

The problem with this approach could be, that if the user has two folders added to a source:
...
There would be a problem when the user wants both locally available...
I feel that this is pretty much an edge case? especially since xbmc doesn't (natively) support several versions of the same movie.
da-anda Wrote:If there are issues with replicating the folder structure on the mobile device (protocols in folder names), I'd probably use the hashed version of the file path as folder name (which would make it a bit more difficult to create/copy those cached files manually). Using a shares name is IMO not secure enough and could lead to duplicates in the cache
Could you give me an example for protocols in folder names?

As you noticed above, it's troublesome to strip the "source" and rewrite the original file uri to a local version. That's why I wouldn't rewrite the entire VFS url at all, but use the full qualified path including "smb://{IP}/share/...", because that's what's also stored in your DB. And as having something like "smb://123.234.234.12/foo/bar" as folder structure should be impossible I'd simply md5 hash the full VFS path. Picking up your example it would translate into this:

Code:
Pseudo code:
var source =  "smb://{IP}/movies/avatar/avatar.mkv";
var cachePath = 'special://userdata/cache/';
var pathInfo = parseUrl(source);
var filePath = pathInfo['protocol'] + pathInfo['dirname'];                // smb://{IP}/movies/avatar/
var fileName = pathInfo['basename'];                                         // avatar.mkv
var localCacheFile = cachePath + md5(filePath) + '/' + fileName; // special://userdata/cache/5A34K43AK74k1280E3/avatar.mkv

That way you will never get into any trouble with duplicate filenames or alike and also don't have to care about any shares, addons or whatever.
Reply
#8
(2013-04-01, 00:54)jmarshall Wrote: I'd suggest making it reasonably generic, in that you can choose content based on some VFS entry (or database query via smartplaylists) and duplicate that onto the local client.
Yes, that is my goal. Also the other way around, that if a user buys a new album while on holiday, he should be able to copy them to the local folder and xbmc takes care of copying to the nas once we gets home.
(2013-04-01, 00:54)jmarshall Wrote: I expect much of the sync might be doable using an add-on (i.e. not really much core code required).
I agree, the only thing I wanted to do in core is the functionality to copy a file (should already be there because of the filemanager) and the ability to calculate the local path from the online path (and vise versa). Those functionalities should of course be exposed to xbmc APIs.
Then addon developers could create service addons that automatically sync files in whatever way they see fit.
Examples:
- sync everything that's in favourites
- sync a whole database/source
- sync everything from a specific tv show/musician etc...
- sync everything with a rating > X (actually asked for in some feature request)
...

@da-anda
Well, I will think a little bit more about this, but I would love to be able to add content to the library while in mobile mode, which would not be possible with hashed paths...
Also, your approach would prohibit the user to use the local files in other apps, that maybe have some restrictions on the folder layout.
Reply
#9
IMO a offline cache is different from a library + file sync approach. My approach is only suitable for a offline/mobile cache and the most easy and reliable one to achieve it IMO - syncing libraries and pushing new files back to master/server requires mapped shares between both (share A on local XBMC maps to share D on target XBMC) - so you probably would need a sync wizard/dialog that asks to which share selected file(s) should be synced to.
Reply
#10
I had to solve pretty much exactly Step 3 (grab a local copy of the db, take it on the road, modify it, then sync changes when we get back) at work. We ended up basically creating a new db every time. We created a second temporary database where all rows were added without respect to their ID's (caveat: we also had a "case number" which served as a secondary unique id), then updated all table referencing that row to reflect the new ID. Then we drop the old db and replace it with the new one. Any transactions occurring after the process has started are intercepted, modified if appropriate, and applied to the new db.
Reply
#11
@da-anda: yes, I was more thinking about a file sync method than a pure offline cache.

@Bstrdsmkr: the idea with the secondary unique id is quite nice, didn't occur to me Wink
My idea was more like undoing all local changesets to the db since the last sync. Now replay all changesets from the mysql db (this should not have any merge conflicts, since our working db has no local changes right now). After that we grab the local changesets and replay them (any merge issues will now be made on the local changesets, because it would propably be a bad idea to change the mysql once, as they could already be in use by other devices). Now inserting a local "INSERT" changeset could look like that.
Code:
void ApplyLocalInsertChangeset(Changeset change)
{
  sql = "SELECT * FROM " +change.table+ " WHERE id="+change.id;
  executeSQL(sql);
  if(sql result not empty)
  { //Conflict, we already have sth. with that id
    sql = changeset.builSQLWithouID(); //Build the INSERT sql query without the ID
    executeSQL(sql);
    int newID = Get id of our inserted row;
    Now update all further local changes and change them if they in some way reference this changesets table and id...
  }
  else
  { //No conflict, go ahead
     sql = changeset.buildSQL(); //Build the normal INSERT sql query WITH THE ID
     executeSQL(sql);
  }
}
Reply
#12
Another feature that I could see being beneifical is not only being able to set up rules on what is cached to the mobile client device as well as rules on when it should be deleted.

Example:
I have one device that is on a weak WIFI signal that streams content from a central NAS. I'd love to be able to cache all new tv/movies that is added to the NAS on this device. Once it has been flagged as watched in the SQL database (whether it be from the cached device or any other device) the tv/movie is removed.
Reply
#13
Hey,

I suppose while not getting technical, I would like to provide a use-case scenario as to which plans can be built on. This would be an ideal scenario, but would technically work for things that are outside this scope.

In my car, I have a RPi, that's attached to the screens in the headrests, we go on a holiday that requires me to drive me, the wife and our 3 kids to wherever we going. I can be driving for 9hrs straight at these points.

So before the holiday I fill up the 256GB USB HDD with some movies the kids will watch. (Currently I do this by spending a few days maintaining the Car RPi's library, and just bringing in the drive (aka. planning))

The Car RPi turns off 45mins after I lock the car, it has WiFi and easily connects to my home network from where its usually parked. To turn it back on, all I have to do is start the engine for a second

I would like to be able to over the course of whenever, just browse xbmc on my PC, or inside one of my other RPi's around the house. Find a Film or TV Show in my library be able to say: Right click > "Sync" > Add >Car RPi (To remove say: Right Click > "Sync" > Remove > Car RPi)

I don't see at the moment how I would need it multi-directional (I suppose if I was in the car I could connect to the home library and chose which to sync, but I wouldn't use that at least very very rarely)

(Sorry now I'm getting slightly technical)

I guess a master/slave ability on a "separate database" (I say that, but I highly doubt it would need a new db, but I'm not a professional) where the Car RPi would quite simply be the "bitch", it would take anything the "master" gives it.

As for a few points though, the way Fice suggested with folders/sources and same filenames. That could be overcome by not replicating the folder structure (why would you need to do it?) Using the Library functions you already have all the information you need and you could just alter the filepath in the database entry to be whatever you wanted.

This would allow you to specify where to save to (on the "slave" device) and not really worry about it. I suppose as little maintenance work as possible.


Apologies if this is not needed nor wanted, however I do believe if you have a few use-case scenarios it allows you to think in the way that the end-user would use it, and design it appropriately
Reply
#14
Ok, some refinements:

Local Folder Structure
Every source folder will have a unique local folder. This local folder will automatically be set to sth. like (and stored in the db):
LocalPath: special://userdata/cache/{HASH_OF_THE_SOURCE_FOLDER_PATH}/
That way we can still keep the remote folder structure, we can deal with two source folders having the same file(-name) inside and we don't complicate the setup with an additional wizard or anything.
Now I could expose a context menu in the Source management window with a "set local folder path". So, if someone cares, he can still control it.

Sync Policies
As mentioned earlier, sync policies will be normal service plugins that listen to events. (I probably need to expose a few new events? E.g. is a service script notified when a item gets added to favourites?).
Now some pseudo code, on what such a plugin would do:
Code:
bool DoWeWantItLocally(item)
{
//TODO: sync policie related
}

OnEvent(item)
{
    if(DoWeWantItLocally(item))
        xbmc.MakeLocalCopy(item)
    else
        if(xbmc.IsLocallyAvailable(item))
            xbmc.RemoveLocalCopy(item)
}
Also xbmc should store which policies wanted what file locally, so we only remove a local copy, if there isn't any policie left who wants it.

As an alternative, Sync policies could be a new kind of addon, that have to return a bool (true indicating, it wants the file locally) and the above if/else logic could be handled in core. Preferences?

@juxta: So yes, a sync policy would also be responsible for removing local copies. In your case "DoWeWantItLocally" would just need to return true, if the file is unwatched Wink

@Oxyg3n: So you basically want to "push" items to a mobile device. My idea was that the mobile device "pulls" them. I don't see a big issue why this could not be supported as well. Doesn't the UPNP server now have a feature like "play to"? Perhaps that could be extended to also allow "copy to".
Reply
#15
Just a FYI DLNA/UPnP supports this, it just needs implemented. If you followed those specs you'd have the potential of other devices being able to interoperate immediately.

Updating view status, resume points works too over UPnP so you could easily store the changes on your mobile device then update them all on the next sync with the server.
Reply

Logout Mark Read Team Forum Stats Members Help
GSOC Proposal: mobile mode0