mirror of https://github.com/jellyfin/jellyfin.git
Move GetHlsPlaylist to ITrickplayManager
This commit is contained in:
parent
0e2c362078
commit
619d1d47f2
|
@ -1,6 +1,5 @@
|
||||||
using System;
|
using System;
|
||||||
using System.ComponentModel.DataAnnotations;
|
using System.ComponentModel.DataAnnotations;
|
||||||
using System.Globalization;
|
|
||||||
using System.Net.Mime;
|
using System.Net.Mime;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Jellyfin.Api.Attributes;
|
using Jellyfin.Api.Attributes;
|
||||||
|
@ -54,7 +53,14 @@ public class TrickplayController : BaseJellyfinApiController
|
||||||
[FromRoute, Required] int width,
|
[FromRoute, Required] int width,
|
||||||
[FromQuery] Guid? mediaSourceId)
|
[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>
|
/// <summary>
|
||||||
|
@ -71,7 +77,7 @@ public class TrickplayController : BaseJellyfinApiController
|
||||||
[ProducesResponseType(StatusCodes.Status200OK)]
|
[ProducesResponseType(StatusCodes.Status200OK)]
|
||||||
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
[ProducesResponseType(StatusCodes.Status404NotFound)]
|
||||||
[ProducesImageFile]
|
[ProducesImageFile]
|
||||||
public ActionResult GetTrickplayHlsPlaylist(
|
public ActionResult GetTrickplayGridImage(
|
||||||
[FromRoute, Required] Guid itemId,
|
[FromRoute, Required] Guid itemId,
|
||||||
[FromRoute, Required] int width,
|
[FromRoute, Required] int width,
|
||||||
[FromRoute, Required] int index,
|
[FromRoute, Required] int index,
|
||||||
|
@ -91,78 +97,4 @@ public class TrickplayController : BaseJellyfinApiController
|
||||||
|
|
||||||
return NotFound();
|
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>
|
/// <param name="index">The tile grid's index.</param>
|
||||||
/// <returns>The absolute path.</returns>
|
/// <returns>The absolute path.</returns>
|
||||||
string GetTrickplayTilePath(BaseItem item, int width, int index);
|
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.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Configuration;
|
using MediaBrowser.Controller.Configuration;
|
||||||
|
@ -321,6 +322,81 @@ public class TrickplayManager : ITrickplayManager
|
||||||
return Path.Combine(GetTrickplayDirectory(item, width), index + ".jpg");
|
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)
|
private string GetTrickplayDirectory(BaseItem item, int? width = null)
|
||||||
{
|
{
|
||||||
var path = Path.Combine(item.GetInternalMetadataPath(), "trickplay");
|
var path = Path.Combine(item.GetInternalMetadataPath(), "trickplay");
|
||||||
|
|
Loading…
Reference in New Issue