aboutsummaryrefslogtreecommitdiff
path: root/MediaBrowser.Api/Subtitles/SubtitleService.cs
diff options
context:
space:
mode:
Diffstat (limited to 'MediaBrowser.Api/Subtitles/SubtitleService.cs')
-rw-r--r--MediaBrowser.Api/Subtitles/SubtitleService.cs82
1 files changed, 78 insertions, 4 deletions
diff --git a/MediaBrowser.Api/Subtitles/SubtitleService.cs b/MediaBrowser.Api/Subtitles/SubtitleService.cs
index 3e692cb22..dc5799239 100644
--- a/MediaBrowser.Api/Subtitles/SubtitleService.cs
+++ b/MediaBrowser.Api/Subtitles/SubtitleService.cs
@@ -1,6 +1,4 @@
-using System.IO;
-using System.Linq;
-using MediaBrowser.Controller.Entities;
+using MediaBrowser.Controller.Entities;
using MediaBrowser.Controller.Library;
using MediaBrowser.Controller.MediaEncoding;
using MediaBrowser.Controller.Net;
@@ -11,6 +9,10 @@ using MediaBrowser.Model.Providers;
using ServiceStack;
using System;
using System.Collections.Generic;
+using System.Globalization;
+using System.IO;
+using System.Linq;
+using System.Text;
using System.Threading;
using System.Threading.Tasks;
@@ -69,7 +71,8 @@ namespace MediaBrowser.Api.Subtitles
public string Id { get; set; }
}
- [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format (vtt).")]
+ [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format.")]
+ [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/{StartPositionTicks}/Stream.{Format}", "GET", Summary = "Gets subtitles in a specified format.")]
public class GetSubtitle
{
/// <summary>
@@ -90,6 +93,29 @@ namespace MediaBrowser.Api.Subtitles
[ApiMember(Name = "StartPositionTicks", Description = "StartPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
public long StartPositionTicks { get; set; }
+
+ [ApiMember(Name = "EndPositionTicks", Description = "EndPositionTicks", IsRequired = false, DataType = "string", ParameterType = "query", Verb = "GET")]
+ public long? EndPositionTicks { get; set; }
+ }
+
+ [Route("/Videos/{Id}/{MediaSourceId}/Subtitles/{Index}/subtitles.m3u8", "GET", Summary = "Gets an HLS subtitle playlist.")]
+ public class GetSubtitlePlaylist
+ {
+ /// <summary>
+ /// Gets or sets the id.
+ /// </summary>
+ /// <value>The id.</value>
+ [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string Id { get; set; }
+
+ [ApiMember(Name = "MediaSourceId", Description = "MediaSourceId", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")]
+ public string MediaSourceId { get; set; }
+
+ [ApiMember(Name = "Index", Description = "The subtitle stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
+ public int Index { get; set; }
+
+ [ApiMember(Name = "SegmentLength", Description = "The subtitle srgment length", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")]
+ public int SegmentLength { get; set; }
}
public class SubtitleService : BaseApiService
@@ -105,6 +131,53 @@ namespace MediaBrowser.Api.Subtitles
_subtitleEncoder = subtitleEncoder;
}
+ public object Get(GetSubtitlePlaylist request)
+ {
+ var item = (Video)_libraryManager.GetItemById(new Guid(request.Id));
+
+ var mediaSource = item.GetMediaSources(false)
+ .First(i => string.Equals(i.Id, request.MediaSourceId ?? request.Id));
+
+ var builder = new StringBuilder();
+
+ var runtime = mediaSource.RunTimeTicks ?? -1;
+
+ if (runtime <= 0)
+ {
+ throw new ArgumentException("HLS Subtitles are not supported for this media.");
+ }
+
+ builder.AppendLine("#EXTM3U");
+ builder.AppendLine("#EXT-X-TARGETDURATION:" + request.SegmentLength.ToString(CultureInfo.InvariantCulture));
+ builder.AppendLine("#EXT-X-VERSION:3");
+ builder.AppendLine("#EXT-X-MEDIA-SEQUENCE:0");
+
+ long positionTicks = 0;
+ var segmentLengthTicks = TimeSpan.FromSeconds(request.SegmentLength).Ticks;
+
+ while (positionTicks < runtime)
+ {
+ var remaining = runtime - positionTicks;
+ var lengthTicks = Math.Min(remaining, segmentLengthTicks);
+
+ builder.AppendLine("#EXTINF:" + TimeSpan.FromTicks(lengthTicks).TotalSeconds.ToString(CultureInfo.InvariantCulture));
+
+ var endPositionTicks = Math.Min(runtime, positionTicks + segmentLengthTicks);
+
+ var url = string.Format("stream.srt?StartPositionTicks={0}&EndPositionTicks={1}",
+ positionTicks.ToString(CultureInfo.InvariantCulture),
+ endPositionTicks.ToString(CultureInfo.InvariantCulture));
+
+ builder.AppendLine(url);
+
+ positionTicks += segmentLengthTicks;
+ }
+
+ builder.AppendLine("#EXT-X-ENDLIST");
+
+ return ResultFactory.GetResult(builder.ToString(), Common.Net.MimeTypes.GetMimeType("playlist.m3u8"), new Dictionary<string, string>());
+ }
+
public object Get(GetSubtitle request)
{
if (string.IsNullOrEmpty(request.Format))
@@ -132,6 +205,7 @@ namespace MediaBrowser.Api.Subtitles
request.Index,
request.Format,
request.StartPositionTicks,
+ request.EndPositionTicks,
CancellationToken.None).ConfigureAwait(false);
}