diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index c0b05d9..0000000 --- a/.travis.yml +++ /dev/null @@ -1,20 +0,0 @@ -language: csharp -sudo: false -dist: trusty -env: - global: - # We want to build our product in Release configuration - - CONFIGURATION=Release - # Set the DOTNET_SKIP_FIRST_TIME_EXPERIENCE environment variable to stop wasting time caching packages - - DOTNET_SKIP_FIRST_TIME_EXPERIENCE=true - # Disable sending usage data to Microsoft - - DOTNET_CLI_TELEMETRY_OPTOUT=1 - # Skip xml docs for packages - - NUGET_XMLDOC_MODE=skip -mono: none -dotnet: 2.1 -install: - - dotnet restore -script: - - dotnet build ./Plex.Server.Webhooks/ - - dotnet test ./Plex.Server.Webhooks.Tests/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index 23e3bc9..a924af3 100644 --- a/LICENSE +++ b/LICENSE @@ -186,7 +186,7 @@ same "printed page" as the copyright notice for easier identification within third-party archives. - Copyright 2018 Hinni Solutions + Copyright 2021 Hinni Solutions Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/Plex.Server.Webhooks.Tests/ParseDemoEventTest.cs b/Plex.Server.Webhooks.Tests/ParseDemoEventTest.cs index bb9868f..4d646b9 100644 --- a/Plex.Server.Webhooks.Tests/ParseDemoEventTest.cs +++ b/Plex.Server.Webhooks.Tests/ParseDemoEventTest.cs @@ -14,13 +14,12 @@ public void ParseEvent() // Arrange var path = Path.Combine(Environment.CurrentDirectory, "Payloads", "MediaPlay.json"); var payload = File.ReadAllText(path); - var parser = new WebhookParser(); // Act - var plexEvent = parser.ParseEvent(payload); + var plexEvent = PlexWebhookParser.ParseEvent(payload); // Assert - Assert.IsType(plexEvent); + Assert.IsType(plexEvent); } } } \ No newline at end of file diff --git a/Plex.Server.Webhooks.Tests/Plex.Server.Webhooks.Tests.csproj b/Plex.Server.Webhooks.Tests/Plex.Server.Webhooks.Tests.csproj index 68a0ba0..42b6c5b 100644 --- a/Plex.Server.Webhooks.Tests/Plex.Server.Webhooks.Tests.csproj +++ b/Plex.Server.Webhooks.Tests/Plex.Server.Webhooks.Tests.csproj @@ -1,29 +1,24 @@ - netcoreapp2.1 - + net5.0 false - Hinni - Hinni Solutions - - Copyright © 2017-2018 Hinni Solutions - + Copyright © 2017-2021 Hinni Solutions - https://github.com/Hinni/plex-server-webhooks - Plex MediaServer Webhooks Tests - - 2.0.0 + 2.1.0 - - - + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + diff --git a/Plex.Server.Webhooks/Converters/EventTypeConverter.cs b/Plex.Server.Webhooks/Converters/EventTypeConverter.cs new file mode 100644 index 0000000..124cfc6 --- /dev/null +++ b/Plex.Server.Webhooks/Converters/EventTypeConverter.cs @@ -0,0 +1,21 @@ +using System; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Plex.Server.Webhooks.Extensions; + +namespace Plex.Server.Webhooks.Converters +{ + public class EventTypeConverter : StringEnumConverter + { + public override object? ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer) + { + if (reader.TokenType != JsonToken.String) return base.ReadJson(reader, objectType, existingValue, serializer); + + string enumText = reader.Value?.ToString(); + var result = enumText.GetEventType(); + if (result == null) throw new NotImplementedException($"Event {enumText} is not implemented yet."); + + return base.ReadJson(reader, objectType, existingValue, serializer); + } + } +} diff --git a/Plex.Server.Webhooks/Converters/WebhookJsonConverter.cs b/Plex.Server.Webhooks/Converters/WebhookJsonConverter.cs deleted file mode 100644 index b088e87..0000000 --- a/Plex.Server.Webhooks/Converters/WebhookJsonConverter.cs +++ /dev/null @@ -1,50 +0,0 @@ -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; -using Plex.Server.Webhooks.Events; -using System; -using System.Collections.Generic; - -namespace Plex.Server.Webhooks.Converters -{ - public class WebhookJsonConverter : JsonConverter - { - private static readonly IDictionary TypeMapping = new Dictionary() - { - {"media.play", typeof(MediaPlay)}, - {"media.pause", typeof(MediaPause)}, - {"media.resume", typeof(MediaResume)}, - {"media.stop", typeof(MediaStop)}, - {"media.scrobble", typeof(MediaScrobble)}, - {"media.rate", typeof(MediaRate)}, - }; - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - throw new NotImplementedException("The webhook JSON converter does not support write operations."); - } - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) - { - var jsonObject = JObject.Load(reader); - - //serialise based on the event type - JToken eventName = null; - jsonObject.TryGetValue("event", StringComparison.CurrentCultureIgnoreCase, out eventName); - - if (!TypeMapping.ContainsKey(eventName.ToString())) - { - throw new NotImplementedException(string.Format("Event {0} is not implemented yet.", eventName)); - } - - Type type = TypeMapping[eventName.ToString()]; - WebhookEventBase webhookItem = (WebhookEventBase)jsonObject.ToObject(type, serializer); - - return webhookItem; - } - - public override bool CanConvert(Type objectType) - { - return objectType == typeof(WebhookEventBase); - } - } -} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Enums/EventType.cs b/Plex.Server.Webhooks/Enums/EventType.cs new file mode 100644 index 0000000..be267fa --- /dev/null +++ b/Plex.Server.Webhooks/Enums/EventType.cs @@ -0,0 +1,61 @@ +using System.Runtime.Serialization; + +namespace Plex.Server.Webhooks.Events +{ + /// + /// Represents the event types for the Webhook being hit + /// + public enum EventType + { + #region New Content + + /// A new item is added that appears in the user’s On Deck. A poster is also attached to this event. + [EnumMember(Value = "library.on.deck")] + LibraryOnDeck, + /// A new item is added to a library to which the user has access. A poster is also attached to this event. + [EnumMember(Value = "library.new")] + LibraryNew, + + #endregion + + #region Playback + + /// Media playback pauses. + [EnumMember(Value = "media.pause")] + MediaPause, + /// Media starts playing. An appropriate poster is attached. + [EnumMember(Value = "media.play")] + MediaPlay, + /// Media is rated. A poster is also attached to this event. + [EnumMember(Value = "media.rate")] + MediaRate, + /// Media playback resumes. + [EnumMember(Value = "media.resume")] + MediaResume, + /// Media is viewed (played past the 90% mark). + [EnumMember(Value = "media.scrobble")] + MediaScrobble, + /// Media playback stops. + [EnumMember(Value = "media.stop")] + MediaStop, + + #endregion + + #region Server Owner + + /// A database backup is completed successfully via Scheduled Tasks. + [EnumMember(Value = "admin.database.backup")] + AdminDatabaseBackup, + /// Corruption is detected in the server database. + [EnumMember(Value = "admin.database.corrupted")] + AdminDatabaseCorrupted, + /// A device accesses the owner’s server for any reason, which may come from background connection testing and doesn’t necessarily indicate active browsing or playback. + [EnumMember(Value = "device.new")] + DeviceNew, + /// Playback is started by a shared user for the server. A poster is also attached to this event. + [EnumMember(Value = "playback.started")] + PlaybackStarted + + #endregion + } +} diff --git a/Plex.Server.Webhooks/Events/Core/Account.cs b/Plex.Server.Webhooks/Events/Core/Account.cs index 764e731..3bcd112 100644 --- a/Plex.Server.Webhooks/Events/Core/Account.cs +++ b/Plex.Server.Webhooks/Events/Core/Account.cs @@ -2,15 +2,21 @@ namespace Plex.Server.Webhooks.Events.Core { + /// + /// Represents the User + /// public class Account { + /// The Id [JsonProperty("id")] public int Id { get; set; } + /// The Thumbnail [JsonProperty("thumb")] public string Thumb { get; set; } + /// The Username [JsonProperty("title")] - public string Title { get; set; } + public string Name { get; set; } } } \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/Core/Metadata.cs b/Plex.Server.Webhooks/Events/Core/Metadata.cs index 2e0b798..a9bf4e2 100644 --- a/Plex.Server.Webhooks/Events/Core/Metadata.cs +++ b/Plex.Server.Webhooks/Events/Core/Metadata.cs @@ -4,77 +4,104 @@ namespace Plex.Server.Webhooks.Events.Core { + /// + /// Represents the Metadata + /// public class Metadata { + /// The Library Section Type [JsonProperty("librarySectionType")] public string LibrarySectionType { get; set; } + /// The Rating Key [JsonProperty("ratingKey")] public string RatingKey { get; set; } + /// The Key [JsonProperty("key")] public string Key { get; set; } + /// The Parent Rating Key [JsonProperty("parentRatingKey")] public string ParentRatingKey { get; set; } + /// The Grandparent Rating Key [JsonProperty("grandparentRatingKey")] public string GrandparentRatingKey { get; set; } + /// The Id [JsonProperty("guid")] - public string Guid { get; set; } + public string Id { get; set; } + /// The Library Section ID [JsonProperty("librarySectionID")] public int LibrarySectionID { get; set; } + /// The Type [JsonProperty("type")] public string Type { get; set; } + /// The Title [JsonProperty("title")] public string Title { get; set; } + /// The Grandparent Key [JsonProperty("grandparentKey")] public string GrandparentKey { get; set; } + /// The Parent Key [JsonProperty("parentKey")] public string ParentKey { get; set; } + /// The Grandparent Title [JsonProperty("grandparentTitle")] public string GrandparentTitle { get; set; } + /// The Parent Title [JsonProperty("parentTitle")] public string ParentTitle { get; set; } + /// The Summary [JsonProperty("summary")] public string Summary { get; set; } + /// The Index [JsonProperty("index")] public int Index { get; set; } + /// The Parent Index [JsonProperty("parentIndex")] public int ParentIndex { get; set; } + /// The Rating Count [JsonProperty("ratingCount")] public int RatingCount { get; set; } + /// The Thumbnail [JsonProperty("thumb")] public string Thumb { get; set; } + /// The Art [JsonProperty("art")] public string Art { get; set; } + /// The Parent Thumb [JsonProperty("parentThumb")] public string ParentThumb { get; set; } + /// The Grandparent Thumbnail [JsonProperty("grandparentThumb")] public string GrandparentThumb { get; set; } + /// The Grandparent Art [JsonProperty("grandparentArt")] public string GrandparentArt { get; set; } + /// Added At [JsonProperty("addedAt"), JsonConverter(typeof(EpochToDateTimeConverter))] public DateTime AddedAt { get; set; } + /// Updated At [JsonProperty("updatedAt"), JsonConverter(typeof(EpochToDateTimeConverter))] public DateTime UpdatedAt { get; set; } } diff --git a/Plex.Server.Webhooks/Events/Core/Player.cs b/Plex.Server.Webhooks/Events/Core/Player.cs index 2c8ab2b..30c1765 100644 --- a/Plex.Server.Webhooks/Events/Core/Player.cs +++ b/Plex.Server.Webhooks/Events/Core/Player.cs @@ -2,18 +2,25 @@ namespace Plex.Server.Webhooks.Events.Core { + /// + /// Represents the Player (device) + /// public class Player { + /// The Id + [JsonProperty("uuid")] + public string Id { get; set; } + + /// The Name + [JsonProperty("title")] + public string Name { get; set; } + + /// Is Local [JsonProperty("local")] public bool Local { get; set; } + /// The Public Address [JsonProperty("publicAddress")] public string PublicAddress { get; set; } - - [JsonProperty("title")] - public string Title { get; set; } - - [JsonProperty("uuid")] - public string Uuid { get; set; } } } \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/Core/Server.cs b/Plex.Server.Webhooks/Events/Core/Server.cs index a40526e..1a7d185 100644 --- a/Plex.Server.Webhooks/Events/Core/Server.cs +++ b/Plex.Server.Webhooks/Events/Core/Server.cs @@ -2,12 +2,17 @@ namespace Plex.Server.Webhooks.Events.Core { + /// + /// Represents the Server + /// public class Server { - [JsonProperty("title")] - public string Title { get; set; } - + /// The Id [JsonProperty("uuid")] - public string Uuid { get; set; } + public string Id { get; set; } + + /// The Name + [JsonProperty("title")] + public string Name { get; set; } } } \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/Core/WebhookEventBase.cs b/Plex.Server.Webhooks/Events/Core/WebhookEventBase.cs index a07ab69..b3089b9 100644 --- a/Plex.Server.Webhooks/Events/Core/WebhookEventBase.cs +++ b/Plex.Server.Webhooks/Events/Core/WebhookEventBase.cs @@ -1,28 +1,43 @@ using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Plex.Server.Webhooks.Converters; using Plex.Server.Webhooks.Events.Core; namespace Plex.Server.Webhooks.Events { + /// + /// Represents the base for webhook events + /// public abstract class WebhookEventBase - { - [JsonProperty("event")] - public string EventType { get; set; } - + { + /// Is User [JsonProperty("user")] public bool User { get; set; } + /// The Event Type + [JsonProperty("event")] + [JsonConverter(typeof(EventTypeConverter))] + public EventType EventType { get; set; } + + + + /// Is Owner [JsonProperty("owner")] public bool Owner { get; set; } + /// The Account [JsonProperty("Account")] public Account Account { get; set; } + /// The Server [JsonProperty("Server")] public Core.Server Server { get; set; } + /// The Player [JsonProperty("Player")] public Player Player { get; set; } + /// The Metadata [JsonProperty("Metadata")] public Metadata Metadata { get; set; } } diff --git a/Plex.Server.Webhooks/Events/MediaPause.cs b/Plex.Server.Webhooks/Events/MediaPause.cs deleted file mode 100644 index ec3c393..0000000 --- a/Plex.Server.Webhooks/Events/MediaPause.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Plex.Server.Webhooks.Events -{ - public class MediaPause : WebhookEventBase - { } -} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/MediaPlay.cs b/Plex.Server.Webhooks/Events/MediaPlay.cs deleted file mode 100644 index 0e160fe..0000000 --- a/Plex.Server.Webhooks/Events/MediaPlay.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Plex.Server.Webhooks.Events -{ - public class MediaPlay : WebhookEventBase - { } -} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/MediaRate.cs b/Plex.Server.Webhooks/Events/MediaRate.cs deleted file mode 100644 index 5acc1dd..0000000 --- a/Plex.Server.Webhooks/Events/MediaRate.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Plex.Server.Webhooks.Events -{ - public class MediaRate : WebhookEventBase - { } -} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/MediaResume.cs b/Plex.Server.Webhooks/Events/MediaResume.cs deleted file mode 100644 index f7205d0..0000000 --- a/Plex.Server.Webhooks/Events/MediaResume.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Plex.Server.Webhooks.Events -{ - public class MediaResume : WebhookEventBase - { } -} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/MediaScrobble.cs b/Plex.Server.Webhooks/Events/MediaScrobble.cs deleted file mode 100644 index a81ef14..0000000 --- a/Plex.Server.Webhooks/Events/MediaScrobble.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Plex.Server.Webhooks.Events -{ - public class MediaScrobble : WebhookEventBase - { } -} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/MediaStop.cs b/Plex.Server.Webhooks/Events/MediaStop.cs deleted file mode 100644 index 9b55ffd..0000000 --- a/Plex.Server.Webhooks/Events/MediaStop.cs +++ /dev/null @@ -1,5 +0,0 @@ -namespace Plex.Server.Webhooks.Events -{ - public class MediaStop : WebhookEventBase - { } -} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Events/PlexWebhookEvent.cs b/Plex.Server.Webhooks/Events/PlexWebhookEvent.cs new file mode 100644 index 0000000..566becf --- /dev/null +++ b/Plex.Server.Webhooks/Events/PlexWebhookEvent.cs @@ -0,0 +1,8 @@ +namespace Plex.Server.Webhooks.Events +{ + /// + /// Represents the Plex Webhook event + /// + public class PlexWebhookEvent : WebhookEventBase + { } +} diff --git a/Plex.Server.Webhooks/Extensions/StringExtensions.cs b/Plex.Server.Webhooks/Extensions/StringExtensions.cs new file mode 100644 index 0000000..52a366d --- /dev/null +++ b/Plex.Server.Webhooks/Extensions/StringExtensions.cs @@ -0,0 +1,26 @@ +using System; +using Plex.Server.Webhooks.Events; + +namespace Plex.Server.Webhooks.Extensions +{ + public static class StringExtensions + { + /// + /// Get the . + /// + /// The input string + /// The + internal static EventType? GetEventType(this string enumString) + { + try + { + var result = Enum.Parse(enumString.Replace(".", ""), true); + return result; + } + catch (Exception e) + { + return null; + } + } + } +} diff --git a/Plex.Server.Webhooks/Plex.Server.Webhooks.csproj b/Plex.Server.Webhooks/Plex.Server.Webhooks.csproj index 3413ab4..e399c02 100644 --- a/Plex.Server.Webhooks/Plex.Server.Webhooks.csproj +++ b/Plex.Server.Webhooks/Plex.Server.Webhooks.csproj @@ -1,14 +1,14 @@ - netstandard1.0 + netstandard2.1 true Hinni - 2.0.0 + 2.1.0 A library to parse event webhooks from Plex server. https://github.com/Hinni/plex-server-webhooks - Switched project to .NET Standard 1.0 - Copyright © 2017-2018 Hinni Solutions + Switched project to .NET Standard 2.0 + Copyright © 2017-2021 Hinni Solutions Hinni Solutions @@ -16,7 +16,7 @@ - + diff --git a/Plex.Server.Webhooks/Service/PlexWebhookParser.cs b/Plex.Server.Webhooks/Service/PlexWebhookParser.cs new file mode 100644 index 0000000..87398c4 --- /dev/null +++ b/Plex.Server.Webhooks/Service/PlexWebhookParser.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using Newtonsoft.Json; +using Plex.Server.Webhooks.Converters; +using Plex.Server.Webhooks.Events; + +namespace Plex.Server.Webhooks.Service +{ + /// + /// Represents the Plex Webhook Parser + /// + public static class PlexWebhookParser + { + /// + /// Deserialize Plex Webhook data + /// + /// The incoming webhook data + /// - The object + public static PlexWebhookEvent ParseEvent(string json) => + JsonConvert.DeserializeObject(json); + } +} \ No newline at end of file diff --git a/Plex.Server.Webhooks/Service/WebhookParser.cs b/Plex.Server.Webhooks/Service/WebhookParser.cs deleted file mode 100644 index f43d929..0000000 --- a/Plex.Server.Webhooks/Service/WebhookParser.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Newtonsoft.Json; -using Plex.Server.Webhooks.Converters; -using Plex.Server.Webhooks.Events; -using System; - -namespace Plex.Server.Webhooks.Service -{ - public class WebhookParser - { - private readonly JsonConverter[] _converters; - - public WebhookParser() - { - _converters = new JsonConverter[] { new WebhookJsonConverter() }; - } - - public WebhookEventBase ParseEvent(String json) - { - return JsonConvert.DeserializeObject(json, _converters); - } - } -} \ No newline at end of file diff --git a/plex-server-webhooks.sln b/plex-server-webhooks.sln index ab02ac5..8db6c81 100644 --- a/plex-server-webhooks.sln +++ b/plex-server-webhooks.sln @@ -1,19 +1,18 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.106 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29920.165 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{393F97E6-85EC-4751-971D-C4AF2C743C7D}" ProjectSection(SolutionItems) = preProject .gitignore = .gitignore - .travis.yml = .travis.yml LICENSE = LICENSE readme.md = readme.md EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Plex.Server.Webhooks", "Plex.Server.Webhooks\Plex.Server.Webhooks.csproj", "{2A555898-1357-4175-B2E0-28D7C767900F}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Plex.Server.Webhooks.Tests", "Plex.Server.Webhooks.Tests\Plex.Server.Webhooks.Tests.csproj", "{019E3641-8A52-407B-A554-7BB0CEEA5229}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Plex.Server.Webhooks.Tests", "Plex.Server.Webhooks.Tests\Plex.Server.Webhooks.Tests.csproj", "{019E3641-8A52-407B-A554-7BB0CEEA5229}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/readme.md b/readme.md index 4384915..aeed927 100644 --- a/readme.md +++ b/readme.md @@ -4,13 +4,15 @@ [![GitHub release](https://img.shields.io/github/release/Hinni/plex-server-webhooks.svg)](https://github.com/Hinni/plex-server-webhooks/releases) [![NuGet](https://img.shields.io/nuget/v/Plex.Server.Webhooks.svg)](https://www.nuget.org/packages/Plex.Server.Webhooks/) -A library to parse event webhooks from Plex server. +A library to parse event webhooks from Plex Media Server. ## Download via NuGet Install Plex.Server.Webhooks via NuGet package manager (nuget.org) - Install-Package Plex.Server.Webhooks +```cmd +Install-Package Plex.Server.Webhooks +``` ## Usage @@ -24,8 +26,8 @@ var events = parser.ParseEvent(json); ## Plex Webhook Documentation Check out the documentation on Plex: -https://support.plex.tv/hc/en-us/articles/115002267687-Webhooks +[Webhooks on Plex Support](https://support.plex.tv/articles/115002267687-webhooks/) ## Thanks -* [mirajavora](https://github.com/mirajavora) for the project structure and converters used in [sendgrid-webhooks](https://github.com/mirajavora/sendgrid-webhooks) \ No newline at end of file +* [mirajavora](https://github.com/mirajavora) for the project structure and converters used in [sendgrid-webhooks](https://github.com/mirajavora/sendgrid-webhooks)