diff --git a/Kyoo.Common/Models/Attributes/ComputedAttribute.cs b/Kyoo.Common/Models/Attributes/ComputedAttribute.cs
new file mode 100644
index 00000000..b7f07048
--- /dev/null
+++ b/Kyoo.Common/Models/Attributes/ComputedAttribute.cs
@@ -0,0 +1,10 @@
+using System;
+
+namespace Kyoo.Models.Attributes
+{
+ ///
+ /// An attribute to inform that the property is computed automatically and can't be assigned manually.
+ ///
+ [AttributeUsage(AttributeTargets.Property)]
+ public class ComputedAttribute : NotMergeableAttribute { }
+}
\ No newline at end of file
diff --git a/Kyoo.Common/Models/Resources/Episode.cs b/Kyoo.Common/Models/Resources/Episode.cs
index e5a677d4..307ab115 100644
--- a/Kyoo.Common/Models/Resources/Episode.cs
+++ b/Kyoo.Common/Models/Resources/Episode.cs
@@ -17,12 +17,17 @@ namespace Kyoo.Models
public int ID { get; set; }
///
- public string Slug
+ [Computed] public string Slug
{
- get => GetSlug(ShowSlug, SeasonNumber, EpisodeNumber, AbsoluteNumber);
+ get
+ {
+ if (ShowSlug == null && Show == null)
+ return GetSlug(ShowID.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber);
+ return GetSlug(ShowSlug ?? Show.Slug, SeasonNumber, EpisodeNumber, AbsoluteNumber);
+ }
[UsedImplicitly] private set
{
- Match match = Regex.Match(value, @"(?.*)-s(?\d*)e(?\d*)");
+ Match match = Regex.Match(value, @"(?.+)-s(?\d+)e(?\d+)");
if (match.Success)
{
@@ -45,7 +50,7 @@ namespace Kyoo.Models
}
}
}
-
+
///
/// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed.
///
diff --git a/Kyoo.Common/Models/Resources/Season.cs b/Kyoo.Common/Models/Resources/Season.cs
index 142b7e24..e3440670 100644
--- a/Kyoo.Common/Models/Resources/Season.cs
+++ b/Kyoo.Common/Models/Resources/Season.cs
@@ -16,12 +16,17 @@ namespace Kyoo.Models
public int ID { get; set; }
///
- public string Slug
+ [Computed] public string Slug
{
- get => $"{ShowSlug}-s{SeasonNumber}";
+ get
+ {
+ if (ShowSlug == null && Show == null)
+ return $"{ShowID}-s{SeasonNumber}";
+ return $"{ShowSlug ?? Show?.Slug}-s{SeasonNumber}";
+ }
[UsedImplicitly] private set
{
- Match match = Regex.Match(value, @"(?.*)-s(?\d*)");
+ Match match = Regex.Match(value ?? "", @"(?.+)-s(?\d+)");
if (!match.Success)
throw new ArgumentException("Invalid season slug. Format: {showSlug}-s{seasonNumber}");
@@ -29,7 +34,7 @@ namespace Kyoo.Models
SeasonNumber = int.Parse(match.Groups["season"].Value);
}
}
-
+
///
/// The slug of the Show that contain this episode. If this is not set, this season is ill-formed.
///
diff --git a/Kyoo.Common/Models/Resources/Track.cs b/Kyoo.Common/Models/Resources/Track.cs
index 21aa9d63..e0d543c2 100644
--- a/Kyoo.Common/Models/Resources/Track.cs
+++ b/Kyoo.Common/Models/Resources/Track.cs
@@ -29,7 +29,7 @@ namespace Kyoo.Models
public int ID { get; set; }
///
- public string Slug
+ [Computed] public string Slug
{
get
{
diff --git a/Kyoo.Common/Utility/Merger.cs b/Kyoo.Common/Utility/Merger.cs
index 047b5b09..d6378ca9 100644
--- a/Kyoo.Common/Utility/Merger.cs
+++ b/Kyoo.Common/Utility/Merger.cs
@@ -79,7 +79,7 @@ namespace Kyoo
Type type = typeof(T);
IEnumerable properties = type.GetProperties()
- .Where(x => x.CanRead && x.CanWrite
+ .Where(x => x.CanRead && x.CanWrite
&& Attribute.GetCustomAttribute(x, typeof(NotMergeableAttribute)) == null);
if (where != null)
diff --git a/Kyoo.CommonAPI/DatabaseContext.cs b/Kyoo.CommonAPI/DatabaseContext.cs
index a2b7eeb2..2e425415 100644
--- a/Kyoo.CommonAPI/DatabaseContext.cs
+++ b/Kyoo.CommonAPI/DatabaseContext.cs
@@ -330,6 +330,16 @@ namespace Kyoo
modelBuilder.Entity