From 321e5cba60825d5791730da75cd12905e97b527e Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 3 Oct 2019 11:51:28 -0400 Subject: Add new MediaAttachment to store attachments found during media probing. --- .../Probing/ProbeResultNormalizer.cs | 38 +++++++++++++++++++ MediaBrowser.Model/Dto/MediaSourceInfo.cs | 2 + MediaBrowser.Model/Entities/MediaAttachment.cs | 44 ++++++++++++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 MediaBrowser.Model/Entities/MediaAttachment.cs diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 54d02fc9f..2c001d775 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -49,6 +49,10 @@ namespace MediaBrowser.MediaEncoding.Probing .Where(i => i.Type != MediaStreamType.Subtitle || !string.IsNullOrWhiteSpace(i.Codec)) .ToList(); + info.MediaAttachments = internalStreams.Select(s => GetMediaAttachment(s)) + .Where(i => i != null) + .ToList(); + if (data.format != null) { info.Container = NormalizeFormat(data.format.format_name); @@ -513,6 +517,40 @@ namespace MediaBrowser.MediaEncoding.Probing return codec; } + /// + /// Converts ffprobe stream info to our MediaAttachment class + /// + /// The stream info. + /// MediaAttachments. + private MediaAttachment GetMediaAttachment(MediaStreamInfo streamInfo) + { + if (!string.Equals(streamInfo.codec_type, "attachment", StringComparison.OrdinalIgnoreCase)) + { + return null; + } + + var attachment = new MediaAttachment + { + Codec = streamInfo.codec_name, + Index = streamInfo.index + }; + + // Filter out junk + if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) + { + attachment.CodecTag = streamInfo.codec_tag_string; + } + + if (streamInfo.tags != null) + { + attachment.Filename = GetDictionaryValue(streamInfo.tags, "filename"); + attachment.MIMEType = GetDictionaryValue(streamInfo.tags, "mimetype"); + attachment.Comment = GetDictionaryValue(streamInfo.tags, "comment"); + } + + return attachment; + } + /// /// Converts ffprobe stream info to our MediaStream class /// diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 5bdc4809a..8a1aa55b6 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -57,6 +57,8 @@ namespace MediaBrowser.Model.Dto public List MediaStreams { get; set; } + public List MediaAttachments { get; set; } + public string[] Formats { get; set; } public int? Bitrate { get; set; } diff --git a/MediaBrowser.Model/Entities/MediaAttachment.cs b/MediaBrowser.Model/Entities/MediaAttachment.cs new file mode 100644 index 000000000..daabbe91d --- /dev/null +++ b/MediaBrowser.Model/Entities/MediaAttachment.cs @@ -0,0 +1,44 @@ +namespace MediaBrowser.Model.Entities +{ + /// + /// Class MediaAttachment + /// + public class MediaAttachment + { + /// + /// Gets or sets the codec. + /// + /// The codec. + public string Codec { get; set; } + + /// + /// Gets or sets the codec tag. + /// + /// The codec tag. + public string CodecTag { get; set; } + + /// + /// Gets or sets the comment. + /// + /// The comment. + public string Comment { get; set; } + + /// + /// Gets or sets the index. + /// + /// The index. + public int Index { get; set; } + + /// + /// Gets or sets the filename. + /// + /// The filename. + public string Filename { get; set; } + + /// + /// Gets or sets the MIME type. + /// + /// The MIME type. + public string MIMEType { get; set; } + } +} -- cgit v1.2.3 From 03ecf57548b3bd6058b9427ff48f06050725ad4a Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Fri, 4 Oct 2019 13:23:08 -0400 Subject: Store MediaAttachments in DB. --- .../Data/SqliteItemRepository.cs | 179 +++++++++++++++++++++ .../Persistence/IItemRepository.cs | 15 ++ .../Persistence/MediaAttachmentQuery.cs | 20 +++ .../MediaInfo/FFProbeVideoInfo.cs | 4 + 4 files changed, 218 insertions(+) create mode 100644 MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 31a661c5d..58f04e4fc 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -94,6 +94,8 @@ namespace Emby.Server.Implementations.Data { const string CreateMediaStreamsTableCommand = "create table if not exists mediastreams (ItemId GUID, StreamIndex INT, StreamType TEXT, Codec TEXT, Language TEXT, ChannelLayout TEXT, Profile TEXT, AspectRatio TEXT, Path TEXT, IsInterlaced BIT, BitRate INT NULL, Channels INT NULL, SampleRate INT NULL, IsDefault BIT, IsForced BIT, IsExternal BIT, Height INT NULL, Width INT NULL, AverageFrameRate FLOAT NULL, RealFrameRate FLOAT NULL, Level FLOAT NULL, PixelFormat TEXT, BitDepth INT NULL, IsAnamorphic BIT NULL, RefFrames INT NULL, CodecTag TEXT NULL, Comment TEXT NULL, NalLengthSize TEXT NULL, IsAvc BIT NULL, Title TEXT NULL, TimeBase TEXT NULL, CodecTimeBase TEXT NULL, ColorPrimaries TEXT NULL, ColorSpace TEXT NULL, ColorTransfer TEXT NULL, PRIMARY KEY (ItemId, StreamIndex))"; + const string CreateMediaAttachmentsTableCommand + = "create table if not exists mediaattachments (ItemId GUID, AttachmentIndex INT, Codec TEXT, CodecTag TEXT NULL, Comment TEXT NULL, Filename TEXT NULL, MIMEType TEXT NULL, PRIMARY KEY (ItemId, AttachmentIndex))"; string[] queries = { @@ -116,6 +118,7 @@ namespace Emby.Server.Implementations.Data "create table if not exists " + ChaptersTableName + " (ItemId GUID, ChapterIndex INT NOT NULL, StartPositionTicks BIGINT NOT NULL, Name TEXT, ImagePath TEXT, PRIMARY KEY (ItemId, ChapterIndex))", CreateMediaStreamsTableCommand, + CreateMediaAttachmentsTableCommand, "pragma shrink_memory" }; @@ -423,6 +426,17 @@ namespace Emby.Server.Implementations.Data "ColorTransfer" }; + private static readonly string[] _mediaAttachmentSaveColumns = + { + "ItemId", + "AttachmentIndex", + "Codec", + "CodecTag", + "Comment", + "Filename", + "MIMEType" + }; + private static string GetSaveItemCommandText() { var saveColumns = new [] @@ -6130,5 +6144,170 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type return item; } + + public List GetMediaAttachments(MediaAttachmentQuery query) + { + CheckDisposed(); + + if (query == null) + { + throw new ArgumentNullException(nameof(query)); + } + + var cmdText = "select " + + string.Join(",", _mediaAttachmentSaveColumns) + + " from mediaattachments where" + + " ItemId=@ItemId"; + + if (query.Index.HasValue) + { + cmdText += "AND AttachmentIndex=@AttachmentIndex"; + } + + cmdText += " order by AttachmentIndex ASC"; + + using (var connection = GetConnection(true)) + { + var list = new List(); + + using (var statement = PrepareStatement(connection, cmdText)) + { + statement.TryBind("@ItemId", query.ItemId.ToGuidBlob()); + + if (query.Index.HasValue) + { + statement.TryBind("@AttachmentIndex", query.Index.Value); + } + + foreach (var row in statement.ExecuteQuery()) { + list.Add(GetMediaAttachment(row)); + } + } + + return list; + } + } + + public void SaveMediaAttachments(Guid id, List attachments, CancellationToken cancellationToken) + { + CheckDisposed(); + if (id == Guid.Empty) + { + throw new ArgumentNullException(nameof(id)); + } + + if (attachments == null) + { + throw new ArgumentNullException(nameof(attachments)); + } + + using (var connection = GetConnection()) + { + connection.RunInTransaction(db => + { + var itemIdBlob = id.ToGuidBlob(); + + db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); + + InsertMediaAttachments(itemIdBlob, attachments, db); + + }, TransactionMode); + } + } + + private void InsertMediaAttachments(byte[] idBlob, List attachments, IDatabaseConnection db) + { + var startIndex = 0; + var limit = 10; + + while (startIndex < attachments.Count) + { + var insertText = new StringBuilder(string.Format("insert into mediaattachments ({0}) values ", string.Join(",", _mediaAttachmentSaveColumns))); + + var endIndex = Math.Min(attachments.Count, startIndex + limit); + + for (var i = startIndex; i < endIndex; i++) + { + if (i != startIndex) + { + insertText.Append(","); + } + + var index = i.ToString(CultureInfo.InvariantCulture); + insertText.Append("(@ItemId, "); + + foreach (var column in _mediaAttachmentSaveColumns.Skip(1)) + { + insertText.Append("@" + column + index + ","); + } + insertText.Length -= 1; + + insertText.Append(")"); + } + + using (var statement = PrepareStatement(db, insertText.ToString())) + { + statement.TryBind("@ItemId", idBlob); + + for (var i = startIndex; i < endIndex; i++) + { + var index = i.ToString(CultureInfo.InvariantCulture); + + var attachment = attachments[i]; + + statement.TryBind("@AttachmentIndex" + index, attachment.Index); + statement.TryBind("@Codec" + index, attachment.Codec); + statement.TryBind("@CodecTag" + index, attachment.CodecTag); + statement.TryBind("@Comment" + index, attachment.Comment); + statement.TryBind("@Filename" + index, attachment.Filename); + statement.TryBind("@MIMEType" + index, attachment.MIMEType); + } + + statement.Reset(); + statement.MoveNext(); + } + startIndex += limit; + } + } + + /// + /// Gets the attachment. + /// + /// The reader. + /// MediaAttachment + private MediaAttachment GetMediaAttachment(IReadOnlyList reader) + { + var item = new MediaAttachment + { + Index = reader[1].ToInt() + }; + + if (reader[2].SQLiteType != SQLiteType.Null) + { + item.Codec = reader[2].ToString(); + } + + if (reader[2].SQLiteType != SQLiteType.Null) + { + item.CodecTag = reader[3].ToString(); + } + + if (reader[4].SQLiteType != SQLiteType.Null) + { + item.Comment = reader[4].ToString(); + } + + if (reader[6].SQLiteType != SQLiteType.Null) + { + item.Filename = reader[5].ToString(); + } + + if (reader[6].SQLiteType != SQLiteType.Null) + { + item.MIMEType = reader[6].ToString(); + } + + return item; + } } } diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 47e0f3453..68df20c3a 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -78,6 +78,21 @@ namespace MediaBrowser.Controller.Persistence /// The cancellation token. void SaveMediaStreams(Guid id, List streams, CancellationToken cancellationToken); + /// + /// Gets the media attachments. + /// + /// The query. + /// IEnumerable{MediaAttachment}. + List GetMediaAttachments(MediaAttachmentQuery query); + + /// + /// Saves the media attachments. + /// + /// The identifier. + /// The attachments. + /// The cancellation token. + void SaveMediaAttachments(Guid id, List attachments, CancellationToken cancellationToken); + /// /// Gets the item ids. /// diff --git a/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs b/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs new file mode 100644 index 000000000..91ab34aab --- /dev/null +++ b/MediaBrowser.Controller/Persistence/MediaAttachmentQuery.cs @@ -0,0 +1,20 @@ +using System; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.Persistence +{ + public class MediaAttachmentQuery + { + /// + /// Gets or sets the index. + /// + /// The index. + public int? Index { get; set; } + + /// + /// Gets or sets the item identifier. + /// + /// The item identifier. + public Guid ItemId { get; set; } + } +} diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index d2abd2a63..ae3e584d4 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -158,11 +158,13 @@ namespace MediaBrowser.Providers.MediaInfo MetadataRefreshOptions options) { List mediaStreams; + List mediaAttachments; List chapters; if (mediaInfo != null) { mediaStreams = mediaInfo.MediaStreams; + mediaAttachments = mediaInfo.MediaAttachments; video.TotalBitrate = mediaInfo.Bitrate; //video.FormatName = (mediaInfo.Container ?? string.Empty) @@ -198,6 +200,7 @@ namespace MediaBrowser.Providers.MediaInfo else { mediaStreams = new List(); + mediaAttachments = new List(); chapters = new List(); } @@ -223,6 +226,7 @@ namespace MediaBrowser.Providers.MediaInfo video.HasSubtitles = mediaStreams.Any(i => i.Type == MediaStreamType.Subtitle); _itemRepo.SaveMediaStreams(video.Id, mediaStreams, cancellationToken); + _itemRepo.SaveMediaAttachments(video.Id, mediaAttachments, cancellationToken); if (options.MetadataRefreshMode == MetadataRefreshMode.FullRefresh || options.MetadataRefreshMode == MetadataRefreshMode.Default) -- cgit v1.2.3 From 1513c76a3e0b8f84def98df3fe99432370076497 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 7 Oct 2019 07:53:28 -0400 Subject: Support MediaAttachment retrieval in MediaSourceManager. --- .../Library/MediaSourceManager.cs | 26 ++++++++++++++++++++++ .../Library/IMediaSourceManager.cs | 19 ++++++++++++++++ 2 files changed, 45 insertions(+) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index d83e1fc02..e069ebd17 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -128,6 +128,32 @@ namespace Emby.Server.Implementations.Library return streams; } + public List GetMediaAttachments(MediaAttachmentQuery query) + { + var list = _itemRepo.GetMediaAttachments(query); + return list; + } + + public List GetMediaAttachments(string mediaSourceId) + { + var list = GetMediaAttachments(new MediaAttachmentQuery + { + ItemId = new Guid(mediaSourceId) + }); + + return list; + } + + public List GetMediaAttachments(Guid itemId) + { + var list = GetMediaAttachments(new MediaAttachmentQuery + { + ItemId = itemId + }); + + return list; + } + public async Task> GetPlayackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken) { var mediaSources = GetStaticMediaSources(item, enablePathSubstitution, user); diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index fbae4edb0..961028b04 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -38,6 +38,25 @@ namespace MediaBrowser.Controller.Library /// IEnumerable<MediaStream>. List GetMediaStreams(MediaStreamQuery query); + /// + /// Gets the media attachments. + /// + /// The item identifier. + /// IEnumerable<MediaAttachment>. + List GetMediaAttachments(Guid itemId); + /// + /// Gets the media attachments. + /// + /// The The media source identifier. + /// IEnumerable<MediaAttachment>. + List GetMediaAttachments(string mediaSourceId); + /// + /// Gets the media attachments. + /// + /// The query. + /// IEnumerable<MediaAttachment>. + List GetMediaAttachments(MediaAttachmentQuery query); + /// /// Gets the playack media sources. /// -- cgit v1.2.3 From f22ca6dd9eeac73cfc5e24dceb67a7f817f77b9a Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 7 Oct 2019 07:54:11 -0400 Subject: Retrieve media attachments in BaseItem. --- MediaBrowser.Controller/Entities/BaseItem.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Controller/Entities/BaseItem.cs b/MediaBrowser.Controller/Entities/BaseItem.cs index 599d41bb2..2e2b465a0 100644 --- a/MediaBrowser.Controller/Entities/BaseItem.cs +++ b/MediaBrowser.Controller/Entities/BaseItem.cs @@ -1098,6 +1098,7 @@ namespace MediaBrowser.Controller.Entities Id = item.Id.ToString("N", CultureInfo.InvariantCulture), Protocol = protocol ?? MediaProtocol.File, MediaStreams = MediaSourceManager.GetMediaStreams(item.Id), + MediaAttachments = MediaSourceManager.GetMediaAttachments(item.Id), Name = GetMediaSourceName(item), Path = enablePathSubstitution ? GetMappedPath(item, item.Path, protocol) : item.Path, RunTimeTicks = item.RunTimeTicks, -- cgit v1.2.3 From 12f752d8b1bbc9d6d480bfc34283dd15a08d1f8a Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Fri, 18 Oct 2019 07:52:32 -0400 Subject: FFMPEG extractor for attachments. --- .../MediaEncoding/IAttachmentExtractor.cs | 17 ++ .../Attachments/AttachmentExtractor.cs | 277 +++++++++++++++++++++ 2 files changed, 294 insertions(+) create mode 100644 MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs create mode 100644 MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs new file mode 100644 index 000000000..59c0a3f21 --- /dev/null +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -0,0 +1,17 @@ +using System.IO; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Entities; + +namespace MediaBrowser.Controller.MediaEncoding +{ + public interface IAttachmentExtractor + { + Task<(MediaAttachment attachment, Stream stream)> GetAttachment(BaseItem item, + string mediaSourceId, + int attachmentStreamIndex, + CancellationToken cancellationToken); + } +} diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs new file mode 100644 index 000000000..d6106df29 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -0,0 +1,277 @@ +using System; +using System.Collections.Concurrent; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Configuration; +using MediaBrowser.Common.Extensions; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Model.Diagnostics; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.MediaInfo; +using MediaBrowser.Model.Serialization; +using Microsoft.Extensions.Logging; +using UtfUnknown; + +namespace MediaBrowser.MediaEncoding.Attachments +{ + public class AttachmentExtractor : IAttachmentExtractor + { + private readonly ILibraryManager _libraryManager; + private readonly ILogger _logger; + private readonly IApplicationPaths _appPaths; + private readonly IFileSystem _fileSystem; + private readonly IMediaEncoder _mediaEncoder; + private readonly IMediaSourceManager _mediaSourceManager; + private readonly IProcessFactory _processFactory; + + public AttachmentExtractor( + ILibraryManager libraryManager, + ILoggerFactory loggerFactory, + IApplicationPaths appPaths, + IFileSystem fileSystem, + IMediaEncoder mediaEncoder, + IMediaSourceManager mediaSourceManager, + IProcessFactory processFactory) + { + _libraryManager = libraryManager; + _logger = loggerFactory.CreateLogger(nameof(AttachmentExtractor)); + _appPaths = appPaths; + _fileSystem = fileSystem; + _mediaEncoder = mediaEncoder; + _mediaSourceManager = mediaSourceManager; + _processFactory = processFactory; + } + + private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); + + public async Task<(MediaAttachment attachment, Stream stream)> GetAttachment(BaseItem item, string mediaSourceId, int attachmentStreamIndex, CancellationToken cancellationToken) + { + if (item == null) + { + throw new ArgumentNullException(nameof(item)); + } + if (string.IsNullOrWhiteSpace(mediaSourceId)) + { + throw new ArgumentNullException(nameof(mediaSourceId)); + } + + var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, false, cancellationToken).ConfigureAwait(false); + var mediaSource = mediaSources + .First(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); + var mediaAttachment = mediaSource.MediaAttachments + .First(i => i.Index == attachmentStreamIndex); + var attachmentStream = await GetAttachmentStream(mediaSource, mediaAttachment, cancellationToken) + .ConfigureAwait(false); + + return (mediaAttachment, attachmentStream); + } + + private async Task GetAttachmentStream( + MediaSourceInfo mediaSource, + MediaAttachment mediaAttachment, + CancellationToken cancellationToken) + { + var inputFiles = new[] {mediaSource.Path}; + var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false); + var stream = await GetAttachmentStream(fileInfo.Path, fileInfo.Protocol, cancellationToken).ConfigureAwait(false); + return stream; + } + + private async Task GetAttachmentStream( + string path, + MediaProtocol protocol, + CancellationToken cancellationToken) + { + return File.OpenRead(path); + } + + private async Task GetReadableFile( + string mediaPath, + string[] inputFiles, + MediaProtocol protocol, + MediaAttachment mediaAttachment, + CancellationToken cancellationToken) + { + var outputPath = GetAttachmentCachePath(mediaPath, protocol, mediaAttachment.Index); + await ExtractAttachment(inputFiles, protocol, mediaAttachment.Index, outputPath, cancellationToken) + .ConfigureAwait(false); + + return new AttachmentInfo(outputPath, MediaProtocol.File); + } + + private struct AttachmentInfo + { + public AttachmentInfo(string path, MediaProtocol protocol) + { + Path = path; + Protocol = protocol; + } + public string Path { get; set; } + public MediaProtocol Protocol { get; set; } + } + + private readonly ConcurrentDictionary _semaphoreLocks = + new ConcurrentDictionary(); + + private SemaphoreSlim GetLock(string filename) + { + return _semaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1)); + } + + private async Task ExtractAttachment( + string[] inputFiles, + MediaProtocol protocol, + int attachmentStreamIndex, + string outputPath, + CancellationToken cancellationToken) + { + var semaphore = GetLock(outputPath); + + await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); + + try + { + if (!File.Exists(outputPath)) + { + await ExtractAttachmentInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), attachmentStreamIndex, outputPath, cancellationToken).ConfigureAwait(false); + } + } + finally + { + semaphore.Release(); + } + } + + private async Task ExtractAttachmentInternal( + string inputPath, + int attachmentStreamIndex, + string outputPath, + CancellationToken cancellationToken) + { + if (string.IsNullOrEmpty(inputPath)) + { + throw new ArgumentNullException(nameof(inputPath)); + } + + if (string.IsNullOrEmpty(outputPath)) + { + throw new ArgumentNullException(nameof(outputPath)); + } + + Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); + + var processArgs = string.Format("-dump_attachment:{1} {2} -i {0} -t 0 -f null null", inputPath, attachmentStreamIndex, outputPath); + var process = _processFactory.Create(new ProcessOptions + { + CreateNoWindow = true, + UseShellExecute = false, + EnableRaisingEvents = true, + FileName = _mediaEncoder.EncoderPath, + Arguments = processArgs, + IsHidden = true, + ErrorDialog = false + }); + + _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); + + try + { + process.Start(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error starting ffmpeg"); + + throw; + } + + var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false); + + if (!ranToCompletion) + { + try + { + _logger.LogWarning("Killing ffmpeg attachment extraction process"); + process.Kill(); + } + catch (Exception ex) + { + _logger.LogError(ex, "Error killing attachment extraction process"); + } + + } + + var exitCode = ranToCompletion ? process.ExitCode : -1; + + process.Dispose(); + + var failed = false; + + if (exitCode == -1) + { + failed = true; + + try + { + _logger.LogWarning("Deleting extracted attachment due to failure: {Path}", outputPath); + _fileSystem.DeleteFile(outputPath); + } + catch (FileNotFoundException) + { + + } + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting extracted attachment {Path}", outputPath); + } + + } + else if (!File.Exists(outputPath)) + { + failed = true; + } + + if (failed) + { + var msg = $"ffmpeg attachment extraction failed for {inputPath} to {outputPath}"; + + _logger.LogError(msg); + + throw new Exception(msg); + } + else + { + var msg = $"ffmpeg attachment extraction completed for {inputPath} to {outputPath}"; + + _logger.LogInformation(msg); + } + } + + private string GetAttachmentCachePath(string mediaPath, MediaProtocol protocol, int attachmentStreamIndex) + { + if (protocol == MediaProtocol.File) + { + var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); + var filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); + var prefix = filename.Substring(0, 1); + return Path.Combine(AttachmentCachePath, prefix, filename); + } + else + { + var filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); + var prefix = filename.Substring(0, 1); + return Path.Combine(AttachmentCachePath, prefix, filename); + } + } + + } +} -- cgit v1.2.3 From a9a85f251e77cf1670e69733e1d7b5ab9116aaaf Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Fri, 18 Oct 2019 07:56:53 -0400 Subject: Instantiate AttachmentExtractor in ApplicationHost. --- Emby.Server.Implementations/ApplicationHost.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 04904fc4a..bcd99ffe4 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -282,6 +282,8 @@ namespace Emby.Server.Implementations private ISubtitleEncoder SubtitleEncoder { get; set; } + private IAttachmentExtractor AttachmentExtractor { get; set; } + private ISessionManager SessionManager { get; set; } private ILiveTvManager LiveTvManager { get; set; } @@ -904,6 +906,10 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager)); + AttachmentExtractor = new MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, MediaSourceManager, ProcessFactory); + + serviceCollection.AddSingleton(AttachmentExtractor); + _displayPreferencesRepository.Initialize(); var userDataRepo = new SqliteUserDataRepository(LoggerFactory, ApplicationPaths); -- cgit v1.2.3 From 8c89d8993269033931fb53b66212e4f87c6edbb5 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Fri, 18 Oct 2019 07:57:40 -0400 Subject: Attachment service. --- MediaBrowser.Api/Attachments/AttachmentService.cs | 67 +++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 MediaBrowser.Api/Attachments/AttachmentService.cs diff --git a/MediaBrowser.Api/Attachments/AttachmentService.cs b/MediaBrowser.Api/Attachments/AttachmentService.cs new file mode 100644 index 000000000..4c7d5eccc --- /dev/null +++ b/MediaBrowser.Api/Attachments/AttachmentService.cs @@ -0,0 +1,67 @@ +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; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Library; +using MediaBrowser.Controller.MediaEncoding; +using MediaBrowser.Controller.Net; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Providers; +using MediaBrowser.Model.Services; +using Microsoft.Extensions.Logging; +using MimeTypes = MediaBrowser.Model.Net.MimeTypes; + +namespace MediaBrowser.Api.Attachments +{ + [Route("/Videos/{Id}/{MediaSourceId}/Attachments/{Index}/Attachment", "GET", Summary = "Gets specified attachment.")] + public class GetAttachment + { + [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] + public Guid 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 attachment stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")] + public int Index { get; set; } + } + + public class AttachmentService : BaseApiService + { + private readonly ILibraryManager _libraryManager; + private readonly IAttachmentExtractor _attachmentExtractor; + + public AttachmentService(ILibraryManager libraryManager, IAttachmentExtractor attachmentExtractor) + { + _libraryManager = libraryManager; + _attachmentExtractor = attachmentExtractor; + } + + public async Task Get(GetAttachment request) + { + var item = (Video)_libraryManager.GetItemById(request.Id); + var (attachment, attachmentStream) = await GetAttachment(request).ConfigureAwait(false); + var mime = string.IsNullOrWhiteSpace(attachment.MIMEType) ? "application/octet-stream" : attachment.MIMEType; + + return ResultFactory.GetResult(Request, attachmentStream, mime); + } + + private Task<(MediaAttachment, Stream)> GetAttachment(GetAttachment request) + { + var item = _libraryManager.GetItemById(request.Id); + + return _attachmentExtractor.GetAttachment(item, + request.MediaSourceId, + request.Index, + CancellationToken.None); + } + + } +} -- cgit v1.2.3 From 01b1c847e95c28ec780dfe3f2c7d1b33ffd08bd0 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Fri, 18 Oct 2019 07:59:03 -0400 Subject: Provide delivery URLs for attachments in PlaybackInfo. --- MediaBrowser.Api/Playback/MediaInfoService.cs | 8 ++++++++ MediaBrowser.Model/Entities/MediaAttachment.cs | 6 ++++++ 2 files changed, 14 insertions(+) diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index da8f99a3d..6c57e37a1 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -524,6 +524,14 @@ namespace MediaBrowser.Api.Playback SetDeviceSpecificSubtitleInfo(streamInfo, mediaSource, auth.Token); } } + + foreach (var attachment in mediaSource.MediaAttachments) + { + attachment.DeliveryUrl = string.Format("/Videos/{0}/{1}/Attachments/{2}/Attachment", + item.Id, + mediaSource.Id, + attachment.Index); + } } private long? GetMaxBitrate(long? clientMaxBitrate, User user) diff --git a/MediaBrowser.Model/Entities/MediaAttachment.cs b/MediaBrowser.Model/Entities/MediaAttachment.cs index daabbe91d..26279b72b 100644 --- a/MediaBrowser.Model/Entities/MediaAttachment.cs +++ b/MediaBrowser.Model/Entities/MediaAttachment.cs @@ -40,5 +40,11 @@ namespace MediaBrowser.Model.Entities /// /// The MIME type. public string MIMEType { get; set; } + + /// + /// Gets or sets the delivery URL. + /// + /// The delivery URL. + public string DeliveryUrl { get; set; } } } -- cgit v1.2.3 From 20727906c85c0d519eda86194b081a22f60dcf61 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 22 Oct 2019 10:57:15 -0400 Subject: Use attachment filename if available. --- MediaBrowser.Api/Attachments/AttachmentService.cs | 5 ++++- MediaBrowser.Api/Playback/MediaInfoService.cs | 6 ++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Api/Attachments/AttachmentService.cs b/MediaBrowser.Api/Attachments/AttachmentService.cs index 4c7d5eccc..d8771f8c0 100644 --- a/MediaBrowser.Api/Attachments/AttachmentService.cs +++ b/MediaBrowser.Api/Attachments/AttachmentService.cs @@ -20,7 +20,7 @@ using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Attachments { - [Route("/Videos/{Id}/{MediaSourceId}/Attachments/{Index}/Attachment", "GET", Summary = "Gets specified attachment.")] + [Route("/Videos/{Id}/{MediaSourceId}/Attachments/{Index}/{Filename}", "GET", Summary = "Gets specified attachment.")] public class GetAttachment { [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -31,6 +31,9 @@ namespace MediaBrowser.Api.Attachments [ApiMember(Name = "Index", Description = "The attachment stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")] public int Index { get; set; } + + [ApiMember(Name = "Filename", Description = "The attachment filename", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] + public string Filename { get; set; } } public class AttachmentService : BaseApiService diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 6c57e37a1..41b324975 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -527,10 +527,12 @@ namespace MediaBrowser.Api.Playback foreach (var attachment in mediaSource.MediaAttachments) { - attachment.DeliveryUrl = string.Format("/Videos/{0}/{1}/Attachments/{2}/Attachment", + var filename = string.IsNullOrWhiteSpace(attachment.Filename) ? "Attachment" : attachment.Filename; + attachment.DeliveryUrl = string.Format("/Videos/{0}/{1}/Attachments/{2}/{3}", item.Id, mediaSource.Id, - attachment.Index); + attachment.Index, + filename); } } -- cgit v1.2.3 From 90dfe729bb9f8929bf584b93f93aabd84abbef3d Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 08:48:27 -0500 Subject: Add space when building query string for attachments. Co-Authored-By: Vasily --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 58f04e4fc..d02aa9b1f 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6161,7 +6161,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type if (query.Index.HasValue) { - cmdText += "AND AttachmentIndex=@AttachmentIndex"; + cmdText += " AND AttachmentIndex=@AttachmentIndex"; } cmdText += " order by AttachmentIndex ASC"; -- cgit v1.2.3 From 4573fb5301b02e8b57a15a57f909b1b63d6b3900 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 10:19:53 -0500 Subject: Use ToByteArray instead of ToGuidBlob. --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 08f53f0f5..2b07844e7 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6175,7 +6175,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type using (var statement = PrepareStatement(connection, cmdText)) { - statement.TryBind("@ItemId", query.ItemId.ToGuidBlob()); + statement.TryBind("@ItemId", query.ItemId.ToByteArray()); if (query.Index.HasValue) { @@ -6208,7 +6208,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { connection.RunInTransaction(db => { - var itemIdBlob = id.ToGuidBlob(); + var itemIdBlob = id.ToByteArray(); db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); -- cgit v1.2.3 From 0dde5e46df13f63158288ce73b98b25a6440de43 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 10:28:33 -0500 Subject: Flatten using connection in GetMediaAttachments/SaveMediaAttachments --- .../Data/SqliteItemRepository.cs | 39 ++++++++++------------ 1 file changed, 17 insertions(+), 22 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 2b07844e7..62837933c 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6169,26 +6169,23 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type cmdText += " order by AttachmentIndex ASC"; - using (var connection = GetConnection(true)) + var list = new List(); + using var connection = GetConnection(true); + using (var statement = PrepareStatement(connection, cmdText)) { - var list = new List(); + statement.TryBind("@ItemId", query.ItemId.ToByteArray()); - using (var statement = PrepareStatement(connection, cmdText)) + if (query.Index.HasValue) { - statement.TryBind("@ItemId", query.ItemId.ToByteArray()); - - if (query.Index.HasValue) - { - statement.TryBind("@AttachmentIndex", query.Index.Value); - } - - foreach (var row in statement.ExecuteQuery()) { - list.Add(GetMediaAttachment(row)); - } + statement.TryBind("@AttachmentIndex", query.Index.Value); } - return list; + foreach (var row in statement.ExecuteQuery()) { + list.Add(GetMediaAttachment(row)); + } } + + return list; } public void SaveMediaAttachments(Guid id, List attachments, CancellationToken cancellationToken) @@ -6204,18 +6201,16 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type throw new ArgumentNullException(nameof(attachments)); } - using (var connection = GetConnection()) + using var connection = GetConnection(); + connection.RunInTransaction(db => { - connection.RunInTransaction(db => - { - var itemIdBlob = id.ToByteArray(); + var itemIdBlob = id.ToByteArray(); - db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); + db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); - InsertMediaAttachments(itemIdBlob, attachments, db); + InsertMediaAttachments(itemIdBlob, attachments, db); - }, TransactionMode); - } + }, TransactionMode); } private void InsertMediaAttachments(byte[] idBlob, List attachments, IDatabaseConnection db) -- cgit v1.2.3 From c2d8f210b1c8daa86a37b530a7da05370d3b209a Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 10:31:32 -0500 Subject: Check for cancellation in SaveMediaAttachments. --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 62837933c..8d39cdb8f 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6201,6 +6201,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type throw new ArgumentNullException(nameof(attachments)); } + cancellationToken.ThrowIfCancellationRequested(); + using var connection = GetConnection(); connection.RunInTransaction(db => { -- cgit v1.2.3 From ad2101ce52999fccf51e52510729fd36e3495369 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 10:33:50 -0500 Subject: Rename "limit" to "insertAtOnce" in InsertMediaAttachments. --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 8d39cdb8f..7c0a58596 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6218,13 +6218,13 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type private void InsertMediaAttachments(byte[] idBlob, List attachments, IDatabaseConnection db) { var startIndex = 0; - var limit = 10; + var insertAtOnce = 10; while (startIndex < attachments.Count) { var insertText = new StringBuilder(string.Format("insert into mediaattachments ({0}) values ", string.Join(",", _mediaAttachmentSaveColumns))); - var endIndex = Math.Min(attachments.Count, startIndex + limit); + var endIndex = Math.Min(attachments.Count, startIndex + insertAtOnce); for (var i = startIndex; i < endIndex; i++) { @@ -6266,7 +6266,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.Reset(); statement.MoveNext(); } - startIndex += limit; + startIndex += insertAtOnce; } } -- cgit v1.2.3 From 7110069b399496979aa8fdc701d0e1af536425f7 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 10:37:19 -0500 Subject: Return list result directly for MediaAttachments. --- Emby.Server.Implementations/Library/MediaSourceManager.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 2e24b847b..27eb39530 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -130,28 +130,23 @@ namespace Emby.Server.Implementations.Library public List GetMediaAttachments(MediaAttachmentQuery query) { - var list = _itemRepo.GetMediaAttachments(query); - return list; + return _itemRepo.GetMediaAttachments(query); } public List GetMediaAttachments(string mediaSourceId) { - var list = GetMediaAttachments(new MediaAttachmentQuery + return GetMediaAttachments(new MediaAttachmentQuery { ItemId = new Guid(mediaSourceId) }); - - return list; } public List GetMediaAttachments(Guid itemId) { - var list = GetMediaAttachments(new MediaAttachmentQuery + return GetMediaAttachments(new MediaAttachmentQuery { ItemId = itemId }); - - return list; } public async Task> GetPlayackMediaSources(BaseItem item, User user, bool allowMediaProbe, bool enablePathSubstitution, CancellationToken cancellationToken) -- cgit v1.2.3 From bd545891c0327eb155198c4e835f874156f416a6 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 10:38:53 -0500 Subject: Indentation fix. --- MediaBrowser.Api/Attachments/AttachmentService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Api/Attachments/AttachmentService.cs b/MediaBrowser.Api/Attachments/AttachmentService.cs index d8771f8c0..9fceebd3b 100644 --- a/MediaBrowser.Api/Attachments/AttachmentService.cs +++ b/MediaBrowser.Api/Attachments/AttachmentService.cs @@ -50,8 +50,8 @@ namespace MediaBrowser.Api.Attachments public async Task Get(GetAttachment request) { var item = (Video)_libraryManager.GetItemById(request.Id); - var (attachment, attachmentStream) = await GetAttachment(request).ConfigureAwait(false); - var mime = string.IsNullOrWhiteSpace(attachment.MIMEType) ? "application/octet-stream" : attachment.MIMEType; + var (attachment, attachmentStream) = await GetAttachment(request).ConfigureAwait(false); + var mime = string.IsNullOrWhiteSpace(attachment.MIMEType) ? "application/octet-stream" : attachment.MIMEType; return ResultFactory.GetResult(Request, attachmentStream, mime); } -- cgit v1.2.3 From e9c893f07eeb0ddb59f136cedfdf7e5a3f06d36d Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 10:58:56 -0500 Subject: Fail attachment extraction on non-zero exit code. --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index d6106df29..246023582 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -216,7 +216,7 @@ namespace MediaBrowser.MediaEncoding.Attachments var failed = false; - if (exitCode == -1) + if (exitCode != 0) { failed = true; -- cgit v1.2.3 From 9eef5f860d29eaa32d6b06f76d74f6c9bbe1e3cd Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 11:16:57 -0500 Subject: AttachmentExtractor logging cleanup. --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 246023582..57b80d060 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -220,9 +220,9 @@ namespace MediaBrowser.MediaEncoding.Attachments { failed = true; + _logger.LogWarning("Deleting extracted attachment {Path} due to failure: {ExitCode}", outputPath, exitCode); try { - _logger.LogWarning("Deleting extracted attachment due to failure: {Path}", outputPath); _fileSystem.DeleteFile(outputPath); } catch (FileNotFoundException) -- cgit v1.2.3 From 262a8f47afb4905be4eac815dd92849c7616ce89 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 11:31:41 -0500 Subject: Remove attachment filenames from attachment URLs. --- MediaBrowser.Api/Attachments/AttachmentService.cs | 5 +---- MediaBrowser.Api/Playback/MediaInfoService.cs | 6 ++---- 2 files changed, 3 insertions(+), 8 deletions(-) diff --git a/MediaBrowser.Api/Attachments/AttachmentService.cs b/MediaBrowser.Api/Attachments/AttachmentService.cs index 9fceebd3b..c52ca2481 100644 --- a/MediaBrowser.Api/Attachments/AttachmentService.cs +++ b/MediaBrowser.Api/Attachments/AttachmentService.cs @@ -20,7 +20,7 @@ using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Attachments { - [Route("/Videos/{Id}/{MediaSourceId}/Attachments/{Index}/{Filename}", "GET", Summary = "Gets specified attachment.")] + [Route("/Videos/{Id}/{MediaSourceId}/Attachments/{Index}", "GET", Summary = "Gets specified attachment.")] public class GetAttachment { [ApiMember(Name = "Id", Description = "Item Id", IsRequired = true, DataType = "string", ParameterType = "path", Verb = "GET")] @@ -31,9 +31,6 @@ namespace MediaBrowser.Api.Attachments [ApiMember(Name = "Index", Description = "The attachment stream index", IsRequired = true, DataType = "int", ParameterType = "path", Verb = "GET")] public int Index { get; set; } - - [ApiMember(Name = "Filename", Description = "The attachment filename", IsRequired = false, DataType = "string", ParameterType = "path", Verb = "GET")] - public string Filename { get; set; } } public class AttachmentService : BaseApiService diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index 41b324975..de5c4ddb7 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -527,12 +527,10 @@ namespace MediaBrowser.Api.Playback foreach (var attachment in mediaSource.MediaAttachments) { - var filename = string.IsNullOrWhiteSpace(attachment.Filename) ? "Attachment" : attachment.Filename; - attachment.DeliveryUrl = string.Format("/Videos/{0}/{1}/Attachments/{2}/{3}", + attachment.DeliveryUrl = string.Format("/Videos/{0}/{1}/Attachments/{2}", item.Id, mediaSource.Id, - attachment.Index, - filename); + attachment.Index); } } -- cgit v1.2.3 From c7d303a6ae9e0d5489273fa5a15262987c735bd0 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 11:39:40 -0500 Subject: MediaExtractor logging cleanup. --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 57b80d060..b369e4515 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -250,9 +250,7 @@ namespace MediaBrowser.MediaEncoding.Attachments } else { - var msg = $"ffmpeg attachment extraction completed for {inputPath} to {outputPath}"; - - _logger.LogInformation(msg); + _logger.LogInformation("ffmpeg attachment extraction completed for {Path} to {Path}", inputPath, outputPath); } } -- cgit v1.2.3 From 154fb1fe9b45892807a9bea9abb282380bfd9383 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 11:45:31 -0500 Subject: AttachmentExtractor code cleanup. --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index b369e4515..1c214d5d3 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -256,19 +256,18 @@ namespace MediaBrowser.MediaEncoding.Attachments private string GetAttachmentCachePath(string mediaPath, MediaProtocol protocol, int attachmentStreamIndex) { + String filename; if (protocol == MediaProtocol.File) { var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); - var filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); - var prefix = filename.Substring(0, 1); - return Path.Combine(AttachmentCachePath, prefix, filename); + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture) + "_" + date.Ticks.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); } else { - var filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); - var prefix = filename.Substring(0, 1); - return Path.Combine(AttachmentCachePath, prefix, filename); + filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); } + var prefix = filename.Substring(0, 1); + return Path.Combine(AttachmentCachePath, prefix, filename); } } -- cgit v1.2.3 From 04a96788f9f3ea20b05d3c57d16d222ba7a53101 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 14:34:21 -0500 Subject: Convert exceptions for missing MediaSource or MediaAttachment to ResourceNotFoundException with appropriate message. --- .../Attachments/AttachmentExtractor.cs | 24 ++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 1c214d5d3..be5908cce 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -65,10 +65,26 @@ namespace MediaBrowser.MediaEncoding.Attachments } var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, false, cancellationToken).ConfigureAwait(false); - var mediaSource = mediaSources - .First(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); - var mediaAttachment = mediaSource.MediaAttachments - .First(i => i.Index == attachmentStreamIndex); + MediaSourceInfo mediaSource; + MediaAttachment mediaAttachment; + try + { + mediaSource = mediaSources + .First(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); + } + catch (Exception ex) when (ex is ArgumentNullException || ex is InvalidOperationException) + { + throw new ResourceNotFoundException($"MediaSource {mediaSourceId} not found"); + } + try + { + mediaAttachment = mediaSource.MediaAttachments + .First(i => i.Index == attachmentStreamIndex); + } + catch (Exception ex) when (ex is ArgumentNullException || ex is InvalidOperationException) + { + throw new ResourceNotFoundException($"MediaSource {mediaSourceId} has no attachment with stream index {attachmentStreamIndex}"); + } var attachmentStream = await GetAttachmentStream(mediaSource, mediaAttachment, cancellationToken) .ConfigureAwait(false); -- cgit v1.2.3 From 28a6718d8e77527c3949118676dc6e165e3608f5 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Mon, 4 Nov 2019 14:48:28 -0500 Subject: Return path of extracted attachment, which is always a file, instead of AttachmentInfo with path and protocol. --- .../Attachments/AttachmentExtractor.cs | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index be5908cce..6bef1cd5a 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -97,20 +97,19 @@ namespace MediaBrowser.MediaEncoding.Attachments CancellationToken cancellationToken) { var inputFiles = new[] {mediaSource.Path}; - var fileInfo = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false); - var stream = await GetAttachmentStream(fileInfo.Path, fileInfo.Protocol, cancellationToken).ConfigureAwait(false); + var attachmentPath = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false); + var stream = await GetAttachmentStream(attachmentPath, cancellationToken).ConfigureAwait(false); return stream; } private async Task GetAttachmentStream( string path, - MediaProtocol protocol, CancellationToken cancellationToken) { return File.OpenRead(path); } - private async Task GetReadableFile( + private async Task GetReadableFile( string mediaPath, string[] inputFiles, MediaProtocol protocol, @@ -121,18 +120,7 @@ namespace MediaBrowser.MediaEncoding.Attachments await ExtractAttachment(inputFiles, protocol, mediaAttachment.Index, outputPath, cancellationToken) .ConfigureAwait(false); - return new AttachmentInfo(outputPath, MediaProtocol.File); - } - - private struct AttachmentInfo - { - public AttachmentInfo(string path, MediaProtocol protocol) - { - Path = path; - Protocol = protocol; - } - public string Path { get; set; } - public MediaProtocol Protocol { get; set; } + return outputPath; } private readonly ConcurrentDictionary _semaphoreLocks = -- cgit v1.2.3 From 6ca252ba5c651e41ad8a18c5555f5b60d81f0952 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 07:09:55 -0500 Subject: Remove check for "[0]" in codec_tag. --- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 2c001d775..f2056c566 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -535,8 +535,7 @@ namespace MediaBrowser.MediaEncoding.Probing Index = streamInfo.index }; - // Filter out junk - if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) + if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string)) { attachment.CodecTag = streamInfo.codec_tag_string; } -- cgit v1.2.3 From bd4da93d1e871f7d58075b6780c4c1c30fc34fd7 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 07:48:32 -0500 Subject: Throw ArgumentException instead of ArgumentNullException on empty Guid. --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 7c0a58596..e7e93d0db 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6193,7 +6193,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type CheckDisposed(); if (id == Guid.Empty) { - throw new ArgumentNullException(nameof(id)); + throw new ArgumentException(nameof(id)); } if (attachments == null) -- cgit v1.2.3 From 24a460dc939b8dab2aa7e3e4db7ce47373a50d1d Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 08:13:22 -0500 Subject: Update Emby.Server.Implementations/Data/SqliteItemRepository.cs formatting Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 7c0a58596..27a29318b 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6240,6 +6240,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { insertText.Append("@" + column + index + ","); } + insertText.Length -= 1; insertText.Append(")"); -- cgit v1.2.3 From 25bc7b81c37b635109e5c14baabf64954a517512 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 08:13:35 -0500 Subject: Update Emby.Server.Implementations/Data/SqliteItemRepository.cs formatting Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 27a29318b..de95adfa1 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6267,6 +6267,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.Reset(); statement.MoveNext(); } + startIndex += insertAtOnce; } } -- cgit v1.2.3 From 349310787cbf49964a0e9bd1548adb5a3a3a3c1c Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 08:16:46 -0500 Subject: Update MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs formatting Co-Authored-By: Bond-009 --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 6bef1cd5a..0c8d9ae9c 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -59,6 +59,7 @@ namespace MediaBrowser.MediaEncoding.Attachments { throw new ArgumentNullException(nameof(item)); } + if (string.IsNullOrWhiteSpace(mediaSourceId)) { throw new ArgumentNullException(nameof(mediaSourceId)); -- cgit v1.2.3 From d33e0a4e2c59783c785c992ea0c3a31596ae3058 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 08:17:34 -0500 Subject: Simplify AttachmentExtractor instantiation. Co-Authored-By: Bond-009 --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index ac37cfe07..9330d5719 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -908,7 +908,7 @@ namespace Emby.Server.Implementations AttachmentExtractor = new MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, MediaSourceManager, ProcessFactory); - serviceCollection.AddSingleton(AttachmentExtractor); + serviceCollection.AddSingleton(); _displayPreferencesRepository.Initialize(); -- cgit v1.2.3 From e5b65ed034c6ca0fcee9f73cc991a0962a44278f Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 08:19:07 -0500 Subject: Update Emby.Server.Implementations/Data/SqliteItemRepository.cs formatting Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index de95adfa1..a7e779251 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6180,7 +6180,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.TryBind("@AttachmentIndex", query.Index.Value); } - foreach (var row in statement.ExecuteQuery()) { + foreach (var row in statement.ExecuteQuery()) + { list.Add(GetMediaAttachment(row)); } } -- cgit v1.2.3 From a78aec56e357742c2906edbb1fcce47cb9a3c6dd Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 08:21:06 -0500 Subject: Format attachment DeliveryURL with CultureInfo.InvariantCulture. Co-Authored-By: Bond-009 --- MediaBrowser.Api/Playback/MediaInfoService.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.Api/Playback/MediaInfoService.cs b/MediaBrowser.Api/Playback/MediaInfoService.cs index de5c4ddb7..296d565b9 100644 --- a/MediaBrowser.Api/Playback/MediaInfoService.cs +++ b/MediaBrowser.Api/Playback/MediaInfoService.cs @@ -527,7 +527,9 @@ namespace MediaBrowser.Api.Playback foreach (var attachment in mediaSource.MediaAttachments) { - attachment.DeliveryUrl = string.Format("/Videos/{0}/{1}/Attachments/{2}", + attachment.DeliveryUrl = string.Format( + CultureInfo.InvariantCulture, + "/Videos/{0}/{1}/Attachments/{2}", item.Id, mediaSource.Id, attachment.Index); -- cgit v1.2.3 From 3602251cf53c636e3006605e2b48a77d7952d029 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 08:36:17 -0500 Subject: Update Emby.Server.Implementations/Data/SqliteItemRepository.cs Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index a7e779251..2152ed605 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6231,7 +6231,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type { if (i != startIndex) { - insertText.Append(","); + insertText.Append(','); } var index = i.ToString(CultureInfo.InvariantCulture); -- cgit v1.2.3 From 8505ee9d6c0b2f073fd39c538cbdb0ee9ee95354 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Tue, 5 Nov 2019 14:53:46 -0500 Subject: Extract the prefix for MediaAttachment insertions to a static member instead of generating it per-query. --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 2b9c6a52f..dd8620f9f 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -51,6 +51,19 @@ namespace Emby.Server.Implementations.Data private readonly TypeMapper _typeMapper; private readonly JsonSerializerOptions _jsonOptions; + static SqliteItemRepository() { + var queryPrefixText = new StringBuilder(); + queryPrefixText.Append("insert into mediaattachments ("); + foreach (var column in _mediaAttachmentSaveColumns) + { + queryPrefixText.Append(column); + queryPrefixText.Append(','); + } + queryPrefixText.Length -= 1; + queryPrefixText.Append(") values "); + _mediaAttachmentInsertPrefix = queryPrefixText.ToString(); + } + /// /// Initializes a new instance of the class. /// @@ -436,6 +449,7 @@ namespace Emby.Server.Implementations.Data "Filename", "MIMEType" }; + private static readonly string _mediaAttachmentInsertPrefix; private static string GetSaveItemCommandText() { @@ -6223,7 +6237,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type while (startIndex < attachments.Count) { - var insertText = new StringBuilder(string.Format("insert into mediaattachments ({0}) values ", string.Join(",", _mediaAttachmentSaveColumns))); + var insertText = new StringBuilder(_mediaAttachmentInsertPrefix); var endIndex = Math.Min(attachments.Count, startIndex + insertAtOnce); -- cgit v1.2.3 From 79bbf09ecba6d3c2ddb0955bdbd51164a6c7a236 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Wed, 6 Nov 2019 08:43:49 -0500 Subject: Revert "Simplify AttachmentExtractor instantiation." This reverts commit d33e0a4e2c59783c785c992ea0c3a31596ae3058. --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 9330d5719..ac37cfe07 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -908,7 +908,7 @@ namespace Emby.Server.Implementations AttachmentExtractor = new MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, MediaSourceManager, ProcessFactory); - serviceCollection.AddSingleton(); + serviceCollection.AddSingleton(AttachmentExtractor); _displayPreferencesRepository.Initialize(); -- cgit v1.2.3 From 4f3b8831552db1d376198384cfe42894883286dd Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Wed, 6 Nov 2019 09:46:31 -0500 Subject: Clean up handling of missing source/attachment in AttachmentExtractor. --- .../Attachments/AttachmentExtractor.cs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 0c8d9ae9c..bda5c2f37 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -66,23 +66,15 @@ namespace MediaBrowser.MediaEncoding.Attachments } var mediaSources = await _mediaSourceManager.GetPlayackMediaSources(item, null, true, false, cancellationToken).ConfigureAwait(false); - MediaSourceInfo mediaSource; - MediaAttachment mediaAttachment; - try - { - mediaSource = mediaSources - .First(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); - } - catch (Exception ex) when (ex is ArgumentNullException || ex is InvalidOperationException) + var mediaSource = mediaSources + .FirstOrDefault(i => string.Equals(i.Id, mediaSourceId, StringComparison.OrdinalIgnoreCase)); + if (mediaSource == null) { throw new ResourceNotFoundException($"MediaSource {mediaSourceId} not found"); } - try - { - mediaAttachment = mediaSource.MediaAttachments - .First(i => i.Index == attachmentStreamIndex); - } - catch (Exception ex) when (ex is ArgumentNullException || ex is InvalidOperationException) + var mediaAttachment = mediaSource.MediaAttachments + .FirstOrDefault(i => i.Index == attachmentStreamIndex); + if (mediaAttachment == null) { throw new ResourceNotFoundException($"MediaSource {mediaSourceId} has no attachment with stream index {attachmentStreamIndex}"); } -- cgit v1.2.3 From 74fb63a8989fe19c5e985a09f9cb45e42022320f Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Wed, 6 Nov 2019 10:43:14 -0500 Subject: Use block rather than local using statement. --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index dd8620f9f..f7774000c 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6184,7 +6184,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type cmdText += " order by AttachmentIndex ASC"; var list = new List(); - using var connection = GetConnection(true); + using (var connection = GetConnection(true)) using (var statement = PrepareStatement(connection, cmdText)) { statement.TryBind("@ItemId", query.ItemId.ToByteArray()); @@ -6218,16 +6218,18 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type cancellationToken.ThrowIfCancellationRequested(); - using var connection = GetConnection(); - connection.RunInTransaction(db => + using (var connection = GetConnection()) { - var itemIdBlob = id.ToByteArray(); + connection.RunInTransaction(db => + { + var itemIdBlob = id.ToByteArray(); - db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); + db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); - InsertMediaAttachments(itemIdBlob, attachments, db); + InsertMediaAttachments(itemIdBlob, attachments, db); - }, TransactionMode); + }, TransactionMode); + } } private void InsertMediaAttachments(byte[] idBlob, List attachments, IDatabaseConnection db) -- cgit v1.2.3 From 6defe80b62483350111dc6ba2f18cfd83542c4b1 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 08:38:36 -0500 Subject: Check for cancellation between each batch of MediaAttachment inserts. --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index f7774000c..195671168 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6226,13 +6226,13 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type db.Execute("delete from mediaattachments where ItemId=@ItemId", itemIdBlob); - InsertMediaAttachments(itemIdBlob, attachments, db); + InsertMediaAttachments(itemIdBlob, attachments, db, cancellationToken); }, TransactionMode); } } - private void InsertMediaAttachments(byte[] idBlob, List attachments, IDatabaseConnection db) + private void InsertMediaAttachments(byte[] idBlob, List attachments, IDatabaseConnection db, CancellationToken cancellationToken) { var startIndex = 0; var insertAtOnce = 10; @@ -6263,6 +6263,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type insertText.Append(")"); } + cancellationToken.ThrowIfCancellationRequested(); + using (var statement = PrepareStatement(db, insertText.ToString())) { statement.TryBind("@ItemId", idBlob); -- cgit v1.2.3 From c09eb3470815c8f868fd6eda6b542169d29f2098 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 08:56:12 -0500 Subject: Check for attachment file before trying to remove it during cleanup. --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index bda5c2f37..501dd3fed 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -220,11 +220,10 @@ namespace MediaBrowser.MediaEncoding.Attachments _logger.LogWarning("Deleting extracted attachment {Path} due to failure: {ExitCode}", outputPath, exitCode); try { - _fileSystem.DeleteFile(outputPath); - } - catch (FileNotFoundException) - { - + if (File.Exists(outputPath)) + { + _fileSystem.DeleteFile(outputPath); + } } catch (IOException ex) { -- cgit v1.2.3 From f60e9b0b62388f6e758870b53f3fb59b842fecd2 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:20:29 -0500 Subject: formatting Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 195671168..ba75488fb 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -51,7 +51,8 @@ namespace Emby.Server.Implementations.Data private readonly TypeMapper _typeMapper; private readonly JsonSerializerOptions _jsonOptions; - static SqliteItemRepository() { + static SqliteItemRepository() + { var queryPrefixText = new StringBuilder(); queryPrefixText.Append("insert into mediaattachments ("); foreach (var column in _mediaAttachmentSaveColumns) -- cgit v1.2.3 From 4b75e6518e707096e4749c82d6fb7cdd303d3a43 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:21:40 -0500 Subject: Update MediaBrowser.Api/Attachments/AttachmentService.cs formatting Co-Authored-By: Bond-009 --- MediaBrowser.Api/Attachments/AttachmentService.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/MediaBrowser.Api/Attachments/AttachmentService.cs b/MediaBrowser.Api/Attachments/AttachmentService.cs index c52ca2481..1ebfaa14b 100644 --- a/MediaBrowser.Api/Attachments/AttachmentService.cs +++ b/MediaBrowser.Api/Attachments/AttachmentService.cs @@ -62,6 +62,5 @@ namespace MediaBrowser.Api.Attachments request.Index, CancellationToken.None); } - } } -- cgit v1.2.3 From d6aa02ff09e262bc57a4dcf6dbbc11e6d1c963dd Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:22:07 -0500 Subject: Update Emby.Server.Implementations/Data/SqliteItemRepository.cs formatting Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index ba75488fb..a63052a68 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -60,6 +60,7 @@ namespace Emby.Server.Implementations.Data queryPrefixText.Append(column); queryPrefixText.Append(','); } + queryPrefixText.Length -= 1; queryPrefixText.Append(") values "); _mediaAttachmentInsertPrefix = queryPrefixText.ToString(); -- cgit v1.2.3 From 193a1fa474202ec0933c1a937c56ccecf58c4410 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:23:28 -0500 Subject: Update Emby.Server.Implementations/Library/MediaSourceManager.cs docs Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Library/MediaSourceManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 27eb39530..833a5c88f 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -128,6 +128,7 @@ namespace Emby.Server.Implementations.Library return streams; } + /// public List GetMediaAttachments(MediaAttachmentQuery query) { return _itemRepo.GetMediaAttachments(query); -- cgit v1.2.3 From 8b2d7062c43ff6618d5bf4a5e26d0ba5bb70bd07 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:24:30 -0500 Subject: Update Emby.Server.Implementations/Library/MediaSourceManager.cs docs Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Library/MediaSourceManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 833a5c88f..df6f0e77f 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -134,6 +134,7 @@ namespace Emby.Server.Implementations.Library return _itemRepo.GetMediaAttachments(query); } + /// public List GetMediaAttachments(string mediaSourceId) { return GetMediaAttachments(new MediaAttachmentQuery -- cgit v1.2.3 From 92aae268a352c20964ca10348078fdaf4fbf8263 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:24:53 -0500 Subject: Update MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs formatting Co-Authored-By: Bond-009 --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 501dd3fed..4218b180d 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -204,7 +204,6 @@ namespace MediaBrowser.MediaEncoding.Attachments { _logger.LogError(ex, "Error killing attachment extraction process"); } - } var exitCode = ranToCompletion ? process.ExitCode : -1; -- cgit v1.2.3 From 492bbc9e13f177eea62b0b22a921106def90309c Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:25:44 -0500 Subject: Update MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs String -> string Co-Authored-By: Bond-009 --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 4218b180d..7c3a0fbd3 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -251,7 +251,7 @@ namespace MediaBrowser.MediaEncoding.Attachments private string GetAttachmentCachePath(string mediaPath, MediaProtocol protocol, int attachmentStreamIndex) { - String filename; + string filename; if (protocol == MediaProtocol.File) { var date = _fileSystem.GetLastWriteTimeUtc(mediaPath); -- cgit v1.2.3 From d73f46dcda8db877edae4918a6053cad924808fa Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:27:55 -0500 Subject: Update Emby.Server.Implementations/Library/MediaSourceManager.cs docs Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Library/MediaSourceManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index df6f0e77f..9574a28e9 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -143,6 +143,7 @@ namespace Emby.Server.Implementations.Library }); } + /// public List GetMediaAttachments(Guid itemId) { return GetMediaAttachments(new MediaAttachmentQuery -- cgit v1.2.3 From 0fd7886a12bee56d72f00a066c3e475fa8040060 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:28:11 -0500 Subject: Update MediaBrowser.Controller/Library/IMediaSourceManager.cs formatting Co-Authored-By: Bond-009 --- MediaBrowser.Controller/Library/IMediaSourceManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 961028b04..8bd55b29f 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -44,6 +44,7 @@ namespace MediaBrowser.Controller.Library /// The item identifier. /// IEnumerable<MediaAttachment>. List GetMediaAttachments(Guid itemId); + /// /// Gets the media attachments. /// -- cgit v1.2.3 From 743685110c31f5da0f3e96e537c717e251909f38 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:29:34 -0500 Subject: Update MediaBrowser.Controller/Library/IMediaSourceManager.cs formatting Co-Authored-By: Bond-009 --- MediaBrowser.Controller/Library/IMediaSourceManager.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index 8bd55b29f..dda8d397a 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -50,6 +50,7 @@ namespace MediaBrowser.Controller.Library /// /// The The media source identifier. /// IEnumerable<MediaAttachment>. + List GetMediaAttachments(string mediaSourceId); /// /// Gets the media attachments. -- cgit v1.2.3 From c6855e6a2a347db17f2b8b2f18dd89d5b47a8816 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:53:39 -0500 Subject: Simplify AttachmentExtractor instantiation. --- Emby.Server.Implementations/ApplicationHost.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index ac37cfe07..97da5b437 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -282,8 +282,6 @@ namespace Emby.Server.Implementations private ISubtitleEncoder SubtitleEncoder { get; set; } - private IAttachmentExtractor AttachmentExtractor { get; set; } - private ISessionManager SessionManager { get; set; } private ILiveTvManager LiveTvManager { get; set; } @@ -906,9 +904,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager)); - AttachmentExtractor = new MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor(LibraryManager, LoggerFactory, ApplicationPaths, FileSystemManager, MediaEncoder, MediaSourceManager, ProcessFactory); - - serviceCollection.AddSingleton(AttachmentExtractor); + serviceCollection.AddSingleton(typeof(MediaBrowser.Controller.MediaEncoding.IAttachmentExtractor),typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor)); _displayPreferencesRepository.Initialize(); -- cgit v1.2.3 From 2338a53229431070b1c128436e990a486011205b Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:55:39 -0500 Subject: Don't user ILoggerFactory. --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 7c3a0fbd3..d18463cb5 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -35,7 +35,7 @@ namespace MediaBrowser.MediaEncoding.Attachments public AttachmentExtractor( ILibraryManager libraryManager, - ILoggerFactory loggerFactory, + ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, @@ -43,7 +43,7 @@ namespace MediaBrowser.MediaEncoding.Attachments IProcessFactory processFactory) { _libraryManager = libraryManager; - _logger = loggerFactory.CreateLogger(nameof(AttachmentExtractor)); + _logger = logger; _appPaths = appPaths; _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; -- cgit v1.2.3 From 2f728fd2a1be2e0abde3b8d7f8269b849e1555c6 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:58:26 -0500 Subject: Update MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs formatting Co-Authored-By: Bond-009 --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 7c3a0fbd3..2cecdf1cd 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -89,7 +89,7 @@ namespace MediaBrowser.MediaEncoding.Attachments MediaAttachment mediaAttachment, CancellationToken cancellationToken) { - var inputFiles = new[] {mediaSource.Path}; + var inputFiles = new[] { mediaSource.Path }; var attachmentPath = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false); var stream = await GetAttachmentStream(attachmentPath, cancellationToken).ConfigureAwait(false); return stream; -- cgit v1.2.3 From 1eb3df1d6ce21641612ce2f7ce9f25cd757a0e0d Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 11:59:54 -0500 Subject: Update MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs formatting / style Co-Authored-By: Bond-009 --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index f5f5d213f..e5b82d075 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -166,7 +166,12 @@ namespace MediaBrowser.MediaEncoding.Attachments Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); - var processArgs = string.Format("-dump_attachment:{1} {2} -i {0} -t 0 -f null null", inputPath, attachmentStreamIndex, outputPath); + var processArgs = string.Format( + CultureInfo.InvariantCulture, + "-dump_attachment:{1} {2} -i {0} -t 0 -f null null", + inputPath, + attachmentStreamIndex, + outputPath); var process = _processFactory.Create(new ProcessOptions { CreateNoWindow = true, -- cgit v1.2.3 From 3a9bf84e3b1b4d6c3cd1eaf979a418087ce41e0d Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 12:00:47 -0500 Subject: Update MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs formatting Co-Authored-By: Bond-009 --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index e5b82d075..0780df773 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -233,7 +233,6 @@ namespace MediaBrowser.MediaEncoding.Attachments { _logger.LogError(ex, "Error deleting extracted attachment {Path}", outputPath); } - } else if (!File.Exists(outputPath)) { -- cgit v1.2.3 From 79858eb26c60aa7ad8b6e63ee90fbd2e0727d594 Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Thu, 7 Nov 2019 14:24:49 -0500 Subject: Remove use of ProcessFactory, as well as arbitrary timeout in AttachmentExtractor. --- .../Attachments/AttachmentExtractor.cs | 31 +++++++++++++--------- MediaBrowser.MediaEncoding/packages.config | 3 --- 2 files changed, 18 insertions(+), 16 deletions(-) delete mode 100644 MediaBrowser.MediaEncoding/packages.config diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index f5f5d213f..369e597ea 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.Collections.Concurrent; using System.Globalization; using System.IO; @@ -31,7 +32,6 @@ namespace MediaBrowser.MediaEncoding.Attachments private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; private readonly IMediaSourceManager _mediaSourceManager; - private readonly IProcessFactory _processFactory; public AttachmentExtractor( ILibraryManager libraryManager, @@ -39,8 +39,7 @@ namespace MediaBrowser.MediaEncoding.Attachments IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, - IMediaSourceManager mediaSourceManager, - IProcessFactory processFactory) + IMediaSourceManager mediaSourceManager) { _libraryManager = libraryManager; _logger = logger; @@ -48,7 +47,6 @@ namespace MediaBrowser.MediaEncoding.Attachments _fileSystem = fileSystem; _mediaEncoder = mediaEncoder; _mediaSourceManager = mediaSourceManager; - _processFactory = processFactory; } private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); @@ -167,16 +165,19 @@ namespace MediaBrowser.MediaEncoding.Attachments Directory.CreateDirectory(Path.GetDirectoryName(outputPath)); var processArgs = string.Format("-dump_attachment:{1} {2} -i {0} -t 0 -f null null", inputPath, attachmentStreamIndex, outputPath); - var process = _processFactory.Create(new ProcessOptions + var startInfo = new ProcessStartInfo { - CreateNoWindow = true, - UseShellExecute = false, - EnableRaisingEvents = true, - FileName = _mediaEncoder.EncoderPath, Arguments = processArgs, - IsHidden = true, + FileName = _mediaEncoder.EncoderPath, + UseShellExecute = false, + CreateNoWindow = true, + WindowStyle = ProcessWindowStyle.Hidden, ErrorDialog = false - }); + }; + var process = new Process + { + StartInfo = startInfo + }; _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); @@ -191,7 +192,12 @@ namespace MediaBrowser.MediaEncoding.Attachments throw; } - var ranToCompletion = await process.WaitForExitAsync(300000).ConfigureAwait(false); + var processTcs = new TaskCompletionSource(); + process.EnableRaisingEvents = true; + process.Exited += (sender, args) => processTcs.TrySetResult(true); + var unregister = cancellationToken.Register(() => processTcs.TrySetResult(process.HasExited)); + var ranToCompletion = await processTcs.Task.ConfigureAwait(false); + unregister.Dispose(); if (!ranToCompletion) { @@ -205,7 +211,6 @@ namespace MediaBrowser.MediaEncoding.Attachments _logger.LogError(ex, "Error killing attachment extraction process"); } } - var exitCode = ranToCompletion ? process.ExitCode : -1; process.Dispose(); diff --git a/MediaBrowser.MediaEncoding/packages.config b/MediaBrowser.MediaEncoding/packages.config deleted file mode 100644 index bbeaf5f00..000000000 --- a/MediaBrowser.MediaEncoding/packages.config +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file -- cgit v1.2.3 From dee247453e7b5cab1badb6a844af690cdf80aacd Mon Sep 17 00:00:00 2001 From: Andrew Mahone Date: Wed, 13 Nov 2019 08:52:37 -0500 Subject: Throw InvalidOperationException when attachment extraction exits abnormally or doesn't produce output. --- MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index 4e277826a..cb22343c4 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -250,7 +250,7 @@ namespace MediaBrowser.MediaEncoding.Attachments _logger.LogError(msg); - throw new Exception(msg); + throw new InvalidOperationException(msg); } else { -- cgit v1.2.3 From 9989b7b68fb6d87d3a2bf7f271e8fe0c8c3e41ab Mon Sep 17 00:00:00 2001 From: Stanislav Ionascu Date: Sun, 13 Oct 2019 11:21:20 +0200 Subject: Replace BDInfo plugin with nupkg and UHD/Atmos/DTS:X support --- BDInfo/BDInfo.csproj | 17 - BDInfo/BDInfoSettings.cs | 33 - BDInfo/BDROM.cs | 449 ------ BDInfo/LanguageCodes.cs | 493 ------- BDInfo/Properties/AssemblyInfo.cs | 21 - BDInfo/ReadMe.txt | 5 - BDInfo/TSCodecAC3.cs | 309 ---- BDInfo/TSCodecAVC.cs | 148 -- BDInfo/TSCodecDTS.cs | 159 -- BDInfo/TSCodecDTSHD.cs | 246 ---- BDInfo/TSCodecLPCM.cs | 123 -- BDInfo/TSCodecMPEG2.cs | 208 --- BDInfo/TSCodecMVC.cs | 36 - BDInfo/TSCodecTrueHD.cs | 186 --- BDInfo/TSCodecVC1.cs | 131 -- BDInfo/TSInterleavedFile.cs | 37 - BDInfo/TSPlaylistFile.cs | 1282 ---------------- BDInfo/TSStream.cs | 780 ---------- BDInfo/TSStreamBuffer.cs | 130 -- BDInfo/TSStreamClip.cs | 107 -- BDInfo/TSStreamClipFile.cs | 244 --- BDInfo/TSStreamFile.cs | 1555 -------------------- .../BdInfo/BdInfoDirectoryInfo.cs | 74 + .../BdInfo/BdInfoExaminer.cs | 4 +- .../BdInfo/BdInfoFileInfo.cs | 40 + .../MediaBrowser.MediaEncoding.csproj | 2 +- MediaBrowser.sln | 2 - 27 files changed, 117 insertions(+), 6704 deletions(-) delete mode 100644 BDInfo/BDInfo.csproj delete mode 100644 BDInfo/BDInfoSettings.cs delete mode 100644 BDInfo/BDROM.cs delete mode 100644 BDInfo/LanguageCodes.cs delete mode 100644 BDInfo/Properties/AssemblyInfo.cs delete mode 100644 BDInfo/ReadMe.txt delete mode 100644 BDInfo/TSCodecAC3.cs delete mode 100644 BDInfo/TSCodecAVC.cs delete mode 100644 BDInfo/TSCodecDTS.cs delete mode 100644 BDInfo/TSCodecDTSHD.cs delete mode 100644 BDInfo/TSCodecLPCM.cs delete mode 100644 BDInfo/TSCodecMPEG2.cs delete mode 100644 BDInfo/TSCodecMVC.cs delete mode 100644 BDInfo/TSCodecTrueHD.cs delete mode 100644 BDInfo/TSCodecVC1.cs delete mode 100644 BDInfo/TSInterleavedFile.cs delete mode 100644 BDInfo/TSPlaylistFile.cs delete mode 100644 BDInfo/TSStream.cs delete mode 100644 BDInfo/TSStreamBuffer.cs delete mode 100644 BDInfo/TSStreamClip.cs delete mode 100644 BDInfo/TSStreamClipFile.cs delete mode 100644 BDInfo/TSStreamFile.cs create mode 100644 MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs create mode 100644 MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs diff --git a/BDInfo/BDInfo.csproj b/BDInfo/BDInfo.csproj deleted file mode 100644 index 9dbaa9e2f..000000000 --- a/BDInfo/BDInfo.csproj +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - netstandard2.0 - false - true - - - diff --git a/BDInfo/BDInfoSettings.cs b/BDInfo/BDInfoSettings.cs deleted file mode 100644 index f4cb30016..000000000 --- a/BDInfo/BDInfoSettings.cs +++ /dev/null @@ -1,33 +0,0 @@ - -namespace BDInfo -{ - class BDInfoSettings - { - public static bool GenerateStreamDiagnostics => true; - - public static bool EnableSSIF => true; - - public static bool AutosaveReport => false; - - public static bool GenerateFrameDataFile => false; - - public static bool FilterLoopingPlaylists => true; - - public static bool FilterShortPlaylists => false; - - public static int FilterShortPlaylistsValue => 0; - - public static bool UseImagePrefix => false; - - public static string UseImagePrefixValue => null; - - /// - /// Setting this to false throws an IComparer error on some discs. - /// - public static bool KeepStreamOrder => true; - - public static bool GenerateTextSummary => false; - - public static string LastPath => string.Empty; - } -} diff --git a/BDInfo/BDROM.cs b/BDInfo/BDROM.cs deleted file mode 100644 index 3a0c14ffd..000000000 --- a/BDInfo/BDROM.cs +++ /dev/null @@ -1,449 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using MediaBrowser.Model.IO; - -namespace BDInfo -{ - public class BDROM - { - public FileSystemMetadata DirectoryRoot = null; - public FileSystemMetadata DirectoryBDMV = null; - public FileSystemMetadata DirectoryBDJO = null; - public FileSystemMetadata DirectoryCLIPINF = null; - public FileSystemMetadata DirectoryPLAYLIST = null; - public FileSystemMetadata DirectorySNP = null; - public FileSystemMetadata DirectorySSIF = null; - public FileSystemMetadata DirectorySTREAM = null; - - public string VolumeLabel = null; - public ulong Size = 0; - public bool IsBDPlus = false; - public bool IsBDJava = false; - public bool IsDBOX = false; - public bool IsPSP = false; - public bool Is3D = false; - public bool Is50Hz = false; - - private readonly IFileSystem _fileSystem; - - public Dictionary PlaylistFiles = - new Dictionary(); - public Dictionary StreamClipFiles = - new Dictionary(); - public Dictionary StreamFiles = - new Dictionary(); - public Dictionary InterleavedFiles = - new Dictionary(); - - public delegate bool OnStreamClipFileScanError( - TSStreamClipFile streamClipFile, Exception ex); - - public event OnStreamClipFileScanError StreamClipFileScanError; - - public delegate bool OnStreamFileScanError( - TSStreamFile streamClipFile, Exception ex); - - public event OnStreamFileScanError StreamFileScanError; - - public delegate bool OnPlaylistFileScanError( - TSPlaylistFile playlistFile, Exception ex); - - public event OnPlaylistFileScanError PlaylistFileScanError; - - public BDROM(string path, IFileSystem fileSystem) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - _fileSystem = fileSystem; - // - // Locate BDMV directories. - // - - DirectoryBDMV = - GetDirectoryBDMV(path); - - if (DirectoryBDMV == null) - { - throw new Exception("Unable to locate BD structure."); - } - - DirectoryRoot = - _fileSystem.GetDirectoryInfo(Path.GetDirectoryName(DirectoryBDMV.FullName)); - DirectoryBDJO = - GetDirectory("BDJO", DirectoryBDMV, 0); - DirectoryCLIPINF = - GetDirectory("CLIPINF", DirectoryBDMV, 0); - DirectoryPLAYLIST = - GetDirectory("PLAYLIST", DirectoryBDMV, 0); - DirectorySNP = - GetDirectory("SNP", DirectoryRoot, 0); - DirectorySTREAM = - GetDirectory("STREAM", DirectoryBDMV, 0); - DirectorySSIF = - GetDirectory("SSIF", DirectorySTREAM, 0); - - if (DirectoryCLIPINF == null - || DirectoryPLAYLIST == null) - { - throw new Exception("Unable to locate BD structure."); - } - - // - // Initialize basic disc properties. - // - - VolumeLabel = GetVolumeLabel(DirectoryRoot); - Size = (ulong)GetDirectorySize(DirectoryRoot); - - if (null != GetDirectory("BDSVM", DirectoryRoot, 0)) - { - IsBDPlus = true; - } - if (null != GetDirectory("SLYVM", DirectoryRoot, 0)) - { - IsBDPlus = true; - } - if (null != GetDirectory("ANYVM", DirectoryRoot, 0)) - { - IsBDPlus = true; - } - - if (DirectoryBDJO != null && - _fileSystem.GetFilePaths(DirectoryBDJO.FullName).Any()) - { - IsBDJava = true; - } - - if (DirectorySNP != null && - GetFilePaths(DirectorySNP.FullName, ".mnv").Any()) - { - IsPSP = true; - } - - if (DirectorySSIF != null && - _fileSystem.GetFilePaths(DirectorySSIF.FullName).Any()) - { - Is3D = true; - } - - if (File.Exists(Path.Combine(DirectoryRoot.FullName, "FilmIndex.xml"))) - { - IsDBOX = true; - } - - // - // Initialize file lists. - // - - if (DirectoryPLAYLIST != null) - { - FileSystemMetadata[] files = GetFiles(DirectoryPLAYLIST.FullName, ".mpls").ToArray(); - foreach (var file in files) - { - PlaylistFiles.Add( - file.Name.ToUpper(), new TSPlaylistFile(this, file)); - } - } - - if (DirectorySTREAM != null) - { - FileSystemMetadata[] files = GetFiles(DirectorySTREAM.FullName, ".m2ts").ToArray(); - foreach (var file in files) - { - StreamFiles.Add( - file.Name.ToUpper(), new TSStreamFile(file, _fileSystem)); - } - } - - if (DirectoryCLIPINF != null) - { - FileSystemMetadata[] files = GetFiles(DirectoryCLIPINF.FullName, ".clpi").ToArray(); - foreach (var file in files) - { - StreamClipFiles.Add( - file.Name.ToUpper(), new TSStreamClipFile(file)); - } - } - - if (DirectorySSIF != null) - { - FileSystemMetadata[] files = GetFiles(DirectorySSIF.FullName, ".ssif").ToArray(); - foreach (var file in files) - { - InterleavedFiles.Add( - file.Name.ToUpper(), new TSInterleavedFile(file)); - } - } - } - - private IEnumerable GetFiles(string path, string extension) - { - return _fileSystem.GetFiles(path, new[] { extension }, false, false); - } - - private IEnumerable GetFilePaths(string path, string extension) - { - return _fileSystem.GetFilePaths(path, new[] { extension }, false, false); - } - - public void Scan() - { - foreach (var streamClipFile in StreamClipFiles.Values) - { - try - { - streamClipFile.Scan(); - } - catch (Exception ex) - { - if (StreamClipFileScanError != null) - { - if (StreamClipFileScanError(streamClipFile, ex)) - { - continue; - } - else - { - break; - } - } - else throw; - } - } - - foreach (var streamFile in StreamFiles.Values) - { - string ssifName = Path.GetFileNameWithoutExtension(streamFile.Name) + ".SSIF"; - if (InterleavedFiles.ContainsKey(ssifName)) - { - streamFile.InterleavedFile = InterleavedFiles[ssifName]; - } - } - - TSStreamFile[] streamFiles = new TSStreamFile[StreamFiles.Count]; - StreamFiles.Values.CopyTo(streamFiles, 0); - Array.Sort(streamFiles, CompareStreamFiles); - - foreach (var playlistFile in PlaylistFiles.Values) - { - try - { - playlistFile.Scan(StreamFiles, StreamClipFiles); - } - catch (Exception ex) - { - if (PlaylistFileScanError != null) - { - if (PlaylistFileScanError(playlistFile, ex)) - { - continue; - } - else - { - break; - } - } - else throw; - } - } - - foreach (var streamFile in streamFiles) - { - try - { - var playlists = new List(); - foreach (var playlist in PlaylistFiles.Values) - { - foreach (var streamClip in playlist.StreamClips) - { - if (streamClip.Name == streamFile.Name) - { - playlists.Add(playlist); - break; - } - } - } - streamFile.Scan(playlists, false); - } - catch (Exception ex) - { - if (StreamFileScanError != null) - { - if (StreamFileScanError(streamFile, ex)) - { - continue; - } - else - { - break; - } - } - else throw; - } - } - - foreach (var playlistFile in PlaylistFiles.Values) - { - playlistFile.Initialize(); - if (!Is50Hz) - { - foreach (var videoStream in playlistFile.VideoStreams) - { - if (videoStream.FrameRate == TSFrameRate.FRAMERATE_25 || - videoStream.FrameRate == TSFrameRate.FRAMERATE_50) - { - Is50Hz = true; - } - } - } - } - } - - private FileSystemMetadata GetDirectoryBDMV( - string path) - { - if (string.IsNullOrEmpty(path)) - { - throw new ArgumentNullException(nameof(path)); - } - - FileSystemMetadata dir = _fileSystem.GetDirectoryInfo(path); - - while (dir != null) - { - if (string.Equals(dir.Name, "BDMV", StringComparison.OrdinalIgnoreCase)) - { - return dir; - } - var parentFolder = Path.GetDirectoryName(dir.FullName); - if (string.IsNullOrEmpty(parentFolder)) - { - dir = null; - } - else - { - dir = _fileSystem.GetDirectoryInfo(parentFolder); - } - } - - return GetDirectory("BDMV", _fileSystem.GetDirectoryInfo(path), 0); - } - - private FileSystemMetadata GetDirectory( - string name, - FileSystemMetadata dir, - int searchDepth) - { - if (dir != null) - { - FileSystemMetadata[] children = _fileSystem.GetDirectories(dir.FullName).ToArray(); - foreach (var child in children) - { - if (string.Equals(child.Name, name, StringComparison.OrdinalIgnoreCase)) - { - return child; - } - } - if (searchDepth > 0) - { - foreach (var child in children) - { - GetDirectory( - name, child, searchDepth - 1); - } - } - } - return null; - } - - private long GetDirectorySize(FileSystemMetadata directoryInfo) - { - long size = 0; - - //if (!ExcludeDirs.Contains(directoryInfo.Name.ToUpper())) // TODO: Keep? - { - FileSystemMetadata[] pathFiles = _fileSystem.GetFiles(directoryInfo.FullName).ToArray(); - foreach (var pathFile in pathFiles) - { - if (pathFile.Extension.ToUpper() == ".SSIF") - { - continue; - } - size += pathFile.Length; - } - - FileSystemMetadata[] pathChildren = _fileSystem.GetDirectories(directoryInfo.FullName).ToArray(); - foreach (var pathChild in pathChildren) - { - size += GetDirectorySize(pathChild); - } - } - - return size; - } - - private string GetVolumeLabel(FileSystemMetadata dir) - { - return dir.Name; - } - - public int CompareStreamFiles( - TSStreamFile x, - TSStreamFile y) - { - // TODO: Use interleaved file sizes - - if ((x == null || x.FileInfo == null) && (y == null || y.FileInfo == null)) - { - return 0; - } - else if ((x == null || x.FileInfo == null) && (y != null && y.FileInfo != null)) - { - return 1; - } - else if ((x != null && x.FileInfo != null) && (y == null || y.FileInfo == null)) - { - return -1; - } - else - { - if (x.FileInfo.Length > y.FileInfo.Length) - { - return 1; - } - else if (y.FileInfo.Length > x.FileInfo.Length) - { - return -1; - } - else - { - return 0; - } - } - } - } -} diff --git a/BDInfo/LanguageCodes.cs b/BDInfo/LanguageCodes.cs deleted file mode 100644 index ab2693ffb..000000000 --- a/BDInfo/LanguageCodes.cs +++ /dev/null @@ -1,493 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - public abstract class LanguageCodes - { - public static string GetName(string code) - { - switch (code) - { - case "abk": return "Abkhazian"; - case "ace": return "Achinese"; - case "ach": return "Acoli"; - case "ada": return "Adangme"; - case "aar": return "Afar"; - case "afh": return "Afrihili"; - case "afr": return "Afrikaans"; - case "afa": return "Afro-Asiatic (Other)"; - case "aka": return "Akan"; - case "akk": return "Akkadian"; - case "alb": return "Albanian"; - case "sqi": return "Albanian"; - case "ale": return "Aleut"; - case "alg": return "Algonquian languages"; - case "tut": return "Altaic (Other)"; - case "amh": return "Amharic"; - case "apa": return "Apache languages"; - case "ara": return "Arabic"; - case "arc": return "Aramaic"; - case "arp": return "Arapaho"; - case "arn": return "Araucanian"; - case "arw": return "Arawak"; - case "arm": return "Armenian"; - case "hye": return "Armenian"; - case "art": return "Artificial (Other)"; - case "asm": return "Assamese"; - case "ath": return "Athapascan languages"; - case "aus": return "Australian languages"; - case "map": return "Austronesian (Other)"; - case "ava": return "Avaric"; - case "ave": return "Avestan"; - case "awa": return "Awadhi"; - case "aym": return "Aymara"; - case "aze": return "Azerbaijani"; - case "ban": return "Balinese"; - case "bat": return "Baltic (Other)"; - case "bal": return "Baluchi"; - case "bam": return "Bambara"; - case "bai": return "Bamileke languages"; - case "bad": return "Banda"; - case "bnt": return "Bantu (Other)"; - case "bas": return "Basa"; - case "bak": return "Bashkir"; - case "baq": return "Basque"; - case "eus": return "Basque"; - case "btk": return "Batak (Indonesia)"; - case "bej": return "Beja"; - case "bel": return "Belarusian"; - case "bem": return "Bemba"; - case "ben": return "Bengali"; - case "ber": return "Berber (Other)"; - case "bho": return "Bhojpuri"; - case "bih": return "Bihari"; - case "bik": return "Bikol"; - case "bin": return "Bini"; - case "bis": return "Bislama"; - case "bos": return "Bosnian"; - case "bra": return "Braj"; - case "bre": return "Breton"; - case "bug": return "Buginese"; - case "bul": return "Bulgarian"; - case "bua": return "Buriat"; - case "bur": return "Burmese"; - case "mya": return "Burmese"; - case "cad": return "Caddo"; - case "car": return "Carib"; - case "cat": return "Catalan"; - case "cau": return "Caucasian (Other)"; - case "ceb": return "Cebuano"; - case "cel": return "Celtic (Other)"; - case "cai": return "Central American Indian (Other)"; - case "chg": return "Chagatai"; - case "cmc": return "Chamic languages"; - case "cha": return "Chamorro"; - case "che": return "Chechen"; - case "chr": return "Cherokee"; - case "chy": return "Cheyenne"; - case "chb": return "Chibcha"; - case "chi": return "Chinese"; - case "zho": return "Chinese"; - case "chn": return "Chinook jargon"; - case "chp": return "Chipewyan"; - case "cho": return "Choctaw"; - case "chu": return "Church Slavic"; - case "chk": return "Chuukese"; - case "chv": return "Chuvash"; - case "cop": return "Coptic"; - case "cor": return "Cornish"; - case "cos": return "Corsican"; - case "cre": return "Cree"; - case "mus": return "Creek"; - case "crp": return "Creoles and pidgins (Other)"; - case "cpe": return "Creoles and pidgins,"; - case "cpf": return "Creoles and pidgins,"; - case "cpp": return "Creoles and pidgins,"; - case "scr": return "Croatian"; - case "hrv": return "Croatian"; - case "cus": return "Cushitic (Other)"; - case "cze": return "Czech"; - case "ces": return "Czech"; - case "dak": return "Dakota"; - case "dan": return "Danish"; - case "day": return "Dayak"; - case "del": return "Delaware"; - case "din": return "Dinka"; - case "div": return "Divehi"; - case "doi": return "Dogri"; - case "dgr": return "Dogrib"; - case "dra": return "Dravidian (Other)"; - case "dua": return "Duala"; - case "dut": return "Dutch"; - case "nld": return "Dutch"; - case "dum": return "Dutch, Middle (ca. 1050-1350)"; - case "dyu": return "Dyula"; - case "dzo": return "Dzongkha"; - case "efi": return "Efik"; - case "egy": return "Egyptian (Ancient)"; - case "eka": return "Ekajuk"; - case "elx": return "Elamite"; - case "eng": return "English"; - case "enm": return "English, Middle (1100-1500)"; - case "ang": return "English, Old (ca.450-1100)"; - case "epo": return "Esperanto"; - case "est": return "Estonian"; - case "ewe": return "Ewe"; - case "ewo": return "Ewondo"; - case "fan": return "Fang"; - case "fat": return "Fanti"; - case "fao": return "Faroese"; - case "fij": return "Fijian"; - case "fin": return "Finnish"; - case "fiu": return "Finno-Ugrian (Other)"; - case "fon": return "Fon"; - case "fre": return "French"; - case "fra": return "French"; - case "frm": return "French, Middle (ca.1400-1600)"; - case "fro": return "French, Old (842-ca.1400)"; - case "fry": return "Frisian"; - case "fur": return "Friulian"; - case "ful": return "Fulah"; - case "gaa": return "Ga"; - case "glg": return "Gallegan"; - case "lug": return "Ganda"; - case "gay": return "Gayo"; - case "gba": return "Gbaya"; - case "gez": return "Geez"; - case "geo": return "Georgian"; - case "kat": return "Georgian"; - case "ger": return "German"; - case "deu": return "German"; - case "nds": return "Saxon"; - case "gmh": return "German, Middle High (ca.1050-1500)"; - case "goh": return "German, Old High (ca.750-1050)"; - case "gem": return "Germanic (Other)"; - case "gil": return "Gilbertese"; - case "gon": return "Gondi"; - case "gor": return "Gorontalo"; - case "got": return "Gothic"; - case "grb": return "Grebo"; - case "grc": return "Greek, Ancient (to 1453)"; - case "gre": return "Greek"; - case "ell": return "Greek"; - case "grn": return "Guarani"; - case "guj": return "Gujarati"; - case "gwi": return "Gwich´in"; - case "hai": return "Haida"; - case "hau": return "Hausa"; - case "haw": return "Hawaiian"; - case "heb": return "Hebrew"; - case "her": return "Herero"; - case "hil": return "Hiligaynon"; - case "him": return "Himachali"; - case "hin": return "Hindi"; - case "hmo": return "Hiri Motu"; - case "hit": return "Hittite"; - case "hmn": return "Hmong"; - case "hun": return "Hungarian"; - case "hup": return "Hupa"; - case "iba": return "Iban"; - case "ice": return "Icelandic"; - case "isl": return "Icelandic"; - case "ibo": return "Igbo"; - case "ijo": return "Ijo"; - case "ilo": return "Iloko"; - case "inc": return "Indic (Other)"; - case "ine": return "Indo-European (Other)"; - case "ind": return "Indonesian"; - case "ina": return "Interlingua (International"; - case "ile": return "Interlingue"; - case "iku": return "Inuktitut"; - case "ipk": return "Inupiaq"; - case "ira": return "Iranian (Other)"; - case "gle": return "Irish"; - case "mga": return "Irish, Middle (900-1200)"; - case "sga": return "Irish, Old (to 900)"; - case "iro": return "Iroquoian languages"; - case "ita": return "Italian"; - case "jpn": return "Japanese"; - case "jav": return "Javanese"; - case "jrb": return "Judeo-Arabic"; - case "jpr": return "Judeo-Persian"; - case "kab": return "Kabyle"; - case "kac": return "Kachin"; - case "kal": return "Kalaallisut"; - case "kam": return "Kamba"; - case "kan": return "Kannada"; - case "kau": return "Kanuri"; - case "kaa": return "Kara-Kalpak"; - case "kar": return "Karen"; - case "kas": return "Kashmiri"; - case "kaw": return "Kawi"; - case "kaz": return "Kazakh"; - case "kha": return "Khasi"; - case "khm": return "Khmer"; - case "khi": return "Khoisan (Other)"; - case "kho": return "Khotanese"; - case "kik": return "Kikuyu"; - case "kmb": return "Kimbundu"; - case "kin": return "Kinyarwanda"; - case "kir": return "Kirghiz"; - case "kom": return "Komi"; - case "kon": return "Kongo"; - case "kok": return "Konkani"; - case "kor": return "Korean"; - case "kos": return "Kosraean"; - case "kpe": return "Kpelle"; - case "kro": return "Kru"; - case "kua": return "Kuanyama"; - case "kum": return "Kumyk"; - case "kur": return "Kurdish"; - case "kru": return "Kurukh"; - case "kut": return "Kutenai"; - case "lad": return "Ladino"; - case "lah": return "Lahnda"; - case "lam": return "Lamba"; - case "lao": return "Lao"; - case "lat": return "Latin"; - case "lav": return "Latvian"; - case "ltz": return "Letzeburgesch"; - case "lez": return "Lezghian"; - case "lin": return "Lingala"; - case "lit": return "Lithuanian"; - case "loz": return "Lozi"; - case "lub": return "Luba-Katanga"; - case "lua": return "Luba-Lulua"; - case "lui": return "Luiseno"; - case "lun": return "Lunda"; - case "luo": return "Luo (Kenya and Tanzania)"; - case "lus": return "Lushai"; - case "mac": return "Macedonian"; - case "mkd": return "Macedonian"; - case "mad": return "Madurese"; - case "mag": return "Magahi"; - case "mai": return "Maithili"; - case "mak": return "Makasar"; - case "mlg": return "Malagasy"; - case "may": return "Malay"; - case "msa": return "Malay"; - case "mal": return "Malayalam"; - case "mlt": return "Maltese"; - case "mnc": return "Manchu"; - case "mdr": return "Mandar"; - case "man": return "Mandingo"; - case "mni": return "Manipuri"; - case "mno": return "Manobo languages"; - case "glv": return "Manx"; - case "mao": return "Maori"; - case "mri": return "Maori"; - case "mar": return "Marathi"; - case "chm": return "Mari"; - case "mah": return "Marshall"; - case "mwr": return "Marwari"; - case "mas": return "Masai"; - case "myn": return "Mayan languages"; - case "men": return "Mende"; - case "mic": return "Micmac"; - case "min": return "Minangkabau"; - case "mis": return "Miscellaneous languages"; - case "moh": return "Mohawk"; - case "mol": return "Moldavian"; - case "mkh": return "Mon-Khmer (Other)"; - case "lol": return "Mongo"; - case "mon": return "Mongolian"; - case "mos": return "Mossi"; - case "mul": return "Multiple languages"; - case "mun": return "Munda languages"; - case "nah": return "Nahuatl"; - case "nau": return "Nauru"; - case "nav": return "Navajo"; - case "nde": return "Ndebele, North"; - case "nbl": return "Ndebele, South"; - case "ndo": return "Ndonga"; - case "nep": return "Nepali"; - case "new": return "Newari"; - case "nia": return "Nias"; - case "nic": return "Niger-Kordofanian (Other)"; - case "ssa": return "Nilo-Saharan (Other)"; - case "niu": return "Niuean"; - case "non": return "Norse, Old"; - case "nai": return "North American Indian (Other)"; - case "sme": return "Northern Sami"; - case "nor": return "Norwegian"; - case "nob": return "Norwegian Bokmål"; - case "nno": return "Norwegian Nynorsk"; - case "nub": return "Nubian languages"; - case "nym": return "Nyamwezi"; - case "nya": return "Nyanja"; - case "nyn": return "Nyankole"; - case "nyo": return "Nyoro"; - case "nzi": return "Nzima"; - case "oci": return "Occitan"; - case "oji": return "Ojibwa"; - case "ori": return "Oriya"; - case "orm": return "Oromo"; - case "osa": return "Osage"; - case "oss": return "Ossetian"; - case "oto": return "Otomian languages"; - case "pal": return "Pahlavi"; - case "pau": return "Palauan"; - case "pli": return "Pali"; - case "pam": return "Pampanga"; - case "pag": return "Pangasinan"; - case "pan": return "Panjabi"; - case "pap": return "Papiamento"; - case "paa": return "Papuan (Other)"; - case "per": return "Persian"; - case "fas": return "Persian"; - case "peo": return "Persian, Old (ca.600-400 B.C.)"; - case "phi": return "Philippine (Other)"; - case "phn": return "Phoenician"; - case "pon": return "Pohnpeian"; - case "pol": return "Polish"; - case "por": return "Portuguese"; - case "pra": return "Prakrit languages"; - case "pro": return "Provençal"; - case "pus": return "Pushto"; - case "que": return "Quechua"; - case "roh": return "Raeto-Romance"; - case "raj": return "Rajasthani"; - case "rap": return "Rapanui"; - case "rar": return "Rarotongan"; - case "roa": return "Romance (Other)"; - case "rum": return "Romanian"; - case "ron": return "Romanian"; - case "rom": return "Romany"; - case "run": return "Rundi"; - case "rus": return "Russian"; - case "sal": return "Salishan languages"; - case "sam": return "Samaritan Aramaic"; - case "smi": return "Sami languages (Other)"; - case "smo": return "Samoan"; - case "sad": return "Sandawe"; - case "sag": return "Sango"; - case "san": return "Sanskrit"; - case "sat": return "Santali"; - case "srd": return "Sardinian"; - case "sas": return "Sasak"; - case "sco": return "Scots"; - case "gla": return "Gaelic"; - case "sel": return "Selkup"; - case "sem": return "Semitic (Other)"; - case "scc": return "Serbian"; - case "srp": return "Serbian"; - case "srr": return "Serer"; - case "shn": return "Shan"; - case "sna": return "Shona"; - case "sid": return "Sidamo"; - case "sgn": return "Sign languages"; - case "bla": return "Siksika"; - case "snd": return "Sindhi"; - case "sin": return "Sinhalese"; - case "sit": return "Sino-Tibetan (Other)"; - case "sio": return "Siouan languages"; - case "den": return "Slave (Athapascan)"; - case "sla": return "Slavic (Other)"; - case "slo": return "Slovak"; - case "slk": return "Slovak"; - case "slv": return "Slovenian"; - case "sog": return "Sogdian"; - case "som": return "Somali"; - case "son": return "Songhai"; - case "snk": return "Soninke"; - case "wen": return "Sorbian languages"; - case "nso": return "Sotho, Northern"; - case "sot": return "Sotho, Southern"; - case "sai": return "South American Indian (Other)"; - case "spa": return "Spanish"; - case "suk": return "Sukuma"; - case "sux": return "Sumerian"; - case "sun": return "Sundanese"; - case "sus": return "Susu"; - case "swa": return "Swahili"; - case "ssw": return "Swati"; - case "swe": return "Swedish"; - case "syr": return "Syriac"; - case "tgl": return "Tagalog"; - case "tah": return "Tahitian"; - case "tai": return "Tai (Other)"; - case "tgk": return "Tajik"; - case "tmh": return "Tamashek"; - case "tam": return "Tamil"; - case "tat": return "Tatar"; - case "tel": return "Telugu"; - case "ter": return "Tereno"; - case "tet": return "Tetum"; - case "tha": return "Thai"; - case "tib": return "Tibetan"; - case "bod": return "Tibetan"; - case "tig": return "Tigre"; - case "tir": return "Tigrinya"; - case "tem": return "Timne"; - case "tiv": return "Tiv"; - case "tli": return "Tlingit"; - case "tpi": return "Tok Pisin"; - case "tkl": return "Tokelau"; - case "tog": return "Tonga (Nyasa)"; - case "ton": return "Tonga (Tonga Islands)"; - case "tsi": return "Tsimshian"; - case "tso": return "Tsonga"; - case "tsn": return "Tswana"; - case "tum": return "Tumbuka"; - case "tur": return "Turkish"; - case "ota": return "Turkish, Ottoman (1500-1928)"; - case "tuk": return "Turkmen"; - case "tvl": return "Tuvalu"; - case "tyv": return "Tuvinian"; - case "twi": return "Twi"; - case "uga": return "Ugaritic"; - case "uig": return "Uighur"; - case "ukr": return "Ukrainian"; - case "umb": return "Umbundu"; - case "und": return "Undetermined"; - case "urd": return "Urdu"; - case "uzb": return "Uzbek"; - case "vai": return "Vai"; - case "ven": return "Venda"; - case "vie": return "Vietnamese"; - case "vol": return "Volapük"; - case "vot": return "Votic"; - case "wak": return "Wakashan languages"; - case "wal": return "Walamo"; - case "war": return "Waray"; - case "was": return "Washo"; - case "wel": return "Welsh"; - case "cym": return "Welsh"; - case "wol": return "Wolof"; - case "xho": return "Xhosa"; - case "sah": return "Yakut"; - case "yao": return "Yao"; - case "yap": return "Yapese"; - case "yid": return "Yiddish"; - case "yor": return "Yoruba"; - case "ypk": return "Yupik languages"; - case "znd": return "Zande"; - case "zap": return "Zapotec"; - case "zen": return "Zenaga"; - case "zha": return "Zhuang"; - case "zul": return "Zulu"; - case "zun": return "Zuni"; - - default: return code; - } - } - } -} diff --git a/BDInfo/Properties/AssemblyInfo.cs b/BDInfo/Properties/AssemblyInfo.cs deleted file mode 100644 index f65c7036a..000000000 --- a/BDInfo/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System.Reflection; -using System.Resources; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("BDInfo")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("Jellyfin Project")] -[assembly: AssemblyProduct("Jellyfin Server")] -[assembly: AssemblyCopyright("Copyright © 2016 CinemaSquid. Copyright © 2019 Jellyfin Contributors. Code released under the GNU General Public License")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: NeutralResourcesLanguage("en")] - -// Setting ComVisible to false makes the types in this assembly not visible -// to COM components. If you need to access a type in this assembly from -// COM, set the ComVisible attribute to true on that type. -[assembly: ComVisible(false)] diff --git a/BDInfo/ReadMe.txt b/BDInfo/ReadMe.txt deleted file mode 100644 index e70b0b66c..000000000 --- a/BDInfo/ReadMe.txt +++ /dev/null @@ -1,5 +0,0 @@ -The source is taken from the BDRom folder of this project: - -http://www.cinemasquid.com/blu-ray/tools/bdinfo - -BDInfoSettings was taken from the FormSettings class, and changed so that the settings all return defaults. diff --git a/BDInfo/TSCodecAC3.cs b/BDInfo/TSCodecAC3.cs deleted file mode 100644 index 35d306a19..000000000 --- a/BDInfo/TSCodecAC3.cs +++ /dev/null @@ -1,309 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -#undef DEBUG -using System.IO; - -namespace BDInfo -{ - public abstract class TSCodecAC3 - { - private static byte[] eac3_blocks = new byte[] { 1, 2, 3, 6 }; - - public static void Scan( - TSAudioStream stream, - TSStreamBuffer buffer, - ref string tag) - { - if (stream.IsInitialized) return; - - byte[] sync = buffer.ReadBytes(2); - if (sync == null || - sync[0] != 0x0B || - sync[1] != 0x77) - { - return; - } - - int sr_code = 0; - int frame_size = 0; - int frame_size_code = 0; - int channel_mode = 0; - int lfe_on = 0; - int dial_norm = 0; - int num_blocks = 0; - - byte[] hdr = buffer.ReadBytes(4); - int bsid = (hdr[3] & 0xF8) >> 3; - buffer.Seek(-4, SeekOrigin.Current); - if (bsid <= 10) - { - byte[] crc = buffer.ReadBytes(2); - sr_code = buffer.ReadBits(2); - frame_size_code = buffer.ReadBits(6); - bsid = buffer.ReadBits(5); - int bsmod = buffer.ReadBits(3); - - channel_mode = buffer.ReadBits(3); - int cmixlev = 0; - if (((channel_mode & 0x1) > 0) && (channel_mode != 0x1)) - { - cmixlev = buffer.ReadBits(2); - } - int surmixlev = 0; - if ((channel_mode & 0x4) > 0) - { - surmixlev = buffer.ReadBits(2); - } - int dsurmod = 0; - if (channel_mode == 0x2) - { - dsurmod = buffer.ReadBits(2); - if (dsurmod == 0x2) - { - stream.AudioMode = TSAudioMode.Surround; - } - } - lfe_on = buffer.ReadBits(1); - dial_norm = buffer.ReadBits(5); - int compr = 0; - if (1 == buffer.ReadBits(1)) - { - compr = buffer.ReadBits(8); - } - int langcod = 0; - if (1 == buffer.ReadBits(1)) - { - langcod = buffer.ReadBits(8); - } - int mixlevel = 0; - int roomtyp = 0; - if (1 == buffer.ReadBits(1)) - { - mixlevel = buffer.ReadBits(5); - roomtyp = buffer.ReadBits(2); - } - if (channel_mode == 0) - { - int dialnorm2 = buffer.ReadBits(5); - int compr2 = 0; - if (1 == buffer.ReadBits(1)) - { - compr2 = buffer.ReadBits(8); - } - int langcod2 = 0; - if (1 == buffer.ReadBits(1)) - { - langcod2 = buffer.ReadBits(8); - } - int mixlevel2 = 0; - int roomtyp2 = 0; - if (1 == buffer.ReadBits(1)) - { - mixlevel2 = buffer.ReadBits(5); - roomtyp2 = buffer.ReadBits(2); - } - } - int copyrightb = buffer.ReadBits(1); - int origbs = buffer.ReadBits(1); - if (bsid == 6) - { - if (1 == buffer.ReadBits(1)) - { - int dmixmod = buffer.ReadBits(2); - int ltrtcmixlev = buffer.ReadBits(3); - int ltrtsurmixlev = buffer.ReadBits(3); - int lorocmixlev = buffer.ReadBits(3); - int lorosurmixlev = buffer.ReadBits(3); - } - if (1 == buffer.ReadBits(1)) - { - int dsurexmod = buffer.ReadBits(2); - int dheadphonmod = buffer.ReadBits(2); - if (dheadphonmod == 0x2) - { - // TODO - } - int adconvtyp = buffer.ReadBits(1); - int xbsi2 = buffer.ReadBits(8); - int encinfo = buffer.ReadBits(1); - if (dsurexmod == 2) - { - stream.AudioMode = TSAudioMode.Extended; - } - } - } - } - else - { - int frame_type = buffer.ReadBits(2); - int substreamid = buffer.ReadBits(3); - frame_size = (buffer.ReadBits(11) + 1) << 1; - - sr_code = buffer.ReadBits(2); - if (sr_code == 3) - { - sr_code = buffer.ReadBits(2); - } - else - { - num_blocks = buffer.ReadBits(2); - } - channel_mode = buffer.ReadBits(3); - lfe_on = buffer.ReadBits(1); - } - - switch (channel_mode) - { - case 0: // 1+1 - stream.ChannelCount = 2; - if (stream.AudioMode == TSAudioMode.Unknown) - { - stream.AudioMode = TSAudioMode.DualMono; - } - break; - case 1: // 1/0 - stream.ChannelCount = 1; - break; - case 2: // 2/0 - stream.ChannelCount = 2; - if (stream.AudioMode == TSAudioMode.Unknown) - { - stream.AudioMode = TSAudioMode.Stereo; - } - break; - case 3: // 3/0 - stream.ChannelCount = 3; - break; - case 4: // 2/1 - stream.ChannelCount = 3; - break; - case 5: // 3/1 - stream.ChannelCount = 4; - break; - case 6: // 2/2 - stream.ChannelCount = 4; - break; - case 7: // 3/2 - stream.ChannelCount = 5; - break; - default: - stream.ChannelCount = 0; - break; - } - - switch (sr_code) - { - case 0: - stream.SampleRate = 48000; - break; - case 1: - stream.SampleRate = 44100; - break; - case 2: - stream.SampleRate = 32000; - break; - default: - stream.SampleRate = 0; - break; - } - - if (bsid <= 10) - { - switch (frame_size_code >> 1) - { - case 18: - stream.BitRate = 640000; - break; - case 17: - stream.BitRate = 576000; - break; - case 16: - stream.BitRate = 512000; - break; - case 15: - stream.BitRate = 448000; - break; - case 14: - stream.BitRate = 384000; - break; - case 13: - stream.BitRate = 320000; - break; - case 12: - stream.BitRate = 256000; - break; - case 11: - stream.BitRate = 224000; - break; - case 10: - stream.BitRate = 192000; - break; - case 9: - stream.BitRate = 160000; - break; - case 8: - stream.BitRate = 128000; - break; - case 7: - stream.BitRate = 112000; - break; - case 6: - stream.BitRate = 96000; - break; - case 5: - stream.BitRate = 80000; - break; - case 4: - stream.BitRate = 64000; - break; - case 3: - stream.BitRate = 56000; - break; - case 2: - stream.BitRate = 48000; - break; - case 1: - stream.BitRate = 40000; - break; - case 0: - stream.BitRate = 32000; - break; - default: - stream.BitRate = 0; - break; - } - } - else - { - stream.BitRate = (long) - (4.0 * frame_size * stream.SampleRate / (num_blocks * 256)); - } - - stream.LFE = lfe_on; - if (stream.StreamType != TSStreamType.AC3_PLUS_AUDIO && - stream.StreamType != TSStreamType.AC3_PLUS_SECONDARY_AUDIO) - { - stream.DialNorm = dial_norm - 31; - } - stream.IsVBR = false; - stream.IsInitialized = true; - } - } -} diff --git a/BDInfo/TSCodecAVC.cs b/BDInfo/TSCodecAVC.cs deleted file mode 100644 index 5833d169f..000000000 --- a/BDInfo/TSCodecAVC.cs +++ /dev/null @@ -1,148 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - public abstract class TSCodecAVC - { - public static void Scan( - TSVideoStream stream, - TSStreamBuffer buffer, - ref string tag) - { - uint parse = 0; - byte accessUnitDelimiterParse = 0; - byte sequenceParameterSetParse = 0; - string profile = null; - string level = null; - byte constraintSet0Flag = 0; - byte constraintSet1Flag = 0; - byte constraintSet2Flag = 0; - byte constraintSet3Flag = 0; - - for (int i = 0; i < buffer.Length; i++) - { - parse = (parse << 8) + buffer.ReadByte(); - - if (parse == 0x00000109) - { - accessUnitDelimiterParse = 1; - } - else if (accessUnitDelimiterParse > 0) - { - --accessUnitDelimiterParse; - if (accessUnitDelimiterParse == 0) - { - switch ((parse & 0xFF) >> 5) - { - case 0: // I - case 3: // SI - case 5: // I, SI - tag = "I"; - break; - - case 1: // I, P - case 4: // SI, SP - case 6: // I, SI, P, SP - tag = "P"; - break; - - case 2: // I, P, B - case 7: // I, SI, P, SP, B - tag = "B"; - break; - } - if (stream.IsInitialized) return; - } - } - else if (parse == 0x00000127 || parse == 0x00000167) - { - sequenceParameterSetParse = 3; - } - else if (sequenceParameterSetParse > 0) - { - --sequenceParameterSetParse; - switch (sequenceParameterSetParse) - { - case 2: - switch (parse & 0xFF) - { - case 66: - profile = "Baseline Profile"; - break; - case 77: - profile = "Main Profile"; - break; - case 88: - profile = "Extended Profile"; - break; - case 100: - profile = "High Profile"; - break; - case 110: - profile = "High 10 Profile"; - break; - case 122: - profile = "High 4:2:2 Profile"; - break; - case 144: - profile = "High 4:4:4 Profile"; - break; - default: - profile = "Unknown Profile"; - break; - } - break; - - case 1: - constraintSet0Flag = (byte) - ((parse & 0x80) >> 7); - constraintSet1Flag = (byte) - ((parse & 0x40) >> 6); - constraintSet2Flag = (byte) - ((parse & 0x20) >> 5); - constraintSet3Flag = (byte) - ((parse & 0x10) >> 4); - break; - - case 0: - byte b = (byte)(parse & 0xFF); - if (b == 11 && constraintSet3Flag == 1) - { - level = "1b"; - } - else - { - level = string.Format( - "{0:D}.{1:D}", - b / 10, (b - ((b / 10) * 10))); - } - stream.EncodingProfile = string.Format( - "{0} {1}", profile, level); - stream.IsVBR = true; - stream.IsInitialized = true; - break; - } - } - } - return; - } - } -} diff --git a/BDInfo/TSCodecDTS.cs b/BDInfo/TSCodecDTS.cs deleted file mode 100644 index ff94cb702..000000000 --- a/BDInfo/TSCodecDTS.cs +++ /dev/null @@ -1,159 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - public abstract class TSCodecDTS - { - private static int[] dca_sample_rates = - { - 0, 8000, 16000, 32000, 0, 0, 11025, 22050, 44100, 0, 0, - 12000, 24000, 48000, 96000, 192000 - }; - - private static int[] dca_bit_rates = - { - 32000, 56000, 64000, 96000, 112000, 128000, - 192000, 224000, 256000, 320000, 384000, - 448000, 512000, 576000, 640000, 768000, - 896000, 1024000, 1152000, 1280000, 1344000, - 1408000, 1411200, 1472000, 1509000, 1920000, - 2048000, 3072000, 3840000, 1/*open*/, 2/*variable*/, 3/*lossless*/ - }; - - private static int[] dca_channels = - { - 1, 2, 2, 2, 2, 3, 3, 4, 4, 5, 6, 6, 6, 7, 8, 8 - }; - - private static int[] dca_bits_per_sample = - { - 16, 16, 20, 20, 0, 24, 24 - }; - - public static void Scan( - TSAudioStream stream, - TSStreamBuffer buffer, - long bitrate, - ref string tag) - { - if (stream.IsInitialized) return; - - bool syncFound = false; - uint sync = 0; - for (int i = 0; i < buffer.Length; i++) - { - sync = (sync << 8) + buffer.ReadByte(); - if (sync == 0x7FFE8001) - { - syncFound = true; - break; - } - } - if (!syncFound) return; - - int frame_type = buffer.ReadBits(1); - int samples_deficit = buffer.ReadBits(5); - int crc_present = buffer.ReadBits(1); - int sample_blocks = buffer.ReadBits(7); - int frame_size = buffer.ReadBits(14); - if (frame_size < 95) - { - return; - } - int amode = buffer.ReadBits(6); - int sample_rate = buffer.ReadBits(4); - if (sample_rate < 0 || sample_rate >= dca_sample_rates.Length) - { - return; - } - int bit_rate = buffer.ReadBits(5); - if (bit_rate < 0 || bit_rate >= dca_bit_rates.Length) - { - return; - } - int downmix = buffer.ReadBits(1); - int dynrange = buffer.ReadBits(1); - int timestamp = buffer.ReadBits(1); - int aux_data = buffer.ReadBits(1); - int hdcd = buffer.ReadBits(1); - int ext_descr = buffer.ReadBits(3); - int ext_coding = buffer.ReadBits(1); - int aspf = buffer.ReadBits(1); - int lfe = buffer.ReadBits(2); - int predictor_history = buffer.ReadBits(1); - if (crc_present == 1) - { - int crc = buffer.ReadBits(16); - } - int multirate_inter = buffer.ReadBits(1); - int version = buffer.ReadBits(4); - int copy_history = buffer.ReadBits(2); - int source_pcm_res = buffer.ReadBits(3); - int front_sum = buffer.ReadBits(1); - int surround_sum = buffer.ReadBits(1); - int dialog_norm = buffer.ReadBits(4); - if (source_pcm_res < 0 || source_pcm_res >= dca_bits_per_sample.Length) - { - return; - } - int subframes = buffer.ReadBits(4); - int total_channels = buffer.ReadBits(3) + 1 + ext_coding; - - stream.SampleRate = dca_sample_rates[sample_rate]; - stream.ChannelCount = total_channels; - stream.LFE = (lfe > 0 ? 1 : 0); - stream.BitDepth = dca_bits_per_sample[source_pcm_res]; - stream.DialNorm = -dialog_norm; - if ((source_pcm_res & 0x1) == 0x1) - { - stream.AudioMode = TSAudioMode.Extended; - } - - stream.BitRate = (uint)dca_bit_rates[bit_rate]; - switch (stream.BitRate) - { - case 1: - if (bitrate > 0) - { - stream.BitRate = bitrate; - stream.IsVBR = false; - stream.IsInitialized = true; - } - else - { - stream.BitRate = 0; - } - break; - - case 2: - case 3: - stream.IsVBR = true; - stream.IsInitialized = true; - break; - - default: - stream.IsVBR = false; - stream.IsInitialized = true; - break; - } - } - } -} diff --git a/BDInfo/TSCodecDTSHD.cs b/BDInfo/TSCodecDTSHD.cs deleted file mode 100644 index 57a136d2d..000000000 --- a/BDInfo/TSCodecDTSHD.cs +++ /dev/null @@ -1,246 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - public abstract class TSCodecDTSHD - { - private static int[] SampleRates = new int[] - { 0x1F40, 0x3E80, 0x7D00, 0x0FA00, 0x1F400, 0x5622, 0x0AC44, 0x15888, 0x2B110, 0x56220, 0x2EE0, 0x5DC0, 0x0BB80, 0x17700, 0x2EE00, 0x5DC00 }; - - public static void Scan( - TSAudioStream stream, - TSStreamBuffer buffer, - long bitrate, - ref string tag) - { - if (stream.IsInitialized && - (stream.StreamType == TSStreamType.DTS_HD_SECONDARY_AUDIO || - (stream.CoreStream != null && - stream.CoreStream.IsInitialized))) return; - - bool syncFound = false; - uint sync = 0; - for (int i = 0; i < buffer.Length; i++) - { - sync = (sync << 8) + buffer.ReadByte(); - if (sync == 0x64582025) - { - syncFound = true; - break; - } - } - - if (!syncFound) - { - tag = "CORE"; - if (stream.CoreStream == null) - { - stream.CoreStream = new TSAudioStream(); - stream.CoreStream.StreamType = TSStreamType.DTS_AUDIO; - } - if (!stream.CoreStream.IsInitialized) - { - buffer.BeginRead(); - TSCodecDTS.Scan(stream.CoreStream, buffer, bitrate, ref tag); - } - return; - } - - tag = "HD"; - int temp1 = buffer.ReadBits(8); - int nuSubStreamIndex = buffer.ReadBits(2); - int nuExtSSHeaderSize = 0; - int nuExtSSFSize = 0; - int bBlownUpHeader = buffer.ReadBits(1); - if (1 == bBlownUpHeader) - { - nuExtSSHeaderSize = buffer.ReadBits(12) + 1; - nuExtSSFSize = buffer.ReadBits(20) + 1; - } - else - { - nuExtSSHeaderSize = buffer.ReadBits(8) + 1; - nuExtSSFSize = buffer.ReadBits(16) + 1; - } - int nuNumAudioPresent = 1; - int nuNumAssets = 1; - int bStaticFieldsPresent = buffer.ReadBits(1); - if (1 == bStaticFieldsPresent) - { - int nuRefClockCode = buffer.ReadBits(2); - int nuExSSFrameDurationCode = buffer.ReadBits(3) + 1; - long nuTimeStamp = 0; - if (1 == buffer.ReadBits(1)) - { - nuTimeStamp = (buffer.ReadBits(18) << 18) + buffer.ReadBits(18); - } - nuNumAudioPresent = buffer.ReadBits(3) + 1; - nuNumAssets = buffer.ReadBits(3) + 1; - int[] nuActiveExSSMask = new int[nuNumAudioPresent]; - for (int i = 0; i < nuNumAudioPresent; i++) - { - nuActiveExSSMask[i] = buffer.ReadBits(nuSubStreamIndex + 1); //? - } - for (int i = 0; i < nuNumAudioPresent; i++) - { - for (int j = 0; j < nuSubStreamIndex + 1; j++) - { - if (((j + 1) % 2) == 1) - { - int mask = buffer.ReadBits(8); - } - } - } - if (1 == buffer.ReadBits(1)) - { - int nuMixMetadataAdjLevel = buffer.ReadBits(2); - int nuBits4MixOutMask = buffer.ReadBits(2) * 4 + 4; - int nuNumMixOutConfigs = buffer.ReadBits(2) + 1; - int[] nuMixOutChMask = new int[nuNumMixOutConfigs]; - for (int i = 0; i < nuNumMixOutConfigs; i++) - { - nuMixOutChMask[i] = buffer.ReadBits(nuBits4MixOutMask); - } - } - } - int[] AssetSizes = new int[nuNumAssets]; - for (int i = 0; i < nuNumAssets; i++) - { - if (1 == bBlownUpHeader) - { - AssetSizes[i] = buffer.ReadBits(20) + 1; - } - else - { - AssetSizes[i] = buffer.ReadBits(16) + 1; - } - } - for (int i = 0; i < nuNumAssets; i++) - { - long bufferPosition = buffer.Position; - int nuAssetDescriptorFSIZE = buffer.ReadBits(9) + 1; - int DescriptorDataForAssetIndex = buffer.ReadBits(3); - if (1 == bStaticFieldsPresent) - { - int AssetTypeDescrPresent = buffer.ReadBits(1); - if (1 == AssetTypeDescrPresent) - { - int AssetTypeDescriptor = buffer.ReadBits(4); - } - int LanguageDescrPresent = buffer.ReadBits(1); - if (1 == LanguageDescrPresent) - { - int LanguageDescriptor = buffer.ReadBits(24); - } - int bInfoTextPresent = buffer.ReadBits(1); - if (1 == bInfoTextPresent) - { - int nuInfoTextByteSize = buffer.ReadBits(10) + 1; - int[] InfoText = new int[nuInfoTextByteSize]; - for (int j = 0; j < nuInfoTextByteSize; j++) - { - InfoText[j] = buffer.ReadBits(8); - } - } - int nuBitResolution = buffer.ReadBits(5) + 1; - int nuMaxSampleRate = buffer.ReadBits(4); - int nuTotalNumChs = buffer.ReadBits(8) + 1; - int bOne2OneMapChannels2Speakers = buffer.ReadBits(1); - int nuSpkrActivityMask = 0; - if (1 == bOne2OneMapChannels2Speakers) - { - int bEmbeddedStereoFlag = 0; - if (nuTotalNumChs > 2) - { - bEmbeddedStereoFlag = buffer.ReadBits(1); - } - int bEmbeddedSixChFlag = 0; - if (nuTotalNumChs > 6) - { - bEmbeddedSixChFlag = buffer.ReadBits(1); - } - int bSpkrMaskEnabled = buffer.ReadBits(1); - int nuNumBits4SAMask = 0; - if (1 == bSpkrMaskEnabled) - { - nuNumBits4SAMask = buffer.ReadBits(2); - nuNumBits4SAMask = nuNumBits4SAMask * 4 + 4; - nuSpkrActivityMask = buffer.ReadBits(nuNumBits4SAMask); - } - // TODO... - } - stream.SampleRate = SampleRates[nuMaxSampleRate]; - stream.BitDepth = nuBitResolution; - - stream.LFE = 0; - if ((nuSpkrActivityMask & 0x8) == 0x8) - { - ++stream.LFE; - } - if ((nuSpkrActivityMask & 0x1000) == 0x1000) - { - ++stream.LFE; - } - stream.ChannelCount = nuTotalNumChs - stream.LFE; - } - if (nuNumAssets > 1) - { - // TODO... - break; - } - } - - // TODO - if (stream.CoreStream != null) - { - var coreStream = (TSAudioStream)stream.CoreStream; - if (coreStream.AudioMode == TSAudioMode.Extended && - stream.ChannelCount == 5) - { - stream.AudioMode = TSAudioMode.Extended; - } - /* - if (coreStream.DialNorm != 0) - { - stream.DialNorm = coreStream.DialNorm; - } - */ - } - - if (stream.StreamType == TSStreamType.DTS_HD_MASTER_AUDIO) - { - stream.IsVBR = true; - stream.IsInitialized = true; - } - else if (bitrate > 0) - { - stream.IsVBR = false; - stream.BitRate = bitrate; - if (stream.CoreStream != null) - { - stream.BitRate += stream.CoreStream.BitRate; - stream.IsInitialized = true; - } - stream.IsInitialized = (stream.BitRate > 0 ? true : false); - } - } - } -} diff --git a/BDInfo/TSCodecLPCM.cs b/BDInfo/TSCodecLPCM.cs deleted file mode 100644 index 5709d8689..000000000 --- a/BDInfo/TSCodecLPCM.cs +++ /dev/null @@ -1,123 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - public abstract class TSCodecLPCM - { - public static void Scan( - TSAudioStream stream, - TSStreamBuffer buffer, - ref string tag) - { - if (stream.IsInitialized) return; - - byte[] header = buffer.ReadBytes(4); - int flags = (header[2] << 8) + header[3]; - - switch ((flags & 0xF000) >> 12) - { - case 1: // 1/0/0 - stream.ChannelCount = 1; - stream.LFE = 0; - break; - case 3: // 2/0/0 - stream.ChannelCount = 2; - stream.LFE = 0; - break; - case 4: // 3/0/0 - stream.ChannelCount = 3; - stream.LFE = 0; - break; - case 5: // 2/1/0 - stream.ChannelCount = 3; - stream.LFE = 0; - break; - case 6: // 3/1/0 - stream.ChannelCount = 4; - stream.LFE = 0; - break; - case 7: // 2/2/0 - stream.ChannelCount = 4; - stream.LFE = 0; - break; - case 8: // 3/2/0 - stream.ChannelCount = 5; - stream.LFE = 0; - break; - case 9: // 3/2/1 - stream.ChannelCount = 5; - stream.LFE = 1; - break; - case 10: // 3/4/0 - stream.ChannelCount = 7; - stream.LFE = 0; - break; - case 11: // 3/4/1 - stream.ChannelCount = 7; - stream.LFE = 1; - break; - default: - stream.ChannelCount = 0; - stream.LFE = 0; - break; - } - - switch ((flags & 0xC0) >> 6) - { - case 1: - stream.BitDepth = 16; - break; - case 2: - stream.BitDepth = 20; - break; - case 3: - stream.BitDepth = 24; - break; - default: - stream.BitDepth = 0; - break; - } - - switch ((flags & 0xF00) >> 8) - { - case 1: - stream.SampleRate = 48000; - break; - case 4: - stream.SampleRate = 96000; - break; - case 5: - stream.SampleRate = 192000; - break; - default: - stream.SampleRate = 0; - break; - } - - stream.BitRate = (uint) - (stream.SampleRate * stream.BitDepth * - (stream.ChannelCount + stream.LFE)); - - stream.IsVBR = false; - stream.IsInitialized = true; - } - } -} diff --git a/BDInfo/TSCodecMPEG2.cs b/BDInfo/TSCodecMPEG2.cs deleted file mode 100644 index 8bcd07d02..000000000 --- a/BDInfo/TSCodecMPEG2.cs +++ /dev/null @@ -1,208 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -#undef DEBUG - - -namespace BDInfo -{ - public abstract class TSCodecMPEG2 - { - public static void Scan( - TSVideoStream stream, - TSStreamBuffer buffer, - ref string tag) - { - int parse = 0; - int pictureParse = 0; - int sequenceHeaderParse = 0; - int extensionParse = 0; - int sequenceExtensionParse = 0; - - for (int i = 0; i < buffer.Length; i++) - { - parse = (parse << 8) + buffer.ReadByte(); - - if (parse == 0x00000100) - { - pictureParse = 2; - } - else if (parse == 0x000001B3) - { - sequenceHeaderParse = 7; - } - else if (sequenceHeaderParse > 0) - { - --sequenceHeaderParse; - switch (sequenceHeaderParse) - { -#if DEBUG - case 6: - break; - - case 5: - break; - - case 4: - stream.Width = - (int)((parse & 0xFFF000) >> 12); - stream.Height = - (int)(parse & 0xFFF); - break; - - case 3: - stream.AspectRatio = - (TSAspectRatio)((parse & 0xF0) >> 4); - - switch ((parse & 0xF0) >> 4) - { - case 0: // Forbidden - break; - case 1: // Square - break; - case 2: // 4:3 - break; - case 3: // 16:9 - break; - case 4: // 2.21:1 - break; - default: // Reserved - break; - } - - switch (parse & 0xF) - { - case 0: // Forbidden - break; - case 1: // 23.976 - stream.FrameRateEnumerator = 24000; - stream.FrameRateDenominator = 1001; - break; - case 2: // 24 - stream.FrameRateEnumerator = 24000; - stream.FrameRateDenominator = 1000; - break; - case 3: // 25 - stream.FrameRateEnumerator = 25000; - stream.FrameRateDenominator = 1000; - break; - case 4: // 29.97 - stream.FrameRateEnumerator = 30000; - stream.FrameRateDenominator = 1001; - break; - case 5: // 30 - stream.FrameRateEnumerator = 30000; - stream.FrameRateDenominator = 1000; - break; - case 6: // 50 - stream.FrameRateEnumerator = 50000; - stream.FrameRateDenominator = 1000; - break; - case 7: // 59.94 - stream.FrameRateEnumerator = 60000; - stream.FrameRateDenominator = 1001; - break; - case 8: // 60 - stream.FrameRateEnumerator = 60000; - stream.FrameRateDenominator = 1000; - break; - default: // Reserved - stream.FrameRateEnumerator = 0; - stream.FrameRateDenominator = 0; - break; - } - break; - - case 2: - break; - - case 1: - break; -#endif - - case 0: -#if DEBUG - stream.BitRate = - (((parse & 0xFFFFC0) >> 6) * 200); -#endif - stream.IsVBR = true; - stream.IsInitialized = true; - break; - } - } - else if (pictureParse > 0) - { - --pictureParse; - if (pictureParse == 0) - { - switch ((parse & 0x38) >> 3) - { - case 1: - tag = "I"; - break; - case 2: - tag = "P"; - break; - case 3: - tag = "B"; - break; - default: - break; - } - if (stream.IsInitialized) return; - } - } - else if (parse == 0x000001B5) - { - extensionParse = 1; - } - else if (extensionParse > 0) - { - --extensionParse; - if (extensionParse == 0) - { - if ((parse & 0xF0) == 0x10) - { - sequenceExtensionParse = 1; - } - } - } - else if (sequenceExtensionParse > 0) - { - --sequenceExtensionParse; -#if DEBUG - if (sequenceExtensionParse == 0) - { - uint sequenceExtension = - ((parse & 0x8) >> 3); - if (sequenceExtension == 0) - { - stream.IsInterlaced = true; - } - else - { - stream.IsInterlaced = false; - } - } -#endif - } - } - } - } -} diff --git a/BDInfo/TSCodecMVC.cs b/BDInfo/TSCodecMVC.cs deleted file mode 100644 index abff0c1b0..000000000 --- a/BDInfo/TSCodecMVC.cs +++ /dev/null @@ -1,36 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - // TODO: Do something more interesting here... - - public abstract class TSCodecMVC - { - public static void Scan( - TSVideoStream stream, - TSStreamBuffer buffer, - ref string tag) - { - stream.IsVBR = true; - stream.IsInitialized = true; - } - } -} diff --git a/BDInfo/TSCodecTrueHD.cs b/BDInfo/TSCodecTrueHD.cs deleted file mode 100644 index 5e81e162c..000000000 --- a/BDInfo/TSCodecTrueHD.cs +++ /dev/null @@ -1,186 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - public abstract class TSCodecTrueHD - { - public static void Scan( - TSAudioStream stream, - TSStreamBuffer buffer, - ref string tag) - { - if (stream.IsInitialized && - stream.CoreStream != null && - stream.CoreStream.IsInitialized) return; - - bool syncFound = false; - uint sync = 0; - for (int i = 0; i < buffer.Length; i++) - { - sync = (sync << 8) + buffer.ReadByte(); - if (sync == 0xF8726FBA) - { - syncFound = true; - break; - } - } - - if (!syncFound) - { - tag = "CORE"; - if (stream.CoreStream == null) - { - stream.CoreStream = new TSAudioStream(); - stream.CoreStream.StreamType = TSStreamType.AC3_AUDIO; - } - if (!stream.CoreStream.IsInitialized) - { - buffer.BeginRead(); - TSCodecAC3.Scan(stream.CoreStream, buffer, ref tag); - } - return; - } - - tag = "HD"; - int ratebits = buffer.ReadBits(4); - if (ratebits != 0xF) - { - stream.SampleRate = - (((ratebits & 8) > 0 ? 44100 : 48000) << (ratebits & 7)); - } - int temp1 = buffer.ReadBits(8); - int channels_thd_stream1 = buffer.ReadBits(5); - int temp2 = buffer.ReadBits(2); - - stream.ChannelCount = 0; - stream.LFE = 0; - int c_LFE2 = buffer.ReadBits(1); - if (c_LFE2 == 1) - { - stream.LFE += 1; - } - int c_Cvh = buffer.ReadBits(1); - if (c_Cvh == 1) - { - stream.ChannelCount += 1; - } - int c_LRw = buffer.ReadBits(1); - if (c_LRw == 1) - { - stream.ChannelCount += 2; - } - int c_LRsd = buffer.ReadBits(1); - if (c_LRsd == 1) - { - stream.ChannelCount += 2; - } - int c_Ts = buffer.ReadBits(1); - if (c_Ts == 1) - { - stream.ChannelCount += 1; - } - int c_Cs = buffer.ReadBits(1); - if (c_Cs == 1) - { - stream.ChannelCount += 1; - } - int c_LRrs = buffer.ReadBits(1); - if (c_LRrs == 1) - { - stream.ChannelCount += 2; - } - int c_LRc = buffer.ReadBits(1); - if (c_LRc == 1) - { - stream.ChannelCount += 2; - } - int c_LRvh = buffer.ReadBits(1); - if (c_LRvh == 1) - { - stream.ChannelCount += 2; - } - int c_LRs = buffer.ReadBits(1); - if (c_LRs == 1) - { - stream.ChannelCount += 2; - } - int c_LFE = buffer.ReadBits(1); - if (c_LFE == 1) - { - stream.LFE += 1; - } - int c_C = buffer.ReadBits(1); - if (c_C == 1) - { - stream.ChannelCount += 1; - } - int c_LR = buffer.ReadBits(1); - if (c_LR == 1) - { - stream.ChannelCount += 2; - } - - int access_unit_size = 40 << (ratebits & 7); - int access_unit_size_pow2 = 64 << (ratebits & 7); - - int a1 = buffer.ReadBits(16); - int a2 = buffer.ReadBits(16); - int a3 = buffer.ReadBits(16); - - int is_vbr = buffer.ReadBits(1); - int peak_bitrate = buffer.ReadBits(15); - peak_bitrate = (peak_bitrate * stream.SampleRate) >> 4; - - double peak_bitdepth = - (double)peak_bitrate / - (stream.ChannelCount + stream.LFE) / - stream.SampleRate; - if (peak_bitdepth > 14) - { - stream.BitDepth = 24; - } - else - { - stream.BitDepth = 16; - } - -#if DEBUG - System.Diagnostics.Debug.WriteLine(string.Format( - "{0}\t{1}\t{2:F2}", - stream.PID, peak_bitrate, peak_bitdepth)); -#endif - /* - // TODO: Get THD dialnorm from metadata - if (stream.CoreStream != null) - { - TSAudioStream coreStream = (TSAudioStream)stream.CoreStream; - if (coreStream.DialNorm != 0) - { - stream.DialNorm = coreStream.DialNorm; - } - } - */ - - stream.IsVBR = true; - stream.IsInitialized = true; - } - } -} diff --git a/BDInfo/TSCodecVC1.cs b/BDInfo/TSCodecVC1.cs deleted file mode 100644 index e2fbbf692..000000000 --- a/BDInfo/TSCodecVC1.cs +++ /dev/null @@ -1,131 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - - -namespace BDInfo -{ - public abstract class TSCodecVC1 - { - public static void Scan( - TSVideoStream stream, - TSStreamBuffer buffer, - ref string tag) - { - int parse = 0; - byte frameHeaderParse = 0; - byte sequenceHeaderParse = 0; - bool isInterlaced = false; - - for (int i = 0; i < buffer.Length; i++) - { - parse = (parse << 8) + buffer.ReadByte(); - - if (parse == 0x0000010D) - { - frameHeaderParse = 4; - } - else if (frameHeaderParse > 0) - { - --frameHeaderParse; - if (frameHeaderParse == 0) - { - uint pictureType = 0; - if (isInterlaced) - { - if ((parse & 0x80000000) == 0) - { - pictureType = - (uint)((parse & 0x78000000) >> 13); - } - else - { - pictureType = - (uint)((parse & 0x3c000000) >> 12); - } - } - else - { - pictureType = - (uint)((parse & 0xf0000000) >> 14); - } - - if ((pictureType & 0x20000) == 0) - { - tag = "P"; - } - else if ((pictureType & 0x10000) == 0) - { - tag = "B"; - } - else if ((pictureType & 0x8000) == 0) - { - tag = "I"; - } - else if ((pictureType & 0x4000) == 0) - { - tag = "BI"; - } - else - { - tag = null; - } - if (stream.IsInitialized) return; - } - } - else if (parse == 0x0000010F) - { - sequenceHeaderParse = 6; - } - else if (sequenceHeaderParse > 0) - { - --sequenceHeaderParse; - switch (sequenceHeaderParse) - { - case 5: - int profileLevel = ((parse & 0x38) >> 3); - if (((parse & 0xC0) >> 6) == 3) - { - stream.EncodingProfile = string.Format( - "Advanced Profile {0}", profileLevel); - } - else - { - stream.EncodingProfile = string.Format( - "Main Profile {0}", profileLevel); - } - break; - - case 0: - if (((parse & 0x40) >> 6) > 0) - { - isInterlaced = true; - } - else - { - isInterlaced = false; - } - break; - } - stream.IsVBR = true; - stream.IsInitialized = true; - } - } - } - } -} diff --git a/BDInfo/TSInterleavedFile.cs b/BDInfo/TSInterleavedFile.cs deleted file mode 100644 index 0f35cfb2a..000000000 --- a/BDInfo/TSInterleavedFile.cs +++ /dev/null @@ -1,37 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -using MediaBrowser.Model.IO; - -// TODO: Do more interesting things here... - -namespace BDInfo -{ - public class TSInterleavedFile - { - public FileSystemMetadata FileInfo = null; - public string Name = null; - - public TSInterleavedFile(FileSystemMetadata fileInfo) - { - FileInfo = fileInfo; - Name = fileInfo.Name.ToUpper(); - } - } -} diff --git a/BDInfo/TSPlaylistFile.cs b/BDInfo/TSPlaylistFile.cs deleted file mode 100644 index 1cc629b1d..000000000 --- a/BDInfo/TSPlaylistFile.cs +++ /dev/null @@ -1,1282 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -#undef DEBUG -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using MediaBrowser.Model.IO; - -namespace BDInfo -{ - public class TSPlaylistFile - { - private FileSystemMetadata FileInfo = null; - public string FileType = null; - public bool IsInitialized = false; - public string Name = null; - public BDROM BDROM = null; - public bool HasHiddenTracks = false; - public bool HasLoops = false; - public bool IsCustom = false; - - public List Chapters = new List(); - - public Dictionary Streams = - new Dictionary(); - public Dictionary PlaylistStreams = - new Dictionary(); - public List StreamClips = - new List(); - public List> AngleStreams = - new List>(); - public List> AngleClips = - new List>(); - public int AngleCount = 0; - - public List SortedStreams = - new List(); - public List VideoStreams = - new List(); - public List AudioStreams = - new List(); - public List TextStreams = - new List(); - public List GraphicsStreams = - new List(); - - public TSPlaylistFile(BDROM bdrom, - FileSystemMetadata fileInfo) - { - BDROM = bdrom; - FileInfo = fileInfo; - Name = fileInfo.Name.ToUpper(); - } - - public TSPlaylistFile(BDROM bdrom, - string name, - List clips) - { - BDROM = bdrom; - Name = name; - IsCustom = true; - foreach (var clip in clips) - { - var newClip = new TSStreamClip( - clip.StreamFile, clip.StreamClipFile); - - newClip.Name = clip.Name; - newClip.TimeIn = clip.TimeIn; - newClip.TimeOut = clip.TimeOut; - newClip.Length = newClip.TimeOut - newClip.TimeIn; - newClip.RelativeTimeIn = TotalLength; - newClip.RelativeTimeOut = newClip.RelativeTimeIn + newClip.Length; - newClip.AngleIndex = clip.AngleIndex; - newClip.Chapters.Add(clip.TimeIn); - StreamClips.Add(newClip); - - if (newClip.AngleIndex > AngleCount) - { - AngleCount = newClip.AngleIndex; - } - if (newClip.AngleIndex == 0) - { - Chapters.Add(newClip.RelativeTimeIn); - } - } - LoadStreamClips(); - IsInitialized = true; - } - - public override string ToString() - { - return Name; - } - - public ulong InterleavedFileSize - { - get - { - ulong size = 0; - foreach (var clip in StreamClips) - { - size += clip.InterleavedFileSize; - } - return size; - } - } - public ulong FileSize - { - get - { - ulong size = 0; - foreach (var clip in StreamClips) - { - size += clip.FileSize; - } - return size; - } - } - public double TotalLength - { - get - { - double length = 0; - foreach (var clip in StreamClips) - { - if (clip.AngleIndex == 0) - { - length += clip.Length; - } - } - return length; - } - } - - public double TotalAngleLength - { - get - { - double length = 0; - foreach (var clip in StreamClips) - { - length += clip.Length; - } - return length; - } - } - - public ulong TotalSize - { - get - { - ulong size = 0; - foreach (var clip in StreamClips) - { - if (clip.AngleIndex == 0) - { - size += clip.PacketSize; - } - } - return size; - } - } - - public ulong TotalAngleSize - { - get - { - ulong size = 0; - foreach (var clip in StreamClips) - { - size += clip.PacketSize; - } - return size; - } - } - - public ulong TotalBitRate - { - get - { - if (TotalLength > 0) - { - return (ulong)Math.Round(((TotalSize * 8.0) / TotalLength)); - } - return 0; - } - } - - public ulong TotalAngleBitRate - { - get - { - if (TotalAngleLength > 0) - { - return (ulong)Math.Round(((TotalAngleSize * 8.0) / TotalAngleLength)); - } - return 0; - } - } - - public void Scan( - Dictionary streamFiles, - Dictionary streamClipFiles) - { - Stream fileStream = null; - BinaryReader fileReader = null; - - try - { - Streams.Clear(); - StreamClips.Clear(); - - fileStream = File.OpenRead(FileInfo.FullName); - fileReader = new BinaryReader(fileStream); - - byte[] data = new byte[fileStream.Length]; - int dataLength = fileReader.Read(data, 0, data.Length); - - int pos = 0; - - FileType = ReadString(data, 8, ref pos); - if (FileType != "MPLS0100" && FileType != "MPLS0200") - { - throw new Exception(string.Format( - "Playlist {0} has an unknown file type {1}.", - FileInfo.Name, FileType)); - } - - int playlistOffset = ReadInt32(data, ref pos); - int chaptersOffset = ReadInt32(data, ref pos); - int extensionsOffset = ReadInt32(data, ref pos); - - pos = playlistOffset; - - int playlistLength = ReadInt32(data, ref pos); - int playlistReserved = ReadInt16(data, ref pos); - int itemCount = ReadInt16(data, ref pos); - int subitemCount = ReadInt16(data, ref pos); - - var chapterClips = new List(); - for (int itemIndex = 0; itemIndex < itemCount; itemIndex++) - { - int itemStart = pos; - int itemLength = ReadInt16(data, ref pos); - string itemName = ReadString(data, 5, ref pos); - string itemType = ReadString(data, 4, ref pos); - - TSStreamFile streamFile = null; - string streamFileName = string.Format( - "{0}.M2TS", itemName); - if (streamFiles.ContainsKey(streamFileName)) - { - streamFile = streamFiles[streamFileName]; - } - if (streamFile == null) - { - // Error condition - } - - TSStreamClipFile streamClipFile = null; - string streamClipFileName = string.Format( - "{0}.CLPI", itemName); - if (streamClipFiles.ContainsKey(streamClipFileName)) - { - streamClipFile = streamClipFiles[streamClipFileName]; - } - if (streamClipFile == null) - { - throw new Exception(string.Format( - "Playlist {0} referenced missing file {1}.", - FileInfo.Name, streamFileName)); - } - - pos += 1; - int multiangle = (data[pos] >> 4) & 0x01; - int condition = data[pos] & 0x0F; - pos += 2; - - int inTime = ReadInt32(data, ref pos); - if (inTime < 0) inTime &= 0x7FFFFFFF; - double timeIn = (double)inTime / 45000; - - int outTime = ReadInt32(data, ref pos); - if (outTime < 0) outTime &= 0x7FFFFFFF; - double timeOut = (double)outTime / 45000; - - var streamClip = new TSStreamClip( - streamFile, streamClipFile); - - streamClip.Name = streamFileName; //TODO - streamClip.TimeIn = timeIn; - streamClip.TimeOut = timeOut; - streamClip.Length = streamClip.TimeOut - streamClip.TimeIn; - streamClip.RelativeTimeIn = TotalLength; - streamClip.RelativeTimeOut = streamClip.RelativeTimeIn + streamClip.Length; - StreamClips.Add(streamClip); - chapterClips.Add(streamClip); - - pos += 12; - if (multiangle > 0) - { - int angles = data[pos]; - pos += 2; - for (int angle = 0; angle < angles - 1; angle++) - { - string angleName = ReadString(data, 5, ref pos); - string angleType = ReadString(data, 4, ref pos); - pos += 1; - - TSStreamFile angleFile = null; - string angleFileName = string.Format( - "{0}.M2TS", angleName); - if (streamFiles.ContainsKey(angleFileName)) - { - angleFile = streamFiles[angleFileName]; - } - if (angleFile == null) - { - throw new Exception(string.Format( - "Playlist {0} referenced missing angle file {1}.", - FileInfo.Name, angleFileName)); - } - - TSStreamClipFile angleClipFile = null; - string angleClipFileName = string.Format( - "{0}.CLPI", angleName); - if (streamClipFiles.ContainsKey(angleClipFileName)) - { - angleClipFile = streamClipFiles[angleClipFileName]; - } - if (angleClipFile == null) - { - throw new Exception(string.Format( - "Playlist {0} referenced missing angle file {1}.", - FileInfo.Name, angleClipFileName)); - } - - var angleClip = - new TSStreamClip(angleFile, angleClipFile); - angleClip.AngleIndex = angle + 1; - angleClip.TimeIn = streamClip.TimeIn; - angleClip.TimeOut = streamClip.TimeOut; - angleClip.RelativeTimeIn = streamClip.RelativeTimeIn; - angleClip.RelativeTimeOut = streamClip.RelativeTimeOut; - angleClip.Length = streamClip.Length; - StreamClips.Add(angleClip); - } - if (angles - 1 > AngleCount) AngleCount = angles - 1; - } - - int streamInfoLength = ReadInt16(data, ref pos); - pos += 2; - int streamCountVideo = data[pos++]; - int streamCountAudio = data[pos++]; - int streamCountPG = data[pos++]; - int streamCountIG = data[pos++]; - int streamCountSecondaryAudio = data[pos++]; - int streamCountSecondaryVideo = data[pos++]; - int streamCountPIP = data[pos++]; - pos += 5; - -#if DEBUG - Debug.WriteLine(string.Format( - "{0} : {1} -> V:{2} A:{3} PG:{4} IG:{5} 2A:{6} 2V:{7} PIP:{8}", - Name, streamFileName, streamCountVideo, streamCountAudio, streamCountPG, streamCountIG, - streamCountSecondaryAudio, streamCountSecondaryVideo, streamCountPIP)); -#endif - - for (int i = 0; i < streamCountVideo; i++) - { - var stream = CreatePlaylistStream(data, ref pos); - if (stream != null) PlaylistStreams[stream.PID] = stream; - } - for (int i = 0; i < streamCountAudio; i++) - { - var stream = CreatePlaylistStream(data, ref pos); - if (stream != null) PlaylistStreams[stream.PID] = stream; - } - for (int i = 0; i < streamCountPG; i++) - { - var stream = CreatePlaylistStream(data, ref pos); - if (stream != null) PlaylistStreams[stream.PID] = stream; - } - for (int i = 0; i < streamCountIG; i++) - { - var stream = CreatePlaylistStream(data, ref pos); - if (stream != null) PlaylistStreams[stream.PID] = stream; - } - for (int i = 0; i < streamCountSecondaryAudio; i++) - { - var stream = CreatePlaylistStream(data, ref pos); - if (stream != null) PlaylistStreams[stream.PID] = stream; - pos += 2; - } - for (int i = 0; i < streamCountSecondaryVideo; i++) - { - var stream = CreatePlaylistStream(data, ref pos); - if (stream != null) PlaylistStreams[stream.PID] = stream; - pos += 6; - } - /* - * TODO - * - for (int i = 0; i < streamCountPIP; i++) - { - TSStream stream = CreatePlaylistStream(data, ref pos); - if (stream != null) PlaylistStreams[stream.PID] = stream; - } - */ - - pos += itemLength - (pos - itemStart) + 2; - } - - pos = chaptersOffset + 4; - - int chapterCount = ReadInt16(data, ref pos); - - for (int chapterIndex = 0; - chapterIndex < chapterCount; - chapterIndex++) - { - int chapterType = data[pos + 1]; - - if (chapterType == 1) - { - int streamFileIndex = - ((int)data[pos + 2] << 8) + data[pos + 3]; - - long chapterTime = - ((long)data[pos + 4] << 24) + - ((long)data[pos + 5] << 16) + - ((long)data[pos + 6] << 8) + - ((long)data[pos + 7]); - - var streamClip = chapterClips[streamFileIndex]; - - double chapterSeconds = (double)chapterTime / 45000; - - double relativeSeconds = - chapterSeconds - - streamClip.TimeIn + - streamClip.RelativeTimeIn; - - // TODO: Ignore short last chapter? - if (TotalLength - relativeSeconds > 1.0) - { - streamClip.Chapters.Add(chapterSeconds); - this.Chapters.Add(relativeSeconds); - } - } - else - { - // TODO: Handle other chapter types? - } - pos += 14; - } - } - finally - { - if (fileReader != null) - { - fileReader.Dispose(); - } - if (fileStream != null) - { - fileStream.Dispose(); - } - } - } - - public void Initialize() - { - LoadStreamClips(); - - var clipTimes = new Dictionary>(); - foreach (var clip in StreamClips) - { - if (clip.AngleIndex == 0) - { - if (clipTimes.ContainsKey(clip.Name)) - { - if (clipTimes[clip.Name].Contains(clip.TimeIn)) - { - HasLoops = true; - break; - } - else - { - clipTimes[clip.Name].Add(clip.TimeIn); - } - } - else - { - clipTimes[clip.Name] = new List { clip.TimeIn }; - } - } - } - ClearBitrates(); - IsInitialized = true; - } - - protected TSStream CreatePlaylistStream(byte[] data, ref int pos) - { - TSStream stream = null; - - int start = pos; - - int headerLength = data[pos++]; - int headerPos = pos; - int headerType = data[pos++]; - - int pid = 0; - int subpathid = 0; - int subclipid = 0; - - switch (headerType) - { - case 1: - pid = ReadInt16(data, ref pos); - break; - case 2: - subpathid = data[pos++]; - subclipid = data[pos++]; - pid = ReadInt16(data, ref pos); - break; - case 3: - subpathid = data[pos++]; - pid = ReadInt16(data, ref pos); - break; - case 4: - subpathid = data[pos++]; - subclipid = data[pos++]; - pid = ReadInt16(data, ref pos); - break; - default: - break; - } - - pos = headerPos + headerLength; - - int streamLength = data[pos++]; - int streamPos = pos; - - var streamType = (TSStreamType)data[pos++]; - switch (streamType) - { - case TSStreamType.MVC_VIDEO: - // TODO - break; - - case TSStreamType.AVC_VIDEO: - case TSStreamType.MPEG1_VIDEO: - case TSStreamType.MPEG2_VIDEO: - case TSStreamType.VC1_VIDEO: - - var videoFormat = (TSVideoFormat) - (data[pos] >> 4); - var frameRate = (TSFrameRate) - (data[pos] & 0xF); - var aspectRatio = (TSAspectRatio) - (data[pos + 1] >> 4); - - stream = new TSVideoStream(); - ((TSVideoStream)stream).VideoFormat = videoFormat; - ((TSVideoStream)stream).AspectRatio = aspectRatio; - ((TSVideoStream)stream).FrameRate = frameRate; - -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2} {3} {4}", - pid, - streamType, - videoFormat, - frameRate, - aspectRatio)); -#endif - - break; - - case TSStreamType.AC3_AUDIO: - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - case TSStreamType.AC3_TRUE_HD_AUDIO: - case TSStreamType.DTS_AUDIO: - case TSStreamType.DTS_HD_AUDIO: - case TSStreamType.DTS_HD_MASTER_AUDIO: - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - case TSStreamType.LPCM_AUDIO: - case TSStreamType.MPEG1_AUDIO: - case TSStreamType.MPEG2_AUDIO: - - int audioFormat = ReadByte(data, ref pos); - - var channelLayout = (TSChannelLayout) - (audioFormat >> 4); - var sampleRate = (TSSampleRate) - (audioFormat & 0xF); - - string audioLanguage = ReadString(data, 3, ref pos); - - stream = new TSAudioStream(); - ((TSAudioStream)stream).ChannelLayout = channelLayout; - ((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate); - ((TSAudioStream)stream).LanguageCode = audioLanguage; - -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2} {3} {4}", - pid, - streamType, - audioLanguage, - channelLayout, - sampleRate)); -#endif - - break; - - case TSStreamType.INTERACTIVE_GRAPHICS: - case TSStreamType.PRESENTATION_GRAPHICS: - - string graphicsLanguage = ReadString(data, 3, ref pos); - - stream = new TSGraphicsStream(); - ((TSGraphicsStream)stream).LanguageCode = graphicsLanguage; - - if (data[pos] != 0) - { - } - -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2}", - pid, - streamType, - graphicsLanguage)); -#endif - - break; - - case TSStreamType.SUBTITLE: - - int code = ReadByte(data, ref pos); // TODO - string textLanguage = ReadString(data, 3, ref pos); - - stream = new TSTextStream(); - ((TSTextStream)stream).LanguageCode = textLanguage; - -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2}", - pid, - streamType, - textLanguage)); -#endif - - break; - - default: - break; - } - - pos = streamPos + streamLength; - - if (stream != null) - { - stream.PID = (ushort)pid; - stream.StreamType = streamType; - } - - return stream; - } - - private void LoadStreamClips() - { - AngleClips.Clear(); - if (AngleCount > 0) - { - for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++) - { - AngleClips.Add(new Dictionary()); - } - } - - TSStreamClip referenceClip = null; - if (StreamClips.Count > 0) - { - referenceClip = StreamClips[0]; - } - foreach (var clip in StreamClips) - { - if (clip.StreamClipFile.Streams.Count > referenceClip.StreamClipFile.Streams.Count) - { - referenceClip = clip; - } - else if (clip.Length > referenceClip.Length) - { - referenceClip = clip; - } - if (AngleCount > 0) - { - if (clip.AngleIndex == 0) - { - for (int angleIndex = 0; angleIndex < AngleCount; angleIndex++) - { - AngleClips[angleIndex][clip.RelativeTimeIn] = clip; - } - } - else - { - AngleClips[clip.AngleIndex - 1][clip.RelativeTimeIn] = clip; - } - } - } - - foreach (var clipStream - in referenceClip.StreamClipFile.Streams.Values) - { - if (!Streams.ContainsKey(clipStream.PID)) - { - var stream = clipStream.Clone(); - Streams[clipStream.PID] = stream; - - if (!IsCustom && !PlaylistStreams.ContainsKey(stream.PID)) - { - stream.IsHidden = true; - HasHiddenTracks = true; - } - - if (stream.IsVideoStream) - { - VideoStreams.Add((TSVideoStream)stream); - } - else if (stream.IsAudioStream) - { - AudioStreams.Add((TSAudioStream)stream); - } - else if (stream.IsGraphicsStream) - { - GraphicsStreams.Add((TSGraphicsStream)stream); - } - else if (stream.IsTextStream) - { - TextStreams.Add((TSTextStream)stream); - } - } - } - - if (referenceClip.StreamFile != null) - { - // TODO: Better way to add this in? - if (BDInfoSettings.EnableSSIF && - referenceClip.StreamFile.InterleavedFile != null && - referenceClip.StreamFile.Streams.ContainsKey(4114) && - !Streams.ContainsKey(4114)) - { - var stream = referenceClip.StreamFile.Streams[4114].Clone(); - Streams[4114] = stream; - if (stream.IsVideoStream) - { - VideoStreams.Add((TSVideoStream)stream); - } - } - - foreach (var clipStream - in referenceClip.StreamFile.Streams.Values) - { - if (Streams.ContainsKey(clipStream.PID)) - { - var stream = Streams[clipStream.PID]; - - if (stream.StreamType != clipStream.StreamType) continue; - - if (clipStream.BitRate > stream.BitRate) - { - stream.BitRate = clipStream.BitRate; - } - stream.IsVBR = clipStream.IsVBR; - - if (stream.IsVideoStream && - clipStream.IsVideoStream) - { - ((TSVideoStream)stream).EncodingProfile = - ((TSVideoStream)clipStream).EncodingProfile; - } - else if (stream.IsAudioStream && - clipStream.IsAudioStream) - { - var audioStream = (TSAudioStream)stream; - var clipAudioStream = (TSAudioStream)clipStream; - - if (clipAudioStream.ChannelCount > audioStream.ChannelCount) - { - audioStream.ChannelCount = clipAudioStream.ChannelCount; - } - if (clipAudioStream.LFE > audioStream.LFE) - { - audioStream.LFE = clipAudioStream.LFE; - } - if (clipAudioStream.SampleRate > audioStream.SampleRate) - { - audioStream.SampleRate = clipAudioStream.SampleRate; - } - if (clipAudioStream.BitDepth > audioStream.BitDepth) - { - audioStream.BitDepth = clipAudioStream.BitDepth; - } - if (clipAudioStream.DialNorm < audioStream.DialNorm) - { - audioStream.DialNorm = clipAudioStream.DialNorm; - } - if (clipAudioStream.AudioMode != TSAudioMode.Unknown) - { - audioStream.AudioMode = clipAudioStream.AudioMode; - } - if (clipAudioStream.CoreStream != null && - audioStream.CoreStream == null) - { - audioStream.CoreStream = (TSAudioStream) - clipAudioStream.CoreStream.Clone(); - } - } - } - } - } - - for (int i = 0; i < AngleCount; i++) - { - AngleStreams.Add(new Dictionary()); - } - - if (!BDInfoSettings.KeepStreamOrder) - { - VideoStreams.Sort(CompareVideoStreams); - } - foreach (TSStream stream in VideoStreams) - { - SortedStreams.Add(stream); - for (int i = 0; i < AngleCount; i++) - { - var angleStream = stream.Clone(); - angleStream.AngleIndex = i + 1; - AngleStreams[i][angleStream.PID] = angleStream; - SortedStreams.Add(angleStream); - } - } - - if (!BDInfoSettings.KeepStreamOrder) - { - AudioStreams.Sort(CompareAudioStreams); - } - foreach (TSStream stream in AudioStreams) - { - SortedStreams.Add(stream); - } - - if (!BDInfoSettings.KeepStreamOrder) - { - GraphicsStreams.Sort(CompareGraphicsStreams); - } - foreach (TSStream stream in GraphicsStreams) - { - SortedStreams.Add(stream); - } - - if (!BDInfoSettings.KeepStreamOrder) - { - TextStreams.Sort(CompareTextStreams); - } - foreach (TSStream stream in TextStreams) - { - SortedStreams.Add(stream); - } - } - - public void ClearBitrates() - { - foreach (var clip in StreamClips) - { - clip.PayloadBytes = 0; - clip.PacketCount = 0; - clip.PacketSeconds = 0; - - if (clip.StreamFile != null) - { - foreach (var stream in clip.StreamFile.Streams.Values) - { - stream.PayloadBytes = 0; - stream.PacketCount = 0; - stream.PacketSeconds = 0; - } - - if (clip.StreamFile != null && - clip.StreamFile.StreamDiagnostics != null) - { - clip.StreamFile.StreamDiagnostics.Clear(); - } - } - } - - foreach (var stream in SortedStreams) - { - stream.PayloadBytes = 0; - stream.PacketCount = 0; - stream.PacketSeconds = 0; - } - } - - public bool IsValid - { - get - { - if (!IsInitialized) return false; - - if (BDInfoSettings.FilterShortPlaylists && - TotalLength < BDInfoSettings.FilterShortPlaylistsValue) - { - return false; - } - - if (HasLoops && - BDInfoSettings.FilterLoopingPlaylists) - { - return false; - } - - return true; - } - } - - public int CompareVideoStreams( - TSVideoStream x, - TSVideoStream y) - { - if (x == null && y == null) - { - return 0; - } - else if (x == null && y != null) - { - return 1; - } - else if (x != null && y == null) - { - return -1; - } - else - { - if (x.Height > y.Height) - { - return -1; - } - else if (y.Height > x.Height) - { - return 1; - } - else if (x.PID > y.PID) - { - return 1; - } - else if (y.PID > x.PID) - { - return -1; - } - else - { - return 0; - } - } - } - - public int CompareAudioStreams( - TSAudioStream x, - TSAudioStream y) - { - if (x == y) - { - return 0; - } - else if (x == null && y == null) - { - return 0; - } - else if (x == null && y != null) - { - return -1; - } - else if (x != null && y == null) - { - return 1; - } - else - { - if (x.ChannelCount > y.ChannelCount) - { - return -1; - } - else if (y.ChannelCount > x.ChannelCount) - { - return 1; - } - else - { - int sortX = GetStreamTypeSortIndex(x.StreamType); - int sortY = GetStreamTypeSortIndex(y.StreamType); - - if (sortX > sortY) - { - return -1; - } - else if (sortY > sortX) - { - return 1; - } - else - { - if (x.LanguageCode == "eng") - { - return -1; - } - else if (y.LanguageCode == "eng") - { - return 1; - } - else if (x.LanguageCode != y.LanguageCode) - { - return string.Compare( - x.LanguageName, y.LanguageName); - } - else if (x.PID < y.PID) - { - return -1; - } - else if (y.PID < x.PID) - { - return 1; - } - return 0; - } - } - } - } - - public int CompareTextStreams( - TSTextStream x, - TSTextStream y) - { - if (x == y) - { - return 0; - } - else if (x == null && y == null) - { - return 0; - } - else if (x == null && y != null) - { - return -1; - } - else if (x != null && y == null) - { - return 1; - } - else - { - if (x.LanguageCode == "eng") - { - return -1; - } - else if (y.LanguageCode == "eng") - { - return 1; - } - else - { - if (x.LanguageCode == y.LanguageCode) - { - if (x.PID > y.PID) - { - return 1; - } - else if (y.PID > x.PID) - { - return -1; - } - else - { - return 0; - } - } - else - { - return string.Compare( - x.LanguageName, y.LanguageName); - } - } - } - } - - private int CompareGraphicsStreams( - TSGraphicsStream x, - TSGraphicsStream y) - { - if (x == y) - { - return 0; - } - else if (x == null && y == null) - { - return 0; - } - else if (x == null && y != null) - { - return -1; - } - else if (x != null && y == null) - { - return 1; - } - else - { - int sortX = GetStreamTypeSortIndex(x.StreamType); - int sortY = GetStreamTypeSortIndex(y.StreamType); - - if (sortX > sortY) - { - return -1; - } - else if (sortY > sortX) - { - return 1; - } - else if (x.LanguageCode == "eng") - { - return -1; - } - else if (y.LanguageCode == "eng") - { - return 1; - } - else - { - if (x.LanguageCode == y.LanguageCode) - { - if (x.PID > y.PID) - { - return 1; - } - else if (y.PID > x.PID) - { - return -1; - } - else - { - return 0; - } - } - else - { - return string.Compare(x.LanguageName, y.LanguageName); - } - } - } - } - - private int GetStreamTypeSortIndex(TSStreamType streamType) - { - switch (streamType) - { - case TSStreamType.Unknown: - return 0; - case TSStreamType.MPEG1_VIDEO: - return 1; - case TSStreamType.MPEG2_VIDEO: - return 2; - case TSStreamType.AVC_VIDEO: - return 3; - case TSStreamType.VC1_VIDEO: - return 4; - case TSStreamType.MVC_VIDEO: - return 5; - - case TSStreamType.MPEG1_AUDIO: - return 1; - case TSStreamType.MPEG2_AUDIO: - return 2; - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - return 3; - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - return 4; - case TSStreamType.AC3_AUDIO: - return 5; - case TSStreamType.DTS_AUDIO: - return 6; - case TSStreamType.AC3_PLUS_AUDIO: - return 7; - case TSStreamType.DTS_HD_AUDIO: - return 8; - case TSStreamType.AC3_TRUE_HD_AUDIO: - return 9; - case TSStreamType.DTS_HD_MASTER_AUDIO: - return 10; - case TSStreamType.LPCM_AUDIO: - return 11; - - case TSStreamType.SUBTITLE: - return 1; - case TSStreamType.INTERACTIVE_GRAPHICS: - return 2; - case TSStreamType.PRESENTATION_GRAPHICS: - return 3; - - default: - return 0; - } - } - - protected string ReadString( - byte[] data, - int count, - ref int pos) - { - string val = Encoding.ASCII.GetString(data, pos, count); - - pos += count; - - return val; - } - - protected int ReadInt32( - byte[] data, - ref int pos) - { - int val = - ((int)data[pos] << 24) + - ((int)data[pos + 1] << 16) + - ((int)data[pos + 2] << 8) + - ((int)data[pos + 3]); - - pos += 4; - - return val; - } - - protected int ReadInt16( - byte[] data, - ref int pos) - { - int val = - ((int)data[pos] << 8) + - ((int)data[pos + 1]); - - pos += 2; - - return val; - } - - protected byte ReadByte( - byte[] data, - ref int pos) - { - return data[pos++]; - } - } -} diff --git a/BDInfo/TSStream.cs b/BDInfo/TSStream.cs deleted file mode 100644 index 3c30a8597..000000000 --- a/BDInfo/TSStream.cs +++ /dev/null @@ -1,780 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -using System; -using System.Collections.Generic; - -namespace BDInfo -{ - public enum TSStreamType : byte - { - Unknown = 0, - MPEG1_VIDEO = 0x01, - MPEG2_VIDEO = 0x02, - AVC_VIDEO = 0x1b, - MVC_VIDEO = 0x20, - VC1_VIDEO = 0xea, - MPEG1_AUDIO = 0x03, - MPEG2_AUDIO = 0x04, - LPCM_AUDIO = 0x80, - AC3_AUDIO = 0x81, - AC3_PLUS_AUDIO = 0x84, - AC3_PLUS_SECONDARY_AUDIO = 0xA1, - AC3_TRUE_HD_AUDIO = 0x83, - DTS_AUDIO = 0x82, - DTS_HD_AUDIO = 0x85, - DTS_HD_SECONDARY_AUDIO = 0xA2, - DTS_HD_MASTER_AUDIO = 0x86, - PRESENTATION_GRAPHICS = 0x90, - INTERACTIVE_GRAPHICS = 0x91, - SUBTITLE = 0x92 - } - - public enum TSVideoFormat : byte - { - Unknown = 0, - VIDEOFORMAT_480i = 1, - VIDEOFORMAT_576i = 2, - VIDEOFORMAT_480p = 3, - VIDEOFORMAT_1080i = 4, - VIDEOFORMAT_720p = 5, - VIDEOFORMAT_1080p = 6, - VIDEOFORMAT_576p = 7, - } - - public enum TSFrameRate : byte - { - Unknown = 0, - FRAMERATE_23_976 = 1, - FRAMERATE_24 = 2, - FRAMERATE_25 = 3, - FRAMERATE_29_97 = 4, - FRAMERATE_50 = 6, - FRAMERATE_59_94 = 7 - } - - public enum TSChannelLayout : byte - { - Unknown = 0, - CHANNELLAYOUT_MONO = 1, - CHANNELLAYOUT_STEREO = 3, - CHANNELLAYOUT_MULTI = 6, - CHANNELLAYOUT_COMBO = 12 - } - - public enum TSSampleRate : byte - { - Unknown = 0, - SAMPLERATE_48 = 1, - SAMPLERATE_96 = 4, - SAMPLERATE_192 = 5, - SAMPLERATE_48_192 = 12, - SAMPLERATE_48_96 = 14 - } - - public enum TSAspectRatio - { - Unknown = 0, - ASPECT_4_3 = 2, - ASPECT_16_9 = 3, - ASPECT_2_21 = 4 - } - - public class TSDescriptor - { - public byte Name; - public byte[] Value; - - public TSDescriptor(byte name, byte length) - { - Name = name; - Value = new byte[length]; - } - - public TSDescriptor Clone() - { - var descriptor = - new TSDescriptor(Name, (byte)Value.Length); - Value.CopyTo(descriptor.Value, 0); - return descriptor; - } - } - - public abstract class TSStream - { - public TSStream() - { - } - - public override string ToString() - { - return string.Format("{0} ({1})", CodecShortName, PID); - } - - public ushort PID; - public TSStreamType StreamType; - public List Descriptors = null; - public long BitRate = 0; - public long ActiveBitRate = 0; - public bool IsVBR = false; - public bool IsInitialized = false; - public string LanguageName; - public bool IsHidden = false; - - public ulong PayloadBytes = 0; - public ulong PacketCount = 0; - public double PacketSeconds = 0; - public int AngleIndex = 0; - - public ulong PacketSize => PacketCount * 192; - - private string _LanguageCode; - public string LanguageCode - { - get => _LanguageCode; - set - { - _LanguageCode = value; - LanguageName = LanguageCodes.GetName(value); - } - } - - public bool IsVideoStream - { - get - { - switch (StreamType) - { - case TSStreamType.MPEG1_VIDEO: - case TSStreamType.MPEG2_VIDEO: - case TSStreamType.AVC_VIDEO: - case TSStreamType.MVC_VIDEO: - case TSStreamType.VC1_VIDEO: - return true; - - default: - return false; - } - } - } - - public bool IsAudioStream - { - get - { - switch (StreamType) - { - case TSStreamType.MPEG1_AUDIO: - case TSStreamType.MPEG2_AUDIO: - case TSStreamType.LPCM_AUDIO: - case TSStreamType.AC3_AUDIO: - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - case TSStreamType.AC3_TRUE_HD_AUDIO: - case TSStreamType.DTS_AUDIO: - case TSStreamType.DTS_HD_AUDIO: - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - case TSStreamType.DTS_HD_MASTER_AUDIO: - return true; - - default: - return false; - } - } - } - - public bool IsGraphicsStream - { - get - { - switch (StreamType) - { - case TSStreamType.PRESENTATION_GRAPHICS: - case TSStreamType.INTERACTIVE_GRAPHICS: - return true; - - default: - return false; - } - } - } - - public bool IsTextStream - { - get - { - switch (StreamType) - { - case TSStreamType.SUBTITLE: - return true; - - default: - return false; - } - } - } - - public string CodecName - { - get - { - switch (StreamType) - { - case TSStreamType.MPEG1_VIDEO: - return "MPEG-1 Video"; - case TSStreamType.MPEG2_VIDEO: - return "MPEG-2 Video"; - case TSStreamType.AVC_VIDEO: - return "MPEG-4 AVC Video"; - case TSStreamType.MVC_VIDEO: - return "MPEG-4 MVC Video"; - case TSStreamType.VC1_VIDEO: - return "VC-1 Video"; - case TSStreamType.MPEG1_AUDIO: - return "MP1 Audio"; - case TSStreamType.MPEG2_AUDIO: - return "MP2 Audio"; - case TSStreamType.LPCM_AUDIO: - return "LPCM Audio"; - case TSStreamType.AC3_AUDIO: - if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended) - return "Dolby Digital EX Audio"; - else - return "Dolby Digital Audio"; - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - return "Dolby Digital Plus Audio"; - case TSStreamType.AC3_TRUE_HD_AUDIO: - return "Dolby TrueHD Audio"; - case TSStreamType.DTS_AUDIO: - if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended) - return "DTS-ES Audio"; - else - return "DTS Audio"; - case TSStreamType.DTS_HD_AUDIO: - return "DTS-HD High-Res Audio"; - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - return "DTS Express"; - case TSStreamType.DTS_HD_MASTER_AUDIO: - return "DTS-HD Master Audio"; - case TSStreamType.PRESENTATION_GRAPHICS: - return "Presentation Graphics"; - case TSStreamType.INTERACTIVE_GRAPHICS: - return "Interactive Graphics"; - case TSStreamType.SUBTITLE: - return "Subtitle"; - default: - return "UNKNOWN"; - } - } - } - - public string CodecAltName - { - get - { - switch (StreamType) - { - case TSStreamType.MPEG1_VIDEO: - return "MPEG-1"; - case TSStreamType.MPEG2_VIDEO: - return "MPEG-2"; - case TSStreamType.AVC_VIDEO: - return "AVC"; - case TSStreamType.MVC_VIDEO: - return "MVC"; - case TSStreamType.VC1_VIDEO: - return "VC-1"; - case TSStreamType.MPEG1_AUDIO: - return "MP1"; - case TSStreamType.MPEG2_AUDIO: - return "MP2"; - case TSStreamType.LPCM_AUDIO: - return "LPCM"; - case TSStreamType.AC3_AUDIO: - return "DD AC3"; - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - return "DD AC3+"; - case TSStreamType.AC3_TRUE_HD_AUDIO: - return "Dolby TrueHD"; - case TSStreamType.DTS_AUDIO: - return "DTS"; - case TSStreamType.DTS_HD_AUDIO: - return "DTS-HD Hi-Res"; - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - return "DTS Express"; - case TSStreamType.DTS_HD_MASTER_AUDIO: - return "DTS-HD Master"; - case TSStreamType.PRESENTATION_GRAPHICS: - return "PGS"; - case TSStreamType.INTERACTIVE_GRAPHICS: - return "IGS"; - case TSStreamType.SUBTITLE: - return "SUB"; - default: - return "UNKNOWN"; - } - } - } - - public string CodecShortName - { - get - { - switch (StreamType) - { - case TSStreamType.MPEG1_VIDEO: - return "MPEG-1"; - case TSStreamType.MPEG2_VIDEO: - return "MPEG-2"; - case TSStreamType.AVC_VIDEO: - return "AVC"; - case TSStreamType.MVC_VIDEO: - return "MVC"; - case TSStreamType.VC1_VIDEO: - return "VC-1"; - case TSStreamType.MPEG1_AUDIO: - return "MP1"; - case TSStreamType.MPEG2_AUDIO: - return "MP2"; - case TSStreamType.LPCM_AUDIO: - return "LPCM"; - case TSStreamType.AC3_AUDIO: - if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended) - return "AC3-EX"; - else - return "AC3"; - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - return "AC3+"; - case TSStreamType.AC3_TRUE_HD_AUDIO: - return "TrueHD"; - case TSStreamType.DTS_AUDIO: - if (((TSAudioStream)this).AudioMode == TSAudioMode.Extended) - return "DTS-ES"; - else - return "DTS"; - case TSStreamType.DTS_HD_AUDIO: - return "DTS-HD HR"; - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - return "DTS Express"; - case TSStreamType.DTS_HD_MASTER_AUDIO: - return "DTS-HD MA"; - case TSStreamType.PRESENTATION_GRAPHICS: - return "PGS"; - case TSStreamType.INTERACTIVE_GRAPHICS: - return "IGS"; - case TSStreamType.SUBTITLE: - return "SUB"; - default: - return "UNKNOWN"; - } - } - } - - public virtual string Description => ""; - - public abstract TSStream Clone(); - - protected void CopyTo(TSStream stream) - { - stream.PID = PID; - stream.StreamType = StreamType; - stream.IsVBR = IsVBR; - stream.BitRate = BitRate; - stream.IsInitialized = IsInitialized; - stream.LanguageCode = _LanguageCode; - if (Descriptors != null) - { - stream.Descriptors = new List(); - foreach (var descriptor in Descriptors) - { - stream.Descriptors.Add(descriptor.Clone()); - } - } - } - } - - public class TSVideoStream : TSStream - { - public TSVideoStream() - { - } - - public int Width; - public int Height; - public bool IsInterlaced; - public int FrameRateEnumerator; - public int FrameRateDenominator; - public TSAspectRatio AspectRatio; - public string EncodingProfile; - - private TSVideoFormat _VideoFormat; - public TSVideoFormat VideoFormat - { - get => _VideoFormat; - set - { - _VideoFormat = value; - switch (value) - { - case TSVideoFormat.VIDEOFORMAT_480i: - Height = 480; - IsInterlaced = true; - break; - case TSVideoFormat.VIDEOFORMAT_480p: - Height = 480; - IsInterlaced = false; - break; - case TSVideoFormat.VIDEOFORMAT_576i: - Height = 576; - IsInterlaced = true; - break; - case TSVideoFormat.VIDEOFORMAT_576p: - Height = 576; - IsInterlaced = false; - break; - case TSVideoFormat.VIDEOFORMAT_720p: - Height = 720; - IsInterlaced = false; - break; - case TSVideoFormat.VIDEOFORMAT_1080i: - Height = 1080; - IsInterlaced = true; - break; - case TSVideoFormat.VIDEOFORMAT_1080p: - Height = 1080; - IsInterlaced = false; - break; - } - } - } - - private TSFrameRate _FrameRate; - public TSFrameRate FrameRate - { - get => _FrameRate; - set - { - _FrameRate = value; - switch (value) - { - case TSFrameRate.FRAMERATE_23_976: - FrameRateEnumerator = 24000; - FrameRateDenominator = 1001; - break; - case TSFrameRate.FRAMERATE_24: - FrameRateEnumerator = 24000; - FrameRateDenominator = 1000; - break; - case TSFrameRate.FRAMERATE_25: - FrameRateEnumerator = 25000; - FrameRateDenominator = 1000; - break; - case TSFrameRate.FRAMERATE_29_97: - FrameRateEnumerator = 30000; - FrameRateDenominator = 1001; - break; - case TSFrameRate.FRAMERATE_50: - FrameRateEnumerator = 50000; - FrameRateDenominator = 1000; - break; - case TSFrameRate.FRAMERATE_59_94: - FrameRateEnumerator = 60000; - FrameRateDenominator = 1001; - break; - } - } - } - - public override string Description - { - get - { - string description = ""; - - if (Height > 0) - { - description += string.Format("{0:D}{1} / ", - Height, - IsInterlaced ? "i" : "p"); - } - if (FrameRateEnumerator > 0 && - FrameRateDenominator > 0) - { - if (FrameRateEnumerator % FrameRateDenominator == 0) - { - description += string.Format("{0:D} fps / ", - FrameRateEnumerator / FrameRateDenominator); - } - else - { - description += string.Format("{0:F3} fps / ", - (double)FrameRateEnumerator / FrameRateDenominator); - } - - } - if (AspectRatio == TSAspectRatio.ASPECT_4_3) - { - description += "4:3 / "; - } - else if (AspectRatio == TSAspectRatio.ASPECT_16_9) - { - description += "16:9 / "; - } - if (EncodingProfile != null) - { - description += EncodingProfile + " / "; - } - if (description.EndsWith(" / ")) - { - description = description.Substring(0, description.Length - 3); - } - return description; - } - } - - public override TSStream Clone() - { - var stream = new TSVideoStream(); - CopyTo(stream); - - stream.VideoFormat = _VideoFormat; - stream.FrameRate = _FrameRate; - stream.Width = Width; - stream.Height = Height; - stream.IsInterlaced = IsInterlaced; - stream.FrameRateEnumerator = FrameRateEnumerator; - stream.FrameRateDenominator = FrameRateDenominator; - stream.AspectRatio = AspectRatio; - stream.EncodingProfile = EncodingProfile; - - return stream; - } - } - - public enum TSAudioMode - { - Unknown, - DualMono, - Stereo, - Surround, - Extended - } - - public class TSAudioStream : TSStream - { - public TSAudioStream() - { - } - - public int SampleRate; - public int ChannelCount; - public int BitDepth; - public int LFE; - public int DialNorm; - public TSAudioMode AudioMode; - public TSAudioStream CoreStream; - public TSChannelLayout ChannelLayout; - - public static int ConvertSampleRate( - TSSampleRate sampleRate) - { - switch (sampleRate) - { - case TSSampleRate.SAMPLERATE_48: - return 48000; - - case TSSampleRate.SAMPLERATE_96: - case TSSampleRate.SAMPLERATE_48_96: - return 96000; - - case TSSampleRate.SAMPLERATE_192: - case TSSampleRate.SAMPLERATE_48_192: - return 192000; - } - return 0; - } - - public string ChannelDescription - { - get - { - if (ChannelLayout == TSChannelLayout.CHANNELLAYOUT_MONO && - ChannelCount == 2) - { - } - - string description = ""; - if (ChannelCount > 0) - { - description += string.Format( - "{0:D}.{1:D}", - ChannelCount, LFE); - } - else - { - switch (ChannelLayout) - { - case TSChannelLayout.CHANNELLAYOUT_MONO: - description += "1.0"; - break; - case TSChannelLayout.CHANNELLAYOUT_STEREO: - description += "2.0"; - break; - case TSChannelLayout.CHANNELLAYOUT_MULTI: - description += "5.1"; - break; - } - } - if (AudioMode == TSAudioMode.Extended) - { - if (StreamType == TSStreamType.AC3_AUDIO) - { - description += "-EX"; - } - if (StreamType == TSStreamType.DTS_AUDIO || - StreamType == TSStreamType.DTS_HD_AUDIO || - StreamType == TSStreamType.DTS_HD_MASTER_AUDIO) - { - description += "-ES"; - } - } - return description; - } - } - - public override string Description - { - get - { - string description = ChannelDescription; - - if (SampleRate > 0) - { - description += string.Format( - " / {0:D} kHz", SampleRate / 1000); - } - if (BitRate > 0) - { - description += string.Format( - " / {0:D} kbps", (uint)Math.Round((double)BitRate / 1000)); - } - if (BitDepth > 0) - { - description += string.Format( - " / {0:D}-bit", BitDepth); - } - if (DialNorm != 0) - { - description += string.Format( - " / DN {0}dB", DialNorm); - } - if (ChannelCount == 2) - { - switch (AudioMode) - { - case TSAudioMode.DualMono: - description += " / Dual Mono"; - break; - - case TSAudioMode.Surround: - description += " / Dolby Surround"; - break; - } - } - if (description.EndsWith(" / ")) - { - description = description.Substring(0, description.Length - 3); - } - if (CoreStream != null) - { - string codec = ""; - switch (CoreStream.StreamType) - { - case TSStreamType.AC3_AUDIO: - codec = "AC3 Embedded"; - break; - case TSStreamType.DTS_AUDIO: - codec = "DTS Core"; - break; - } - description += string.Format( - " ({0}: {1})", - codec, - CoreStream.Description); - } - return description; - } - } - - public override TSStream Clone() - { - var stream = new TSAudioStream(); - CopyTo(stream); - - stream.SampleRate = SampleRate; - stream.ChannelLayout = ChannelLayout; - stream.ChannelCount = ChannelCount; - stream.BitDepth = BitDepth; - stream.LFE = LFE; - stream.DialNorm = DialNorm; - stream.AudioMode = AudioMode; - if (CoreStream != null) - { - stream.CoreStream = (TSAudioStream)CoreStream.Clone(); - } - - return stream; - } - } - - public class TSGraphicsStream : TSStream - { - public TSGraphicsStream() - { - IsVBR = true; - IsInitialized = true; - } - - public override TSStream Clone() - { - var stream = new TSGraphicsStream(); - CopyTo(stream); - return stream; - } - } - - public class TSTextStream : TSStream - { - public TSTextStream() - { - IsVBR = true; - IsInitialized = true; - } - - public override TSStream Clone() - { - var stream = new TSTextStream(); - CopyTo(stream); - return stream; - } - } -} diff --git a/BDInfo/TSStreamBuffer.cs b/BDInfo/TSStreamBuffer.cs deleted file mode 100644 index 30bd1a3f4..000000000 --- a/BDInfo/TSStreamBuffer.cs +++ /dev/null @@ -1,130 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -using System; -using System.Collections.Specialized; -using System.IO; - -namespace BDInfo -{ - public class TSStreamBuffer - { - private MemoryStream Stream = new MemoryStream(); - private int SkipBits = 0; - private byte[] Buffer; - private int BufferLength = 0; - public int TransferLength = 0; - - public TSStreamBuffer() - { - Buffer = new byte[4096]; - Stream = new MemoryStream(Buffer); - } - - public long Length => (long)BufferLength; - - public long Position => Stream.Position; - - public void Add( - byte[] buffer, - int offset, - int length) - { - TransferLength += length; - - if (BufferLength + length >= Buffer.Length) - { - length = Buffer.Length - BufferLength; - } - if (length > 0) - { - Array.Copy(buffer, offset, Buffer, BufferLength, length); - BufferLength += length; - } - } - - public void Seek( - long offset, - SeekOrigin loc) - { - Stream.Seek(offset, loc); - } - - public void Reset() - { - BufferLength = 0; - TransferLength = 0; - } - - public void BeginRead() - { - SkipBits = 0; - Stream.Seek(0, SeekOrigin.Begin); - } - - public void EndRead() - { - } - - public byte[] ReadBytes(int bytes) - { - if (Stream.Position + bytes >= BufferLength) - { - return null; - } - - byte[] value = new byte[bytes]; - Stream.Read(value, 0, bytes); - return value; - } - - public byte ReadByte() - { - return (byte)Stream.ReadByte(); - } - - public int ReadBits(int bits) - { - long pos = Stream.Position; - - int shift = 24; - int data = 0; - for (int i = 0; i < 4; i++) - { - if (pos + i >= BufferLength) break; - data += (Stream.ReadByte() << shift); - shift -= 8; - } - var vector = new BitVector32(data); - - int value = 0; - for (int i = SkipBits; i < SkipBits + bits; i++) - { - value <<= 1; - value += (vector[1 << (32 - i - 1)] ? 1 : 0); - } - - SkipBits += bits; - Stream.Seek(pos + (SkipBits >> 3), SeekOrigin.Begin); - SkipBits = SkipBits % 8; - - return value; - } - } -} diff --git a/BDInfo/TSStreamClip.cs b/BDInfo/TSStreamClip.cs deleted file mode 100644 index 295eeb6b1..000000000 --- a/BDInfo/TSStreamClip.cs +++ /dev/null @@ -1,107 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -using System; -using System.Collections.Generic; - -namespace BDInfo -{ - public class TSStreamClip - { - public int AngleIndex = 0; - public string Name; - public double TimeIn; - public double TimeOut; - public double RelativeTimeIn; - public double RelativeTimeOut; - public double Length; - - public ulong FileSize = 0; - public ulong InterleavedFileSize = 0; - public ulong PayloadBytes = 0; - public ulong PacketCount = 0; - public double PacketSeconds = 0; - - public List Chapters = new List(); - - public TSStreamFile StreamFile = null; - public TSStreamClipFile StreamClipFile = null; - - public TSStreamClip( - TSStreamFile streamFile, - TSStreamClipFile streamClipFile) - { - if (streamFile != null) - { - Name = streamFile.Name; - StreamFile = streamFile; - FileSize = (ulong)StreamFile.FileInfo.Length; - if (StreamFile.InterleavedFile != null) - { - InterleavedFileSize = (ulong)StreamFile.InterleavedFile.FileInfo.Length; - } - } - StreamClipFile = streamClipFile; - } - - public string DisplayName - { - get - { - if (StreamFile != null && - StreamFile.InterleavedFile != null && - BDInfoSettings.EnableSSIF) - { - return StreamFile.InterleavedFile.Name; - } - return Name; - } - } - - public ulong PacketSize => PacketCount * 192; - - public ulong PacketBitRate - { - get - { - if (PacketSeconds > 0) - { - return (ulong)Math.Round(((PacketSize * 8.0) / PacketSeconds)); - } - return 0; - } - } - - public bool IsCompatible(TSStreamClip clip) - { - foreach (var stream1 in StreamFile.Streams.Values) - { - if (clip.StreamFile.Streams.ContainsKey(stream1.PID)) - { - var stream2 = clip.StreamFile.Streams[stream1.PID]; - if (stream1.StreamType != stream2.StreamType) - { - return false; - } - } - } - return true; - } - } -} diff --git a/BDInfo/TSStreamClipFile.cs b/BDInfo/TSStreamClipFile.cs deleted file mode 100644 index e1097b23d..000000000 --- a/BDInfo/TSStreamClipFile.cs +++ /dev/null @@ -1,244 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -#undef DEBUG -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; -using MediaBrowser.Model.IO; - -namespace BDInfo -{ - public class TSStreamClipFile - { - public FileSystemMetadata FileInfo = null; - public string FileType = null; - public bool IsValid = false; - public string Name = null; - - public Dictionary Streams = - new Dictionary(); - - public TSStreamClipFile(FileSystemMetadata fileInfo) - { - FileInfo = fileInfo; - Name = fileInfo.Name.ToUpper(); - } - - public void Scan() - { - Stream fileStream = null; - BinaryReader fileReader = null; - - try - { -#if DEBUG - Debug.WriteLine(string.Format( - "Scanning {0}...", Name)); -#endif - Streams.Clear(); - - fileStream = File.OpenRead(FileInfo.FullName); - fileReader = new BinaryReader(fileStream); - - byte[] data = new byte[fileStream.Length]; - fileReader.Read(data, 0, data.Length); - - byte[] fileType = new byte[8]; - Array.Copy(data, 0, fileType, 0, fileType.Length); - - FileType = Encoding.ASCII.GetString(fileType, 0, fileType.Length); - if (FileType != "HDMV0100" && - FileType != "HDMV0200") - { - throw new Exception(string.Format( - "Clip info file {0} has an unknown file type {1}.", - FileInfo.Name, FileType)); - } -#if DEBUG - Debug.WriteLine(string.Format( - "\tFileType: {0}", FileType)); -#endif - int clipIndex = - ((int)data[12] << 24) + - ((int)data[13] << 16) + - ((int)data[14] << 8) + - ((int)data[15]); - - int clipLength = - ((int)data[clipIndex] << 24) + - ((int)data[clipIndex + 1] << 16) + - ((int)data[clipIndex + 2] << 8) + - ((int)data[clipIndex + 3]); - - byte[] clipData = new byte[clipLength]; - Array.Copy(data, clipIndex + 4, clipData, 0, clipData.Length); - - int streamCount = clipData[8]; -#if DEBUG - Debug.WriteLine(string.Format( - "\tStreamCount: {0}", streamCount)); -#endif - int streamOffset = 10; - for (int streamIndex = 0; - streamIndex < streamCount; - streamIndex++) - { - TSStream stream = null; - - ushort PID = (ushort) - ((clipData[streamOffset] << 8) + - clipData[streamOffset + 1]); - - streamOffset += 2; - - var streamType = (TSStreamType) - clipData[streamOffset + 1]; - switch (streamType) - { - case TSStreamType.MVC_VIDEO: - // TODO - break; - - case TSStreamType.AVC_VIDEO: - case TSStreamType.MPEG1_VIDEO: - case TSStreamType.MPEG2_VIDEO: - case TSStreamType.VC1_VIDEO: - { - var videoFormat = (TSVideoFormat) - (clipData[streamOffset + 2] >> 4); - var frameRate = (TSFrameRate) - (clipData[streamOffset + 2] & 0xF); - var aspectRatio = (TSAspectRatio) - (clipData[streamOffset + 3] >> 4); - - stream = new TSVideoStream(); - ((TSVideoStream)stream).VideoFormat = videoFormat; - ((TSVideoStream)stream).AspectRatio = aspectRatio; - ((TSVideoStream)stream).FrameRate = frameRate; -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2} {3} {4}", - PID, - streamType, - videoFormat, - frameRate, - aspectRatio)); -#endif - } - break; - - case TSStreamType.AC3_AUDIO: - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - case TSStreamType.AC3_TRUE_HD_AUDIO: - case TSStreamType.DTS_AUDIO: - case TSStreamType.DTS_HD_AUDIO: - case TSStreamType.DTS_HD_MASTER_AUDIO: - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - case TSStreamType.LPCM_AUDIO: - case TSStreamType.MPEG1_AUDIO: - case TSStreamType.MPEG2_AUDIO: - { - byte[] languageBytes = new byte[3]; - Array.Copy(clipData, streamOffset + 3, - languageBytes, 0, languageBytes.Length); - string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length); - - var channelLayout = (TSChannelLayout) - (clipData[streamOffset + 2] >> 4); - var sampleRate = (TSSampleRate) - (clipData[streamOffset + 2] & 0xF); - - stream = new TSAudioStream(); - ((TSAudioStream)stream).LanguageCode = languageCode; - ((TSAudioStream)stream).ChannelLayout = channelLayout; - ((TSAudioStream)stream).SampleRate = TSAudioStream.ConvertSampleRate(sampleRate); - ((TSAudioStream)stream).LanguageCode = languageCode; -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2} {3} {4}", - PID, - streamType, - languageCode, - channelLayout, - sampleRate)); -#endif - } - break; - - case TSStreamType.INTERACTIVE_GRAPHICS: - case TSStreamType.PRESENTATION_GRAPHICS: - { - byte[] languageBytes = new byte[3]; - Array.Copy(clipData, streamOffset + 2, - languageBytes, 0, languageBytes.Length); - string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length); - - stream = new TSGraphicsStream(); - stream.LanguageCode = languageCode; -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2}", - PID, - streamType, - languageCode)); -#endif - } - break; - - case TSStreamType.SUBTITLE: - { - byte[] languageBytes = new byte[3]; - Array.Copy(clipData, streamOffset + 3, - languageBytes, 0, languageBytes.Length); - string languageCode = Encoding.ASCII.GetString(languageBytes, 0, languageBytes.Length); -#if DEBUG - Debug.WriteLine(string.Format( - "\t{0} {1} {2}", - PID, - streamType, - languageCode)); -#endif - stream = new TSTextStream(); - stream.LanguageCode = languageCode; - } - break; - } - - if (stream != null) - { - stream.PID = PID; - stream.StreamType = streamType; - Streams.Add(PID, stream); - } - - streamOffset += clipData[streamOffset] + 1; - } - IsValid = true; - } - finally - { - if (fileReader != null) fileReader.Dispose(); - if (fileStream != null) fileStream.Dispose(); - } - } - } -} diff --git a/BDInfo/TSStreamFile.cs b/BDInfo/TSStreamFile.cs deleted file mode 100644 index ecf6609e2..000000000 --- a/BDInfo/TSStreamFile.cs +++ /dev/null @@ -1,1555 +0,0 @@ -//============================================================================ -// BDInfo - Blu-ray Video and Audio Analysis Tool -// Copyright © 2010 Cinema Squid -// -// This library is free software; you can redistribute it and/or -// modify it under the terms of the GNU Lesser General Public -// License as published by the Free Software Foundation; either -// version 2.1 of the License, or (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -//============================================================================= - -#undef DEBUG -using System; -using System.Collections.Generic; -using System.IO; -using MediaBrowser.Model.IO; - -namespace BDInfo -{ - public class TSStreamState - { - public ulong TransferCount = 0; - - public string StreamTag = null; - - public ulong TotalPackets = 0; - public ulong WindowPackets = 0; - - public ulong TotalBytes = 0; - public ulong WindowBytes = 0; - - public long PeakTransferLength = 0; - public long PeakTransferRate = 0; - - public double TransferMarker = 0; - public double TransferInterval = 0; - - public TSStreamBuffer StreamBuffer = new TSStreamBuffer(); - - public uint Parse = 0; - public bool TransferState = false; - public int TransferLength = 0; - public int PacketLength = 0; - public byte PacketLengthParse = 0; - public byte PacketParse = 0; - - public byte PTSParse = 0; - public ulong PTS = 0; - public ulong PTSTemp = 0; - public ulong PTSLast = 0; - public ulong PTSPrev = 0; - public ulong PTSDiff = 0; - public ulong PTSCount = 0; - public ulong PTSTransfer = 0; - - public byte DTSParse = 0; - public ulong DTSTemp = 0; - public ulong DTSPrev = 0; - - public byte PESHeaderLength = 0; - public byte PESHeaderFlags = 0; -#if DEBUG - public byte PESHeaderIndex = 0; - public byte[] PESHeader = new byte[256 + 9]; -#endif - } - - public class TSPacketParser - { - public bool SyncState = false; - public byte TimeCodeParse = 4; - public byte PacketLength = 0; - public byte HeaderParse = 0; - - public uint TimeCode; - public byte TransportErrorIndicator; - public byte PayloadUnitStartIndicator; - public byte TransportPriority; - public ushort PID; - public byte TransportScramblingControl; - public byte AdaptionFieldControl; - - public bool AdaptionFieldState = false; - public byte AdaptionFieldParse = 0; - public byte AdaptionFieldLength = 0; - - public ushort PCRPID = 0xFFFF; - public byte PCRParse = 0; - public ulong PreviousPCR = 0; - public ulong PCR = 0; - public ulong PCRCount = 0; - public ulong PTSFirst = ulong.MaxValue; - public ulong PTSLast = ulong.MinValue; - public ulong PTSDiff = 0; - - public byte[] PAT = new byte[1024]; - public bool PATSectionStart = false; - public byte PATPointerField = 0; - public uint PATOffset = 0; - public byte PATSectionLengthParse = 0; - public ushort PATSectionLength = 0; - public uint PATSectionParse = 0; - public bool PATTransferState = false; - public byte PATSectionNumber = 0; - public byte PATLastSectionNumber = 0; - - public ushort TransportStreamId = 0xFFFF; - - public List PMTProgramDescriptors = new List(); - public ushort PMTPID = 0xFFFF; - public Dictionary PMT = new Dictionary(); - public bool PMTSectionStart = false; - public ushort PMTProgramInfoLength = 0; - public byte PMTProgramDescriptor = 0; - public byte PMTProgramDescriptorLengthParse = 0; - public byte PMTProgramDescriptorLength = 0; - public ushort PMTStreamInfoLength = 0; - public uint PMTStreamDescriptorLengthParse = 0; - public uint PMTStreamDescriptorLength = 0; - public byte PMTPointerField = 0; - public uint PMTOffset = 0; - public uint PMTSectionLengthParse = 0; - public ushort PMTSectionLength = 0; - public uint PMTSectionParse = 0; - public bool PMTTransferState = false; - public byte PMTSectionNumber = 0; - public byte PMTLastSectionNumber = 0; - - public byte PMTTemp = 0; - - public TSStream Stream = null; - public TSStreamState StreamState = null; - - public ulong TotalPackets = 0; - } - - public class TSStreamDiagnostics - { - public ulong Bytes = 0; - public ulong Packets = 0; - public double Marker = 0; - public double Interval = 0; - public string Tag = null; - } - - public class TSStreamFile - { - public FileSystemMetadata FileInfo = null; - public string Name = null; - public long Size = 0; - public double Length = 0; - - public TSInterleavedFile InterleavedFile = null; - - private Dictionary StreamStates = - new Dictionary(); - - public Dictionary Streams = - new Dictionary(); - - public Dictionary> StreamDiagnostics = - new Dictionary>(); - - private List Playlists = null; - - private readonly IFileSystem _fileSystem; - - public TSStreamFile(FileSystemMetadata fileInfo, IFileSystem fileSystem) - { - FileInfo = fileInfo; - _fileSystem = fileSystem; - Name = fileInfo.Name.ToUpper(); - } - - public string DisplayName - { - get - { - if (BDInfoSettings.EnableSSIF && - InterleavedFile != null) - { - return InterleavedFile.Name; - } - return Name; - } - } - - private bool ScanStream( - TSStream stream, - TSStreamState streamState, - TSStreamBuffer buffer) - { - streamState.StreamTag = null; - - long bitrate = 0; - if (stream.IsAudioStream && - streamState.PTSTransfer > 0) - { - bitrate = (long)Math.Round( - (buffer.TransferLength * 8.0) / - ((double)streamState.PTSTransfer / 90000)); - - if (bitrate > streamState.PeakTransferRate) - { - streamState.PeakTransferRate = bitrate; - } - } - if (buffer.TransferLength > streamState.PeakTransferLength) - { - streamState.PeakTransferLength = buffer.TransferLength; - } - - buffer.BeginRead(); - switch (stream.StreamType) - { - case TSStreamType.MPEG2_VIDEO: - TSCodecMPEG2.Scan( - (TSVideoStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.AVC_VIDEO: - TSCodecAVC.Scan( - (TSVideoStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.MVC_VIDEO: - TSCodecMVC.Scan( - (TSVideoStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.VC1_VIDEO: - TSCodecVC1.Scan( - (TSVideoStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.AC3_AUDIO: - TSCodecAC3.Scan( - (TSAudioStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - TSCodecAC3.Scan( - (TSAudioStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.AC3_TRUE_HD_AUDIO: - TSCodecTrueHD.Scan( - (TSAudioStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.LPCM_AUDIO: - TSCodecLPCM.Scan( - (TSAudioStream)stream, buffer, ref streamState.StreamTag); - break; - - case TSStreamType.DTS_AUDIO: - TSCodecDTS.Scan( - (TSAudioStream)stream, buffer, bitrate, ref streamState.StreamTag); - break; - - case TSStreamType.DTS_HD_AUDIO: - case TSStreamType.DTS_HD_MASTER_AUDIO: - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - TSCodecDTSHD.Scan( - (TSAudioStream)stream, buffer, bitrate, ref streamState.StreamTag); - break; - - default: - stream.IsInitialized = true; - break; - } - buffer.EndRead(); - streamState.StreamBuffer.Reset(); - - bool isAVC = false; - bool isMVC = false; - foreach (var finishedStream in Streams.Values) - { - if (!finishedStream.IsInitialized) - { - return false; - } - if (finishedStream.StreamType == TSStreamType.AVC_VIDEO) - { - isAVC = true; - } - if (finishedStream.StreamType == TSStreamType.MVC_VIDEO) - { - isMVC = true; - } - } - if (isMVC && !isAVC) - { - return false; - } - return true; - } - - private void UpdateStreamBitrates( - ushort PTSPID, - ulong PTS, - ulong PTSDiff) - { - if (Playlists == null) return; - - foreach (ushort PID in StreamStates.Keys) - { - if (Streams.ContainsKey(PID) && - Streams[PID].IsVideoStream && - PID != PTSPID) - { - continue; - } - if (StreamStates[PID].WindowPackets == 0) - { - continue; - } - UpdateStreamBitrate(PID, PTSPID, PTS, PTSDiff); - } - - foreach (var playlist in Playlists) - { - double packetSeconds = 0; - foreach (var clip in playlist.StreamClips) - { - if (clip.AngleIndex == 0) - { - packetSeconds += clip.PacketSeconds; - } - } - if (packetSeconds > 0) - { - foreach (var playlistStream in playlist.SortedStreams) - { - if (playlistStream.IsVBR) - { - playlistStream.BitRate = (long)Math.Round( - ((playlistStream.PayloadBytes * 8.0) / packetSeconds)); - - if (playlistStream.StreamType == TSStreamType.AC3_TRUE_HD_AUDIO && - ((TSAudioStream)playlistStream).CoreStream != null) - { - playlistStream.BitRate -= - ((TSAudioStream)playlistStream).CoreStream.BitRate; - } - } - } - } - } - } - - private void UpdateStreamBitrate( - ushort PID, - ushort PTSPID, - ulong PTS, - ulong PTSDiff) - { - if (Playlists == null) return; - - var streamState = StreamStates[PID]; - double streamTime = (double)PTS / 90000; - double streamInterval = (double)PTSDiff / 90000; - double streamOffset = streamTime + streamInterval; - - foreach (var playlist in Playlists) - { - foreach (var clip in playlist.StreamClips) - { - if (clip.Name != this.Name) continue; - - if (streamTime == 0 || - (streamTime >= clip.TimeIn && - streamTime <= clip.TimeOut)) - { - clip.PayloadBytes += streamState.WindowBytes; - clip.PacketCount += streamState.WindowPackets; - - if (streamOffset > clip.TimeIn && - streamOffset - clip.TimeIn > clip.PacketSeconds) - { - clip.PacketSeconds = streamOffset - clip.TimeIn; - } - - var playlistStreams = playlist.Streams; - if (clip.AngleIndex > 0 && - clip.AngleIndex < playlist.AngleStreams.Count + 1) - { - playlistStreams = playlist.AngleStreams[clip.AngleIndex - 1]; - } - if (playlistStreams.ContainsKey(PID)) - { - var stream = playlistStreams[PID]; - - stream.PayloadBytes += streamState.WindowBytes; - stream.PacketCount += streamState.WindowPackets; - - if (stream.IsVideoStream) - { - stream.PacketSeconds += streamInterval; - - stream.ActiveBitRate = (long)Math.Round( - ((stream.PayloadBytes * 8.0) / - stream.PacketSeconds)); - } - - if (stream.StreamType == TSStreamType.AC3_TRUE_HD_AUDIO && - ((TSAudioStream)stream).CoreStream != null) - { - stream.ActiveBitRate -= - ((TSAudioStream)stream).CoreStream.BitRate; - } - } - } - } - } - - if (Streams.ContainsKey(PID)) - { - var stream = Streams[PID]; - stream.PayloadBytes += streamState.WindowBytes; - stream.PacketCount += streamState.WindowPackets; - - if (stream.IsVideoStream) - { - var diag = new TSStreamDiagnostics(); - diag.Marker = (double)PTS / 90000; - diag.Interval = (double)PTSDiff / 90000; - diag.Bytes = streamState.WindowBytes; - diag.Packets = streamState.WindowPackets; - diag.Tag = streamState.StreamTag; - StreamDiagnostics[PID].Add(diag); - - stream.PacketSeconds += streamInterval; - } - } - streamState.WindowPackets = 0; - streamState.WindowBytes = 0; - } - - public void Scan(List playlists, bool isFullScan) - { - if (playlists == null || playlists.Count == 0) - { - return; - } - - Playlists = playlists; - int dataSize = 16384; - Stream fileStream = null; - try - { - string fileName; - if (BDInfoSettings.EnableSSIF && - InterleavedFile != null) - { - fileName = InterleavedFile.FileInfo.FullName; - } - else - { - fileName = FileInfo.FullName; - } - fileStream = _fileSystem.GetFileStream( - fileName, - FileOpenMode.Open, - FileAccessMode.Read, - FileShareMode.Read, - false); - - Size = 0; - Length = 0; - - Streams.Clear(); - StreamStates.Clear(); - StreamDiagnostics.Clear(); - - var parser = - new TSPacketParser(); - - long fileLength = (uint)fileStream.Length; - byte[] buffer = new byte[dataSize]; - int bufferLength = 0; - while ((bufferLength = - fileStream.Read(buffer, 0, buffer.Length)) > 0) - { - int offset = 0; - for (int i = 0; i < bufferLength; i++) - { - if (parser.SyncState == false) - { - if (parser.TimeCodeParse > 0) - { - parser.TimeCodeParse--; - switch (parser.TimeCodeParse) - { - case 3: - parser.TimeCode = 0; - parser.TimeCode |= - ((uint)buffer[i] & 0x3F) << 24; - break; - case 2: - parser.TimeCode |= - ((uint)buffer[i] & 0xFF) << 16; - break; - case 1: - parser.TimeCode |= - ((uint)buffer[i] & 0xFF) << 8; - break; - case 0: - parser.TimeCode |= - ((uint)buffer[i] & 0xFF); - break; - } - } - else if (buffer[i] == 0x47) - { - parser.SyncState = true; - parser.PacketLength = 187; - parser.TimeCodeParse = 4; - parser.HeaderParse = 3; - } - } - else if (parser.HeaderParse > 0) - { - parser.PacketLength--; - parser.HeaderParse--; - - switch (parser.HeaderParse) - { - case 2: - { - parser.TransportErrorIndicator = - (byte)((buffer[i] >> 7) & 0x1); - parser.PayloadUnitStartIndicator = - (byte)((buffer[i] >> 6) & 0x1); - parser.TransportPriority = - (byte)((buffer[i] >> 5) & 0x1); - parser.PID = - (ushort)((buffer[i] & 0x1f) << 8); - } - break; - - case 1: - { - parser.PID |= (ushort)buffer[i]; - if (Streams.ContainsKey(parser.PID)) - { - parser.Stream = Streams[parser.PID]; - } - else - { - parser.Stream = null; - } - if (!StreamStates.ContainsKey(parser.PID)) - { - StreamStates[parser.PID] = new TSStreamState(); - } - parser.StreamState = StreamStates[parser.PID]; - parser.StreamState.TotalPackets++; - parser.StreamState.WindowPackets++; - parser.TotalPackets++; - } - break; - - case 0: - { - parser.TransportScramblingControl = - (byte)((buffer[i] >> 6) & 0x3); - parser.AdaptionFieldControl = - (byte)((buffer[i] >> 4) & 0x3); - - if ((parser.AdaptionFieldControl & 0x2) == 0x2) - { - parser.AdaptionFieldState = true; - } - if (parser.PayloadUnitStartIndicator == 1) - { - if (parser.PID == 0) - { - parser.PATSectionStart = true; - } - else if (parser.PID == parser.PMTPID) - { - parser.PMTSectionStart = true; - } - else if (parser.StreamState != null && - parser.StreamState.TransferState) - { - parser.StreamState.TransferState = false; - parser.StreamState.TransferCount++; - - bool isFinished = ScanStream( - parser.Stream, - parser.StreamState, - parser.StreamState.StreamBuffer); - - if (!isFullScan && isFinished) - { - return; - } - } - } - } - break; - } - } - else if (parser.AdaptionFieldState) - { - parser.PacketLength--; - parser.AdaptionFieldParse = buffer[i]; - parser.AdaptionFieldLength = buffer[i]; - parser.AdaptionFieldState = false; - } - else if (parser.AdaptionFieldParse > 0) - { - parser.PacketLength--; - parser.AdaptionFieldParse--; - if ((parser.AdaptionFieldLength - parser.AdaptionFieldParse) == 1) - { - if ((buffer[i] & 0x10) == 0x10) - { - parser.PCRParse = 6; - parser.PCR = 0; - } - } - else if (parser.PCRParse > 0) - { - parser.PCRParse--; - parser.PCR = (parser.PCR << 8) + (ulong)buffer[i]; - if (parser.PCRParse == 0) - { - parser.PreviousPCR = parser.PCR; - parser.PCR = (parser.PCR & 0x1FF) + - ((parser.PCR >> 15) * 300); - } - parser.PCRCount++; - } - if (parser.PacketLength == 0) - { - parser.SyncState = false; - } - } - else if (parser.PID == 0) - { - if (parser.PATTransferState) - { - if ((bufferLength - i) > parser.PATSectionLength) - { - offset = parser.PATSectionLength; - } - else - { - offset = (bufferLength - i); - } - if (parser.PacketLength <= offset) - { - offset = parser.PacketLength; - } - - for (int k = 0; k < offset; k++) - { - parser.PAT[parser.PATOffset++] = buffer[i++]; - parser.PATSectionLength--; - parser.PacketLength--; - } - --i; - - if (parser.PATSectionLength == 0) - { - parser.PATTransferState = false; - if (parser.PATSectionNumber == parser.PATLastSectionNumber) - { - for (int k = 0; k < (parser.PATOffset - 4); k += 4) - { - uint programNumber = (uint) - ((parser.PAT[k] << 8) + - parser.PAT[k + 1]); - - ushort programPID = (ushort) - (((parser.PAT[k + 2] & 0x1F) << 8) + - parser.PAT[k + 3]); - - if (programNumber == 1) - { - parser.PMTPID = programPID; - } - } - } - } - } - else - { - --parser.PacketLength; - if (parser.PATSectionStart) - { - parser.PATPointerField = buffer[i]; - if (parser.PATPointerField == 0) - { - parser.PATSectionLengthParse = 3; - } - parser.PATSectionStart = false; - } - else if (parser.PATPointerField > 0) - { - --parser.PATPointerField; - if (parser.PATPointerField == 0) - { - parser.PATSectionLengthParse = 3; - } - } - else if (parser.PATSectionLengthParse > 0) - { - --parser.PATSectionLengthParse; - switch (parser.PATSectionLengthParse) - { - case 2: - break; - case 1: - parser.PATSectionLength = (ushort) - ((buffer[i] & 0xF) << 8); - break; - case 0: - parser.PATSectionLength |= buffer[i]; - if (parser.PATSectionLength > 1021) - { - parser.PATSectionLength = 0; - } - else - { - parser.PATSectionParse = 5; - } - break; - } - } - else if (parser.PATSectionParse > 0) - { - --parser.PATSectionLength; - --parser.PATSectionParse; - - switch (parser.PATSectionParse) - { - case 4: - parser.TransportStreamId = (ushort) - (buffer[i] << 8); - break; - case 3: - parser.TransportStreamId |= buffer[i]; - break; - case 2: - break; - case 1: - parser.PATSectionNumber = buffer[i]; - if (parser.PATSectionNumber == 0) - { - parser.PATOffset = 0; - } - break; - case 0: - parser.PATLastSectionNumber = buffer[i]; - parser.PATTransferState = true; - break; - } - } - } - if (parser.PacketLength == 0) - { - parser.SyncState = false; - } - } - else if (parser.PID == parser.PMTPID) - { - if (parser.PMTTransferState) - { - if ((bufferLength - i) >= parser.PMTSectionLength) - { - offset = parser.PMTSectionLength; - } - else - { - offset = (bufferLength - i); - } - if (parser.PacketLength <= offset) - { - offset = parser.PacketLength; - } - if (!parser.PMT.ContainsKey(parser.PID)) - { - parser.PMT[parser.PID] = new byte[1024]; - } - - byte[] PMT = parser.PMT[parser.PID]; - for (int k = 0; k < offset; k++) - { - PMT[parser.PMTOffset++] = buffer[i++]; - --parser.PMTSectionLength; - --parser.PacketLength; - } - --i; - - if (parser.PMTSectionLength == 0) - { - parser.PMTTransferState = false; - if (parser.PMTSectionNumber == parser.PMTLastSectionNumber) - { - //Console.WriteLine("PMT Start: " + parser.PMTTemp); - try - { - for (int k = 0; k < (parser.PMTOffset - 4); k += 5) - { - byte streamType = PMT[k]; - - ushort streamPID = (ushort) - (((PMT[k + 1] & 0x1F) << 8) + - PMT[k + 2]); - - ushort streamInfoLength = (ushort) - (((PMT[k + 3] & 0xF) << 8) + - PMT[k + 4]); - - /* - if (streamInfoLength == 2) - { - // TODO: Cleanup - //streamInfoLength = 0; - } - - Console.WriteLine(string.Format( - "Type: {0} PID: {1} Length: {2}", - streamType, streamPID, streamInfoLength)); - */ - - if (!Streams.ContainsKey(streamPID)) - { - var streamDescriptors = - new List(); - - /* - * TODO: Getting bad streamInfoLength - if (streamInfoLength > 0) - { - for (int d = 0; d < streamInfoLength; d++) - { - byte name = PMT[k + d + 5]; - byte length = PMT[k + d + 6]; - TSDescriptor descriptor = - new TSDescriptor(name, length); - for (int v = 0; v < length; v++) - { - descriptor.Value[v] = - PMT[k + d + v + 7]; - } - streamDescriptors.Add(descriptor); - d += (length + 1); - } - } - */ - CreateStream(streamPID, streamType, streamDescriptors); - } - k += streamInfoLength; - } - } - catch - { - // TODO - //Console.WriteLine(ex.Message); - } - } - } - } - else - { - --parser.PacketLength; - if (parser.PMTSectionStart) - { - parser.PMTPointerField = buffer[i]; - if (parser.PMTPointerField == 0) - { - parser.PMTSectionLengthParse = 3; - } - parser.PMTSectionStart = false; - } - else if (parser.PMTPointerField > 0) - { - --parser.PMTPointerField; - if (parser.PMTPointerField == 0) - { - parser.PMTSectionLengthParse = 3; - } - } - else if (parser.PMTSectionLengthParse > 0) - { - --parser.PMTSectionLengthParse; - switch (parser.PMTSectionLengthParse) - { - case 2: - if (buffer[i] != 0x2) - { - parser.PMTSectionLengthParse = 0; - } - break; - case 1: - parser.PMTSectionLength = (ushort) - ((buffer[i] & 0xF) << 8); - break; - case 0: - parser.PMTSectionLength |= buffer[i]; - if (parser.PMTSectionLength > 1021) - { - parser.PMTSectionLength = 0; - } - else - { - parser.PMTSectionParse = 9; - } - break; - } - } - else if (parser.PMTSectionParse > 0) - { - --parser.PMTSectionLength; - --parser.PMTSectionParse; - - switch (parser.PMTSectionParse) - { - case 8: - case 7: - break; - case 6: - parser.PMTTemp = buffer[i]; - break; - case 5: - parser.PMTSectionNumber = buffer[i]; - if (parser.PMTSectionNumber == 0) - { - parser.PMTOffset = 0; - } - break; - case 4: - parser.PMTLastSectionNumber = buffer[i]; - break; - case 3: - parser.PCRPID = (ushort) - ((buffer[i] & 0x1F) << 8); - break; - case 2: - parser.PCRPID |= buffer[i]; - break; - case 1: - parser.PMTProgramInfoLength = (ushort) - ((buffer[i] & 0xF) << 8); - break; - case 0: - parser.PMTProgramInfoLength |= buffer[i]; - if (parser.PMTProgramInfoLength == 0) - { - parser.PMTTransferState = true; - } - else - { - parser.PMTProgramDescriptorLengthParse = 2; - } - break; - } - } - else if (parser.PMTProgramInfoLength > 0) - { - --parser.PMTSectionLength; - --parser.PMTProgramInfoLength; - - if (parser.PMTProgramDescriptorLengthParse > 0) - { - --parser.PMTProgramDescriptorLengthParse; - switch (parser.PMTProgramDescriptorLengthParse) - { - case 1: - parser.PMTProgramDescriptor = buffer[i]; - break; - case 0: - parser.PMTProgramDescriptorLength = buffer[i]; - parser.PMTProgramDescriptors.Add( - new TSDescriptor( - parser.PMTProgramDescriptor, - parser.PMTProgramDescriptorLength)); - break; - } - } - else if (parser.PMTProgramDescriptorLength > 0) - { - --parser.PMTProgramDescriptorLength; - - var descriptor = parser.PMTProgramDescriptors[ - parser.PMTProgramDescriptors.Count - 1]; - - int valueIndex = - descriptor.Value.Length - - parser.PMTProgramDescriptorLength - 1; - - descriptor.Value[valueIndex] = buffer[i]; - - if (parser.PMTProgramDescriptorLength == 0 && - parser.PMTProgramInfoLength > 0) - { - parser.PMTProgramDescriptorLengthParse = 2; - } - } - if (parser.PMTProgramInfoLength == 0) - { - parser.PMTTransferState = true; - } - } - } - if (parser.PacketLength == 0) - { - parser.SyncState = false; - } - } - else if (parser.Stream != null && - parser.StreamState != null && - parser.TransportScramblingControl == 0) - { - var stream = parser.Stream; - var streamState = parser.StreamState; - - streamState.Parse = - (streamState.Parse << 8) + buffer[i]; - - if (streamState.TransferState) - { - if ((bufferLength - i) >= streamState.PacketLength && - streamState.PacketLength > 0) - { - offset = streamState.PacketLength; - } - else - { - offset = (bufferLength - i); - } - if (parser.PacketLength <= offset) - { - offset = parser.PacketLength; - } - streamState.TransferLength = offset; - - if (!stream.IsInitialized || - stream.IsVideoStream) - { - streamState.StreamBuffer.Add( - buffer, i, offset); - } - else - { - streamState.StreamBuffer.TransferLength += offset; - } - - i += (int)(streamState.TransferLength - 1); - streamState.PacketLength -= streamState.TransferLength; - parser.PacketLength -= (byte)streamState.TransferLength; - - streamState.TotalBytes += (ulong)streamState.TransferLength; - streamState.WindowBytes += (ulong)streamState.TransferLength; - - if (streamState.PacketLength == 0) - { - streamState.TransferState = false; - streamState.TransferCount++; - bool isFinished = ScanStream( - stream, - streamState, - streamState.StreamBuffer); - - if (!isFullScan && isFinished) - { - return; - } - } - } - else - { - --parser.PacketLength; - - bool headerFound = false; - if (stream.IsVideoStream && - streamState.Parse == 0x000001FD) - { - headerFound = true; - } - if (stream.IsVideoStream && - streamState.Parse >= 0x000001E0 && - streamState.Parse <= 0x000001EF) - { - headerFound = true; - } - if (stream.IsAudioStream && - streamState.Parse == 0x000001BD) - { - headerFound = true; - } - if (stream.IsAudioStream && - (streamState.Parse == 0x000001FA || - streamState.Parse == 0x000001FD)) - { - headerFound = true; - } - - if (!stream.IsVideoStream && - !stream.IsAudioStream && - (streamState.Parse == 0x000001FA || - streamState.Parse == 0x000001FD || - streamState.Parse == 0x000001BD || - (streamState.Parse >= 0x000001E0 && - streamState.Parse <= 0x000001EF))) - { - headerFound = true; - } - - if (headerFound) - { - streamState.PacketLengthParse = 2; -#if DEBUG - streamState.PESHeaderIndex = 0; - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)((streamState.Parse >> 24) & 0xFF); - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)((streamState.Parse >> 16) & 0xFF); - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)((streamState.Parse >> 8) & 0xFF); - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - } - else if (streamState.PacketLengthParse > 0) - { - --streamState.PacketLengthParse; - switch (streamState.PacketLengthParse) - { - case 1: -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 0: - streamState.PacketLength = - (int)(streamState.Parse & 0xFFFF); - streamState.PacketParse = 3; -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - } - } - else if (streamState.PacketParse > 0) - { - --streamState.PacketLength; - --streamState.PacketParse; - - switch (streamState.PacketParse) - { - case 2: -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 1: - streamState.PESHeaderFlags = - (byte)(streamState.Parse & 0xFF); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 0: - streamState.PESHeaderLength = - (byte)(streamState.Parse & 0xFF); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - if ((streamState.PESHeaderFlags & 0xC0) == 0x80) - { - streamState.PTSParse = 5; - } - else if ((streamState.PESHeaderFlags & 0xC0) == 0xC0) - { - streamState.DTSParse = 10; - } - if (streamState.PESHeaderLength == 0) - { - streamState.TransferState = true; - } - break; - } - } - else if (streamState.PTSParse > 0) - { - --streamState.PacketLength; - --streamState.PESHeaderLength; - --streamState.PTSParse; - - switch (streamState.PTSParse) - { - case 4: - streamState.PTSTemp = - ((streamState.Parse & 0xE) << 29); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - break; - - case 3: - streamState.PTSTemp |= - ((streamState.Parse & 0xFF) << 22); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 2: - streamState.PTSTemp |= - ((streamState.Parse & 0xFE) << 14); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 1: - streamState.PTSTemp |= - ((streamState.Parse & 0xFF) << 7); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 0: - streamState.PTSTemp |= - ((streamState.Parse & 0xFE) >> 1); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - streamState.PTS = streamState.PTSTemp; - - if (streamState.PTS > streamState.PTSLast) - { - if (streamState.PTSLast > 0) - { - streamState.PTSTransfer = (streamState.PTS - streamState.PTSLast); - } - streamState.PTSLast = streamState.PTS; - } - - streamState.PTSDiff = streamState.PTS - streamState.DTSPrev; - - if (streamState.PTSCount > 0 && - stream.IsVideoStream) - { - UpdateStreamBitrates(stream.PID, streamState.PTS, streamState.PTSDiff); - if (streamState.DTSTemp < parser.PTSFirst) - { - parser.PTSFirst = streamState.DTSTemp; - } - if (streamState.DTSTemp > parser.PTSLast) - { - parser.PTSLast = streamState.DTSTemp; - } - Length = (double)(parser.PTSLast - parser.PTSFirst) / 90000; - } - - streamState.DTSPrev = streamState.PTS; - streamState.PTSCount++; - if (streamState.PESHeaderLength == 0) - { - streamState.TransferState = true; - } - break; - } - } - else if (streamState.DTSParse > 0) - { - --streamState.PacketLength; - --streamState.PESHeaderLength; - --streamState.DTSParse; - - switch (streamState.DTSParse) - { - case 9: - streamState.PTSTemp = - ((streamState.Parse & 0xE) << 29); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 8: - streamState.PTSTemp |= - ((streamState.Parse & 0xFF) << 22); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 7: - streamState.PTSTemp |= - ((streamState.Parse & 0xFE) << 14); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - break; - - case 6: - streamState.PTSTemp |= - ((streamState.Parse & 0xFF) << 7); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 5: - streamState.PTSTemp |= - ((streamState.Parse & 0xFE) >> 1); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - streamState.PTS = streamState.PTSTemp; - if (streamState.PTS > streamState.PTSLast) - { - streamState.PTSLast = streamState.PTS; - } - break; - - case 4: - streamState.DTSTemp = - ((streamState.Parse & 0xE) << 29); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - break; - - case 3: - streamState.DTSTemp |= - ((streamState.Parse & 0xFF) << 22); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - break; - - case 2: - streamState.DTSTemp |= - ((streamState.Parse & 0xFE) << 14); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - break; - - case 1: - streamState.DTSTemp |= - ((streamState.Parse & 0xFF) << 7); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - break; - - case 0: - streamState.DTSTemp |= - ((streamState.Parse & 0xFE) >> 1); -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xff); -#endif - streamState.PTSDiff = streamState.DTSTemp - streamState.DTSPrev; - - if (streamState.PTSCount > 0 && - stream.IsVideoStream) - { - UpdateStreamBitrates(stream.PID, streamState.DTSTemp, streamState.PTSDiff); - if (streamState.DTSTemp < parser.PTSFirst) - { - parser.PTSFirst = streamState.DTSTemp; - } - if (streamState.DTSTemp > parser.PTSLast) - { - parser.PTSLast = streamState.DTSTemp; - } - Length = (double)(parser.PTSLast - parser.PTSFirst) / 90000; - } - streamState.DTSPrev = streamState.DTSTemp; - streamState.PTSCount++; - if (streamState.PESHeaderLength == 0) - { - streamState.TransferState = true; - } - break; - } - } - else if (streamState.PESHeaderLength > 0) - { - --streamState.PacketLength; - --streamState.PESHeaderLength; -#if DEBUG - streamState.PESHeader[streamState.PESHeaderIndex++] = - (byte)(streamState.Parse & 0xFF); -#endif - if (streamState.PESHeaderLength == 0) - { - streamState.TransferState = true; - } - } - } - if (parser.PacketLength == 0) - { - parser.SyncState = false; - } - } - else - { - parser.PacketLength--; - if ((bufferLength - i) >= parser.PacketLength) - { - i = i + parser.PacketLength; - parser.PacketLength = 0; - } - else - { - parser.PacketLength -= (byte)((bufferLength - i) + 1); - i = bufferLength; - } - if (parser.PacketLength == 0) - { - parser.SyncState = false; - } - } - } - Size += bufferLength; - } - - ulong PTSLast = 0; - ulong PTSDiff = 0; - foreach (var stream in Streams.Values) - { - if (!stream.IsVideoStream) continue; - - if (StreamStates.ContainsKey(stream.PID) && - StreamStates[stream.PID].PTSLast > PTSLast) - { - PTSLast = StreamStates[stream.PID].PTSLast; - PTSDiff = PTSLast - StreamStates[stream.PID].DTSPrev; - } - UpdateStreamBitrates(stream.PID, PTSLast, PTSDiff); - } - } - finally - { - if (fileStream != null) - { - fileStream.Dispose(); - } - } - } - - private TSStream CreateStream( - ushort streamPID, - byte streamType, - List streamDescriptors) - { - TSStream stream = null; - - switch ((TSStreamType)streamType) - { - case TSStreamType.MVC_VIDEO: - case TSStreamType.AVC_VIDEO: - case TSStreamType.MPEG1_VIDEO: - case TSStreamType.MPEG2_VIDEO: - case TSStreamType.VC1_VIDEO: - { - stream = new TSVideoStream(); - } - break; - - case TSStreamType.AC3_AUDIO: - case TSStreamType.AC3_PLUS_AUDIO: - case TSStreamType.AC3_PLUS_SECONDARY_AUDIO: - case TSStreamType.AC3_TRUE_HD_AUDIO: - case TSStreamType.DTS_AUDIO: - case TSStreamType.DTS_HD_AUDIO: - case TSStreamType.DTS_HD_MASTER_AUDIO: - case TSStreamType.DTS_HD_SECONDARY_AUDIO: - case TSStreamType.LPCM_AUDIO: - case TSStreamType.MPEG1_AUDIO: - case TSStreamType.MPEG2_AUDIO: - { - stream = new TSAudioStream(); - } - break; - - case TSStreamType.INTERACTIVE_GRAPHICS: - case TSStreamType.PRESENTATION_GRAPHICS: - { - stream = new TSGraphicsStream(); - } - break; - - case TSStreamType.SUBTITLE: - { - stream = new TSTextStream(); - } - break; - - default: - break; - } - - if (stream != null && - !Streams.ContainsKey(streamPID)) - { - stream.PID = streamPID; - stream.StreamType = (TSStreamType)streamType; - stream.Descriptors = streamDescriptors; - Streams[stream.PID] = stream; - } - if (!StreamDiagnostics.ContainsKey(streamPID)) - { - StreamDiagnostics[streamPID] = - new List(); - } - - return stream; - } - } -} diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs new file mode 100644 index 000000000..91c8b2792 --- /dev/null +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoDirectoryInfo.cs @@ -0,0 +1,74 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using BDInfo.IO; +using MediaBrowser.Model.IO; + +namespace MediaBrowser.MediaEncoding.BdInfo +{ + class BdInfoDirectoryInfo : BDInfo.IO.IDirectoryInfo + { + IFileSystem _fileSystem = null; + + FileSystemMetadata _impl = null; + + public string Name => _impl.Name; + + public string FullName => _impl.FullName; + + public IDirectoryInfo Parent + { + get + { + var parentFolder = System.IO.Path.GetDirectoryName(_impl.FullName); + if (parentFolder != null) + { + return new BdInfoDirectoryInfo(_fileSystem, parentFolder); + } + return null; + } + } + + public BdInfoDirectoryInfo(IFileSystem fileSystem, string path) + { + _fileSystem = fileSystem; + _impl = _fileSystem.GetDirectoryInfo(path); + } + + private BdInfoDirectoryInfo(IFileSystem fileSystem, FileSystemMetadata impl) + { + _fileSystem = fileSystem; + _impl = impl; + } + + public IDirectoryInfo[] GetDirectories() + { + return Array.ConvertAll(_fileSystem.GetDirectories(_impl.FullName).ToArray(), + x => new BdInfoDirectoryInfo(_fileSystem, x)); + } + + public IFileInfo[] GetFiles() + { + return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName).ToArray(), + x => new BdInfoFileInfo(_fileSystem, x)); + } + + public IFileInfo[] GetFiles(string searchPattern) + { + return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, false).ToArray(), + x => new BdInfoFileInfo(_fileSystem, x)); + } + + public IFileInfo[] GetFiles(string searchPattern, System.IO.SearchOption searchOption) + { + return Array.ConvertAll(_fileSystem.GetFiles(_impl.FullName, new[] { searchPattern }, false, + searchOption.HasFlag(System.IO.SearchOption.AllDirectories)).ToArray(), + x => new BdInfoFileInfo(_fileSystem, x)); + } + + public static IDirectoryInfo FromFileSystemPath(Model.IO.IFileSystem fs, string path) + { + return new BdInfoDirectoryInfo(fs, path); + } + } +} diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs index 3b6b91684..3260f3051 100644 --- a/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoExaminer.cs @@ -1,4 +1,4 @@ -using System; +using System; using System.Collections.Generic; using System.Linq; using BDInfo; @@ -32,7 +32,7 @@ namespace MediaBrowser.MediaEncoding.BdInfo throw new ArgumentNullException(nameof(path)); } - var bdrom = new BDROM(path, _fileSystem); + var bdrom = new BDROM(BdInfoDirectoryInfo.FromFileSystemPath(_fileSystem, path)); bdrom.Scan(); diff --git a/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs new file mode 100644 index 000000000..de9d7cb78 --- /dev/null +++ b/MediaBrowser.MediaEncoding/BdInfo/BdInfoFileInfo.cs @@ -0,0 +1,40 @@ +using MediaBrowser.Model.IO; + +namespace MediaBrowser.MediaEncoding.BdInfo +{ + class BdInfoFileInfo : BDInfo.IO.IFileInfo + { + IFileSystem _fileSystem = null; + + FileSystemMetadata _impl = null; + + public string Name => _impl.Name; + + public string FullName => _impl.FullName; + + public string Extension => _impl.Extension; + + public long Length => _impl.Length; + + public bool IsDir => _impl.IsDirectory; + + public BdInfoFileInfo(IFileSystem fileSystem, FileSystemMetadata impl) + { + _fileSystem = fileSystem; + _impl = impl; + } + + public System.IO.Stream OpenRead() + { + return _fileSystem.GetFileStream(FullName, + FileOpenMode.Open, + FileAccessMode.Read, + FileShareMode.Read); + } + + public System.IO.StreamReader OpenText() + { + return new System.IO.StreamReader(OpenRead()); + } + } +} diff --git a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj index 558ea7d67..74a5e53b2 100644 --- a/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj +++ b/MediaBrowser.MediaEncoding/MediaBrowser.MediaEncoding.csproj @@ -11,13 +11,13 @@ - + diff --git a/MediaBrowser.sln b/MediaBrowser.sln index 27c8c1668..0d2a3b885 100644 --- a/MediaBrowser.sln +++ b/MediaBrowser.sln @@ -25,8 +25,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Photos", "Emby.Photos\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DvdLib", "DvdLib\DvdLib.csproj", "{713F42B5-878E-499D-A878-E4C652B1D5E8}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "BDInfo", "BDInfo\BDInfo.csproj", "{88AE38DF-19D7-406F-A6A9-09527719A21E}" -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Emby.Server.Implementations", "Emby.Server.Implementations\Emby.Server.Implementations.csproj", "{E383961B-9356-4D5D-8233-9A1079D03055}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RSSDP", "RSSDP\RSSDP.csproj", "{21002819-C39A-4D3E-BE83-2A276A77FB1F}" -- cgit v1.2.3 From c8f403238e3e98aee79959d6e52be9dcd7876256 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 6 Dec 2019 21:28:47 +0100 Subject: Move to .Net Core 3.1 --- Dockerfile | 2 +- Dockerfile.arm | 2 +- Dockerfile.arm64 | 2 +- Jellyfin.Server/Jellyfin.Server.csproj | 2 +- tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj | 2 +- .../Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj | 4 ++-- tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj | 2 +- 7 files changed, 8 insertions(+), 8 deletions(-) diff --git a/Dockerfile b/Dockerfile index 2a60bf184..53a425262 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -ARG DOTNET_VERSION=3.0 +ARG DOTNET_VERSION=3.1 ARG FFMPEG_VERSION=latest FROM node:alpine as web-builder diff --git a/Dockerfile.arm b/Dockerfile.arm index fd3d1e070..4d8fbb77d 100644 --- a/Dockerfile.arm +++ b/Dockerfile.arm @@ -1,6 +1,6 @@ # Requires binfm_misc registration # https://github.com/multiarch/qemu-user-static#binfmt_misc-register -ARG DOTNET_VERSION=3.0 +ARG DOTNET_VERSION=3.1 FROM node:alpine as web-builder diff --git a/Dockerfile.arm64 b/Dockerfile.arm64 index 3c1b2e3ea..d41268f13 100644 --- a/Dockerfile.arm64 +++ b/Dockerfile.arm64 @@ -1,6 +1,6 @@ # Requires binfm_misc registration # https://github.com/multiarch/qemu-user-static#binfmt_misc-register -ARG DOTNET_VERSION=3.0 +ARG DOTNET_VERSION=3.1 FROM node:alpine as web-builder diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 110028176..0ba7b328e 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -3,7 +3,7 @@ jellyfin Exe - netcoreapp3.0 + netcoreapp3.1 false true diff --git a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj index aa005b31d..bc0114d1e 100644 --- a/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj +++ b/tests/Jellyfin.Common.Tests/Jellyfin.Common.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 false diff --git a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj index 70e2d1851..7f6b90533 100644 --- a/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj +++ b/tests/Jellyfin.MediaEncoding.Tests/Jellyfin.MediaEncoding.Tests.csproj @@ -1,12 +1,12 @@ - netcoreapp3.0 + netcoreapp3.1 false - + diff --git a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj index fe1518131..79d2f2144 100644 --- a/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj +++ b/tests/Jellyfin.Naming.Tests/Jellyfin.Naming.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.0 + netcoreapp3.1 false -- cgit v1.2.3 From 554c967dd6a0e7e75e737912e869b7269cd72081 Mon Sep 17 00:00:00 2001 From: Neil Burrows Date: Fri, 13 Dec 2019 10:29:38 +0000 Subject: Add Excluded Tags using SQLite parameters --- .../Data/SqliteItemRepository.cs | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 69cfcb67b..3f96b43b3 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4593,10 +4593,26 @@ namespace Emby.Server.Implementations.Data if (query.ExcludeInheritedTags.Length > 0) { - var tagValues = query.ExcludeInheritedTags.Select(i => "'" + GetCleanValue(i) + "'"); - var tagValuesList = string.Join(",", tagValues); + var paramName = "@ExcludeInheritedTags"; - whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + tagValuesList + ")) is null)"); + if (statement == null) + { + List tagParamList = new List(); + + for (int index = 0; index < query.ExcludeInheritedTags.Length; index++) + { + tagParamList.Add(paramName + index); + } + + whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + string.Join(",", tagParamList) + ")) is null)"); + } + else + { + for (int index = 0; index < query.ExcludeInheritedTags.Length; index++) + { + statement.TryBind(paramName + index, GetCleanValue(query.ExcludeInheritedTags[0])); + } + } } if (query.SeriesStatuses.Length > 0) -- cgit v1.2.3 From 12bb4a92eb69a0dfe06add8f4aebf5da749c6126 Mon Sep 17 00:00:00 2001 From: Neil Burrows Date: Fri, 13 Dec 2019 11:08:19 +0000 Subject: Tidying up code --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 3f96b43b3..2a74a826b 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4594,17 +4594,10 @@ namespace Emby.Server.Implementations.Data if (query.ExcludeInheritedTags.Length > 0) { var paramName = "@ExcludeInheritedTags"; - if (statement == null) { - List tagParamList = new List(); - - for (int index = 0; index < query.ExcludeInheritedTags.Length; index++) - { - tagParamList.Add(paramName + index); - } - - whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + string.Join(",", tagParamList) + ")) is null)"); + int index = 0; + whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + string.Join(",", query.ExcludeInheritedTags.Select(t => paramName + index++)) + ")) is null)"); } else { -- cgit v1.2.3 From 55317b5c749a36411f6582f8cf6a9477f1a2c880 Mon Sep 17 00:00:00 2001 From: Neil Burrows Date: Fri, 13 Dec 2019 13:45:04 +0000 Subject: Fixing index error & split out code for readability --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 2a74a826b..b664738cb 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4596,14 +4596,19 @@ namespace Emby.Server.Implementations.Data var paramName = "@ExcludeInheritedTags"; if (statement == null) { - int index = 0; - whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + string.Join(",", query.ExcludeInheritedTags.Select(t => paramName + index++)) + ")) is null)"); + List paramList = new List(); + for (int index = 0; index < query.ExcludeInheritedTags.Length; index++) + { + paramList.Add(paramName + index); + } + + whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + string.Join(",", paramList) + ")) is null)"); } else { for (int index = 0; index < query.ExcludeInheritedTags.Length; index++) { - statement.TryBind(paramName + index, GetCleanValue(query.ExcludeInheritedTags[0])); + statement.TryBind(paramName + index, GetCleanValue(query.ExcludeInheritedTags[index])); } } } -- cgit v1.2.3 From 5a8e972952e45ff7361d8370e289eb44911b914c Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 13 Dec 2019 20:11:37 +0100 Subject: Enable TreatWarningsAsErrors for some projects Analyzers are only run in debug build, so setting TreatWarningsAsErrors for release build will catch the compiler warnings until we resolve all analyzer warnings. --- Emby.Naming/Audio/AlbumParser.cs | 3 +++ Emby.Naming/Audio/AudioFileParser.cs | 3 +++ Emby.Naming/Audio/MultiPartResult.cs | 3 +++ Emby.Naming/AudioBook/AudioBookFilePathParser.cs | 3 +++ Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs | 3 +++ Emby.Naming/AudioBook/AudioBookInfo.cs | 3 +++ Emby.Naming/AudioBook/AudioBookListResolver.cs | 3 +++ Emby.Naming/AudioBook/AudioBookResolver.cs | 3 +++ Emby.Naming/Common/EpisodeExpression.cs | 3 +++ Emby.Naming/Common/MediaType.cs | 3 +++ Emby.Naming/Common/NamingOptions.cs | 3 +++ Emby.Naming/Emby.Naming.csproj | 10 +++++++--- Emby.Naming/Subtitles/SubtitleInfo.cs | 3 +++ Emby.Naming/Subtitles/SubtitleParser.cs | 3 +++ Emby.Naming/TV/EpisodeInfo.cs | 3 +++ Emby.Naming/TV/EpisodePathParser.cs | 3 +++ Emby.Naming/TV/EpisodePathParserResult.cs | 3 +++ Emby.Naming/TV/EpisodeResolver.cs | 3 +++ Emby.Naming/TV/SeasonPathParser.cs | 3 +++ Emby.Naming/TV/SeasonPathParserResult.cs | 3 +++ Emby.Naming/Video/CleanDateTimeParser.cs | 3 +++ Emby.Naming/Video/CleanDateTimeResult.cs | 5 +++++ Emby.Naming/Video/CleanStringParser.cs | 3 +++ Emby.Naming/Video/CleanStringResult.cs | 4 ++++ Emby.Naming/Video/ExtraResolver.cs | 3 +++ Emby.Naming/Video/ExtraResult.cs | 4 ++++ Emby.Naming/Video/ExtraRule.cs | 6 ++++++ Emby.Naming/Video/ExtraRuleType.cs | 5 +++++ Emby.Naming/Video/FileStack.cs | 13 +++++++++---- Emby.Naming/Video/FlagParser.cs | 3 +++ Emby.Naming/Video/Format3DParser.cs | 3 +++ Emby.Naming/Video/Format3DResult.cs | 3 +++ Emby.Naming/Video/Format3DRule.cs | 4 ++++ Emby.Naming/Video/StackResolver.cs | 3 +++ Emby.Naming/Video/StackResult.cs | 3 +++ Emby.Naming/Video/StubResolver.cs | 3 +++ Emby.Naming/Video/StubResult.cs | 3 +++ Emby.Naming/Video/StubTypeRule.cs | 3 +++ Emby.Naming/Video/VideoFileInfo.cs | 1 + Emby.Naming/Video/VideoInfo.cs | 17 ++++++++++------- Emby.Naming/Video/VideoListResolver.cs | 3 +++ Emby.Naming/Video/VideoResolver.cs | 3 +++ Emby.Photos/Emby.Photos.csproj | 10 +++++++--- .../Emby.Server.Implementations.csproj | 6 +++--- Emby.Server.Implementations/Library/UserManager.cs | 4 ++-- .../LiveTv/EmbyTV/DirectRecorder.cs | 3 ++- .../LiveTv/Listings/SchedulesDirect.cs | 6 +++--- .../LiveTv/TunerHosts/SharedHttpStream.cs | 3 ++- .../Updates/InstallationManager.cs | 4 ++-- Jellyfin.Api/Jellyfin.Api.csproj | 2 +- Jellyfin.Server/Jellyfin.Server.csproj | 4 ++-- 51 files changed, 175 insertions(+), 32 deletions(-) diff --git a/Emby.Naming/Audio/AlbumParser.cs b/Emby.Naming/Audio/AlbumParser.cs index e8d765552..4975b8e19 100644 --- a/Emby.Naming/Audio/AlbumParser.cs +++ b/Emby.Naming/Audio/AlbumParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Globalization; using System.IO; diff --git a/Emby.Naming/Audio/AudioFileParser.cs b/Emby.Naming/Audio/AudioFileParser.cs index 609eb779a..9f21e93dc 100644 --- a/Emby.Naming/Audio/AudioFileParser.cs +++ b/Emby.Naming/Audio/AudioFileParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/Audio/MultiPartResult.cs b/Emby.Naming/Audio/MultiPartResult.cs index 00e4a9eb2..8f68d97fa 100644 --- a/Emby.Naming/Audio/MultiPartResult.cs +++ b/Emby.Naming/Audio/MultiPartResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Audio { public class MultiPartResult diff --git a/Emby.Naming/AudioBook/AudioBookFilePathParser.cs b/Emby.Naming/AudioBook/AudioBookFilePathParser.cs index ea7f06c8c..8dc2e1b97 100644 --- a/Emby.Naming/AudioBook/AudioBookFilePathParser.cs +++ b/Emby.Naming/AudioBook/AudioBookFilePathParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Globalization; using System.IO; diff --git a/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs b/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs index f845e8243..68d6ca4d4 100644 --- a/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs +++ b/Emby.Naming/AudioBook/AudioBookFilePathParserResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.AudioBook { public class AudioBookFilePathParserResult diff --git a/Emby.Naming/AudioBook/AudioBookInfo.cs b/Emby.Naming/AudioBook/AudioBookInfo.cs index d53f53c52..b0b5bd881 100644 --- a/Emby.Naming/AudioBook/AudioBookInfo.cs +++ b/Emby.Naming/AudioBook/AudioBookInfo.cs @@ -7,6 +7,9 @@ namespace Emby.Naming.AudioBook /// public class AudioBookInfo { + /// + /// Initializes a new instance of the class. + /// public AudioBookInfo() { Files = new List(); diff --git a/Emby.Naming/AudioBook/AudioBookListResolver.cs b/Emby.Naming/AudioBook/AudioBookListResolver.cs index 414ef1183..97f359285 100644 --- a/Emby.Naming/AudioBook/AudioBookListResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookListResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System.Collections.Generic; using System.Linq; using Emby.Naming.Common; diff --git a/Emby.Naming/AudioBook/AudioBookResolver.cs b/Emby.Naming/AudioBook/AudioBookResolver.cs index 4a2b516d0..0b0d2035e 100644 --- a/Emby.Naming/AudioBook/AudioBookResolver.cs +++ b/Emby.Naming/AudioBook/AudioBookResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/Common/EpisodeExpression.cs b/Emby.Naming/Common/EpisodeExpression.cs index 136d8189d..30a74fb65 100644 --- a/Emby.Naming/Common/EpisodeExpression.cs +++ b/Emby.Naming/Common/EpisodeExpression.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Text.RegularExpressions; diff --git a/Emby.Naming/Common/MediaType.cs b/Emby.Naming/Common/MediaType.cs index a7b08bf79..a61f10489 100644 --- a/Emby.Naming/Common/MediaType.cs +++ b/Emby.Naming/Common/MediaType.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Common { public enum MediaType diff --git a/Emby.Naming/Common/NamingOptions.cs b/Emby.Naming/Common/NamingOptions.cs index 4c2c43437..69e68660d 100644 --- a/Emby.Naming/Common/NamingOptions.cs +++ b/Emby.Naming/Common/NamingOptions.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Linq; using System.Text.RegularExpressions; diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index 7258beaf4..c69b36894 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -6,6 +6,10 @@ true + + true + + @@ -21,13 +25,13 @@ https://github.com/jellyfin/jellyfin - - + + ../jellyfin.ruleset diff --git a/Emby.Naming/Subtitles/SubtitleInfo.cs b/Emby.Naming/Subtitles/SubtitleInfo.cs index 96fce04d7..fe42846c6 100644 --- a/Emby.Naming/Subtitles/SubtitleInfo.cs +++ b/Emby.Naming/Subtitles/SubtitleInfo.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Subtitles { public class SubtitleInfo diff --git a/Emby.Naming/Subtitles/SubtitleParser.cs b/Emby.Naming/Subtitles/SubtitleParser.cs index ac9432d57..99680c622 100644 --- a/Emby.Naming/Subtitles/SubtitleParser.cs +++ b/Emby.Naming/Subtitles/SubtitleParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/TV/EpisodeInfo.cs b/Emby.Naming/TV/EpisodeInfo.cs index de79b8bba..667129a57 100644 --- a/Emby.Naming/TV/EpisodeInfo.cs +++ b/Emby.Naming/TV/EpisodeInfo.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.TV { public class EpisodeInfo diff --git a/Emby.Naming/TV/EpisodePathParser.cs b/Emby.Naming/TV/EpisodePathParser.cs index a98e8221a..4fac543f9 100644 --- a/Emby.Naming/TV/EpisodePathParser.cs +++ b/Emby.Naming/TV/EpisodePathParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Collections.Generic; using System.Globalization; diff --git a/Emby.Naming/TV/EpisodePathParserResult.cs b/Emby.Naming/TV/EpisodePathParserResult.cs index 996edfc50..3acbbc101 100644 --- a/Emby.Naming/TV/EpisodePathParserResult.cs +++ b/Emby.Naming/TV/EpisodePathParserResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.TV { public class EpisodePathParserResult diff --git a/Emby.Naming/TV/EpisodeResolver.cs b/Emby.Naming/TV/EpisodeResolver.cs index 2d7bcb638..5e115fc75 100644 --- a/Emby.Naming/TV/EpisodeResolver.cs +++ b/Emby.Naming/TV/EpisodeResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/TV/SeasonPathParser.cs b/Emby.Naming/TV/SeasonPathParser.cs index f34faf8e8..e5f90e966 100644 --- a/Emby.Naming/TV/SeasonPathParser.cs +++ b/Emby.Naming/TV/SeasonPathParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Globalization; using System.IO; diff --git a/Emby.Naming/TV/SeasonPathParserResult.cs b/Emby.Naming/TV/SeasonPathParserResult.cs index 548dbd5d2..57c234754 100644 --- a/Emby.Naming/TV/SeasonPathParserResult.cs +++ b/Emby.Naming/TV/SeasonPathParserResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.TV { public class SeasonPathParserResult diff --git a/Emby.Naming/Video/CleanDateTimeParser.cs b/Emby.Naming/Video/CleanDateTimeParser.cs index c6b6039d4..a9db4cccc 100644 --- a/Emby.Naming/Video/CleanDateTimeParser.cs +++ b/Emby.Naming/Video/CleanDateTimeParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Globalization; using System.IO; diff --git a/Emby.Naming/Video/CleanDateTimeResult.cs b/Emby.Naming/Video/CleanDateTimeResult.cs index 6bf24e4d8..a7581972e 100644 --- a/Emby.Naming/Video/CleanDateTimeResult.cs +++ b/Emby.Naming/Video/CleanDateTimeResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Video { public class CleanDateTimeResult @@ -7,11 +10,13 @@ namespace Emby.Naming.Video /// /// The name. public string Name { get; set; } + /// /// Gets or sets the year. /// /// The year. public int? Year { get; set; } + /// /// Gets or sets a value indicating whether this instance has changed. /// diff --git a/Emby.Naming/Video/CleanStringParser.cs b/Emby.Naming/Video/CleanStringParser.cs index 02b90310d..be028c662 100644 --- a/Emby.Naming/Video/CleanStringParser.cs +++ b/Emby.Naming/Video/CleanStringParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System.Collections.Generic; using System.Text.RegularExpressions; diff --git a/Emby.Naming/Video/CleanStringResult.cs b/Emby.Naming/Video/CleanStringResult.cs index b3bc59712..786fe9e02 100644 --- a/Emby.Naming/Video/CleanStringResult.cs +++ b/Emby.Naming/Video/CleanStringResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Video { public class CleanStringResult @@ -7,6 +10,7 @@ namespace Emby.Naming.Video /// /// The name. public string Name { get; set; } + /// /// Gets or sets a value indicating whether this instance has changed. /// diff --git a/Emby.Naming/Video/ExtraResolver.cs b/Emby.Naming/Video/ExtraResolver.cs index 9f70494d0..989ede206 100644 --- a/Emby.Naming/Video/ExtraResolver.cs +++ b/Emby.Naming/Video/ExtraResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/Video/ExtraResult.cs b/Emby.Naming/Video/ExtraResult.cs index ff6f20c47..6081a4494 100644 --- a/Emby.Naming/Video/ExtraResult.cs +++ b/Emby.Naming/Video/ExtraResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Video { public class ExtraResult @@ -7,6 +10,7 @@ namespace Emby.Naming.Video /// /// The type of the extra. public string ExtraType { get; set; } + /// /// Gets or sets the rule. /// diff --git a/Emby.Naming/Video/ExtraRule.cs b/Emby.Naming/Video/ExtraRule.cs index b8eb8427e..cfce79fd0 100644 --- a/Emby.Naming/Video/ExtraRule.cs +++ b/Emby.Naming/Video/ExtraRule.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using Emby.Naming.Common; namespace Emby.Naming.Video @@ -9,16 +12,19 @@ namespace Emby.Naming.Video /// /// The token. public string Token { get; set; } + /// /// Gets or sets the type of the extra. /// /// The type of the extra. public string ExtraType { get; set; } + /// /// Gets or sets the type of the rule. /// /// The type of the rule. public ExtraRuleType RuleType { get; set; } + /// /// Gets or sets the type of the media. /// diff --git a/Emby.Naming/Video/ExtraRuleType.cs b/Emby.Naming/Video/ExtraRuleType.cs index 565239ff9..2bf2799ff 100644 --- a/Emby.Naming/Video/ExtraRuleType.cs +++ b/Emby.Naming/Video/ExtraRuleType.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Video { public enum ExtraRuleType @@ -6,10 +9,12 @@ namespace Emby.Naming.Video /// The suffix /// Suffix = 0, + /// /// The filename /// Filename = 1, + /// /// The regex /// diff --git a/Emby.Naming/Video/FileStack.cs b/Emby.Naming/Video/FileStack.cs index 584bdf2d2..56adf6add 100644 --- a/Emby.Naming/Video/FileStack.cs +++ b/Emby.Naming/Video/FileStack.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Collections.Generic; using System.Linq; @@ -6,15 +9,17 @@ namespace Emby.Naming.Video { public class FileStack { - public string Name { get; set; } - public List Files { get; set; } - public bool IsDirectoryStack { get; set; } - public FileStack() { Files = new List(); } + public string Name { get; set; } + + public List Files { get; set; } + + public bool IsDirectoryStack { get; set; } + public bool ContainsFile(string file, bool isDirectory) { if (IsDirectoryStack == isDirectory) diff --git a/Emby.Naming/Video/FlagParser.cs b/Emby.Naming/Video/FlagParser.cs index bb129499b..acf3438c2 100644 --- a/Emby.Naming/Video/FlagParser.cs +++ b/Emby.Naming/Video/FlagParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using Emby.Naming.Common; diff --git a/Emby.Naming/Video/Format3DParser.cs b/Emby.Naming/Video/Format3DParser.cs index 333a48641..25905f33c 100644 --- a/Emby.Naming/Video/Format3DParser.cs +++ b/Emby.Naming/Video/Format3DParser.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Linq; using Emby.Naming.Common; diff --git a/Emby.Naming/Video/Format3DResult.cs b/Emby.Naming/Video/Format3DResult.cs index 40fc31e08..6ebd72f6b 100644 --- a/Emby.Naming/Video/Format3DResult.cs +++ b/Emby.Naming/Video/Format3DResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System.Collections.Generic; namespace Emby.Naming.Video diff --git a/Emby.Naming/Video/Format3DRule.cs b/Emby.Naming/Video/Format3DRule.cs index dc260175a..ae9fb5b19 100644 --- a/Emby.Naming/Video/Format3DRule.cs +++ b/Emby.Naming/Video/Format3DRule.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Video { public class Format3DRule @@ -7,6 +10,7 @@ namespace Emby.Naming.Video /// /// The token. public string Token { get; set; } + /// /// Gets or sets the preceeding token. /// diff --git a/Emby.Naming/Video/StackResolver.cs b/Emby.Naming/Video/StackResolver.cs index b8ba42da4..e7a769ae6 100644 --- a/Emby.Naming/Video/StackResolver.cs +++ b/Emby.Naming/Video/StackResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Collections.Generic; using System.IO; diff --git a/Emby.Naming/Video/StackResult.cs b/Emby.Naming/Video/StackResult.cs index de35d2825..31ef2d69c 100644 --- a/Emby.Naming/Video/StackResult.cs +++ b/Emby.Naming/Video/StackResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System.Collections.Generic; namespace Emby.Naming.Video diff --git a/Emby.Naming/Video/StubResolver.cs b/Emby.Naming/Video/StubResolver.cs index b78244cb3..bbf399677 100644 --- a/Emby.Naming/Video/StubResolver.cs +++ b/Emby.Naming/Video/StubResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using System.Linq; diff --git a/Emby.Naming/Video/StubResult.cs b/Emby.Naming/Video/StubResult.cs index 7a62e7b98..5ac85528f 100644 --- a/Emby.Naming/Video/StubResult.cs +++ b/Emby.Naming/Video/StubResult.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Video { public struct StubResult diff --git a/Emby.Naming/Video/StubTypeRule.cs b/Emby.Naming/Video/StubTypeRule.cs index d76532150..17c3ef8c5 100644 --- a/Emby.Naming/Video/StubTypeRule.cs +++ b/Emby.Naming/Video/StubTypeRule.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + namespace Emby.Naming.Video { public class StubTypeRule diff --git a/Emby.Naming/Video/VideoFileInfo.cs b/Emby.Naming/Video/VideoFileInfo.cs index 2f42f7784..250a1ec45 100644 --- a/Emby.Naming/Video/VideoFileInfo.cs +++ b/Emby.Naming/Video/VideoFileInfo.cs @@ -77,6 +77,7 @@ namespace Emby.Naming.Video /// The file name without extension. public string FileNameWithoutExtension => !IsDirectory ? System.IO.Path.GetFileNameWithoutExtension(Path) : System.IO.Path.GetFileName(Path); + /// public override string ToString() { // Makes debugging easier diff --git a/Emby.Naming/Video/VideoInfo.cs b/Emby.Naming/Video/VideoInfo.cs index f576b6ca2..a585bb99a 100644 --- a/Emby.Naming/Video/VideoInfo.cs +++ b/Emby.Naming/Video/VideoInfo.cs @@ -7,6 +7,16 @@ namespace Emby.Naming.Video /// public class VideoInfo { + /// + /// Initializes a new instance of the class. + /// + public VideoInfo() + { + Files = new List(); + Extras = new List(); + AlternateVersions = new List(); + } + /// /// Gets or sets the name. /// @@ -36,12 +46,5 @@ namespace Emby.Naming.Video /// /// The alternate versions. public List AlternateVersions { get; set; } - - public VideoInfo() - { - Files = new List(); - Extras = new List(); - AlternateVersions = new List(); - } } } diff --git a/Emby.Naming/Video/VideoListResolver.cs b/Emby.Naming/Video/VideoListResolver.cs index 5fa0041e0..5a32846bf 100644 --- a/Emby.Naming/Video/VideoListResolver.cs +++ b/Emby.Naming/Video/VideoListResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.Collections.Generic; using System.IO; diff --git a/Emby.Naming/Video/VideoResolver.cs b/Emby.Naming/Video/VideoResolver.cs index 91f443500..5a93e1eaf 100644 --- a/Emby.Naming/Video/VideoResolver.cs +++ b/Emby.Naming/Video/VideoResolver.cs @@ -1,3 +1,6 @@ +#pragma warning disable CS1591 +#pragma warning disable SA1600 + using System; using System.IO; using System.Linq; diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj index 64692c370..4bd0f1e4a 100644 --- a/Emby.Photos/Emby.Photos.csproj +++ b/Emby.Photos/Emby.Photos.csproj @@ -1,5 +1,9 @@ + + true + + @@ -20,12 +24,12 @@ true - - + + ../jellyfin.ruleset diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index fde4d7059..6b45f75bc 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -50,13 +50,13 @@ true - - + + ../jellyfin.ruleset diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 85bfa154a..fd414616f 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -392,7 +392,7 @@ namespace Emby.Server.Implementations.Library if (providers.Length == 0) { // Assign the user to the InvalidAuthProvider since no configured auth provider was valid/found - _logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user.Name, user.Policy.AuthenticationProviderId); + _logger.LogWarning("User {UserName} was found with invalid/missing Authentication Provider {AuthenticationProviderId}. Assigning user to InvalidAuthProvider until this is corrected", user?.Name, user?.Policy.AuthenticationProviderId); providers = new IAuthenticationProvider[] { _invalidAuthProvider }; } @@ -472,7 +472,7 @@ namespace Emby.Server.Implementations.Library if (!success && _networkManager.IsInLocalNetwork(remoteEndPoint) - && user.Configuration.EnableLocalPassword + && user?.Configuration.EnableLocalPassword == true && !string.IsNullOrEmpty(user.EasyPassword)) { // Check easy password diff --git a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs index 8dee7046e..84e8c31f9 100644 --- a/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs +++ b/Emby.Server.Implementations/LiveTv/EmbyTV/DirectRecorder.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Net; @@ -74,7 +75,7 @@ namespace Emby.Server.Implementations.LiveTv.EmbyTV DecompressionMethod = CompressionMethod.None }; - using (var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false)) + using (var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false)) { _logger.LogInformation("Opened recording stream from tuner provider"); diff --git a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs index 838ac97d7..1dd794da0 100644 --- a/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs +++ b/Emby.Server.Implementations/LiveTv/Listings/SchedulesDirect.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.IO; using System.Linq; using System.Net; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common; @@ -12,7 +13,6 @@ using MediaBrowser.Common.Net; using MediaBrowser.Controller.LiveTv; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.LiveTv; using MediaBrowser.Model.Net; using MediaBrowser.Model.Serialization; @@ -663,7 +663,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings try { - return await _httpClient.SendAsync(options, "GET").ConfigureAwait(false); + return await _httpClient.SendAsync(options, HttpMethod.Get).ConfigureAwait(false); } catch (HttpException ex) { @@ -738,7 +738,7 @@ namespace Emby.Server.Implementations.LiveTv.Listings httpOptions.RequestHeaders["token"] = token; - using (await _httpClient.SendAsync(httpOptions, "PUT").ConfigureAwait(false)) + using (await _httpClient.SendAsync(httpOptions, HttpMethod.Put).ConfigureAwait(false)) { } } diff --git a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs index 758495362..0d94f4b32 100644 --- a/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs +++ b/Emby.Server.Implementations/LiveTv/TunerHosts/SharedHttpStream.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.IO; +using System.Net.Http; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; @@ -64,7 +65,7 @@ namespace Emby.Server.Implementations.LiveTv.TunerHosts httpRequestOptions.RequestHeaders[header.Key] = header.Value; } - var response = await _httpClient.SendAsync(httpRequestOptions, "GET").ConfigureAwait(false); + var response = await _httpClient.SendAsync(httpRequestOptions, HttpMethod.Get).ConfigureAwait(false); var extension = "ts"; var requiresRemux = false; diff --git a/Emby.Server.Implementations/Updates/InstallationManager.cs b/Emby.Server.Implementations/Updates/InstallationManager.cs index 2705e0628..c897036eb 100644 --- a/Emby.Server.Implementations/Updates/InstallationManager.cs +++ b/Emby.Server.Implementations/Updates/InstallationManager.cs @@ -1,10 +1,10 @@ using System; using System.Collections.Concurrent; using System.Collections.Generic; -using System.Globalization; using System.IO; using System.Linq; using System.Net.Http; +using System.Runtime.CompilerServices; using System.Security.Cryptography; using System.Threading; using System.Threading.Tasks; @@ -189,7 +189,7 @@ namespace Emby.Server.Implementations.Updates } /// - public async IAsyncEnumerable GetAvailablePluginUpdates(CancellationToken cancellationToken = default) + public async IAsyncEnumerable GetAvailablePluginUpdates([EnumeratorCancellation] CancellationToken cancellationToken = default) { var catalog = await GetAvailablePackages(cancellationToken).ConfigureAwait(false); diff --git a/Jellyfin.Api/Jellyfin.Api.csproj b/Jellyfin.Api/Jellyfin.Api.csproj index a2818b45d..73ffaa53d 100644 --- a/Jellyfin.Api/Jellyfin.Api.csproj +++ b/Jellyfin.Api/Jellyfin.Api.csproj @@ -17,7 +17,7 @@ - + diff --git a/Jellyfin.Server/Jellyfin.Server.csproj b/Jellyfin.Server/Jellyfin.Server.csproj index 110028176..5ec791af9 100644 --- a/Jellyfin.Server/Jellyfin.Server.csproj +++ b/Jellyfin.Server/Jellyfin.Server.csproj @@ -24,8 +24,8 @@ - - + + -- cgit v1.2.3 From 1b2453b4e90b90f19e0527f34f60912eb8ad9474 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 14 Dec 2019 12:51:27 +0900 Subject: fix playlist deletion --- .../Library/LibraryManager.cs | 2 +- .../Playlists/PlaylistManager.cs | 35 +++++++++++++++------- MediaBrowser.Api/Library/LibraryService.cs | 5 ++-- 3 files changed, 27 insertions(+), 15 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 6942088fe..b03b7e67e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -394,7 +394,7 @@ namespace Emby.Server.Implementations.Library foreach (var fileSystemInfo in item.GetDeletePaths().ToList()) { - if (File.Exists(fileSystemInfo.FullName)) + if (File.Exists(fileSystemInfo.FullName) || Directory.Exists(fileSystemInfo.FullName)) { try { diff --git a/Emby.Server.Implementations/Playlists/PlaylistManager.cs b/Emby.Server.Implementations/Playlists/PlaylistManager.cs index 0f58e43ed..b26f4026c 100644 --- a/Emby.Server.Implementations/Playlists/PlaylistManager.cs +++ b/Emby.Server.Implementations/Playlists/PlaylistManager.cs @@ -56,10 +56,8 @@ namespace Emby.Server.Implementations.Playlists { var name = options.Name; - var folderName = _fileSystem.GetValidFilename(name) + " [playlist]"; - + var folderName = _fileSystem.GetValidFilename(name); var parentFolder = GetPlaylistsFolder(Guid.Empty); - if (parentFolder == null) { throw new ArgumentException(); @@ -253,11 +251,13 @@ namespace Emby.Server.Implementations.Playlists SavePlaylistFile(playlist); } - _providerManager.QueueRefresh(playlist.Id, new MetadataRefreshOptions(new DirectoryService(_fileSystem)) - { - ForceSave = true - - }, RefreshPriority.High); + _providerManager.QueueRefresh( + playlist.Id, + new MetadataRefreshOptions(new DirectoryService(_fileSystem)) + { + ForceSave = true + }, + RefreshPriority.High); } public void MoveItem(string playlistId, string entryId, int newIndex) @@ -303,7 +303,8 @@ namespace Emby.Server.Implementations.Playlists private void SavePlaylistFile(Playlist item) { - // This is probably best done as a metatata provider, but saving a file over itself will first require some core work to prevent this from happening when not needed + // this is probably best done as a metadata provider + // saving a file over itself will require some work to prevent this from happening when not needed var playlistPath = item.Path; var extension = Path.GetExtension(playlistPath); @@ -335,12 +336,14 @@ namespace Emby.Server.Implementations.Playlists { entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value); } + playlist.PlaylistEntries.Add(entry); } string text = new WplContent().ToText(playlist); File.WriteAllText(playlistPath, text); } + if (string.Equals(".zpl", extension, StringComparison.OrdinalIgnoreCase)) { var playlist = new ZplPlaylist(); @@ -375,6 +378,7 @@ namespace Emby.Server.Implementations.Playlists string text = new ZplContent().ToText(playlist); File.WriteAllText(playlistPath, text); } + if (string.Equals(".m3u", extension, StringComparison.OrdinalIgnoreCase)) { var playlist = new M3uPlaylist(); @@ -398,12 +402,14 @@ namespace Emby.Server.Implementations.Playlists { entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value); } + playlist.PlaylistEntries.Add(entry); } string text = new M3uContent().ToText(playlist); File.WriteAllText(playlistPath, text); } + if (string.Equals(".m3u8", extension, StringComparison.OrdinalIgnoreCase)) { var playlist = new M3uPlaylist(); @@ -427,12 +433,14 @@ namespace Emby.Server.Implementations.Playlists { entry.Duration = TimeSpan.FromTicks(child.RunTimeTicks.Value); } + playlist.PlaylistEntries.Add(entry); } string text = new M3u8Content().ToText(playlist); File.WriteAllText(playlistPath, text); } + if (string.Equals(".pls", extension, StringComparison.OrdinalIgnoreCase)) { var playlist = new PlsPlaylist(); @@ -448,6 +456,7 @@ namespace Emby.Server.Implementations.Playlists { entry.Length = TimeSpan.FromTicks(child.RunTimeTicks.Value); } + playlist.PlaylistEntries.Add(entry); } @@ -473,7 +482,7 @@ namespace Emby.Server.Implementations.Playlists throw new ArgumentException("File absolute path was null or empty.", nameof(fileAbsolutePath)); } - if (!folderPath.EndsWith(Path.DirectorySeparatorChar.ToString())) + if (!folderPath.EndsWith(Path.DirectorySeparatorChar)) { folderPath = folderPath + Path.DirectorySeparatorChar; } @@ -481,7 +490,11 @@ namespace Emby.Server.Implementations.Playlists var folderUri = new Uri(folderPath); var fileAbsoluteUri = new Uri(fileAbsolutePath); - if (folderUri.Scheme != fileAbsoluteUri.Scheme) { return fileAbsolutePath; } // path can't be made relative. + // path can't be made relative + if (folderUri.Scheme != fileAbsoluteUri.Scheme) + { + return fileAbsolutePath; + } var relativeUri = folderUri.MakeRelativeUri(fileAbsoluteUri); string relativePath = Uri.UnescapeDataString(relativeUri.ToString()); diff --git a/MediaBrowser.Api/Library/LibraryService.cs b/MediaBrowser.Api/Library/LibraryService.cs index 0cc5e112f..b1ea3e262 100644 --- a/MediaBrowser.Api/Library/LibraryService.cs +++ b/MediaBrowser.Api/Library/LibraryService.cs @@ -1006,8 +1006,8 @@ namespace MediaBrowser.Api.Library public void Delete(DeleteItems request) { var ids = string.IsNullOrWhiteSpace(request.Ids) - ? Array.Empty() - : request.Ids.Split(','); + ? Array.Empty() + : request.Ids.Split(','); foreach (var i in ids) { @@ -1028,7 +1028,6 @@ namespace MediaBrowser.Api.Library _libraryManager.DeleteItem(item, new DeleteOptions { DeleteFileLocation = true - }, true); } } -- cgit v1.2.3 From 623e85a9e4472b8dd5b31574daf15e85866a25f7 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sat, 14 Dec 2019 22:34:18 +0900 Subject: add suggested changes Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Library/LibraryManager.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index b03b7e67e..3bb07bc31 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -392,9 +392,9 @@ namespace Emby.Server.Implementations.Library // Add this flag to GetDeletePaths if required in the future var isRequiredForDelete = true; - foreach (var fileSystemInfo in item.GetDeletePaths().ToList()) + foreach (var fileSystemInfo in item.GetDeletePaths()) { - if (File.Exists(fileSystemInfo.FullName) || Directory.Exists(fileSystemInfo.FullName)) + if (fileSystemInfo.IsDirectory ? Directory.Exists(fileSystemInfo.FullName) : File.Exists(fileSystemInfo.FullName)) { try { -- cgit v1.2.3 From d9c0721e3dee52ec8a101cf3d35ca18ef5bd6cf3 Mon Sep 17 00:00:00 2001 From: Neil Burrows Date: Sat, 14 Dec 2019 17:48:30 +0000 Subject: Reformatting code --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index b664738cb..ef1fe07c1 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -4596,13 +4596,9 @@ namespace Emby.Server.Implementations.Data var paramName = "@ExcludeInheritedTags"; if (statement == null) { - List paramList = new List(); - for (int index = 0; index < query.ExcludeInheritedTags.Length; index++) - { - paramList.Add(paramName + index); - } - - whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + string.Join(",", paramList) + ")) is null)"); + int index = 0; + string excludedTags = string.Join(",", query.ExcludeInheritedTags.Select(t => paramName + index++)); + whereClauses.Add("((select CleanValue from itemvalues where ItemId=Guid and Type=6 and cleanvalue in (" + excludedTags + ")) is null)"); } else { -- cgit v1.2.3 From 28e922326dd7ac480a3ec0dc7f3465ea351ffed1 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 15 Dec 2019 13:38:59 +0900 Subject: remove space Co-Authored-By: Bond-009 --- Emby.Server.Implementations/Library/LibraryManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 3bb07bc31..1f5bd7deb 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -392,7 +392,7 @@ namespace Emby.Server.Implementations.Library // Add this flag to GetDeletePaths if required in the future var isRequiredForDelete = true; - foreach (var fileSystemInfo in item.GetDeletePaths()) + foreach (var fileSystemInfo in item.GetDeletePaths()) { if (fileSystemInfo.IsDirectory ? Directory.Exists(fileSystemInfo.FullName) : File.Exists(fileSystemInfo.FullName)) { -- cgit v1.2.3 From 742d84e53fa7b5048383a41d31399d5f6a27fa50 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Tue, 17 Dec 2019 17:41:12 +0100 Subject: Enable analyzers for Emby.Naming --- Emby.Naming/Emby.Naming.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Naming/Emby.Naming.csproj b/Emby.Naming/Emby.Naming.csproj index c69b36894..ed1670adf 100644 --- a/Emby.Naming/Emby.Naming.csproj +++ b/Emby.Naming/Emby.Naming.csproj @@ -26,12 +26,12 @@ - + ../jellyfin.ruleset -- cgit v1.2.3 From 5c9e849b85f92f542cd23022b9bbcda209111d09 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 18 Dec 2019 12:03:54 +0100 Subject: Enable analyzers --- Emby.Photos/Emby.Photos.csproj | 4 ++-- Emby.Server.Implementations/Emby.Server.Implementations.csproj | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Emby.Photos/Emby.Photos.csproj b/Emby.Photos/Emby.Photos.csproj index 4bd0f1e4a..23b7a819b 100644 --- a/Emby.Photos/Emby.Photos.csproj +++ b/Emby.Photos/Emby.Photos.csproj @@ -25,11 +25,11 @@ - + ../jellyfin.ruleset diff --git a/Emby.Server.Implementations/Emby.Server.Implementations.csproj b/Emby.Server.Implementations/Emby.Server.Implementations.csproj index 6b45f75bc..14cda0868 100644 --- a/Emby.Server.Implementations/Emby.Server.Implementations.csproj +++ b/Emby.Server.Implementations/Emby.Server.Implementations.csproj @@ -51,12 +51,12 @@ - + ../jellyfin.ruleset -- cgit v1.2.3 From eb12754fc5b74d1bed7236c7f454903232a9b144 Mon Sep 17 00:00:00 2001 From: David Date: Wed, 18 Dec 2019 17:18:55 +0100 Subject: Add Tmdb as a Provider for Season Images Changes to be committed: modified: CONTRIBUTORS.md new file: MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs modified: MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs --- CONTRIBUTORS.md | 1 + .../Tmdb/TV/TmdbSeasonImageProvider.cs | 152 +++++++++++++++++++++ .../Tmdb/TV/TmdbSeasonProvider.cs | 3 + 3 files changed, 156 insertions(+) create mode 100644 MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index d69e6330b..458944778 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -31,6 +31,7 @@ - [fhriley](https://github.com/fhriley) - [nevado](https://github.com/nevado) - [mark-monteiro](https://github.com/mark-monteiro) + - [ullmie02](https://github.com/ullmie02) # Emby Contributors diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs new file mode 100644 index 000000000..3a0062ef7 --- /dev/null +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs @@ -0,0 +1,152 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using MediaBrowser.Common.Net; +using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Entities.TV; +using MediaBrowser.Controller.Providers; +using MediaBrowser.Model.Dto; +using MediaBrowser.Model.Entities; +using MediaBrowser.Model.Globalization; +using MediaBrowser.Model.IO; +using MediaBrowser.Model.Providers; +using MediaBrowser.Model.Serialization; +using MediaBrowser.Providers.Tmdb.Models.General; +using MediaBrowser.Providers.Tmdb.Movies; + +namespace MediaBrowser.Providers.Tmdb.TV +{ + public class TmdbSeasonImageProvider : IRemoteImageProvider, IHasOrder + { + private readonly IJsonSerializer _jsonSerializer; + private readonly IHttpClient _httpClient; + private readonly IFileSystem _fileSystem; + private readonly ILocalizationManager _localization; + + public TmdbSeasonImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem, ILocalizationManager localization) + { + _jsonSerializer = jsonSerializer; + _httpClient = httpClient; + _fileSystem = fileSystem; + _localization = localization; + } + + public int Order => 1; + + public string Name => ProviderName; + + public static string ProviderName => TmdbUtils.ProviderName; + + public Task GetImageResponse(string url, CancellationToken cancellationToken) + { + return _httpClient.GetResponse(new HttpRequestOptions + { + CancellationToken = cancellationToken, + Url = url + }); + } + + public async Task> GetImages(BaseItem item, CancellationToken cancellationToken) + { + var season = (Season)item; + var series = season.Series; + + var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tmdb) : null; + + var list = new List(); + + if (string.IsNullOrEmpty(seriesId)) + { + return list; + } + + var seasonNumber = season.IndexNumber; + + if (!seasonNumber.HasValue) + { + return list; + } + + var language = item.GetPreferredMetadataLanguage(); + + var results = await FetchImages(season, seriesId, language, _jsonSerializer, cancellationToken).ConfigureAwait(false); + + var tmdbSettings = await TmdbMovieProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); + + var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original"); + + list.AddRange(results.Select(i => new RemoteImageInfo + { + Url = tmdbImageUrl + i.File_Path, + CommunityRating = i.Vote_Average, + VoteCount = i.Vote_Count, + Width = i.Width, + Height = i.Height, + Language = TmdbMovieProvider.AdjustImageLanguage(i.Iso_639_1, language), + ProviderName = Name, + Type = ImageType.Primary, + RatingType = RatingType.Score + })); + + + var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); + + return list.OrderByDescending(i => + { + if (string.Equals(language, i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 3; + } + if (!isLanguageEn) + { + if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) + { + return 2; + } + } + if (string.IsNullOrEmpty(i.Language)) + { + return isLanguageEn ? 3 : 2; + } + return 0; + }) + .ThenByDescending(i => i.CommunityRating ?? 0) + .ThenByDescending(i => i.VoteCount ?? 0); + } + + private async Task> FetchImages(Season item, string tmdbId, string language, IJsonSerializer jsonSerializer, + CancellationToken cancellationToken) + { + await TmdbSeasonProvider.Current.EnsureSeasonInfo(tmdbId, item.IndexNumber.GetValueOrDefault(), language, cancellationToken).ConfigureAwait(false); + + var path = TmdbSeriesProvider.Current.GetDataFilePath(tmdbId, language); + + if (!string.IsNullOrEmpty(path)) + { + var fileInfo = _fileSystem.GetFileInfo(path); + + if (fileInfo.Exists) + { + return jsonSerializer.DeserializeFromFile(path).Images.Posters; + } + } + + return null; + } + + public IEnumerable GetSupportedImages(BaseItem item) + { + return new List + { + ImageType.Primary + }; + } + + public bool Supports(BaseItem item) + { + return item is Season; + } + } +} diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs index 2f2ac58e8..fc0cde8b3 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonProvider.cs @@ -32,6 +32,8 @@ namespace MediaBrowser.Providers.Tmdb.TV private readonly ILocalizationManager _localization; private readonly ILogger _logger; + internal static TmdbSeasonProvider Current { get; private set; } + public TmdbSeasonProvider(IHttpClient httpClient, IServerConfigurationManager configurationManager, IFileSystem fileSystem, ILocalizationManager localization, IJsonSerializer jsonSerializer, ILoggerFactory loggerFactory) { _httpClient = httpClient; @@ -40,6 +42,7 @@ namespace MediaBrowser.Providers.Tmdb.TV _localization = localization; _jsonSerializer = jsonSerializer; _logger = loggerFactory.CreateLogger(GetType().Name); + Current = this; } public async Task> GetMetadata(SeasonInfo info, CancellationToken cancellationToken) -- cgit v1.2.3 From 1f323683b3b8cfbfd64b74dfc862a678962c7d38 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 19 Dec 2019 18:59:55 +0100 Subject: Add requested changes --- MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs index 3a0062ef7..747676966 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs @@ -59,14 +59,14 @@ namespace MediaBrowser.Providers.Tmdb.TV if (string.IsNullOrEmpty(seriesId)) { - return list; + return Enumerable.Empty(); } var seasonNumber = season.IndexNumber; if (!seasonNumber.HasValue) { - return list; + return Enumerable.Empty(); } var language = item.GetPreferredMetadataLanguage(); @@ -88,7 +88,7 @@ namespace MediaBrowser.Providers.Tmdb.TV ProviderName = Name, Type = ImageType.Primary, RatingType = RatingType.Score - })); + }).ToList()); var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); -- cgit v1.2.3 From ce8754d05286f0cebf4710da928f91167137ddb2 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 19 Dec 2019 19:58:00 +0100 Subject: Refactor list of RemoteImageInfo --- MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs index 747676966..51db2fb13 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs @@ -55,8 +55,6 @@ namespace MediaBrowser.Providers.Tmdb.TV var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tmdb) : null; - var list = new List(); - if (string.IsNullOrEmpty(seriesId)) { return Enumerable.Empty(); @@ -77,7 +75,7 @@ namespace MediaBrowser.Providers.Tmdb.TV var tmdbImageUrl = tmdbSettings.images.GetImageUrl("original"); - list.AddRange(results.Select(i => new RemoteImageInfo + var list = results.Select(i => new RemoteImageInfo { Url = tmdbImageUrl + i.File_Path, CommunityRating = i.Vote_Average, @@ -88,8 +86,7 @@ namespace MediaBrowser.Providers.Tmdb.TV ProviderName = Name, Type = ImageType.Primary, RatingType = RatingType.Score - }).ToList()); - + }).ToList(); var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); -- cgit v1.2.3 From d720d8f3569a0db11ba170c92d8d4ff055c4eaa9 Mon Sep 17 00:00:00 2001 From: David Date: Fri, 20 Dec 2019 20:04:27 +0100 Subject: Add requested changes --- .../Tmdb/TV/TmdbSeasonImageProvider.cs | 23 ++++++++++------------ 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs index 51db2fb13..f0b2cd88e 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.IO; using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -22,15 +23,11 @@ namespace MediaBrowser.Providers.Tmdb.TV { private readonly IJsonSerializer _jsonSerializer; private readonly IHttpClient _httpClient; - private readonly IFileSystem _fileSystem; - private readonly ILocalizationManager _localization; - public TmdbSeasonImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient, IFileSystem fileSystem, ILocalizationManager localization) + public TmdbSeasonImageProvider(IJsonSerializer jsonSerializer, IHttpClient httpClient) { _jsonSerializer = jsonSerializer; _httpClient = httpClient; - _fileSystem = fileSystem; - _localization = localization; } public int Order => 1; @@ -69,7 +66,7 @@ namespace MediaBrowser.Providers.Tmdb.TV var language = item.GetPreferredMetadataLanguage(); - var results = await FetchImages(season, seriesId, language, _jsonSerializer, cancellationToken).ConfigureAwait(false); + var results = await FetchImages(season, seriesId, language, cancellationToken).ConfigureAwait(false); var tmdbSettings = await TmdbMovieProvider.Current.GetTmdbSettings(cancellationToken).ConfigureAwait(false); @@ -86,7 +83,7 @@ namespace MediaBrowser.Providers.Tmdb.TV ProviderName = Name, Type = ImageType.Primary, RatingType = RatingType.Score - }).ToList(); + }); var isLanguageEn = string.Equals(language, "en", StringComparison.OrdinalIgnoreCase); @@ -96,6 +93,7 @@ namespace MediaBrowser.Providers.Tmdb.TV { return 3; } + if (!isLanguageEn) { if (string.Equals("en", i.Language, StringComparison.OrdinalIgnoreCase)) @@ -103,18 +101,19 @@ namespace MediaBrowser.Providers.Tmdb.TV return 2; } } + if (string.IsNullOrEmpty(i.Language)) { return isLanguageEn ? 3 : 2; } + return 0; }) .ThenByDescending(i => i.CommunityRating ?? 0) .ThenByDescending(i => i.VoteCount ?? 0); } - private async Task> FetchImages(Season item, string tmdbId, string language, IJsonSerializer jsonSerializer, - CancellationToken cancellationToken) + private async Task> FetchImages(Season item, string tmdbId, string language, CancellationToken cancellationToken) { await TmdbSeasonProvider.Current.EnsureSeasonInfo(tmdbId, item.IndexNumber.GetValueOrDefault(), language, cancellationToken).ConfigureAwait(false); @@ -122,11 +121,9 @@ namespace MediaBrowser.Providers.Tmdb.TV if (!string.IsNullOrEmpty(path)) { - var fileInfo = _fileSystem.GetFileInfo(path); - - if (fileInfo.Exists) + if (File.Exists(path)) { - return jsonSerializer.DeserializeFromFile(path).Images.Posters; + return _jsonSerializer.DeserializeFromFile(path).Images.Posters; } } -- cgit v1.2.3 From 94d3dda3243dae2daea564b9a1b5c6493b07061e Mon Sep 17 00:00:00 2001 From: David Date: Fri, 20 Dec 2019 20:10:02 +0100 Subject: Refactor seriesId --- MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs index f0b2cd88e..24cc8c73b 100644 --- a/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs +++ b/MediaBrowser.Providers/Tmdb/TV/TmdbSeasonImageProvider.cs @@ -50,7 +50,7 @@ namespace MediaBrowser.Providers.Tmdb.TV var season = (Season)item; var series = season.Series; - var seriesId = series != null ? series.GetProviderId(MetadataProviders.Tmdb) : null; + var seriesId = series?.GetProviderId(MetadataProviders.Tmdb); if (string.IsNullOrEmpty(seriesId)) { -- cgit v1.2.3 From b87750d8e06db371c6161f78b74b057ec9346749 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Fri, 20 Dec 2019 21:50:15 +0100 Subject: Update vs code workspace --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index e2a09c0f1..73f347c9f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -10,7 +10,7 @@ "request": "launch", "preLaunchTask": "build", // If you have changed target frameworks, make sure to update the program path. - "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.0/jellyfin.dll", + "program": "${workspaceFolder}/Jellyfin.Server/bin/Debug/netcoreapp3.1/jellyfin.dll", "args": [], "cwd": "${workspaceFolder}/Jellyfin.Server", // For more information about the 'console' field, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md#console-terminal-window -- cgit v1.2.3 From cf2e2a3f309d59c3c31696fc7f3ef2b6668c89dd Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 22 Dec 2019 21:39:26 +0100 Subject: Fix exceptions while scanning Fixes these exceptions: ``` [2019-12-22 20:48:14.779 +01:00] [ERR] Error in WaitForExit System.InvalidOperationException: No process is associated with this object. at System.Diagnostics.Process.EnsureState(State state) at System.Diagnostics.Process.EnsureState(State state) at System.Diagnostics.Process.GetWaitState() at System.Diagnostics.Process.WaitForExitCore(Int32 milliseconds) at System.Diagnostics.Process.WaitForExit(Int32 milliseconds) at Emby.Server.Implementations.Diagnostics.CommonProcess.WaitForExit(Int32 timeMs) in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 100 at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 785 [2019-12-22 20:48:14.790 +01:00] [INF] Killing ffmpeg process [2019-12-22 20:48:14.795 +01:00] [ERR] Error killing process System.InvalidOperationException: No process is associated with this object. at System.Diagnostics.Process.EnsureState(State state) at System.Diagnostics.Process.EnsureState(State state) at System.Diagnostics.Process.Kill() at Emby.Server.Implementations.Diagnostics.CommonProcess.Kill() in /home/pi/dev/jellyfin/Emby.Server.Implementations/Diagnostics/CommonProcess.cs:line 95 at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.StopProcess(ProcessWrapper process, Int32 waitTimeMs) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 799 [2019-12-22 20:48:14.808 +01:00] [ERR] Error in "ffprobe" System.Text.Json.JsonException: The JSON value could not be converted to System.String. Path: $.streams[0].start_pts | LineNumber: 32 | BytePositionInLine: 26. ---> System.InvalidOperationException: Cannot get the value of a token type 'Number' as a string. at System.Text.Json.Utf8JsonReader.GetString() at System.Text.Json.Serialization.Converters.JsonConverterString.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options) at System.Text.Json.JsonPropertyInfoNotNullable`4.OnRead(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader) at System.Text.Json.JsonPropertyInfo.Read(JsonTokenType tokenType, ReadStack& state, Utf8JsonReader& reader) at System.Text.Json.JsonSerializer.HandleValue(JsonTokenType tokenType, JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& state) at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack) --- End of inner exception stack trace --- at System.Text.Json.ThrowHelper.ReThrowWithPath(ReadStack& readStack, Utf8JsonReader& reader, Exception ex) at System.Text.Json.JsonSerializer.ReadCore(JsonSerializerOptions options, Utf8JsonReader& reader, ReadStack& readStack) at System.Text.Json.JsonSerializer.ReadCore(JsonReaderState& readerState, Boolean isFinalBlock, ReadOnlySpan`1 buffer, JsonSerializerOptions options, ReadStack& readStack) at System.Text.Json.JsonSerializer.ReadAsync[TValue](Stream utf8Json, Type returnType, JsonSerializerOptions options, CancellationToken cancellationToken) at MediaBrowser.MediaEncoding.Encoder.MediaEncoder.GetMediaInfoInternal(String inputPath, String primaryPath, MediaProtocol protocol, Boolean extractChapters, String probeSizeArgument, Boolean isAudio, Nullable`1 videoType, Boolean forceEnableLogging, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs:line 399 at MediaBrowser.Providers.MediaInfo.FFProbeVideoInfo.ProbeVideo[T](T item, MetadataRefreshOptions options, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs:line 122 at MediaBrowser.Providers.Manager.MetadataService`2.RunCustomProvider(ICustomMetadataProvider`1 provider, TItemType item, String logName, MetadataRefreshOptions options, RefreshResult refreshResult, CancellationToken cancellationToken) in /home/pi/dev/jellyfin/MediaBrowser.Providers/Manager/MetadataService.cs:line 815 ``` --- .../Json/Converters/GuidConverter.cs | 20 -- .../Json/Converters/JsonGuidConverter.cs | 20 ++ .../Json/Converters/JsonInt32Converter.cs | 40 +++ MediaBrowser.Common/Json/JsonDefaults.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs | 30 +- .../Probing/FFProbeHelpers.cs | 21 +- .../Probing/InternalMediaInfoResult.cs | 325 +-------------------- MediaBrowser.MediaEncoding/Probing/MediaChapter.cs | 32 ++ .../Probing/MediaFormatInfo.cs | 81 +++++ .../Probing/MediaStreamInfo.cs | 282 ++++++++++++++++++ .../Probing/ProbeResultNormalizer.cs | 181 ++++++------ 11 files changed, 579 insertions(+), 455 deletions(-) delete mode 100644 MediaBrowser.Common/Json/Converters/GuidConverter.cs create mode 100644 MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs create mode 100644 MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs create mode 100644 MediaBrowser.MediaEncoding/Probing/MediaChapter.cs create mode 100644 MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs create mode 100644 MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs diff --git a/MediaBrowser.Common/Json/Converters/GuidConverter.cs b/MediaBrowser.Common/Json/Converters/GuidConverter.cs deleted file mode 100644 index 3081e12ee..000000000 --- a/MediaBrowser.Common/Json/Converters/GuidConverter.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System; -using System.Text.Json; -using System.Text.Json.Serialization; - -namespace MediaBrowser.Common.Json.Converters -{ - /// - /// Converts a GUID object or value to/from JSON. - /// - public class GuidConverter : JsonConverter - { - /// - public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) - => new Guid(reader.GetString()); - - /// - public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) - => writer.WriteStringValue(value); - } -} diff --git a/MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs b/MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs new file mode 100644 index 000000000..d35a761f3 --- /dev/null +++ b/MediaBrowser.Common/Json/Converters/JsonGuidConverter.cs @@ -0,0 +1,20 @@ +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Common.Json.Converters +{ + /// + /// Converts a GUID object or value to/from JSON. + /// + public class JsonGuidConverter : JsonConverter + { + /// + public override Guid Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + => new Guid(reader.GetString()); + + /// + public override void Write(Utf8JsonWriter writer, Guid value, JsonSerializerOptions options) + => writer.WriteStringValue(value); + } +} diff --git a/MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs b/MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs new file mode 100644 index 000000000..0fd68babe --- /dev/null +++ b/MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs @@ -0,0 +1,40 @@ +using System; +using System.Buffers; +using System.Buffers.Text; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace MediaBrowser.Common.Json.Converters +{ + /// + /// Converts a GUID object or value to/from JSON. + /// + public class JsonInt32Converter : JsonConverter + { + /// + public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + static void ThrowFormatException() => throw new FormatException("Invalid format for an integer."); + ReadOnlySpan span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; + if (!Utf8Parser.TryParse(span, out int number, out _)) + { + ThrowFormatException(); + } + + return number; + } + + /// + public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) + { + static void ThrowInvalidOperationException() => throw new InvalidOperationException(); + Span span = new byte[16]; + if (Utf8Formatter.TryFormat(value, span, out int bytesWritten)) + { + writer.WriteStringValue(span.Slice(0, bytesWritten)); + } + + ThrowInvalidOperationException(); + } + } +} diff --git a/MediaBrowser.Common/Json/JsonDefaults.cs b/MediaBrowser.Common/Json/JsonDefaults.cs index 4ba0d5a1a..4a6ee0a79 100644 --- a/MediaBrowser.Common/Json/JsonDefaults.cs +++ b/MediaBrowser.Common/Json/JsonDefaults.cs @@ -21,7 +21,7 @@ namespace MediaBrowser.Common.Json WriteIndented = false }; - options.Converters.Add(new GuidConverter()); + options.Converters.Add(new JsonGuidConverter()); options.Converters.Add(new JsonStringEnumConverter()); return options; diff --git a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs index 6bcd6cd46..e0f7b992c 100644 --- a/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs +++ b/MediaBrowser.MediaEncoding/Encoder/MediaEncoder.cs @@ -397,7 +397,8 @@ namespace MediaBrowser.MediaEncoding.Encoder try { result = await JsonSerializer.DeserializeAsync( - process.StandardOutput.BaseStream).ConfigureAwait(false); + process.StandardOutput.BaseStream, + cancellationToken: cancellationToken).ConfigureAwait(false); } catch { @@ -406,24 +407,24 @@ namespace MediaBrowser.MediaEncoding.Encoder throw; } - if (result == null || (result.streams == null && result.format == null)) + if (result == null || (result.Streams == null && result.Format == null)) { throw new Exception("ffprobe failed - streams and format are both null."); } - if (result.streams != null) + if (result.Streams != null) { // Normalize aspect ratio if invalid - foreach (var stream in result.streams) + foreach (var stream in result.Streams) { - if (string.Equals(stream.display_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(stream.DisplayAspectRatio, "0:1", StringComparison.OrdinalIgnoreCase)) { - stream.display_aspect_ratio = string.Empty; + stream.DisplayAspectRatio = string.Empty; } - if (string.Equals(stream.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(stream.SampleAspectRatio, "0:1", StringComparison.OrdinalIgnoreCase)) { - stream.sample_aspect_ratio = string.Empty; + stream.SampleAspectRatio = string.Empty; } } } @@ -778,6 +779,7 @@ namespace MediaBrowser.MediaEncoding.Encoder _runningProcesses.Add(process); } } + private void StopProcess(ProcessWrapper process, int waitTimeMs) { try @@ -786,18 +788,16 @@ namespace MediaBrowser.MediaEncoding.Encoder { return; } - } - catch (Exception ex) - { - _logger.LogError(ex, "Error in WaitForExit"); - } - try - { _logger.LogInformation("Killing ffmpeg process"); process.Process.Kill(); } + catch (InvalidOperationException) + { + // The process has already exited or + // there is no process associated with this Process object. + } catch (Exception ex) { _logger.LogError(ex, "Error killing process"); diff --git a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs index e4eabaf38..cd3d82e86 100644 --- a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs +++ b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs @@ -16,24 +16,19 @@ namespace MediaBrowser.MediaEncoding.Probing throw new ArgumentNullException(nameof(result)); } - if (result.format != null && result.format.tags != null) + if (result.Format != null && result.Format.Tags != null) { - result.format.tags = ConvertDictionaryToCaseInSensitive(result.format.tags); + result.Format.Tags = ConvertDictionaryToCaseInSensitive(result.Format.Tags); } - if (result.streams != null) + if (result.Streams != null) { // Convert all dictionaries to case insensitive - foreach (var stream in result.streams) + foreach (var stream in result.Streams) { - if (stream.tags != null) + if (stream.Tags != null) { - stream.tags = ConvertDictionaryToCaseInSensitive(stream.tags); - } - - if (stream.disposition != null) - { - stream.disposition = ConvertDictionaryToCaseInSensitive(stream.disposition); + stream.Tags = ConvertDictionaryToCaseInSensitive(stream.Tags); } } } @@ -45,7 +40,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// The tags. /// The key. /// System.String. - public static string GetDictionaryValue(Dictionary tags, string key) + public static string GetDictionaryValue(IReadOnlyDictionary tags, string key) { if (tags == null) { @@ -103,7 +98,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// /// The dict. /// Dictionary{System.StringSystem.String}. - private static Dictionary ConvertDictionaryToCaseInSensitive(Dictionary dict) + private static Dictionary ConvertDictionaryToCaseInSensitive(IReadOnlyDictionary dict) { return new Dictionary(dict, StringComparer.OrdinalIgnoreCase); } diff --git a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs index cc9d27608..0e319c1a8 100644 --- a/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs +++ b/MediaBrowser.MediaEncoding/Probing/InternalMediaInfoResult.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; +using System.Text.Json.Serialization; namespace MediaBrowser.MediaEncoding.Probing { /// - /// Class MediaInfoResult + /// Class MediaInfoResult. /// public class InternalMediaInfoResult { @@ -11,331 +12,21 @@ namespace MediaBrowser.MediaEncoding.Probing /// Gets or sets the streams. /// /// The streams. - public MediaStreamInfo[] streams { get; set; } + [JsonPropertyName("streams")] + public IReadOnlyList Streams { get; set; } /// /// Gets or sets the format. /// /// The format. - public MediaFormatInfo format { get; set; } + [JsonPropertyName("format")] + public MediaFormatInfo Format { get; set; } /// /// Gets or sets the chapters. /// /// The chapters. - public MediaChapter[] Chapters { get; set; } - } - - public class MediaChapter - { - public int id { get; set; } - public string time_base { get; set; } - public long start { get; set; } - public string start_time { get; set; } - public long end { get; set; } - public string end_time { get; set; } - public Dictionary tags { get; set; } - } - - /// - /// Represents a stream within the output - /// - public class MediaStreamInfo - { - /// - /// Gets or sets the index. - /// - /// The index. - public int index { get; set; } - - /// - /// Gets or sets the profile. - /// - /// The profile. - public string profile { get; set; } - - /// - /// Gets or sets the codec_name. - /// - /// The codec_name. - public string codec_name { get; set; } - - /// - /// Gets or sets the codec_long_name. - /// - /// The codec_long_name. - public string codec_long_name { get; set; } - - /// - /// Gets or sets the codec_type. - /// - /// The codec_type. - public string codec_type { get; set; } - - /// - /// Gets or sets the sample_rate. - /// - /// The sample_rate. - public string sample_rate { get; set; } - - /// - /// Gets or sets the channels. - /// - /// The channels. - public int channels { get; set; } - - /// - /// Gets or sets the channel_layout. - /// - /// The channel_layout. - public string channel_layout { get; set; } - - /// - /// Gets or sets the avg_frame_rate. - /// - /// The avg_frame_rate. - public string avg_frame_rate { get; set; } - - /// - /// Gets or sets the duration. - /// - /// The duration. - public string duration { get; set; } - - /// - /// Gets or sets the bit_rate. - /// - /// The bit_rate. - public string bit_rate { get; set; } - - /// - /// Gets or sets the width. - /// - /// The width. - public int width { get; set; } - - /// - /// Gets or sets the refs. - /// - /// The refs. - public int refs { get; set; } - - /// - /// Gets or sets the height. - /// - /// The height. - public int height { get; set; } - - /// - /// Gets or sets the display_aspect_ratio. - /// - /// The display_aspect_ratio. - public string display_aspect_ratio { get; set; } - - /// - /// Gets or sets the tags. - /// - /// The tags. - public Dictionary tags { get; set; } - - /// - /// Gets or sets the bits_per_sample. - /// - /// The bits_per_sample. - public int bits_per_sample { get; set; } - - /// - /// Gets or sets the bits_per_raw_sample. - /// - /// The bits_per_raw_sample. - public int bits_per_raw_sample { get; set; } - - /// - /// Gets or sets the r_frame_rate. - /// - /// The r_frame_rate. - public string r_frame_rate { get; set; } - - /// - /// Gets or sets the has_b_frames. - /// - /// The has_b_frames. - public int has_b_frames { get; set; } - - /// - /// Gets or sets the sample_aspect_ratio. - /// - /// The sample_aspect_ratio. - public string sample_aspect_ratio { get; set; } - - /// - /// Gets or sets the pix_fmt. - /// - /// The pix_fmt. - public string pix_fmt { get; set; } - - /// - /// Gets or sets the level. - /// - /// The level. - public int level { get; set; } - - /// - /// Gets or sets the time_base. - /// - /// The time_base. - public string time_base { get; set; } - - /// - /// Gets or sets the start_time. - /// - /// The start_time. - public string start_time { get; set; } - - /// - /// Gets or sets the codec_time_base. - /// - /// The codec_time_base. - public string codec_time_base { get; set; } - - /// - /// Gets or sets the codec_tag. - /// - /// The codec_tag. - public string codec_tag { get; set; } - - /// - /// Gets or sets the codec_tag_string. - /// - /// The codec_tag_string. - public string codec_tag_string { get; set; } - - /// - /// Gets or sets the sample_fmt. - /// - /// The sample_fmt. - public string sample_fmt { get; set; } - - /// - /// Gets or sets the dmix_mode. - /// - /// The dmix_mode. - public string dmix_mode { get; set; } - - /// - /// Gets or sets the start_pts. - /// - /// The start_pts. - public string start_pts { get; set; } - - /// - /// Gets or sets the is_avc. - /// - /// The is_avc. - public string is_avc { get; set; } - - /// - /// Gets or sets the nal_length_size. - /// - /// The nal_length_size. - public string nal_length_size { get; set; } - - /// - /// Gets or sets the ltrt_cmixlev. - /// - /// The ltrt_cmixlev. - public string ltrt_cmixlev { get; set; } - - /// - /// Gets or sets the ltrt_surmixlev. - /// - /// The ltrt_surmixlev. - public string ltrt_surmixlev { get; set; } - - /// - /// Gets or sets the loro_cmixlev. - /// - /// The loro_cmixlev. - public string loro_cmixlev { get; set; } - - /// - /// Gets or sets the loro_surmixlev. - /// - /// The loro_surmixlev. - public string loro_surmixlev { get; set; } - - public string field_order { get; set; } - - /// - /// Gets or sets the disposition. - /// - /// The disposition. - public Dictionary disposition { get; set; } - } - - /// - /// Class MediaFormat - /// - public class MediaFormatInfo - { - /// - /// Gets or sets the filename. - /// - /// The filename. - public string filename { get; set; } - - /// - /// Gets or sets the nb_streams. - /// - /// The nb_streams. - public int nb_streams { get; set; } - - /// - /// Gets or sets the format_name. - /// - /// The format_name. - public string format_name { get; set; } - - /// - /// Gets or sets the format_long_name. - /// - /// The format_long_name. - public string format_long_name { get; set; } - - /// - /// Gets or sets the start_time. - /// - /// The start_time. - public string start_time { get; set; } - - /// - /// Gets or sets the duration. - /// - /// The duration. - public string duration { get; set; } - - /// - /// Gets or sets the size. - /// - /// The size. - public string size { get; set; } - - /// - /// Gets or sets the bit_rate. - /// - /// The bit_rate. - public string bit_rate { get; set; } - - /// - /// Gets or sets the probe_score. - /// - /// The probe_score. - public int probe_score { get; set; } - - /// - /// Gets or sets the tags. - /// - /// The tags. - public Dictionary tags { get; set; } + [JsonPropertyName("chapters")] + public IReadOnlyList Chapters { get; set; } } } diff --git a/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs new file mode 100644 index 000000000..a3607a760 --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs @@ -0,0 +1,32 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// + /// Class MediaChapter. + /// + public class MediaChapter + { + [JsonPropertyName("id")] + public int id { get; set; } + + [JsonPropertyName("time_base")] + public string TimeBase { get; set; } + + [JsonPropertyName("start")] + public long Start { get; set; } + + [JsonPropertyName("start_time")] + public string StartTime { get; set; } + + [JsonPropertyName("end")] + public long End { get; set; } + + [JsonPropertyName("end_time")] + public string EndTime { get; set; } + + [JsonPropertyName("tags")] + public IReadOnlyDictionary Tags { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs new file mode 100644 index 000000000..d5529e56c --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// + /// Class MediaFormat. + /// + public class MediaFormatInfo + { + /// + /// Gets or sets the filename. + /// + /// The filename. + [JsonPropertyName("filename")] + public string Fileame { get; set; } + + /// + /// Gets or sets the nb_streams. + /// + /// The nb_streams. + [JsonPropertyName("nb_streams")] + public int NbStreams { get; set; } + + /// + /// Gets or sets the format_name. + /// + /// The format_name. + [JsonPropertyName("format_name")] + public string FormatName { get; set; } + + /// + /// Gets or sets the format_long_name. + /// + /// The format_long_name. + [JsonPropertyName("format_long_name")] + public string FormatLongName { get; set; } + + /// + /// Gets or sets the start_time. + /// + /// The start_time. + [JsonPropertyName("start_time")] + public string StartTime { get; set; } + + /// + /// Gets or sets the duration. + /// + /// The duration. + [JsonPropertyName("duration")] + public string Duration { get; set; } + + /// + /// Gets or sets the size. + /// + /// The size. + [JsonPropertyName("size")] + public string Size { get; set; } + + /// + /// Gets or sets the bit_rate. + /// + /// The bit_rate. + [JsonPropertyName("bit_rate")] + public string BitRate { get; set; } + + /// + /// Gets or sets the probe_score. + /// + /// The probe_score. + [JsonPropertyName("probe_score")] + public int ProbeScore { get; set; } + + /// + /// Gets or sets the tags. + /// + /// The tags. + [JsonPropertyName("tags")] + public IReadOnlyDictionary Tags { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs new file mode 100644 index 000000000..7fa7afa5b --- /dev/null +++ b/MediaBrowser.MediaEncoding/Probing/MediaStreamInfo.cs @@ -0,0 +1,282 @@ +using System.Collections.Generic; +using System.Text.Json.Serialization; +using MediaBrowser.Common.Json.Converters; + +namespace MediaBrowser.MediaEncoding.Probing +{ + /// + /// Represents a stream within the output. + /// + public class MediaStreamInfo + { + /// + /// Gets or sets the index. + /// + /// The index. + [JsonPropertyName("index")] + public int Index { get; set; } + + /// + /// Gets or sets the profile. + /// + /// The profile. + [JsonPropertyName("profile")] + public string Profile { get; set; } + + /// + /// Gets or sets the codec_name. + /// + /// The codec_name. + [JsonPropertyName("codec_name")] + public string CodecName { get; set; } + + /// + /// Gets or sets the codec_long_name. + /// + /// The codec_long_name. + [JsonPropertyName("codec_long_name")] + public string CodecLongName { get; set; } + + /// + /// Gets or sets the codec_type. + /// + /// The codec_type. + [JsonPropertyName("codec_type")] + public string CodecType { get; set; } + + /// + /// Gets or sets the sample_rate. + /// + /// The sample_rate. + [JsonPropertyName("sample_rate")] + public string SampleRate { get; set; } + + /// + /// Gets or sets the channels. + /// + /// The channels. + [JsonPropertyName("channels")] + public int Channels { get; set; } + + /// + /// Gets or sets the channel_layout. + /// + /// The channel_layout. + [JsonPropertyName("channel_layout")] + public string ChannelLayout { get; set; } + + /// + /// Gets or sets the avg_frame_rate. + /// + /// The avg_frame_rate. + [JsonPropertyName("avg_frame_rate")] + public string AverageFrameRate { get; set; } + + /// + /// Gets or sets the duration. + /// + /// The duration. + [JsonPropertyName("duration")] + public string Duration { get; set; } + + /// + /// Gets or sets the bit_rate. + /// + /// The bit_rate. + [JsonPropertyName("bit_rate")] + public string BitRate { get; set; } + + /// + /// Gets or sets the width. + /// + /// The width. + [JsonPropertyName("width")] + public int Width { get; set; } + + /// + /// Gets or sets the refs. + /// + /// The refs. + [JsonPropertyName("refs")] + public int Refs { get; set; } + + /// + /// Gets or sets the height. + /// + /// The height. + [JsonPropertyName("height")] + public int Height { get; set; } + + /// + /// Gets or sets the display_aspect_ratio. + /// + /// The display_aspect_ratio. + [JsonPropertyName("display_aspect_ratio")] + public string DisplayAspectRatio { get; set; } + + /// + /// Gets or sets the tags. + /// + /// The tags. + [JsonPropertyName("tags")] + public IReadOnlyDictionary Tags { get; set; } + + /// + /// Gets or sets the bits_per_sample. + /// + /// The bits_per_sample. + [JsonPropertyName("bits_per_sample")] + public int BitsPerSample { get; set; } + + /// + /// Gets or sets the bits_per_raw_sample. + /// + /// The bits_per_raw_sample. + [JsonPropertyName("bits_per_raw_sample")] + [JsonConverter(typeof(JsonInt32Converter))] + public int BitsPerRawSample { get; set; } + + /// + /// Gets or sets the r_frame_rate. + /// + /// The r_frame_rate. + [JsonPropertyName("r_frame_rate")] + public string RFrameRate { get; set; } + + /// + /// Gets or sets the has_b_frames. + /// + /// The has_b_frames. + [JsonPropertyName("has_b_frames")] + public int HasBFrames { get; set; } + + /// + /// Gets or sets the sample_aspect_ratio. + /// + /// The sample_aspect_ratio. + [JsonPropertyName("sample_aspect_ratio")] + public string SampleAspectRatio { get; set; } + + /// + /// Gets or sets the pix_fmt. + /// + /// The pix_fmt. + [JsonPropertyName("pix_fmt")] + public string PixelFormat { get; set; } + + /// + /// Gets or sets the level. + /// + /// The level. + [JsonPropertyName("level")] + public int Level { get; set; } + + /// + /// Gets or sets the time_base. + /// + /// The time_base. + [JsonPropertyName("time_base")] + public string TimeBase { get; set; } + + /// + /// Gets or sets the start_time. + /// + /// The start_time. + [JsonPropertyName("start_time")] + public string StartTime { get; set; } + + /// + /// Gets or sets the codec_time_base. + /// + /// The codec_time_base. + [JsonPropertyName("codec_time_base")] + public string CodecTimeBase { get; set; } + + /// + /// Gets or sets the codec_tag. + /// + /// The codec_tag. + [JsonPropertyName("codec_tag")] + public string CodecTag { get; set; } + + /// + /// Gets or sets the codec_tag_string. + /// + /// The codec_tag_string. + [JsonPropertyName("codec_tag_string")] + public string CodecTagString { get; set; } + + /// + /// Gets or sets the sample_fmt. + /// + /// The sample_fmt. + [JsonPropertyName("sample_fmt")] + public string SampleFmt { get; set; } + + /// + /// Gets or sets the dmix_mode. + /// + /// The dmix_mode. + [JsonPropertyName("dmix_mode")] + public string DmixMode { get; set; } + + /// + /// Gets or sets the start_pts. + /// + /// The start_pts. + [JsonPropertyName("start_pts")] + public int StartPts { get; set; } + + /// + /// Gets or sets the is_avc. + /// + /// The is_avc. + [JsonPropertyName("is_avc")] + public string IsAvc { get; set; } + + /// + /// Gets or sets the nal_length_size. + /// + /// The nal_length_size. + [JsonPropertyName("nal_length_size")] + public string NalLengthSize { get; set; } + + /// + /// Gets or sets the ltrt_cmixlev. + /// + /// The ltrt_cmixlev. + [JsonPropertyName("ltrt_cmixlev")] + public string LtrtCmixlev { get; set; } + + /// + /// Gets or sets the ltrt_surmixlev. + /// + /// The ltrt_surmixlev. + [JsonPropertyName("ltrt_surmixlev")] + public string LtrtSurmixlev { get; set; } + + /// + /// Gets or sets the loro_cmixlev. + /// + /// The loro_cmixlev. + [JsonPropertyName("loro_cmixlev")] + public string LoroCmixlev { get; set; } + + /// + /// Gets or sets the loro_surmixlev. + /// + /// The loro_surmixlev. + [JsonPropertyName("loro_surmixlev")] + public string LoroSurmixlev { get; set; } + + [JsonPropertyName("field_order")] + public string FieldOrder { get; set; } + + /// + /// Gets or sets the disposition. + /// + /// The disposition. + [JsonPropertyName("disposition")] + public IReadOnlyDictionary Disposition { get; set; } + } +} diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 54d02fc9f..99f0df60f 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -8,7 +8,6 @@ using System.Xml; using MediaBrowser.Controller.Library; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.Extensions; using MediaBrowser.Model.Globalization; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; @@ -41,21 +40,21 @@ namespace MediaBrowser.MediaEncoding.Probing FFProbeHelpers.NormalizeFFProbeResult(data); SetSize(data, info); - var internalStreams = data.streams ?? new MediaStreamInfo[] { }; + var internalStreams = data.Streams ?? new MediaStreamInfo[] { }; - info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.format)) + info.MediaStreams = internalStreams.Select(s => GetMediaStream(isAudio, s, data.Format)) .Where(i => i != null) // Drop subtitle streams if we don't know the codec because it will just cause failures if we don't know how to handle them .Where(i => i.Type != MediaStreamType.Subtitle || !string.IsNullOrWhiteSpace(i.Codec)) .ToList(); - if (data.format != null) + if (data.Format != null) { - info.Container = NormalizeFormat(data.format.format_name); + info.Container = NormalizeFormat(data.Format.FormatName); - if (!string.IsNullOrEmpty(data.format.bit_rate)) + if (!string.IsNullOrEmpty(data.Format.BitRate)) { - if (int.TryParse(data.format.bit_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(data.Format.BitRate, NumberStyles.Any, _usCulture, out var value)) { info.Bitrate = value; } @@ -65,22 +64,22 @@ namespace MediaBrowser.MediaEncoding.Probing var tags = new Dictionary(StringComparer.OrdinalIgnoreCase); var tagStreamType = isAudio ? "audio" : "video"; - if (data.streams != null) + if (data.Streams != null) { - var tagStream = data.streams.FirstOrDefault(i => string.Equals(i.codec_type, tagStreamType, StringComparison.OrdinalIgnoreCase)); + var tagStream = data.Streams.FirstOrDefault(i => string.Equals(i.CodecType, tagStreamType, StringComparison.OrdinalIgnoreCase)); - if (tagStream != null && tagStream.tags != null) + if (tagStream != null && tagStream.Tags != null) { - foreach (var pair in tagStream.tags) + foreach (var pair in tagStream.Tags) { tags[pair.Key] = pair.Value; } } } - if (data.format != null && data.format.tags != null) + if (data.Format != null && data.Format.Tags != null) { - foreach (var pair in data.format.tags) + foreach (var pair in data.Format.Tags) { tags[pair.Key] = pair.Value; } @@ -153,9 +152,9 @@ namespace MediaBrowser.MediaEncoding.Probing FetchFromItunesInfo(itunesXml, info); } - if (data.format != null && !string.IsNullOrEmpty(data.format.duration)) + if (data.Format != null && !string.IsNullOrEmpty(data.Format.Duration)) { - info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.format.duration, _usCulture)).Ticks; + info.RunTimeTicks = TimeSpan.FromSeconds(double.Parse(data.Format.Duration, _usCulture)).Ticks; } FetchWtvInfo(info, data); @@ -523,7 +522,7 @@ namespace MediaBrowser.MediaEncoding.Probing private MediaStream GetMediaStream(bool isAudio, MediaStreamInfo streamInfo, MediaFormatInfo formatInfo) { // These are mp4 chapters - if (string.Equals(streamInfo.codec_name, "mov_text", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.CodecName, "mov_text", StringComparison.OrdinalIgnoreCase)) { // Edit: but these are also sometimes subtitles? //return null; @@ -531,71 +530,71 @@ namespace MediaBrowser.MediaEncoding.Probing var stream = new MediaStream { - Codec = streamInfo.codec_name, - Profile = streamInfo.profile, - Level = streamInfo.level, - Index = streamInfo.index, - PixelFormat = streamInfo.pix_fmt, - NalLengthSize = streamInfo.nal_length_size, - TimeBase = streamInfo.time_base, - CodecTimeBase = streamInfo.codec_time_base + Codec = streamInfo.CodecName, + Profile = streamInfo.Profile, + Level = streamInfo.Level, + Index = streamInfo.Index, + PixelFormat = streamInfo.PixelFormat, + NalLengthSize = streamInfo.NalLengthSize, + TimeBase = streamInfo.TimeBase, + CodecTimeBase = streamInfo.CodecTimeBase }; - if (string.Equals(streamInfo.is_avc, "true", StringComparison.OrdinalIgnoreCase) || - string.Equals(streamInfo.is_avc, "1", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.IsAvc, "true", StringComparison.OrdinalIgnoreCase) || + string.Equals(streamInfo.IsAvc, "1", StringComparison.OrdinalIgnoreCase)) { stream.IsAVC = true; } - else if (string.Equals(streamInfo.is_avc, "false", StringComparison.OrdinalIgnoreCase) || - string.Equals(streamInfo.is_avc, "0", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(streamInfo.IsAvc, "false", StringComparison.OrdinalIgnoreCase) || + string.Equals(streamInfo.IsAvc, "0", StringComparison.OrdinalIgnoreCase)) { stream.IsAVC = false; } - if (!string.IsNullOrWhiteSpace(streamInfo.field_order) && !string.Equals(streamInfo.field_order, "progressive", StringComparison.OrdinalIgnoreCase)) + if (!string.IsNullOrWhiteSpace(streamInfo.FieldOrder) && !string.Equals(streamInfo.FieldOrder, "progressive", StringComparison.OrdinalIgnoreCase)) { stream.IsInterlaced = true; } // Filter out junk - if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string) && streamInfo.codec_tag_string.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) + if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString) && streamInfo.CodecTagString.IndexOf("[0]", StringComparison.OrdinalIgnoreCase) == -1) { - stream.CodecTag = streamInfo.codec_tag_string; + stream.CodecTag = streamInfo.CodecTagString; } - if (streamInfo.tags != null) + if (streamInfo.Tags != null) { - stream.Language = GetDictionaryValue(streamInfo.tags, "language"); - stream.Comment = GetDictionaryValue(streamInfo.tags, "comment"); - stream.Title = GetDictionaryValue(streamInfo.tags, "title"); + stream.Language = GetDictionaryValue(streamInfo.Tags, "language"); + stream.Comment = GetDictionaryValue(streamInfo.Tags, "comment"); + stream.Title = GetDictionaryValue(streamInfo.Tags, "title"); } - if (string.Equals(streamInfo.codec_type, "audio", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(streamInfo.CodecType, "audio", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Audio; - stream.Channels = streamInfo.channels; + stream.Channels = streamInfo.Channels; - if (!string.IsNullOrEmpty(streamInfo.sample_rate)) + if (!string.IsNullOrEmpty(streamInfo.SampleRate)) { - if (int.TryParse(streamInfo.sample_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.SampleRate, NumberStyles.Any, _usCulture, out var value)) { stream.SampleRate = value; } } - stream.ChannelLayout = ParseChannelLayout(streamInfo.channel_layout); + stream.ChannelLayout = ParseChannelLayout(streamInfo.ChannelLayout); - if (streamInfo.bits_per_sample > 0) + if (streamInfo.BitsPerSample > 0) { - stream.BitDepth = streamInfo.bits_per_sample; + stream.BitDepth = streamInfo.BitsPerSample; } - else if (streamInfo.bits_per_raw_sample > 0) + else if (streamInfo.BitsPerRawSample > 0) { - stream.BitDepth = streamInfo.bits_per_raw_sample; + stream.BitDepth = streamInfo.BitsPerRawSample; } } - else if (string.Equals(streamInfo.codec_type, "subtitle", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(streamInfo.CodecType, "subtitle", StringComparison.OrdinalIgnoreCase)) { stream.Type = MediaStreamType.Subtitle; stream.Codec = NormalizeSubtitleCodec(stream.Codec); @@ -603,14 +602,14 @@ namespace MediaBrowser.MediaEncoding.Probing stream.localizedDefault = _localization.GetLocalizedString("Default"); stream.localizedForced = _localization.GetLocalizedString("Forced"); } - else if (string.Equals(streamInfo.codec_type, "video", StringComparison.OrdinalIgnoreCase)) + else if (string.Equals(streamInfo.CodecType, "video", StringComparison.OrdinalIgnoreCase)) { stream.Type = isAudio || string.Equals(stream.Codec, "mjpeg", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase) ? MediaStreamType.EmbeddedImage : MediaStreamType.Video; - stream.AverageFrameRate = GetFrameRate(streamInfo.avg_frame_rate); - stream.RealFrameRate = GetFrameRate(streamInfo.r_frame_rate); + stream.AverageFrameRate = GetFrameRate(streamInfo.AverageFrameRate); + stream.RealFrameRate = GetFrameRate(streamInfo.RFrameRate); if (isAudio || string.Equals(stream.Codec, "gif", StringComparison.OrdinalIgnoreCase) || string.Equals(stream.Codec, "png", StringComparison.OrdinalIgnoreCase)) @@ -635,17 +634,17 @@ namespace MediaBrowser.MediaEncoding.Probing stream.Type = MediaStreamType.Video; } - stream.Width = streamInfo.width; - stream.Height = streamInfo.height; + stream.Width = streamInfo.Width; + stream.Height = streamInfo.Height; stream.AspectRatio = GetAspectRatio(streamInfo); - if (streamInfo.bits_per_sample > 0) + if (streamInfo.BitsPerSample > 0) { - stream.BitDepth = streamInfo.bits_per_sample; + stream.BitDepth = streamInfo.BitsPerSample; } - else if (streamInfo.bits_per_raw_sample > 0) + else if (streamInfo.BitsPerRawSample > 0) { - stream.BitDepth = streamInfo.bits_per_raw_sample; + stream.BitDepth = streamInfo.BitsPerRawSample; } //stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase) || @@ -653,11 +652,11 @@ namespace MediaBrowser.MediaEncoding.Probing // string.Equals(stream.AspectRatio, "2.40:1", StringComparison.OrdinalIgnoreCase); // http://stackoverflow.com/questions/17353387/how-to-detect-anamorphic-video-with-ffprobe - stream.IsAnamorphic = string.Equals(streamInfo.sample_aspect_ratio, "0:1", StringComparison.OrdinalIgnoreCase); + stream.IsAnamorphic = string.Equals(streamInfo.SampleAspectRatio, "0:1", StringComparison.OrdinalIgnoreCase); - if (streamInfo.refs > 0) + if (streamInfo.Refs > 0) { - stream.RefFrames = streamInfo.refs; + stream.RefFrames = streamInfo.Refs; } } else @@ -668,18 +667,18 @@ namespace MediaBrowser.MediaEncoding.Probing // Get stream bitrate var bitrate = 0; - if (!string.IsNullOrEmpty(streamInfo.bit_rate)) + if (!string.IsNullOrEmpty(streamInfo.BitRate)) { - if (int.TryParse(streamInfo.bit_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(streamInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) { bitrate = value; } } - if (bitrate == 0 && formatInfo != null && !string.IsNullOrEmpty(formatInfo.bit_rate) && stream.Type == MediaStreamType.Video) + if (bitrate == 0 && formatInfo != null && !string.IsNullOrEmpty(formatInfo.BitRate) && stream.Type == MediaStreamType.Video) { // If the stream info doesn't have a bitrate get the value from the media format info - if (int.TryParse(formatInfo.bit_rate, NumberStyles.Any, _usCulture, out var value)) + if (int.TryParse(formatInfo.BitRate, NumberStyles.Any, _usCulture, out var value)) { bitrate = value; } @@ -690,14 +689,18 @@ namespace MediaBrowser.MediaEncoding.Probing stream.BitRate = bitrate; } - if (streamInfo.disposition != null) + var disposition = streamInfo.Disposition; + if (disposition != null) { - var isDefault = GetDictionaryValue(streamInfo.disposition, "default"); - var isForced = GetDictionaryValue(streamInfo.disposition, "forced"); - - stream.IsDefault = string.Equals(isDefault, "1", StringComparison.OrdinalIgnoreCase); + if (disposition.GetValueOrDefault("default") == 1) + { + stream.IsDefault = true; + } - stream.IsForced = string.Equals(isForced, "1", StringComparison.OrdinalIgnoreCase); + if (disposition.GetValueOrDefault("forced") == 1) + { + stream.IsForced = true; + } } NormalizeStreamTitle(stream); @@ -724,7 +727,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// The tags. /// The key. /// System.String. - private string GetDictionaryValue(Dictionary tags, string key) + private string GetDictionaryValue(IReadOnlyDictionary tags, string key) { if (tags == null) { @@ -747,7 +750,7 @@ namespace MediaBrowser.MediaEncoding.Probing private string GetAspectRatio(MediaStreamInfo info) { - var original = info.display_aspect_ratio; + var original = info.DisplayAspectRatio; var parts = (original ?? string.Empty).Split(':'); if (!(parts.Length == 2 && @@ -756,8 +759,8 @@ namespace MediaBrowser.MediaEncoding.Probing width > 0 && height > 0)) { - width = info.width; - height = info.height; + width = info.Width; + height = info.Height; } if (width > 0 && height > 0) @@ -850,20 +853,20 @@ namespace MediaBrowser.MediaEncoding.Probing private void SetAudioRuntimeTicks(InternalMediaInfoResult result, MediaInfo data) { - if (result.streams != null) + if (result.Streams != null) { // Get the first info stream - var stream = result.streams.FirstOrDefault(s => string.Equals(s.codec_type, "audio", StringComparison.OrdinalIgnoreCase)); + var stream = result.Streams.FirstOrDefault(s => string.Equals(s.CodecType, "audio", StringComparison.OrdinalIgnoreCase)); if (stream != null) { // Get duration from stream properties - var duration = stream.duration; + var duration = stream.Duration; // If it's not there go into format properties if (string.IsNullOrEmpty(duration)) { - duration = result.format.duration; + duration = result.Format.Duration; } // If we got something, parse it @@ -877,11 +880,11 @@ namespace MediaBrowser.MediaEncoding.Probing private void SetSize(InternalMediaInfoResult data, MediaInfo info) { - if (data.format != null) + if (data.Format != null) { - if (!string.IsNullOrEmpty(data.format.size)) + if (!string.IsNullOrEmpty(data.Format.Size)) { - info.Size = long.Parse(data.format.size, _usCulture); + info.Size = long.Parse(data.Format.Size, _usCulture); } else { @@ -1194,16 +1197,16 @@ namespace MediaBrowser.MediaEncoding.Probing { var info = new ChapterInfo(); - if (chapter.tags != null) + if (chapter.Tags != null) { - if (chapter.tags.TryGetValue("title", out string name)) + if (chapter.Tags.TryGetValue("title", out string name)) { info.Name = name; } } // Limit accuracy to milliseconds to match xml saving - var secondsString = chapter.start_time; + var secondsString = chapter.StartTime; if (double.TryParse(secondsString, NumberStyles.Any, CultureInfo.InvariantCulture, out var seconds)) { @@ -1218,12 +1221,12 @@ namespace MediaBrowser.MediaEncoding.Probing private void FetchWtvInfo(MediaInfo video, InternalMediaInfoResult data) { - if (data.format == null || data.format.tags == null) + if (data.Format == null || data.Format.Tags == null) { return; } - var genres = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/Genre"); + var genres = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/Genre"); if (!string.IsNullOrWhiteSpace(genres)) { @@ -1239,14 +1242,14 @@ namespace MediaBrowser.MediaEncoding.Probing } } - var officialRating = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/ParentalRating"); + var officialRating = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/ParentalRating"); if (!string.IsNullOrWhiteSpace(officialRating)) { video.OfficialRating = officialRating; } - var people = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaCredits"); + var people = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/MediaCredits"); if (!string.IsNullOrEmpty(people)) { @@ -1256,7 +1259,7 @@ namespace MediaBrowser.MediaEncoding.Probing .ToArray(); } - var year = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/OriginalReleaseTime"); + var year = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/OriginalReleaseTime"); if (!string.IsNullOrWhiteSpace(year)) { if (int.TryParse(year, NumberStyles.Integer, _usCulture, out var val)) @@ -1265,7 +1268,7 @@ namespace MediaBrowser.MediaEncoding.Probing } } - var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/MediaOriginalBroadcastDateTime"); + var premiereDateString = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/MediaOriginalBroadcastDateTime"); if (!string.IsNullOrWhiteSpace(premiereDateString)) { // Credit to MCEBuddy: https://mcebuddy2x.codeplex.com/ @@ -1276,9 +1279,9 @@ namespace MediaBrowser.MediaEncoding.Probing } } - var description = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitleDescription"); + var description = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/SubTitleDescription"); - var subTitle = FFProbeHelpers.GetDictionaryValue(data.format.tags, "WM/SubTitle"); + var subTitle = FFProbeHelpers.GetDictionaryValue(data.Format.Tags, "WM/SubTitle"); // For below code, credit to MCEBuddy: https://mcebuddy2x.codeplex.com/ -- cgit v1.2.3 From f9a454628d7204bc30d64f9c0589d766ad5f3109 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 22 Dec 2019 22:21:41 +0100 Subject: Preformance!!! --- .../Json/Converters/JsonInt32Converter.cs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs b/MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs index 0fd68babe..fe5dd6cd4 100644 --- a/MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs +++ b/MediaBrowser.Common/Json/Converters/JsonInt32Converter.cs @@ -15,7 +15,20 @@ namespace MediaBrowser.Common.Json.Converters public override int Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) { static void ThrowFormatException() => throw new FormatException("Invalid format for an integer."); - ReadOnlySpan span = reader.HasValueSequence ? reader.ValueSequence.ToArray() : reader.ValueSpan; + ReadOnlySpan span = stackalloc byte[0]; + + if (reader.HasValueSequence) + { + long sequenceLength = reader.ValueSequence.Length; + Span stackSpan = stackalloc byte[(int)sequenceLength]; + reader.ValueSequence.CopyTo(stackSpan); + span = stackSpan; + } + else + { + span = reader.ValueSpan; + } + if (!Utf8Parser.TryParse(span, out int number, out _)) { ThrowFormatException(); @@ -28,7 +41,7 @@ namespace MediaBrowser.Common.Json.Converters public override void Write(Utf8JsonWriter writer, int value, JsonSerializerOptions options) { static void ThrowInvalidOperationException() => throw new InvalidOperationException(); - Span span = new byte[16]; + Span span = stackalloc byte[16]; if (Utf8Formatter.TryFormat(value, span, out int bytesWritten)) { writer.WriteStringValue(span.Slice(0, bytesWritten)); -- cgit v1.2.3 From a22f1dabb4a26e46c4843b9bd8946e03293b8adb Mon Sep 17 00:00:00 2001 From: arg2009 Date: Mon, 23 Dec 2019 09:13:46 +0000 Subject: Added translation using Weblate (Indonesian) --- Emby.Server.Implementations/Localization/Core/id.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/id.json diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/id.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From a41ec5c9d4642f28cc1a277f555fc6a4f2929b85 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Mon, 23 Dec 2019 15:29:30 +0100 Subject: Fix typo --- MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs index d5529e56c..6b60b66c0 100644 --- a/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs +++ b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// /// The filename. [JsonPropertyName("filename")] - public string Fileame { get; set; } + public string Filename { get; set; } /// /// Gets or sets the nb_streams. -- cgit v1.2.3 From ef62df69dfe08dc162bffb7507d095df43f95ab2 Mon Sep 17 00:00:00 2001 From: arg2009 Date: Mon, 23 Dec 2019 09:15:45 +0000 Subject: Translated using Weblate (Indonesian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/id/ --- .../Localization/Core/id.json | 33 +++++++++++++++++++++- 1 file changed, 32 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/id.json b/Emby.Server.Implementations/Localization/Core/id.json index 0967ef424..8d17ad38e 100644 --- a/Emby.Server.Implementations/Localization/Core/id.json +++ b/Emby.Server.Implementations/Localization/Core/id.json @@ -1 +1,32 @@ -{} +{ + "Albums": "Album", + "AuthenticationSucceededWithUserName": "{0} berhasil diautentikasi", + "AppDeviceValues": "Aplikasi: {0}, Alat: {1}", + "LabelRunningTimeValue": "Waktu berjalan: {0}", + "MessageApplicationUpdatedTo": "Jellyfin Server sudah diperbarui ke {0}", + "MessageApplicationUpdated": "Jellyfin Server sudah diperbarui", + "Latest": "Terbaru", + "LabelIpAddressValue": "IP address: {0}", + "ItemRemovedWithName": "{0} sudah dikeluarkan dari perpustakaan", + "ItemAddedWithName": "{0} sudah dimasukkan ke dalam perpustakaan", + "Inherit": "Warisan", + "HomeVideos": "Video Rumah", + "HeaderRecordingGroups": "Grup Rekaman", + "HeaderNextUp": "Selanjutnya", + "HeaderLiveTV": "TV Live", + "HeaderFavoriteSongs": "Lagu Favorit", + "HeaderFavoriteShows": "Tayangan Favorit", + "HeaderFavoriteEpisodes": "Episode Favorit", + "HeaderFavoriteArtists": "Artis Favorit", + "HeaderFavoriteAlbums": "Album Favorit", + "HeaderContinueWatching": "Masih Melihat", + "HeaderCameraUploads": "Uplod Kamera", + "HeaderAlbumArtists": "Album Artis", + "Genres": "Genre", + "Folders": "Folder", + "Favorites": "Favorit", + "Collections": "Koleksi", + "Books": "Buku", + "Artists": "Artis", + "Application": "Aplikasi" +} -- cgit v1.2.3 From 5bf0eb2b0ef29a9398d638a910e2cd3945331252 Mon Sep 17 00:00:00 2001 From: Odd Stråbø Date: Wed, 25 Dec 2019 00:15:55 +0000 Subject: Translated using Weblate (Norwegian Bokmål) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nb_NO/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Emby.Server.Implementations/Localization/Core/nb.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json index 1237fb70a..48216f71c 100644 --- a/Emby.Server.Implementations/Localization/Core/nb.json +++ b/Emby.Server.Implementations/Localization/Core/nb.json @@ -45,7 +45,7 @@ "NameSeasonNumber": "Sesong {0}", "NameSeasonUnknown": "Sesong ukjent", "NewVersionIsAvailable": "En ny versjon av Jellyfin-serveren er tilgjengelig for nedlastning.", - "NotificationOptionApplicationUpdateAvailable": "Applikasjon oppdatering tilgjengelig", + "NotificationOptionApplicationUpdateAvailable": "Programvareoppdatering er tilgjengelig", "NotificationOptionApplicationUpdateInstalled": "Applikasjonsoppdatering installert", "NotificationOptionAudioPlayback": "Lyd tilbakespilling startet", "NotificationOptionAudioPlaybackStopped": "Lyd avspilling stoppet", -- cgit v1.2.3 From d7164d2eb758fa9045b92bacc930f86f1b4b71a3 Mon Sep 17 00:00:00 2001 From: Allan <176101024@qq.com> Date: Thu, 26 Dec 2019 08:47:55 +0000 Subject: Translated using Weblate (Chinese (Simplified)) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hans/ --- Emby.Server.Implementations/Localization/Core/zh-CN.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json index 87f8553ae..6a72a28e5 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-CN.json +++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json @@ -24,7 +24,7 @@ "HeaderFavoriteShows": "最爱的节目", "HeaderFavoriteSongs": "最爱的歌曲", "HeaderLiveTV": "电视直播", - "HeaderNextUp": "接下来", + "HeaderNextUp": "下一步", "HeaderRecordingGroups": "录制组", "HomeVideos": "家庭视频", "Inherit": "继承", @@ -34,7 +34,7 @@ "LabelRunningTimeValue": "运行时间:{0}", "Latest": "最新", "MessageApplicationUpdated": "Jellyfin 服务器已更新", - "MessageApplicationUpdatedTo": "Jellyfin Server 的版本已更新为 {0}", + "MessageApplicationUpdatedTo": "Jellyfin Server 版本已更新为 {0}", "MessageNamedServerConfigurationUpdatedWithValue": "服务器配置 {0} 部分已更新", "MessageServerConfigurationUpdated": "服务器配置已更新", "MixedContent": "混合内容", -- cgit v1.2.3 From 49ce876c2c2bdbd9fb51f2cae1ba7680bf675de5 Mon Sep 17 00:00:00 2001 From: Z Yang Date: Fri, 27 Dec 2019 03:52:01 +0000 Subject: Translated using Weblate (Chinese (Simplified)) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/zh_Hans/ --- Emby.Server.Implementations/Localization/Core/zh-CN.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/zh-CN.json b/Emby.Server.Implementations/Localization/Core/zh-CN.json index 6a72a28e5..a4d53c57e 100644 --- a/Emby.Server.Implementations/Localization/Core/zh-CN.json +++ b/Emby.Server.Implementations/Localization/Core/zh-CN.json @@ -42,7 +42,7 @@ "Music": "音乐", "MusicVideos": "音乐视频", "NameInstallFailed": "{0} 安装失败", - "NameSeasonNumber": "季 {0}", + "NameSeasonNumber": "第 {0} 季", "NameSeasonUnknown": "未知季", "NewVersionIsAvailable": "Jellyfin Server 有新版本可以下载。", "NotificationOptionApplicationUpdateAvailable": "有可用的应用程序更新", -- cgit v1.2.3 From ab57b504fe2dabb8e493caaf4289c0eec3bddaed Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Sun, 29 Dec 2019 19:32:12 +0100 Subject: Delete user config dir on user deletion --- Emby.Server.Implementations/Library/UserManager.cs | 84 ++++++++-------------- MediaBrowser.Controller/Library/IUserManager.cs | 2 - 2 files changed, 29 insertions(+), 57 deletions(-) diff --git a/Emby.Server.Implementations/Library/UserManager.cs b/Emby.Server.Implementations/Library/UserManager.cs index 85bfa154a..bfb3ddae2 100644 --- a/Emby.Server.Implementations/Library/UserManager.cs +++ b/Emby.Server.Implementations/Library/UserManager.cs @@ -42,13 +42,13 @@ namespace Emby.Server.Implementations.Library /// public class UserManager : IUserManager { + private readonly object _policySyncLock = new object(); + private readonly object _configSyncLock = new object(); /// /// The logger. /// private readonly ILogger _logger; - private readonly object _policySyncLock = new object(); - /// /// Gets the active user repository. /// @@ -255,7 +255,12 @@ namespace Emby.Server.Implementations.Library return builder.ToString(); } - public async Task AuthenticateUser(string username, string password, string hashedPassword, string remoteEndPoint, bool isUserSession) + public async Task AuthenticateUser( + string username, + string password, + string hashedPassword, + string remoteEndPoint, + bool isUserSession) { if (string.IsNullOrWhiteSpace(username)) { @@ -754,13 +759,10 @@ namespace Emby.Server.Implementations.Library return user; } - /// - /// Deletes the user. - /// - /// The user. - /// Task. - /// user - /// + /// + /// The user is null. + /// The user doesn't exist, or is the last administrator. + /// The user can't be deleted; there are no other users. public void DeleteUser(User user) { if (user == null) @@ -779,7 +781,7 @@ namespace Emby.Server.Implementations.Library if (_users.Count == 1) { - throw new ArgumentException(string.Format( + throw new InvalidOperationException(string.Format( CultureInfo.InvariantCulture, "The user '{0}' cannot be deleted because there must be at least one user in the system.", user.Name)); @@ -800,17 +802,20 @@ namespace Emby.Server.Implementations.Library _userRepository.DeleteUser(user); - try - { - _fileSystem.DeleteFile(configPath); - } - catch (IOException ex) + // Delete user config dir + lock (_configSyncLock) + lock (_policySyncLock) { - _logger.LogError(ex, "Error deleting file {path}", configPath); + try + { + Directory.Delete(user.ConfigurationDirectoryPath, true); + } + catch (IOException ex) + { + _logger.LogError(ex, "Error deleting user config dir: {Path}", user.ConfigurationDirectoryPath); + } } - DeleteUserPolicy(user); - _users.TryRemove(user.Id, out _); OnUserDeleted(user); @@ -918,10 +923,9 @@ namespace Emby.Server.Implementations.Library public UserPolicy GetUserPolicy(User user) { var path = GetPolicyFilePath(user); - if (!File.Exists(path)) { - return GetDefaultPolicy(user); + return GetDefaultPolicy(); } try @@ -931,19 +935,15 @@ namespace Emby.Server.Implementations.Library return (UserPolicy)_xmlSerializer.DeserializeFromFile(typeof(UserPolicy), path); } } - catch (IOException) - { - return GetDefaultPolicy(user); - } catch (Exception ex) { - _logger.LogError(ex, "Error reading policy file: {path}", path); + _logger.LogError(ex, "Error reading policy file: {Path}", path); - return GetDefaultPolicy(user); + return GetDefaultPolicy(); } } - private static UserPolicy GetDefaultPolicy(User user) + private static UserPolicy GetDefaultPolicy() { return new UserPolicy { @@ -983,27 +983,6 @@ namespace Emby.Server.Implementations.Library } } - private void DeleteUserPolicy(User user) - { - var path = GetPolicyFilePath(user); - - try - { - lock (_policySyncLock) - { - _fileSystem.DeleteFile(path); - } - } - catch (IOException) - { - - } - catch (Exception ex) - { - _logger.LogError(ex, "Error deleting policy file"); - } - } - private static string GetPolicyFilePath(User user) { return Path.Combine(user.ConfigurationDirectoryPath, "policy.xml"); @@ -1030,19 +1009,14 @@ namespace Emby.Server.Implementations.Library return (UserConfiguration)_xmlSerializer.DeserializeFromFile(typeof(UserConfiguration), path); } } - catch (IOException) - { - return new UserConfiguration(); - } catch (Exception ex) { - _logger.LogError(ex, "Error reading policy file: {path}", path); + _logger.LogError(ex, "Error reading policy file: {Path}", path); return new UserConfiguration(); } } - private readonly object _configSyncLock = new object(); public void UpdateConfiguration(Guid userId, UserConfiguration config) { var user = GetUserById(userId); diff --git a/MediaBrowser.Controller/Library/IUserManager.cs b/MediaBrowser.Controller/Library/IUserManager.cs index 8d92c9f6f..be7b4ce59 100644 --- a/MediaBrowser.Controller/Library/IUserManager.cs +++ b/MediaBrowser.Controller/Library/IUserManager.cs @@ -102,8 +102,6 @@ namespace MediaBrowser.Controller.Library /// /// The user. /// Task. - /// user - /// void DeleteUser(User user); /// -- cgit v1.2.3 From 49330e30827eb4fc6b94cfbf6cd611e1d297920d Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Mon, 30 Dec 2019 16:03:20 +0100 Subject: Fix a couple of TODOs --- Emby.Dlna/Eventing/EventManager.cs | 36 ++++++---------- Emby.Server.Implementations/ApplicationHost.cs | 3 +- .../Collections/CollectionManager.cs | 48 +++++----------------- 3 files changed, 23 insertions(+), 64 deletions(-) diff --git a/Emby.Dlna/Eventing/EventManager.cs b/Emby.Dlna/Eventing/EventManager.cs index 4b542a820..b76a0066d 100644 --- a/Emby.Dlna/Eventing/EventManager.cs +++ b/Emby.Dlna/Eventing/EventManager.cs @@ -29,25 +29,15 @@ namespace Emby.Dlna.Eventing { var subscription = GetSubscription(subscriptionId, false); - int timeoutSeconds; + subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300; + int timeoutSeconds = subscription.TimeoutSeconds; + subscription.SubscriptionTime = DateTime.UtcNow; - // Remove logging for now because some devices are sending this very frequently - // TODO re-enable with dlna debug logging setting - //_logger.LogDebug("Renewing event subscription for {0} with timeout of {1} to {2}", - // subscription.NotificationType, - // timeout, - // subscription.CallbackUrl); - - if (subscription != null) - { - subscription.TimeoutSeconds = ParseTimeout(requestedTimeoutString) ?? 300; - timeoutSeconds = subscription.TimeoutSeconds; - subscription.SubscriptionTime = DateTime.UtcNow; - } - else - { - timeoutSeconds = 300; - } + _logger.LogDebug( + "Renewing event subscription for {0} with timeout of {1} to {2}", + subscription.NotificationType, + timeoutSeconds, + subscription.CallbackUrl); return GetEventSubscriptionResponse(subscriptionId, requestedTimeoutString, timeoutSeconds); } @@ -57,12 +47,10 @@ namespace Emby.Dlna.Eventing var timeout = ParseTimeout(requestedTimeoutString) ?? 300; var id = "uuid:" + Guid.NewGuid().ToString("N", CultureInfo.InvariantCulture); - // Remove logging for now because some devices are sending this very frequently - // TODO re-enable with dlna debug logging setting - //_logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}", - // notificationType, - // timeout, - // callbackUrl); + _logger.LogDebug("Creating event subscription for {0} with timeout of {1} to {2}", + notificationType, + timeout, + callbackUrl); _subscriptions.TryAdd(id, new EventSubscription { diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index aed0c14a2..67bc0cd2b 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -764,9 +764,8 @@ namespace Emby.Server.Implementations LibraryManager = new LibraryManager(this, LoggerFactory, TaskManager, UserManager, ServerConfigurationManager, UserDataManager, () => LibraryMonitor, FileSystemManager, () => ProviderManager, () => UserViewManager); serviceCollection.AddSingleton(LibraryManager); - // TODO wtaylor: investigate use of second music manager var musicManager = new MusicManager(LibraryManager); - serviceCollection.AddSingleton(new MusicManager(LibraryManager)); + serviceCollection.AddSingleton(musicManager); LibraryMonitor = new LibraryMonitor(LoggerFactory, LibraryManager, ServerConfigurationManager, FileSystemManager); serviceCollection.AddSingleton(LibraryMonitor); diff --git a/Emby.Server.Implementations/Collections/CollectionManager.cs b/Emby.Server.Implementations/Collections/CollectionManager.cs index 2b8a5bdc5..1d7c11989 100644 --- a/Emby.Server.Implementations/Collections/CollectionManager.cs +++ b/Emby.Server.Implementations/Collections/CollectionManager.cs @@ -31,11 +31,7 @@ namespace Emby.Server.Implementations.Collections private readonly ILogger _logger; private readonly IProviderManager _providerManager; private readonly ILocalizationManager _localizationManager; - private IApplicationPaths _appPaths; - - public event EventHandler CollectionCreated; - public event EventHandler ItemsAddedToCollection; - public event EventHandler ItemsRemovedFromCollection; + private readonly IApplicationPaths _appPaths; public CollectionManager( ILibraryManager libraryManager, @@ -55,6 +51,10 @@ namespace Emby.Server.Implementations.Collections _appPaths = appPaths; } + public event EventHandler CollectionCreated; + public event EventHandler ItemsAddedToCollection; + public event EventHandler ItemsRemovedFromCollection; + private IEnumerable FindFolders(string path) { return _libraryManager @@ -341,11 +341,11 @@ namespace Emby.Server.Implementations.Collections } } - public class CollectionManagerEntryPoint : IServerEntryPoint + public sealed class CollectionManagerEntryPoint : IServerEntryPoint { private readonly CollectionManager _collectionManager; private readonly IServerConfigurationManager _config; - private ILogger _logger; + private readonly ILogger _logger; public CollectionManagerEntryPoint(ICollectionManager collectionManager, IServerConfigurationManager config, ILogger logger) { @@ -354,6 +354,7 @@ namespace Emby.Server.Implementations.Collections _logger = logger; } + /// public async Task RunAsync() { if (!_config.Configuration.CollectionsUpgraded && _config.Configuration.IsStartupWizardCompleted) @@ -377,39 +378,10 @@ namespace Emby.Server.Implementations.Collections } } - #region IDisposable Support - private bool disposedValue = false; // To detect redundant calls - - protected virtual void Dispose(bool disposing) - { - if (!disposedValue) - { - if (disposing) - { - // TODO: dispose managed state (managed objects). - } - - // TODO: free unmanaged resources (unmanaged objects) and override a finalizer below. - // TODO: set large fields to null. - - disposedValue = true; - } - } - - // TODO: override a finalizer only if Dispose(bool disposing) above has code to free unmanaged resources. - // ~CollectionManagerEntryPoint() { - // // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - // Dispose(false); - // } - - // This code added to correctly implement the disposable pattern. + /// public void Dispose() { - // Do not change this code. Put cleanup code in Dispose(bool disposing) above. - Dispose(true); - // TODO: uncomment the following line if the finalizer is overridden above. - // GC.SuppressFinalize(this); + // Nothing to dispose } - #endregion } } -- cgit v1.2.3 From f672ecbac5c8dee8fc4c21cbbc27bf4a33d08e03 Mon Sep 17 00:00:00 2001 From: marty Date: Sun, 29 Dec 2019 11:37:18 +0000 Subject: Translated using Weblate (Lithuanian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/ --- .../Localization/Core/lt-LT.json | 26 +++++++++++----------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json index e2f3ba3dc..bfacb6556 100644 --- a/Emby.Server.Implementations/Localization/Core/lt-LT.json +++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json @@ -18,13 +18,13 @@ "HeaderAlbumArtists": "Albumo atlikėjai", "HeaderCameraUploads": "Camera Uploads", "HeaderContinueWatching": "Žiūrėti toliau", - "HeaderFavoriteAlbums": "Favorite Albums", - "HeaderFavoriteArtists": "Favorite Artists", - "HeaderFavoriteEpisodes": "Favorite Episodes", - "HeaderFavoriteShows": "Favorite Shows", - "HeaderFavoriteSongs": "Favorite Songs", - "HeaderLiveTV": "Live TV", - "HeaderNextUp": "Next Up", + "HeaderFavoriteAlbums": "Mėgstami Albumai", + "HeaderFavoriteArtists": "Mėgstami Atlikėjai", + "HeaderFavoriteEpisodes": "Mėgstamiausios serijos", + "HeaderFavoriteShows": "Mėgstamiausi serialai", + "HeaderFavoriteSongs": "Mėgstamos dainos", + "HeaderLiveTV": "TV gyvai", + "HeaderNextUp": "Toliau eilėje", "HeaderRecordingGroups": "Recording Groups", "HomeVideos": "Home videos", "Inherit": "Inherit", @@ -50,19 +50,19 @@ "NotificationOptionAudioPlayback": "Audio playback started", "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", "NotificationOptionCameraImageUploaded": "Camera image uploaded", - "NotificationOptionInstallationFailed": "Installation failure", + "NotificationOptionInstallationFailed": "Diegimo klaida", "NotificationOptionNewLibraryContent": "New content added", "NotificationOptionPluginError": "Plugin failure", "NotificationOptionPluginInstalled": "Plugin installed", "NotificationOptionPluginUninstalled": "Plugin uninstalled", "NotificationOptionPluginUpdateInstalled": "Plugin update installed", - "NotificationOptionServerRestartRequired": "Server restart required", + "NotificationOptionServerRestartRequired": "Reikalingas serverio perleidimas.", "NotificationOptionTaskFailed": "Scheduled task failure", "NotificationOptionUserLockedOut": "User locked out", "NotificationOptionVideoPlayback": "Video playback started", "NotificationOptionVideoPlaybackStopped": "Video playback stopped", - "Photos": "Photos", - "Playlists": "Playlists", + "Photos": "Nuotraukos", + "Playlists": "Grojaraštis", "Plugin": "Plugin", "PluginInstalledWithName": "{0} was installed", "PluginUninstalledWithName": "{0} was uninstalled", @@ -71,8 +71,8 @@ "ScheduledTaskFailedWithName": "{0} failed", "ScheduledTaskStartedWithName": "{0} started", "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", - "Shows": "Shows", - "Songs": "Songs", + "Shows": "Laidos", + "Songs": "Kūriniai", "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.", "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}", "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}", -- cgit v1.2.3 From c10cb661694fca763ec4e5be30110ce077a0b428 Mon Sep 17 00:00:00 2001 From: dkanada Date: Wed, 1 Jan 2020 14:45:09 +0900 Subject: remove directory check --- Emby.Server.Implementations/Library/LibraryManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Library/LibraryManager.cs b/Emby.Server.Implementations/Library/LibraryManager.cs index 1f5bd7deb..cee51479e 100644 --- a/Emby.Server.Implementations/Library/LibraryManager.cs +++ b/Emby.Server.Implementations/Library/LibraryManager.cs @@ -394,7 +394,7 @@ namespace Emby.Server.Implementations.Library foreach (var fileSystemInfo in item.GetDeletePaths()) { - if (fileSystemInfo.IsDirectory ? Directory.Exists(fileSystemInfo.FullName) : File.Exists(fileSystemInfo.FullName)) + if (Directory.Exists(fileSystemInfo.FullName) || File.Exists(fileSystemInfo.FullName)) { try { -- cgit v1.2.3 From c62599f8736ee64defdb920a205dd113d3653029 Mon Sep 17 00:00:00 2001 From: marty Date: Mon, 30 Dec 2019 20:02:47 +0000 Subject: Translated using Weblate (Lithuanian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/ --- .../Localization/Core/lt-LT.json | 124 ++++++++++----------- 1 file changed, 62 insertions(+), 62 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json index bfacb6556..9ba274811 100644 --- a/Emby.Server.Implementations/Localization/Core/lt-LT.json +++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json @@ -1,22 +1,22 @@ { "Albums": "Albumai", - "AppDeviceValues": "App: {0}, Device: {1}", - "Application": "Application", + "AppDeviceValues": "Programa: {0}, Įrenginys: {1}", + "Application": "Programa", "Artists": "Atlikėjai", - "AuthenticationSucceededWithUserName": "{0} successfully authenticated", + "AuthenticationSucceededWithUserName": "{0} sėkmingai autentifikuota", "Books": "Knygos", - "CameraImageUploadedFrom": "A new camera image has been uploaded from {0}", + "CameraImageUploadedFrom": "Nauja nuotrauka įkelta iš kameros {0}", "Channels": "Kanalai", - "ChapterNameValue": "Chapter {0}", + "ChapterNameValue": "Scena{0}", "Collections": "Kolekcijos", - "DeviceOfflineWithName": "{0} has disconnected", - "DeviceOnlineWithName": "{0} is connected", - "FailedLoginAttemptWithUserName": "Failed login attempt from {0}", + "DeviceOfflineWithName": "{0} buvo atjungtas", + "DeviceOnlineWithName": "{0} prisijungęs", + "FailedLoginAttemptWithUserName": "{0} - nesėkmingas bandymas prisijungti", "Favorites": "Mėgstami", "Folders": "Katalogai", "Genres": "Žanrai", "HeaderAlbumArtists": "Albumo atlikėjai", - "HeaderCameraUploads": "Camera Uploads", + "HeaderCameraUploads": "Kameros", "HeaderContinueWatching": "Žiūrėti toliau", "HeaderFavoriteAlbums": "Mėgstami Albumai", "HeaderFavoriteArtists": "Mėgstami Atlikėjai", @@ -25,73 +25,73 @@ "HeaderFavoriteSongs": "Mėgstamos dainos", "HeaderLiveTV": "TV gyvai", "HeaderNextUp": "Toliau eilėje", - "HeaderRecordingGroups": "Recording Groups", - "HomeVideos": "Home videos", - "Inherit": "Inherit", - "ItemAddedWithName": "{0} was added to the library", - "ItemRemovedWithName": "{0} was removed from the library", + "HeaderRecordingGroups": "Įrašų grupės", + "HomeVideos": "Namų vaizdo įrašai", + "Inherit": "Paveldėti", + "ItemAddedWithName": "{0} - buvo įkeltas į mediateką", + "ItemRemovedWithName": "{0} - buvo pašalinta iš mediatekos", "LabelIpAddressValue": "Ip address: {0}", - "LabelRunningTimeValue": "Running time: {0}", - "Latest": "Latest", - "MessageApplicationUpdated": "Jellyfin Server has been updated", - "MessageApplicationUpdatedTo": "Jellyfin Server has been updated to {0}", - "MessageNamedServerConfigurationUpdatedWithValue": "Server configuration section {0} has been updated", - "MessageServerConfigurationUpdated": "Server configuration has been updated", + "LabelRunningTimeValue": "Trukmė: {0}", + "Latest": "Naujausi", + "MessageApplicationUpdated": "\"Jellyfin Server\" atnaujintas", + "MessageApplicationUpdatedTo": "\"Jellyfin Server\" buvo atnaujinta iki {0}", + "MessageNamedServerConfigurationUpdatedWithValue": "Serverio nustatymai (skyrius {0}) buvo atnaujinti", + "MessageServerConfigurationUpdated": "Serverio nustatymai buvo atnaujinti", "MixedContent": "Mixed content", "Movies": "Filmai", - "Music": "Music", - "MusicVideos": "Music videos", - "NameInstallFailed": "{0} installation failed", - "NameSeasonNumber": "Season {0}", - "NameSeasonUnknown": "Season Unknown", - "NewVersionIsAvailable": "A new version of Jellyfin Server is available for download.", - "NotificationOptionApplicationUpdateAvailable": "Application update available", - "NotificationOptionApplicationUpdateInstalled": "Application update installed", - "NotificationOptionAudioPlayback": "Audio playback started", - "NotificationOptionAudioPlaybackStopped": "Audio playback stopped", - "NotificationOptionCameraImageUploaded": "Camera image uploaded", + "Music": "Muzika", + "MusicVideos": "Muzikiniai klipai", + "NameInstallFailed": "{0} diegimo klaida", + "NameSeasonNumber": "Sezonas {0}", + "NameSeasonUnknown": "Sezonas neatpažintas", + "NewVersionIsAvailable": "Nauja \"Jellyfin Server\" versija yra prieinama atsisiuntimui.", + "NotificationOptionApplicationUpdateAvailable": "Galimi programos atnaujinimai", + "NotificationOptionApplicationUpdateInstalled": "Programos atnaujinimai įdiegti", + "NotificationOptionAudioPlayback": "Garso atkūrimas pradėtas", + "NotificationOptionAudioPlaybackStopped": "Garso atkūrimas sustabdytas", + "NotificationOptionCameraImageUploaded": "Kameros vaizdai įkelti", "NotificationOptionInstallationFailed": "Diegimo klaida", - "NotificationOptionNewLibraryContent": "New content added", - "NotificationOptionPluginError": "Plugin failure", - "NotificationOptionPluginInstalled": "Plugin installed", - "NotificationOptionPluginUninstalled": "Plugin uninstalled", - "NotificationOptionPluginUpdateInstalled": "Plugin update installed", - "NotificationOptionServerRestartRequired": "Reikalingas serverio perleidimas.", - "NotificationOptionTaskFailed": "Scheduled task failure", - "NotificationOptionUserLockedOut": "User locked out", - "NotificationOptionVideoPlayback": "Video playback started", - "NotificationOptionVideoPlaybackStopped": "Video playback stopped", + "NotificationOptionNewLibraryContent": "Naujas turinys įkeltas", + "NotificationOptionPluginError": "Įskiepio klaida", + "NotificationOptionPluginInstalled": "Įskiepis įdiegtas", + "NotificationOptionPluginUninstalled": "Įskiepis pašalintas", + "NotificationOptionPluginUpdateInstalled": "Įskiepio atnaujinimas įdiegtas", + "NotificationOptionServerRestartRequired": "Reikalingas serverio perleidimas", + "NotificationOptionTaskFailed": "Suplanuotos užduoties klaida", + "NotificationOptionUserLockedOut": "Vartotojas užblokuotas", + "NotificationOptionVideoPlayback": "Vaizdo įrašo atkūrimas pradėtas", + "NotificationOptionVideoPlaybackStopped": "Vaizdo įrašo atkūrimas sustabdytas", "Photos": "Nuotraukos", "Playlists": "Grojaraštis", "Plugin": "Plugin", - "PluginInstalledWithName": "{0} was installed", - "PluginUninstalledWithName": "{0} was uninstalled", - "PluginUpdatedWithName": "{0} was updated", + "PluginInstalledWithName": "{0} buvo įdiegtas", + "PluginUninstalledWithName": "{0} buvo pašalintas", + "PluginUpdatedWithName": "{0} buvo atnaujintas", "ProviderValue": "Provider: {0}", - "ScheduledTaskFailedWithName": "{0} failed", - "ScheduledTaskStartedWithName": "{0} started", - "ServerNameNeedsToBeRestarted": "{0} needs to be restarted", + "ScheduledTaskFailedWithName": "{0} klaida", + "ScheduledTaskStartedWithName": "{0} paleista", + "ServerNameNeedsToBeRestarted": "{0} reikia iš naujo paleisti", "Shows": "Laidos", "Songs": "Kūriniai", - "StartupEmbyServerIsLoading": "Jellyfin Server is loading. Please try again shortly.", + "StartupEmbyServerIsLoading": "Jellyfin Server kraunasi. Netrukus pabandykite dar kartą.", "SubtitleDownloadFailureForItem": "Subtitles failed to download for {0}", - "SubtitleDownloadFailureFromForItem": "Subtitles failed to download from {0} for {1}", - "SubtitlesDownloadedForItem": "Subtitles downloaded for {0}", + "SubtitleDownloadFailureFromForItem": "{1} subtitrai buvo nesėkmingai parsiųsti iš {0}", + "SubtitlesDownloadedForItem": "{0} subtitrai parsiųsti", "Sync": "Sinchronizuoti", "System": "System", - "TvShows": "TV Shows", + "TvShows": "TV Serialai", "User": "User", - "UserCreatedWithName": "User {0} has been created", - "UserDeletedWithName": "User {0} has been deleted", - "UserDownloadingItemWithValues": "{0} is downloading {1}", - "UserLockedOutWithName": "User {0} has been locked out", - "UserOfflineFromDevice": "{0} has disconnected from {1}", - "UserOnlineFromDevice": "{0} is online from {1}", - "UserPasswordChangedWithName": "Password has been changed for user {0}", - "UserPolicyUpdatedWithName": "User policy has been updated for {0}", - "UserStartedPlayingItemWithValues": "{0} is playing {1} on {2}", - "UserStoppedPlayingItemWithValues": "{0} has finished playing {1} on {2}", - "ValueHasBeenAddedToLibrary": "{0} has been added to your media library", + "UserCreatedWithName": "Vartotojas {0} buvo sukurtas", + "UserDeletedWithName": "Vartotojas {0} ištrintas", + "UserDownloadingItemWithValues": "{0} siunčiasi {1}", + "UserLockedOutWithName": "Vartotojas {0} užblokuotas", + "UserOfflineFromDevice": "{0} buvo atjungtas nuo {1}", + "UserOnlineFromDevice": "{0} prisijungęs iš {1}", + "UserPasswordChangedWithName": "Slaptažodis pakeistas vartotojui {0}", + "UserPolicyUpdatedWithName": "Vartotojo {0} teisės buvo pakeistos", + "UserStartedPlayingItemWithValues": "{0} leidžia {1} į {2}", + "UserStoppedPlayingItemWithValues": "{0} baigė leisti {1} į {2}", + "ValueHasBeenAddedToLibrary": "{0} pridėtas į mediateką", "ValueSpecialEpisodeName": "Ypatinga - {0}", "VersionNumber": "Version {0}" } -- cgit v1.2.3 From 72d2b5910ad2d7ba5b020247e9ae5d03edb5aeb6 Mon Sep 17 00:00:00 2001 From: erikasne6152 Date: Mon, 30 Dec 2019 21:38:20 +0000 Subject: Translated using Weblate (Lithuanian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/lt/ --- Emby.Server.Implementations/Localization/Core/lt-LT.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/lt-LT.json b/Emby.Server.Implementations/Localization/Core/lt-LT.json index 9ba274811..e8e1b7740 100644 --- a/Emby.Server.Implementations/Localization/Core/lt-LT.json +++ b/Emby.Server.Implementations/Localization/Core/lt-LT.json @@ -30,7 +30,7 @@ "Inherit": "Paveldėti", "ItemAddedWithName": "{0} - buvo įkeltas į mediateką", "ItemRemovedWithName": "{0} - buvo pašalinta iš mediatekos", - "LabelIpAddressValue": "Ip address: {0}", + "LabelIpAddressValue": "IP adresas: {0}", "LabelRunningTimeValue": "Trukmė: {0}", "Latest": "Naujausi", "MessageApplicationUpdated": "\"Jellyfin Server\" atnaujintas", -- cgit v1.2.3 From 59cdfdc2d9435f06dc535837ae9d1fe63543bb08 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Thu, 2 Jan 2020 14:38:13 +0100 Subject: Fix JSON subtitle writer --- MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs index 241ebc6df..1b452b0ce 100644 --- a/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs +++ b/MediaBrowser.MediaEncoding/Subtitles/JsonWriter.cs @@ -16,6 +16,7 @@ namespace MediaBrowser.MediaEncoding.Subtitles using (var writer = new Utf8JsonWriter(stream)) { var trackevents = info.TrackEvents; + writer.WriteStartObject(); writer.WriteStartArray("TrackEvents"); for (int i = 0; i < trackevents.Count; i++) @@ -33,7 +34,10 @@ namespace MediaBrowser.MediaEncoding.Subtitles writer.WriteEndObject(); } + writer.WriteEndArray(); writer.WriteEndObject(); + + writer.Flush(); } } } -- cgit v1.2.3 From 09d1f976d994f13dd6e69bae3d371262abb0d56d Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 2 Jan 2020 20:19:01 +0100 Subject: Replace unicode char with its integer value --- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 54d02fc9f..3067238f7 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1334,24 +1334,25 @@ namespace MediaBrowser.MediaEncoding.Probing { video.Timestamp = GetMpegTimestamp(video.Path); - _logger.LogDebug("Video has {timestamp} timestamp", video.Timestamp); + _logger.LogDebug("Video has {Timestamp} timestamp", video.Timestamp); } catch (Exception ex) { - _logger.LogError(ex, "Error extracting timestamp info from {path}", video.Path); + _logger.LogError(ex, "Error extracting timestamp info from {Path}", video.Path); video.Timestamp = null; } } } } + // REVIEW: private TransportStreamTimestamp GetMpegTimestamp(string path) { - var packetBuffer = new byte['Å']; + var packetBuffer = new byte[197]; - using (var fs = _fileSystem.GetFileStream(path, FileOpenMode.Open, FileAccessMode.Read, FileShareMode.Read)) + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { - fs.Read(packetBuffer, 0, packetBuffer.Length); + fs.Read(packetBuffer); } if (packetBuffer[0] == 71) @@ -1359,7 +1360,7 @@ namespace MediaBrowser.MediaEncoding.Probing return TransportStreamTimestamp.None; } - if ((packetBuffer[4] == 71) && (packetBuffer['Ä'] == 71)) + if ((packetBuffer[4] == 71) && (packetBuffer[196] == 71)) { if ((packetBuffer[0] == 0) && (packetBuffer[1] == 0) && (packetBuffer[2] == 0) && (packetBuffer[3] == 0)) { -- cgit v1.2.3 From 599432890311c9255cb376bbeb6f5f4f673fbf1b Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 2 Jan 2020 21:22:10 +0100 Subject: Fix baseurl (again) --- Emby.Server.Implementations/ApplicationHost.cs | 40 +++++++++++++++-------- MediaBrowser.Controller/IServerApplicationHost.cs | 8 +++-- 2 files changed, 32 insertions(+), 16 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 67bc0cd2b..9b853c6d1 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -103,14 +103,11 @@ using MediaBrowser.Providers.Subtitles; using MediaBrowser.Providers.TV.TheTVDB; using MediaBrowser.WebDashboard.Api; using MediaBrowser.XbmcMetadata.Providers; -using Microsoft.AspNetCore.Builder; -using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Extensions; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; -using Microsoft.OpenApi.Models; using OperatingSystem = MediaBrowser.Common.System.OperatingSystem; namespace Emby.Server.Implementations @@ -1478,7 +1475,7 @@ namespace Emby.Server.Implementations /// /// The IPv6 address. /// The IPv6 address without the scope id. - private string RemoveScopeId(string address) + private ReadOnlySpan RemoveScopeId(ReadOnlySpan address) { var index = address.IndexOf('%'); if (index == -1) @@ -1486,33 +1483,50 @@ namespace Emby.Server.Implementations return address; } - return address.Substring(0, index); + return address.Slice(0, index); } + /// public string GetLocalApiUrl(IPAddress ipAddress) { if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6) { var str = RemoveScopeId(ipAddress.ToString()); + Span span = new char[str.Length + 2]; + span[0] = '['; + str.CopyTo(span.Slice(1)); + span[^1] = ']'; - return GetLocalApiUrl("[" + str + "]"); + return GetLocalApiUrl(span); } return GetLocalApiUrl(ipAddress.ToString()); } - public string GetLocalApiUrl(string host) + /// + public string GetLocalApiUrl(ReadOnlySpan host) { + var url = new StringBuilder(64); if (EnableHttps) { - return string.Format("https://{0}:{1}", - host, - HttpsPort.ToString(CultureInfo.InvariantCulture)); + url.Append("https://"); + } + else + { + url.Append("http://"); + } + + url.Append(host) + .Append(':') + .Append(HttpPort); + + string baseUrl = ServerConfigurationManager.Configuration.BaseUrl; + if (baseUrl.Length != 0) + { + url.Append('/').Append(baseUrl); } - return string.Format("http://{0}:{1}", - host, - HttpPort.ToString(CultureInfo.InvariantCulture)); + return url.ToString(); } public Task> GetLocalIpAddresses(CancellationToken cancellationToken) diff --git a/MediaBrowser.Controller/IServerApplicationHost.cs b/MediaBrowser.Controller/IServerApplicationHost.cs index b3c56bdd5..25f0905eb 100644 --- a/MediaBrowser.Controller/IServerApplicationHost.cs +++ b/MediaBrowser.Controller/IServerApplicationHost.cs @@ -71,13 +71,15 @@ namespace MediaBrowser.Controller /// /// Gets the local API URL. /// - /// The host. - /// System.String. - string GetLocalApiUrl(string host); + /// The hostname. + /// The local API URL. + string GetLocalApiUrl(ReadOnlySpan hostname); /// /// Gets the local API URL. /// + /// The IP address. + /// The local API URL. string GetLocalApiUrl(IPAddress address); void LaunchUrl(string url); -- cgit v1.2.3 From 295eaa2ccb65f2a8d4d2f9d97f6c3cbe410b1588 Mon Sep 17 00:00:00 2001 From: Constantin Matel Date: Fri, 3 Jan 2020 15:36:58 +0000 Subject: Added translation using Weblate (Romanian) --- Emby.Server.Implementations/Localization/Core/ro.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/ro.json diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/ro.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 5cd8338e73669d28c894aac9918a67af2cbc9730 Mon Sep 17 00:00:00 2001 From: shoeflydbm Date: Thu, 2 Jan 2020 21:35:07 +0000 Subject: Translated using Weblate (Norwegian Bokmål) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/nb_NO/ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Localization/Core/nb.json | 52 +++++++++++----------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/nb.json b/Emby.Server.Implementations/Localization/Core/nb.json index 48216f71c..7d4b2bdac 100644 --- a/Emby.Server.Implementations/Localization/Core/nb.json +++ b/Emby.Server.Implementations/Localization/Core/nb.json @@ -17,7 +17,7 @@ "Genres": "Sjangre", "HeaderAlbumArtists": "Albumartister", "HeaderCameraUploads": "Kameraopplastinger", - "HeaderContinueWatching": "Forsett å se på", + "HeaderContinueWatching": "Fortsett å se", "HeaderFavoriteAlbums": "Favorittalbum", "HeaderFavoriteArtists": "Favorittartister", "HeaderFavoriteEpisodes": "Favorittepisoder", @@ -25,18 +25,18 @@ "HeaderFavoriteSongs": "Favorittsanger", "HeaderLiveTV": "Direkte-TV", "HeaderNextUp": "Neste", - "HeaderRecordingGroups": "Opptak Grupper", - "HomeVideos": "Hjemmelaget filmer", + "HeaderRecordingGroups": "Opptaksgrupper", + "HomeVideos": "Hjemmelagde filmer", "Inherit": "Arve", "ItemAddedWithName": "{0} ble lagt til i biblioteket", "ItemRemovedWithName": "{0} ble fjernet fra biblioteket", - "LabelIpAddressValue": "IP adresse: {0}", - "LabelRunningTimeValue": "Løpetid {0}", + "LabelIpAddressValue": "IP-adresse: {0}", + "LabelRunningTimeValue": "Kjøretid {0}", "Latest": "Siste", - "MessageApplicationUpdated": "Jellyfin server har blitt oppdatert", - "MessageApplicationUpdatedTo": "Jellyfin-serveren ble oppdatert til {0}", - "MessageNamedServerConfigurationUpdatedWithValue": "Server konfigurasjon seksjon {0} har blitt oppdatert", - "MessageServerConfigurationUpdated": "Server konfigurasjon er oppdatert", + "MessageApplicationUpdated": "Jellyfin Server har blitt oppdatert", + "MessageApplicationUpdatedTo": "Jellyfin Server ble oppdatert til {0}", + "MessageNamedServerConfigurationUpdatedWithValue": "Serverkonfigurasjon seksjon {0} har blitt oppdatert", + "MessageServerConfigurationUpdated": "Serverkonfigurasjon er oppdatert", "MixedContent": "Blandet innhold", "Movies": "Filmer", "Music": "Musikk", @@ -44,38 +44,38 @@ "NameInstallFailed": "{0}-installasjonen mislyktes", "NameSeasonNumber": "Sesong {0}", "NameSeasonUnknown": "Sesong ukjent", - "NewVersionIsAvailable": "En ny versjon av Jellyfin-serveren er tilgjengelig for nedlastning.", + "NewVersionIsAvailable": "En ny versjon av Jellyfin Server er tilgjengelig for nedlasting.", "NotificationOptionApplicationUpdateAvailable": "Programvareoppdatering er tilgjengelig", "NotificationOptionApplicationUpdateInstalled": "Applikasjonsoppdatering installert", - "NotificationOptionAudioPlayback": "Lyd tilbakespilling startet", - "NotificationOptionAudioPlaybackStopped": "Lyd avspilling stoppet", - "NotificationOptionCameraImageUploaded": "Kamera bilde lastet opp", + "NotificationOptionAudioPlayback": "Lydavspilling startet", + "NotificationOptionAudioPlaybackStopped": "Lydavspilling stoppet", + "NotificationOptionCameraImageUploaded": "Kamerabilde lastet opp", "NotificationOptionInstallationFailed": "Installasjonsfeil", - "NotificationOptionNewLibraryContent": "Ny innhold er lagt til", - "NotificationOptionPluginError": "Plugin feil", + "NotificationOptionNewLibraryContent": "Nytt innhold lagt til", + "NotificationOptionPluginError": "Pluginfeil", "NotificationOptionPluginInstalled": "Plugin installert", "NotificationOptionPluginUninstalled": "Plugin avinstallert", - "NotificationOptionPluginUpdateInstalled": "Plugin oppdatering installert", - "NotificationOptionServerRestartRequired": "Server omstart er nødvendig", - "NotificationOptionTaskFailed": "Feil under utføring av planlagt oppgaver", + "NotificationOptionPluginUpdateInstalled": "Pluginoppdatering installert", + "NotificationOptionServerRestartRequired": "Serveromstart er nødvendig", + "NotificationOptionTaskFailed": "Feil under utføring av planlagt oppgave", "NotificationOptionUserLockedOut": "Bruker er utestengt", - "NotificationOptionVideoPlayback": "Video tilbakespilling startet", - "NotificationOptionVideoPlaybackStopped": "Video avspilling stoppet", + "NotificationOptionVideoPlayback": "Videoavspilling startet", + "NotificationOptionVideoPlaybackStopped": "Videoavspilling stoppet", "Photos": "Bilder", - "Playlists": "Spillelister", + "Playlists": "Spliielister", "Plugin": "Plugin", "PluginInstalledWithName": "{0} ble installert", "PluginUninstalledWithName": "{0} ble avinstallert", "PluginUpdatedWithName": "{0} ble oppdatert", - "ProviderValue": "Leverandører: {0}", - "ScheduledTaskFailedWithName": "{0} Mislykkes", - "ScheduledTaskStartedWithName": "{0} Startet", + "ProviderValue": "Leverandør: {0}", + "ScheduledTaskFailedWithName": "{0} mislykkes", + "ScheduledTaskStartedWithName": "{0} startet", "ServerNameNeedsToBeRestarted": "{0} må startes på nytt", "Shows": "Programmer", "Songs": "Sanger", - "StartupEmbyServerIsLoading": "Jellyfin server laster. Prøv igjen snart.", + "StartupEmbyServerIsLoading": "Jellyfin Server laster. Prøv igjen snart.", "SubtitleDownloadFailureForItem": "En feil oppstå under nedlasting av undertekster for {0}", - "SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned teksting fra {0} for {1}", + "SubtitleDownloadFailureFromForItem": "Kunne ikke laste ned undertekster fra {0} for {1}", "SubtitlesDownloadedForItem": "Undertekster lastet ned for {0}", "Sync": "Synkroniser", "System": "System", -- cgit v1.2.3 From 2497573b7f0427074c4e885d1ba1806e47d490d8 Mon Sep 17 00:00:00 2001 From: Sacha Korban Date: Fri, 3 Jan 2020 18:30:35 +1100 Subject: Update the build script to use .NET core SDK 3.1 --- deployment/centos-package-x64/Dockerfile | 2 +- deployment/debian-package-arm64/Dockerfile.amd64 | 4 ++-- deployment/debian-package-arm64/Dockerfile.arm64 | 4 ++-- deployment/debian-package-arm64/docker-build.sh | 4 ++-- deployment/debian-package-armhf/Dockerfile.amd64 | 4 ++-- deployment/debian-package-armhf/Dockerfile.armhf | 4 ++-- deployment/debian-package-armhf/docker-build.sh | 4 ++-- deployment/debian-package-x64/Dockerfile | 4 ++-- deployment/debian-package-x64/docker-build.sh | 4 ++-- deployment/debian-package-x64/pkg-src/control | 2 +- deployment/fedora-package-x64/Dockerfile | 2 +- deployment/fedora-package-x64/pkg-src/jellyfin.spec | 2 +- deployment/linux-x64/Dockerfile | 4 ++-- deployment/macos/Dockerfile | 4 ++-- deployment/portable/Dockerfile | 4 ++-- deployment/ubuntu-package-arm64/Dockerfile.amd64 | 4 ++-- deployment/ubuntu-package-arm64/Dockerfile.arm64 | 4 ++-- deployment/ubuntu-package-arm64/docker-build.sh | 4 ++-- deployment/ubuntu-package-armhf/Dockerfile.amd64 | 4 ++-- deployment/ubuntu-package-armhf/Dockerfile.armhf | 4 ++-- deployment/ubuntu-package-armhf/docker-build.sh | 4 ++-- deployment/ubuntu-package-x64/Dockerfile | 4 ++-- deployment/ubuntu-package-x64/docker-build.sh | 4 ++-- deployment/win-x64/Dockerfile | 4 ++-- deployment/win-x86/Dockerfile | 4 ++-- 25 files changed, 46 insertions(+), 46 deletions(-) diff --git a/deployment/centos-package-x64/Dockerfile b/deployment/centos-package-x64/Dockerfile index 04daef93c..2b346f46a 100644 --- a/deployment/centos-package-x64/Dockerfile +++ b/deployment/centos-package-x64/Dockerfile @@ -3,7 +3,7 @@ FROM centos:7 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/centos-package-x64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist diff --git a/deployment/debian-package-arm64/Dockerfile.amd64 b/deployment/debian-package-arm64/Dockerfile.amd64 index 069c2ed35..b63e08b7d 100644 --- a/deployment/debian-package-arm64/Dockerfile.amd64 +++ b/deployment/debian-package-arm64/Dockerfile.amd64 @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-arm64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/debian-package-arm64/Dockerfile.arm64 b/deployment/debian-package-arm64/Dockerfile.arm64 index d2e1c1f12..9ca486844 100644 --- a/deployment/debian-package-arm64/Dockerfile.arm64 +++ b/deployment/debian-package-arm64/Dockerfile.arm64 @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-arm64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/89fb60b1-3359-414e-94cf-359f57f37c7c/256e6dac8f44f9bad01f23f9a27b01ee/dotnet-sdk-3.0.101-linux-arm64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/5a4c8f96-1c73-401c-a6de-8e100403188a/0ce6ab39747e2508366d498f9c0a0669/dotnet-sdk-3.1.100-linux-arm64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/debian-package-arm64/docker-build.sh b/deployment/debian-package-arm64/docker-build.sh index b36b928ba..67ab6bd74 100755 --- a/deployment/debian-package-arm64/docker-build.sh +++ b/deployment/debian-package-arm64/docker-build.sh @@ -8,8 +8,8 @@ set -o xtrace # Move to source directory pushd ${SOURCE_DIR} -# Remove build-dep for dotnet-sdk-3.0, since it's not a package in this image -sed -i '/dotnet-sdk-3.0,/d' debian/control +# Remove build-dep for dotnet-sdk-3.1, since it's not a package in this image +sed -i '/dotnet-sdk-3.1,/d' debian/control # Build DEB export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} diff --git a/deployment/debian-package-armhf/Dockerfile.amd64 b/deployment/debian-package-armhf/Dockerfile.amd64 index d0afbed51..1b64b5314 100644 --- a/deployment/debian-package-armhf/Dockerfile.amd64 +++ b/deployment/debian-package-armhf/Dockerfile.amd64 @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-armhf ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/debian-package-armhf/Dockerfile.armhf b/deployment/debian-package-armhf/Dockerfile.armhf index dd9e3297e..dd398b5aa 100644 --- a/deployment/debian-package-armhf/Dockerfile.armhf +++ b/deployment/debian-package-armhf/Dockerfile.armhf @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-armhf ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/0b30374c-3d52-45ad-b4e5-9a39d0bf5bf0/deb17f7b32968b3a2186650711456152/dotnet-sdk-3.0.101-linux-arm.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/67766a96-eb8c-4cd2-bca4-ea63d2cc115c/7bf13840aa2ed88793b7315d5e0d74e6/dotnet-sdk-3.1.100-linux-arm.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/debian-package-armhf/docker-build.sh b/deployment/debian-package-armhf/docker-build.sh index 1b3af9a93..1bd7fb291 100755 --- a/deployment/debian-package-armhf/docker-build.sh +++ b/deployment/debian-package-armhf/docker-build.sh @@ -8,8 +8,8 @@ set -o xtrace # Move to source directory pushd ${SOURCE_DIR} -# Remove build-dep for dotnet-sdk-3.0, since it's not a package in this image -sed -i '/dotnet-sdk-3.0,/d' debian/control +# Remove build-dep for dotnet-sdk-3.1, since it's not a package in this image +sed -i '/dotnet-sdk-3.1,/d' debian/control # Build DEB export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} diff --git a/deployment/debian-package-x64/Dockerfile b/deployment/debian-package-x64/Dockerfile index 36e8cf322..e863d1edf 100644 --- a/deployment/debian-package-x64/Dockerfile +++ b/deployment/debian-package-x64/Dockerfile @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/debian-package-x64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/debian-package-x64/docker-build.sh b/deployment/debian-package-x64/docker-build.sh index bb27bc7ee..962a522eb 100755 --- a/deployment/debian-package-x64/docker-build.sh +++ b/deployment/debian-package-x64/docker-build.sh @@ -8,8 +8,8 @@ set -o xtrace # Move to source directory pushd ${SOURCE_DIR} -# Remove build-dep for dotnet-sdk-3.0, since it's not a package in this image -sed -i '/dotnet-sdk-3.0,/d' debian/control +# Remove build-dep for dotnet-sdk-3.1, since it's not a package in this image +sed -i '/dotnet-sdk-3.1,/d' debian/control # Build DEB dpkg-buildpackage -us -uc diff --git a/deployment/debian-package-x64/pkg-src/control b/deployment/debian-package-x64/pkg-src/control index 07e82069f..13fd3ecab 100644 --- a/deployment/debian-package-x64/pkg-src/control +++ b/deployment/debian-package-x64/pkg-src/control @@ -3,7 +3,7 @@ Section: misc Priority: optional Maintainer: Jellyfin Team Build-Depends: debhelper (>= 9), - dotnet-sdk-3.0, + dotnet-sdk-3.1, libc6-dev, libcurl4-openssl-dev, libfontconfig1-dev, diff --git a/deployment/fedora-package-x64/Dockerfile b/deployment/fedora-package-x64/Dockerfile index 769c62ab2..f5c3ab7a6 100644 --- a/deployment/fedora-package-x64/Dockerfile +++ b/deployment/fedora-package-x64/Dockerfile @@ -3,7 +3,7 @@ FROM fedora:29 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/fedora-package-x64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist diff --git a/deployment/fedora-package-x64/pkg-src/jellyfin.spec b/deployment/fedora-package-x64/pkg-src/jellyfin.spec index 7118fcf3f..914f3d44a 100644 --- a/deployment/fedora-package-x64/pkg-src/jellyfin.spec +++ b/deployment/fedora-package-x64/pkg-src/jellyfin.spec @@ -38,7 +38,7 @@ Requires: libcurl, fontconfig, freetype, openssl, glibc libicu # Requirements not packaged in main repos # COPR @dotnet-sig/dotnet or # https://packages.microsoft.com/rhel/7/prod/ -BuildRequires: dotnet-runtime-3.0, dotnet-sdk-3.0 +BuildRequires: dotnet-runtime-3.1, dotnet-sdk-3.1 # RPMfusion free Requires: ffmpeg diff --git a/deployment/linux-x64/Dockerfile b/deployment/linux-x64/Dockerfile index 169d07a57..c47057546 100644 --- a/deployment/linux-x64/Dockerfile +++ b/deployment/linux-x64/Dockerfile @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/linux-x64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/macos/Dockerfile b/deployment/macos/Dockerfile index c8b4e80bf..b522df884 100644 --- a/deployment/macos/Dockerfile +++ b/deployment/macos/Dockerfile @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/macos ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/portable/Dockerfile b/deployment/portable/Dockerfile index 17297a298..965eb82b8 100644 --- a/deployment/portable/Dockerfile +++ b/deployment/portable/Dockerfile @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/portable ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/ubuntu-package-arm64/Dockerfile.amd64 b/deployment/ubuntu-package-arm64/Dockerfile.amd64 index fac00ffea..ac4f7404d 100644 --- a/deployment/ubuntu-package-arm64/Dockerfile.amd64 +++ b/deployment/ubuntu-package-arm64/Dockerfile.amd64 @@ -3,7 +3,7 @@ FROM ubuntu:bionic ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-arm64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/ubuntu-package-arm64/Dockerfile.arm64 b/deployment/ubuntu-package-arm64/Dockerfile.arm64 index 304cd0efd..af7084459 100644 --- a/deployment/ubuntu-package-arm64/Dockerfile.arm64 +++ b/deployment/ubuntu-package-arm64/Dockerfile.arm64 @@ -3,7 +3,7 @@ FROM ubuntu:bionic ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-arm64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/89fb60b1-3359-414e-94cf-359f57f37c7c/256e6dac8f44f9bad01f23f9a27b01ee/dotnet-sdk-3.0.101-linux-arm64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/5a4c8f96-1c73-401c-a6de-8e100403188a/0ce6ab39747e2508366d498f9c0a0669/dotnet-sdk-3.1.100-linux-arm64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/ubuntu-package-arm64/docker-build.sh b/deployment/ubuntu-package-arm64/docker-build.sh index b36b928ba..67ab6bd74 100755 --- a/deployment/ubuntu-package-arm64/docker-build.sh +++ b/deployment/ubuntu-package-arm64/docker-build.sh @@ -8,8 +8,8 @@ set -o xtrace # Move to source directory pushd ${SOURCE_DIR} -# Remove build-dep for dotnet-sdk-3.0, since it's not a package in this image -sed -i '/dotnet-sdk-3.0,/d' debian/control +# Remove build-dep for dotnet-sdk-3.1, since it's not a package in this image +sed -i '/dotnet-sdk-3.1,/d' debian/control # Build DEB export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} diff --git a/deployment/ubuntu-package-armhf/Dockerfile.amd64 b/deployment/ubuntu-package-armhf/Dockerfile.amd64 index 3c6053775..590eecab7 100644 --- a/deployment/ubuntu-package-armhf/Dockerfile.amd64 +++ b/deployment/ubuntu-package-armhf/Dockerfile.amd64 @@ -3,7 +3,7 @@ FROM ubuntu:bionic ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-armhf ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/ubuntu-package-armhf/Dockerfile.armhf b/deployment/ubuntu-package-armhf/Dockerfile.armhf index 1d019bf2d..06a8dace2 100644 --- a/deployment/ubuntu-package-armhf/Dockerfile.armhf +++ b/deployment/ubuntu-package-armhf/Dockerfile.armhf @@ -3,7 +3,7 @@ FROM ubuntu:bionic ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-armhf ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/0b30374c-3d52-45ad-b4e5-9a39d0bf5bf0/deb17f7b32968b3a2186650711456152/dotnet-sdk-3.0.101-linux-arm.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/67766a96-eb8c-4cd2-bca4-ea63d2cc115c/7bf13840aa2ed88793b7315d5e0d74e6/dotnet-sdk-3.1.100-linux-arm.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/ubuntu-package-armhf/docker-build.sh b/deployment/ubuntu-package-armhf/docker-build.sh index 1b3af9a93..1bd7fb291 100755 --- a/deployment/ubuntu-package-armhf/docker-build.sh +++ b/deployment/ubuntu-package-armhf/docker-build.sh @@ -8,8 +8,8 @@ set -o xtrace # Move to source directory pushd ${SOURCE_DIR} -# Remove build-dep for dotnet-sdk-3.0, since it's not a package in this image -sed -i '/dotnet-sdk-3.0,/d' debian/control +# Remove build-dep for dotnet-sdk-3.1, since it's not a package in this image +sed -i '/dotnet-sdk-3.1,/d' debian/control # Build DEB export CONFIG_SITE=/etc/dpkg-cross/cross-config.${ARCH} diff --git a/deployment/ubuntu-package-x64/Dockerfile b/deployment/ubuntu-package-x64/Dockerfile index d881c04e3..8237ced29 100644 --- a/deployment/ubuntu-package-x64/Dockerfile +++ b/deployment/ubuntu-package-x64/Dockerfile @@ -3,7 +3,7 @@ FROM ubuntu:bionic ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/ubuntu-package-x64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -18,7 +18,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/ubuntu-package-x64/docker-build.sh b/deployment/ubuntu-package-x64/docker-build.sh index bb27bc7ee..962a522eb 100755 --- a/deployment/ubuntu-package-x64/docker-build.sh +++ b/deployment/ubuntu-package-x64/docker-build.sh @@ -8,8 +8,8 @@ set -o xtrace # Move to source directory pushd ${SOURCE_DIR} -# Remove build-dep for dotnet-sdk-3.0, since it's not a package in this image -sed -i '/dotnet-sdk-3.0,/d' debian/control +# Remove build-dep for dotnet-sdk-3.1, since it's not a package in this image +sed -i '/dotnet-sdk-3.1,/d' debian/control # Build DEB dpkg-buildpackage -us -uc diff --git a/deployment/win-x64/Dockerfile b/deployment/win-x64/Dockerfile index 0f85a07d8..8a3374954 100644 --- a/deployment/win-x64/Dockerfile +++ b/deployment/win-x64/Dockerfile @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/win-x64 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet diff --git a/deployment/win-x86/Dockerfile b/deployment/win-x86/Dockerfile index f07a8d7fe..f8dc5be83 100644 --- a/deployment/win-x86/Dockerfile +++ b/deployment/win-x86/Dockerfile @@ -3,7 +3,7 @@ FROM debian:10 ARG SOURCE_DIR=/jellyfin ARG PLATFORM_DIR=/jellyfin/deployment/win-x86 ARG ARTIFACT_DIR=/dist -ARG SDK_VERSION=3.0 +ARG SDK_VERSION=3.1 # Docker run environment ENV SOURCE_DIR=/jellyfin ENV ARTIFACT_DIR=/dist @@ -16,7 +16,7 @@ RUN apt-get update \ # Install dotnet repository # https://dotnet.microsoft.com/download/linux-package-manager/debian9/sdk-current -RUN wget https://download.visualstudio.microsoft.com/download/pr/4f51cfd8-311d-43fe-a887-c80b40358cfd/440d10dc2091b8d0f1a12b7124034e49/dotnet-sdk-3.0.101-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ +RUN wget https://download.visualstudio.microsoft.com/download/pr/d731f991-8e68-4c7c-8ea0-fad5605b077a/49497b5420eecbd905158d86d738af64/dotnet-sdk-3.1.100-linux-x64.tar.gz -O dotnet-sdk.tar.gz \ && mkdir -p dotnet-sdk \ && tar -xzf dotnet-sdk.tar.gz -C dotnet-sdk \ && ln -s $( pwd )/dotnet-sdk/dotnet /usr/bin/dotnet -- cgit v1.2.3 From aa7aadb2b21f09b14fb99b9f4e3282e57164a0ea Mon Sep 17 00:00:00 2001 From: Cota Fainado <20hvoby5pb@protonmail.com> Date: Sat, 4 Jan 2020 23:01:24 +0000 Subject: Added translation using Weblate (Portuguese) --- Emby.Server.Implementations/Localization/Core/pt.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 Emby.Server.Implementations/Localization/Core/pt.json diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json new file mode 100644 index 000000000..0967ef424 --- /dev/null +++ b/Emby.Server.Implementations/Localization/Core/pt.json @@ -0,0 +1 @@ +{} -- cgit v1.2.3 From 0b592376d59d10d14dbdd248c24f7ec6397c3508 Mon Sep 17 00:00:00 2001 From: Constantin Matel Date: Fri, 3 Jan 2020 15:38:12 +0000 Subject: Translated using Weblate (Romanian) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/ro/ --- .../Localization/Core/ro.json | 97 +++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/ro.json b/Emby.Server.Implementations/Localization/Core/ro.json index 0967ef424..b871626f0 100644 --- a/Emby.Server.Implementations/Localization/Core/ro.json +++ b/Emby.Server.Implementations/Localization/Core/ro.json @@ -1 +1,96 @@ -{} +{ + "HeaderNextUp": "Urmează", + "VersionNumber": "Versiunea {0}", + "ValueSpecialEpisodeName": "Special - {0}", + "ValueHasBeenAddedToLibrary": "{0} a fost adăugat la biblioteca multimedia", + "UserStoppedPlayingItemWithValues": "{0} a terminat rularea {1} pe {2}", + "UserStartedPlayingItemWithValues": "{0} ruleaza {1} pe {2}", + "UserPolicyUpdatedWithName": "Politica utilizatorului {0} a fost actualizată", + "UserPasswordChangedWithName": "Parola utilizatorului {0} a fost schimbată", + "UserOnlineFromDevice": "{0} este conectat de la {1}", + "UserOfflineFromDevice": "{0} s-a deconectat de la {1}", + "UserLockedOutWithName": "Utilizatorul {0} a fost blocat", + "UserDownloadingItemWithValues": "{0} descarcă {1}", + "UserDeletedWithName": "Utilizatorul {0} a fost eliminat", + "UserCreatedWithName": "Utilizatorul {0} a fost creat", + "User": "Utilizator", + "TvShows": "Spectacole TV", + "System": "Sistem", + "Sync": "Sincronizare", + "SubtitlesDownloadedForItem": "Subtitrari descarcate pentru {0}", + "SubtitleDownloadFailureFromForItem": "Subtitrările nu au putut fi descărcate de la {0} pentru {1}", + "StartupEmbyServerIsLoading": "Se încarcă serverul Jellyfin. Încercați din nou în scurt timp.", + "Songs": "Melodii", + "Shows": "Spectacole", + "ServerNameNeedsToBeRestarted": "{0} trebuie repornit", + "ScheduledTaskStartedWithName": "{0} pornit/ă", + "ScheduledTaskFailedWithName": "{0} eșuat/ă", + "ProviderValue": "Furnizor: {0}", + "PluginUpdatedWithName": "{0} a fost actualizat/ă", + "PluginUninstalledWithName": "{0} a fost dezinstalat", + "PluginInstalledWithName": "{0} a fost instalat", + "Plugin": "Complement", + "Playlists": "Liste redare", + "Photos": "Fotografii", + "NotificationOptionVideoPlaybackStopped": "Redarea video oprită", + "NotificationOptionVideoPlayback": "Începută redarea video", + "NotificationOptionUserLockedOut": "Utilizatorul a fost blocat", + "NotificationOptionTaskFailed": "Activitate programata eșuată", + "NotificationOptionServerRestartRequired": "Este necesară repornirea Serverului", + "NotificationOptionPluginUpdateInstalled": "Actualizare plugin instalată", + "NotificationOptionPluginUninstalled": "Plugin dezinstalat", + "NotificationOptionPluginInstalled": "Plugin instalat", + "NotificationOptionPluginError": "Plugin-ul a eșuat", + "NotificationOptionNewLibraryContent": "Adăugat conținut nou", + "NotificationOptionInstallationFailed": "Eșec la instalare", + "NotificationOptionCameraImageUploaded": "Încarcată imagine cameră", + "NotificationOptionAudioPlaybackStopped": "Redare audio oprită", + "NotificationOptionAudioPlayback": "A inceput redarea audio", + "NotificationOptionApplicationUpdateInstalled": "Actualizarea aplicației a fost instalată", + "NotificationOptionApplicationUpdateAvailable": "Disponibilă o actualizare a aplicației", + "NewVersionIsAvailable": "O nouă versiune a Jellyfin Server este disponibilă pentru descărcare.", + "NameSeasonUnknown": "Sezon Necunoscut", + "NameSeasonNumber": "Sezonul {0}", + "NameInstallFailed": "{0} instalare eșuată", + "MusicVideos": "Videoclipuri muzicale", + "Music": "Muzică", + "Movies": "Filme", + "MixedContent": "Conținut mixt", + "MessageServerConfigurationUpdated": "Configurația serverului a fost actualizată", + "MessageNamedServerConfigurationUpdatedWithValue": "Secțiunea de configurare a serverului {0} a fost acualizata", + "MessageApplicationUpdatedTo": "Jellyfin Server a fost actualizat la {0}", + "MessageApplicationUpdated": "Jellyfin Server a fost actualizat", + "Latest": "Cele mai recente", + "LabelRunningTimeValue": "Durată: {0}", + "LabelIpAddressValue": "Adresa IP: {0}", + "ItemRemovedWithName": "{0} a fost eliminat din bibliotecă", + "ItemAddedWithName": "{0} a fost adăugat în bibliotecă", + "Inherit": "moștenit", + "HomeVideos": "Videoclipuri personale", + "HeaderRecordingGroups": "Grupuri de înregistrare", + "HeaderLiveTV": "TV în Direct", + "HeaderFavoriteSongs": "Melodii Favorite", + "HeaderFavoriteShows": "Spectacole Favorite", + "HeaderFavoriteEpisodes": "Episoade Favorite", + "HeaderFavoriteArtists": "Artiști Favoriți", + "HeaderFavoriteAlbums": "Albume Favorite", + "HeaderContinueWatching": "Vizionează în continuare", + "HeaderCameraUploads": "Incărcări Cameră Foto", + "HeaderAlbumArtists": "Album Artiști", + "Genres": "Genuri", + "Folders": "Dosare", + "Favorites": "Favorite", + "FailedLoginAttemptWithUserName": "Încercare de conectare nereușită de la {0}", + "DeviceOnlineWithName": "{0} este conectat", + "DeviceOfflineWithName": "{0} s-a deconectat", + "Collections": "Colecții", + "ChapterNameValue": "Capitol {0}", + "Channels": "Canale", + "CameraImageUploadedFrom": "O nouă fotografie a fost încărcată din {0}", + "Books": "Cărți", + "AuthenticationSucceededWithUserName": "{0} autentificare reușită", + "Artists": "Artiști", + "Application": "Aplicație", + "AppDeviceValues": "Aplicație: {0}, Dispozitiv: {1}", + "Albums": "Albume" +} -- cgit v1.2.3 From e5e0166951414044b4c251fc562bb8d40620ca1f Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 5 Jan 2020 15:59:31 +0900 Subject: update dotnet version for ci --- .ci/azure-pipelines.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index 13cc67528..6e6cd0058 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -66,6 +66,12 @@ jobs: overWrite: true # Optional flattenFolders: false # Optional + - task: UseDotNet@2 + displayName: Use Correct DotNet Version + inputs: + packageType: sdk + version: 3.1.100 + - task: DotNetCoreCLI@2 displayName: Publish inputs: -- cgit v1.2.3 From f1008ab58d1b7dc9139f31e0a60f15e4be96aa4f Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 5 Jan 2020 16:01:42 +0900 Subject: update job names --- .ci/azure-pipelines.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index 6e6cd0058..992753623 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -19,9 +19,9 @@ jobs: vmImage: ubuntu-latest strategy: matrix: - release: + Release: BuildConfiguration: Release - debug: + Debug: BuildConfiguration: Debug maxParallel: 2 steps: @@ -191,12 +191,12 @@ jobs: # #publishRunAttachments: true # Optional - job: main_build_win - displayName: Main Build Windows + displayName: Publish Windows pool: vmImage: windows-latest strategy: matrix: - release: + Release: BuildConfiguration: Release maxParallel: 2 steps: @@ -373,5 +373,3 @@ jobs: script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines' workingDirectory: $(System.ArtifactsDirectory) # Optional #failOnStderr: false # Optional - - -- cgit v1.2.3 From 303385dfa2799df9162aeb64294991b3bd4108c8 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 5 Jan 2020 16:08:19 +0900 Subject: remove unused parameters --- .ci/azure-pipelines.yml | 61 +------------------------------------------------ 1 file changed, 1 insertion(+), 60 deletions(-) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index 992753623..7427190e6 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -141,54 +141,12 @@ jobs: !**\obj\** !**\xunit.runner.visualstudio.testadapter.dll !**\xunit.runner.visualstudio.dotnetcore.testadapter.dll - #testPlan: # Required when testSelector == TestPlan - #testSuite: # Required when testSelector == TestPlan - #testConfiguration: # Required when testSelector == TestPlan - #tcmTestRun: '$(test.RunId)' # Optional searchFolder: '$(System.DefaultWorkingDirectory)' - #testFiltercriteria: # Optional - #runOnlyImpactedTests: False # Optional - #runAllTestsAfterXBuilds: '50' # Optional - #uiTests: false # Optional - #vstestLocationMethod: 'version' # Optional. Options: version, location - #vsTestVersion: 'latest' # Optional. Options: latest, 16.0, 15.0, 14.0, toolsInstaller - #vstestLocation: # Optional - #runSettingsFile: # Optional - #overrideTestrunParameters: # Optional - #pathtoCustomTestAdapters: # Optional runInParallel: True # Optional runTestsInIsolation: True # Optional codeCoverageEnabled: True # Optional - #otherConsoleOptions: # Optional - #distributionBatchType: 'basedOnTestCases' # Optional. Options: basedOnTestCases, basedOnExecutionTime, basedOnAssembly - #batchingBasedOnAgentsOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customBatchSize - #customBatchSizeValue: '10' # Required when distributionBatchType == BasedOnTestCases && BatchingBasedOnAgentsOption == CustomBatchSize - #batchingBasedOnExecutionTimeOption: 'autoBatchSize' # Optional. Options: autoBatchSize, customTimeBatchSize - #customRunTimePerBatchValue: '60' # Required when distributionBatchType == BasedOnExecutionTime && BatchingBasedOnExecutionTimeOption == CustomTimeBatchSize - #dontDistribute: False # Optional - #testRunTitle: # Optional - #platform: # Optional configuration: 'Debug' # Optional publishRunAttachments: true # Optional - #diagnosticsEnabled: false # Optional - #collectDumpOn: 'onAbortOnly' # Optional. Options: onAbortOnly, always, never - #rerunFailedTests: False # Optional - #rerunType: 'basedOnTestFailurePercentage' # Optional. Options: basedOnTestFailurePercentage, basedOnTestFailureCount - #rerunFailedThreshold: '30' # Optional - #rerunFailedTestCasesMaxLimit: '5' # Optional - #rerunMaxAttempts: '3' # Optional - - # - task: PublishTestResults@2 - # inputs: - # testResultsFormat: 'VSTest' # Options: JUnit, NUnit, VSTest, xUnit, cTest - # testResultsFiles: '**/*.trx' - # #searchFolder: '$(System.DefaultWorkingDirectory)' # Optional - # mergeTestResults: true # Optional - # #failTaskOnFailedTests: false # Optional - # #testRunTitle: # Optional - # #buildPlatform: # Optional - # #buildConfiguration: # Optional - # #publishRunAttachments: true # Optional - job: main_build_win displayName: Publish Windows @@ -252,11 +210,7 @@ jobs: targetType: 'filePath' # Optional. Options: filePath, inline filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath arguments: -InstallFFMPEG -InstallNSSM -MakeNSIS -InstallTrayApp -UXLocation $(Agent.TempDirectory)\jellyfin-ux -InstallLocation $(build.artifactstagingdirectory) - #script: '# Write your PowerShell commands here.Write-Host Hello World' # Required when targetType == Inline errorActionPreference: 'stop' # Optional. Options: stop, continue, silentlyContinue - #failOnStderr: false # Optional - #ignoreLASTEXITCODE: false # Optional - #pwsh: false # Optional workingDirectory: $(Build.SourcesDirectory) # Optional - task: CopyFiles@2 @@ -304,16 +258,9 @@ jobs: displayName: Download the New Assembly Build Artifact inputs: source: 'current' # Options: current, specific - #preferTriggeringPipeline: false # Optional - #tags: # Optional artifact: '$(NugetPackageName)' # Optional - #patterns: '**' # Optional path: '$(System.ArtifactsDirectory)/new-artifacts' - #project: # Required when source == Specific - #pipeline: # Required when source == Specific runVersion: 'latest' # Required when source == Specific. Options: latest, latestFromBranch, specific - #runBranch: 'refs/heads/master' # Required when source == Specific && runVersion == LatestFromBranch - #runId: # Required when source == Specific && runVersion == Specific - task: CopyFiles@2 displayName: Copy New Assembly to new-release folder @@ -329,16 +276,12 @@ jobs: displayName: Download the Reference Assembly Build Artifact inputs: source: 'specific' # Options: current, specific - #preferTriggeringPipeline: false # Optional - #tags: # Optional artifact: '$(NugetPackageName)' # Optional - #patterns: '**' # Optional path: '$(System.ArtifactsDirectory)/current-artifacts' project: '$(System.TeamProjectId)' # Required when source == Specific pipeline: '$(System.DefinitionId)' # Required when source == Specific runVersion: 'latestFromBranch' # Required when source == Specific. Options: latest, latestFromBranch, specific runBranch: 'refs/heads/$(System.PullRequest.TargetBranch)' # Required when source == Specific && runVersion == LatestFromBranch - #runId: # Required when source == Specific && runVersion == Specific - task: CopyFiles@2 displayName: Copy Reference Assembly to current-release folder @@ -356,7 +299,6 @@ jobs: connection: Jellyfin Release Download userRepository: EraYaN/dotnet-compatibility defaultVersionType: 'latest' # Options: latest, specificVersion, specificTag - #version: # Required when defaultVersionType != Latest itemPattern: '**-ci.zip' # Optional downloadPath: '$(System.ArtifactsDirectory)' @@ -371,5 +313,4 @@ jobs: displayName: Execute ABI compatibility check tool inputs: script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines' - workingDirectory: $(System.ArtifactsDirectory) # Optional - #failOnStderr: false # Optional + workingDirectory: $(System.ArtifactsDirectory) -- cgit v1.2.3 From c7d5f35eb7e246191eb2d861eec8eb35be86a277 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 5 Jan 2020 16:32:24 +0900 Subject: update display names for some ci steps --- .ci/azure-pipelines.yml | 48 ++++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index 7427190e6..6d2a0a42b 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -31,32 +31,32 @@ jobs: persistCredentials: true - task: CmdLine@2 - displayName: "Check out web" + displayName: "Clone Web Client (Master, Release, or Tag)" condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web' - task: CmdLine@2 - displayName: "Check out web (PR)" + displayName: "Clone Web Client (PR)" condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest')) inputs: script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web' - task: NodeTool@0 - displayName: 'Install Node.js' + displayName: 'Install Node' condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: versionSpec: '10.x' - task: CmdLine@2 - displayName: "Build Web UI" + displayName: "Build Web Client" condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: script: yarn install workingDirectory: $(Agent.TempDirectory)/jellyfin-web - task: CopyFiles@2 - displayName: Copy the web UI + displayName: 'Copy Web Client' condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional @@ -67,13 +67,13 @@ jobs: flattenFolders: false # Optional - task: UseDotNet@2 - displayName: Use Correct DotNet Version + displayName: 'Update DotNet' inputs: packageType: sdk version: 3.1.100 - task: DotNetCoreCLI@2 - displayName: Publish + displayName: 'Publish Server' inputs: command: publish publishWebProjects: false @@ -164,32 +164,32 @@ jobs: persistCredentials: true - task: CmdLine@2 - displayName: "Check out web (master, release or tag)" + displayName: "Clone Web Client (Master, Release, or Tag)" condition: and(succeeded(), or(contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master'), contains(variables['Build.SourceBranch'], 'tag')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: script: 'git clone --single-branch --branch $(Build.SourceBranchName) --depth=1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web' - task: CmdLine@2 - displayName: "Check out web (PR)" + displayName: "Clone Web Client (PR)" condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest')) inputs: script: 'git clone --single-branch --branch $(System.PullRequest.TargetBranch) --depth 1 https://github.com/jellyfin/jellyfin-web.git $(Agent.TempDirectory)/jellyfin-web' - task: NodeTool@0 - displayName: 'Install Node.js' + displayName: 'Install Node' condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: versionSpec: '10.x' - task: CmdLine@2 - displayName: "Build Web UI" + displayName: "Build Web Client" condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: script: yarn install workingDirectory: $(Agent.TempDirectory)/jellyfin-web - task: CopyFiles@2 - displayName: Copy the web UI + displayName: 'Copy Web Client' condition: and(succeeded(), or(contains(variables['System.PullRequest.TargetBranch'], 'release'), contains(variables['System.PullRequest.TargetBranch'], 'master'), contains(variables['Build.SourceBranch'], 'release'), contains(variables['Build.SourceBranch'], 'master')) ,eq(variables['BuildConfiguration'], 'Release'), in(variables['Build.Reason'], 'PullRequest', 'IndividualCI', 'BatchedCI', 'BuildCompletion')) inputs: sourceFolder: $(Agent.TempDirectory)/jellyfin-web/dist # Optional @@ -200,12 +200,12 @@ jobs: flattenFolders: false # Optional - task: CmdLine@2 - displayName: Clone the UX repository + displayName: 'Clone UX Repository' inputs: script: git clone --depth=1 https://github.com/jellyfin/jellyfin-ux $(Agent.TempDirectory)\jellyfin-ux - task: PowerShell@2 - displayName: Build the NSIS Installer + displayName: 'Build NSIS Installer' inputs: targetType: 'filePath' # Optional. Options: filePath, inline filePath: ./deployment/windows/build-jellyfin.ps1 # Required when targetType == FilePath @@ -214,7 +214,7 @@ jobs: workingDirectory: $(Build.SourcesDirectory) # Optional - task: CopyFiles@2 - displayName: Copy the NSIS Installer to the artifact directory + displayName: 'Copy NSIS Installer' inputs: sourceFolder: $(Build.SourcesDirectory)/deployment/windows/ # Optional contents: 'jellyfin*.exe' @@ -224,7 +224,7 @@ jobs: flattenFolders: true # Optional - task: PublishPipelineArtifact@0 - displayName: 'Publish Setup Artifact' + displayName: 'Publish Artifact Setup' condition: and(eq(variables['BuildConfiguration'], 'Release'), succeeded()) inputs: targetPath: '$(build.artifactstagingdirectory)/setup' @@ -255,7 +255,7 @@ jobs: - checkout: none - task: DownloadPipelineArtifact@2 - displayName: Download the New Assembly Build Artifact + displayName: 'Download New Assembly Build Artifact' inputs: source: 'current' # Options: current, specific artifact: '$(NugetPackageName)' # Optional @@ -263,7 +263,7 @@ jobs: runVersion: 'latest' # Required when source == Specific. Options: latest, latestFromBranch, specific - task: CopyFiles@2 - displayName: Copy New Assembly to new-release folder + displayName: 'Copy New Assembly Build Artifact' inputs: sourceFolder: $(System.ArtifactsDirectory)/new-artifacts # Optional contents: '**/*.dll' @@ -273,7 +273,7 @@ jobs: flattenFolders: true # Optional - task: DownloadPipelineArtifact@2 - displayName: Download the Reference Assembly Build Artifact + displayName: 'Download Reference Assembly Build Artifact' inputs: source: 'specific' # Options: current, specific artifact: '$(NugetPackageName)' # Optional @@ -284,7 +284,7 @@ jobs: runBranch: 'refs/heads/$(System.PullRequest.TargetBranch)' # Required when source == Specific && runVersion == LatestFromBranch - task: CopyFiles@2 - displayName: Copy Reference Assembly to current-release folder + displayName: 'Copy Reference Assembly Build Artifact' inputs: sourceFolder: $(System.ArtifactsDirectory)/current-artifacts # Optional contents: '**/*.dll' @@ -294,7 +294,7 @@ jobs: flattenFolders: true # Optional - task: DownloadGitHubRelease@0 - displayName: Download ABI compatibility check tool from GitHub + displayName: 'Download ABI Compatibility Check Tool' inputs: connection: Jellyfin Release Download userRepository: EraYaN/dotnet-compatibility @@ -303,14 +303,14 @@ jobs: downloadPath: '$(System.ArtifactsDirectory)' - task: ExtractFiles@1 - displayName: Extract ABI compatibility check tool + displayName: 'Extract ABI Compatibility Check Tool' inputs: archiveFilePatterns: '$(System.ArtifactsDirectory)/*-ci.zip' destinationFolder: $(System.ArtifactsDirectory)/tools cleanDestinationFolder: true - task: CmdLine@2 - displayName: Execute ABI compatibility check tool + displayName: 'Execute ABI Compatibility Check Tool' inputs: script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines' - workingDirectory: $(System.ArtifactsDirectory) + workingDirectory: $(System.ArtifactsDirectory) # Optional -- cgit v1.2.3 From d59912450819f6b9e8cb5b2e8eeb70c4d9de1465 Mon Sep 17 00:00:00 2001 From: dkanada Date: Sun, 5 Jan 2020 16:39:48 +0900 Subject: manually disable compatibility check --- .ci/azure-pipelines.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index 6d2a0a42b..fef2ecda9 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -235,7 +235,9 @@ jobs: pool: vmImage: ubuntu-latest dependsOn: main_build - condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber']) # Only execute if the pullrequest numer is defined. (So not for normal CI builds) + # disabled until ABI is expected to remain unchanged + # only execute for pull requests + condition: and(eq(1, 2), succeeded(), variables['System.PullRequest.PullRequestNumber']) strategy: matrix: Naming: -- cgit v1.2.3 From 2ca7200a0526e5374f0b0e10d6f5d22965bacaa5 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Sun, 5 Jan 2020 19:24:24 +0100 Subject: Updated for v0.0.5 of the compat checker. --- .ci/azure-pipelines.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index fef2ecda9..ba9989e70 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -311,8 +311,9 @@ jobs: destinationFolder: $(System.ArtifactsDirectory)/tools cleanDestinationFolder: true + # The `--warnings-only` switch will swallow the return code and not emit any errors. - task: CmdLine@2 displayName: 'Execute ABI Compatibility Check Tool' inputs: - script: 'dotnet tools/CompatibilityCheckerCoreCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines' + script: 'dotnet tools/CompatibilityCheckerCLI.dll current-release/$(AssemblyFileName) new-release/$(AssemblyFileName) --azure-pipelines --warnings-only' workingDirectory: $(System.ArtifactsDirectory) # Optional -- cgit v1.2.3 From 65f65db8b9c7dcc2022ff6542a50481cb8d0cabf Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Sun, 5 Jan 2020 19:25:33 +0100 Subject: Re-enable compat checks. --- .ci/azure-pipelines.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index ba9989e70..e5d09b0ab 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -235,9 +235,8 @@ jobs: pool: vmImage: ubuntu-latest dependsOn: main_build - # disabled until ABI is expected to remain unchanged # only execute for pull requests - condition: and(eq(1, 2), succeeded(), variables['System.PullRequest.PullRequestNumber']) + condition: and(succeeded(), variables['System.PullRequest.PullRequestNumber']) strategy: matrix: Naming: -- cgit v1.2.3 From 21b78f44c8efe7eaa01430f23075d605c3d05356 Mon Sep 17 00:00:00 2001 From: Erwin de Haan Date: Sun, 5 Jan 2020 19:30:32 +0100 Subject: Add new dotnet version to compat stage as well. --- .ci/azure-pipelines.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.ci/azure-pipelines.yml b/.ci/azure-pipelines.yml index e5d09b0ab..143873266 100644 --- a/.ci/azure-pipelines.yml +++ b/.ci/azure-pipelines.yml @@ -254,6 +254,12 @@ jobs: maxParallel: 2 steps: - checkout: none + + - task: UseDotNet@2 + displayName: 'Update DotNet' + inputs: + packageType: sdk + version: 3.1.100 - task: DownloadPipelineArtifact@2 displayName: 'Download New Assembly Build Artifact' -- cgit v1.2.3 From 0a483c83f94983e8e12acc8643c26452a3cb5536 Mon Sep 17 00:00:00 2001 From: Cota Fainado <20hvoby5pb@protonmail.com> Date: Sat, 4 Jan 2020 23:03:09 +0000 Subject: Translated using Weblate (Portuguese) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/ --- .../Localization/Core/pt.json | 97 +++++++++++++++++++++- 1 file changed, 96 insertions(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json index 0967ef424..c8d4b4c32 100644 --- a/Emby.Server.Implementations/Localization/Core/pt.json +++ b/Emby.Server.Implementations/Localization/Core/pt.json @@ -1 +1,96 @@ -{} +{ + "HeaderLiveTV": "TV em Directo", + "Collections": "Colecções", + "Books": "Livros", + "Artists": "Artistas", + "Albums": "Álbuns", + "HeaderNextUp": "A Seguir", + "HeaderFavoriteSongs": "Músicas Favoritas", + "HeaderFavoriteArtists": "Artistas Favoritos", + "HeaderFavoriteAlbums": "Álbuns Favoritos", + "HeaderFavoriteEpisodes": "Episódios Favoritos", + "HeaderFavoriteShows": "Séries Favoritas", + "HeaderContinueWatching": "Continuar a Ver", + "HeaderAlbumArtists": "Artistas do Álbum", + "Genres": "Géneros", + "Folders": "Pastas", + "Favorites": "Favoritos", + "Channels": "Canais", + "UserDownloadingItemWithValues": "{0} está a transferir {1}", + "VersionNumber": "Versão {0}", + "ValueHasBeenAddedToLibrary": "{0} foi adicionado à sua biblioteca multimédia", + "UserStoppedPlayingItemWithValues": "{0} terminou a reprodução de {1} em {2}", + "UserStartedPlayingItemWithValues": "{0} está a reproduzir {1} em {2}", + "UserPolicyUpdatedWithName": "A política do utilizador {0} foi alterada", + "UserPasswordChangedWithName": "A palavra-passe do utilizador {0} foi alterada", + "UserOnlineFromDevice": "{0} ligou-se a partir de {1}", + "UserOfflineFromDevice": "{0} desligou-se a partir de {1}", + "UserLockedOutWithName": "Utilizador {0} bloqueado", + "UserDeletedWithName": "Utilizador {0} removido", + "UserCreatedWithName": "Utilizador {0} criado", + "User": "Utilizador", + "TvShows": "Programas", + "System": "Sistema", + "SubtitlesDownloadedForItem": "Legendas transferidas para {0}", + "SubtitleDownloadFailureFromForItem": "Falha na transferência de legendas de {0} para {1}", + "StartupEmbyServerIsLoading": "O servidor Jellyfin está a iniciar. Tente novamente dentro de momentos.", + "ServerNameNeedsToBeRestarted": "{0} necessita ser reiniciado", + "ScheduledTaskStartedWithName": "{0} iniciou", + "ScheduledTaskFailedWithName": "{0} falhou", + "ProviderValue": "Fornecedor: {0}", + "PluginUpdatedWithName": "{0} foi actualizado", + "PluginUninstalledWithName": "{0} foi desinstalado", + "PluginInstalledWithName": "{0} foi instalado", + "Plugin": "Extensão", + "NotificationOptionVideoPlaybackStopped": "Reprodução de vídeo parada", + "NotificationOptionVideoPlayback": "Reprodução de vídeo iniciada", + "NotificationOptionUserLockedOut": "Utilizador bloqueado", + "NotificationOptionTaskFailed": "Falha em tarefa agendada", + "NotificationOptionServerRestartRequired": "É necessário reiniciar o servidor", + "NotificationOptionPluginUpdateInstalled": "Extensão actualizada", + "NotificationOptionPluginUninstalled": "Extensão desinstalada", + "NotificationOptionPluginInstalled": "Extensão instalada", + "NotificationOptionPluginError": "Falha na extensão", + "NotificationOptionNewLibraryContent": "Novo conteúdo adicionado", + "NotificationOptionInstallationFailed": "Falha de instalação", + "NotificationOptionCameraImageUploaded": "Imagem da câmara enviada", + "NotificationOptionAudioPlaybackStopped": "Reprodução Parada", + "NotificationOptionAudioPlayback": "Reprodução Iniciada", + "NotificationOptionApplicationUpdateInstalled": "A actualização da aplicação foi instalada", + "NotificationOptionApplicationUpdateAvailable": "Uma actualização da aplicação está disponível", + "NewVersionIsAvailable": "Uma nova versão do servidor Jellyfin está disponível para transferência.", + "NameSeasonUnknown": "Temporada Desconhecida", + "NameSeasonNumber": "Temporada {0}", + "NameInstallFailed": "Falha na instalação de {0}", + "MusicVideos": "Videoclips", + "Music": "Música", + "MixedContent": "Conteúdo Misto", + "MessageServerConfigurationUpdated": "A configuração do servidor foi actualizada", + "MessageNamedServerConfigurationUpdatedWithValue": "Configurações do servidor na secção {0} foram atualizadas", + "MessageApplicationUpdatedTo": "O servidor Jellyfin foi actualizado para a versão {0}", + "MessageApplicationUpdated": "O servidor Jellyfin foi actualizado", + "Latest": "Mais Recente", + "LabelRunningTimeValue": "Duração: {0}", + "LabelIpAddressValue": "Endereço IP: {0}", + "ItemRemovedWithName": "{0} foi removido da biblioteca", + "ItemAddedWithName": "{0} foi adicionado à biblioteca", + "Inherit": "Herdar", + "HomeVideos": "Vídeos Caseiros", + "HeaderRecordingGroups": "Grupos de Gravação", + "ValueSpecialEpisodeName": "Especial - {0}", + "Sync": "Sincronização", + "Songs": "Músicas", + "Shows": "Séries", + "Playlists": "Listas de Reprodução", + "Photos": "Fotografias", + "Movies": "Filmes", + "HeaderCameraUploads": "Envios a partir da câmara", + "FailedLoginAttemptWithUserName": "Tentativa de ligação a partir de {0} falhou", + "DeviceOnlineWithName": "{0} ligou-se", + "DeviceOfflineWithName": "{0} desligou-se", + "ChapterNameValue": "Capítulo {0}", + "CameraImageUploadedFrom": "Uma nova imagem de câmara foi enviada a partir de {0}", + "AuthenticationSucceededWithUserName": "{0} autenticado com sucesso", + "Application": "Aplicação", + "AppDeviceValues": "Aplicação {0}, Dispositivo: {1}" +} -- cgit v1.2.3 From a4d0e4b38ee23a7edde067f093580199a1014658 Mon Sep 17 00:00:00 2001 From: Thoscellen Date: Sat, 4 Jan 2020 23:16:08 +0000 Subject: Translated using Weblate (French) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/fr/ --- Emby.Server.Implementations/Localization/Core/fr.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Emby.Server.Implementations/Localization/Core/fr.json b/Emby.Server.Implementations/Localization/Core/fr.json index 9805992be..e1dce82ff 100644 --- a/Emby.Server.Implementations/Localization/Core/fr.json +++ b/Emby.Server.Implementations/Localization/Core/fr.json @@ -19,10 +19,10 @@ "HeaderCameraUploads": "Photos transférées", "HeaderContinueWatching": "Continuer à regarder", "HeaderFavoriteAlbums": "Albums favoris", - "HeaderFavoriteArtists": "Artistes favoris", + "HeaderFavoriteArtists": "Artistes préférés", "HeaderFavoriteEpisodes": "Épisodes favoris", "HeaderFavoriteShows": "Séries favorites", - "HeaderFavoriteSongs": "Chansons favorites", + "HeaderFavoriteSongs": "Chansons préférées", "HeaderLiveTV": "TV en direct", "HeaderNextUp": "À suivre", "HeaderRecordingGroups": "Groupes d'enregistrements", -- cgit v1.2.3 From 80dfc78ba5ec3895fd374a5bd761d0d0e9e6a862 Mon Sep 17 00:00:00 2001 From: samucamg Date: Sun, 5 Jan 2020 21:47:39 +0000 Subject: Translated using Weblate (Portuguese) Translation: Jellyfin/Jellyfin Translate-URL: https://translate.jellyfin.org/projects/jellyfin/jellyfin-core/pt/ --- Emby.Server.Implementations/Localization/Core/pt.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/Localization/Core/pt.json b/Emby.Server.Implementations/Localization/Core/pt.json index c8d4b4c32..ef8d988c8 100644 --- a/Emby.Server.Implementations/Localization/Core/pt.json +++ b/Emby.Server.Implementations/Localization/Core/pt.json @@ -1,5 +1,5 @@ { - "HeaderLiveTV": "TV em Directo", + "HeaderLiveTV": "TV ao Vivo", "Collections": "Colecções", "Books": "Livros", "Artists": "Artistas", -- cgit v1.2.3 From 70210b47a4dedd3d3905fc4d234c0346f58d064f Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Mon, 6 Jan 2020 10:39:01 +0100 Subject: Update MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs Co-Authored-By: dkanada --- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 3067238f7..ff3596a85 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -1345,7 +1345,7 @@ namespace MediaBrowser.MediaEncoding.Probing } } - // REVIEW: + // REVIEW: find out why the byte array needs to be 197 bytes long and comment the reason private TransportStreamTimestamp GetMpegTimestamp(string path) { var packetBuffer = new byte[197]; -- cgit v1.2.3 From 49fef5f09c12ff4b40b7213a9e155802acf45fff Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 7 Jan 2020 11:13:11 +0100 Subject: Update MediaBrowser.MediaEncoding/Probing/MediaChapter.cs Co-Authored-By: Erwin de Haan --- MediaBrowser.MediaEncoding/Probing/MediaChapter.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs index a3607a760..6a45ccf49 100644 --- a/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs +++ b/MediaBrowser.MediaEncoding/Probing/MediaChapter.cs @@ -9,7 +9,7 @@ namespace MediaBrowser.MediaEncoding.Probing public class MediaChapter { [JsonPropertyName("id")] - public int id { get; set; } + public int Id { get; set; } [JsonPropertyName("time_base")] public string TimeBase { get; set; } -- cgit v1.2.3 From 9dfafb9e9fcddb253b157fe03b085b7fceef4290 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Tue, 7 Jan 2020 11:13:47 +0100 Subject: Update MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs Co-Authored-By: Erwin de Haan --- MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs index 6b60b66c0..8af122ef9 100644 --- a/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs +++ b/MediaBrowser.MediaEncoding/Probing/MediaFormatInfo.cs @@ -13,7 +13,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// /// The filename. [JsonPropertyName("filename")] - public string Filename { get; set; } + public string FileName { get; set; } /// /// Gets or sets the nb_streams. -- cgit v1.2.3 From a253fa616da3fd982ca2190b69d25853893665f1 Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 26 Dec 2019 23:09:00 +0100 Subject: Fix build and address comments --- Emby.Server.Implementations/ApplicationHost.cs | 2 +- .../Data/SqliteItemRepository.cs | 34 ++++---- .../Library/MediaSourceManager.cs | 9 -- Jellyfin.Api/Controllers/StartupController.cs | 1 - MediaBrowser.Api/Attachments/AttachmentService.cs | 19 ++--- .../Library/IMediaSourceManager.cs | 11 +-- .../MediaEncoding/IAttachmentExtractor.cs | 4 +- .../Attachments/AttachmentExtractor.cs | 97 +++++++++++----------- .../Encoder/EncodingUtils.cs | 2 +- 9 files changed, 82 insertions(+), 97 deletions(-) diff --git a/Emby.Server.Implementations/ApplicationHost.cs b/Emby.Server.Implementations/ApplicationHost.cs index 7c3f59af2..c5ac27ed4 100644 --- a/Emby.Server.Implementations/ApplicationHost.cs +++ b/Emby.Server.Implementations/ApplicationHost.cs @@ -878,7 +878,7 @@ namespace Emby.Server.Implementations serviceCollection.AddSingleton(typeof(IResourceFileManager), typeof(ResourceFileManager)); serviceCollection.AddSingleton(); - serviceCollection.AddSingleton(typeof(MediaBrowser.Controller.MediaEncoding.IAttachmentExtractor),typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor)); + serviceCollection.AddSingleton(typeof(IAttachmentExtractor), typeof(MediaBrowser.MediaEncoding.Attachments.AttachmentExtractor)); _displayPreferencesRepository.Initialize(); diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 2206816a5..91ca8477d 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -55,8 +55,8 @@ namespace Emby.Server.Implementations.Data queryPrefixText.Append("insert into mediaattachments ("); foreach (var column in _mediaAttachmentSaveColumns) { - queryPrefixText.Append(column); - queryPrefixText.Append(','); + queryPrefixText.Append(column) + .Append(','); } queryPrefixText.Length -= 1; @@ -449,6 +449,7 @@ namespace Emby.Server.Implementations.Data "Filename", "MIMEType" }; + private static readonly string _mediaAttachmentInsertPrefix; private static string GetSaveItemCommandText() @@ -6208,7 +6209,10 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type return list; } - public void SaveMediaAttachments(Guid id, List attachments, CancellationToken cancellationToken) + public void SaveMediaAttachments( + Guid id, + List attachments, + CancellationToken cancellationToken) { CheckDisposed(); if (id == Guid.Empty) @@ -6237,24 +6241,22 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type } } - private void InsertMediaAttachments(byte[] idBlob, List attachments, IDatabaseConnection db, CancellationToken cancellationToken) + private void InsertMediaAttachments( + byte[] idBlob, + List attachments, + IDatabaseConnection db, + CancellationToken cancellationToken) { - var startIndex = 0; - var insertAtOnce = 10; + const int InsertAtOnce = 10; - while (startIndex < attachments.Count) + for (var startIndex = 0; startIndex < attachments.Count; startIndex += InsertAtOnce) { var insertText = new StringBuilder(_mediaAttachmentInsertPrefix); - var endIndex = Math.Min(attachments.Count, startIndex + insertAtOnce); + var endIndex = Math.Min(attachments.Count, startIndex + InsertAtOnce); for (var i = startIndex; i < endIndex; i++) { - if (i != startIndex) - { - insertText.Append(','); - } - var index = i.ToString(CultureInfo.InvariantCulture); insertText.Append("(@ItemId, "); @@ -6265,9 +6267,11 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type insertText.Length -= 1; - insertText.Append(")"); + insertText.Append("),"); } + insertText.Length--; + cancellationToken.ThrowIfCancellationRequested(); using (var statement = PrepareStatement(db, insertText.ToString())) @@ -6291,8 +6295,6 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.Reset(); statement.MoveNext(); } - - startIndex += insertAtOnce; } } diff --git a/Emby.Server.Implementations/Library/MediaSourceManager.cs b/Emby.Server.Implementations/Library/MediaSourceManager.cs index 4eff2807c..ba1564d1f 100644 --- a/Emby.Server.Implementations/Library/MediaSourceManager.cs +++ b/Emby.Server.Implementations/Library/MediaSourceManager.cs @@ -136,15 +136,6 @@ namespace Emby.Server.Implementations.Library return _itemRepo.GetMediaAttachments(query); } - /// - public List GetMediaAttachments(string mediaSourceId) - { - return GetMediaAttachments(new MediaAttachmentQuery - { - ItemId = new Guid(mediaSourceId) - }); - } - /// public List GetMediaAttachments(Guid itemId) { diff --git a/Jellyfin.Api/Controllers/StartupController.cs b/Jellyfin.Api/Controllers/StartupController.cs index 1014c8c56..afc9b8f3d 100644 --- a/Jellyfin.Api/Controllers/StartupController.cs +++ b/Jellyfin.Api/Controllers/StartupController.cs @@ -96,7 +96,6 @@ namespace Jellyfin.Api.Controllers public StartupUserDto GetFirstUser() { var user = _userManager.Users.First(); - return new StartupUserDto { Name = user.Name, diff --git a/MediaBrowser.Api/Attachments/AttachmentService.cs b/MediaBrowser.Api/Attachments/AttachmentService.cs index 1ebfaa14b..ef09951b6 100644 --- a/MediaBrowser.Api/Attachments/AttachmentService.cs +++ b/MediaBrowser.Api/Attachments/AttachmentService.cs @@ -1,22 +1,14 @@ 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; -using MediaBrowser.Controller.Entities; +using MediaBrowser.Controller.Configuration; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; using MediaBrowser.Controller.Net; -using MediaBrowser.Controller.Providers; using MediaBrowser.Model.Entities; -using MediaBrowser.Model.IO; -using MediaBrowser.Model.Providers; using MediaBrowser.Model.Services; using Microsoft.Extensions.Logging; -using MimeTypes = MediaBrowser.Model.Net.MimeTypes; namespace MediaBrowser.Api.Attachments { @@ -38,7 +30,13 @@ namespace MediaBrowser.Api.Attachments private readonly ILibraryManager _libraryManager; private readonly IAttachmentExtractor _attachmentExtractor; - public AttachmentService(ILibraryManager libraryManager, IAttachmentExtractor attachmentExtractor) + public AttachmentService( + ILogger logger, + IServerConfigurationManager serverConfigurationManager, + IHttpResultFactory httpResultFactory, + ILibraryManager libraryManager, + IAttachmentExtractor attachmentExtractor) + : base(logger, serverConfigurationManager, httpResultFactory) { _libraryManager = libraryManager; _attachmentExtractor = attachmentExtractor; @@ -46,7 +44,6 @@ namespace MediaBrowser.Api.Attachments public async Task Get(GetAttachment request) { - var item = (Video)_libraryManager.GetItemById(request.Id); var (attachment, attachmentStream) = await GetAttachment(request).ConfigureAwait(false); var mime = string.IsNullOrWhiteSpace(attachment.MIMEType) ? "application/octet-stream" : attachment.MIMEType; diff --git a/MediaBrowser.Controller/Library/IMediaSourceManager.cs b/MediaBrowser.Controller/Library/IMediaSourceManager.cs index dda8d397a..09e6fda88 100644 --- a/MediaBrowser.Controller/Library/IMediaSourceManager.cs +++ b/MediaBrowser.Controller/Library/IMediaSourceManager.cs @@ -41,21 +41,14 @@ namespace MediaBrowser.Controller.Library /// /// Gets the media attachments. /// - /// The item identifier. + /// The item identifier. /// IEnumerable<MediaAttachment>. List GetMediaAttachments(Guid itemId); /// /// Gets the media attachments. /// - /// The The media source identifier. - /// IEnumerable<MediaAttachment>. - - List GetMediaAttachments(string mediaSourceId); - /// - /// Gets the media attachments. - /// - /// The query. + /// The query. /// IEnumerable<MediaAttachment>. List GetMediaAttachments(MediaAttachmentQuery query); diff --git a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs index 59c0a3f21..7c7e84de6 100644 --- a/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs +++ b/MediaBrowser.Controller/MediaEncoding/IAttachmentExtractor.cs @@ -2,14 +2,14 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Controller.Entities; -using MediaBrowser.Model.MediaInfo; using MediaBrowser.Model.Entities; namespace MediaBrowser.Controller.MediaEncoding { public interface IAttachmentExtractor { - Task<(MediaAttachment attachment, Stream stream)> GetAttachment(BaseItem item, + Task<(MediaAttachment attachment, Stream stream)> GetAttachment( + BaseItem item, string mediaSourceId, int attachmentStreamIndex, CancellationToken cancellationToken); diff --git a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs index cb22343c4..c371e8b94 100644 --- a/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs +++ b/MediaBrowser.MediaEncoding/Attachments/AttachmentExtractor.cs @@ -4,44 +4,41 @@ using System.Collections.Concurrent; using System.Globalization; using System.IO; using System.Linq; -using System.Text; using System.Threading; using System.Threading.Tasks; using MediaBrowser.Common.Configuration; using MediaBrowser.Common.Extensions; -using MediaBrowser.Common.Net; using MediaBrowser.Controller.Entities; using MediaBrowser.Controller.Library; using MediaBrowser.Controller.MediaEncoding; -using MediaBrowser.Model.Diagnostics; using MediaBrowser.Model.Dto; using MediaBrowser.Model.Entities; using MediaBrowser.Model.IO; using MediaBrowser.Model.MediaInfo; -using MediaBrowser.Model.Serialization; using Microsoft.Extensions.Logging; -using UtfUnknown; namespace MediaBrowser.MediaEncoding.Attachments { - public class AttachmentExtractor : IAttachmentExtractor + public class AttachmentExtractor : IAttachmentExtractor, IDisposable { - private readonly ILibraryManager _libraryManager; private readonly ILogger _logger; private readonly IApplicationPaths _appPaths; private readonly IFileSystem _fileSystem; private readonly IMediaEncoder _mediaEncoder; private readonly IMediaSourceManager _mediaSourceManager; + private readonly ConcurrentDictionary _semaphoreLocks = + new ConcurrentDictionary(); + + private bool _disposed = false; + public AttachmentExtractor( - ILibraryManager libraryManager, ILogger logger, IApplicationPaths appPaths, IFileSystem fileSystem, IMediaEncoder mediaEncoder, IMediaSourceManager mediaSourceManager) { - _libraryManager = libraryManager; _logger = logger; _appPaths = appPaths; _fileSystem = fileSystem; @@ -49,8 +46,7 @@ namespace MediaBrowser.MediaEncoding.Attachments _mediaSourceManager = mediaSourceManager; } - private string AttachmentCachePath => Path.Combine(_appPaths.DataPath, "attachments"); - + /// public async Task<(MediaAttachment attachment, Stream stream)> GetAttachment(BaseItem item, string mediaSourceId, int attachmentStreamIndex, CancellationToken cancellationToken) { if (item == null) @@ -70,12 +66,14 @@ namespace MediaBrowser.MediaEncoding.Attachments { throw new ResourceNotFoundException($"MediaSource {mediaSourceId} not found"); } + var mediaAttachment = mediaSource.MediaAttachments .FirstOrDefault(i => i.Index == attachmentStreamIndex); if (mediaAttachment == null) { throw new ResourceNotFoundException($"MediaSource {mediaSourceId} has no attachment with stream index {attachmentStreamIndex}"); } + var attachmentStream = await GetAttachmentStream(mediaSource, mediaAttachment, cancellationToken) .ConfigureAwait(false); @@ -87,49 +85,32 @@ namespace MediaBrowser.MediaEncoding.Attachments MediaAttachment mediaAttachment, CancellationToken cancellationToken) { - var inputFiles = new[] { mediaSource.Path }; - var attachmentPath = await GetReadableFile(mediaSource.Path, inputFiles, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false); - var stream = await GetAttachmentStream(attachmentPath, cancellationToken).ConfigureAwait(false); - return stream; + var attachmentPath = await GetReadableFile(mediaSource.Path, mediaSource.Path, mediaSource.Protocol, mediaAttachment, cancellationToken).ConfigureAwait(false); + return File.OpenRead(attachmentPath); } - private async Task GetAttachmentStream( - string path, - CancellationToken cancellationToken) - { - return File.OpenRead(path); - } - - private async Task GetReadableFile( + private async Task GetReadableFile( string mediaPath, - string[] inputFiles, + string inputFile, MediaProtocol protocol, MediaAttachment mediaAttachment, CancellationToken cancellationToken) { var outputPath = GetAttachmentCachePath(mediaPath, protocol, mediaAttachment.Index); - await ExtractAttachment(inputFiles, protocol, mediaAttachment.Index, outputPath, cancellationToken) + await ExtractAttachment(inputFile, protocol, mediaAttachment.Index, outputPath, cancellationToken) .ConfigureAwait(false); return outputPath; } - private readonly ConcurrentDictionary _semaphoreLocks = - new ConcurrentDictionary(); - - private SemaphoreSlim GetLock(string filename) - { - return _semaphoreLocks.GetOrAdd(filename, key => new SemaphoreSlim(1, 1)); - } - private async Task ExtractAttachment( - string[] inputFiles, + string inputFile, MediaProtocol protocol, int attachmentStreamIndex, string outputPath, CancellationToken cancellationToken) { - var semaphore = GetLock(outputPath); + var semaphore = _semaphoreLocks.GetOrAdd(outputPath, key => new SemaphoreSlim(1, 1)); await semaphore.WaitAsync(cancellationToken).ConfigureAwait(false); @@ -137,7 +118,11 @@ namespace MediaBrowser.MediaEncoding.Attachments { if (!File.Exists(outputPath)) { - await ExtractAttachmentInternal(_mediaEncoder.GetInputArgument(inputFiles, protocol), attachmentStreamIndex, outputPath, cancellationToken).ConfigureAwait(false); + await ExtractAttachmentInternal( + _mediaEncoder.GetInputArgument(new[] { inputFile }, protocol), + attachmentStreamIndex, + outputPath, + cancellationToken).ConfigureAwait(false); } } finally @@ -186,16 +171,7 @@ namespace MediaBrowser.MediaEncoding.Attachments _logger.LogInformation("{File} {Arguments}", process.StartInfo.FileName, process.StartInfo.Arguments); - try - { - process.Start(); - } - catch (Exception ex) - { - _logger.LogError(ex, "Error starting ffmpeg"); - - throw; - } + process.Start(); var processTcs = new TaskCompletionSource(); process.EnableRaisingEvents = true; @@ -216,6 +192,7 @@ namespace MediaBrowser.MediaEncoding.Attachments _logger.LogError(ex, "Error killing attachment extraction process"); } } + var exitCode = ranToCompletion ? process.ExitCode : -1; process.Dispose(); @@ -270,9 +247,35 @@ namespace MediaBrowser.MediaEncoding.Attachments { filename = (mediaPath + attachmentStreamIndex.ToString(CultureInfo.InvariantCulture)).GetMD5().ToString("D"); } + var prefix = filename.Substring(0, 1); - return Path.Combine(AttachmentCachePath, prefix, filename); + return Path.Combine(_appPaths.DataPath, "attachments", prefix, filename); + } + + /// + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); } + /// + /// Releases unmanaged and - optionally - managed resources. + /// + /// true to release both managed and unmanaged resources; false to release only unmanaged resources. + protected virtual void Dispose(bool disposing) + { + if (_disposed) + { + return; + } + + if (disposing) + { + + } + + _disposed = true; + } } } diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index d4aede572..c5da42089 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// The path. /// System.String. - private static string GetFileInputArgument(string path) + public static string GetFileInputArgument(string path) { if (path.IndexOf("://") != -1) { -- cgit v1.2.3 From 8a0ef4103632b2888249af2f385e1e7bfc06fbfe Mon Sep 17 00:00:00 2001 From: Bond_009 Date: Thu, 26 Dec 2019 23:20:31 +0100 Subject: Minor improvements --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 4 ++-- MediaBrowser.Controller/Persistence/IItemRepository.cs | 2 +- MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs | 2 +- MediaBrowser.Model/Dto/MediaSourceInfo.cs | 2 +- MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs | 10 +++++----- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 91ca8477d..2ff19a639 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6211,7 +6211,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type public void SaveMediaAttachments( Guid id, - List attachments, + IReadOnlyList attachments, CancellationToken cancellationToken) { CheckDisposed(); @@ -6243,7 +6243,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type private void InsertMediaAttachments( byte[] idBlob, - List attachments, + IReadOnlyList attachments, IDatabaseConnection db, CancellationToken cancellationToken) { diff --git a/MediaBrowser.Controller/Persistence/IItemRepository.cs b/MediaBrowser.Controller/Persistence/IItemRepository.cs index 68df20c3a..5a5b7f58f 100644 --- a/MediaBrowser.Controller/Persistence/IItemRepository.cs +++ b/MediaBrowser.Controller/Persistence/IItemRepository.cs @@ -91,7 +91,7 @@ namespace MediaBrowser.Controller.Persistence /// The identifier. /// The attachments. /// The cancellation token. - void SaveMediaAttachments(Guid id, List attachments, CancellationToken cancellationToken); + void SaveMediaAttachments(Guid id, IReadOnlyList attachments, CancellationToken cancellationToken); /// /// Gets the item ids. diff --git a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs index c5da42089..d4aede572 100644 --- a/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs +++ b/MediaBrowser.MediaEncoding/Encoder/EncodingUtils.cs @@ -43,7 +43,7 @@ namespace MediaBrowser.MediaEncoding.Encoder /// /// The path. /// System.String. - public static string GetFileInputArgument(string path) + private static string GetFileInputArgument(string path) { if (path.IndexOf("://") != -1) { diff --git a/MediaBrowser.Model/Dto/MediaSourceInfo.cs b/MediaBrowser.Model/Dto/MediaSourceInfo.cs index 8a1aa55b6..5cb056566 100644 --- a/MediaBrowser.Model/Dto/MediaSourceInfo.cs +++ b/MediaBrowser.Model/Dto/MediaSourceInfo.cs @@ -57,7 +57,7 @@ namespace MediaBrowser.Model.Dto public List MediaStreams { get; set; } - public List MediaAttachments { get; set; } + public IReadOnlyList MediaAttachments { get; set; } public string[] Formats { get; set; } diff --git a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs index ae3e584d4..2b178d4d4 100644 --- a/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs +++ b/MediaBrowser.Providers/MediaInfo/FFProbeVideoInfo.cs @@ -158,7 +158,7 @@ namespace MediaBrowser.Providers.MediaInfo MetadataRefreshOptions options) { List mediaStreams; - List mediaAttachments; + IReadOnlyList mediaAttachments; List chapters; if (mediaInfo != null) @@ -200,7 +200,7 @@ namespace MediaBrowser.Providers.MediaInfo else { mediaStreams = new List(); - mediaAttachments = new List(); + mediaAttachments = Array.Empty(); chapters = new List(); } @@ -213,13 +213,13 @@ namespace MediaBrowser.Providers.MediaInfo FetchEmbeddedInfo(video, mediaInfo, options, libraryOptions); FetchPeople(video, mediaInfo, options); video.Timestamp = mediaInfo.Timestamp; - video.Video3DFormat = video.Video3DFormat ?? mediaInfo.Video3DFormat; + video.Video3DFormat ??= mediaInfo.Video3DFormat; } var videoStream = mediaStreams.FirstOrDefault(i => i.Type == MediaStreamType.Video); - video.Height = videoStream == null ? 0 : videoStream.Height ?? 0; - video.Width = videoStream == null ? 0 : videoStream.Width ?? 0; + video.Height = videoStream?.Height ?? 0; + video.Width = videoStream?.Width ?? 0; video.DefaultVideoStreamIndex = videoStream == null ? (int?)null : videoStream.Index; -- cgit v1.2.3 From 73fac50e57982ac46aea2b487e9906826c3dc3b2 Mon Sep 17 00:00:00 2001 From: dkanada Date: Wed, 8 Jan 2020 10:52:48 +0900 Subject: rename two properties based on code suggestions --- Emby.Server.Implementations/Data/SqliteItemRepository.cs | 8 ++++---- MediaBrowser.Api/Attachments/AttachmentService.cs | 2 +- MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs | 4 ++-- MediaBrowser.Model/Entities/MediaAttachment.cs | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Emby.Server.Implementations/Data/SqliteItemRepository.cs b/Emby.Server.Implementations/Data/SqliteItemRepository.cs index 2ff19a639..c514846e5 100644 --- a/Emby.Server.Implementations/Data/SqliteItemRepository.cs +++ b/Emby.Server.Implementations/Data/SqliteItemRepository.cs @@ -6288,8 +6288,8 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type statement.TryBind("@Codec" + index, attachment.Codec); statement.TryBind("@CodecTag" + index, attachment.CodecTag); statement.TryBind("@Comment" + index, attachment.Comment); - statement.TryBind("@Filename" + index, attachment.Filename); - statement.TryBind("@MIMEType" + index, attachment.MIMEType); + statement.TryBind("@FileName" + index, attachment.FileName); + statement.TryBind("@MimeType" + index, attachment.MimeType); } statement.Reset(); @@ -6327,12 +6327,12 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type if (reader[6].SQLiteType != SQLiteType.Null) { - item.Filename = reader[5].ToString(); + item.FileName = reader[5].ToString(); } if (reader[6].SQLiteType != SQLiteType.Null) { - item.MIMEType = reader[6].ToString(); + item.MimeType = reader[6].ToString(); } return item; diff --git a/MediaBrowser.Api/Attachments/AttachmentService.cs b/MediaBrowser.Api/Attachments/AttachmentService.cs index ef09951b6..1632ca1b0 100644 --- a/MediaBrowser.Api/Attachments/AttachmentService.cs +++ b/MediaBrowser.Api/Attachments/AttachmentService.cs @@ -45,7 +45,7 @@ namespace MediaBrowser.Api.Attachments public async Task Get(GetAttachment request) { var (attachment, attachmentStream) = await GetAttachment(request).ConfigureAwait(false); - var mime = string.IsNullOrWhiteSpace(attachment.MIMEType) ? "application/octet-stream" : attachment.MIMEType; + var mime = string.IsNullOrWhiteSpace(attachment.MimeType) ? "application/octet-stream" : attachment.MimeType; return ResultFactory.GetResult(Request, attachmentStream, mime); } diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index f2056c566..6664b34a5 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -542,8 +542,8 @@ namespace MediaBrowser.MediaEncoding.Probing if (streamInfo.tags != null) { - attachment.Filename = GetDictionaryValue(streamInfo.tags, "filename"); - attachment.MIMEType = GetDictionaryValue(streamInfo.tags, "mimetype"); + attachment.FileName = GetDictionaryValue(streamInfo.tags, "filename"); + attachment.MimeType = GetDictionaryValue(streamInfo.tags, "mimetype"); attachment.Comment = GetDictionaryValue(streamInfo.tags, "comment"); } diff --git a/MediaBrowser.Model/Entities/MediaAttachment.cs b/MediaBrowser.Model/Entities/MediaAttachment.cs index 26279b72b..8f8c3efd2 100644 --- a/MediaBrowser.Model/Entities/MediaAttachment.cs +++ b/MediaBrowser.Model/Entities/MediaAttachment.cs @@ -33,13 +33,13 @@ namespace MediaBrowser.Model.Entities /// Gets or sets the filename. /// /// The filename. - public string Filename { get; set; } + public string FileName { get; set; } /// /// Gets or sets the MIME type. /// /// The MIME type. - public string MIMEType { get; set; } + public string MimeType { get; set; } /// /// Gets or sets the delivery URL. -- cgit v1.2.3 From 75f19a762cf4cf769df7545612e68e95bb6905f2 Mon Sep 17 00:00:00 2001 From: Anthony Lavado Date: Wed, 8 Jan 2020 04:05:07 -0500 Subject: Re-order the path statement to avoid file issues Fixes #31874. --- Emby.Server.Implementations/IO/ManagedFileSystem.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Emby.Server.Implementations/IO/ManagedFileSystem.cs b/Emby.Server.Implementations/IO/ManagedFileSystem.cs index 442fbabd1..9568f62df 100644 --- a/Emby.Server.Implementations/IO/ManagedFileSystem.cs +++ b/Emby.Server.Implementations/IO/ManagedFileSystem.cs @@ -109,7 +109,7 @@ namespace Emby.Server.Implementations.IO } try { - return Path.Combine(Path.GetFullPath(folderPath), filePath); + return Path.GetFullPath(Path.Combine(folderPath, filePath)); } catch (ArgumentException) { -- cgit v1.2.3 From 277e9d2b0b9859aa374ed4c4add10f3c46dbdfd2 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 8 Jan 2020 18:13:11 +0100 Subject: fix build --- .../Probing/ProbeResultNormalizer.cs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs index 37baef5b0..bd89c6cae 100644 --- a/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs +++ b/MediaBrowser.MediaEncoding/Probing/ProbeResultNormalizer.cs @@ -52,7 +52,7 @@ namespace MediaBrowser.MediaEncoding.Probing .Where(i => i != null) .ToList(); - if (data.format != null) + if (data.Format != null) { info.Container = NormalizeFormat(data.Format.FormatName); @@ -523,27 +523,27 @@ namespace MediaBrowser.MediaEncoding.Probing /// MediaAttachments. private MediaAttachment GetMediaAttachment(MediaStreamInfo streamInfo) { - if (!string.Equals(streamInfo.codec_type, "attachment", StringComparison.OrdinalIgnoreCase)) + if (!string.Equals(streamInfo.CodecType, "attachment", StringComparison.OrdinalIgnoreCase)) { return null; } var attachment = new MediaAttachment { - Codec = streamInfo.codec_name, - Index = streamInfo.index + Codec = streamInfo.CodecName, + Index = streamInfo.Index }; - if (!string.IsNullOrWhiteSpace(streamInfo.codec_tag_string)) + if (!string.IsNullOrWhiteSpace(streamInfo.CodecTagString)) { - attachment.CodecTag = streamInfo.codec_tag_string; + attachment.CodecTag = streamInfo.CodecTagString; } - if (streamInfo.tags != null) + if (streamInfo.Tags != null) { - attachment.FileName = GetDictionaryValue(streamInfo.tags, "filename"); - attachment.MimeType = GetDictionaryValue(streamInfo.tags, "mimetype"); - attachment.Comment = GetDictionaryValue(streamInfo.tags, "comment"); + attachment.FileName = GetDictionaryValue(streamInfo.Tags, "filename"); + attachment.MimeType = GetDictionaryValue(streamInfo.Tags, "mimetype"); + attachment.Comment = GetDictionaryValue(streamInfo.Tags, "comment"); } return attachment; -- cgit v1.2.3 From b1af8a4178b5d993b09e5682a0149ea37766ff91 Mon Sep 17 00:00:00 2001 From: Bond-009 Date: Wed, 8 Jan 2020 18:14:01 +0100 Subject: Rename function --- MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs index cd3d82e86..78dc7b607 100644 --- a/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs +++ b/MediaBrowser.MediaEncoding/Probing/FFProbeHelpers.cs @@ -18,7 +18,7 @@ namespace MediaBrowser.MediaEncoding.Probing if (result.Format != null && result.Format.Tags != null) { - result.Format.Tags = ConvertDictionaryToCaseInSensitive(result.Format.Tags); + result.Format.Tags = ConvertDictionaryToCaseInsensitive(result.Format.Tags); } if (result.Streams != null) @@ -28,7 +28,7 @@ namespace MediaBrowser.MediaEncoding.Probing { if (stream.Tags != null) { - stream.Tags = ConvertDictionaryToCaseInSensitive(stream.Tags); + stream.Tags = ConvertDictionaryToCaseInsensitive(stream.Tags); } } } @@ -98,7 +98,7 @@ namespace MediaBrowser.MediaEncoding.Probing /// /// The dict. /// Dictionary{System.StringSystem.String}. - private static Dictionary ConvertDictionaryToCaseInSensitive(IReadOnlyDictionary dict) + private static Dictionary ConvertDictionaryToCaseInsensitive(IReadOnlyDictionary dict) { return new Dictionary(dict, StringComparer.OrdinalIgnoreCase); } -- cgit v1.2.3