Compare commits
13 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a162ebb25d | |||
| 36eec27d9f | |||
| ce8aea629b | |||
| a8f821625b | |||
| 6cb2d89b95 | |||
| 080f3856b7 | |||
| b436ae13a1 | |||
| dce122840c | |||
| 9129bbda71 | |||
| 698237a77a | |||
| 0bb2cb1108 | |||
| 286d43c840 | |||
| 6675f7f762 |
@@ -3,3 +3,4 @@ obj/
|
||||
.vs/
|
||||
.idea/
|
||||
artifacts
|
||||
nuget.config
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Version>1.3.0.0</Version>
|
||||
<AssemblyVersion>1.3.0.0</AssemblyVersion>
|
||||
<FileVersion>1.3.0.0</FileVersion>
|
||||
<Version>1.3.3.0</Version>
|
||||
<AssemblyVersion>1.3.3.0</AssemblyVersion>
|
||||
<FileVersion>1.3.3.0</FileVersion>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
|
||||
@@ -118,14 +118,14 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Configuration
|
||||
{
|
||||
get
|
||||
{
|
||||
_logger.LogInformation("JFUsernamesTo configured: {Message}", string.Join(", ", _jfUsernamesTo));
|
||||
_logger.LogDebug("JFUsernamesTo configured: {Message}", string.Join(", ", _jfUsernamesTo));
|
||||
return string.Join(", ", _jfUsernamesTo);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
value.Replace(" ", string.Empty, StringComparison.CurrentCulture).Split(',').ToList().ForEach(u => _jfUsernamesTo.Add(u));
|
||||
_logger.LogInformation("Set JFUsernamesTo to: {Message}", value);
|
||||
_logger.LogDebug("Set JFUsernamesTo to: {Message}", value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Jellyfin.Controller" Version="10.9.0-20240509061132" />
|
||||
<PackageReference Include="Jellyfin.Model" Version="10.9.0-20240509061132" />
|
||||
<PackageReference Include="Jellyfin.Controller" Version="10.10.0" />
|
||||
<PackageReference Include="Jellyfin.Model" Version="10.10.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
|
||||
@@ -164,7 +164,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
||||
var statusCode = await TubeArchivistApi.GetInstance().SetProgress(videoId, progress).ConfigureAwait(true);
|
||||
if (statusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
Logger.LogInformation("{Message}", $"POST /video/{videoId}/progress returned {statusCode} for video {eventArgs.Item.Name} with progress {progress} seconds");
|
||||
Logger.LogCritical("{Message}", $"POST /video/{videoId}/progress returned {statusCode} for video {eventArgs.Item.Name} with progress {progress} seconds");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -176,7 +176,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
||||
if (user != null && Configuration.GetJFUsernamesToArray().Contains(user!.Username))
|
||||
{
|
||||
var isPlayed = eventArgs.Item.IsPlayed(user);
|
||||
Logger.LogInformation("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;
|
||||
if (eventArgs.Item is Series)
|
||||
{
|
||||
@@ -194,7 +194,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata
|
||||
var statusCode = await TubeArchivistApi.GetInstance().SetWatchedStatus(itemYTId, isPlayed).ConfigureAwait(true);
|
||||
if (statusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
Logger.LogInformation("POST /watched returned {StatusCode} for item {ItemName} ({VideoYTId}) with watched status {IsPlayed}", statusCode, eventArgs.Item.Name, itemYTId, isPlayed);
|
||||
Logger.LogCritical("POST /watched returned {StatusCode} for item {ItemName} ({VideoYTId}) with watched status {IsPlayed}", statusCode, eventArgs.Item.Name, itemYTId, isPlayed);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -85,6 +85,12 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Providers
|
||||
Type = ImageType.Banner,
|
||||
Url = channel.BannerUrl
|
||||
});
|
||||
list.Add(new RemoteImageInfo
|
||||
{
|
||||
ProviderName = Name,
|
||||
Type = ImageType.Backdrop,
|
||||
Url = channel.TvartUrl
|
||||
});
|
||||
}
|
||||
|
||||
return list;
|
||||
|
||||
@@ -56,11 +56,13 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
/// <inheritdoc/>
|
||||
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
progress.Report(0);
|
||||
if (Plugin.Instance!.Configuration.JFTASync)
|
||||
{
|
||||
var start = DateTime.Now;
|
||||
_logger.LogInformation("Starting Jellyfin->TubeArchivist playback progresses synchronization.");
|
||||
var taApi = TubeArchivistApi.GetInstance();
|
||||
var videosCount = 0;
|
||||
foreach (var jfUsername in Plugin.Instance!.Configuration.GetJFUsernamesToArray())
|
||||
{
|
||||
var user = _userManager.GetUserByName(jfUsername);
|
||||
@@ -89,7 +91,60 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
IncludeItemTypes = new[] { BaseItemKind.Series }
|
||||
});
|
||||
_logger.LogInformation("Analyzing collection {Id} with name {Name}", collectionItem.Id, collectionItem.Name);
|
||||
_logger.LogInformation("Found {Message} channels", channels.Count);
|
||||
_logger.LogDebug("Found {Message} channels", channels.Count);
|
||||
|
||||
foreach (Series channel in channels)
|
||||
{
|
||||
var channelYTId = Utils.GetChannelNameFromPath(channel.Path);
|
||||
var years = channel.GetChildren(user, false, new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Season }
|
||||
});
|
||||
_logger.LogDebug("Found {Years} years in channel {ChannelName}", years.Count, channel.Name);
|
||||
|
||||
foreach (Season year in years)
|
||||
{
|
||||
var videos = year.GetChildren(user, false, new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Episode }
|
||||
});
|
||||
_logger.LogDebug("Found {Videos} videos in year {YearName} of the channel {ChannelName}", videos.Count, year.Name, channel.Name);
|
||||
videosCount += videos.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Found a total of {VideosCount} videos", videosCount);
|
||||
|
||||
var processedVideosCount = 0;
|
||||
foreach (var jfUsername in Plugin.Instance!.Configuration.GetJFUsernamesToArray())
|
||||
{
|
||||
var user = _userManager.GetUserByName(jfUsername);
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogInformation("{Message}", $"Jellyfin user with username {jfUsername} not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
var collectionItem = _libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
Name = Plugin.Instance?.Configuration.CollectionTitle,
|
||||
IncludeItemTypes = new[] { BaseItemKind.CollectionFolder }
|
||||
}).FirstOrDefault();
|
||||
|
||||
if (collectionItem == null)
|
||||
{
|
||||
var message = $"Collection '{Plugin.Instance?.Configuration.CollectionTitle}' not found.";
|
||||
_logger.LogCritical("{Message}", message);
|
||||
}
|
||||
else
|
||||
{
|
||||
var collection = (CollectionFolder)collectionItem;
|
||||
var channels = collection.GetChildren(user, false, new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Series }
|
||||
});
|
||||
|
||||
foreach (Series channel in channels)
|
||||
{
|
||||
@@ -100,7 +155,6 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Season }
|
||||
});
|
||||
_logger.LogInformation("Found {Years} years in channel {ChannelName}", years.Count, channel.Name);
|
||||
|
||||
foreach (Season year in years)
|
||||
{
|
||||
@@ -108,16 +162,16 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Episode }
|
||||
});
|
||||
_logger.LogInformation("Found {Videos} videos in year {YearName} of the channel {ChannelName}", videos.Count, year.Name, channel.Name);
|
||||
videosCount += videos.Count;
|
||||
|
||||
foreach (Episode video in videos)
|
||||
{
|
||||
var videoYTId = Utils.GetVideoNameFromPath(video.Path);
|
||||
var playbackProgress = _userDataManager.GetUserData(user.Id, video).PlaybackPositionTicks / TimeSpan.TicksPerSecond;
|
||||
var playbackProgress = _userDataManager.GetUserData(user, video).PlaybackPositionTicks / TimeSpan.TicksPerSecond;
|
||||
var statusCode = await taApi.SetProgress(videoYTId, playbackProgress).ConfigureAwait(true);
|
||||
if (statusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
_logger.LogInformation("{Message}", $"POST /video/{videoYTId}/progress returned {statusCode} for video {video.Name} with progress {progress} seconds");
|
||||
_logger.LogCritical("{Message}", $"POST /video/{videoYTId}/progress returned {statusCode} for video {video.Name} with progress {progress} seconds");
|
||||
}
|
||||
|
||||
if (!isChannelCheckedForWatched && channel.IsPlayed(user))
|
||||
@@ -126,7 +180,7 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
statusCode = await taApi.SetWatchedStatus(channelYTId, isChannelPlayed).ConfigureAwait(true);
|
||||
if (statusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
_logger.LogInformation("{Message}", $"POST /watched returned {statusCode} for channel {channel.Name} ({channelYTId}) with wacthed status {isChannelPlayed}");
|
||||
_logger.LogCritical("{Message}", $"POST /watched returned {statusCode} for channel {channel.Name} ({channelYTId}) with wacthed status {isChannelPlayed}");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -142,9 +196,12 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
statusCode = await taApi.SetWatchedStatus(videoYTId, isVideoPlayed).ConfigureAwait(true);
|
||||
if (statusCode != System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
_logger.LogInformation("{Message}", $"POST /watched returned {statusCode} for video {video.Name} ({videoYTId}) with wacthed status {isVideoPlayed}");
|
||||
_logger.LogCritical("{Message}", $"POST /watched returned {statusCode} for video {video.Name} ({videoYTId}) with wacthed status {isVideoPlayed}");
|
||||
}
|
||||
}
|
||||
|
||||
processedVideosCount++;
|
||||
progress.Report(processedVideosCount * 100 / videosCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -157,6 +214,8 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
{
|
||||
_logger.LogInformation("Jellyfin->TubeArchivist playback synchronization is currently disabled.");
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -56,11 +56,13 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
/// <inheritdoc/>
|
||||
public async Task ExecuteAsync(IProgress<double> progress, CancellationToken cancellationToken)
|
||||
{
|
||||
progress.Report(0);
|
||||
if (Plugin.Instance!.Configuration.TAJFSync)
|
||||
{
|
||||
var start = DateTime.Now;
|
||||
_logger.LogInformation("Starting TubeArchivist->Jellyfin playback progresses synchronization.");
|
||||
var taApi = TubeArchivistApi.GetInstance();
|
||||
var videosCount = 0;
|
||||
foreach (var jfUsername in Plugin.Instance!.Configuration.GetJFUsernamesToArray())
|
||||
{
|
||||
var user = _userManager.GetUserByName(jfUsername);
|
||||
@@ -89,7 +91,60 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
IncludeItemTypes = new[] { BaseItemKind.Series }
|
||||
});
|
||||
_logger.LogInformation("Analyzing collection {Id} with name {Name}", collectionItem.Id, collectionItem.Name);
|
||||
_logger.LogInformation("Found {Message} channels", channels.Count);
|
||||
_logger.LogDebug("Found {Message} channels", channels.Count);
|
||||
|
||||
foreach (Series channel in channels)
|
||||
{
|
||||
var years = channel.GetChildren(user, false, new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Season }
|
||||
});
|
||||
_logger.LogDebug("Found {Years} years in channel {ChannelName}", years.Count, channel.Name);
|
||||
|
||||
foreach (Season year in years)
|
||||
{
|
||||
var videos = year.GetChildren(user, false, new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Episode }
|
||||
});
|
||||
_logger.LogDebug("Found {Videos} videos in year {YearName} of the channel {ChannelName}", videos.Count, year.Name, channel.Name);
|
||||
|
||||
videosCount += videos.Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_logger.LogInformation("Found a total of {VideosCount} videos", videosCount);
|
||||
|
||||
var processedVideosCount = 0;
|
||||
foreach (var jfUsername in Plugin.Instance!.Configuration.GetJFUsernamesToArray())
|
||||
{
|
||||
var user = _userManager.GetUserByName(jfUsername);
|
||||
if (user == null)
|
||||
{
|
||||
_logger.LogInformation("{Message}", $"Jellyfin user with username {jfUsername} not found");
|
||||
continue;
|
||||
}
|
||||
|
||||
var collectionItem = _libraryManager.GetItemList(new InternalItemsQuery
|
||||
{
|
||||
Name = Plugin.Instance?.Configuration.CollectionTitle,
|
||||
IncludeItemTypes = new[] { BaseItemKind.CollectionFolder }
|
||||
}).FirstOrDefault();
|
||||
|
||||
if (collectionItem == null)
|
||||
{
|
||||
var message = $"Collection '{Plugin.Instance?.Configuration.CollectionTitle}' not found.";
|
||||
_logger.LogCritical("{Message}", message);
|
||||
}
|
||||
else
|
||||
{
|
||||
var collection = (CollectionFolder)collectionItem;
|
||||
var channels = collection.GetChildren(user, false, new InternalItemsQuery
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Series }
|
||||
});
|
||||
|
||||
foreach (Series channel in channels)
|
||||
{
|
||||
@@ -97,7 +152,6 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Season }
|
||||
});
|
||||
_logger.LogInformation("Found {Years} years in channel {ChannelName}", years.Count, channel.Name);
|
||||
|
||||
foreach (Season year in years)
|
||||
{
|
||||
@@ -105,7 +159,6 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
{
|
||||
IncludeItemTypes = new[] { BaseItemKind.Episode }
|
||||
});
|
||||
_logger.LogInformation("Found {Videos} videos in year {YearName} of the channel {ChannelName}", videos.Count, year.Name, channel.Name);
|
||||
|
||||
foreach (Episode video in videos)
|
||||
{
|
||||
@@ -134,6 +187,9 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
_userDataManager.SaveUserData(user, video, userUpdateData, UserDataSaveReason.UpdateUserData);
|
||||
_logger.LogInformation("{Message}", $"Playback progress for video {video.Name} set to {userItemData.PlaybackPositionTicks / TimeSpan.TicksPerSecond} seconds for user {jfUsername}.");
|
||||
_logger.LogInformation("{Message}", $"Watched status for video {video.Name} set to {userItemData.Played} seconds for user {jfUsername}.");
|
||||
|
||||
processedVideosCount++;
|
||||
progress.Report(processedVideosCount * 100 / videosCount);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,6 +203,8 @@ namespace Jellyfin.Plugin.TubeArchivistMetadata.Tasks
|
||||
{
|
||||
_logger.LogInformation("TubeArchivist->Jellyfin playback synchronization is currently disabled.");
|
||||
}
|
||||
|
||||
progress.Report(100);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
||||
@@ -49,6 +49,7 @@ Once installed, you have to configure the following parameters in the plugin con
|
||||
<li>TubeArchivist instance address</li>
|
||||
<li>TubeArchivist API key</li>
|
||||
<li>Overviews length (channels and videos descriptions)</li>
|
||||
<li>Playback synchronization settings discussed in the <a href="#playback-synchronization">Playback synchronization</a> paragraph</li>
|
||||
</ul>
|
||||
|
||||

|
||||
@@ -65,6 +66,26 @@ _NOTE: If you are using Docker containers, it is important to mount the TubeArch
|
||||
4. Scrolling down, uncheck all metadata and image providers except `TubeArchivist`. (You won't find TubeArchivist in seasons providers, so just disable everything there)
|
||||
5. Save and come back to Home, you will see the newly added library. Jellyfin will have executed the metadata fetching for you after the collection creation and then you will see the metadata and the images of channels and videos
|
||||
|
||||
|
||||
## Playback synchronization
|
||||
<p>Starting from v1.3.1 this plugin offers playback progress and watched status bidirectional synchronization, but you can choose to enable only a one way synchronization (Jellyfin->TubeArchivist or TubeArchivist->Jellyfin) too.</p>
|
||||
|
||||
### Jellyfin->TubeArchivist synchronization
|
||||
<p>This kind of synchronization is done listening for progress and watched status changes while playing the videos for the specified users.<br>Furthermore, there is a task that runs at Jellyfin startup to synchronize the whole library.</p>
|
||||
<p>In the plugin configuration you will find these settings:</p>
|
||||
|
||||

|
||||
<p>In the text field you can specify one Jellyfin username to synchronize data of to TubeArchivist.</p>
|
||||
|
||||
### TubeArchivist->Jellyfin synchronization
|
||||
<p>This kind of synchronization is done using a Jellyfin scheduled task that regularly synchronizes data from TubeArchivist API to Jellyfin.</p>
|
||||
<p>In the plugin configuration you will find these settings:</p>
|
||||
|
||||

|
||||
<p>In the first text field you can specify one or more Jellyfin usernames to update data for.<br>
|
||||
In the second field you can specify the interval in seconds the task should run at, so that you can choose according to your system requirements. The lower is the interval the higher will be the resources consuption on your system.</p>
|
||||
|
||||
|
||||
## Build
|
||||
|
||||
1. To build this plugin you will need [.Net 8.x](https://dotnet.microsoft.com/download/dotnet/8.0).
|
||||
|
||||
+3
-3
@@ -2,8 +2,8 @@
|
||||
name: "TubeArchivistMetadata"
|
||||
guid: "dc97d0c6-28b0-4242-afb4-5833ae1b3715"
|
||||
imageUrl: https://raw.githubusercontent.com/tubearchivist/tubearchivist-jf-plugin/master/images/logo.png
|
||||
version: "1.3.0.0"
|
||||
targetAbi: "10.9.1.0"
|
||||
version: "1.3.3.0"
|
||||
targetAbi: "10.10.0.0"
|
||||
framework: "net8.0"
|
||||
overview: "Metadata for your TubeArchivist library on Jellyfin"
|
||||
description: >
|
||||
@@ -14,4 +14,4 @@ owner: "DarkFighterLuke"
|
||||
artifacts:
|
||||
- "Jellyfin.Plugin.TubeArchivistMetadata.dll"
|
||||
changelog: >
|
||||
Add support for Jellyfin 10.9.1
|
||||
Add compatibility with Jellyfin 10.10
|
||||
|
||||
@@ -8,6 +8,22 @@
|
||||
"overview": "Metadata for your TubeArchivist library on Jellyfin",
|
||||
"imageUrl": "https://raw.githubusercontent.com/tubearchivist/tubearchivist-jf-plugin/master/images/logo.png",
|
||||
"versions": [
|
||||
{
|
||||
"version": "1.3.2.0",
|
||||
"changelog": "Add tasks progress status Adjust logs levels\n",
|
||||
"targetAbi": "10.9.1.0",
|
||||
"sourceUrl": "https://github.com/tubearchivist/tubearchivist-jf-plugin/releases/download/v1.3.2/tubearchivistmetadata_1.3.2.0.zip",
|
||||
"checksum": "6162235807535a5c2a7570276798e69e",
|
||||
"timestamp": "2024-09-14T13:41:58Z"
|
||||
},
|
||||
{
|
||||
"version": "1.3.1.0",
|
||||
"changelog": "Add support for Jellyfin 10.9.1\n",
|
||||
"targetAbi": "10.9.1.0",
|
||||
"sourceUrl": "https://github.com/tubearchivist/tubearchivist-jf-plugin/releases/download/v1.3.1/tubearchivistmetadata_1.3.1.0.zip",
|
||||
"checksum": "b0b526bbd1702970108e3b9a8c3709de",
|
||||
"timestamp": "2024-09-12T13:36:12Z"
|
||||
},
|
||||
{
|
||||
"version": "1.3.0.0",
|
||||
"changelog": "Add support for Jellyfin 10.9.1\n",
|
||||
|
||||
Reference in New Issue
Block a user