-
Notifications
You must be signed in to change notification settings - Fork 74
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[webhook/api] Create a basic plex webhook with some very rough code.
This currently is only designed to operate on episodes but not specials. Code does contain structure to do this.
- Loading branch information
Showing
2 changed files
with
168 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Runtime.Serialization; | ||
using System.Text; | ||
using System.Threading.Tasks; | ||
using AniDBAPI; | ||
using JMMServer.API.Model.core; | ||
using JMMServer.Entities; | ||
using JMMServer.Providers; | ||
using JMMServer.Repositories; | ||
using Nancy; | ||
using Nancy.ModelBinding; | ||
using Newtonsoft.Json; | ||
using Newtonsoft.Json.Serialization; | ||
|
||
namespace JMMServer.API.Module.apiv2 | ||
{ | ||
public class PlexWebook : NancyModule | ||
{ | ||
public PlexWebook() : base("/plex") | ||
{ | ||
Post["/"] = o => WebhookPost(); | ||
} | ||
|
||
object WebhookPost() | ||
{ | ||
PlexEvent eventData = JsonConvert.DeserializeObject<PlexEvent>(this.Context.Request.Form.payload, new JsonSerializerSettings(){ContractResolver = new CamelCasePropertyNamesContractResolver()}); | ||
|
||
switch (eventData.Event) | ||
{ | ||
case "media.scrobble": | ||
Scrobble(eventData); | ||
break; | ||
} | ||
|
||
return APIStatus.statusOK(); | ||
} | ||
|
||
#region Plex events | ||
|
||
private void Scrobble(PlexEvent data) | ||
{ | ||
PlexEvent.PlexMetadata metadata = data.Metadata; | ||
if (!data.Metadata.Guid.StartsWith("com.plexapp.agents.shoko://")) return; | ||
|
||
string[] parts = metadata.Guid.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); | ||
int animeId = int.Parse(parts[1]); | ||
int series = int.Parse(parts[2]); | ||
|
||
var anime = RepoFactory.AnimeSeries.GetByID(animeId); | ||
|
||
enEpisodeType episodeType; | ||
switch (series) //I hate magic number's but this is just about how I can do this, also the rest of this is for later. | ||
{ | ||
case -4: | ||
episodeType = enEpisodeType.Parody; | ||
break; | ||
case -3: | ||
episodeType = enEpisodeType.Trailer; | ||
break; | ||
case -2: | ||
episodeType = enEpisodeType.Other; | ||
break; | ||
case -1: | ||
episodeType = enEpisodeType.Credits; | ||
break; | ||
case 0: | ||
episodeType = enEpisodeType.Special; | ||
break; | ||
default: | ||
episodeType = enEpisodeType.Episode; | ||
break; | ||
} | ||
|
||
if (episodeType != enEpisodeType.Episode || metadata.Index == 0) //metadata.index = 0 when it's something else. | ||
return; //right now no clean way to detect the episode. I could do by title. | ||
|
||
|
||
AnimeEpisode episode = anime | ||
.GetAnimeEpisodes() | ||
.Where(a => a.EpisodeTypeEnum == episodeType) | ||
.Where(a => metadata.Title.Equals(a?.PlexContract?.Title, StringComparison.InvariantCultureIgnoreCase)) | ||
.FirstOrDefault(a => a?.TvDBEpisode?.SeasonNumber == series); | ||
if (episode == null) return; | ||
|
||
var user = RepoFactory.JMMUser.GetAll().FirstOrDefault(u => data.Account.Title.FindIn(u.Contract?.PlexUsers)); | ||
if (user == null) | ||
return; //At this point in time, we don't want to scrobble for unknown users. | ||
|
||
episode.ToggleWatchedStatus(true, true, FromUnixTime(metadata.LastViewedAt), false, false, user.JMMUserID, true); | ||
anime.UpdateStats(true, false, true); | ||
} | ||
|
||
#endregion | ||
|
||
public DateTime FromUnixTime(long unixTime) | ||
{ | ||
var epoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc); | ||
return epoch.AddMilliseconds(unixTime); | ||
} | ||
|
||
|
||
#region plexapi | ||
|
||
internal class PlexEvent | ||
{ | ||
public string Event; | ||
public bool User; | ||
public bool Owner; | ||
|
||
public PlexAccount Account; | ||
public PlexBasicInfo Server; | ||
public PlexPlayerInfo Player; | ||
public PlexMetadata Metadata; | ||
|
||
public class PlexAccount | ||
{ | ||
public int Id; | ||
public string Thumb; | ||
public string Title; | ||
} | ||
|
||
public class PlexBasicInfo | ||
{ | ||
public string Title; | ||
public string Uuid; | ||
} | ||
|
||
public class PlexPlayerInfo : PlexBasicInfo | ||
{ | ||
public bool Local; | ||
public string PublicAddress; | ||
} | ||
|
||
public class PlexMetadata | ||
{ | ||
public string LibrarySectionType; | ||
public string RatingKey; | ||
public string Key; | ||
public string ParentRatingKey; | ||
public string GrandparentRatingKey; | ||
public string Guid; | ||
public int LibrarySectionId; | ||
public string Type; | ||
public string Title; | ||
public string GrandparentKey; | ||
public string ParentKey; | ||
public string GranparentTitle; | ||
public string Summary; | ||
public int Index; | ||
public int ParentIndex; | ||
public int RatingCount; | ||
public string Thumb; | ||
public string Art; | ||
public string ParentThumb; | ||
public string GrandparentThumb; | ||
public string GrandparentArt; | ||
public int LastViewedAt; | ||
public int AddedAt; | ||
public int UpdatedAt; | ||
} | ||
} | ||
|
||
#endregion | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
will this replace JMMServerPlex? or shoko support plex at two diffrent endpoint ?
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As far as I know this will only work for users with Plex Pass. Also @bigretromike, I'm locking down the Master branch for the refactor merge in 6 hours after 3.7.0.5 so make all changes before then.
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@bigretromike its an additional endpoint, as this is a plexpass only feature, i have some extra to possibly do something though got to work out the best implementation.
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://support.plex.tv/hc/en-us/articles/115002267687-Webhooks
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh, wow. You need to pay subscription (plexpass) to be able to allow your own server to communicate with your own services - I didn't know it is so much superior.
Thanks for info and clarify. To bad you couldn't reused apiv2 code, but yeah. Its Plex - it need 'his' endpoints and names 👍
Also @ElementalCrisis I'm probably fine. Maybe one thing could be fixed but its not as big as to delay 3.7.0.5, go for is as its delayed anyway.
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, I have further plans that will allow two way syncing from ShokoServer. For the interested
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so basically there could be a cripped-plex-client inside shoko (according to this: Cazzar/ShokoMetadata.bundle#1) to support plex the same way as nakamori does kodi but without having kodi inside shoko 👍
Good that there is not as many htpc media apps out there that cannot use custom endpoint.
We could also fork plex client/server :-) and strip it from premium gate and making it the supperior player with things that @hidden4003 miss in it; Then we could throw any support out :-) and focus on plexification of shoko
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No Plexification. It'll be way too much work to maintain. Plus I don't like the people they run Plex
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, if it was anything I would be looking at a plugin or a middle-man. As it would be exceptionally hacky, but it is really the only clean way you can do it for free bidirectionally.
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@da3dsoul it was a joke, don't worry.
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like it was only half. You've been wanting a nice transcoder in JMM forever
8ddf1cb
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I have it in UMS 👍 which give me the best transcoding available for all enabled device without needed of client 👍 And I have ability to tweak each client differently to get best out of speed/quality.
I will work more with it to make it better to provide people with nice Guide.
Also it works with Kodi and any DLNA enabled player as client to so client-less and client endpoints are supported.