feat: allow text upload (#3738)

This commit is contained in:
Vlad Stan
2026-02-25 07:53:42 +01:00
committed by dni ⚡
parent 67bb86c1ce
commit af8f3382c1
7 changed files with 41 additions and 19 deletions
+26 -12
View File
@@ -3,6 +3,7 @@ import io
from uuid import uuid4 from uuid import uuid4
from fastapi import UploadFile from fastapi import UploadFile
from loguru import logger
from PIL import Image from PIL import Image
from lnbits.core.crud.assets import create_asset, get_user_assets_count from lnbits.core.crud.assets import create_asset, get_user_assets_count
@@ -29,17 +30,7 @@ async def create_user_asset(user_id: str, file: UploadFile, is_public: bool) ->
f"File limit of {settings.lnbits_max_asset_size_mb}MB exceeded." f"File limit of {settings.lnbits_max_asset_size_mb}MB exceeded."
) )
image = Image.open(io.BytesIO(contents)) thumb_buffer = thumbnail_from_bytes(contents)
thumbnail_width = min(256, settings.lnbits_asset_thumbnail_width)
thumbnail_height = min(256, settings.lnbits_asset_thumbnail_height)
image.thumbnail((thumbnail_width, thumbnail_height))
# Save thumbnail to an in-memory buffer
thumb_buffer = io.BytesIO()
thumbnail_format = settings.lnbits_asset_thumbnail_format or "PNG"
image.save(thumb_buffer, format=thumbnail_format)
thumb_buffer.seek(0)
asset = Asset( asset = Asset(
id=uuid4().hex, id=uuid4().hex,
@@ -48,9 +39,32 @@ async def create_user_asset(user_id: str, file: UploadFile, is_public: bool) ->
is_public=is_public, is_public=is_public,
name=file.filename or "unnamed", name=file.filename or "unnamed",
size_bytes=len(contents), size_bytes=len(contents),
thumbnail_base64=base64.b64encode(thumb_buffer.getvalue()).decode("utf-8"), thumbnail_base64=(
base64.b64encode(thumb_buffer.getvalue()).decode("utf-8")
if thumb_buffer
else None
),
data=contents, data=contents,
) )
await create_asset(asset) await create_asset(asset)
return asset return asset
def thumbnail_from_bytes(contents: bytes) -> io.BytesIO | None:
try:
image = Image.open(io.BytesIO(contents))
thumbnail_width = min(256, settings.lnbits_asset_thumbnail_width)
thumbnail_height = min(256, settings.lnbits_asset_thumbnail_height)
image.thumbnail((thumbnail_width, thumbnail_height))
# Save thumbnail to an in-memory buffer
thumb_buffer = io.BytesIO()
thumbnail_format = settings.lnbits_asset_thumbnail_format or "PNG"
image.save(thumb_buffer, format=thumbnail_format)
thumb_buffer.seek(0)
return thumb_buffer
except Exception as exc:
logger.warning(f"Failed to create thumbnail: {exc}")
return None
+4 -4
View File
@@ -57,11 +57,11 @@ async def api_get_asset(
@asset_router.get( @asset_router.get(
"/{asset_id}/binary", "/{asset_id}/data",
name="Get user asset binary", name="Get user asset data",
summary="Get user asset binary data by ID", summary="Get user asset data data by ID",
) )
async def api_get_asset_binary( async def api_get_asset_data(
asset_id: str, asset_id: str,
user_id: str | None = Depends(optional_user_id), user_id: str | None = Depends(optional_user_id),
) -> Response: ) -> Response:
+4
View File
@@ -306,6 +306,10 @@ class AssetSettings(LNbitsSettings):
"heic", "heic",
"heif", "heif",
"heics", "heics",
"text/plain",
"text/json" "text/xml",
"application/json",
"application/pdf",
] ]
) )
lnbits_asset_thumbnail_width: int = Field(default=128, ge=0) lnbits_asset_thumbnail_width: int = Field(default=128, ge=0)
File diff suppressed because one or more lines are too long
@@ -16,6 +16,7 @@ window.app.component('lnbits-admin-assets-config', {
this.newAllowedAssetMimeType this.newAllowedAssetMimeType
) )
this.newAllowedAssetMimeType = '' this.newAllowedAssetMimeType = ''
this.formData.touch = null
} }
}, },
removeAllowedAssetMimeType(type) { removeAllowedAssetMimeType(type) {
@@ -23,18 +24,21 @@ window.app.component('lnbits-admin-assets-config', {
if (index !== -1) { if (index !== -1) {
this.formData.lnbits_assets_allowed_mime_types.splice(index, 1) this.formData.lnbits_assets_allowed_mime_types.splice(index, 1)
} }
this.formData.touch = null
}, },
addNewNoLimitUser() { addNewNoLimitUser() {
if (this.newNoLimitUser) { if (this.newNoLimitUser) {
this.removeNoLimitUser(this.newNoLimitUser) this.removeNoLimitUser(this.newNoLimitUser)
this.formData.lnbits_assets_no_limit_users.push(this.newNoLimitUser) this.formData.lnbits_assets_no_limit_users.push(this.newNoLimitUser)
this.newNoLimitUser = '' this.newNoLimitUser = ''
this.formData.touch = null
} }
}, },
removeNoLimitUser(user) { removeNoLimitUser(user) {
if (user) { if (user) {
this.formData.lnbits_assets_no_limit_users = this.formData.lnbits_assets_no_limit_users =
this.formData.lnbits_assets_no_limit_users.filter(u => u !== user) this.formData.lnbits_assets_no_limit_users.filter(u => u !== user)
this.formData.touch = null
} }
} }
} }
+1 -1
View File
@@ -609,7 +609,7 @@ window.PageAccount = {
} }
}, },
copyAssetLinkToClipboard(asset) { copyAssetLinkToClipboard(asset) {
const assetUrl = `${window.location.origin}/api/v1/assets/${asset.id}/binary` const assetUrl = `${window.location.origin}/api/v1/assets/${asset.id}/data`
this.utils.copyText(assetUrl) this.utils.copyText(assetUrl)
}, },
addUserLabel() { addUserLabel() {
+1 -1
View File
@@ -941,7 +941,7 @@
v-if="props.row.thumbnail_base64" v-if="props.row.thumbnail_base64"
target="_blank" target="_blank"
style="color: inherit" style="color: inherit"
:href="`/api/v1/assets/${props.row.id}/binary`" :href="`/api/v1/assets/${props.row.id}/data`"
> >
<q-img <q-img
:src=" :src="