mirror of
https://github.com/jellyfin/jellyfin.git
synced 2025-07-31 14:33:54 -04:00
Merge pull request #3086 from redSpoutnik/api-upload-subtitle
Add Post subtitle in API
This commit is contained in:
commit
96dcd9c87e
@ -11,6 +11,7 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Jellyfin.Api.Attributes;
|
using Jellyfin.Api.Attributes;
|
||||||
using Jellyfin.Api.Constants;
|
using Jellyfin.Api.Constants;
|
||||||
|
using Jellyfin.Api.Models.SubtitleDtos;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
using MediaBrowser.Controller.Library;
|
using MediaBrowser.Controller.Library;
|
||||||
using MediaBrowser.Controller.MediaEncoding;
|
using MediaBrowser.Controller.MediaEncoding;
|
||||||
@ -319,6 +320,33 @@ namespace Jellyfin.Api.Controllers
|
|||||||
return File(Encoding.UTF8.GetBytes(builder.ToString()), MimeTypes.GetMimeType("playlist.m3u8"));
|
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>
|
/// <summary>
|
||||||
/// Encodes a subtitle in the specified format.
|
/// Encodes a subtitle in the specified format.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
34
Jellyfin.Api/Models/SubtitleDtos/UploadSubtitleDto.cs
Normal file
34
Jellyfin.Api/Models/SubtitleDtos/UploadSubtitleDto.cs
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using MediaBrowser.Controller.Entities;
|
using MediaBrowser.Controller.Entities;
|
||||||
@ -52,6 +53,14 @@ namespace MediaBrowser.Controller.Subtitles
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
Task DownloadSubtitles(Video video, LibraryOptions libraryOptions, string subtitleId, CancellationToken cancellationToken);
|
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>
|
/// <summary>
|
||||||
/// Gets the remote subtitles.
|
/// Gets the remote subtitles.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -150,37 +150,11 @@ namespace MediaBrowser.Providers.Subtitles
|
|||||||
var parts = subtitleId.Split(new[] { '_' }, 2);
|
var parts = subtitleId.Split(new[] { '_' }, 2);
|
||||||
var provider = GetProvider(parts[0]);
|
var provider = GetProvider(parts[0]);
|
||||||
|
|
||||||
var saveInMediaFolder = libraryOptions.SaveSubtitlesWithMedia;
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var response = await GetRemoteSubtitles(subtitleId, cancellationToken).ConfigureAwait(false);
|
var response = await GetRemoteSubtitles(subtitleId, cancellationToken).ConfigureAwait(false);
|
||||||
|
|
||||||
using (var stream = response.Stream)
|
await TrySaveSubtitle(video, libraryOptions, response).ConfigureAwait(false);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
catch (RateLimitExceededException)
|
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)
|
private async Task TrySaveToFiles(Stream stream, List<string> savePaths)
|
||||||
{
|
{
|
||||||
Exception exceptionToThrow = null;
|
Exception exceptionToThrow = null;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user