SubtitleEditParser.cs 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Globalization;
  4. using System.IO;
  5. using System.Linq;
  6. using Jellyfin.Extensions;
  7. using MediaBrowser.Model.MediaInfo;
  8. using Microsoft.Extensions.Logging;
  9. using Nikse.SubtitleEdit.Core.Common;
  10. using SubtitleFormat = Nikse.SubtitleEdit.Core.SubtitleFormats.SubtitleFormat;
  11. namespace MediaBrowser.MediaEncoding.Subtitles
  12. {
  13. /// <summary>
  14. /// SubStation Alpha subtitle parser.
  15. /// </summary>
  16. public class SubtitleEditParser : ISubtitleParser
  17. {
  18. private readonly ILogger<SubtitleEditParser> _logger;
  19. private readonly Dictionary<string, List<Type>> _subtitleFormatTypes;
  20. /// <summary>
  21. /// Initializes a new instance of the <see cref="SubtitleEditParser"/> class.
  22. /// </summary>
  23. /// <param name="logger">The logger.</param>
  24. public SubtitleEditParser(ILogger<SubtitleEditParser> logger)
  25. {
  26. _logger = logger;
  27. _subtitleFormatTypes = GetSubtitleFormatTypes();
  28. }
  29. /// <inheritdoc />
  30. public SubtitleTrackInfo Parse(Stream stream, string fileExtension)
  31. {
  32. var subtitle = new Subtitle();
  33. var lines = stream.ReadAllLines().ToList();
  34. if (!_subtitleFormatTypes.TryGetValue(fileExtension, out var subtitleFormatTypesForExtension))
  35. {
  36. throw new ArgumentException($"Unsupported file extension: {fileExtension}", nameof(fileExtension));
  37. }
  38. foreach (var subtitleFormatType in subtitleFormatTypesForExtension)
  39. {
  40. var subtitleFormat = (SubtitleFormat)Activator.CreateInstance(subtitleFormatType, true)!;
  41. _logger.LogDebug(
  42. "Trying to parse '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser",
  43. fileExtension,
  44. subtitleFormat.Name);
  45. subtitleFormat.LoadSubtitle(subtitle, lines, fileExtension);
  46. if (subtitleFormat.ErrorCount == 0)
  47. {
  48. break;
  49. }
  50. else if (subtitleFormat.TryGetErrors(out var errors))
  51. {
  52. _logger.LogError(
  53. "{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser, errors: {Errors}",
  54. subtitleFormat.ErrorCount,
  55. fileExtension,
  56. subtitleFormat.Name,
  57. errors);
  58. }
  59. else
  60. {
  61. _logger.LogError(
  62. "{ErrorCount} errors encountered while parsing '{FileExtension}' subtitle using the {SubtitleFormatParser} format parser",
  63. subtitleFormat.ErrorCount,
  64. fileExtension,
  65. subtitleFormat.Name);
  66. }
  67. }
  68. if (subtitle.Paragraphs.Count == 0)
  69. {
  70. throw new ArgumentException("Unsupported format: " + fileExtension);
  71. }
  72. var trackInfo = new SubtitleTrackInfo();
  73. int len = subtitle.Paragraphs.Count;
  74. var trackEvents = new SubtitleTrackEvent[len];
  75. for (int i = 0; i < len; i++)
  76. {
  77. var p = subtitle.Paragraphs[i];
  78. trackEvents[i] = new SubtitleTrackEvent(p.Number.ToString(CultureInfo.InvariantCulture), p.Text)
  79. {
  80. StartPositionTicks = p.StartTime.TimeSpan.Ticks,
  81. EndPositionTicks = p.EndTime.TimeSpan.Ticks
  82. };
  83. }
  84. trackInfo.TrackEvents = trackEvents;
  85. return trackInfo;
  86. }
  87. /// <inheritdoc />
  88. public bool SupportsFileExtension(string fileExtension)
  89. => _subtitleFormatTypes.ContainsKey(fileExtension);
  90. private Dictionary<string, List<Type>> GetSubtitleFormatTypes()
  91. {
  92. var subtitleFormatTypes = new Dictionary<string, List<Type>>(StringComparer.OrdinalIgnoreCase);
  93. var assembly = typeof(SubtitleFormat).Assembly;
  94. foreach (var type in assembly.GetTypes())
  95. {
  96. if (!type.IsSubclassOf(typeof(SubtitleFormat)) || type.IsAbstract)
  97. {
  98. continue;
  99. }
  100. try
  101. {
  102. var tempInstance = (SubtitleFormat)Activator.CreateInstance(type, true)!;
  103. var extension = tempInstance.Extension.TrimStart('.');
  104. if (!string.IsNullOrEmpty(extension))
  105. {
  106. // Store only the type, we will instantiate from it later
  107. if (!subtitleFormatTypes.TryGetValue(extension, out var subtitleFormatTypesForExtension))
  108. {
  109. subtitleFormatTypes[extension] = [type];
  110. }
  111. else
  112. {
  113. subtitleFormatTypesForExtension.Add(type);
  114. }
  115. }
  116. }
  117. catch (Exception ex)
  118. {
  119. _logger.LogWarning(ex, "Failed to create instance of the subtitle format {SubtitleFormatType}", type.Name);
  120. }
  121. }
  122. return subtitleFormatTypes;
  123. }
  124. }
  125. }