Skip to content

Commit ee63f00

Browse files
committed
✨ database: generate filename if name is None
1 parent a94897f commit ee63f00

File tree

5 files changed

+223
-34
lines changed

5 files changed

+223
-34
lines changed

nonebot_plugin_all4one/database/__init__.py

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111
from nonebot_plugin_localstore import get_plugin_data_dir
1212
from nonebot.adapters.onebot.v12.exception import DatabaseError
1313

14+
from .fleep import get as get_file_info
15+
1416

1517
def get_sha256(data: bytes) -> str:
1618
return sha256(data).hexdigest()
@@ -63,7 +65,7 @@ async def get_file(file_id: str, src: Optional[str] = None) -> File:
6365

6466

6567
async def upload_file(
66-
name: str,
68+
name: Optional[str] = None,
6769
src: Optional[str] = None,
6870
src_id: Optional[str] = None,
6971
url: Optional[str] = None,
@@ -106,17 +108,22 @@ async def upload_file(
106108
async with AsyncClient() as client:
107109
response = await client.get(url, headers=headers)
108110
data = response.content
109-
if data:
110-
# 如果是 JSON 格式,bytes 编码为 base64
111-
# https://12.onebot.dev/connect/data-protocol/basic-types/#_5
112-
if isinstance(data, str):
113-
data = b64decode(data)
114-
sha256 = get_sha256(data)
115-
path = str(FILE_PATH / sha256)
116-
async with await open_file(path, "wb") as f:
117-
await f.write(data)
111+
if not data:
112+
# FIXME: 还没决定放什么异常
113+
raise
114+
# 如果是 JSON 格式,bytes 编码为 base64
115+
# https://12.onebot.dev/connect/data-protocol/basic-types/#_5
116+
if isinstance(data, str):
117+
data = b64decode(data)
118+
119+
sha256 = get_sha256(data)
120+
extensions = get_file_info(data[:128]).extensions
121+
filename = f"{sha256}.{extensions[0] if extensions else ''}"
122+
path = str(FILE_PATH / filename)
123+
async with await open_file(path, "wb") as f:
124+
await f.write(data)
118125
file = File(
119-
name=name,
126+
name=name or filename,
120127
src=src,
121128
src_id=src_id,
122129
url=url,
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
[
2+
{"type": "raster-image", "extension": "bmp", "mime": "image/bmp", "offset": 0, "signature": ["42 4D"]},
3+
{"type": "raster-image", "extension": "gif", "mime": "image/gif", "offset": 0, "signature": ["47 49 46 38"]},
4+
{"type": "raster-image", "extension": "jpg", "mime": "image/jpeg", "offset": 0, "signature": ["FF D8 FF"]},
5+
{"type": "raster-image", "extension": "jp2", "mime": "image/jp2", "offset": 0, "signature": ["00 00 00 0C 6A 50 20 20"]},
6+
{"type": "raster-image", "extension": "png", "mime": "image/png", "offset": 0, "signature": ["89 50 4E 47 0D 0A 1A 0A"]},
7+
{"type": "raster-image", "extension": "webp", "mime": "image/webp", "offset": 8, "signature": ["57 45 42 50"]},
8+
{"type": "raster-image", "extension": "ico", "mime": "image/x-icon", "offset": 0, "signature": ["00 00 01 00"]},
9+
{"type": "raster-image", "extension": "psd", "mime": "image/vnd.adobe.photoshop", "offset": 0, "signature": ["38 42 50 53"]},
10+
{"type": "raster-image", "extension": "tiff", "mime": "image/tiff", "offset": 0, "signature": ["49 20 49", "49 49 2A 00", "4D 4D 00 2A", "4D 4D 00 2B"]},
11+
{"type": "raw-image", "extension": "raw", "mime": "application/octet-stream", "offset": 0, "signature": ["49 49 55 00"]},
12+
{"type": "raw-image", "extension": "arw", "mime": "application/octet-stream", "offset": 0, "signature": ["49 49 2A 00"]},
13+
{"type": "raw-image", "extension": "x3f", "mime": "application/octet-stream", "offset": 0, "signature": ["46 4F 56 62"]},
14+
{"type": "raw-image", "extension": "srw", "mime": "application/octet-stream", "offset": 0, "signature": ["4D 4D 00 2A"]},
15+
{"type": "raw-image", "extension": "pef", "mime": "application/octet-stream", "offset": 0, "signature": ["4D 4D 00 2A"]},
16+
{"type": "raw-image", "extension": "rw2", "mime": "application/octet-stream", "offset": 0, "signature": ["49 49 55 00"]},
17+
{"type": "raw-image", "extension": "nef", "mime": "application/octet-stream", "offset": 0, "signature": ["4D 4D 00 2A"]},
18+
{"type": "raw-image", "extension": "nrw", "mime": "application/octet-stream", "offset": 0, "signature": ["49 49 2A 00"]},
19+
{"type": "raw-image", "extension": "raf", "mime": "application/octet-stream", "offset": 0, "signature": ["46 55 4A 49"]},
20+
{"type": "raw-image", "extension": "erf", "mime": "application/octet-stream", "offset": 0, "signature": ["4D 4D 00 2A"]},
21+
{"type": "raw-image", "extension": "crw", "mime": "application/octet-stream", "offset": 0, "signature": ["49 49 1A 00"]},
22+
{"type": "raw-image", "extension": "cr2", "mime": "application/octet-stream", "offset": 0, "signature": ["49 49 2A 00"]},
23+
{"type": "raw-image", "extension": "orf", "mime": "application/octet-stream", "offset": 0, "signature": ["49 49 52 4F", "49 49 52 53"]},
24+
{"type": "raw-image", "extension": "dng", "mime": "application/octet-stream", "offset": 0, "signature": ["4D 4D 00 2A", "49 49 2A 00"]},
25+
{"type": "vector-image", "extension": "ai", "mime": "application/postscript", "offset": 0, "signature": ["25 50 44 46"]},
26+
{"type": "vector-image", "extension": "eps", "mime": "application/postscript", "offset": 0, "signature": ["C5 D0 D3 C6", "25 21 50 53 2D 41 64 6F"]},
27+
{"type": "3d-image", "extension": "obj", "mime": "text/plain", "offset": 2, "signature": ["4D 61 78 32 4F 62 6A", "42 6C 65 6E 64 65 72"]},
28+
{"type": "3d-image", "extension": "mtl", "mime": "text/plain", "offset": 2, "signature": ["4D 61 78 32 4D 74 6C", "42 6C 65 6E 64 65 72 20 4D 54 4C 20 46 69 6C 65"]},
29+
{"type": "3d-image", "extension": "xsi", "mime": "text/plain", "offset": 0, "signature": ["78 73 69"]},
30+
{"type": "3d-image", "extension": "ply", "mime": "text/plain", "offset": 50, "signature": ["70 6C 79"]},
31+
{"type": "3d-image", "extension": "ma", "mime": "text/plain", "offset": 2, "signature": ["4D 61 79 61"]},
32+
{"type": "3d-image", "extension": "wrl", "mime": "text/plain", "offset": 1, "signature": ["56 52 4D 4C"]},
33+
{"type": "3d-image", "extension": "x3d", "mime": "application/xml", "offset": 50, "signature": ["58 33 44"]},
34+
{"type": "3d-image", "extension": "fbx", "mime": "application/octet-stream", "offset": 2, "signature": ["46 42 58"]},
35+
{"type": "3d-image", "extension": "ms3d", "mime": "application/octet-stream", "offset": 0, "signature": ["4D 53 33 44"]},
36+
{"type": "3d-image", "extension": "c4d", "mime": "application/octet-stream", "offset": 0, "signature": ["58 43 34 44 43 34 44 36"]},
37+
{"type": "audio", "extension": "aiff", "mime": "audio/aiff", "offset": 0, "signature": ["46 4F 52 4D 00"]},
38+
{"type": "audio", "extension": "aac", "mime": "audio/aac", "offset": 0, "signature": ["FF F1", "FF F9"]},
39+
{"type": "audio", "extension": "midi", "mime": "audio/midi", "offset": 0, "signature": ["4D 54 68 64"]},
40+
{"type": "audio", "extension": "mp3", "mime": "audio/mpeg", "offset": 0, "signature": ["49 44 33", "FF FB"]},
41+
{"type": "audio", "extension": "m4a", "mime": "audio/mp4", "offset": 4, "signature": ["66 74 79 70 4D 34 41 20"]},
42+
{"type": "audio", "extension": "oga", "mime": "audio/ogg", "offset": 0, "signature": ["4F 67 67 53 00 02 00 00"]},
43+
{"type": "audio", "extension": "wav", "mime": "audio/wav", "offset": 0, "signature": ["52 49 46 46"]},
44+
{"type": "audio", "extension": "wma", "mime": "audio/x-ms-wma", "offset": 0, "signature": ["30 26 B2 75 8E 66 CF 11"]},
45+
{"type": "audio", "extension": "flac", "mime": "audio/flac", "offset": 0, "signature": ["66 4C 61 43 00 00 00 22"]},
46+
{"type": "audio", "extension": "mka", "mime": "audio/x-matroska", "offset": 31, "signature": ["6D 61 74 72 6F 73 6B 61"]},
47+
{"type": "audio", "extension": "au", "mime": "audio/basic", "offset": 0, "signature": ["2E 73 6E 64"]},
48+
{"type": "audio", "extension": "ra", "mime": "application/octet-stream", "offset": 0, "signature": ["2E 52 4D 46"]},
49+
{"type": "audio", "extension": "amr", "mime": "application/octet-stream", "offset": 0, "signature": ["23 21 41 4D"]},
50+
{"type": "audio", "extension": "ac3", "mime": "application/octet-stream", "offset": 0, "signature": ["0B 77"]},
51+
{"type": "audio", "extension": "voc", "mime": "application/octet-stream", "offset": 0, "signature": ["43 72 65 61 74 69 76 65"]},
52+
{"type": "video", "extension": "3g2", "mime": "video/3gpp2", "offset": 4, "signature": ["66 74 79 70 33 67 70"]},
53+
{"type": "video", "extension": "3gp", "mime": "video/3gpp", "offset": 4, "signature": ["66 74 79 70 33 67 70"]},
54+
{"type": "video", "extension": "avi", "mime": "video/avi", "offset": 8, "signature": ["41 56 49 20 4C 49 53 54"]},
55+
{"type": "video", "extension": "flv", "mime": "video/x-flv", "offset": 0, "signature": ["46 4C 56"]},
56+
{"type": "video", "extension": "mxf", "mime": "application/mxf", "offset": 0, "signature": ["06 0E 2B 34"]},
57+
{"type": "video", "extension": "m4v", "mime": "video/mp4", "offset": 4, "signature": ["66 74 79 70 4D 34 56 20", "66 74 79 70 6D 70 34 32"]},
58+
{"type": "video", "extension": "mkv", "mime": "video/x-matroska", "offset": 31, "signature": ["6D 61 74 72 6F 73 6B 61"]},
59+
{"type": "video", "extension": "mov", "mime": "video/quicktime", "offset": 4, "signature": ["66 74 79 70 71 74 20 20", "6D 6F 6F 76", "66 72 65 65", "6D 64 61 74", "77 69 64 65", "70 6E 6F 74", "73 6B 69 70"]},
60+
{"type": "video", "extension": "mp4", "mime": "video/mp4", "offset": 4, "signature": ["66 74 79 70 4D 53 4E 56", "66 74 79 70 69 73 6F 6D"]},
61+
{"type": "video", "extension": "swf", "mime": "application/vnd.adobe.flash-movie", "offset": 0, "signature": ["43 57 53", "46 57 53"]},
62+
{"type": "video", "extension": "mpg", "mime": "video/mpeg", "offset": 0, "signature": ["00 00 01 BA"]},
63+
{"type": "video", "extension": "vob", "mime": "video/dvd", "offset": 0, "signature": ["00 00 01 BA"]},
64+
{"type": "video", "extension": "wmv", "mime": "video/x-ms-wmv", "offset": 0, "signature": ["30 26 B2 75 8E 66 CF 11"]},
65+
{"type": "video", "extension": "asf", "mime": "video/x-ms-asf", "offset": 0, "signature": ["30 26 B2 75 8E 66 CF 11"]},
66+
{"type": "video", "extension": "ogv", "mime": "video/ogg", "offset": 0, "signature": ["4F 67 67 53 00 02 00 00"]},
67+
{"type": "video", "extension": "webm", "mime": "video/webm", "offset": 0, "signature": ["1A 45 DF A3"]},
68+
{"type": "document", "extension": "odt", "mime": "application/vnd.oasis.opendocument.text", "offset": 73, "signature": ["74 65 78 74"]},
69+
{"type": "document", "extension": "odp", "mime": "application/vnd.oasis.opendocument.presentation", "offset": 73, "signature": ["70 72 65 73 65 6E 74 61 74 69 6F 6E"]},
70+
{"type": "document", "extension": "ods", "mime": "application/vnd.oasis.opendocument.spreadsheet", "offset": 73, "signature": ["73 70 72 65 61 64 73 68 65 65 74"]},
71+
{"type": "document", "extension": "doc", "mime": "application/vnd.ms-excel", "offset": 0, "signature": ["D0 CF 11 E0 A1 B1 1A E1", "50 4B 03 04 14 00 06 00"]},
72+
{"type": "document", "extension": "pps", "mime": "application/vnd.ms-powerpoint", "offset": 0, "signature": ["D0 CF 11 E0 A1 B1 1A E1", "50 4B 03 04 14 00 06 00"]},
73+
{"type": "document", "extension": "ppt", "mime": "application/vnd.ms-powerpoint", "offset": 0, "signature": ["D0 CF 11 E0 A1 B1 1A E1", "50 4B 03 04 14 00 06 00"]},
74+
{"type": "document", "extension": "xls", "mime": "application/vnd.ms-excel", "offset": 0, "signature": ["D0 CF 11 E0 A1 B1 1A E1", "50 4B 03 04 14 00 06 00"]},
75+
{"type": "document", "extension": "docx", "mime": "application/vnd.openxmlformats-officedocument.wordprocessingml.document", "offset": 0, "signature": ["D0 CF 11 E0 A1 B1 1A E1", "50 4B 03 04 14 00 06 00"]},
76+
{"type": "document", "extension": "pptx", "mime": "application/vnd.openxmlformats-officedocument.presentationml.presentation", "offset": 0, "signature": ["D0 CF 11 E0 A1 B1 1A E1", "50 4B 03 04 14 00 06 00"]},
77+
{"type": "document", "extension": "xlsx", "mime": "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "offset": 0, "signature": ["D0 CF 11 E0 A1 B1 1A E1", "50 4B 03 04 14 00 06 00"]},
78+
{"type": "document", "extension": "pages", "mime": "application/zip", "offset": 0, "signature": ["50 4B 03 04"]},
79+
{"type": "document", "extension": "key", "mime": "application/zip", "offset": 0, "signature": ["50 4B 03 04"]},
80+
{"type": "document", "extension": "numbers", "mime": "application/zip", "offset": 0, "signature": ["50 4B 03 04"]},
81+
{"type": "document", "extension": "pdf", "mime": "application/pdf", "offset": 0, "signature": ["25 50 44 46"]},
82+
{"type": "document", "extension": "rtf", "mime": "application/rtf", "offset": 0, "signature": ["7B 5C 72 74 66 31"]},
83+
{"type": "document", "extension": "epub", "mime": "application/epub+zip", "offset": 0, "signature": ["50 4B 03 04"]},
84+
{"type": "document", "extension": "xml", "mime": "application/xml", "offset": 2, "signature": ["78 6D 6C"]},
85+
{"type": "archive", "extension": "7z", "mime": "application/x-7z-compressed", "offset": 0, "signature": ["37 7A BC AF 27 1C"]},
86+
{"type": "archive", "extension": "rar", "mime": "application/vnd.rar", "offset": 0, "signature": ["52 61 72 21 1A 07 00", "52 61 72 21 1A 07 01 00"]},
87+
{"type": "archive", "extension": "tar.z", "mime": "application/x-compress", "offset": 0, "signature": ["1F 9D", "1F A0"]},
88+
{"type": "archive", "extension": "gz", "mime": "application/gzip", "offset": 0, "signature": ["1F 8B 08"]},
89+
{"type": "archive", "extension": "zip", "mime": "application/zip", "offset": 0, "signature": ["50 4B 03 04", "50 4B 05 06", "50 4B 07 08"]},
90+
{"type": "archive", "extension": "dmg", "mime": "application/x-apple-diskimage", "offset": 0, "signature": ["78 01 73 0D 62 62 60"]},
91+
{"type": "archive", "extension": "iso", "mime": "application/octet-stream", "offset": 0, "signature": ["43 49 53 4F", "43 44 30 30 31"]},
92+
{"type": "executable", "extension": "com", "mime": "application/x-msdownload", "offset": 0, "signature": ["4D 5A"]},
93+
{"type": "executable", "extension": "exe", "mime": "application/vnd.microsoft.portable-executable", "offset": 0, "signature": ["4D 5A 90 00"]},
94+
{"type": "executable", "extension": "jar", "mime": "application/java-archive", "offset": 0, "signature": ["50 4B 03 04"]},
95+
{"type": "font", "extension": "ttf", "mime": "font/ttf", "offset": 0, "signature": ["00 01 00 00"]},
96+
{"type": "font", "extension": "otf", "mime": "font/otf", "offset": 0, "signature": ["4F 54 54 4F"]},
97+
{"type": "font", "extension": "woff", "mime": "font/woff", "offset": 0, "signature": ["77 4F 46 46"]},
98+
{"type": "font", "extension": "woff2", "mime": "font/woff2", "offset": 0, "signature": ["77 4F 46 32"]},
99+
{"type": "system", "extension": "cab", "mime": "application/vnd.ms-cab-compressed", "offset": 0, "signature": ["4D 53 43 46"]},
100+
{"type": "system", "extension": "cat", "mime": "application/vnd.microsoft.portable-executable", "offset": 0, "signature": ["30 82"]},
101+
{"type": "system", "extension": "dll", "mime": "application/vnd.microsoft.portable-executable", "offset": 0, "signature": ["4D 5A 90 00"]},
102+
{"type": "system", "extension": "drv", "mime": "application/vnd.microsoft.portable-executable", "offset": 0, "signature": ["4D 5A 90 00"]},
103+
{"type": "system", "extension": "sdb", "mime": "application/vnd.microsoft.portable-executable", "offset": 8, "signature": ["73 64 62 66"]},
104+
{"type": "system", "extension": "sys", "mime": "application/vnd.microsoft.portable-executable", "offset": 0, "signature": ["4D 5A 80 00", "4D 5A 90 00"]},
105+
{"type": "system", "extension": "reg", "mime": "application/vnd.microsoft.portable-executable", "offset": 0, "signature": ["52 45 47 45 44 49 54", "57 69 6E 64 6F 77 73 20 52 65 67 69 73 74 72 79"]},
106+
{"type": "database", "extension": "sqlite", "mime": "application/x-sqlite3", "offset": 0, "signature": ["53 51 4C 69 74 65 20 66 6F 72 6D 61 74 20 33 00"]}
107+
]
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""
2+
Name: fleep.py
3+
Description: File format determination library
4+
Author: Mykyta Paliienko
5+
License: MIT
6+
"""
7+
8+
import json
9+
from pathlib import Path
10+
11+
with (Path(__file__).parent / "fleep.json").open(encoding="utf-8") as data_file:
12+
data = json.load(data_file)
13+
14+
15+
class Info:
16+
"""
17+
Generates object with given arguments
18+
19+
Args:
20+
types (list) -> list of file types
21+
extensions (list) -> list of file extensions
22+
mimes (list) -> list of file MIME types
23+
24+
Returns:
25+
(<class 'fleep.Info'>) -> Class instance
26+
"""
27+
28+
def __init__(self, types: list, extensions: list, mimes: list):
29+
self.types = types
30+
self.extensions = extensions
31+
self.mimes = mimes
32+
33+
def type_matches(self, type_: str):
34+
"""Checks if file type matches with given type"""
35+
return type_ in self.types
36+
37+
def extension_matches(self, extension: str):
38+
"""Checks if file extension matches with given extension"""
39+
return extension in self.extensions
40+
41+
def mime_matches(self, mime: str):
42+
"""Checks if file MIME type matches with given MIME type"""
43+
return mime in self.mimes
44+
45+
46+
def get(obj: bytes):
47+
"""
48+
Determines file format and picks suitable file types, extensions and MIME types
49+
50+
Args:
51+
obj (bytes) -> byte sequence (128 bytes are enough)
52+
53+
Returns:
54+
(<class 'fleep.Info'>) -> Class instance
55+
"""
56+
57+
if not isinstance(obj, bytes):
58+
raise TypeError("object type must be bytes")
59+
60+
stream = " ".join([f"{byte:02X}" for byte in obj])
61+
62+
types = {}
63+
extensions = {}
64+
mimes = {}
65+
for element in data:
66+
for signature in element["signature"]:
67+
offset = element["offset"] * 2 + element["offset"]
68+
if signature == stream[offset : len(signature) + offset]:
69+
types[element["type"]] = len(signature)
70+
extensions[element["extension"]] = len(signature)
71+
mimes[element["mime"]] = len(signature)
72+
return Info(
73+
sorted(types, key=lambda x: types.get(x, False), reverse=True),
74+
sorted(extensions.keys(), key=lambda x: extensions.get(x, False), reverse=True),
75+
sorted(mimes.keys(), key=lambda x: mimes.get(x, False), reverse=True),
76+
)
77+
78+
79+
def supported_types():
80+
"""Returns a list of supported file types"""
81+
return sorted({x["type"] for x in data})
82+
83+
84+
def supported_extensions():
85+
"""Returns a list of supported file extensions"""
86+
return sorted({x["extension"] for x in data})
87+
88+
89+
def supported_mimes():
90+
"""Returns a list of supported file MIME types"""
91+
return sorted({x["mime"] for x in data})

0 commit comments

Comments
 (0)