mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2025-12-20 02:02:12 -06:00
added plex plugin
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -12,3 +12,4 @@ deploy/**
|
||||
*.ffplugin
|
||||
DiscordNodes/settings.json
|
||||
Gotify/settings.json
|
||||
Plex/settings.json
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -21,6 +21,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Gotify", "Gotify\Gotify.csp
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordNodes", "DiscordNodes\DiscordNodes.csproj", "{27721E6D-1FBF-4950-824E-5231CACDE64C}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Plex", "Plex\Plex.csproj", "{4127A3CC-8BCE-41AE-BDE4-6FA75EF2D8A1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -63,6 +65,10 @@ Global
|
||||
{27721E6D-1FBF-4950-824E-5231CACDE64C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{27721E6D-1FBF-4950-824E-5231CACDE64C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{27721E6D-1FBF-4950-824E-5231CACDE64C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4127A3CC-8BCE-41AE-BDE4-6FA75EF2D8A1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4127A3CC-8BCE-41AE-BDE4-6FA75EF2D8A1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4127A3CC-8BCE-41AE-BDE4-6FA75EF2D8A1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4127A3CC-8BCE-41AE-BDE4-6FA75EF2D8A1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
6
Plex/ExtensionMethods.cs
Normal file
6
Plex/ExtensionMethods.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace FileFlows.Plex;
|
||||
|
||||
internal static class ExtensionMethods
|
||||
{
|
||||
public static string? EmptyAsNull(this string str) => str == string.Empty ? null : str;
|
||||
}
|
||||
5
Plex/GlobalUsings.cs
Normal file
5
Plex/GlobalUsings.cs
Normal file
@@ -0,0 +1,5 @@
|
||||
global using System;
|
||||
global using System.Text;
|
||||
global using System.ComponentModel.DataAnnotations;
|
||||
global using FileFlows.Plugin;
|
||||
global using FileFlows.Plugin.Attributes;
|
||||
119
Plex/MediaManagement/PlexUpdater.cs
Normal file
119
Plex/MediaManagement/PlexUpdater.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using FileFlows.Plex.Models;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace FileFlows.Plex.MediaManagement;
|
||||
|
||||
public class PlexUpdater: Node
|
||||
{
|
||||
public override int Inputs => 1;
|
||||
public override int Outputs => 2;
|
||||
public override FlowElementType Type => FlowElementType.Process;
|
||||
public override string Icon => "fas fa-paper-plane";
|
||||
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var settings = args.GetPluginSettings<PluginSettings>();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(settings?.AccessToken))
|
||||
{
|
||||
args.Logger?.WLog("No access token set");
|
||||
return 2;
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(settings?.ServerUrl))
|
||||
{
|
||||
args.Logger?.WLog("No server URL set");
|
||||
return 2;
|
||||
}
|
||||
|
||||
// get the path
|
||||
string path = args.WorkingFile;
|
||||
path = args.UnMapPath(path);
|
||||
if (args.IsDirectory == false)
|
||||
{
|
||||
bool windows = path.StartsWith("\\") || Regex.IsMatch(path, @"^[a-zA-Z]:\\");
|
||||
string pathSeparator = windows ? "\\" : "/";
|
||||
path = path.Substring(0, path.LastIndexOf(pathSeparator));
|
||||
}
|
||||
|
||||
string url = settings.ServerUrl;
|
||||
if (url.EndsWith("/") == false)
|
||||
url += "/";
|
||||
url += "library/sections";
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
var sectionsResponse= GetWebRequest(httpClient, url + "?X-Plex-Token=" + settings.AccessToken);
|
||||
if (sectionsResponse.success == false)
|
||||
{
|
||||
args.Logger?.WLog("Failed to retrieve sections" + (string.IsNullOrWhiteSpace(sectionsResponse.body) ? "" : ": " + sectionsResponse.body));
|
||||
return 2;
|
||||
}
|
||||
|
||||
PlexSections sections;
|
||||
try
|
||||
{
|
||||
var options = new System.Text.Json.JsonSerializerOptions();
|
||||
options.PropertyNameCaseInsensitive = true;
|
||||
sections = System.Text.Json.JsonSerializer.Deserialize<PlexSections>(sectionsResponse.body, options);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
args.Logger?.ELog("Failed deserializing sections json: " + ex.Message);
|
||||
return 2;
|
||||
}
|
||||
string pathLower = path.ToLower();
|
||||
var section = sections?.MediaContainer?.Directory?.Where(x => {
|
||||
if (x.Location?.Any() != true)
|
||||
return false;
|
||||
foreach (var loc in x.Location) {
|
||||
if (loc.Path == null)
|
||||
continue;
|
||||
if (pathLower.StartsWith(loc.Path.ToLower()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}).FirstOrDefault();
|
||||
if(section == null)
|
||||
{
|
||||
args.Logger?.WLog("Failed to find Plex section for path: " + path);
|
||||
return 2;
|
||||
}
|
||||
|
||||
url += $"/{section.Key}/refresh?path={Uri.EscapeDataString(path)}&X-Plex-Token=" + settings.AccessToken;
|
||||
|
||||
var updateResponse = GetWebRequest(httpClient, url);
|
||||
if (updateResponse.success == false)
|
||||
{
|
||||
if(string.IsNullOrWhiteSpace(updateResponse.body) == false)
|
||||
args.Logger.WLog("Failed to update Plex:" + updateResponse.body);
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private Func<HttpClient, string, (bool success, string body)> _GetWebRequest;
|
||||
internal Func<HttpClient, string, (bool success, string body)> GetWebRequest
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_GetWebRequest == null)
|
||||
{
|
||||
_GetWebRequest = (HttpClient client, string url) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
client.DefaultRequestHeaders.Add("Accept", "application/json");
|
||||
var response = client.GetAsync(url).Result;
|
||||
string body = response.Content.ReadAsStringAsync().Result;
|
||||
return (response.IsSuccessStatusCode, body);
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
return (false, ex.Message);
|
||||
}
|
||||
};
|
||||
}
|
||||
return _GetWebRequest;
|
||||
}
|
||||
}
|
||||
}
|
||||
13
Plex/Models/PlexDirectory.cs
Normal file
13
Plex/Models/PlexDirectory.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
namespace FileFlows.Plex.Models;
|
||||
|
||||
internal class PlexDirectory
|
||||
{
|
||||
public string Key { get; set; }
|
||||
public PlexDirectoryLocation[] Location { get; set; }
|
||||
}
|
||||
|
||||
public class PlexDirectoryLocation
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string Path { get; set; }
|
||||
}
|
||||
12
Plex/Models/PlexSections.cs
Normal file
12
Plex/Models/PlexSections.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
namespace FileFlows.Plex.Models;
|
||||
|
||||
internal class PlexSections
|
||||
{
|
||||
public PlexSection MediaContainer { get; set; }
|
||||
}
|
||||
|
||||
internal class PlexSection
|
||||
{
|
||||
public int Size { get; set; }
|
||||
public PlexDirectory[] Directory { get; set; }
|
||||
}
|
||||
BIN
Plex/Plex.csproj
Normal file
BIN
Plex/Plex.csproj
Normal file
Binary file not shown.
25
Plex/Plex.en.json
Normal file
25
Plex/Plex.en.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"Plugins": {
|
||||
"Plex": {
|
||||
"Description": "A plugin that allows you to communicate with Plex.",
|
||||
"Fields": {
|
||||
"ServerUrl": "Server",
|
||||
"ServerUrl-Placeholder": "http://localhost:32400/",
|
||||
"ServerUrl-Help": "The URL of the Plex server",
|
||||
"AccessToken": "Access Token",
|
||||
"AccessToken-Help": "The access token used to communicate with the Plex server.\nhttps://github.com/revenz/Fenrus/wiki/Plex-Token"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Flow": {
|
||||
"Parts": {
|
||||
"PlexUpdater": {
|
||||
"Outputs": {
|
||||
"1": "Plex update request sent",
|
||||
"2": "Plex update request failed to send"
|
||||
},
|
||||
"Description": "Sends a message to a Plex server to update the library."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Plex/Plugin.cs
Normal file
11
Plex/Plugin.cs
Normal file
@@ -0,0 +1,11 @@
|
||||
namespace FileFlows.Plex;
|
||||
|
||||
public class Plugin : FileFlows.Plugin.IPlugin
|
||||
{
|
||||
public string Name => "Plex";
|
||||
public string MinimumVersion => "0.5.2.690";
|
||||
|
||||
public void Init()
|
||||
{
|
||||
}
|
||||
}
|
||||
18
Plex/PluginSettings.cs
Normal file
18
Plex/PluginSettings.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
namespace FileFlows.Plex
|
||||
{
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class PluginSettings:IPluginSettings
|
||||
{
|
||||
[Text(1)]
|
||||
[Required]
|
||||
public string ServerUrl { get; set; }
|
||||
|
||||
[Text(2)]
|
||||
[Required]
|
||||
public string AccessToken { get; set; }
|
||||
}
|
||||
}
|
||||
37
Plex/Tests/PlexTests.cs
Normal file
37
Plex/Tests/PlexTests.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
#if(DEBUG)
|
||||
|
||||
using FileFlows.Plex.Media;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace FileFlows.Plex.Tests;
|
||||
|
||||
[TestClass]
|
||||
public class PlexTests
|
||||
{
|
||||
[TestMethod]
|
||||
public void Plex_Basic()
|
||||
{
|
||||
var args = new NodeParameters(@"/media/movies/The Batman (2022)/The Batman.mkv", new TestLogger(), false, string.Empty);
|
||||
args.GetPluginSettingsJson = (string input) =>
|
||||
{
|
||||
return File.ReadAllText("../../../settings.json");
|
||||
};
|
||||
|
||||
var node = new PlexUpdater();
|
||||
Assert.AreEqual(1, node.Execute(args));
|
||||
}
|
||||
[TestMethod]
|
||||
public void Plex_Fail()
|
||||
{
|
||||
var args = new NodeParameters(@"/media/unknownmovies/The Batman (2022)/The Batman.mkv", new TestLogger(), false, string.Empty);
|
||||
args.GetPluginSettingsJson = (string input) =>
|
||||
{
|
||||
return File.ReadAllText("../../../settings.json");
|
||||
};
|
||||
|
||||
var node = new PlexUpdater();
|
||||
Assert.AreEqual(2, node.Execute(args));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
59
Plex/Tests/TestLogger.cs
Normal file
59
Plex/Tests/TestLogger.cs
Normal file
@@ -0,0 +1,59 @@
|
||||
#if(DEBUG)
|
||||
|
||||
namespace FileFlows.Plex.Tests;
|
||||
|
||||
using FileFlows.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
internal class TestLogger : ILogger
|
||||
{
|
||||
private List<string> Messages = new List<string>();
|
||||
|
||||
public void DLog(params object[] args) => Log("DBUG", args);
|
||||
|
||||
public void ELog(params object[] args) => Log("ERRR", args);
|
||||
|
||||
public void ILog(params object[] args) => Log("INFO", args);
|
||||
|
||||
public void WLog(params object[] args) => Log("WARN", args);
|
||||
private void Log(string type, object[] args)
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
string message = type + " -> " +
|
||||
string.Join(", ", args.Select(x =>
|
||||
x == null ? "null" :
|
||||
x.GetType().IsPrimitive || x is string ? x.ToString() :
|
||||
System.Text.Json.JsonSerializer.Serialize(x)));
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
public bool Contains(string message)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(message))
|
||||
return false;
|
||||
|
||||
string log = string.Join(Environment.NewLine, Messages);
|
||||
return log.Contains(message);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return String.Join(Environment.NewLine, this.Messages.ToArray());
|
||||
}
|
||||
|
||||
public string GetTail(int length = 50)
|
||||
{
|
||||
if (length <= 0)
|
||||
length = 50;
|
||||
if (Messages.Count <= length)
|
||||
return string.Join(Environment.NewLine, Messages);
|
||||
return string.Join(Environment.NewLine, Messages.TakeLast(length));
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -76,4 +76,10 @@ webhooks
|
||||
[webhooktoken]
|
||||
Gotify
|
||||
gotify
|
||||
lan
|
||||
lan
|
||||
Plex
|
||||
Jellyfin
|
||||
Emby
|
||||
revenz
|
||||
Fenrus
|
||||
Plex-Token
|
||||
|
||||
Reference in New Issue
Block a user