Your ROOT_URL in app.ini is https://git.cloudchain.link/ but you are visiting https://dash.bss.nz/open-source-mirrors/jellyfin/commit/ea439c5ccf7a61157544accd60109afc12dbc2d2?style=unified&whitespace=ignore-all
You should set ROOT_URL correctly, otherwise the web may not work correctly.
8 changed files with
233 additions and
3 deletions
@ -368,6 +368,20 @@ namespace Emby.Naming.Common
IsOptimistic = true ,
IsNamed = true
} ,
// Series and season only expression
// "the show/season 1", "the show/s01"
new EpisodeExpression ( @"(.*(\\|\/))*(?<seriesname>.+)\/[Ss](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)" )
{
IsNamed = true
} ,
// Series and season only expression
// "the show S01", "the show season 1"
new EpisodeExpression ( @"(.*(\\|\/))*(?<seriesname>.+)[\. _\-]+[sS](eason)?[\. _\-]*(?<seasonnumber>[0-9]+)" )
{
IsNamed = true
} ,
} ;
EpisodeWithoutSeasonExpressions = new [ ]
@ -0,0 +1,29 @@
namespace Emby.Naming.TV
{
/// <summary>
/// Holder object for Series information.
/// </summary>
public class SeriesInfo
{
/// <summary>
/// Initializes a new instance of the <see cref="SeriesInfo"/> class.
/// </summary>
/// <param name="path">Path to the file.</param>
public SeriesInfo ( string path )
{
Path = path ;
}
/// <summary>
/// Gets or sets the path.
/// </summary>
/// <value>The path.</value>
public string Path { get ; set ; }
/// <summary>
/// Gets or sets the name of the series.
/// </summary>
/// <value>The name of the series.</value>
public string? Name { get ; set ; }
}
}
@ -0,0 +1,61 @@
using System.Globalization ;
using Emby.Naming.Common ;
namespace Emby.Naming.TV
{
/// <summary>
/// Used to parse information about series from paths containing more information that only the series name.
/// Uses the same regular expressions as the EpisodePathParser but have different success criteria.
/// </summary>
public static class SeriesPathParser
{
/// <summary>
/// Parses information about series from path.
/// </summary>
/// <param name="options"><see cref="NamingOptions"/> object containing EpisodeExpressions and MultipleEpisodeExpressions.</param>
/// <param name="path">Path.</param>
/// <returns>Returns <see cref="SeriesPathParserResult"/> object.</returns>
public static SeriesPathParserResult Parse ( NamingOptions options , string path )
{
SeriesPathParserResult ? result = null ;
foreach ( var expression in options . EpisodeExpressions )
{
var currentResult = Parse ( path , expression ) ;
if ( currentResult . Success )
{
result = currentResult ;
break ;
}
}
if ( result ! = null )
{
if ( ! string . IsNullOrEmpty ( result . SeriesName ) )
{
result . SeriesName = result . SeriesName . Trim ( ' ' , '_' , '.' , '-' ) ;
}
}
return result ? ? new SeriesPathParserResult ( ) ;
}
private static SeriesPathParserResult Parse ( string name , EpisodeExpression expression )
{
var result = new SeriesPathParserResult ( ) ;
var match = expression . Regex . Match ( name ) ;
if ( match . Success & & match . Groups . Count > = 3 )
{
if ( expression . IsNamed )
{
result . SeriesName = match . Groups [ "seriesname" ] . Value ;
result . Success = ! string . IsNullOrEmpty ( result . SeriesName ) & & ! string . IsNullOrEmpty ( match . Groups [ "seasonnumber" ] ? . Value ) ;
}
}
return result ;
}
}
}
@ -0,0 +1,19 @@
namespace Emby.Naming.TV
{
/// <summary>
/// Holder object for <see cref="SeriesPathParser"/> result.
/// </summary>
public class SeriesPathParserResult
{
/// <summary>
/// Gets or sets the name of the series.
/// </summary>
/// <value>The name of the series.</value>
public string? SeriesName { get ; set ; }
/// <summary>
/// Gets or sets a value indicating whether parsing was successful.
/// </summary>
public bool Success { get ; set ; }
}
}
@ -0,0 +1,49 @@
using System.IO ;
using System.Text.RegularExpressions ;
using Emby.Naming.Common ;
namespace Emby.Naming.TV
{
/// <summary>
/// Used to resolve information about series from path.
/// </summary>
public static class SeriesResolver
{
/// <summary>
/// Regex that matches strings of at least 2 characters separated by a dot or underscore.
/// Used for removing separators between words, i.e turns "The_show" into "The show" while
/// preserving namings like "S.H.O.W".
/// </summary>
private static readonly Regex _seriesNameRegex = new Regex ( @"((?<a>[^\._]{2,})[\._]*)|([\._](?<b>[^\._]{2,}))" ) ;
/// <summary>
/// Resolve information about series from path.
/// </summary>
/// <param name="options"><see cref="NamingOptions"/> object passed to <see cref="SeriesPathParser"/>.</param>
/// <param name="path">Path to series.</param>
/// <returns>SeriesInfo.</returns>
public static SeriesInfo Resolve ( NamingOptions options , string path )
{
string seriesName = Path . GetFileName ( path ) ;
SeriesPathParserResult result = SeriesPathParser . Parse ( options , path ) ;
if ( result . Success )
{
if ( ! string . IsNullOrEmpty ( result . SeriesName ) )
{
seriesName = result . SeriesName ;
}
}
if ( ! string . IsNullOrEmpty ( seriesName ) )
{
seriesName = _seriesNameRegex . Replace ( seriesName , "${a} ${b}" ) . Trim ( ) ;
}
return new SeriesInfo ( path )
{
Name = seriesName
} ;
}
}
}
@ -55,6 +55,8 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return null ;
}
var seriesInfo = Naming . TV . SeriesResolver . Resolve ( _libraryManager . GetNamingOptions ( ) , args . Path ) ;
var collectionType = args . GetCollectionType ( ) ;
if ( string . Equals ( collectionType , CollectionType . TvShows , StringComparison . OrdinalIgnoreCase ) )
{
@ -64,7 +66,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return new Series
{
Path = args . Path ,
Name = Path. GetFileName ( args . Path )
Name = seriesInfo. Name
} ;
}
}
@ -81,7 +83,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return new Series
{
Path = args . Path ,
Name = Path. GetFileName ( args . Path )
Name = seriesInfo. Name
} ;
}
@ -95,7 +97,7 @@ namespace Emby.Server.Implementations.Library.Resolvers.TV
return new Series
{
Path = args . Path ,
Name = Path. GetFileName ( args . Path )
Name = seriesInfo. Name
} ;
}
}
@ -0,0 +1,28 @@
using Emby.Naming.Common ;
using Emby.Naming.TV ;
using Xunit ;
namespace Jellyfin.Naming.Tests.TV
{
public class SeriesPathParserTest
{
[Theory]
[InlineData("The.Show.S01", "The.Show")]
[InlineData("/The.Show.S01", "The.Show")]
[InlineData("/some/place/The.Show.S01", "The.Show")]
[InlineData("/something/The.Show.S01", "The.Show")]
[InlineData("The Show Season 10", "The Show")]
[InlineData("The Show S01E01", "The Show")]
[InlineData("The Show S01E01 Episode", "The Show")]
[InlineData("/something/The Show/Season 1", "The Show")]
[InlineData("/something/The Show/S01", "The Show")]
public void SeriesPathParserParseTest ( string path , string name )
{
NamingOptions o = new NamingOptions ( ) ;
var res = SeriesPathParser . Parse ( o , path ) ;
Assert . Equal ( name , res . SeriesName ) ;
Assert . True ( res . Success ) ;
}
}
}
@ -0,0 +1,28 @@
using Emby.Naming.Common ;
using Emby.Naming.TV ;
using Xunit ;
namespace Jellyfin.Naming.Tests.TV
{
public class SeriesResolverTests
{
[Theory]
[InlineData("The.Show.S01", "The Show")]
[InlineData("The.Show.S01.COMPLETE", "The Show")]
[InlineData("S.H.O.W.S01", "S.H.O.W")]
[InlineData("The.Show.P.I.S01", "The Show P.I")]
[InlineData("The_Show_Season_1", "The Show")]
[InlineData("/something/The_Show/Season 10", "The Show")]
[InlineData("The Show", "The Show")]
[InlineData("/some/path/The Show", "The Show")]
[InlineData("/some/path/The Show s02e10 720p hdtv", "The Show")]
[InlineData("/some/path/The Show s02e10 the episode 720p hdtv", "The Show")]
public void SeriesResolverResolveTest ( string path , string name )
{
NamingOptions o = new NamingOptions ( ) ;
var res = SeriesResolver . Resolve ( o , path ) ;
Assert . Equal ( name , res . Name ) ;
}
}
}