Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[package:mime] make mp3 default for audio/mpeg #2048

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions pkgs/mime/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 2.0.1
* `extensionFromMime(String mimeType)` returns `mp3` instead of `mpga` for mime type `audio/mpeg`.
* `extensionFromMime(String mimeType)` Add default lookup for all mime type.

## 2.0.0

* **[Breaking]** `extensionFromMime(String mimeType)` returns `null` instead of `mimeType` for an unknown mime type.
Expand Down
2 changes: 1 addition & 1 deletion pkgs/mime/doc/media_types.md
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ Supported media types and file extensions.
| `audio/basic` | `snd` | `au` |
| `audio/midi` | `mid` | `kar`, `midi`, `rmi` |
| `audio/mp4` | `m4a` | `m4b`, `mp4a` |
| `audio/mpeg` | `mpga` | `m2a`, `m3a`, `mp2`, `mp2a`, `mp3` |
| `audio/mpeg` | `mp3` | `m2a`, `m3a`, `mp2`, `mp2a`, `mpga` |
| `audio/ogg` | `ogg` | `oga`, `spx` |
| `audio/s3m` | `s3m` | |
| `audio/silk` | `sil` | |
Expand Down
120 changes: 118 additions & 2 deletions pkgs/mime/lib/src/extension.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'package:meta/meta.dart';

import 'default_extension_map.dart';

/// Default extension for recognized MIME types.
Expand All @@ -13,36 +15,150 @@ import 'default_extension_map.dart';
///
/// Used by [extensionFromMime].
final Map<String, String> _defaultMimeTypeMap = {
..._additionalMimeTypesForExistingExtensionsMap,
for (var entry in defaultExtensionMap.entries) entry.value: entry.key,
..._defaultMimeTypeFallbackMap,
};

/// A map for with the default file extensions for MIME types.
///
/// setting default file extensions for MIME types,
/// which are having multiple extensions
///
/// used by [_defaultMimeTypeMap]
const Map<String, String> _defaultMimeTypeFallbackMap = {
'application/inkml+xml': 'inkml',
'application/mathematica': 'nb',
'application/mp21': 'mp21',
'application/msword': 'doc',
'application/octet-stream': 'so',
'application/onenote': 'onetoc2',
'application/pgp-signature': 'sig',
'application/pkcs7-mime': 'p7m',
'application/postscript': 'ps',
'application/smil+xml': 'smil',
'application/tei+xml': 'teicorpus',
'application/vnd.acucorp': 'atc',
'application/vnd.adobe.fxp': 'fxpl',
'application/vnd.clonk.c4group': 'c4u',
'application/vnd.dece.data': 'uvvf',
'application/vnd.dece.ttml+xml': 'uvvt',
'application/vnd.dece.unspecified': 'uvx',
'application/vnd.dece.zip': 'uvz',
'application/vnd.eszigno3+xml': 'et3',
'application/vnd.fdsn.seed': 'seed',
'application/vnd.framemaker': 'maker',
'application/vnd.geometry-explorer': 'gre',
'application/vnd.grafeq': 'gqs',
'application/vnd.ibm.modcap': 'listafp',
'application/vnd.iccprofile': 'icm',
'application/vnd.intercon.formnet': 'xpx',
'application/vnd.kahootz': 'ktz',
'application/vnd.kde.kpresenter': 'kpt',
'application/vnd.kde.kword': 'kwt',
'application/vnd.kinar': 'knp',
'application/vnd.koan': 'skt',
'application/vnd.ms-excel': 'xls',
'application/vnd.ms-powerpoint': 'ppt',
'application/vnd.ms-project': 'mpt',
'application/vnd.ms-works': 'wps',
'application/vnd.nitf': 'ntf',
'application/vnd.palm': 'pqa',
'application/vnd.quark.quarkxpress': 'qxt',
'application/vnd.simtech-mindmapper': 'twds',
'application/vnd.solent.sdkm+xml': 'sdkm',
'application/vnd.stardivision.writer': 'vor',
'application/vnd.sus-calendar': 'susp',
'application/vnd.symbian.install': 'sisx',
'application/vnd.tcpdump.pcap': 'pcap',
'application/vnd.ufdl': 'ufdl',
'application/vnd.visio': 'vsw',
'application/vnd.zul': 'zirz',
'application/x-authorware-bin': 'x32',
'application/x-blorb': 'blorb',
'application/x-bzip2': 'bz2',
'application/x-cbr': 'cbz',
'application/x-debian-package': 'deb',
'application/x-director': 'w3d',
'application/x-font-ttf': 'ttf',
'application/x-font-type1': 'pfm',
'application/x-lzh-compressed': 'lzh',
'application/x-mobipocket-ebook': 'prc',
'application/x-msdownload': 'msi',
'application/x-msmediaview': 'mvb',
'application/x-msmetafile': 'wmf',
'application/x-netcdf': 'nc',
'application/x-pkcs12': 'pfx',
'application/x-pkcs7-certificates': 'spc',
'application/x-texinfo': 'texinfo',
'application/x-x509-ca-cert': 'der',
'application/x-zmachine': 'z8',
'application/xhtml+xml': 'xhtml',
'application/xml': 'xml',
'audio/x-aiff': 'aif',
'application/xv+xml': 'xvml',
'audio/basic': 'snd',
'audio/midi': 'mid',
'audio/mp4': 'm4a',
'audio/mpeg': 'mp3',
'audio/ogg': 'ogg',
'audio/vnd.dece.audio': 'uvva',
'audio/x-aiff': 'aif',
'audio/x-pn-realaudio': 'ram',
'image/jpeg': 'jpg',
'image/tiff': 'tif',
'image/svg+xml': 'svg',
'image/tiff': 'tif',
'image/vnd.dece.graphic': 'uvvi',
'image/vnd.djvu': 'djvu',
'image/x-freehand': 'fhc',
'image/x-pict': 'pic',
'message/rfc822': 'mime',
'model/iges': 'igs',
'model/mesh': 'silo',
'model/vrml': 'vrml',
'model/x3d+binary': 'x3dbz',
'model/x3d+vrml': 'x3dvz',
'model/x3d+xml': 'x3dz',
'text/calendar': 'ics',
'text/html': 'html',
'text/javascript': 'js',
'text/markdown': 'md',
'text/plain': 'txt',
'text/sgml': 'sgml',
'text/troff': 'tr',
'text/uri-list': 'urls',
'text/x-asm': 'asm',
'text/x-c': 'c',
'text/x-fortran': 'for',
'text/x-pascal': 'pas',
'video/jpm': 'jpm',
'video/mj2': 'mjp2',
'video/mp4': 'mp4',
'video/mpeg': 'mpg',
'video/quicktime': 'mov',
'video/vnd.dece.hd': 'uvvh',
'video/vnd.dece.mobile': 'uvvm',
'video/vnd.dece.pd': 'uvvp',
'video/vnd.dece.sd': 'uvvs',
'video/vnd.dece.video': 'uvvv',
'video/vnd.mpegurl': 'mxu',
'video/vnd.uvvu.mp4': 'uvvu',
'video/x-matroska': 'mkv',
'video/x-ms-asf': 'asx',
};

/// Additional MIME types for existing extensions.
///
/// used for additional mime types, used by the existing extensions
/// used by [_defaultMimeTypeMap]
const Map<String, String> _additionalMimeTypesForExistingExtensionsMap = {
'audio/wav': 'wav',
};

/// access [_defaultMimeTypeFallbackMap] for testing purposes
@visibleForTesting
const Map<String, String> defaultMimeTypeFallbackMap =
_defaultMimeTypeFallbackMap;

/// The default file extension for a given MIME type.
///
/// If [mimeType] has multiple associated extensions,
Expand Down
4 changes: 3 additions & 1 deletion pkgs/mime/pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
name: mime
version: 2.0.0
version: 2.0.1
description: >-
Utilities for handling media (MIME) types, including determining a type from
a file extension and file contents.
Expand All @@ -18,3 +18,5 @@ environment:
dev_dependencies:
dart_flutter_team_lints: ^3.0.0
test: ^1.16.0
dependencies:
meta: ^1.16.0
28 changes: 28 additions & 0 deletions pkgs/mime/test/extension_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.

import 'package:mime/mime.dart';
import 'package:mime/src/default_extension_map.dart';
import 'package:test/test.dart';

void main() {
Expand All @@ -20,6 +21,7 @@ void main() {
expect(extensionFromMime('text/html'), equals('html'));
expect(extensionFromMime('text/plain'), equals('txt'));
expect(extensionFromMime('text/x-c'), equals('c'));
expect(extensionFromMime('audio/mpeg'), equals('mp3'));
});

test('invalid-mime-type', () {
Expand All @@ -30,4 +32,30 @@ void main() {
test('unknown-mime-type', () {
expect(extensionFromMime('application/to-be-invented'), isNull);
});

test('fallback-mime-type-missing-implementations', () {
final mimeTypesUsedCounter = <String, int>{};
for (final mimeType in defaultExtensionMap.values) {
final current = mimeTypesUsedCounter[mimeType];
if (current == null) {
mimeTypesUsedCounter[mimeType] = 1;
} else {
mimeTypesUsedCounter[mimeType] = current + 1;
}
}
final requiresOverride = mimeTypesUsedCounter.entries
.where((e) => e.value > 1)
.map((e) => e.key);
final missingOverrides = requiresOverride
.where((e) => !defaultMimeTypeFallbackMap.containsKey(e));
expect(missingOverrides, isEmpty,
reason: 'missing overrides of mime types for $missingOverrides');
});

test('overridden-type-not-in-map', () {
for (final mimeType in defaultMimeTypeFallbackMap.entries) {
expect(defaultExtensionMap[mimeType.value], mimeType.key,
reason: 'override is missing in original map');
}
});
}