Browse Source

Merge pull request #3086 from redSpoutnik/api-upload-subtitle

Add Post subtitle in API
Claus Vium 4 years ago
parent
commit
96dcd9c87e

+ 28 - 0
Jellyfin.Api/Controllers/SubtitleController.cs

@@ -11,6 +11,7 @@ using System.Threading;
 using System.Threading.Tasks;
 using Jellyfin.Api.Attributes;
 using Jellyfin.Api.Constants;
+using Jellyfin.Api.Models.SubtitleDtos;
 using MediaBrowser.Controller.Entities;
 using MediaBrowser.Controller.Library;
 using MediaBrowser.Controller.MediaEncoding;
@@ -319,6 +320,33 @@ namespace Jellyfin.Api.Controllers
             return File(Encoding.UTF8.GetBytes(builder.ToString()), MimeTypes.GetMimeType("playlist.m3u8"));
         }
 
+        /// <summary>
+        /// Upload an external subtitle file.
+        /// </summary>
+        /// <param name="itemId">The item the subtitle belongs to.</param>
+        /// <param name="body">The request body.</param>
+        /// <response code="204">Subtitle uploaded.</response>
+        /// <returns>A <see cref="NoContentResult"/>.</returns>
+        [HttpPost("Videos/{itemId}/Subtitles")]
+        public async Task<ActionResult> UploadSubtitle(
+            [FromRoute, Required] Guid itemId,
+            [FromBody, Required] UploadSubtitleDto body)
+        {
+            var video = (Video)_libraryManager.GetItemById(itemId);
+            var data = Convert.FromBase64String(body.Data);
+            await using var memoryStream = new MemoryStream(data);
+            await _subtitleManager.UploadSubtitle(
+                video,
+                new SubtitleResponse
+                {
+                    Format = body.Format,
+                    Language = body.Language,
+                    IsForced = body.IsForced,
+                    Stream = memoryStream
+                }).ConfigureAwait(false);
+            return NoContent();
+        }
+
         /// <summary>
         /// Encodes a subtitle in the specified format.
         /// </summary>

+ 34 - 0
Jellyfin.Api/Models/SubtitleDtos/UploadSubtitleDto.cs

@@ -0,0 +1,34 @@
+using System.ComponentModel.DataAnnotations;
+
+namespace Jellyfin.Api.Models.SubtitleDtos
+{
+    /// <summary>
+    /// Upload subtitles dto.
+    /// </summary>
+    public class UploadSubtitleDto
+    {
+        /// <summary>
+        /// Gets or sets the subtitle language.
+        /// </summary>
+        [Required]
+        public string Language { get; set; } = string.Empty;
+
+        /// <summary>
+        /// Gets or sets the subtitle format.
+        /// </summary>
+        [Required]
+        public string Format { get; set; } = string.Empty;
+
+        /// <summary>
+        /// Gets or sets a value indicating whether the subtitle is forced.
+        /// </summary>
+        [Required]
+        public bool IsForced { get; set; }
+
+        /// <summary>
+        /// Gets or sets the subtitle data.
+        /// </summary>
+        [Required]
+        public string Data { get; set; } = string.Empty;
+    }
+}

+ 9 - 0
MediaBrowser.Controller/Subtitles/ISubtitleManager.cs

@@ -2,6 +2,7 @@
 
 using System;
 using System.Collections.Generic;
+using System.IO;
 using System.Threading;
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Entities;
@@ -52,6 +53,14 @@ namespace MediaBrowser.Controller.Subtitles
         /// </summary>
         Task DownloadSubtitles(Video video, LibraryOptions libraryOptions, string subtitleId, CancellationToken cancellationToken);
 
+        /// <summary>
+        /// Upload new subtitle.
+        /// </summary>
+        /// <param name="video">The video the subtitle belongs to.</param>
+        /// <param name="response">The subtitle response.</param>
+        /// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
+        Task UploadSubtitle(Video video, SubtitleResponse response);
+
         /// <summary>
         /// Gets the remote subtitles.
         /// </summary>

+ 42 - 27
MediaBrowser.Providers/Subtitles/SubtitleManager.cs

@@ -150,37 +150,11 @@ namespace MediaBrowser.Providers.Subtitles
             var parts = subtitleId.Split(new[] { '_' }, 2);
             var provider = GetProvider(parts[0]);
 
-            var saveInMediaFolder = libraryOptions.SaveSubtitlesWithMedia;
-
             try
             {
                 var response = await GetRemoteSubtitles(subtitleId, cancellationToken).ConfigureAwait(false);
 
-                using (var stream = response.Stream)
-                using (var memoryStream = new MemoryStream())
-                {
-                    await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
-                    memoryStream.Position = 0;
-
-                    var savePaths = new List<string>();
-                    var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLowerInvariant();
-
-                    if (response.IsForced)
-                    {
-                        saveFileName += ".forced";
-                    }
-
-                    saveFileName += "." + response.Format.ToLowerInvariant();
-
-                    if (saveInMediaFolder)
-                    {
-                        savePaths.Add(Path.Combine(video.ContainingFolderPath, saveFileName));
-                    }
-
-                    savePaths.Add(Path.Combine(video.GetInternalMetadataPath(), saveFileName));
-
-                    await TrySaveToFiles(memoryStream, savePaths).ConfigureAwait(false);
-                }
+                await TrySaveSubtitle(video, libraryOptions, response).ConfigureAwait(false);
             }
             catch (RateLimitExceededException)
             {
@@ -199,6 +173,47 @@ namespace MediaBrowser.Providers.Subtitles
             }
         }
 
+        /// <inheritdoc />
+        public Task UploadSubtitle(Video video, SubtitleResponse response)
+        {
+            var libraryOptions = BaseItem.LibraryManager.GetLibraryOptions(video);
+            return TrySaveSubtitle(video, libraryOptions, response);
+        }
+
+        private async Task TrySaveSubtitle(
+            Video video,
+            LibraryOptions libraryOptions,
+            SubtitleResponse response)
+        {
+            var saveInMediaFolder = libraryOptions.SaveSubtitlesWithMedia;
+
+            using (var stream = response.Stream)
+            using (var memoryStream = new MemoryStream())
+            {
+                await stream.CopyToAsync(memoryStream).ConfigureAwait(false);
+                memoryStream.Position = 0;
+
+                var savePaths = new List<string>();
+                var saveFileName = Path.GetFileNameWithoutExtension(video.Path) + "." + response.Language.ToLowerInvariant();
+
+                if (response.IsForced)
+                {
+                    saveFileName += ".forced";
+                }
+
+                saveFileName += "." + response.Format.ToLowerInvariant();
+
+                if (saveInMediaFolder)
+                {
+                    savePaths.Add(Path.Combine(video.ContainingFolderPath, saveFileName));
+                }
+
+                savePaths.Add(Path.Combine(video.GetInternalMetadataPath(), saveFileName));
+
+                await TrySaveToFiles(memoryStream, savePaths).ConfigureAwait(false);
+            }
+        }
+
         private async Task TrySaveToFiles(Stream stream, List<string> savePaths)
         {
             Exception exceptionToThrow = null;