Merge pull request #51 from wolffshots/master
Episodes by YYYYMMDD and some other cleanup
This commit is contained in:
@@ -0,0 +1,17 @@
|
|||||||
|
namespace Jellyfin.Plugin.TubeArchivistMetadata.Configuration;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The NumberingScheme.
|
||||||
|
/// </summary>
|
||||||
|
public enum NumberingScheme
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Default (no numbering).
|
||||||
|
/// </summary>
|
||||||
|
Default,
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// YYYYMMDD (e.g. 20250804 for August 4th, 2025).
|
||||||
|
/// </summary>
|
||||||
|
YYYYMMDD,
|
||||||
|
}
|
||||||
@@ -186,6 +186,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Configuration
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public int TAJFPlaylistsSyncTaskInterval { get; set; }
|
public int TAJFPlaylistsSyncTaskInterval { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the preferred numbering scheme for episodes (index number) in Jellyfin.
|
||||||
|
/// </summary>
|
||||||
|
public NumberingScheme EpisodeNumberingScheme { get; set; } = NumberingScheme.Default;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the playback progress owners Jellyfin usernames to synchronize data from TubeArchivist.
|
/// Gets the playback progress owners Jellyfin usernames to synchronize data from TubeArchivist.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -41,6 +41,18 @@
|
|||||||
<div class="fieldDescription">This is the maximum length of the descriptions showed in series
|
<div class="fieldDescription">This is the maximum length of the descriptions showed in series
|
||||||
and episodes</div>
|
and episodes</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="selectContainer">
|
||||||
|
<label class="selectLabel" for="EpisodeNumberingScheme">Episode numbering scheme</label>
|
||||||
|
<select is="emby-select" id="EpisodeNumberingScheme" name="EpisodeNumberingScheme" label="Description markup" class="emby-select-withcolor emby-select">
|
||||||
|
<option value="Default">Default (no specified numbering)</option>
|
||||||
|
<option value="YYYYMMDD">YYYYMMDD (e.g. 20250804 for August 4th, 2025)</option>
|
||||||
|
</select>
|
||||||
|
<div class="selectArrowContainer">
|
||||||
|
<span class="selectArrow material-icons keyboard_arrow_down" aria-hidden="true"></span>
|
||||||
|
</div>
|
||||||
|
<div class="fieldDescription">This is the numbering scheme for episodes in Jellyfin (IndexNumber).
|
||||||
|
Default is the same as no numbering which allows Jellyfin to use the fallback numbering scheme.
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h2>Synchronization</h2>
|
<h2>Synchronization</h2>
|
||||||
</div>
|
</div>
|
||||||
@@ -160,6 +172,7 @@
|
|||||||
document.querySelector('#JFTAPlaylistsSync').checked = config.JFTAPlaylistsSync;
|
document.querySelector('#JFTAPlaylistsSync').checked = config.JFTAPlaylistsSync;
|
||||||
document.querySelector('#TAJFPlaylistsSync').checked = config.TAJFPlaylistsSync;
|
document.querySelector('#TAJFPlaylistsSync').checked = config.TAJFPlaylistsSync;
|
||||||
document.querySelector('#JFUsernameFrom').value = config.JFUsernameFrom;
|
document.querySelector('#JFUsernameFrom').value = config.JFUsernameFrom;
|
||||||
|
document.querySelector('#EpisodeNumberingScheme').value = config.EpisodeNumberingScheme;
|
||||||
document.querySelector('#TAJFProgressTaskInterval').value = config.TAJFProgressTaskInterval;
|
document.querySelector('#TAJFProgressTaskInterval').value = config.TAJFProgressTaskInterval;
|
||||||
document.querySelector('#JFTAPlaylistsSyncTaskInterval').value = config.JFTAPlaylistsSyncTaskInterval;
|
document.querySelector('#JFTAPlaylistsSyncTaskInterval').value = config.JFTAPlaylistsSyncTaskInterval;
|
||||||
document.querySelector('#TAJFPlaylistsSyncTaskInterval').value = config.TAJFPlaylistsSyncTaskInterval;
|
document.querySelector('#TAJFPlaylistsSyncTaskInterval').value = config.TAJFPlaylistsSyncTaskInterval;
|
||||||
@@ -181,6 +194,7 @@
|
|||||||
config.JFTAPlaylistsSync = document.querySelector('#JFTAPlaylistsSync').checked;
|
config.JFTAPlaylistsSync = document.querySelector('#JFTAPlaylistsSync').checked;
|
||||||
config.TAJFPlaylistsSync = document.querySelector('#TAJFPlaylistsSync').checked;
|
config.TAJFPlaylistsSync = document.querySelector('#TAJFPlaylistsSync').checked;
|
||||||
config.JFUsernameFrom = document.querySelector('#JFUsernameFrom').value;
|
config.JFUsernameFrom = document.querySelector('#JFUsernameFrom').value;
|
||||||
|
config.EpisodeNumberingScheme = document.querySelector('#EpisodeNumberingScheme').value;
|
||||||
config.TAJFProgressTaskInterval = document.querySelector('#TAJFProgressTaskInterval').value;
|
config.TAJFProgressTaskInterval = document.querySelector('#TAJFProgressTaskInterval').value;
|
||||||
config.JFTAPlaylistsSyncTaskInterval = document.querySelector('#JFTAPlaylistsSyncTaskInterval').value;
|
config.JFTAPlaylistsSyncTaskInterval = document.querySelector('#JFTAPlaylistsSyncTaskInterval').value;
|
||||||
config.TAJFPlaylistsSyncTaskInterval = document.querySelector('#TAJFPlaylistsSyncTaskInterval').value;
|
config.TAJFPlaylistsSyncTaskInterval = document.querySelector('#TAJFPlaylistsSyncTaskInterval').value;
|
||||||
|
|||||||
@@ -162,20 +162,20 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Instance!.Configuration.JFTAProgressSync && eventArgs.Users.Any(u => Instance!.Configuration.JFUsernameFrom.Equals(u.Username, StringComparison.Ordinal)))
|
var topParent = eventArgs.Item.GetTopParent();
|
||||||
|
if (
|
||||||
|
Instance!.Configuration.JFTAProgressSync &&
|
||||||
|
eventArgs.Users.Any(u => Instance!.Configuration.JFUsernameFrom.Equals(u.Username, StringComparison.Ordinal)) &&
|
||||||
|
eventArgs.PlaybackPositionTicks.HasValue &&
|
||||||
|
string.Equals(topParent?.Name, Instance?.Configuration.CollectionTitle, StringComparison.OrdinalIgnoreCase)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
BaseItem? season = LibraryManager.GetItemById(eventArgs.Item.ParentId);
|
long progress = (long)eventArgs.PlaybackPositionTicks / TimeSpan.TicksPerSecond;
|
||||||
BaseItem? channel = LibraryManager.GetItemById(season!.ParentId);
|
var videoId = Utils.GetVideoNameFromPath(eventArgs.Item.Path);
|
||||||
BaseItem? collection = LibraryManager.GetItemById(channel!.ParentId);
|
var statusCode = await TubeArchivistApi.GetInstance().SetProgress(videoId, progress).ConfigureAwait(true);
|
||||||
if (collection?.Name.ToLower(CultureInfo.CurrentCulture) == Instance?.Configuration.CollectionTitle.ToLower(CultureInfo.CurrentCulture) && eventArgs.PlaybackPositionTicks != null)
|
if (statusCode != System.Net.HttpStatusCode.OK)
|
||||||
{
|
{
|
||||||
long progress = (long)eventArgs.PlaybackPositionTicks / TimeSpan.TicksPerSecond;
|
Logger.LogCritical("{Message}", $"POST /video/{videoId}/progress returned {statusCode} for video {eventArgs.Item.Name} with progress {progress} seconds");
|
||||||
var videoId = Utils.GetVideoNameFromPath(eventArgs.Item.Path);
|
|
||||||
var statusCode = await TubeArchivistApi.GetInstance().SetProgress(videoId, progress).ConfigureAwait(true);
|
|
||||||
if (statusCode != System.Net.HttpStatusCode.OK)
|
|
||||||
{
|
|
||||||
Logger.LogCritical("{Message}", $"POST /video/{videoId}/progress returned {statusCode} for video {eventArgs.Item.Name} with progress {progress} seconds");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -188,16 +188,22 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var topParent = eventArgs.Item.GetTopParent();
|
||||||
var user = _userManager.GetUserById(eventArgs.UserId);
|
var user = _userManager.GetUserById(eventArgs.UserId);
|
||||||
if (user == null)
|
if (
|
||||||
|
Configuration.JFTAProgressSync &&
|
||||||
|
user != null &&
|
||||||
|
Configuration.GetJFUsernamesToArray().Contains(user!.Username) &&
|
||||||
|
string.Equals(topParent?.Name, Instance?.Configuration.CollectionTitle, StringComparison.OrdinalIgnoreCase)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
Logger.LogError("OnWatchedStatusChange callback called without user id for item {ItemName}", eventArgs.Item.Name);
|
Logger.LogError("OnWatchedStatusChange callback called without user id for item {ItemName}", eventArgs.Item.Name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var userItemData = _userDataManager.GetUserData(user, eventArgs.Item);
|
|
||||||
if (Configuration.JFTAProgressSync && user != null && Configuration.GetJFUsernamesToArray().Contains(user!.Username))
|
if (Configuration.JFTAProgressSync && user != null && Configuration.GetJFUsernamesToArray().Contains(user!.Username))
|
||||||
{
|
{
|
||||||
|
var userItemData = _userDataManager.GetUserData(user, eventArgs.Item);
|
||||||
var isPlayed = eventArgs.Item.IsPlayed(user, userItemData);
|
var isPlayed = eventArgs.Item.IsPlayed(user, userItemData);
|
||||||
Logger.LogDebug("User {UserId} changed watched status to {Status} for the item {ItemName}", eventArgs.UserId, isPlayed, eventArgs.Item.Name);
|
Logger.LogDebug("User {UserId} changed watched status to {Status} for the item {ItemName}", eventArgs.UserId, isPlayed, eventArgs.Item.Name);
|
||||||
string itemYTId;
|
string itemYTId;
|
||||||
|
|||||||
@@ -67,6 +67,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers
|
|||||||
});
|
});
|
||||||
result.HasMetadata = true;
|
result.HasMetadata = true;
|
||||||
result.Item = video.ToEpisode();
|
result.Item = video.ToEpisode();
|
||||||
|
result.Item.Path = info.Path;
|
||||||
result.Provider = Name;
|
result.Provider = Name;
|
||||||
result.People = peopleInfo;
|
result.People = peopleInfo;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
|||||||
foreach (Episode video in videos)
|
foreach (Episode video in videos)
|
||||||
{
|
{
|
||||||
var videoYTId = Utils.GetVideoNameFromPath(video.Path);
|
var videoYTId = Utils.GetVideoNameFromPath(video.Path);
|
||||||
_logger.LogDebug("{VideoYtId}", videoYTId);
|
_logger.LogDebug("Current video extracted YouTube id: {VideoYtId}", videoYTId);
|
||||||
HttpStatusCode statusCode;
|
HttpStatusCode statusCode;
|
||||||
var userItemData = _userDataManager.GetUserData(user, channel);
|
var userItemData = _userDataManager.GetUserData(user, channel);
|
||||||
|
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using Jellyfin.Plugin.TubeArchivistMetadata.Configuration;
|
||||||
using Jellyfin.Plugin.TubeArchivistMetadata.Utilities;
|
using Jellyfin.Plugin.TubeArchivistMetadata.Utilities;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Entities.TV;
|
using MediaBrowser.Controller.Entities.TV;
|
||||||
@@ -126,6 +127,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.TubeArchivist
|
|||||||
Overview = Utils.FormatDescription(Description),
|
Overview = Utils.FormatDescription(Description),
|
||||||
SeasonName = Published.Year.ToString(CultureInfo.CurrentCulture),
|
SeasonName = Published.Year.ToString(CultureInfo.CurrentCulture),
|
||||||
ParentIndexNumber = Published.Year,
|
ParentIndexNumber = Published.Year,
|
||||||
|
IndexNumber = Plugin.Instance?.Configuration?.EpisodeNumberingScheme switch
|
||||||
|
{
|
||||||
|
NumberingScheme.YYYYMMDD => (Published.Year * 10000) + (Published.Month * 100) + Published.Day,
|
||||||
|
_ => null
|
||||||
|
},
|
||||||
SeriesName = Channel.Name,
|
SeriesName = Channel.Name,
|
||||||
ProductionYear = Published.Year,
|
ProductionYear = Published.Year,
|
||||||
PremiereDate = Published,
|
PremiereDate = Published,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
using Microsoft.Extensions.Logging;
|
||||||
|
|
||||||
namespace Jellyfin.Plugin.TubeArchivistMetadata.Utilities
|
namespace Jellyfin.Plugin.TubeArchivistMetadata.Utilities
|
||||||
{
|
{
|
||||||
@@ -45,6 +47,11 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Utilities
|
|||||||
/// <returns>A string with \n replaced by br tags.</returns>
|
/// <returns>A string with \n replaced by br tags.</returns>
|
||||||
public static string FormatDescription(string description)
|
public static string FormatDescription(string description)
|
||||||
{
|
{
|
||||||
|
if (description == null)
|
||||||
|
{
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
var maxLength = 500;
|
var maxLength = 500;
|
||||||
if (Plugin.Instance != null)
|
if (Plugin.Instance != null)
|
||||||
{
|
{
|
||||||
@@ -54,9 +61,10 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Utilities
|
|||||||
if (description.Length > maxLength)
|
if (description.Length > maxLength)
|
||||||
{
|
{
|
||||||
description = description.Substring(0, maxLength);
|
description = description.Substring(0, maxLength);
|
||||||
description = description.Replace("\n", "<br>", System.StringComparison.CurrentCulture);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
description = description.Replace("\n", "<br>", System.StringComparison.CurrentCulture);
|
||||||
|
|
||||||
return description;
|
return description;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -114,6 +114,16 @@ Keep in mind that Jellyfin lowest accepted period is of 1 minute (60 seconds) an
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Episode numbering
|
||||||
|
|
||||||
|
<p>There are different ways to number the episodes as they are configured in Jellyfin.<br>
|
||||||
|
This changes the number after E in S--E-- (for example S2024E100 for episode number 100 of season 2024).</p>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
The options correlate with:
|
||||||
|
- Default - leave the numbering to what Jellyfin does by default (this is what the plugin has always done)
|
||||||
|
- YYYYMMDD - numbers the episode by the year, month, day (e.g. 20250804 for a video published on the 4th of August 2025)
|
||||||
|
|
||||||
## Build
|
## Build
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user