mirror of
https://github.com/revenz/FileFlowsPlugins.git
synced 2026-05-06 08:49:25 -05:00
FF-1659: Improved tv show lookups
This commit is contained in:
@@ -8,7 +8,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Apprise</Product>
|
||||
|
||||
@@ -128,10 +128,7 @@ File shrunk in size by: {{ difference | file_size }} / {{ percent }}%
|
||||
type = this.MessageType?.EmptyAsNull() ?? "info"
|
||||
};
|
||||
|
||||
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
var json = JsonSerializer.Serialize(data);
|
||||
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
|
||||
var content = new StringContent(json, Encoding.UTF8, "application/json");
|
||||
|
||||
using var httpClient = new HttpClient();
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Audio</Product>
|
||||
|
||||
@@ -25,13 +25,11 @@ namespace FileFlows.AudioNodes.Tests
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Basic</Product>
|
||||
|
||||
@@ -7,6 +7,9 @@ using FileHelper = FileFlows.Plugin.Helpers.FileHelper;
|
||||
|
||||
namespace BasicNodes.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Local file service
|
||||
/// </summary>
|
||||
public class LocalFileService : IFileService
|
||||
{
|
||||
/// <summary>
|
||||
|
||||
@@ -57,13 +57,11 @@ public class TestLogger : ILogger
|
||||
/// <param name="args">the arguments of the message</param>
|
||||
private void Log(LogType type, params object[] args)
|
||||
{
|
||||
#pragma warning disable IL2026
|
||||
string message = type + " -> " + string.Join(", ", args.Select(x =>
|
||||
x == null ? "null" :
|
||||
x.GetType().IsPrimitive ? x.ToString() :
|
||||
x is string ? x.ToString() :
|
||||
System.Text.Json.JsonSerializer.Serialize(x)));
|
||||
#pragma warning restore IL2026
|
||||
Writer?.Invoke(message);
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||
<FileVersion>1.0.4.189</FileVersion>
|
||||
<ProductVersion>1.0.4.189</ProductVersion>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Checksum</Product>
|
||||
|
||||
@@ -23,13 +23,11 @@ namespace ChecksumNodes.Tests
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
public bool Contains(string message)
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Comic</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Discord</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,11 +6,9 @@
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Email</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ namespace EmailNodes.Tests
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Emby</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -7,7 +7,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Gotify</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<FileVersion>1.0.4.189</FileVersion>
|
||||
<ProductVersion>1.0.4.189</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Image</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
+31
-9
@@ -1,11 +1,33 @@
|
||||
namespace MetaNodes
|
||||
namespace MetaNodes;
|
||||
/// <summary>
|
||||
/// The Global variables used by this plugin
|
||||
/// </summary>
|
||||
internal class Globals
|
||||
{
|
||||
internal class Globals
|
||||
{
|
||||
public static string MOVIE_INFO = "MovieInfo";
|
||||
public static string MOVIE = "Movie";
|
||||
public static string MOVIE_CREDITS = "MovieCredits";
|
||||
public static string TV_SHOW_INFO = "TVShowInfo";
|
||||
public static string TV_EPISODE_INFO = "TVEpisodeInfo";
|
||||
}
|
||||
/// <summary>
|
||||
/// The name fo the Movie Info variable
|
||||
/// </summary>
|
||||
public static string MOVIE_INFO = "MovieInfo";
|
||||
/// <summary>
|
||||
/// The name fo the Movie variable
|
||||
/// </summary>
|
||||
public static string MOVIE = "Movie";
|
||||
/// <summary>
|
||||
/// The name fo the Movie Credits variable
|
||||
/// </summary>
|
||||
public static string MOVIE_CREDITS = "MovieCredits";
|
||||
/// <summary>
|
||||
/// The name fo the TV Show Info variable
|
||||
/// </summary>
|
||||
public static string TV_SHOW_INFO = "TVShowInfo";
|
||||
/// <summary>
|
||||
/// The name fo the TV Episode Info variable
|
||||
/// </summary>
|
||||
public static string TV_EPISODE_INFO = "TVEpisodeInfo";
|
||||
|
||||
/// <summary>
|
||||
/// The token used to query the MovieDB
|
||||
/// </summary>
|
||||
internal const string MovieDbBearerToken = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxZjVlNTAyNmJkMDM4YmZjZmU2MjI2MWU2ZGEwNjM0ZiIsInN1YiI6IjRiYzg4OTJjMDE3YTNjMGY5MjAwMDIyZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.yMwyT8DEK1rF1gQMKJ-ZSy-dUGxFs5T345XwBLrvrWE";
|
||||
|
||||
}
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Meta</Product>
|
||||
|
||||
@@ -1,60 +1,90 @@
|
||||
#if(DEBUG)
|
||||
|
||||
namespace MetaNodes.Tests
|
||||
using FileFlows.Plugin;
|
||||
|
||||
namespace MetaNodes.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// A logger for tests that stores the logs in memory
|
||||
/// </summary>
|
||||
public class TestLogger : ILogger
|
||||
{
|
||||
using FileFlows.Plugin;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
private readonly List<string> Messages = new();
|
||||
|
||||
internal class TestLogger : ILogger
|
||||
/// <summary>
|
||||
/// Writes an information log message
|
||||
/// </summary>
|
||||
/// <param name="args">the log parameters</param>
|
||||
public void ILog(params object[] args)
|
||||
=> Log(LogType.Info, args);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an debug log message
|
||||
/// </summary>
|
||||
/// <param name="args">the log parameters</param>
|
||||
public void DLog(params object[] args)
|
||||
=> Log(LogType.Debug, args);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an warning log message
|
||||
/// </summary>
|
||||
/// <param name="args">the log parameters</param>
|
||||
public void WLog(params object[] args)
|
||||
=> Log(LogType.Warning, args);
|
||||
|
||||
/// <summary>
|
||||
/// Writes an error log message
|
||||
/// </summary>
|
||||
/// <param name="args">the log parameters</param>
|
||||
public void ELog(params object[] args)
|
||||
=> Log(LogType.Error, args);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the tail of the log
|
||||
/// </summary>
|
||||
/// <param name="length">the number of messages to get</param>
|
||||
public string GetTail(int length = 50)
|
||||
{
|
||||
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;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
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 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));
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
=> string.Join(Environment.NewLine, Messages);
|
||||
if (Messages.Count <= length)
|
||||
return string.Join(Environment.NewLine, Messages);
|
||||
return string.Join(Environment.NewLine, Messages.TakeLast(50));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs a message
|
||||
/// </summary>
|
||||
/// <param name="type">the type of log to record</param>
|
||||
/// <param name="args">the arguments of the message</param>
|
||||
private void Log(LogType type, params object[] args)
|
||||
{
|
||||
string message = type + " -> " + string.Join(", ", args.Select(x =>
|
||||
x == null ? "null" :
|
||||
x.GetType().IsPrimitive ? x.ToString() :
|
||||
x is string ? x.ToString() :
|
||||
System.Text.Json.JsonSerializer.Serialize(x)));
|
||||
Writer?.Invoke(message);
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets an optional writer
|
||||
/// </summary>
|
||||
public Action<string> Writer { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the entire log as a string
|
||||
/// </summary>
|
||||
/// <returns>the entire log</returns>
|
||||
public override string ToString()
|
||||
=> string.Join(Environment.NewLine, Messages);
|
||||
|
||||
/// <summary>
|
||||
/// Checks if the log contains the text
|
||||
/// </summary>
|
||||
/// <param name="text">the text to check for</param>
|
||||
/// <returns>true if it contains it, otherwise false</returns>
|
||||
public bool Contains(string text)
|
||||
=> Messages.Any(x => x.Contains(text));
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
#if(DEBUG)
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using DM.MovieApi;
|
||||
using DM.MovieApi.MovieDb.Movies;
|
||||
using FileFlows.Plugin;
|
||||
@@ -9,12 +10,12 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
namespace MetaNodes.Tests.TheMovieDb;
|
||||
|
||||
[TestClass]
|
||||
public class MovieLookupTests
|
||||
public class MovieLookupTests : TestBase
|
||||
{
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_File_Ghostbusters()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Ghostbusters 1984.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Ghostbusters 1984.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
@@ -33,7 +34,7 @@ public class MovieLookupTests
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_File_Ghostbusters2()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Ghostbusters 2.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Ghostbusters 2.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
@@ -52,7 +53,7 @@ public class MovieLookupTests
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_File_WithDots()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Back.To.The.Future.2.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Back.To.The.Future.2.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
@@ -71,7 +72,7 @@ public class MovieLookupTests
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_File_WithYear()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Back.To.The.Future.1989.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Back.To.The.Future.1989.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
@@ -83,14 +84,14 @@ public class MovieLookupTests
|
||||
var mi = args.Parameters[Globals.MOVIE_INFO] as MovieInfo;
|
||||
Assert.IsNotNull(mi);
|
||||
|
||||
Assert.AreEqual("Back to the Future Part II", mi.Title);
|
||||
Assert.AreEqual("Back to the Future Part II", mi.Title.Replace("(", "").Replace(")", ""));
|
||||
Assert.AreEqual(1989, mi.ReleaseDate.Year);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_Folder_WithYear()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Back To The Future (1989)/Jaws.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Back To The Future (1989)/Jaws.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = true;
|
||||
@@ -109,7 +110,7 @@ public class MovieLookupTests
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_VariablesSet()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Back To The Future (1989)/Jaws.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Back To The Future (1989)/Jaws.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = true;
|
||||
@@ -125,7 +126,7 @@ public class MovieLookupTests
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_NoMatchNoVariables()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/sdfsdfdsvfdcxdsf.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("sdfsdfdsvfdcxdsf.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
@@ -139,10 +140,8 @@ public class MovieLookupTests
|
||||
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_ComplexFile()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}/Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv", logger, false, string.Empty, null);
|
||||
string log = logger.ToString();
|
||||
{
|
||||
var args = GetNodeParameters("Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}/Constantine.2005.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
@@ -161,7 +160,7 @@ public class MovieLookupTests
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_WonderWoman()
|
||||
{
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}/Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}/Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
@@ -178,28 +177,25 @@ public class MovieLookupTests
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
[RequiresUnreferencedCode("")]
|
||||
public void MovieLookupTests_File_TheBatman_Metadata()
|
||||
{
|
||||
MovieDbFactory.RegisterSettings(MovieLookup.MovieDbBearerToken);
|
||||
MovieDbFactory.RegisterSettings(Globals.MovieDbBearerToken);
|
||||
var movieApi = MovieDbFactory.Create<IApiMovieRequest>().Value;
|
||||
var args = new FileFlows.Plugin.NodeParameters(@"/test/Ghostbusters 1984.mkv", new TestLogger(), false, string.Empty, null);;
|
||||
var args = GetNodeParameters("Ghostbusters 1984.mkv");
|
||||
|
||||
var md = MovieLookup.GetVideoMetadata(args, movieApi, 414906, @"D:\videos\temp");
|
||||
Assert.IsNotNull(md);
|
||||
#pragma warning disable IL2026
|
||||
string json = System.Text.Json.JsonSerializer.Serialize(md, new System.Text.Json.JsonSerializerOptions
|
||||
{
|
||||
WriteIndented = true
|
||||
});
|
||||
#pragma warning restore IL2026
|
||||
File.WriteAllText(@"D:\videos\metadata.json", json);
|
||||
}
|
||||
[TestMethod]
|
||||
public void MovieLookupTests_WonderWoman_Nfo()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new NodeParameters(@"/test/Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}/Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv",
|
||||
logger, false, string.Empty, null);;
|
||||
var args = GetNodeParameters(@"Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}/Wonder.Woman.1984.2020.German.DL.AC3.1080p.BluRay.x265-Fun{{fdg$ERGESDG32fesdfgds}}.mkv");
|
||||
|
||||
MovieLookup ml = new MovieLookup();
|
||||
ml.UseFolderName = false;
|
||||
|
||||
@@ -3,33 +3,20 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using DM.MovieApi.MovieDb.Movies;
|
||||
using DM.MovieApi.MovieDb.TV;
|
||||
using FileFlows.Plugin;
|
||||
using MetaNodes.TheMovieDb;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace MetaNodes.Tests.TheMovieDb;
|
||||
|
||||
[TestClass]
|
||||
public class TVEpisodeLookupTests
|
||||
public class TVEpisodeLookupTests : TestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The test context instance
|
||||
/// </summary>
|
||||
private TestContext testContextInstance;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the test context
|
||||
/// </summary>
|
||||
public TestContext TestContext
|
||||
{
|
||||
get { return testContextInstance; }
|
||||
set { testContextInstance = value; }
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TheBatman_s02e01()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 2/The Batman.s02e01.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 2/The Batman.s02e01.mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
@@ -46,8 +33,7 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void TheBatman_2x03()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 2/The Batman - 2x03.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 2/The Batman - 2x03.mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
@@ -64,13 +50,11 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void WithYear()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/Paradise PD (2018) - S04E04 - Good Jeans (1080p NF WEB-DL x265 t3nzin).mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("Paradise PD (2018) - S04E04 - Good Jeans (1080p NF WEB-DL x265 t3nzin).mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
var result = element.Execute(args);
|
||||
TestContext.WriteLine(logger.ToString());
|
||||
|
||||
Assert.AreEqual(1, result);
|
||||
|
||||
@@ -86,8 +70,7 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void TheBatman_3x01_2()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 3/The Batman - 3x01-2.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 3/The Batman - 3x01-2.mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
@@ -105,8 +88,7 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void TheBatman_s4e12_13()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 4/The Batman - s4e12-13.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 4/The Batman - s4e12-13.mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
@@ -124,8 +106,7 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void TheBatman_s5e1_2_3()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 5/The Batman - s5e1-3.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 5/The Batman - s5e1-3.mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
@@ -145,8 +126,7 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void TheBatman_2x03_nfo()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 2/The Batman - 2x03.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 2/The Batman - 2x03.mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
@@ -166,8 +146,7 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void TheBatman_s5e1_2_3_Nfo()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 5/The Batman - s5e1-3.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 5/The Batman - s5e1-3.mkv");
|
||||
|
||||
var element = new TVEpisodeLookup();
|
||||
|
||||
@@ -184,7 +163,6 @@ public class TVEpisodeLookupTests
|
||||
[TestMethod]
|
||||
public void VariousTests()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
foreach (var test in new TVLookupTestData[]
|
||||
{
|
||||
new("See",
|
||||
@@ -204,7 +182,7 @@ public class TVEpisodeLookupTests
|
||||
(string lookupName, string year) = TVShowLookup.GetLookupName(test.Path, true);
|
||||
Assert.AreEqual(test.Show, lookupName);
|
||||
//
|
||||
// var args = new FileFlows.Plugin.NodeParameters(test.Path, logger, false, string.Empty, null);
|
||||
// var args = GetNodeParameters(test.Path);
|
||||
//
|
||||
// var element = new TVEpisodeLookup();
|
||||
//
|
||||
|
||||
@@ -8,13 +8,12 @@ using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
namespace MetaNodes.Tests.TheMovieDb;
|
||||
|
||||
[TestClass]
|
||||
public class TVShowLookupTests
|
||||
public class TVShowLookupTests : TestBase
|
||||
{
|
||||
[TestMethod]
|
||||
public void TheBatman_Filename()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 2/The Batman.s02e01.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 2/The Batman.s02e01.mkv");
|
||||
|
||||
var element = new TVShowLookup();
|
||||
element.UseFolderName = false;
|
||||
@@ -33,12 +32,32 @@ public class TVShowLookupTests
|
||||
Assert.AreEqual(2004, args.Variables["tvshow.Year"]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void YearInFilename()
|
||||
{
|
||||
var args = GetNodeParameters("TestFolder/Eric.2024.S01.01.mkv");
|
||||
|
||||
var element = new TVShowLookup();
|
||||
element.UseFolderName = false;
|
||||
|
||||
var result = element.Execute(args);
|
||||
Assert.AreEqual(1, result);
|
||||
Assert.IsTrue(args.Parameters.ContainsKey(Globals.TV_SHOW_INFO));
|
||||
|
||||
var info = args.Parameters[Globals.TV_SHOW_INFO] as TVShowInfo;
|
||||
Assert.IsNotNull(info);
|
||||
|
||||
Assert.AreEqual("Eric", info.Name);
|
||||
Assert.AreEqual(2024, info.FirstAirDate.Year);
|
||||
Assert.AreEqual("en", info.OriginalLanguage);
|
||||
Assert.AreEqual("Eric", args.Variables["tvshow.Title"]);
|
||||
Assert.AreEqual(2024, args.Variables["tvshow.Year"]);
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void TvdbID_Test()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/media/TV/The Walking Dead (2010) [tvdbid-153021]/Season 07/S07E03 - The Cell [HDTV-1080p][AAC 5.1][h265].mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Walking Dead (2010) [tvdbid-153021]/Season 07/S07E03 - The Cell [HDTV-1080p][AAC 5.1][h265].mkv");
|
||||
|
||||
var element = new TVShowLookup();
|
||||
element.UseFolderName = true;
|
||||
@@ -60,8 +79,7 @@ public class TVShowLookupTests
|
||||
[TestMethod]
|
||||
public void TheBatman_Folder()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/The Batman/Season 2/The Batman.s02e01.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("The Batman/Season 2/The Batman.s02e01.mkv");
|
||||
|
||||
var element = new TVShowLookup();
|
||||
element.UseFolderName = true;
|
||||
@@ -83,8 +101,7 @@ public class TVShowLookupTests
|
||||
[TestMethod]
|
||||
public void SquidGame_Filename()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/Squid Game/Season 1/Squid.Game.1x01-02.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("Squid Game/Season 1/Squid.Game.1x01-02.mkv");
|
||||
|
||||
var element = new TVShowLookup();
|
||||
element.UseFolderName = false;
|
||||
@@ -106,8 +123,7 @@ public class TVShowLookupTests
|
||||
[TestMethod]
|
||||
public void SquidGame_Folder()
|
||||
{
|
||||
var logger = new TestLogger();
|
||||
var args = new FileFlows.Plugin.NodeParameters("/test/tv/Squid Game/Season 1/Squid.Game.1x01-02.mkv", logger, false, string.Empty, null);
|
||||
var args = GetNodeParameters("Squid Game/Season 1/Squid.Game.1x01-02.mkv");
|
||||
|
||||
var element = new TVShowLookup();
|
||||
element.UseFolderName = true;
|
||||
|
||||
@@ -0,0 +1,473 @@
|
||||
#if(DEBUG)
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Models;
|
||||
using FileFlows.Plugin.Services;
|
||||
using System.IO;
|
||||
using FileHelper = FileFlows.Plugin.Helpers.FileHelper;
|
||||
|
||||
namespace MetaNodes.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Local file service
|
||||
/// </summary>
|
||||
public class LocalFileService : IFileService
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the path separator for the file system
|
||||
/// </summary>
|
||||
public char PathSeparator { get; init; } = Path.DirectorySeparatorChar;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the allowed paths the file service can access
|
||||
/// </summary>
|
||||
public string[] AllowedPaths { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a function for replacing variables in a string.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// The function takes a string input, a boolean indicating whether to strip missing variables,
|
||||
/// and a boolean indicating whether to clean special characters.
|
||||
/// </remarks>
|
||||
public ReplaceVariablesDelegate ReplaceVariables { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the permissions to use for files
|
||||
/// </summary>
|
||||
public int? Permissions { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the owner:group to use for files
|
||||
/// </summary>
|
||||
public string OwnerGroup { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the logger used for logging
|
||||
/// </summary>
|
||||
public ILogger? Logger { get; set; }
|
||||
|
||||
public Result<string[]> GetFiles(string path, string searchPattern = "", bool recursive = false)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<string[]>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
return Directory.GetFiles(path, searchPattern ?? string.Empty,
|
||||
recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
public Result<string[]> GetDirectories(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<string[]>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
return Directory.GetDirectories(path);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return new string[] { };
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> DirectoryExists(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
return Directory.Exists(path);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> DirectoryDelete(string path, bool recursive = false)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
Directory.Delete(path, recursive);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> DirectoryMove(string path, string destination)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
if (IsProtectedPath(ref destination))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + destination);
|
||||
try
|
||||
{
|
||||
Directory.Move(path, destination);
|
||||
SetPermissions(destination);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> DirectoryCreate(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
var dirInfo = new DirectoryInfo(path);
|
||||
if (dirInfo.Exists == false)
|
||||
dirInfo.Create();
|
||||
SetPermissions(path);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> FileExists(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
return System.IO.File.Exists(path);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Result<FileInformation> FileInfo(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<FileInformation>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
FileInfo fileInfo = new FileInfo(path);
|
||||
|
||||
return new FileInformation
|
||||
{
|
||||
CreationTime = fileInfo.CreationTime,
|
||||
CreationTimeUtc = fileInfo.CreationTimeUtc,
|
||||
LastWriteTime = fileInfo.LastWriteTime,
|
||||
LastWriteTimeUtc = fileInfo.LastWriteTimeUtc,
|
||||
Extension = fileInfo.Extension.TrimStart('.'),
|
||||
Name = fileInfo.Name,
|
||||
FullName = fileInfo.FullName,
|
||||
Length = fileInfo.Length,
|
||||
Directory = fileInfo.DirectoryName
|
||||
};
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<FileInformation>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> FileDelete(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
if(fileInfo.Exists)
|
||||
fileInfo.Delete();
|
||||
return true;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public Result<long> FileSize(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<long>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
if (fileInfo.Exists == false)
|
||||
return Result<long>.Fail("File does not exist");
|
||||
return fileInfo.Length;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<long>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<DateTime> FileCreationTimeUtc(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<DateTime>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
if (fileInfo.Exists == false)
|
||||
return Result<DateTime>.Fail("File does not exist");
|
||||
return fileInfo.CreationTimeUtc;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<DateTime>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<DateTime> FileLastWriteTimeUtc(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<DateTime>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
if (fileInfo.Exists == false)
|
||||
return Result<DateTime>.Fail("File does not exist");
|
||||
return fileInfo.LastWriteTimeUtc;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<DateTime>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> FileMove(string path, string destination, bool overwrite = true)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
if (IsProtectedPath(ref destination))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + destination);
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
if (fileInfo.Exists == false)
|
||||
return Result<bool>.Fail("File does not exist");
|
||||
var destDir = new FileInfo(destination).Directory;
|
||||
if (destDir.Exists == false)
|
||||
{
|
||||
destDir.Create();
|
||||
SetPermissions(destDir.FullName);
|
||||
}
|
||||
|
||||
fileInfo.MoveTo(destination, overwrite);
|
||||
SetPermissions(destination);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> FileCopy(string path, string destination, bool overwrite = true)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
if (IsProtectedPath(ref destination))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + destination);
|
||||
try
|
||||
{
|
||||
var fileInfo = new FileInfo(path);
|
||||
if (fileInfo.Exists == false)
|
||||
return Result<bool>.Fail("File does not exist");
|
||||
|
||||
var destDir = new FileInfo(destination).Directory;
|
||||
if (destDir.Exists == false)
|
||||
{
|
||||
destDir.Create();
|
||||
SetPermissions(destDir.FullName);
|
||||
}
|
||||
|
||||
fileInfo.CopyTo(destination, overwrite);
|
||||
SetPermissions(destination);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> FileAppendAllText(string path, string text)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
System.IO.File.AppendAllText(path, text);
|
||||
SetPermissions(path);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail(ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public bool FileIsLocal(string path) => true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the local path
|
||||
/// </summary>
|
||||
/// <param name="path">the path</param>
|
||||
/// <returns>the local path to the file</returns>
|
||||
public Result<string> GetLocalPath(string path)
|
||||
=> Result<string>.Success(path);
|
||||
|
||||
public Result<bool> Touch(string path)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
|
||||
if (DirectoryExists(path).Is(true))
|
||||
{
|
||||
try
|
||||
{
|
||||
Directory.SetLastWriteTimeUtc(path, DateTime.UtcNow);
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail("Failed to touch directory: " + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (System.IO.File.Exists(path))
|
||||
System.IO.File.SetLastWriteTimeUtc(path, DateTime.UtcNow);
|
||||
else
|
||||
{
|
||||
System.IO.File.Create(path);
|
||||
SetPermissions(path);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail($"Failed to touch file: '{path}' => {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public Result<long> DirectorySize(string path)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public Result<bool> SetCreationTimeUtc(string path, DateTime date)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
if (!System.IO.File.Exists(path))
|
||||
return Result<bool>.Fail("File not found.");
|
||||
|
||||
System.IO.File.SetCreationTimeUtc(path, date);
|
||||
return Result<bool>.Success(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail($"Error setting creation time: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
public Result<bool> SetLastWriteTimeUtc(string path, DateTime date)
|
||||
{
|
||||
if (IsProtectedPath(ref path))
|
||||
return Result<bool>.Fail("Cannot access protected path: " + path);
|
||||
try
|
||||
{
|
||||
if (!System.IO.File.Exists(path))
|
||||
return Result<bool>.Fail("File not found.");
|
||||
|
||||
System.IO.File.SetLastWriteTimeUtc(path, date);
|
||||
return Result<bool>.Success(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return Result<bool>.Fail($"Error setting last write time: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a path is accessible by the file server
|
||||
/// </summary>
|
||||
/// <param name="path">the path to check</param>
|
||||
/// <returns>true if accessible, otherwise false</returns>
|
||||
private bool IsProtectedPath(ref string path)
|
||||
{
|
||||
if (OperatingSystem.IsWindows())
|
||||
path = path.Replace("/", "\\");
|
||||
else
|
||||
path = path.Replace("\\", "/");
|
||||
|
||||
if(ReplaceVariables != null)
|
||||
path = ReplaceVariables(path, true);
|
||||
|
||||
if (FileHelper.IsSystemDirectory(path))
|
||||
return true; // a system directory, no access
|
||||
|
||||
if (AllowedPaths?.Any() != true)
|
||||
return false; // no allowed paths configured, allow all
|
||||
|
||||
if (OperatingSystem.IsWindows())
|
||||
path = path.ToLowerInvariant();
|
||||
|
||||
for(int i=0;i<AllowedPaths.Length;i++)
|
||||
{
|
||||
string p = OperatingSystem.IsWindows() ? AllowedPaths[i].ToLowerInvariant().TrimEnd('\\') : AllowedPaths[i].TrimEnd('/');
|
||||
if (path.StartsWith(p))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void SetPermissions(string path, int? permissions = null, Action<string> logMethod = null)
|
||||
{
|
||||
logMethod ??= (string message) => Logger?.ILog(message);
|
||||
|
||||
permissions = permissions != null && permissions > 0 ? permissions : Permissions;
|
||||
if (permissions == null || permissions < 1)
|
||||
permissions = 777;
|
||||
|
||||
|
||||
if ((System.IO.File.Exists(path) == false && Directory.Exists(path) == false))
|
||||
{
|
||||
logMethod("SetPermissions: File doesnt existing, skipping");
|
||||
return;
|
||||
}
|
||||
|
||||
//StringLogger stringLogger = new StringLogger();
|
||||
var logger = new TestLogger();
|
||||
|
||||
bool isFile = new FileInfo(path).Exists;
|
||||
|
||||
FileHelper.SetPermissions(logger, path, file: isFile, permissions: permissions);
|
||||
|
||||
FileHelper.ChangeOwner(logger, path, file: isFile, ownerGroup: OwnerGroup);
|
||||
|
||||
logMethod(logger.ToString());
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,78 @@
|
||||
#if(DEBUG)
|
||||
|
||||
using System.Runtime.InteropServices;
|
||||
using FileFlows.Plugin;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
|
||||
namespace MetaNodes.Tests;
|
||||
|
||||
/// <summary>
|
||||
/// Base class for the tests
|
||||
/// </summary>
|
||||
[TestClass]
|
||||
public abstract class TestBase
|
||||
{
|
||||
/// <summary>
|
||||
/// The test context instance
|
||||
/// </summary>
|
||||
private TestContext testContextInstance;
|
||||
|
||||
internal TestLogger Logger = new();
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the test context
|
||||
/// </summary>
|
||||
public TestContext TestContext
|
||||
{
|
||||
get => testContextInstance;
|
||||
set => testContextInstance = value;
|
||||
}
|
||||
|
||||
public string TestPath { get; private set; }
|
||||
public string TempPath { get; private set; }
|
||||
|
||||
public readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
|
||||
public readonly bool IsLinux = RuntimeInformation.IsOSPlatform(OSPlatform.Linux);
|
||||
|
||||
[TestInitialize]
|
||||
public void TestInitialize()
|
||||
{
|
||||
Logger.Writer = (msg) => TestContext.WriteLine(msg);
|
||||
|
||||
this.TestPath = this.TestPath?.EmptyAsNull() ?? (IsLinux ? "~/src/ff-files/test-files/videos" : @"d:\videos\testfiles");
|
||||
this.TempPath = this.TempPath?.EmptyAsNull() ?? (IsLinux ? "~/src/ff-files/temp" : @"d:\videos\temp");
|
||||
|
||||
this.TestPath = this.TestPath.Replace("~/", Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/");
|
||||
this.TempPath = this.TempPath.Replace("~/", Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) + "/");
|
||||
|
||||
if (Directory.Exists(this.TempPath) == false)
|
||||
Directory.CreateDirectory(this.TempPath);
|
||||
}
|
||||
|
||||
[TestCleanup]
|
||||
public void CleanUp()
|
||||
{
|
||||
TestContext.WriteLine(Logger.ToString());
|
||||
}
|
||||
|
||||
protected virtual void TestStarting()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
protected NodeParameters GetNodeParameters(string filename)
|
||||
{
|
||||
string tempPath = Path.GetTempPath();
|
||||
string libPath = Path.Combine(tempPath, "media");
|
||||
if (Directory.Exists(libPath) == false)
|
||||
Directory.CreateDirectory(libPath);
|
||||
return new(filename, Logger, false, libPath, new LocalFileService())
|
||||
{
|
||||
LibraryFileName = filename,
|
||||
TempPath = tempPath
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,9 +1,9 @@
|
||||
using System.Text.RegularExpressions;
|
||||
using DM.MovieApi;
|
||||
using DM.MovieApi.ApiResponse;
|
||||
using DM.MovieApi.MovieDb.Movies;
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using FileHelper = FileFlows.Plugin.Helpers.FileHelper;
|
||||
|
||||
namespace MetaNodes.TheMovieDb;
|
||||
|
||||
@@ -51,9 +51,6 @@ public class MovieLookup : Node
|
||||
{ "movie.Year", 2005 }
|
||||
};
|
||||
}
|
||||
|
||||
internal const string MovieDbBearerToken = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxZjVlNTAyNmJkMDM4YmZjZmU2MjI2MWU2ZGEwNjM0ZiIsInN1YiI6IjRiYzg4OTJjMDE3YTNjMGY5MjAwMDIyZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.yMwyT8DEK1rF1gQMKJ-ZSy-dUGxFs5T345XwBLrvrWE";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the folder name should be used
|
||||
/// </summary>
|
||||
@@ -67,8 +64,7 @@ public class MovieLookup : Node
|
||||
/// <returns>the output to call next</returns>
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
var fileInfo = new FileInfo(args.FileName);
|
||||
string lookupName = UseFolderName ? fileInfo.Directory.Name : fileInfo.Name.Substring(0, fileInfo.Name.LastIndexOf(fileInfo.Extension));
|
||||
string lookupName = UseFolderName ? FileHelper.GetDirectoryName(args.LibraryFileName) : FileHelper.GetShortFileNameWithoutExtension(args.LibraryFileName);
|
||||
lookupName = lookupName.Replace(".", " ").Replace("_", " ");
|
||||
|
||||
// look for year
|
||||
@@ -77,25 +73,27 @@ public class MovieLookup : Node
|
||||
if (match != null)
|
||||
{
|
||||
year = match.Value;
|
||||
lookupName = lookupName.Substring(0, lookupName.IndexOf(year)).Trim();
|
||||
lookupName = lookupName[..lookupName.IndexOf(year, StringComparison.Ordinal)].TrimEnd('(');
|
||||
}
|
||||
|
||||
// remove double spaces in case they were added when removing the year
|
||||
while (lookupName.IndexOf(" ", StringComparison.Ordinal) > 0)
|
||||
lookupName = lookupName.Replace(" ", " ");
|
||||
|
||||
lookupName = lookupName.TrimEnd('(', '-');
|
||||
|
||||
args.Logger?.ILog("Lookup name: " + lookupName);
|
||||
|
||||
// RegisterSettings only needs to be called one time when your application starts-up.
|
||||
MovieDbFactory.RegisterSettings(MovieDbBearerToken);
|
||||
MovieDbFactory.RegisterSettings(Globals.MovieDbBearerToken);
|
||||
|
||||
var movieApi = MovieDbFactory.Create<IApiMovieRequest>().Value;
|
||||
|
||||
ApiSearchResponse<MovieInfo> response = movieApi.SearchByTitleAsync(lookupName).Result;
|
||||
var response = movieApi.SearchByTitleAsync(lookupName).Result;
|
||||
|
||||
|
||||
// try find an exact match
|
||||
var result = response.Results.OrderBy(x =>
|
||||
var results = response.Results.OrderBy(x =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(year) == false)
|
||||
{
|
||||
@@ -128,7 +126,7 @@ public class MovieLookup : Node
|
||||
13 => "xiii",
|
||||
_ => string.Empty
|
||||
};
|
||||
string ln = lookupName.Substring(0, lookupName.LastIndexOf(number.ToString())).ToLower().Trim().Replace(" ", "");
|
||||
string ln = lookupName[..lookupName.LastIndexOf(number.ToString(), StringComparison.Ordinal)].ToLower().Trim().Replace(" ", "");
|
||||
string softTitle = x.Title.ToLower().Replace(" ", "").Trim();
|
||||
if (softTitle == ln + roman)
|
||||
return 0;
|
||||
@@ -137,8 +135,9 @@ public class MovieLookup : Node
|
||||
return 1;
|
||||
})
|
||||
.ThenBy(x => lookupName.ToLower().Trim().Replace(" ", "").StartsWith(x.Title.ToLower().Trim().Replace(" ", "")) ? 0 : 1)
|
||||
.ThenBy(x => x.Title)
|
||||
.FirstOrDefault();
|
||||
// .ThenBy(x => x.Title)
|
||||
.ToList();
|
||||
var result = results.FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
return 2; // no match
|
||||
@@ -165,7 +164,6 @@ public class MovieLookup : Node
|
||||
|
||||
args.UpdateVariables(Variables);
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -205,7 +203,7 @@ public class MovieLookup : Node
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -126,6 +126,7 @@ public class NfoFileCreator : Node
|
||||
if (args.FileService.FileMove(tempFile, output).Failed(out string error))
|
||||
{
|
||||
args.FailureReason = error;
|
||||
args.Logger?.ELog(error);
|
||||
return -1;
|
||||
}
|
||||
args.Logger.ILog("NFO File Created at: " + output);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
using DM.MovieApi.MovieDb.TV;
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using Microsoft.VisualStudio.TestPlatform.Utilities.Helpers;
|
||||
using FileHelper = FileFlows.Plugin.Helpers.FileHelper;
|
||||
|
||||
namespace MetaNodes.TheMovieDb;
|
||||
|
||||
@@ -61,9 +63,7 @@ public class TVEpisodeLookup : Node
|
||||
{ "tvepisode.Overview", "Joker makes Batman laugh" },
|
||||
};
|
||||
}
|
||||
|
||||
internal const string MovieDbBearerToken = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxZjVlNTAyNmJkMDM4YmZjZmU2MjI2MWU2ZGEwNjM0ZiIsInN1YiI6IjRiYzg4OTJjMDE3YTNjMGY5MjAwMDIyZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.yMwyT8DEK1rF1gQMKJ-ZSy-dUGxFs5T345XwBLrvrWE";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Executes the flow element
|
||||
/// </summary>
|
||||
@@ -71,11 +71,9 @@ public class TVEpisodeLookup : Node
|
||||
/// <returns>the output to call next</returns>
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
string filename = args.FileName.Replace("\\", "/");
|
||||
filename = filename[(filename.LastIndexOf("/", StringComparison.Ordinal) + 1)..];
|
||||
filename = filename[..filename.LastIndexOf(".", StringComparison.Ordinal)];
|
||||
string filename = FileHelper.GetShortFileNameWithoutExtension(args.LibraryFileName);
|
||||
|
||||
(string lookupName, string year) = TVShowLookup.GetLookupName(filename, UseFolderName);
|
||||
(string lookupName, string year) = TVShowLookup.GetLookupName(args.LibraryFileName, UseFolderName);
|
||||
|
||||
(string showName, int? season, int? episode, int? lastEpisode, string year2) = TVShowLookup.GetTVShowInfo(filename);
|
||||
|
||||
@@ -94,7 +92,7 @@ public class TVEpisodeLookup : Node
|
||||
args.Logger?.ILog($"Found show info from filename '{lookupName}' season '{season}' episode '{(episode + (lastEpisode == null ? "" : "-" + lastEpisode))}'");
|
||||
|
||||
// RegisterSettings only needs to be called one time when your application starts-up.
|
||||
MovieDbFactory.RegisterSettings(MovieDbBearerToken);
|
||||
MovieDbFactory.RegisterSettings(Globals.MovieDbBearerToken);
|
||||
|
||||
var movieApi = MovieDbFactory.Create<IApiTVShowRequest>().Value;
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ using DM.MovieApi.MovieDb.Movies;
|
||||
using DM.MovieApi.MovieDb.TV;
|
||||
using FileFlows.Plugin;
|
||||
using FileFlows.Plugin.Attributes;
|
||||
using FileFlows.Plugin.Helpers;
|
||||
|
||||
namespace MetaNodes.TheMovieDb;
|
||||
|
||||
@@ -52,9 +53,7 @@ public class TVShowLookup : Node
|
||||
{ "tvshow.Year", 2004 }
|
||||
};
|
||||
}
|
||||
|
||||
internal const string MovieDbBearerToken = "eyJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxZjVlNTAyNmJkMDM4YmZjZmU2MjI2MWU2ZGEwNjM0ZiIsInN1YiI6IjRiYzg4OTJjMDE3YTNjMGY5MjAwMDIyZCIsInNjb3BlcyI6WyJhcGlfcmVhZCJdLCJ2ZXJzaW9uIjoxfQ.yMwyT8DEK1rF1gQMKJ-ZSy-dUGxFs5T345XwBLrvrWE";
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets if the folder name should be used
|
||||
/// </summary>
|
||||
@@ -68,10 +67,10 @@ public class TVShowLookup : Node
|
||||
/// <returns>the output to call next</returns>
|
||||
public override int Execute(NodeParameters args)
|
||||
{
|
||||
(string lookupName, string year) = GetLookupName(args.FileName, UseFolderName);
|
||||
(string lookupName, string year) = GetLookupName(args.LibraryFileName, UseFolderName);
|
||||
|
||||
// RegisterSettings only needs to be called one time when your application starts-up.
|
||||
MovieDbFactory.RegisterSettings(MovieDbBearerToken);
|
||||
MovieDbFactory.RegisterSettings(Globals.MovieDbBearerToken);
|
||||
|
||||
var movieApi = MovieDbFactory.Create<IApiTVShowRequest>().Value;
|
||||
|
||||
@@ -81,18 +80,26 @@ public class TVShowLookup : Node
|
||||
|
||||
|
||||
// try find an exact match
|
||||
var result = response.Results.OrderBy(x =>
|
||||
var results = response.Results.OrderByDescending(x =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(year) == false)
|
||||
{
|
||||
return year == x.FirstAirDate.Year.ToString() ? 0 : 1;
|
||||
if(year == x.FirstAirDate.Year.ToString())
|
||||
return 2;
|
||||
// sometimes the user may have hte date off by one, or the app may have
|
||||
if(year == (x.FirstAirDate.Year - 1).ToString())
|
||||
return 1;
|
||||
if(year == (x.FirstAirDate.Year + 1).ToString())
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
})
|
||||
.ThenBy(x => x.Name.ToLower().Trim().Replace(" ", "") == lookupName.ToLower().Trim().Replace(" ", "") ? 0 : 1)
|
||||
.ThenBy(x => lookupName.ToLower().Trim().Replace(" ", "").StartsWith(x.Name.ToLower().Trim().Replace(" ", "")) ? 0 : 1)
|
||||
.ThenBy(x => x.Name)
|
||||
.FirstOrDefault();
|
||||
// .ThenBy(x => x.Name)
|
||||
.ToList();
|
||||
var result = results.FirstOrDefault();
|
||||
|
||||
if (result == null)
|
||||
{
|
||||
@@ -122,17 +129,16 @@ public class TVShowLookup : Node
|
||||
|
||||
internal static (string? LookupName, string? Year) GetLookupName(string filename, bool useFolderName)
|
||||
{
|
||||
var fileInfo = new FileInfo(filename);
|
||||
string lookupName;
|
||||
if (useFolderName)
|
||||
{
|
||||
lookupName = fileInfo.Directory.Name;
|
||||
lookupName = FileHelper.GetDirectoryName(filename);
|
||||
if (Regex.IsMatch(lookupName, "^(Season|Staffel|Saison|Specials)", RegexOptions.IgnoreCase))
|
||||
lookupName = fileInfo.Directory.Parent.Name;
|
||||
lookupName = FileHelper.GetDirectoryName(FileHelper.GetDirectory(filename));
|
||||
}
|
||||
else
|
||||
{
|
||||
lookupName = fileInfo.Name[..fileInfo.Name.LastIndexOf(fileInfo.Extension, StringComparison.Ordinal)];
|
||||
lookupName = FileHelper.GetShortFileNameWithoutExtension(filename);
|
||||
}
|
||||
|
||||
var result = GetTVShowInfo(lookupName);
|
||||
@@ -189,16 +195,20 @@ public class TVShowLookup : Node
|
||||
{
|
||||
// Replace "1x02" format with "s1e02"
|
||||
text = Regex.Replace(text, @"(?<season>\d+)x(?<episode>\d+)", "s${season}e${episode}", RegexOptions.IgnoreCase);
|
||||
// Replace "s01.02" with "s01e02"
|
||||
text = Regex.Replace(text, @"(?<season>s\d+)\.(?<episode>\d+)", "${season}e${episode}", RegexOptions.IgnoreCase);
|
||||
|
||||
string year = null;
|
||||
var reYear = Regex.Match(text, @"\((19|20)[\d]{2}\)", RegexOptions.CultureInvariant);
|
||||
if (reYear.Success)
|
||||
{
|
||||
year = reYear.Value;
|
||||
text = text.Replace(year, string.Empty);
|
||||
year = year[1..^1]; // remove the ()
|
||||
}
|
||||
|
||||
// string year = null;
|
||||
// var reYear = Regex.Match(text, @"\((19|20)[\d]{2}\)", RegexOptions.CultureInvariant);
|
||||
// if (reYear.Success)
|
||||
// {
|
||||
// year = reYear.Value;
|
||||
// text = text.Replace(year, string.Empty);
|
||||
// year = year[1..^1]; // remove the ()
|
||||
// }
|
||||
(text, var year) = ExtractYearAndCleanText(text);
|
||||
|
||||
|
||||
string pattern = @"^(?<showName>[\w\s.-]+)[. _-]?(?:(s|S)(?<season>\d+)(e|E)(?<episode>\d+)(?:-(?<lastEpisode>\d+))?)";
|
||||
|
||||
Match match = Regex.Match(text, pattern);
|
||||
@@ -220,4 +230,56 @@ public class TVShowLookup : Node
|
||||
|
||||
return (show, season, episode, lastEpisode, year);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Extracts the year from the given text if it matches specific patterns and removes it from the text.
|
||||
/// </summary>
|
||||
/// <param name="text">The input text containing a potential year.</param>
|
||||
/// <returns>
|
||||
/// A tuple containing the cleaned text and the extracted year.
|
||||
/// The year is extracted only if it falls between 1950 and 5 years from the current year.
|
||||
/// </returns>
|
||||
static (string cleanedText, string? year) ExtractYearAndCleanText(string text)
|
||||
{
|
||||
string year = null;
|
||||
int currentYear = DateTime.Now.Year;
|
||||
int upperYearLimit = currentYear + 5;
|
||||
var cleanedText = text;
|
||||
|
||||
// Match year in parentheses (e.g., (2024))
|
||||
var reYear = Regex.Match(text, $@"(19[5-9]\d|20[0-{upperYearLimit % 100 / 10}]\d|{upperYearLimit})(?=[^\d]|$)", RegexOptions.CultureInvariant);
|
||||
if (reYear.Success)
|
||||
{
|
||||
year = reYear.Value;
|
||||
cleanedText = text.Replace(year, string.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Match dot-separated year (e.g., .2024.)
|
||||
var reYearAlt = Regex.Match(text, $@"\.(19[5-9]\d|20[0-{upperYearLimit % 100 / 10}]\d|{upperYearLimit})\.", RegexOptions.CultureInvariant);
|
||||
if (reYearAlt.Success)
|
||||
{
|
||||
year = reYearAlt.Value.Trim('.');
|
||||
cleanedText = text.Replace(reYearAlt.Value, string.Empty);
|
||||
}
|
||||
}
|
||||
|
||||
// Validate the extracted year
|
||||
if (year != null)
|
||||
{
|
||||
int yearInt = int.Parse(year);
|
||||
if (yearInt < 1950 || yearInt > upperYearLimit)
|
||||
{
|
||||
year = null;
|
||||
cleanedText = text; // restore it
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanedText = cleanedText.Replace(" ", " ").Replace("..", ".");
|
||||
}
|
||||
}
|
||||
|
||||
return (cleanedText, year);
|
||||
}
|
||||
}
|
||||
@@ -74,9 +74,7 @@ public abstract class PlexNode:Node
|
||||
{
|
||||
var options = new System.Text.Json.JsonSerializerOptions();
|
||||
options.PropertyNameCaseInsensitive = true;
|
||||
#pragma warning disable IL2026
|
||||
sections = System.Text.Json.JsonSerializer.Deserialize<PlexSections>(sectionsResponse.body, options)!;
|
||||
#pragma warning restore IL2026
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Plex</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -117,15 +117,12 @@ File shrunk in size by: {{ difference | file_size }} / {{ percent }}%
|
||||
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", settings.ApiToken);
|
||||
|
||||
// Create the request content
|
||||
#pragma warning disable IL2026
|
||||
var content = new StringContent(JsonSerializer.Serialize(
|
||||
new {
|
||||
type = "note",
|
||||
title,
|
||||
body
|
||||
}), Encoding.UTF8, "application/json");
|
||||
#pragma warning restore IL2026
|
||||
|
||||
|
||||
var response = httpClient.PostAsync("https://api.pushbullet.com/v2/pushes", content).Result;
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Pushbullet</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Pushover</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<FileVersion>1.0.4.189</FileVersion>
|
||||
<ProductVersion>1.0.4.189</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Site Scraping</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Telegram</Product>
|
||||
|
||||
@@ -24,13 +24,11 @@ internal class TestLogger : ILogger
|
||||
{
|
||||
if (args == null || args.Length == 0)
|
||||
return;
|
||||
#pragma warning disable IL2026
|
||||
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)));
|
||||
#pragma warning restore IL2026
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
|
||||
@@ -301,9 +301,7 @@ public class FfmpegBuilderAudioAddTrack : FfmpegBuilderNode
|
||||
rgxLanguage = new Regex(language, RegexOptions.IgnoreCase);
|
||||
}
|
||||
catch (Exception) { }
|
||||
#pragma warning disable IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
var bestAudio = streams.Where(x => System.Text.Json.JsonSerializer.Serialize(x).ToLower().Contains("commentary") == false)
|
||||
#pragma warning restore IL2026 // Members annotated with 'RequiresUnreferencedCodeAttribute' require dynamic access otherwise can break functionality when trimming application code
|
||||
.OrderBy(x =>
|
||||
{
|
||||
if (language != string.Empty)
|
||||
|
||||
@@ -105,9 +105,7 @@ public class FfmpegBuilderAudioNormalization : FfmpegBuilderNode
|
||||
json = json.Substring(0, json.IndexOf("}", StringComparison.Ordinal) + 1);
|
||||
if (string.IsNullOrEmpty(json))
|
||||
throw new Exception("Failed to parse TwoPass json");
|
||||
#pragma warning disable IL2026
|
||||
LoudNormStats? stats = JsonSerializer.Deserialize<LoudNormStats>(json);
|
||||
#pragma warning restore IL2026
|
||||
|
||||
if (stats.input_i == "-inf" || stats.input_lra == "-inf" || stats.input_tp == "-inf" || stats.input_thresh == "-inf" || stats.target_offset == "-inf")
|
||||
{
|
||||
|
||||
@@ -55,13 +55,11 @@ public class TestLogger : ILogger
|
||||
/// <param name="args">the arguments of the message</param>
|
||||
private void Log(LogType type, params object[] args)
|
||||
{
|
||||
#pragma warning disable IL2026
|
||||
string message = type + " -> " + string.Join(", ", args.Select(x =>
|
||||
x == null ? "null" :
|
||||
x.GetType().IsPrimitive ? x.ToString() :
|
||||
x is string ? x.ToString() :
|
||||
System.Text.Json.JsonSerializer.Serialize(x)));
|
||||
#pragma warning restore IL2026
|
||||
Writer?.Invoke(message);
|
||||
Messages.Add(message);
|
||||
}
|
||||
|
||||
@@ -76,9 +76,7 @@ public abstract class TestBase
|
||||
return;
|
||||
|
||||
string json = File.ReadAllText(filename);
|
||||
#pragma warning disable IL2026
|
||||
var settings = JsonSerializer.Deserialize<TestSettings>(json);
|
||||
#pragma warning restore IL2026
|
||||
this.TestPath = settings.TestPath;
|
||||
this.TempPath = settings.TempPath;
|
||||
this.FfmpegPath = settings.FfmpegPath;
|
||||
|
||||
@@ -34,10 +34,8 @@ internal class VideoMetadata
|
||||
{
|
||||
try
|
||||
{
|
||||
#pragma warning disable IL2026
|
||||
string json = JsonSerializer.Serialize(source);
|
||||
var result = JsonSerializer.Deserialize<VideoMetadata>(json);
|
||||
#pragma warning restore IL2026
|
||||
return result ?? new ();
|
||||
}
|
||||
catch (Exception)
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
<IncludeAllContentForSelfExtract>true</IncludeAllContentForSelfExtract>
|
||||
<FileVersion>1.1.1.528</FileVersion>
|
||||
<ProductVersion>1.1.1.528</ProductVersion>
|
||||
<PublishTrimmed>true</PublishTrimmed>
|
||||
<Company>FileFlows</Company>
|
||||
<Authors>John Andrews</Authors>
|
||||
<Product>Video</Product>
|
||||
|
||||
@@ -233,10 +233,8 @@ namespace FileFlows.VideoNodes
|
||||
// may be from non Legacy VideoNodes
|
||||
try
|
||||
{
|
||||
#pragma warning disable IL2026
|
||||
string json = JsonSerializer.Serialize(args.Parameters[VIDEO_INFO]);
|
||||
var vi = JsonSerializer.Deserialize<VideoInfo>(json);
|
||||
#pragma warning restore IL2026
|
||||
if (vi == null)
|
||||
throw new Exception("Failed to deserailize object");
|
||||
return vi;
|
||||
|
||||
Reference in New Issue
Block a user