content-types 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {content_types-0.2.0 → content_types-0.2.2}/PKG-INFO +22 -6
- content_types-0.2.2/README.md +53 -0
- content_types-0.2.2/content_types/__init__.py +287 -0
- content_types-0.2.2/content_types/py.typed +0 -0
- {content_types-0.2.0 → content_types-0.2.2}/pyproject.toml +6 -1
- content_types-0.2.0/README.md +0 -40
- content_types-0.2.0/content_types/__init__.py +0 -158
- {content_types-0.2.0 → content_types-0.2.2}/.gitignore +0 -0
- {content_types-0.2.0 → content_types-0.2.2}/LICENSE +0 -0
- {content_types-0.2.0 → content_types-0.2.2}/ruff.toml +0 -0
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: content-types
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: A library to map file extensions to content types and vice versa.
|
|
5
|
+
Project-URL: Homepage, https://github.com/mikeckennedy/content-types
|
|
6
|
+
Project-URL: Bug Reports, https://github.com/mikeckennedy/content-types/issues
|
|
7
|
+
Project-URL: Source, https://github.com/mikeckennedy/content-types
|
|
5
8
|
Author-email: Michael Kennedy <mikeckennedy@gmail.com>
|
|
6
9
|
License-Expression: MIT
|
|
7
10
|
License-File: LICENSE
|
|
@@ -26,6 +29,12 @@ A Python library to map file extensions to MIME types.
|
|
|
26
29
|
It also provides a CLI for quick lookups right from your terminal.
|
|
27
30
|
If no known mapping is found, the tool returns `application/octet-stream`.
|
|
28
31
|
|
|
32
|
+
Unlike other libraries, this one does **not** try to access the file
|
|
33
|
+
or parse the bytes of the file or stream. It just looks at the extension
|
|
34
|
+
which is valuable when you don't have access to the file directly.
|
|
35
|
+
For example, you know the filename but it is stored in s3 and you don't want
|
|
36
|
+
to download it just to fully inspect the file.
|
|
37
|
+
|
|
29
38
|
## Installation
|
|
30
39
|
|
|
31
40
|
```bash
|
|
@@ -38,19 +47,26 @@ uv pip install content-types
|
|
|
38
47
|
import content_types
|
|
39
48
|
|
|
40
49
|
# Forward lookup: filename -> MIME type
|
|
41
|
-
|
|
42
|
-
print(
|
|
50
|
+
the_type = content_types.get_content_type("example.jpg")
|
|
51
|
+
print(the_type) # "image/jpeg"
|
|
43
52
|
|
|
44
53
|
# For very common files, you have shortcuts:
|
|
45
|
-
print(f'Content-Type for webp is {content_types.webp}')
|
|
54
|
+
print(f'Content-Type for webp is {content_types.webp}.')
|
|
55
|
+
# Content-Type for webp is image/webp.
|
|
46
56
|
```
|
|
47
57
|
|
|
48
58
|
## CLI
|
|
49
59
|
|
|
50
|
-
|
|
60
|
+
To use the library as a CLI tool, just install it with **uv** or **pipx**.
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
uv tool install content-types
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Now it will be available machine-wide.
|
|
51
67
|
|
|
52
68
|
```bash
|
|
53
|
-
|
|
69
|
+
content-types example.jpg
|
|
54
70
|
|
|
55
71
|
# Outputs image/jpeg
|
|
56
72
|
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|
|
2
|
+
# content-types 🗃️🔎
|
|
3
|
+
|
|
4
|
+
A Python library to map file extensions to MIME types.
|
|
5
|
+
It also provides a CLI for quick lookups right from your terminal.
|
|
6
|
+
If no known mapping is found, the tool returns `application/octet-stream`.
|
|
7
|
+
|
|
8
|
+
Unlike other libraries, this one does **not** try to access the file
|
|
9
|
+
or parse the bytes of the file or stream. It just looks at the extension
|
|
10
|
+
which is valuable when you don't have access to the file directly.
|
|
11
|
+
For example, you know the filename but it is stored in s3 and you don't want
|
|
12
|
+
to download it just to fully inspect the file.
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
uv pip install content-types
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
## Usage
|
|
21
|
+
|
|
22
|
+
```python
|
|
23
|
+
import content_types
|
|
24
|
+
|
|
25
|
+
# Forward lookup: filename -> MIME type
|
|
26
|
+
the_type = content_types.get_content_type("example.jpg")
|
|
27
|
+
print(the_type) # "image/jpeg"
|
|
28
|
+
|
|
29
|
+
# For very common files, you have shortcuts:
|
|
30
|
+
print(f'Content-Type for webp is {content_types.webp}.')
|
|
31
|
+
# Content-Type for webp is image/webp.
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## CLI
|
|
35
|
+
|
|
36
|
+
To use the library as a CLI tool, just install it with **uv** or **pipx**.
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
uv tool install content-types
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Now it will be available machine-wide.
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
content-types example.jpg
|
|
46
|
+
|
|
47
|
+
# Outputs image/jpeg
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Contributing
|
|
51
|
+
|
|
52
|
+
Contributions are welcome! Check out [the GitHub repo](https://github.com/mikeckennedy/content-types)
|
|
53
|
+
for more details on how to get involved.
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
import sys
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
from typing import Dict
|
|
4
|
+
|
|
5
|
+
__VERSION__ = '0.2.2'
|
|
6
|
+
|
|
7
|
+
# This dictionary maps file extensions (no dot) to the most specific content type.
|
|
8
|
+
|
|
9
|
+
# noinspection SpellCheckingInspection
|
|
10
|
+
EXTENSION_TO_CONTENT_TYPE: Dict[str, str] = {
|
|
11
|
+
# Text
|
|
12
|
+
'txt': 'text/plain',
|
|
13
|
+
'htm': 'text/html',
|
|
14
|
+
'html': 'text/html',
|
|
15
|
+
'css': 'text/css',
|
|
16
|
+
'csv': 'text/csv',
|
|
17
|
+
'tsv': 'text/tab-separated-values',
|
|
18
|
+
# JavaScript
|
|
19
|
+
'js': 'application/javascript', # commonly "application/javascript" nowadays
|
|
20
|
+
# MJS for ES modules
|
|
21
|
+
'mjs': 'application/javascript',
|
|
22
|
+
# JSON
|
|
23
|
+
'json': 'application/json',
|
|
24
|
+
'map': 'application/json',
|
|
25
|
+
# XML (keep application/xml)
|
|
26
|
+
'xml': 'application/xml',
|
|
27
|
+
# Images
|
|
28
|
+
'jpg': 'image/jpeg',
|
|
29
|
+
'jpeg': 'image/jpeg',
|
|
30
|
+
'png': 'image/png',
|
|
31
|
+
'gif': 'image/gif',
|
|
32
|
+
'bmp': 'image/bmp',
|
|
33
|
+
'webp': 'image/webp',
|
|
34
|
+
'avif': 'image/avif',
|
|
35
|
+
# Some new ones:
|
|
36
|
+
'ico': 'image/x-icon',
|
|
37
|
+
'svg': 'image/svg+xml',
|
|
38
|
+
'tif': 'image/tiff',
|
|
39
|
+
'tiff': 'image/tiff',
|
|
40
|
+
'heic': 'image/heic', # new
|
|
41
|
+
'heif': 'image/heif', # new
|
|
42
|
+
'jpe': 'image/jpeg', # new alias
|
|
43
|
+
'ief': 'image/ief', # new
|
|
44
|
+
'ras': 'image/x-cmu-raster', # new
|
|
45
|
+
'pnm': 'image/x-portable-anymap',
|
|
46
|
+
'pbm': 'image/x-portable-bitmap',
|
|
47
|
+
'pgm': 'image/x-portable-graymap',
|
|
48
|
+
'ppm': 'image/x-portable-pixmap',
|
|
49
|
+
'rgb': 'image/x-rgb',
|
|
50
|
+
'xbm': 'image/x-xbitmap',
|
|
51
|
+
'xpm': 'image/x-xpixmap',
|
|
52
|
+
'xwd': 'image/x-xwindowdump',
|
|
53
|
+
# Audio
|
|
54
|
+
'mp3': 'audio/mpeg',
|
|
55
|
+
'ogg': 'audio/ogg',
|
|
56
|
+
'wav': 'audio/wav',
|
|
57
|
+
'aac': 'audio/aac',
|
|
58
|
+
'flac': 'audio/flac',
|
|
59
|
+
'm4a': 'audio/mp4',
|
|
60
|
+
'weba': 'audio/webm',
|
|
61
|
+
# New ones:
|
|
62
|
+
'mp2': 'audio/mpeg', # new
|
|
63
|
+
'opus': 'audio/opus', # new
|
|
64
|
+
'aif': 'audio/x-aiff',
|
|
65
|
+
'aifc': 'audio/x-aiff',
|
|
66
|
+
'aiff': 'audio/x-aiff',
|
|
67
|
+
'au': 'audio/basic',
|
|
68
|
+
'snd': 'audio/basic',
|
|
69
|
+
'ra': 'audio/x-pn-realaudio',
|
|
70
|
+
# Video
|
|
71
|
+
'mp4': 'video/mp4',
|
|
72
|
+
'm4v': 'video/mp4',
|
|
73
|
+
'mov': 'video/quicktime',
|
|
74
|
+
'avi': 'video/x-msvideo',
|
|
75
|
+
'wmv': 'video/x-ms-wmv',
|
|
76
|
+
'mpg': 'video/mpeg',
|
|
77
|
+
'mpeg': 'video/mpeg',
|
|
78
|
+
'ogv': 'video/ogg',
|
|
79
|
+
'webm': 'video/webm',
|
|
80
|
+
# New aliases:
|
|
81
|
+
'm1v': 'video/mpeg',
|
|
82
|
+
'mpa': 'video/mpeg',
|
|
83
|
+
'mpe': 'video/mpeg',
|
|
84
|
+
'qt': 'video/quicktime',
|
|
85
|
+
'movie': 'video/x-sgi-movie',
|
|
86
|
+
# 3GP family (prefer official video/*):
|
|
87
|
+
'3gp': 'video/3gpp',
|
|
88
|
+
'3gpp': 'video/3gpp',
|
|
89
|
+
'3g2': 'video/3gpp2',
|
|
90
|
+
'3gpp2': 'video/3gpp2',
|
|
91
|
+
# Archives / Packages
|
|
92
|
+
'pdf': 'application/pdf',
|
|
93
|
+
'zip': 'application/zip',
|
|
94
|
+
'gz': 'application/gzip',
|
|
95
|
+
'tgz': 'application/gzip',
|
|
96
|
+
'tar': 'application/x-tar',
|
|
97
|
+
'7z': 'application/x-7z-compressed',
|
|
98
|
+
'rar': 'application/vnd.rar',
|
|
99
|
+
# Additional
|
|
100
|
+
'bin': 'application/octet-stream', # new explicit
|
|
101
|
+
'a': 'application/octet-stream',
|
|
102
|
+
'so': 'application/octet-stream',
|
|
103
|
+
'o': 'application/octet-stream',
|
|
104
|
+
'obj': 'model/obj', # keep from original (not octet-stream)
|
|
105
|
+
'dll': 'application/x-msdownload',
|
|
106
|
+
'exe': 'application/x-msdownload',
|
|
107
|
+
# Some additional archiving/compression tools
|
|
108
|
+
'bcpio': 'application/x-bcpio',
|
|
109
|
+
'cpio': 'application/x-cpio',
|
|
110
|
+
'shar': 'application/x-shar',
|
|
111
|
+
'sv4cpio': 'application/x-sv4cpio',
|
|
112
|
+
'sv4crc': 'application/x-sv4crc',
|
|
113
|
+
'ustar': 'application/x-ustar',
|
|
114
|
+
'src': 'application/x-wais-source',
|
|
115
|
+
# Application / Office
|
|
116
|
+
'doc': 'application/msword',
|
|
117
|
+
'xls': 'application/vnd.ms-excel',
|
|
118
|
+
'ppt': 'application/vnd.ms-powerpoint',
|
|
119
|
+
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
120
|
+
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
121
|
+
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
122
|
+
# New ones:
|
|
123
|
+
'dot': 'application/msword',
|
|
124
|
+
'wiz': 'application/msword',
|
|
125
|
+
'xlb': 'application/vnd.ms-excel',
|
|
126
|
+
'pot': 'application/vnd.ms-powerpoint',
|
|
127
|
+
'ppa': 'application/vnd.ms-powerpoint',
|
|
128
|
+
'pps': 'application/vnd.ms-powerpoint',
|
|
129
|
+
'pwz': 'application/vnd.ms-powerpoint',
|
|
130
|
+
# Additional special apps
|
|
131
|
+
'webmanifest': 'application/manifest+json',
|
|
132
|
+
'nq': 'application/n-quads',
|
|
133
|
+
'nt': 'application/n-triples',
|
|
134
|
+
'oda': 'application/oda',
|
|
135
|
+
'p7c': 'application/pkcs7-mime',
|
|
136
|
+
'ps': 'application/postscript',
|
|
137
|
+
'ai': 'application/postscript',
|
|
138
|
+
'eps': 'application/postscript',
|
|
139
|
+
'trig': 'application/trig',
|
|
140
|
+
'm3u': 'application/vnd.apple.mpegurl',
|
|
141
|
+
'm3u8': 'application/vnd.apple.mpegurl',
|
|
142
|
+
'wasm': 'application/wasm',
|
|
143
|
+
'csh': 'application/x-csh',
|
|
144
|
+
'dvi': 'application/x-dvi',
|
|
145
|
+
'gtar': 'application/x-gtar',
|
|
146
|
+
'hdf': 'application/x-hdf',
|
|
147
|
+
'h5': 'application/x-hdf5', # not in older standard lists but sometimes used
|
|
148
|
+
'latex': 'application/x-latex',
|
|
149
|
+
'mif': 'application/x-mif',
|
|
150
|
+
'cdf': 'application/x-netcdf',
|
|
151
|
+
'nc': 'application/x-netcdf',
|
|
152
|
+
'p12': 'application/x-pkcs12',
|
|
153
|
+
'pfx': 'application/x-pkcs12',
|
|
154
|
+
'ram': 'application/x-pn-realaudio',
|
|
155
|
+
'pyc': 'application/x-python-code',
|
|
156
|
+
'pyo': 'application/x-python-code',
|
|
157
|
+
'swf': 'application/x-shockwave-flash',
|
|
158
|
+
'tcl': 'application/x-tcl',
|
|
159
|
+
'tex': 'application/x-tex',
|
|
160
|
+
'texi': 'application/x-texinfo',
|
|
161
|
+
'texinfo': 'application/x-texinfo',
|
|
162
|
+
'roff': 'application/x-troff',
|
|
163
|
+
't': 'application/x-troff',
|
|
164
|
+
'tr': 'application/x-troff',
|
|
165
|
+
'man': 'application/x-troff-man',
|
|
166
|
+
'me': 'application/x-troff-me',
|
|
167
|
+
'ms': 'application/x-troff-ms',
|
|
168
|
+
# More XML-based
|
|
169
|
+
'xsl': 'application/xml',
|
|
170
|
+
'rdf': 'application/xml',
|
|
171
|
+
'wsdl': 'application/xml',
|
|
172
|
+
'xpdl': 'application/xml',
|
|
173
|
+
# ODF
|
|
174
|
+
'odt': 'application/vnd.oasis.opendocument.text',
|
|
175
|
+
'ods': 'application/vnd.oasis.opendocument.spreadsheet',
|
|
176
|
+
'odp': 'application/vnd.oasis.opendocument.presentation',
|
|
177
|
+
'odg': 'application/vnd.oasis.opendocument.graphics',
|
|
178
|
+
# Fonts
|
|
179
|
+
'otf': 'font/otf',
|
|
180
|
+
'ttf': 'font/ttf',
|
|
181
|
+
'woff': 'font/woff',
|
|
182
|
+
'woff2': 'font/woff2',
|
|
183
|
+
# 3D
|
|
184
|
+
'gltf': 'model/gltf+json',
|
|
185
|
+
'glb': 'model/gltf-binary',
|
|
186
|
+
'stl': 'model/stl',
|
|
187
|
+
# Scripts / Misc
|
|
188
|
+
'sh': 'application/x-sh',
|
|
189
|
+
'php': 'application/x-httpd-php',
|
|
190
|
+
# Code files
|
|
191
|
+
'py': 'text/x-python', # new (rather than text/plain)
|
|
192
|
+
'c': 'text/plain', # some prefer text/x-c; we’ll keep text/plain
|
|
193
|
+
'h': 'text/plain',
|
|
194
|
+
'ksh': 'text/plain',
|
|
195
|
+
'pl': 'text/plain',
|
|
196
|
+
'bat': 'text/plain',
|
|
197
|
+
# Packages etc.
|
|
198
|
+
'apk': 'application/vnd.android.package-archive',
|
|
199
|
+
'deb': 'application/x-debian-package',
|
|
200
|
+
'rpm': 'application/x-rpm',
|
|
201
|
+
# Messages
|
|
202
|
+
'eml': 'message/rfc822',
|
|
203
|
+
'mht': 'message/rfc822',
|
|
204
|
+
'mhtml': 'message/rfc822',
|
|
205
|
+
'nws': 'message/rfc822',
|
|
206
|
+
# Markdown / Markup
|
|
207
|
+
'md': 'text/markdown',
|
|
208
|
+
'markdown': 'text/markdown',
|
|
209
|
+
# RDF-ish / text-ish
|
|
210
|
+
'n3': 'text/n3',
|
|
211
|
+
'rtx': 'text/richtext',
|
|
212
|
+
'rtf': 'text/rtf',
|
|
213
|
+
'srt': 'text/plain',
|
|
214
|
+
'vtt': 'text/vtt',
|
|
215
|
+
'etx': 'text/x-setext',
|
|
216
|
+
'sgm': 'text/x-sgml',
|
|
217
|
+
'sgml': 'text/x-sgml',
|
|
218
|
+
'vcf': 'text/x-vcard',
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
def get_content_type(filename_or_extension: str | Path, treat_as_binary: bool = True) -> str:
|
|
223
|
+
"""
|
|
224
|
+
Given a filename (or just an extension), return the most specific,
|
|
225
|
+
commonly accepted MIME type based on extension.
|
|
226
|
+
|
|
227
|
+
Falls back to 'application/octet-stream' if not found.
|
|
228
|
+
|
|
229
|
+
Example:
|
|
230
|
+
>>> get_content_type("picture.jpg")
|
|
231
|
+
'image/jpeg'
|
|
232
|
+
>>> get_content_type(".webp")
|
|
233
|
+
'image/webp'
|
|
234
|
+
>>> get_content_type("script.js")
|
|
235
|
+
'application/javascript'
|
|
236
|
+
>>> get_content_type("unknown.xyz")
|
|
237
|
+
'application/octet-stream'
|
|
238
|
+
>>> get_content_type("unknown.xyz", treat_as_binary=False)
|
|
239
|
+
'application/octet-stream'
|
|
240
|
+
"""
|
|
241
|
+
|
|
242
|
+
if filename_or_extension is None:
|
|
243
|
+
raise Exception('filename cannot be None.')
|
|
244
|
+
|
|
245
|
+
if isinstance(filename_or_extension, Path):
|
|
246
|
+
filename_or_extension = filename_or_extension.suffix
|
|
247
|
+
|
|
248
|
+
if '.' not in filename_or_extension:
|
|
249
|
+
filename_or_extension = f'.{filename_or_extension}'
|
|
250
|
+
|
|
251
|
+
# Split by dot, take the last part as extension
|
|
252
|
+
# e.g., "archive.tar.gz" => "gz"
|
|
253
|
+
# Also handle cases like ".webp" => "webp"
|
|
254
|
+
dot_parts = filename_or_extension.lower().split('.')
|
|
255
|
+
ext = dot_parts[-1] if len(dot_parts) > 1 else ''
|
|
256
|
+
|
|
257
|
+
if treat_as_binary:
|
|
258
|
+
return EXTENSION_TO_CONTENT_TYPE.get(ext, 'application/octet-stream')
|
|
259
|
+
|
|
260
|
+
return EXTENSION_TO_CONTENT_TYPE.get(ext, 'text/plain')
|
|
261
|
+
|
|
262
|
+
|
|
263
|
+
webp: str = get_content_type('.webp')
|
|
264
|
+
png: str = get_content_type('.png')
|
|
265
|
+
jpg: str = get_content_type('.jpg')
|
|
266
|
+
mp3: str = get_content_type('.mp3')
|
|
267
|
+
json: str = get_content_type('.json')
|
|
268
|
+
pdf: str = get_content_type('.pdf')
|
|
269
|
+
zip: str = get_content_type('.zip') # noqa == it's fine to overwrite zip() in this module only.
|
|
270
|
+
xml: str = get_content_type('.xml')
|
|
271
|
+
csv: str = get_content_type('.csv')
|
|
272
|
+
md: str = get_content_type('.md')
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
def cli():
|
|
276
|
+
"""
|
|
277
|
+
A simple CLI to look up the MIME type for a given filename or extension.
|
|
278
|
+
Usage example:
|
|
279
|
+
contenttypes my_file.jpg
|
|
280
|
+
"""
|
|
281
|
+
if len(sys.argv) < 2:
|
|
282
|
+
print('Usage: contenttypes [FILENAME_OR_EXTENSION]\nExample: contenttypes .jpg')
|
|
283
|
+
sys.exit(1)
|
|
284
|
+
|
|
285
|
+
filename = sys.argv[1]
|
|
286
|
+
mime_type = get_content_type(filename)
|
|
287
|
+
print(mime_type)
|
|
File without changes
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "content-types"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.2" # You can manage version bumps manually or use a plugin for dynamic versioning
|
|
8
8
|
description = "A library to map file extensions to content types and vice versa."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -31,5 +31,10 @@ classifiers = [
|
|
|
31
31
|
"Topic :: Software Development :: Libraries :: Python Modules"
|
|
32
32
|
]
|
|
33
33
|
|
|
34
|
+
[project.urls]
|
|
35
|
+
"Homepage" = "https://github.com/mikeckennedy/content-types"
|
|
36
|
+
"Bug Reports" = "https://github.com/mikeckennedy/content-types/issues"
|
|
37
|
+
"Source" = "https://github.com/mikeckennedy/content-types"
|
|
38
|
+
|
|
34
39
|
[project.scripts]
|
|
35
40
|
content-types = "content_types:cli"
|
content_types-0.2.0/README.md
DELETED
|
@@ -1,40 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
# content-types 🗃️🔎
|
|
3
|
-
|
|
4
|
-
A Python library to map file extensions to MIME types.
|
|
5
|
-
It also provides a CLI for quick lookups right from your terminal.
|
|
6
|
-
If no known mapping is found, the tool returns `application/octet-stream`.
|
|
7
|
-
|
|
8
|
-
## Installation
|
|
9
|
-
|
|
10
|
-
```bash
|
|
11
|
-
uv pip install content-types
|
|
12
|
-
```
|
|
13
|
-
|
|
14
|
-
## Usage
|
|
15
|
-
|
|
16
|
-
```python
|
|
17
|
-
import content_types
|
|
18
|
-
|
|
19
|
-
# Forward lookup: filename -> MIME type
|
|
20
|
-
mime_type = content_types.get_content_type("example.jpg")
|
|
21
|
-
print(mime_type) # "image/jpeg"
|
|
22
|
-
|
|
23
|
-
# For very common files, you have shortcuts:
|
|
24
|
-
print(f'Content-Type for webp is {content_types.webp}') # 'image/webp'
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
## CLI
|
|
28
|
-
|
|
29
|
-
After installing in a virtual environment or system-wide.
|
|
30
|
-
|
|
31
|
-
```bash
|
|
32
|
-
contenttypes example.jpg
|
|
33
|
-
|
|
34
|
-
# Outputs image/jpeg
|
|
35
|
-
```
|
|
36
|
-
|
|
37
|
-
## Contributing
|
|
38
|
-
|
|
39
|
-
Contributions are welcome! Check out [the GitHub repo](https://github.com/mikeckennedy/content-types)
|
|
40
|
-
for more details on how to get involved.
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
import sys
|
|
2
|
-
from pathlib import Path
|
|
3
|
-
from typing import Dict
|
|
4
|
-
|
|
5
|
-
__VERSION__ = '0.2.0'
|
|
6
|
-
|
|
7
|
-
# This dictionary maps file extensions (no dot) to the most specific content type.
|
|
8
|
-
EXTENSION_TO_CONTENT_TYPE: Dict[str, str] = {
|
|
9
|
-
# Text
|
|
10
|
-
'txt': 'text/plain',
|
|
11
|
-
'htm': 'text/html',
|
|
12
|
-
'html': 'text/html',
|
|
13
|
-
'css': 'text/css',
|
|
14
|
-
'csv': 'text/csv',
|
|
15
|
-
'tsv': 'text/tab-separated-values',
|
|
16
|
-
# JavaScript
|
|
17
|
-
'js': 'application/javascript', # commonly "application/javascript" nowadays
|
|
18
|
-
# JSON
|
|
19
|
-
'json': 'application/json',
|
|
20
|
-
'map': 'application/json', # e.g., SourceMap
|
|
21
|
-
# XML
|
|
22
|
-
'xml': 'application/xml', # can also be "text/xml" in some contexts
|
|
23
|
-
# Images
|
|
24
|
-
'jpg': 'image/jpeg',
|
|
25
|
-
'jpeg': 'image/jpeg',
|
|
26
|
-
'png': 'image/png',
|
|
27
|
-
'gif': 'image/gif',
|
|
28
|
-
'bmp': 'image/bmp',
|
|
29
|
-
'webp': 'image/webp',
|
|
30
|
-
'avif': 'image/avif',
|
|
31
|
-
'ico': 'image/x-icon', # sometimes "image/vnd.microsoft.icon"
|
|
32
|
-
'svg': 'image/svg+xml',
|
|
33
|
-
'tif': 'image/tiff',
|
|
34
|
-
'tiff': 'image/tiff',
|
|
35
|
-
# Audio
|
|
36
|
-
'mp3': 'audio/mpeg',
|
|
37
|
-
'ogg': 'audio/ogg',
|
|
38
|
-
'wav': 'audio/wav',
|
|
39
|
-
'aac': 'audio/aac',
|
|
40
|
-
'flac': 'audio/flac',
|
|
41
|
-
'm4a': 'audio/mp4',
|
|
42
|
-
'weba': 'audio/webm',
|
|
43
|
-
# Video
|
|
44
|
-
'mp4': 'video/mp4',
|
|
45
|
-
'm4v': 'video/mp4', # often container-based
|
|
46
|
-
'mov': 'video/quicktime',
|
|
47
|
-
'avi': 'video/x-msvideo',
|
|
48
|
-
'wmv': 'video/x-ms-wmv',
|
|
49
|
-
'mpg': 'video/mpeg',
|
|
50
|
-
'mpeg': 'video/mpeg',
|
|
51
|
-
'ogv': 'video/ogg',
|
|
52
|
-
'webm': 'video/webm',
|
|
53
|
-
# Application / Archive
|
|
54
|
-
'pdf': 'application/pdf',
|
|
55
|
-
'zip': 'application/zip',
|
|
56
|
-
'gz': 'application/gzip',
|
|
57
|
-
'tgz': 'application/gzip', # or "application/x-tar" + "gzip"
|
|
58
|
-
'tar': 'application/x-tar',
|
|
59
|
-
'7z': 'application/x-7z-compressed',
|
|
60
|
-
'rar': 'application/vnd.rar',
|
|
61
|
-
# Office
|
|
62
|
-
'doc': 'application/msword',
|
|
63
|
-
'xls': 'application/vnd.ms-excel',
|
|
64
|
-
'ppt': 'application/vnd.ms-powerpoint',
|
|
65
|
-
'docx': 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
|
66
|
-
'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
|
67
|
-
'pptx': 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
|
68
|
-
# OpenDocument
|
|
69
|
-
'odt': 'application/vnd.oasis.opendocument.text',
|
|
70
|
-
'ods': 'application/vnd.oasis.opendocument.spreadsheet',
|
|
71
|
-
'odp': 'application/vnd.oasis.opendocument.presentation',
|
|
72
|
-
'odg': 'application/vnd.oasis.opendocument.graphics',
|
|
73
|
-
# Fonts
|
|
74
|
-
'otf': 'font/otf',
|
|
75
|
-
'ttf': 'font/ttf',
|
|
76
|
-
'woff': 'font/woff',
|
|
77
|
-
'woff2': 'font/woff2',
|
|
78
|
-
# 3D model
|
|
79
|
-
'gltf': 'model/gltf+json',
|
|
80
|
-
'glb': 'model/gltf-binary',
|
|
81
|
-
'stl': 'model/stl',
|
|
82
|
-
'obj': 'model/obj', # not officially registered; widely used
|
|
83
|
-
# Scripts / misc
|
|
84
|
-
'sh': 'application/x-sh',
|
|
85
|
-
'php': 'application/x-httpd-php', # Usually not used at runtime for real responses
|
|
86
|
-
'exe': 'application/x-msdownload',
|
|
87
|
-
# Misc
|
|
88
|
-
'apk': 'application/vnd.android.package-archive',
|
|
89
|
-
'deb': 'application/x-debian-package',
|
|
90
|
-
'rpm': 'application/x-rpm',
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
def get_content_type(filename_or_extension: str | Path, treat_as_binary: bool = True) -> str:
|
|
95
|
-
"""
|
|
96
|
-
Given a filename (or just an extension), return the most specific,
|
|
97
|
-
commonly accepted MIME type based on extension.
|
|
98
|
-
|
|
99
|
-
Falls back to 'application/octet-stream' if not found.
|
|
100
|
-
|
|
101
|
-
Example:
|
|
102
|
-
>>> get_content_type("picture.jpg")
|
|
103
|
-
'image/jpeg'
|
|
104
|
-
>>> get_content_type(".webp")
|
|
105
|
-
'image/webp'
|
|
106
|
-
>>> get_content_type("script.js")
|
|
107
|
-
'application/javascript'
|
|
108
|
-
>>> get_content_type("unknown.xyz")
|
|
109
|
-
'application/octet-stream'
|
|
110
|
-
>>> get_content_type("unknown.xyz", treat_as_binary=False)
|
|
111
|
-
'application/octet-stream'
|
|
112
|
-
"""
|
|
113
|
-
|
|
114
|
-
if filename_or_extension is None:
|
|
115
|
-
raise Exception('filename cannot be None.')
|
|
116
|
-
|
|
117
|
-
if isinstance(filename_or_extension, Path):
|
|
118
|
-
filename_or_extension = filename_or_extension.suffix
|
|
119
|
-
|
|
120
|
-
if '.' not in filename_or_extension:
|
|
121
|
-
filename_or_extension = f'.{filename_or_extension}'
|
|
122
|
-
|
|
123
|
-
# Split by dot, take the last part as extension
|
|
124
|
-
# e.g., "archive.tar.gz" => "gz"
|
|
125
|
-
# Also handle cases like ".webp" => "webp"
|
|
126
|
-
dot_parts = filename_or_extension.lower().split('.')
|
|
127
|
-
ext = dot_parts[-1] if len(dot_parts) > 1 else ''
|
|
128
|
-
|
|
129
|
-
if treat_as_binary:
|
|
130
|
-
return EXTENSION_TO_CONTENT_TYPE.get(ext, 'application/octet-stream')
|
|
131
|
-
|
|
132
|
-
return EXTENSION_TO_CONTENT_TYPE.get(ext, 'text/plain')
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
webp: str = get_content_type('.webp')
|
|
136
|
-
png: str = get_content_type('.png')
|
|
137
|
-
jpg: str = get_content_type('.jpg')
|
|
138
|
-
mp3: str = get_content_type('.mp3')
|
|
139
|
-
json: str = get_content_type('.json')
|
|
140
|
-
pdf: str = get_content_type('.pdf')
|
|
141
|
-
zip: str = get_content_type('.zip') # noqa == it's fine to overwrite zip() in this module only.
|
|
142
|
-
xml: str = get_content_type('.xml')
|
|
143
|
-
csv: str = get_content_type('.csv')
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def cli():
|
|
147
|
-
"""
|
|
148
|
-
A simple CLI to look up the MIME type for a given filename or extension.
|
|
149
|
-
Usage example:
|
|
150
|
-
contenttypes my_file.jpg
|
|
151
|
-
"""
|
|
152
|
-
if len(sys.argv) < 2:
|
|
153
|
-
print('Usage: contenttypes [FILENAME_OR_EXTENSION]\nExample: contenttypes .jpg')
|
|
154
|
-
sys.exit(1)
|
|
155
|
-
|
|
156
|
-
filename = sys.argv[1]
|
|
157
|
-
mime_type = get_content_type(filename)
|
|
158
|
-
print(mime_type)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|