mirror of
https://github.com/jellyfin/jellyfin-plugin-reports.git
synced 2024-11-22 21:29:50 +00:00
10.9 (#82)
This commit is contained in:
parent
e9dfdc7c3b
commit
946a9e4144
@ -238,9 +238,8 @@ namespace Jellyfin.Plugin.Reports.Api.Common
|
||||
protected string GetSeriesProductionYear(BaseItem item)
|
||||
{
|
||||
|
||||
string productionYear = item.ProductionYear.ToString();
|
||||
var series = item as Series;
|
||||
if (series == null)
|
||||
string productionYear = item.ProductionYear?.ToString(CultureInfo.InvariantCulture);
|
||||
if (item is not Series series)
|
||||
{
|
||||
if (item.ProductionYear == null || item.ProductionYear == 0)
|
||||
return string.Empty;
|
||||
@ -248,10 +247,10 @@ namespace Jellyfin.Plugin.Reports.Api.Common
|
||||
}
|
||||
|
||||
if (series.Status == SeriesStatus.Continuing)
|
||||
return productionYear += "-Present";
|
||||
return productionYear + "-Present";
|
||||
|
||||
if (series.EndDate != null && series.EndDate.Value.Year != series.ProductionYear)
|
||||
return productionYear += "-" + series.EndDate.Value.Year;
|
||||
return productionYear + "-" + series.EndDate.Value.Year;
|
||||
|
||||
return productionYear;
|
||||
}
|
||||
@ -298,8 +297,8 @@ namespace Jellyfin.Plugin.Reports.Api.Common
|
||||
MediaStreamType.Video);
|
||||
if (stream != null && stream.Width != null)
|
||||
return string.Format(CultureInfo.InvariantCulture, "{0} * {1}",
|
||||
stream.Width,
|
||||
stream.Height != null ? stream.Height.ToString() : "-");
|
||||
stream.Width,
|
||||
stream.Height?.ToString(CultureInfo.InvariantCulture) ?? "-");
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
#nullable disable
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using Jellyfin.Plugin.Reports.Api.Common;
|
||||
using Jellyfin.Plugin.Reports.Api.Model;
|
||||
@ -389,7 +390,7 @@ namespace Jellyfin.Plugin.Reports.Api.Data
|
||||
break;
|
||||
|
||||
case HeaderMetadata.SeasonNumber:
|
||||
option.Column = (i, r) => this.GetObject<Season, string>(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber.ToString());
|
||||
option.Column = (i, r) => this.GetObject<Season, string>(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber?.ToString(CultureInfo.InvariantCulture));
|
||||
option.Header.SortField = "IndexNumber";
|
||||
option.Header.HeaderFieldType = ReportFieldType.Int;
|
||||
break;
|
||||
@ -429,7 +430,7 @@ namespace Jellyfin.Plugin.Reports.Api.Data
|
||||
break;
|
||||
|
||||
case HeaderMetadata.EpisodeNumber:
|
||||
option.Column = (i, r) => this.GetObject<BaseItem, string>(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber.ToString());
|
||||
option.Column = (i, r) => this.GetObject<BaseItem, string>(i, (x) => x.IndexNumber == null ? "" : x.IndexNumber?.ToString(CultureInfo.InvariantCulture));
|
||||
//option.Header.SortField = "IndexNumber";
|
||||
//option.Header.HeaderFieldType = ReportFieldType.Int;
|
||||
break;
|
||||
|
@ -21,7 +21,7 @@ namespace Jellyfin.Plugin.Reports.Api.Data
|
||||
static string EscapeText(string text)
|
||||
{
|
||||
string escapedText = text.Replace("\"", "\"\"", System.StringComparison.Ordinal);
|
||||
return text.IndexOfAny(new char[4] { '"', ',', '\n', '\r' }) == -1 ? escapedText : $"\"{escapedText}\"";
|
||||
return text.IndexOfAny(['"', ',', '\n', '\r']) == -1 ? escapedText : $"\"{escapedText}\"";
|
||||
}
|
||||
static void AppendRows(StreamWriter writer, List<ReportRow> rows)
|
||||
{
|
||||
@ -153,7 +153,7 @@ namespace Jellyfin.Plugin.Reports.Api.Data
|
||||
nextRow += rows.Count();
|
||||
}
|
||||
|
||||
using IXLWorkbook workbook = new XLWorkbook(XLEventTracking.Disabled);
|
||||
using var workbook = new XLWorkbook(XLEventTracking.Disabled);
|
||||
IXLWorksheet worksheet = workbook.Worksheets.Add("ReportExport");
|
||||
|
||||
// Add report rows
|
||||
|
@ -3,6 +3,7 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using Jellyfin.Data.Enums;
|
||||
using Jellyfin.Plugin.Reports.Api.Common;
|
||||
using MediaBrowser.Model.Entities;
|
||||
@ -94,7 +95,7 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
public bool? HasTrailer { get; set; }
|
||||
|
||||
// [ApiMember(Name = "AdjacentTo", Description = "Optional. Return items that are siblings of a supplied item.", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
|
||||
public string AdjacentTo { get; set; }
|
||||
public Guid? AdjacentTo { get; set; }
|
||||
|
||||
// [ApiMember(Name = "MinIndexNumber", Description = "Optional filter by minimum index number.", IsRequired = false, DataType = "int", ParameterType = "query", Verb = "GET")]
|
||||
public int? MinIndexNumber { get; set; }
|
||||
@ -403,46 +404,50 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
|
||||
public string[] GetGenres()
|
||||
{
|
||||
return (Genres ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (Genres ?? string.Empty).Split( '|', StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetTags()
|
||||
{
|
||||
return (Tags ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (Tags ?? string.Empty).Split('|', StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetOfficialRatings()
|
||||
{
|
||||
return (OfficialRatings ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (OfficialRatings ?? string.Empty).Split('|', StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public string[] GetMediaTypes()
|
||||
public MediaType[] GetMediaTypes()
|
||||
{
|
||||
return (MediaTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (MediaTypes ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries)
|
||||
.Select(r => Enum.TryParse(r, out MediaType mt) ? mt : (MediaType?)null)
|
||||
.Where(r => r is not null)
|
||||
.Select(r => r.Value)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public BaseItemKind[] GetIncludeItemTypes() => GetBaseItemKinds(IncludeItemTypes);
|
||||
|
||||
public string[] GetExcludeItemIds()
|
||||
{
|
||||
return (ExcludeItemIds ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (ExcludeItemIds ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public BaseItemKind[] GetExcludeItemTypes() => GetBaseItemKinds(ExcludeItemTypes);
|
||||
|
||||
public int[] GetYears()
|
||||
{
|
||||
return (Years ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
|
||||
return (Years ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray();
|
||||
}
|
||||
|
||||
public Guid[] GetGuids(string value)
|
||||
{
|
||||
return (value ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(i => new Guid(i)).ToArray();
|
||||
return (value ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries).Select(i => new Guid(i)).ToArray();
|
||||
}
|
||||
|
||||
public string[] GetStudios()
|
||||
{
|
||||
return (Studios ?? string.Empty).Split(new[] { '|' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (Studios ?? string.Empty).Split('|', StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public Guid[] GetArtistIds()
|
||||
@ -462,7 +467,7 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
|
||||
public string[] GetPersonTypes()
|
||||
{
|
||||
return (PersonTypes ?? string.Empty).Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
|
||||
return (PersonTypes ?? string.Empty).Split(',', StringSplitOptions.RemoveEmptyEntries);
|
||||
}
|
||||
|
||||
public Guid[] GetPersonIds()
|
||||
@ -484,7 +489,7 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
return Array.Empty<VideoType>();
|
||||
}
|
||||
|
||||
return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
|
||||
return val.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(v => (VideoType)Enum.Parse(typeof(VideoType), v, true)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -500,7 +505,7 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
return Array.Empty<ItemFilter>();
|
||||
}
|
||||
|
||||
return val.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries).Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true)).ToArray();
|
||||
return val.Split(',', StringSplitOptions.RemoveEmptyEntries).Select(v => (ItemFilter)Enum.Parse(typeof(ItemFilter), v, true)).ToArray();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -523,18 +528,18 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
/// Gets the order by.
|
||||
/// </summary>
|
||||
/// <returns>IEnumerable{ItemSortBy}.</returns>
|
||||
public ValueTuple<string, SortOrder>[] GetOrderBy()
|
||||
public ValueTuple<ItemSortBy, SortOrder>[] GetOrderBy()
|
||||
{
|
||||
return GetOrderBy(SortBy, SortOrder);
|
||||
}
|
||||
|
||||
public static (string, SortOrder)[] GetOrderBy(string sortBy, string requestedSortOrder)
|
||||
public static (ItemSortBy, SortOrder)[] GetOrderBy(string sortBy, string requestedSortOrder)
|
||||
{
|
||||
var val = sortBy;
|
||||
|
||||
if (string.IsNullOrEmpty(val))
|
||||
{
|
||||
return Array.Empty<(string, SortOrder)>();
|
||||
return Array.Empty<(ItemSortBy, SortOrder)>();
|
||||
}
|
||||
|
||||
var vals = val.Split(',');
|
||||
@ -545,16 +550,21 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
|
||||
var sortOrders = requestedSortOrder.Split(',');
|
||||
|
||||
var result = new (string, SortOrder)[vals.Length];
|
||||
var result = new (ItemSortBy, SortOrder)[vals.Length];
|
||||
|
||||
for (var i = 0; i < vals.Length; i++)
|
||||
{
|
||||
if (!Enum.TryParse(vals[i], out ItemSortBy currentSortBy))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var sortOrderIndex = sortOrders.Length > i ? i : 0;
|
||||
|
||||
var sortOrderValue = sortOrders.Length > sortOrderIndex ? sortOrders[sortOrderIndex] : null;
|
||||
var sortOrder = string.Equals(sortOrderValue, "Descending", StringComparison.OrdinalIgnoreCase) ? Jellyfin.Data.Enums.SortOrder.Descending : Jellyfin.Data.Enums.SortOrder.Ascending;
|
||||
|
||||
result[i] = (vals[i], sortOrder);
|
||||
result[i] = (currentSortBy, sortOrder);
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1,4 +1,5 @@
|
||||
using System.Net.Mime;
|
||||
using System;
|
||||
using System.Net.Mime;
|
||||
using System.Threading.Tasks;
|
||||
using Jellyfin.Plugin.Reports.Api.Common;
|
||||
using Jellyfin.Plugin.Reports.Api.Model;
|
||||
@ -6,13 +7,14 @@ using MediaBrowser.Controller.Library;
|
||||
using MediaBrowser.Model.Activity;
|
||||
using MediaBrowser.Model.Globalization;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
namespace Jellyfin.Plugin.Reports.Api
|
||||
{
|
||||
[ApiController]
|
||||
[Route("[controller]")]
|
||||
[Authorize(Policy = "DefaultAuthorization")]
|
||||
[Authorize]
|
||||
[Produces(MediaTypeNames.Application.Json)]
|
||||
public class ReportsController : ControllerBase
|
||||
{
|
||||
@ -37,7 +39,7 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
[FromQuery] bool? hasSubtitles,
|
||||
[FromQuery] bool? hasSpecialFeature,
|
||||
[FromQuery] bool? hasTrailer,
|
||||
[FromQuery] string? adjacentTo,
|
||||
[FromQuery] Guid? adjacentTo,
|
||||
[FromQuery] int? minIndexNumber,
|
||||
[FromQuery] int? parentIndexNumber,
|
||||
[FromQuery] bool? hasParentalRating,
|
||||
@ -260,7 +262,7 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
[FromQuery] bool? hasSubtitles,
|
||||
[FromQuery] bool? hasSpecialFeature,
|
||||
[FromQuery] bool? hasTrailer,
|
||||
[FromQuery] string? adjacentTo,
|
||||
[FromQuery] Guid? adjacentTo,
|
||||
[FromQuery] int? minIndexNumber,
|
||||
[FromQuery] int? parentIndexNumber,
|
||||
[FromQuery] bool? hasParentalRating,
|
||||
@ -427,7 +429,7 @@ namespace Jellyfin.Plugin.Reports.Api
|
||||
|
||||
foreach (var (key, value) in headers)
|
||||
{
|
||||
Response.Headers.Add(key, value);
|
||||
Response.Headers.Append(key, value);
|
||||
}
|
||||
|
||||
return File(content, contentType);
|
||||
|
@ -1,7 +1,7 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net6.0</TargetFramework>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<RootNamespace>Jellyfin.Plugin.Reports</RootNamespace>
|
||||
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
|
||||
<CodeAnalysisRuleSet>../jellyfin.ruleset</CodeAnalysisRuleSet>
|
||||
|
15
build.yaml
15
build.yaml
@ -3,8 +3,8 @@ name: "Reports"
|
||||
guid: "d4312cd9-5c90-4f38-82e8-51da566790e8"
|
||||
imageUrl: "https://repo.jellyfin.org/releases/plugin/images/jellyfin-plugin-reports.png"
|
||||
version: 15
|
||||
targetAbi: "10.8.1.0"
|
||||
framework: "net6.0"
|
||||
targetAbi: "10.9.0.0"
|
||||
framework: "net8.0"
|
||||
owner: "jellyfin"
|
||||
overview: "Generate reports of your media library"
|
||||
description: "Generate reports of your media library"
|
||||
@ -16,14 +16,3 @@ artifacts:
|
||||
- "ExcelNumberFormat.dll"
|
||||
- "System.IO.Packaging.dll"
|
||||
changelog: |2-
|
||||
### Bug Fixes ###
|
||||
- Fix CSV Export Format (#73) @mwildgoose
|
||||
|
||||
### Code or Repo Maintenance ###
|
||||
- Use meta ci (#66) @crobibero
|
||||
- Performance improvements (#59) @Bond-009
|
||||
- Style fixes, enable analysis and nullable (#57) @Bond-009
|
||||
|
||||
### CI & build changes ###
|
||||
- fix: meta ci workflows (#68) @h1dden-da3m0n
|
||||
- Use meta ci (#66) @crobibero
|
||||
|
Loading…
Reference in New Issue
Block a user