Move GetHlsPlaylist to ITrickplayManager

pull/9554/head
Nick 11 months ago
parent 0e2c362078
commit 619d1d47f2

@ -1,6 +1,5 @@
using System;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Net.Mime;
using System.Text;
using Jellyfin.Api.Attributes;
@ -54,7 +53,14 @@ public class TrickplayController : BaseJellyfinApiController
[FromRoute, Required] int width,
[FromQuery] Guid? mediaSourceId)
{
return GetTrickplayPlaylistInternal(width, mediaSourceId ?? itemId);
string? playlist = _trickplayManager.GetHlsPlaylist(mediaSourceId ?? itemId, width, User.GetToken());
if (string.IsNullOrEmpty(playlist))
{
return NotFound();
}
return new FileContentResult(Encoding.UTF8.GetBytes(playlist), MimeTypes.GetMimeType("playlist.m3u8"));
}
/// <summary>
@ -71,7 +77,7 @@ public class TrickplayController : BaseJellyfinApiController
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesImageFile]
public ActionResult GetTrickplayHlsPlaylist(
public ActionResult GetTrickplayGridImage(
[FromRoute, Required] Guid itemId,
[FromRoute, Required] int width,
[FromRoute, Required] int index,
@ -91,78 +97,4 @@ public class TrickplayController : BaseJellyfinApiController
return NotFound();
}
private ActionResult GetTrickplayPlaylistInternal(int width, Guid mediaSourceId)
{
var tilesResolutions = _trickplayManager.GetTilesResolutions(mediaSourceId);
if (tilesResolutions is not null && tilesResolutions.TryGetValue(width, out var tilesInfo))
{
var builder = new StringBuilder(128);
if (tilesInfo.TileCount > 0)
{
const string urlFormat = "Trickplay/{0}/{1}.jpg?MediaSourceId={2}&api_key={3}";
const string decimalFormat = "{0:0.###}";
var resolution = $"{tilesInfo.Width}x{tilesInfo.Height}";
var layout = $"{tilesInfo.TileWidth}x{tilesInfo.TileHeight}";
var tilesPerGrid = tilesInfo.TileWidth * tilesInfo.TileHeight;
var tileDuration = tilesInfo.Interval / 1000d;
var infDuration = tileDuration * tilesPerGrid;
var tileGridCount = (int)Math.Ceiling((decimal)tilesInfo.TileCount / tilesPerGrid);
builder
.AppendLine("#EXTM3U")
.Append("#EXT-X-TARGETDURATION:")
.AppendLine(tileGridCount.ToString(CultureInfo.InvariantCulture))
.AppendLine("#EXT-X-VERSION:7")
.AppendLine("#EXT-X-MEDIA-SEQUENCE:1")
.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD")
.AppendLine("#EXT-X-IMAGES-ONLY");
for (int i = 0; i < tileGridCount; i++)
{
// All tile grids before the last one must contain full amount of tiles.
// The final grid will be 0 < count <= maxTiles
if (i == tileGridCount - 1)
{
tilesPerGrid = tilesInfo.TileCount - (i * tilesPerGrid);
infDuration = tileDuration * tilesPerGrid;
}
// EXTINF
builder
.Append("#EXTINF:")
.AppendFormat(CultureInfo.InvariantCulture, decimalFormat, infDuration)
.AppendLine(",");
// EXT-X-TILES
builder
.Append("#EXT-X-TILES:RESOLUTION=")
.Append(resolution)
.Append(",LAYOUT=")
.Append(layout)
.Append(",DURATION=")
.AppendFormat(CultureInfo.InvariantCulture, decimalFormat, tileDuration)
.AppendLine();
// URL
builder
.AppendFormat(
CultureInfo.InvariantCulture,
urlFormat,
width.ToString(CultureInfo.InvariantCulture),
i.ToString(CultureInfo.InvariantCulture),
mediaSourceId.ToString("N"),
User.GetToken())
.AppendLine();
}
builder.AppendLine("#EXT-X-ENDLIST");
return new FileContentResult(Encoding.UTF8.GetBytes(builder.ToString()), MimeTypes.GetMimeType("playlist.m3u8"));
}
}
return NotFound();
}
}

@ -50,4 +50,13 @@ public interface ITrickplayManager
/// <param name="index">The tile grid's index.</param>
/// <returns>The absolute path.</returns>
string GetTrickplayTilePath(BaseItem item, int width, int index);
/// <summary>
/// Gets the trickplay HLS playlist.
/// </summary>
/// <param name="itemId">The item.</param>
/// <param name="width">The width of a single tile.</param>
/// <param name="apiKey">Optional api key of the requesting user.</param>
/// <returns>The text content of the .m3u8 playlist.</returns>
string? GetHlsPlaylist(Guid itemId, int width, string? apiKey);
}

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using MediaBrowser.Controller.Configuration;
@ -321,6 +322,81 @@ public class TrickplayManager : ITrickplayManager
return Path.Combine(GetTrickplayDirectory(item, width), index + ".jpg");
}
/// <inheritdoc />
public string? GetHlsPlaylist(Guid itemId, int width, string? apiKey)
{
var tilesResolutions = GetTilesResolutions(itemId);
if (tilesResolutions is not null && tilesResolutions.TryGetValue(width, out var tilesInfo))
{
var builder = new StringBuilder(128);
if (tilesInfo.TileCount > 0)
{
const string urlFormat = "Trickplay/{0}/{1}.jpg?MediaSourceId={2}&api_key={3}";
const string decimalFormat = "{0:0.###}";
var resolution = $"{tilesInfo.Width}x{tilesInfo.Height}";
var layout = $"{tilesInfo.TileWidth}x{tilesInfo.TileHeight}";
var tilesPerGrid = tilesInfo.TileWidth * tilesInfo.TileHeight;
var tileDuration = tilesInfo.Interval / 1000d;
var infDuration = tileDuration * tilesPerGrid;
var tileGridCount = (int)Math.Ceiling((decimal)tilesInfo.TileCount / tilesPerGrid);
builder
.AppendLine("#EXTM3U")
.Append("#EXT-X-TARGETDURATION:")
.AppendLine(tileGridCount.ToString(CultureInfo.InvariantCulture))
.AppendLine("#EXT-X-VERSION:7")
.AppendLine("#EXT-X-MEDIA-SEQUENCE:1")
.AppendLine("#EXT-X-PLAYLIST-TYPE:VOD")
.AppendLine("#EXT-X-IMAGES-ONLY");
for (int i = 0; i < tileGridCount; i++)
{
// All tile grids before the last one must contain full amount of tiles.
// The final grid will be 0 < count <= maxTiles
if (i == tileGridCount - 1)
{
tilesPerGrid = tilesInfo.TileCount - (i * tilesPerGrid);
infDuration = tileDuration * tilesPerGrid;
}
// EXTINF
builder
.Append("#EXTINF:")
.AppendFormat(CultureInfo.InvariantCulture, decimalFormat, infDuration)
.AppendLine(",");
// EXT-X-TILES
builder
.Append("#EXT-X-TILES:RESOLUTION=")
.Append(resolution)
.Append(",LAYOUT=")
.Append(layout)
.Append(",DURATION=")
.AppendFormat(CultureInfo.InvariantCulture, decimalFormat, tileDuration)
.AppendLine();
// URL
builder
.AppendFormat(
CultureInfo.InvariantCulture,
urlFormat,
width.ToString(CultureInfo.InvariantCulture),
i.ToString(CultureInfo.InvariantCulture),
itemId.ToString("N"),
apiKey)
.AppendLine();
}
builder.AppendLine("#EXT-X-ENDLIST");
return builder.ToString();
}
}
return null;
}
private string GetTrickplayDirectory(BaseItem item, int? width = null)
{
var path = Path.Combine(item.GetInternalMetadataPath(), "trickplay");

Loading…
Cancel
Save