Merge pull request #6941 from holahmeds/mime-type
Use MimeTypes package to determine MIME type
This commit is contained in:
commit
707e5bab97
|
@ -31,6 +31,10 @@
|
|||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1" PrivateAssets="All" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="6.0.0" />
|
||||
<PackageReference Include="MimeTypes" Version="2.2.1">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.Globalization" Version="4.3.0" />
|
||||
<PackageReference Include="System.Text.Json" Version="6.0.0" />
|
||||
</ItemGroup>
|
||||
|
|
|
@ -12,6 +12,15 @@ namespace MediaBrowser.Model.Net
|
|||
/// <summary>
|
||||
/// Class MimeTypes.
|
||||
/// </summary>
|
||||
///
|
||||
/// <remarks>
|
||||
/// For more information on MIME types:
|
||||
/// <list type="bullet">
|
||||
/// <item>http://en.wikipedia.org/wiki/Internet_media_type</item>
|
||||
/// <item>https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types</item>
|
||||
/// <item>http://www.iana.org/assignments/media-types/media-types.xhtml</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
public static class MimeTypes
|
||||
{
|
||||
/// <summary>
|
||||
|
@ -50,81 +59,26 @@ namespace MediaBrowser.Model.Net
|
|||
".wtv",
|
||||
};
|
||||
|
||||
// http://en.wikipedia.org/wiki/Internet_media_type
|
||||
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types/Common_types
|
||||
// http://www.iana.org/assignments/media-types/media-types.xhtml
|
||||
// Add more as needed
|
||||
/// <summary>
|
||||
/// Used for extensions not in <see cref="Model.MimeTypes"/> or to override them.
|
||||
/// </summary>
|
||||
private static readonly Dictionary<string, string> _mimeTypeLookup = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
// Type application
|
||||
{ ".7z", "application/x-7z-compressed" },
|
||||
{ ".azw", "application/vnd.amazon.ebook" },
|
||||
{ ".azw3", "application/vnd.amazon.ebook" },
|
||||
{ ".cbz", "application/x-cbz" },
|
||||
{ ".cbr", "application/epub+zip" },
|
||||
{ ".eot", "application/vnd.ms-fontobject" },
|
||||
{ ".epub", "application/epub+zip" },
|
||||
{ ".js", "application/x-javascript" },
|
||||
{ ".json", "application/json" },
|
||||
{ ".m3u8", "application/x-mpegURL" },
|
||||
{ ".map", "application/x-javascript" },
|
||||
{ ".mobi", "application/x-mobipocket-ebook" },
|
||||
{ ".opf", "application/oebps-package+xml" },
|
||||
{ ".pdf", "application/pdf" },
|
||||
{ ".rar", "application/vnd.rar" },
|
||||
{ ".srt", "application/x-subrip" },
|
||||
{ ".ttml", "application/ttml+xml" },
|
||||
{ ".wasm", "application/wasm" },
|
||||
{ ".xml", "application/xml" },
|
||||
{ ".zip", "application/zip" },
|
||||
|
||||
// Type image
|
||||
{ ".bmp", "image/bmp" },
|
||||
{ ".gif", "image/gif" },
|
||||
{ ".ico", "image/vnd.microsoft.icon" },
|
||||
{ ".jpg", "image/jpeg" },
|
||||
{ ".jpeg", "image/jpeg" },
|
||||
{ ".png", "image/png" },
|
||||
{ ".svg", "image/svg+xml" },
|
||||
{ ".svgz", "image/svg+xml" },
|
||||
{ ".tbn", "image/jpeg" },
|
||||
{ ".tif", "image/tiff" },
|
||||
{ ".tiff", "image/tiff" },
|
||||
{ ".webp", "image/webp" },
|
||||
|
||||
// Type font
|
||||
{ ".ttf", "font/ttf" },
|
||||
{ ".woff", "font/woff" },
|
||||
{ ".woff2", "font/woff2" },
|
||||
|
||||
// Type text
|
||||
{ ".ass", "text/x-ssa" },
|
||||
{ ".ssa", "text/x-ssa" },
|
||||
{ ".css", "text/css" },
|
||||
{ ".csv", "text/csv" },
|
||||
{ ".edl", "text/plain" },
|
||||
{ ".rtf", "text/rtf" },
|
||||
{ ".txt", "text/plain" },
|
||||
{ ".vtt", "text/vtt" },
|
||||
{ ".html", "text/html; charset=UTF-8" },
|
||||
{ ".htm", "text/html; charset=UTF-8" },
|
||||
|
||||
// Type video
|
||||
{ ".3gp", "video/3gpp" },
|
||||
{ ".3g2", "video/3gpp2" },
|
||||
{ ".asf", "video/x-ms-asf" },
|
||||
{ ".avi", "video/x-msvideo" },
|
||||
{ ".flv", "video/x-flv" },
|
||||
{ ".mp4", "video/mp4" },
|
||||
{ ".m4s", "video/mp4" },
|
||||
{ ".m4v", "video/x-m4v" },
|
||||
{ ".mpegts", "video/mp2t" },
|
||||
{ ".mpg", "video/mpeg" },
|
||||
{ ".mkv", "video/x-matroska" },
|
||||
{ ".mov", "video/quicktime" },
|
||||
{ ".mpd", "video/vnd.mpeg.dash.mpd" },
|
||||
{ ".ogv", "video/ogg" },
|
||||
{ ".ts", "video/mp2t" },
|
||||
{ ".webm", "video/webm" },
|
||||
{ ".wmv", "video/x-ms-wmv" },
|
||||
|
||||
// Type audio
|
||||
{ ".aac", "audio/aac" },
|
||||
|
@ -133,37 +87,47 @@ namespace MediaBrowser.Model.Net
|
|||
{ ".dsf", "audio/dsf" },
|
||||
{ ".dsp", "audio/dsp" },
|
||||
{ ".flac", "audio/flac" },
|
||||
{ ".m4a", "audio/mp4" },
|
||||
{ ".m4b", "audio/m4b" },
|
||||
{ ".mid", "audio/midi" },
|
||||
{ ".midi", "audio/midi" },
|
||||
{ ".mp3", "audio/mpeg" },
|
||||
{ ".oga", "audio/ogg" },
|
||||
{ ".ogg", "audio/ogg" },
|
||||
{ ".opus", "audio/ogg" },
|
||||
{ ".vorbis", "audio/vorbis" },
|
||||
{ ".wav", "audio/wav" },
|
||||
{ ".webma", "audio/webm" },
|
||||
{ ".wma", "audio/x-ms-wma" },
|
||||
{ ".wv", "audio/x-wavpack" },
|
||||
{ ".xsp", "audio/xsp" },
|
||||
};
|
||||
|
||||
private static readonly Dictionary<string, string> _extensionLookup = CreateExtensionLookup();
|
||||
|
||||
private static Dictionary<string, string> CreateExtensionLookup()
|
||||
private static readonly Dictionary<string, string> _extensionLookup = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
var dict = _mimeTypeLookup
|
||||
.GroupBy(i => i.Value)
|
||||
.ToDictionary(x => x.Key, x => x.First().Key, StringComparer.OrdinalIgnoreCase);
|
||||
// Type application
|
||||
{ "application/x-cbz", ".cbz" },
|
||||
{ "application/x-javascript", ".js" },
|
||||
{ "application/xml", ".xml" },
|
||||
{ "application/x-mpegURL", ".m3u8" },
|
||||
|
||||
dict["image/jpg"] = ".jpg";
|
||||
dict["image/x-png"] = ".png";
|
||||
// Type audio
|
||||
{ "audio/aac", ".aac" },
|
||||
{ "audio/ac3", ".ac3" },
|
||||
{ "audio/dsf", ".dsf" },
|
||||
{ "audio/dsp", ".dsp" },
|
||||
{ "audio/flac", ".flac" },
|
||||
{ "audio/m4b", ".m4b" },
|
||||
{ "audio/vorbis", ".vorbis" },
|
||||
{ "audio/x-ape", ".ape" },
|
||||
{ "audio/xsp", ".xsp" },
|
||||
{ "audio/x-wavpack", ".wv" },
|
||||
|
||||
dict["audio/x-aac"] = ".aac";
|
||||
// Type image
|
||||
{ "image/jpg", ".jpg" },
|
||||
{ "image/x-png", ".png" },
|
||||
|
||||
return dict;
|
||||
}
|
||||
// Type text
|
||||
{ "text/plain", ".txt" },
|
||||
{ "text/rtf", ".rtf" },
|
||||
{ "text/x-ssa", ".ssa" },
|
||||
|
||||
// Type video
|
||||
{ "video/vnd.mpeg.dash.mpd", ".mpd" },
|
||||
{ "video/x-matroska", ".mkv" },
|
||||
};
|
||||
|
||||
public static string GetMimeType(string path) => GetMimeType(path, "application/octet-stream");
|
||||
|
||||
|
@ -188,31 +152,17 @@ namespace MediaBrowser.Model.Net
|
|||
return result;
|
||||
}
|
||||
|
||||
if (Model.MimeTypes.TryGetMimeType(filename, out var mimeType))
|
||||
{
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
// Catch-all for all video types that don't require specific mime types
|
||||
if (_videoFileExtensions.Contains(ext))
|
||||
{
|
||||
return string.Concat("video/", ext.AsSpan(1));
|
||||
}
|
||||
|
||||
// Type text
|
||||
if (string.Equals(ext, ".html", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(ext, ".htm", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "text/html; charset=UTF-8";
|
||||
}
|
||||
|
||||
if (string.Equals(ext, ".log", StringComparison.OrdinalIgnoreCase)
|
||||
|| string.Equals(ext, ".srt", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "text/plain";
|
||||
}
|
||||
|
||||
// Misc
|
||||
if (string.Equals(ext, ".dll", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return "application/octet-stream";
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
|
@ -231,7 +181,8 @@ namespace MediaBrowser.Model.Net
|
|||
return result;
|
||||
}
|
||||
|
||||
return null;
|
||||
var extension = Model.MimeTypes.GetMimeTypeExtensions(mimeType).FirstOrDefault();
|
||||
return string.IsNullOrEmpty(extension) ? null : "." + extension;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
164
tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs
Normal file
164
tests/Jellyfin.Model.Tests/Net/MimeTypesTests.cs
Normal file
|
@ -0,0 +1,164 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using MediaBrowser.Model.Net;
|
||||
using Xunit;
|
||||
|
||||
namespace Jellyfin.Model.Tests.Net
|
||||
{
|
||||
public class MimeTypesTests
|
||||
{
|
||||
[Theory]
|
||||
[InlineData(".dll", "application/octet-stream")]
|
||||
[InlineData(".log", "text/plain")]
|
||||
[InlineData(".srt", "application/x-subrip")]
|
||||
[InlineData(".html", "text/html; charset=UTF-8")]
|
||||
[InlineData(".htm", "text/html; charset=UTF-8")]
|
||||
[InlineData(".7z", "application/x-7z-compressed")]
|
||||
[InlineData(".azw", "application/vnd.amazon.ebook")]
|
||||
[InlineData(".azw3", "application/vnd.amazon.ebook")]
|
||||
[InlineData(".eot", "application/vnd.ms-fontobject")]
|
||||
[InlineData(".epub", "application/epub+zip")]
|
||||
[InlineData(".json", "application/json")]
|
||||
[InlineData(".mobi", "application/x-mobipocket-ebook")]
|
||||
[InlineData(".opf", "application/oebps-package+xml")]
|
||||
[InlineData(".pdf", "application/pdf")]
|
||||
[InlineData(".rar", "application/vnd.rar")]
|
||||
[InlineData(".ttml", "application/ttml+xml")]
|
||||
[InlineData(".wasm", "application/wasm")]
|
||||
[InlineData(".xml", "application/xml")]
|
||||
[InlineData(".zip", "application/zip")]
|
||||
[InlineData(".bmp", "image/bmp")]
|
||||
[InlineData(".gif", "image/gif")]
|
||||
[InlineData(".ico", "image/vnd.microsoft.icon")]
|
||||
[InlineData(".jpg", "image/jpeg")]
|
||||
[InlineData(".jpeg", "image/jpeg")]
|
||||
[InlineData(".png", "image/png")]
|
||||
[InlineData(".svg", "image/svg+xml")]
|
||||
[InlineData(".svgz", "image/svg+xml")]
|
||||
[InlineData(".tbn", "image/jpeg")]
|
||||
[InlineData(".tif", "image/tiff")]
|
||||
[InlineData(".tiff", "image/tiff")]
|
||||
[InlineData(".webp", "image/webp")]
|
||||
[InlineData(".ttf", "font/ttf")]
|
||||
[InlineData(".woff", "font/woff")]
|
||||
[InlineData(".woff2", "font/woff2")]
|
||||
[InlineData(".ass", "text/x-ssa")]
|
||||
[InlineData(".ssa", "text/x-ssa")]
|
||||
[InlineData(".css", "text/css")]
|
||||
[InlineData(".csv", "text/csv")]
|
||||
[InlineData(".edl", "text/plain")]
|
||||
[InlineData(".txt", "text/plain")]
|
||||
[InlineData(".vtt", "text/vtt")]
|
||||
[InlineData(".3gp", "video/3gpp")]
|
||||
[InlineData(".3g2", "video/3gpp2")]
|
||||
[InlineData(".asf", "video/x-ms-asf")]
|
||||
[InlineData(".avi", "video/x-msvideo")]
|
||||
[InlineData(".flv", "video/x-flv")]
|
||||
[InlineData(".mp4", "video/mp4")]
|
||||
[InlineData(".m4v", "video/x-m4v")]
|
||||
[InlineData(".mpegts", "video/mp2t")]
|
||||
[InlineData(".mpg", "video/mpeg")]
|
||||
[InlineData(".mkv", "video/x-matroska")]
|
||||
[InlineData(".mov", "video/quicktime")]
|
||||
[InlineData(".ogv", "video/ogg")]
|
||||
[InlineData(".ts", "video/mp2t")]
|
||||
[InlineData(".webm", "video/webm")]
|
||||
[InlineData(".wmv", "video/x-ms-wmv")]
|
||||
[InlineData(".aac", "audio/aac")]
|
||||
[InlineData(".ac3", "audio/ac3")]
|
||||
[InlineData(".ape", "audio/x-ape")]
|
||||
[InlineData(".dsf", "audio/dsf")]
|
||||
[InlineData(".dsp", "audio/dsp")]
|
||||
[InlineData(".flac", "audio/flac")]
|
||||
[InlineData(".m4a", "audio/mp4")]
|
||||
[InlineData(".m4b", "audio/m4b")]
|
||||
[InlineData(".mid", "audio/midi")]
|
||||
[InlineData(".midi", "audio/midi")]
|
||||
[InlineData(".mp3", "audio/mpeg")]
|
||||
[InlineData(".oga", "audio/ogg")]
|
||||
[InlineData(".ogg", "audio/ogg")]
|
||||
[InlineData(".opus", "audio/ogg")]
|
||||
[InlineData(".vorbis", "audio/vorbis")]
|
||||
[InlineData(".wav", "audio/wav")]
|
||||
[InlineData(".webma", "audio/webm")]
|
||||
[InlineData(".wma", "audio/x-ms-wma")]
|
||||
[InlineData(".wv", "audio/x-wavpack")]
|
||||
[InlineData(".xsp", "audio/xsp")]
|
||||
public void GetMimeType_Valid_ReturnsCorrectResult(string input, string expectedResult)
|
||||
{
|
||||
Assert.Equal(expectedResult, MimeTypes.GetMimeType(input, null));
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("application/epub+zip", ".epub")]
|
||||
[InlineData("application/json", ".json")]
|
||||
[InlineData("application/oebps-package+xml", ".opf")]
|
||||
[InlineData("application/pdf", ".pdf")]
|
||||
[InlineData("application/ttml+xml", ".ttml")]
|
||||
[InlineData("application/vnd.amazon.ebook", ".azw")]
|
||||
[InlineData("application/vnd.ms-fontobject", ".eot")]
|
||||
[InlineData("application/vnd.rar", ".rar")]
|
||||
[InlineData("application/wasm", ".wasm")]
|
||||
[InlineData("application/x-7z-compressed", ".7z")]
|
||||
[InlineData("application/x-cbz", ".cbz")]
|
||||
[InlineData("application/x-javascript", ".js")]
|
||||
[InlineData("application/x-mobipocket-ebook", ".mobi")]
|
||||
[InlineData("application/x-mpegURL", ".m3u8")]
|
||||
[InlineData("application/x-subrip", ".srt")]
|
||||
[InlineData("application/xml", ".xml")]
|
||||
[InlineData("application/zip", ".zip")]
|
||||
[InlineData("audio/aac", ".aac")]
|
||||
[InlineData("audio/ac3", ".ac3")]
|
||||
[InlineData("audio/dsf", ".dsf")]
|
||||
[InlineData("audio/dsp", ".dsp")]
|
||||
[InlineData("audio/flac", ".flac")]
|
||||
[InlineData("audio/m4b", ".m4b")]
|
||||
[InlineData("audio/mp4", ".m4a")]
|
||||
[InlineData("audio/vorbis", ".vorbis")]
|
||||
[InlineData("audio/wav", ".wav")]
|
||||
[InlineData("audio/x-aac", ".aac")]
|
||||
[InlineData("audio/x-ape", ".ape")]
|
||||
[InlineData("audio/x-ms-wma", ".wma")]
|
||||
[InlineData("audio/x-wavpack", ".wv")]
|
||||
[InlineData("audio/xsp", ".xsp")]
|
||||
[InlineData("font/ttf", ".ttf")]
|
||||
[InlineData("font/woff", ".woff")]
|
||||
[InlineData("font/woff2", ".woff2")]
|
||||
[InlineData("image/bmp", ".bmp")]
|
||||
[InlineData("image/gif", ".gif")]
|
||||
[InlineData("image/jpg", ".jpg")]
|
||||
[InlineData("image/png", ".png")]
|
||||
[InlineData("image/svg+xml", ".svg")]
|
||||
[InlineData("image/tiff", ".tif")]
|
||||
[InlineData("image/vnd.microsoft.icon", ".ico")]
|
||||
[InlineData("image/webp", ".webp")]
|
||||
[InlineData("image/x-png", ".png")]
|
||||
[InlineData("text/css", ".css")]
|
||||
[InlineData("text/csv", ".csv")]
|
||||
[InlineData("text/plain", ".txt")]
|
||||
[InlineData("text/rtf", ".rtf")]
|
||||
[InlineData("text/vtt", ".vtt")]
|
||||
[InlineData("text/x-ssa", ".ssa")]
|
||||
[InlineData("video/3gpp", ".3gp")]
|
||||
[InlineData("video/3gpp2", ".3g2")]
|
||||
[InlineData("video/mp2t", ".ts")]
|
||||
[InlineData("video/mp4", ".mp4")]
|
||||
[InlineData("video/ogg", ".ogv")]
|
||||
[InlineData("video/quicktime", ".mov")]
|
||||
[InlineData("video/vnd.mpeg.dash.mpd", ".mpd")]
|
||||
[InlineData("video/webm", ".webm")]
|
||||
[InlineData("video/x-flv", ".flv")]
|
||||
[InlineData("video/x-m4v", ".m4v")]
|
||||
[InlineData("video/x-matroska", ".mkv")]
|
||||
[InlineData("video/x-ms-asf", ".asf")]
|
||||
[InlineData("video/x-ms-wmv", ".wmv")]
|
||||
[InlineData("video/x-msvideo", ".avi")]
|
||||
public void ToExtension_Valid_ReturnsCorrectResult(string input, string expectedResult)
|
||||
{
|
||||
Assert.Equal(expectedResult, MimeTypes.ToExtension(input));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user