CastagnaIT / plugin.video.netflix

InputStream based Netflix plugin for Kodi
MIT License
1.91k stars 259 forks source link

Push progress/watched status to Netflix #80

Closed Smeulf closed 4 years ago

Smeulf commented 5 years ago

I'm submitting a ...

General information

Not sure if it's a feature request or a bug report...

When you watch an episode from a browser or the netflix app, Netflix remembers the watched status or resume points.

When you browse ie 'My List' and video was already seen, Kodi displays it. But wen you watch something from Kodi, Netflix is not updated.

Would it be possible to send a notification to Netflix when the video is stopped with the watch status/resume point ?

Then it will be possible to continue watching something in the Netflix app that was started on Kodi.

Thanks for your comments.

Addon version used

From sources at commit 8777e02 https://github.com/CastagnaIT/plugin.video.netflix/tree/8777e02a19c3763819d39178b2695dea0a49a03d

Installation

Operating System

Additional informatin on the environment

LibreELEC 9.0.1

Smeulf commented 5 years ago

Looks like a feature request : https://github.com/CastagnaIT/plugin.video.netflix/projects/2#card-19070428

There's a MSL endpoint named "pbo_events", with a "events/stop" parameter called after a video is stopped. Could it be the answer ?

CastagnaIT commented 5 years ago

days ago i tried to track the logs of the endpoint you specified but verifying the logs i have not found a behavior that specifies that it is for that functionality for example i have not found references that are sent to make the server understand that the "stop" is for a certain video running

we should try to understand more deeply in some way

Smeulf commented 5 years ago

https://www.bountysource.com/issues/46068715-netflix-api-watched-movies-don-t-show-up-in-netflix-web-app-s-viewing-activity

According to asciidisco, it's managed by the 'log' endpoint, he added a payload example.

I don't have the proper tools to decode the payloads myself, so I can't tell what's pushed on the 'event' endpoint, but I tend to trust both of you :)

CastagnaIT commented 5 years ago

interesting discussion in the link, summarising at pbo_events the following requests are submitted:

When video starts: reqName=events/engage reqName=events/start

During viewing (often transmitted at every minute or more) reqName=events/keepAlive

At the end of the video: reqName=events/stop

to decode it you have to follow the logic on default_crypto so initially you can decode the data with base64

like asciidisco said this is a complex thing.. first we must try to decode a message sent by the netflix player, maybe creating a separate python software, so based on what we get, understand if we can replicate the requests to be sent at pbo_events

dm2912 commented 5 years ago

I think the most crucial thing is the watched status as that is what Netflix relies on for recommendations etc. without it knowing what you have watched, your recommendations are only based on what you add to your list.

yoshimo commented 5 years ago

According to asciidisco, it's managed by the 'log' endpoint, he added a payload example.

I think that changed, ichnaea isn't called when i watch movies and progress is still saved. There are post requests to ​https://www.netflix.com/nq/msl_v1/cadmium/pbo_logblobs/%5E1.0.0/router these days

CastagnaIT commented 5 years ago

may be i have no longer followed the situations, if you are able to help trying to propose something working you are welcome

Mikau28 commented 5 years ago

Would looking at how plex handles this API endpoint aide in resolving this issue? The only reason I ask is that they have a native kodi plugin.

CastagnaIT commented 5 years ago

which plex? attach link/documentation

Mikau28 commented 5 years ago

https://forums.plex.tv/t/pms-web-api-documentation/62152

Plex, like Netflix but you host your own media. They offer the same functionality of watched and position markers. I realize they are different but how they work could point towards a better direction.

CastagnaIT commented 5 years ago

I don't see any help on this page and there is not even any source code

nohajc commented 4 years ago

like asciidisco said this is a complex thing.. first we must try to decode a message sent by the netflix player, maybe creating a separate python software, so based on what we get, understand if we can replicate the requests to be sent at pbo_events

Hi, I might be able to help. I was playing with the MSL protocol too and I have a mitmproxy plugin which can intercept MSL handshake and decrypt subsequent communication.

The code is really ugly, so I haven't made it public yet, but it works. It's a classic MitM attack where the proxy will present a different RSA public key to the Netflix server, so it can decrypt the response containing AES key and re-encrypt it with the RSA public key the client is expecting.

All of this is limited to the JWK_RSA (Chrome, Firefox, ...) or JWEJS_RSA (IE) schemes where random keys are generated for each handshake.

WIDEVINE scheme (Android app) uses a device-specific RSA key which is usually protected by L1 DRM. That would be more difficult to deal with (and also questionable from a legal standpoint) but also not necessary for this task, I'd say.

dagwieers commented 4 years ago

Once you have this implemented, you will notice that there's no easy way to update resumepoints in Kodi. See: https://github.com/pietje666/plugin.video.vrt.nu/issues/568

But don't let that stop you, because this functionality is very much wanted, and hopefully we can get that functionality fixed in Kodi as well :-)

CastagnaIT commented 4 years ago

this is good news, even if you can only communicate to netflix which movie has been viewed completely is already very good!

take the time you need to clean up the code here at the moment i am very busy to make the code inter-compatible between py2 - py3

yoshimo commented 4 years ago

very nice to hear @nohajc . I assume once we found the necessary request it can be used across multiple platforms, developers are lazy. Code can be ugly as long as it gives us the proper info.

nohajc commented 4 years ago

I'll release the code soon. I just want to make it easier to use. It's almost done, I only need to persist the negotiated AES key, otherwise browser history has to be cleared every time you restart the mitm script. I haven't found any better way to force new MSL handshake.

yoshimo commented 4 years ago

With a clean cache, which request sets up the handshake and does it happen right when i log into the website?

CastagnaIT commented 4 years ago

I'll take a look at the code, I don't know what you're doing, but i inform you that all this must work with the session currently opened by the addon (service) not one new

nohajc commented 4 years ago

@yoshimo https://github.com/CastagnaIT/plugin.video.netflix/blob/master/resources/lib/services/msl/msl_handler.py#L107

It should be the first request to manifest endpoint, the only one which will be unencrypted. It happens some time after login and after choosing a user profile. The MSL session is preserved even after logout though.

@CastagnaIT What I'm doing is a HTTPS proxy which intercepts communication between a real Netflix client (e.g. the cadmium player js library running in browser) and the Netflix server. Normally, you would be able to decrypt TLS with a special CA installed (this is what mitmproxy does by default) but my proxy script also handles MSL decryption.

I will set up a separate repository for this, of course.

nohajc commented 4 years ago

All right, the code is up. Anyone is welcome to try it. https://github.com/nohajc/netflix-mitm-proxy

yoshimo commented 4 years ago

@nohajc i used pip to install pycryptodome, but your script says it can'T find the module on my windows installation. Do you have an idea what goes wrong?

nohajc commented 4 years ago

@nohajc i used pip to install pycryptodome, but your script says it can'T find the module on my windows installation. Do you have an idea what goes wrong?

Ah, sorry, I forgot to mention this in the README. Windows installation of mitmproxy uses its own bundled python runtime. The workaround is to install mitmproxy also with pip.

yoshimo commented 4 years ago

Mhm, how do i force a new handshake in this addon? I deleted the json file to remove the desktop key and broke the proxy and log out and back in doesn't seem to trigger a new handshake. Has anyone successfully compared logs yet?

nohajc commented 4 years ago

Mhm, how do i force a new handshake in this addon?

Yes, logging out does not close the MSL session. The decryption key will stay the same for some time. That's why I cache it in the json file. If you still want a new handshake for some reason, you have to delete all Netflix cookies and local storage or start a new browser profile.

yoshimo commented 4 years ago

1) does a browser cache reset also need a reset of the decryptor cache? 2) How would i reset the session in castagna.netflix so that i have two logs of the same format of the same episode to conpare kodi with the website more easily?

nohajc commented 4 years ago
1. does a browser cache reset also need a reset of the decryptor cache?

Resetting browser cache should trigger a new handshake, but you don't have to delete the json file of the decryptor. It will be updated automatically with a new key.

2. How would i reset the session in castagna.netflix so that i have two logs of the same format of the same episode to conpare kodi with the website more easily?

I'm not sure but I guess deleting msl_data.json could help: https://github.com/CastagnaIT/plugin.video.netflix/blob/master/resources/lib/services/msl/msl_handler.py#L69

CastagnaIT commented 4 years ago

thanks nohajc, i just did a test, you get much information more clearly i will try to study the situations

nohajc commented 4 years ago

thanks nohajc, i just did a test, you get much information more clearly i will try to study the situations

You're welcome. I noticed you've forked the repository. Feel free to make a pull request, so that I can merge your changes.

kidforpm commented 4 years ago

Is there any progress? Maybe it is possible to split this request into two parts. I think it is possible to sync watched status to kodi, syncing it back to Netflix might be a challenge but that would make the plug-in perfect for me. Now reading and syncing play status from and to kodi seems like a very different story.

CastagnaIT commented 4 years ago

the progress can be seen in PR, I have something more in local but not much

I think it is possible to sync watched status to kodi,

it's not easy, you also need to work to find the right compromise with Kodi video management for watched status and resume.

Another obstacle is the Kodi library, i haven't yet researched how to update video watched and resume for each video, without overburdening with too many requests. At least initially the thing will be confined to work for internal use in the addon and not in the Kodi library.

I also think there's going to be another problem with the cache management, not yet checked.

I'm following the set plan, if it's not followed in perfect order, it's only because things are intrinsically linked

kidforpm commented 4 years ago

Maybe you can use some of the Trakt implementation? They have syncing watched status down pretty reliable both ways. Agreed it is harder to sync watch progress into kodi, but Trakt is also outputting progress at reasonable intervals. I would reckon it is more difficult to read and write that info to Netflix database

CastagnaIT commented 4 years ago

i can see how trakt addon update edit the watched/resume status to the Kodi items, but trakt is another thing, here is not useful

dagwieers commented 4 years ago

AFAICT trakt works using VideoLibrary JSONRPC calls, which does not work for plugin://-type resources. This is making our life quite complicated. It would be much easier if Kodi would support plugin://-type resources from Files.GetFileDetails and Files.SetFileDetails JSONRPC calls.

This means we cannot easily manage/sync playcount and resumetime information between content provider and Kodi :-(

See pietje666/plugin.video.vrt.nu#568 for all the discussions, pull-requests and feature request.

CastagnaIT commented 4 years ago

hi dagwieers, thanks for useful info! interesting the rejected PR, from what i understand the kodi team would only accept the change if you create a new separate function

for now i have other things to complete before get to these changes this moment will come

CastagnaIT commented 4 years ago

@dagwieers I'm trying use this https://github.com/xbmc/xbmc/pull/17202 but i have a problem when i use it, is no longer possible to change the watched status of the menuItem through context menu or keyboard shortcut

happen same thing if i set watched/resume status by: xbmcgui.ListItem list_item.setProperty('PlayCount', xy) list_item.setProperty('ResumeTime', xy)

is that normal?

dagwieers commented 4 years ago

@CastagnaIT If you use ListItem properties to set the playcount and resumetime, you are overriding the information from the database. And that is problematic, because if you return to a listing, this information is stale.

With xbmc/xbmc#17202 we no longer need to use ListItem properties, as we can read/write from the database, and rather than set the information in the ListItem, you should update the database and refresh the listing (if necessary).

CastagnaIT commented 4 years ago

i do some tests i was thinking that things are really complicated, i'm not quite sure how to proceed

JSONRPC way, i can not use it when i loading page, this method need a refresh and will result in a Kodi infinite loop (). -In addition i need to use it before the endOfDirectory(), and can cause a nasty Kodi crash if loading is too fast

In addition even if it works, a user can change the status (via ctx menu or keyboard etc), but there is no kodi callback function, then changes it will not be reflected to netflix service. (i'm not yet sure if i will can change status on netflix, because it has a very special mode of operation, but this is another story...)

The method: list_item.setProperty('PlayCount', xy) not work in all case...i think has a bug (e.g. when a item is already watched and you force to set again watched, the override do not work)

The method: list_item.setInfo('video', {'PlayCount': 'xy'}) this works -But the override, breaks down the Kodi menus (like Reset, mark watched etc...) how remove these menu? then you have to re-implement them all manually? bad.. -In this case i can not use this method in conjunction with JSONRPC, then how do i update the value if I don't have access to the listitem? -another problem i can not use twice the method setInfo because otherwise delete the previous values and i can't always have direct access to this informations, and there is no getInfo...


I find it a nightmare, the current situation seem unmanageable

there should now be an opportunity to set/update a initial value when i create an listitem object without overriding a value in db, Kodi should only insert if value not exist or update the existing value directly

perhaps can be implemented in this way: add new set in listItem: setPlayCount() setResumeTime()

and inside the method addDirectoryItems() when executing the for each object loop, add a system to insert/update the value to db by reading setPlayCount/setResumeTime

and after, have a callback way to handle watched/unwatched events when user change manually the value (By Monitor callback)

I think add these two things to Kodi would save a lot of trouble and JSONRPC method can be used without the problems of the overrided values

opened discussion also to forum: https://forum.kodi.tv/showthread.php?tid=351609

dagwieers commented 4 years ago

It is a nightmare, with a lot of tradeoffs. That is why being able to update the database and no longer needing to add this information to the ListItem is crucial.

It is true that there is no hook for the context menu items (Mark as (un)watched or Reset position) and we haven't looked at how we will simplify our existing implementation for Matrix.

But as you indicated, the process would mostly look like:

To speed up this process and ensure we finish before Kodi refreshes an existing listing, we update locally immediately and online asynchronously.

CastagnaIT commented 4 years ago

I'll try making some modifications to Kodi similar described above then if it works, let's see how to proceed since Kodi 19 is in alpha we could find a more suitable system

CastagnaIT commented 4 years ago

if I find a compromise to use list_item.setInfo('video', {'PlayCount': 'xy'}) you know how to remove these menus? image

CastagnaIT commented 4 years ago

I'm almost ready to merge it with the master branch! it would be appreciated if someone would help me run some tests before merge it

for the noobs, test does not mean see if it starts, you must also monitor the log in verbose mode, to ensure that there are no errors

before running the test read also the notes of the PR https://github.com/CastagnaIT/plugin.video.netflix/pull/385

~[plugin.video.netflix_0.17.0_20200220_test1.zip]~

!!!WARNING!!! If you install this test as an upgrade, it may cause problems if you roll back to the previous version and then update again with future versions, so if necessary make a backup! I'll add extra protection to safeguard rollbacks before merge