refresh() did folder scan, magic-byte sniff, and per-file image reads directly
on the event loop. Offload via asyncio.to_thread so the loop stays responsive
during a large sync; behavior (validation, size cap, stem-collision and
missing-dir raises) is unchanged.
Also documents discord.MissingApplicationID in refresh()'s Raises contract -
it is a ClientException, not an HTTPException, so it was previously uncaught
by the existing except clauses and unlisted in the docstring.
Signed-off-by: disqualifier <dev@disqualifier.me>
refresh() previously treated a missing assets/emojis folder (wrong cwd,
missing WorkingDirectory=/WORKDIR) as an empty one, silently deleting
every application emoji on the app every restart with no signal and no
way back (recreated emojis get new IDs). _scan_folder now raises
DPYAppEmojisError naming the absent path instead; a present-but-empty
folder still mirrors as before.
Two files sharing a name stem across extensions (check.png + check.gif)
used to silently collapse to one synced emoji via last-write-wins,
breaking the documented delete+re-add replace workflow with no error.
_scan_folder now raises DPYAppEmojisError naming both colliding files.
A valid extension with unrecognized magic bytes (truncated download,
mismatched format) made discord.py raise an anonymous
ValueError('Unsupported image type given') from create_application_emoji,
which the lib's (Forbidden, HTTPException) catch didn't cover, leaving
no way to tell which file in a large folder was broken. _scan_folder now
pre-flights the same magic-byte check discord.py itself uses and raises
ValueError naming the offending file before any create is attempted.
Also collapses the redundant Forbidden member in the create/delete except
clauses (Forbidden already subclasses HTTPException); log-then-raise
behavior is unchanged.
Bump 0.1.0 -> 0.1.1.
Signed-off-by: disqualifier <dev@disqualifier.me>