fix(storage): migrate fileStorage handlers and seeder from local disk/Seafile to MinIO

Root cause: images not showing because:
1. seed_assets.ts was listing from Seafile (unreliable, 502 errors)
2. fileStorage create/findUniq/del handlers used local disk (not available in containers)
3. link format in file-storage.json had inconsistent path prefix

Changes:
- seed_assets.ts: list objects from MinIO bucket instead of Seafile API; seed
  link as /api/img/{name}, path as "image" (matches MinIO prefix)
- fileStorage/create.ts: upload image/audio/document to MinIO via putObject;
  remove WIBU_UPLOAD_DIR dependency and all fs.writeFile calls
- fileStorage/findUniq.ts: stream file from MinIO via getObject; remove
  WIBU_UPLOAD_DIR and fs.readFile
- fileStorage/del.ts: delete from MinIO via removeObject; remove fs.unlink
- file-storage.json: fix path field to "image" (was full path); all 80 entries
  already have correct link=/api/img/{name} format

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-23 14:28:08 +08:00
parent d145611221
commit 2958950585
5 changed files with 433 additions and 299 deletions

View File

@@ -1,406 +1,563 @@
[
{
"name": "42RCCpBZla4ZWxXcwx7kG-desktop.webp",
"path": "image/42RCCpBZla4ZWxXcwx7kG-desktop.webp",
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d05a9e22-feac-4955-b1a2-75faad37f0ac/42RCCpBZla4ZWxXcwx7kG-desktop.webp",
"mimeType": "image/webp",
"link": "/api/fileStorage/findUnique/Gc79mlIlGuoRQuTqskFj--desktop.webp",
"link": "/api/img/42RCCpBZla4ZWxXcwx7kG-desktop.webp",
"category": "image"
},
{
"name": "42RCCpBZla4ZWxXcwx7kG-mobile.webp",
"path": "image/42RCCpBZla4ZWxXcwx7kG-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c91212b5-7408-4ec9-b7c0-6c0fde2a9fc5/42RCCpBZla4ZWxXcwx7kG-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c91212b5-7408-4ec9-b7c0-6c0fde2a9fc5/42RCCpBZla4ZWxXcwx7kG-mobile.webp",
"link": "/api/img/42RCCpBZla4ZWxXcwx7kG-mobile.webp",
"category": "image"
},
{
"name": "6DQbAvn0St-xHdPGW3vpY-desktop.webp",
"path": "image/6DQbAvn0St-xHdPGW3vpY-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/68cc521e-05e5-4258-af8d-c87fb76c927e/6DQbAvn0St-xHdPGW3vpY-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/68cc521e-05e5-4258-af8d-c87fb76c927e/6DQbAvn0St-xHdPGW3vpY-desktop.webp",
"link": "/api/img/6DQbAvn0St-xHdPGW3vpY-desktop.webp",
"category": "image"
},
{
"name": "6DQbAvn0St-xHdPGW3vpY-mobile.webp",
"path": "image/6DQbAvn0St-xHdPGW3vpY-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/15f7ddd6-448c-4e4a-9b24-0bdc4bce5ce1/6DQbAvn0St-xHdPGW3vpY-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/15f7ddd6-448c-4e4a-9b24-0bdc4bce5ce1/6DQbAvn0St-xHdPGW3vpY-mobile.webp",
"link": "/api/img/6DQbAvn0St-xHdPGW3vpY-mobile.webp",
"category": "image"
},
{
"name": "buku1 (1).jpeg",
"path": "image/buku1 (1).jpeg",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d72b02a6-91f5-4d64-9729-521b306328d3/buku1%20%281%29.jpeg"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d72b02a6-91f5-4d64-9729-521b306328d3/buku1%20%281%29.jpeg",
"link": "/api/img/buku1 (1).jpeg",
"category": "image"
},
{
"name": "buku1.jpeg",
"path": "image/buku1.jpeg",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/912bd7e5-be8a-4c19-8ab8-df6114a38864/buku1.jpeg"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/912bd7e5-be8a-4c19-8ab8-df6114a38864/buku1.jpeg",
"link": "/api/img/buku1.jpeg",
"category": "image"
},
{
"name": "buku6.jpg",
"path": "image/buku6.jpg",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ea56bc7c-094b-464e-859a-6c65bf65361d/buku6.jpg"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ea56bc7c-094b-464e-859a-6c65bf65361d/buku6.jpg",
"link": "/api/img/buku6.jpg",
"category": "image"
},
{
"name": "c7xWNyoYp8Cak28NG5NoG-desktop.webp",
"path": "image/c7xWNyoYp8Cak28NG5NoG-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d84fb066-4352-44f0-b7bc-5d8c5b8ffb61/c7xWNyoYp8Cak28NG5NoG-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d84fb066-4352-44f0-b7bc-5d8c5b8ffb61/c7xWNyoYp8Cak28NG5NoG-desktop.webp",
"link": "/api/img/c7xWNyoYp8Cak28NG5NoG-desktop.webp",
"category": "image"
},
{
"name": "c7xWNyoYp8Cak28NG5NoG-mobile.webp",
"path": "image/c7xWNyoYp8Cak28NG5NoG-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/9fb1c742-9a80-4788-9c73-9d06108e0051/c7xWNyoYp8Cak28NG5NoG-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/9fb1c742-9a80-4788-9c73-9d06108e0051/c7xWNyoYp8Cak28NG5NoG-mobile.webp",
"link": "/api/img/c7xWNyoYp8Cak28NG5NoG-mobile.webp",
"category": "image"
},
{
"name": "cg78Sb_QzZFlli9s2FPVc-mobile.webp",
"path": "image/cg78Sb_QzZFlli9s2FPVc-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c5a2cd18-806d-4dcb-b5c5-b0c6bcef7f35/cg78Sb_QzZFlli9s2FPVc-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c5a2cd18-806d-4dcb-b5c5-b0c6bcef7f35/cg78Sb_QzZFlli9s2FPVc-mobile.webp",
"link": "/api/img/cg78Sb_QzZFlli9s2FPVc-mobile.webp",
"category": "image"
},
{
"name": "d3v1AgLoSJhf5xvmmO3oP-mobile.webp",
"path": "image/d3v1AgLoSJhf5xvmmO3oP-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ae72c51f-9df7-4b07-9fd5-e945c775d9ab/d3v1AgLoSJhf5xvmmO3oP-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ae72c51f-9df7-4b07-9fd5-e945c775d9ab/d3v1AgLoSJhf5xvmmO3oP-mobile.webp",
"link": "/api/img/d3v1AgLoSJhf5xvmmO3oP-mobile.webp",
"category": "image"
},
{
"name": "d6hJgycQawWN3VEcHaqtR-desktop.webp",
"path": "image/d6hJgycQawWN3VEcHaqtR-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4e5b9387-67b5-4c00-8f80-95ec6c54ff4a/d6hJgycQawWN3VEcHaqtR-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4e5b9387-67b5-4c00-8f80-95ec6c54ff4a/d6hJgycQawWN3VEcHaqtR-desktop.webp",
"link": "/api/img/d6hJgycQawWN3VEcHaqtR-desktop.webp",
"category": "image"
},
{
"name": "d6hJgycQawWN3VEcHaqtR-mobile.webp",
"path": "image/d6hJgycQawWN3VEcHaqtR-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/011f65c9-4273-43e8-b6d7-ce7a5319ae83/d6hJgycQawWN3VEcHaqtR-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/011f65c9-4273-43e8-b6d7-ce7a5319ae83/d6hJgycQawWN3VEcHaqtR-mobile.webp",
"link": "/api/img/d6hJgycQawWN3VEcHaqtR-mobile.webp",
"category": "image"
},
{
"name": "DyX82oztXbHfu6HEvbrpt-desktop.webp",
"path": "image/DyX82oztXbHfu6HEvbrpt-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/b715dce5-1606-44cf-976f-57d8142e218e/DyX82oztXbHfu6HEvbrpt-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/b715dce5-1606-44cf-976f-57d8142e218e/DyX82oztXbHfu6HEvbrpt-desktop.webp",
"link": "/api/img/DyX82oztXbHfu6HEvbrpt-desktop.webp",
"category": "image"
},
{
"name": "DyX82oztXbHfu6HEvbrpt-mobile.webp",
"path": "image/DyX82oztXbHfu6HEvbrpt-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d0ff5925-ec84-4100-920c-93e2eb479f13/DyX82oztXbHfu6HEvbrpt-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d0ff5925-ec84-4100-920c-93e2eb479f13/DyX82oztXbHfu6HEvbrpt-mobile.webp",
"link": "/api/img/DyX82oztXbHfu6HEvbrpt-mobile.webp",
"category": "image"
},
{
"name": "EcQIGOF6LW1dIKE53vmba-desktop.webp",
"path": "image/EcQIGOF6LW1dIKE53vmba-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7a97403e-9d6c-4a00-9c54-d5add0bd5915/EcQIGOF6LW1dIKE53vmba-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7a97403e-9d6c-4a00-9c54-d5add0bd5915/EcQIGOF6LW1dIKE53vmba-desktop.webp",
"link": "/api/img/EcQIGOF6LW1dIKE53vmba-desktop.webp",
"category": "image"
},
{
"name": "EcQIGOF6LW1dIKE53vmba-mobile.webp",
"path": "image/EcQIGOF6LW1dIKE53vmba-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7e85b8e8-27f5-46c7-b4fc-590d66eef2ce/EcQIGOF6LW1dIKE53vmba-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7e85b8e8-27f5-46c7-b4fc-590d66eef2ce/EcQIGOF6LW1dIKE53vmba-mobile.webp",
"link": "/api/img/EcQIGOF6LW1dIKE53vmba-mobile.webp",
"category": "image"
},
{
"name": "Ez-SkRyf_F-1gksz_amNg-desktop.webp",
"path": "image/Ez-SkRyf_F-1gksz_amNg-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c16de343-1297-4248-b104-83b3e3605f32/Ez-SkRyf_F-1gksz_amNg-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c16de343-1297-4248-b104-83b3e3605f32/Ez-SkRyf_F-1gksz_amNg-desktop.webp",
"link": "/api/img/Ez-SkRyf_F-1gksz_amNg-desktop.webp",
"category": "image"
},
{
"name": "Ez-SkRyf_F-1gksz_amNg-mobile.webp",
"path": "image/Ez-SkRyf_F-1gksz_amNg-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ece148ca-8aa1-43ef-a8de-ea0bde0a315a/Ez-SkRyf_F-1gksz_amNg-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ece148ca-8aa1-43ef-a8de-ea0bde0a315a/Ez-SkRyf_F-1gksz_amNg-mobile.webp",
"link": "/api/img/Ez-SkRyf_F-1gksz_amNg-mobile.webp",
"category": "image"
},
{
"name": "g4ICsRrmOaIqS_yqlQLZK-desktop.webp",
"path": "image/g4ICsRrmOaIqS_yqlQLZK-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/31280b01-6cdb-4d96-9c96-0eecec6a238c/g4ICsRrmOaIqS_yqlQLZK-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/31280b01-6cdb-4d96-9c96-0eecec6a238c/g4ICsRrmOaIqS_yqlQLZK-desktop.webp",
"link": "/api/img/g4ICsRrmOaIqS_yqlQLZK-desktop.webp",
"category": "image"
},
{
"name": "g4ICsRrmOaIqS_yqlQLZK-mobile.webp",
"path": "image/g4ICsRrmOaIqS_yqlQLZK-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/af7f3e11-1f63-4307-88e9-64382a949279/g4ICsRrmOaIqS_yqlQLZK-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/af7f3e11-1f63-4307-88e9-64382a949279/g4ICsRrmOaIqS_yqlQLZK-mobile.webp",
"link": "/api/img/g4ICsRrmOaIqS_yqlQLZK-mobile.webp",
"category": "image"
},
{
"name": "Gc79mlIlGuoRQuTqskFj--desktop.webp",
"path": "image/Gc79mlIlGuoRQuTqskFj--desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/05214122-51bb-4fba-9b7c-f69e072d8a0d/Gc79mlIlGuoRQuTqskFj--desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/05214122-51bb-4fba-9b7c-f69e072d8a0d/Gc79mlIlGuoRQuTqskFj--desktop.webp",
"link": "/api/img/Gc79mlIlGuoRQuTqskFj--desktop.webp",
"category": "image"
},
{
"name": "Gc79mlIlGuoRQuTqskFj--mobile.webp",
"path": "image/Gc79mlIlGuoRQuTqskFj--mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d49ab5d2-7087-4088-8e59-51f116f21e27/Gc79mlIlGuoRQuTqskFj--mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d49ab5d2-7087-4088-8e59-51f116f21e27/Gc79mlIlGuoRQuTqskFj--mobile.webp",
"link": "/api/img/Gc79mlIlGuoRQuTqskFj--mobile.webp",
"category": "image"
},
{
"name": "Gi8EX3pBmT719AfzXirDS-desktop.webp",
"path": "image/Gi8EX3pBmT719AfzXirDS-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4b456bad-228a-4211-a1bb-431dc081ecc7/Gi8EX3pBmT719AfzXirDS-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4b456bad-228a-4211-a1bb-431dc081ecc7/Gi8EX3pBmT719AfzXirDS-desktop.webp",
"link": "/api/img/Gi8EX3pBmT719AfzXirDS-desktop.webp",
"category": "image"
},
{
"name": "Gi8EX3pBmT719AfzXirDS-mobile.webp",
"path": "image/Gi8EX3pBmT719AfzXirDS-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/68308100-d468-4e53-9cc6-3aa12035c8ab/Gi8EX3pBmT719AfzXirDS-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/68308100-d468-4e53-9cc6-3aa12035c8ab/Gi8EX3pBmT719AfzXirDS-mobile.webp",
"link": "/api/img/Gi8EX3pBmT719AfzXirDS-mobile.webp",
"category": "image"
},
{
"name": "gyNi4s8TnK2UrViU-gN2C-desktop.webp",
"path": "image/gyNi4s8TnK2UrViU-gN2C-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/539debe4-f3fc-4574-a256-ac8c8dbf5a00/gyNi4s8TnK2UrViU-gN2C-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/539debe4-f3fc-4574-a256-ac8c8dbf5a00/gyNi4s8TnK2UrViU-gN2C-desktop.webp",
"link": "/api/img/gyNi4s8TnK2UrViU-gN2C-desktop.webp",
"category": "image"
},
{
"name": "gyNi4s8TnK2UrViU-gN2C-mobile.webp",
"path": "image/gyNi4s8TnK2UrViU-gN2C-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4971a22a-c0dd-4492-bff5-a8aa3e93f27f/gyNi4s8TnK2UrViU-gN2C-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4971a22a-c0dd-4492-bff5-a8aa3e93f27f/gyNi4s8TnK2UrViU-gN2C-mobile.webp",
"link": "/api/img/gyNi4s8TnK2UrViU-gN2C-mobile.webp",
"category": "image"
},
{
"name": "h_Gd0SoeIJVTi_5TWUO-P-desktop.webp",
"path": "image/h_Gd0SoeIJVTi_5TWUO-P-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/8409886e-c01b-421a-ac44-6d3a4bfd0985/h_Gd0SoeIJVTi_5TWUO-P-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/8409886e-c01b-421a-ac44-6d3a4bfd0985/h_Gd0SoeIJVTi_5TWUO-P-desktop.webp",
"link": "/api/img/h_Gd0SoeIJVTi_5TWUO-P-desktop.webp",
"category": "image"
},
{
"name": "h_Gd0SoeIJVTi_5TWUO-P-mobile.webp",
"path": "image/h_Gd0SoeIJVTi_5TWUO-P-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/f4a5280d-bd2d-4c5a-8040-183f9e5d951b/h_Gd0SoeIJVTi_5TWUO-P-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/f4a5280d-bd2d-4c5a-8040-183f9e5d951b/h_Gd0SoeIJVTi_5TWUO-P-mobile.webp",
"link": "/api/img/h_Gd0SoeIJVTi_5TWUO-P-mobile.webp",
"category": "image"
},
{
"name": "hLeF0GRFZqDUngZnDMAAk-desktop.webp",
"path": "image/hLeF0GRFZqDUngZnDMAAk-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/6b33097e-8d9d-4864-964b-6dc49b62b4ae/hLeF0GRFZqDUngZnDMAAk-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/6b33097e-8d9d-4864-964b-6dc49b62b4ae/hLeF0GRFZqDUngZnDMAAk-desktop.webp",
"link": "/api/img/hLeF0GRFZqDUngZnDMAAk-desktop.webp",
"category": "image"
},
{
"name": "hLeF0GRFZqDUngZnDMAAk-mobile.webp",
"path": "image/hLeF0GRFZqDUngZnDMAAk-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7dff816b-65bb-429c-b87e-3ff892d547dc/hLeF0GRFZqDUngZnDMAAk-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7dff816b-65bb-429c-b87e-3ff892d547dc/hLeF0GRFZqDUngZnDMAAk-mobile.webp",
"link": "/api/img/hLeF0GRFZqDUngZnDMAAk-mobile.webp",
"category": "image"
},
{
"name": "hsHiD59dZQxr8G2SAfUYp-mobile.webp",
"path": "image/hsHiD59dZQxr8G2SAfUYp-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/55103cd4-6f57-491d-bd41-03c0068974ef/hsHiD59dZQxr8G2SAfUYp-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/55103cd4-6f57-491d-bd41-03c0068974ef/hsHiD59dZQxr8G2SAfUYp-mobile.webp",
"link": "/api/img/hsHiD59dZQxr8G2SAfUYp-mobile.webp",
"category": "image"
},
{
"name": "hyyTFi8EApjzFEZ9EvJgB-desktop.webp",
"path": "image/hyyTFi8EApjzFEZ9EvJgB-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/0ec4a67e-695e-4524-bf22-f823b80c7e6b/hyyTFi8EApjzFEZ9EvJgB-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/0ec4a67e-695e-4524-bf22-f823b80c7e6b/hyyTFi8EApjzFEZ9EvJgB-desktop.webp",
"link": "/api/img/hyyTFi8EApjzFEZ9EvJgB-desktop.webp",
"category": "image"
},
{
"name": "hyyTFi8EApjzFEZ9EvJgB-mobile.webp",
"path": "image/hyyTFi8EApjzFEZ9EvJgB-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c982541e-f8b2-455a-a3cd-f856cd954bed/hyyTFi8EApjzFEZ9EvJgB-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c982541e-f8b2-455a-a3cd-f856cd954bed/hyyTFi8EApjzFEZ9EvJgB-mobile.webp",
"link": "/api/img/hyyTFi8EApjzFEZ9EvJgB-mobile.webp",
"category": "image"
},
{
"name": "isTT2LmPbeOWD5wAdqleX-mobile.webp",
"path": "image/isTT2LmPbeOWD5wAdqleX-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ef6f8237-0803-422a-83af-4daca61c7065/isTT2LmPbeOWD5wAdqleX-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ef6f8237-0803-422a-83af-4daca61c7065/isTT2LmPbeOWD5wAdqleX-mobile.webp",
"link": "/api/img/isTT2LmPbeOWD5wAdqleX-mobile.webp",
"category": "image"
},
{
"name": "JhJigMo269K1TFGzSB1OS-desktop.webp",
"path": "image/JhJigMo269K1TFGzSB1OS-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/668d2f32-3277-4842-8a01-c3cb5ca0852b/JhJigMo269K1TFGzSB1OS-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/668d2f32-3277-4842-8a01-c3cb5ca0852b/JhJigMo269K1TFGzSB1OS-desktop.webp",
"link": "/api/img/JhJigMo269K1TFGzSB1OS-desktop.webp",
"category": "image"
},
{
"name": "JhJigMo269K1TFGzSB1OS-mobile.webp",
"path": "image/JhJigMo269K1TFGzSB1OS-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/df8c52a3-189a-48a0-b7e7-98efe2479414/JhJigMo269K1TFGzSB1OS-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/df8c52a3-189a-48a0-b7e7-98efe2479414/JhJigMo269K1TFGzSB1OS-mobile.webp",
"link": "/api/img/JhJigMo269K1TFGzSB1OS-mobile.webp",
"category": "image"
},
{
"name": "jYxEXspWH5g6eTTVqK72c-desktop.webp",
"path": "image/jYxEXspWH5g6eTTVqK72c-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/a13572b4-2e22-4d76-8826-64a8e6ae4e13/jYxEXspWH5g6eTTVqK72c-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/a13572b4-2e22-4d76-8826-64a8e6ae4e13/jYxEXspWH5g6eTTVqK72c-desktop.webp",
"link": "/api/img/jYxEXspWH5g6eTTVqK72c-desktop.webp",
"category": "image"
},
{
"name": "jYxEXspWH5g6eTTVqK72c-mobile.webp",
"path": "image/jYxEXspWH5g6eTTVqK72c-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/55f171fa-585f-4a94-bfeb-d2bad2f7ee39/jYxEXspWH5g6eTTVqK72c-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/55f171fa-585f-4a94-bfeb-d2bad2f7ee39/jYxEXspWH5g6eTTVqK72c-mobile.webp",
"link": "/api/img/jYxEXspWH5g6eTTVqK72c-mobile.webp",
"category": "image"
},
{
"name": "K0wY911212dinYA3AFB_f-desktop.webp",
"path": "image/K0wY911212dinYA3AFB_f-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/31ea22bf-9ce1-4dc6-b901-caaec86c35c4/K0wY911212dinYA3AFB_f-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/31ea22bf-9ce1-4dc6-b901-caaec86c35c4/K0wY911212dinYA3AFB_f-desktop.webp",
"link": "/api/img/K0wY911212dinYA3AFB_f-desktop.webp",
"category": "image"
},
{
"name": "K0wY911212dinYA3AFB_f-mobile.webp",
"path": "image/K0wY911212dinYA3AFB_f-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ea061aa6-7e5e-447c-bec8-be1d927cc578/K0wY911212dinYA3AFB_f-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/ea061aa6-7e5e-447c-bec8-be1d927cc578/K0wY911212dinYA3AFB_f-mobile.webp",
"link": "/api/img/K0wY911212dinYA3AFB_f-mobile.webp",
"category": "image"
},
{
"name": "l4qsUEw2JiclGAkkrXp9g-desktop.webp",
"path": "image/l4qsUEw2JiclGAkkrXp9g-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/05088eb1-44bc-44d6-9e67-08dd6bca00ae/l4qsUEw2JiclGAkkrXp9g-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/05088eb1-44bc-44d6-9e67-08dd6bca00ae/l4qsUEw2JiclGAkkrXp9g-desktop.webp",
"link": "/api/img/l4qsUEw2JiclGAkkrXp9g-desktop.webp",
"category": "image"
},
{
"name": "l4qsUEw2JiclGAkkrXp9g-mobile.webp",
"path": "image/l4qsUEw2JiclGAkkrXp9g-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/cf411a77-b7fc-4ac7-a98d-f9f89bc27e85/l4qsUEw2JiclGAkkrXp9g-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/cf411a77-b7fc-4ac7-a98d-f9f89bc27e85/l4qsUEw2JiclGAkkrXp9g-mobile.webp",
"link": "/api/img/l4qsUEw2JiclGAkkrXp9g-mobile.webp",
"category": "image"
},
{
"name": "M9QlgVKIEfCdY3g4F_tRZ-desktop.webp",
"path": "image/M9QlgVKIEfCdY3g4F_tRZ-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/dfa58064-c17b-453a-b0a1-613109757844/M9QlgVKIEfCdY3g4F_tRZ-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/dfa58064-c17b-453a-b0a1-613109757844/M9QlgVKIEfCdY3g4F_tRZ-desktop.webp",
"link": "/api/img/M9QlgVKIEfCdY3g4F_tRZ-desktop.webp",
"category": "image"
},
{
"name": "M9QlgVKIEfCdY3g4F_tRZ-mobile.webp",
"path": "image/M9QlgVKIEfCdY3g4F_tRZ-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4be366ca-1a39-46e9-adf2-d1d28fd83961/M9QlgVKIEfCdY3g4F_tRZ-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4be366ca-1a39-46e9-adf2-d1d28fd83961/M9QlgVKIEfCdY3g4F_tRZ-mobile.webp",
"link": "/api/img/M9QlgVKIEfCdY3g4F_tRZ-mobile.webp",
"category": "image"
},
{
"name": "mtQsaKtQnhxIYVIooCkiQ-desktop.webp",
"path": "image/mtQsaKtQnhxIYVIooCkiQ-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/5015a484-ac9a-485f-9fb0-a29e3824a6ce/mtQsaKtQnhxIYVIooCkiQ-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/5015a484-ac9a-485f-9fb0-a29e3824a6ce/mtQsaKtQnhxIYVIooCkiQ-desktop.webp",
"link": "/api/img/mtQsaKtQnhxIYVIooCkiQ-desktop.webp",
"category": "image"
},
{
"name": "mtQsaKtQnhxIYVIooCkiQ-mobile.webp",
"path": "image/mtQsaKtQnhxIYVIooCkiQ-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/10ddd132-5b85-4a8f-b129-56a10540fc8c/mtQsaKtQnhxIYVIooCkiQ-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/10ddd132-5b85-4a8f-b129-56a10540fc8c/mtQsaKtQnhxIYVIooCkiQ-mobile.webp",
"link": "/api/img/mtQsaKtQnhxIYVIooCkiQ-mobile.webp",
"category": "image"
},
{
"name": "NBPAqjPXn7GQmYTDBI5hu-desktop.webp",
"path": "image/NBPAqjPXn7GQmYTDBI5hu-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/fd8cfea3-5cf2-489e-9f21-e7985335dc98/NBPAqjPXn7GQmYTDBI5hu-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/fd8cfea3-5cf2-489e-9f21-e7985335dc98/NBPAqjPXn7GQmYTDBI5hu-desktop.webp",
"link": "/api/img/NBPAqjPXn7GQmYTDBI5hu-desktop.webp",
"category": "image"
},
{
"name": "NBPAqjPXn7GQmYTDBI5hu-mobile.webp",
"path": "image/NBPAqjPXn7GQmYTDBI5hu-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/f5b02049-95db-4e1b-8bfd-b1a4c431ee49/NBPAqjPXn7GQmYTDBI5hu-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/f5b02049-95db-4e1b-8bfd-b1a4c431ee49/NBPAqjPXn7GQmYTDBI5hu-mobile.webp",
"link": "/api/img/NBPAqjPXn7GQmYTDBI5hu-mobile.webp",
"category": "image"
},
{
"name": "NyPGo-1AtfNm5wkAq7Om6-mobile.webp",
"path": "image/NyPGo-1AtfNm5wkAq7Om6-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/b7361eb8-37e8-4baa-a6d6-01b6131dd788/NyPGo-1AtfNm5wkAq7Om6-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/b7361eb8-37e8-4baa-a6d6-01b6131dd788/NyPGo-1AtfNm5wkAq7Om6-mobile.webp",
"link": "/api/img/NyPGo-1AtfNm5wkAq7Om6-mobile.webp",
"category": "image"
},
{
"name": "OsMY3AYPyGC_CoN1xUjOn-desktop.webp",
"path": "image/OsMY3AYPyGC_CoN1xUjOn-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/509a3603-5d11-4857-baa5-d439da43825a/OsMY3AYPyGC_CoN1xUjOn-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/509a3603-5d11-4857-baa5-d439da43825a/OsMY3AYPyGC_CoN1xUjOn-desktop.webp",
"link": "/api/img/OsMY3AYPyGC_CoN1xUjOn-desktop.webp",
"category": "image"
},
{
"name": "OsMY3AYPyGC_CoN1xUjOn-mobile.webp",
"path": "image/OsMY3AYPyGC_CoN1xUjOn-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/cbe9798a-4cf0-45f7-b041-70269490128b/OsMY3AYPyGC_CoN1xUjOn-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/cbe9798a-4cf0-45f7-b041-70269490128b/OsMY3AYPyGC_CoN1xUjOn-mobile.webp",
"link": "/api/img/OsMY3AYPyGC_CoN1xUjOn-mobile.webp",
"category": "image"
},
{
"name": "pps1ZgzJxDb4VZxEvtZeu-desktop.webp",
"path": "image/pps1ZgzJxDb4VZxEvtZeu-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/500fa1f3-d412-4f48-bc5f-465b91149c6e/pps1ZgzJxDb4VZxEvtZeu-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/500fa1f3-d412-4f48-bc5f-465b91149c6e/pps1ZgzJxDb4VZxEvtZeu-desktop.webp",
"link": "/api/img/pps1ZgzJxDb4VZxEvtZeu-desktop.webp",
"category": "image"
},
{
"name": "pps1ZgzJxDb4VZxEvtZeu-mobile.webp",
"path": "image/pps1ZgzJxDb4VZxEvtZeu-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/19c2b1a6-8c9b-4be9-981c-72d7a3ab6e38/pps1ZgzJxDb4VZxEvtZeu-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/19c2b1a6-8c9b-4be9-981c-72d7a3ab6e38/pps1ZgzJxDb4VZxEvtZeu-mobile.webp",
"link": "/api/img/pps1ZgzJxDb4VZxEvtZeu-mobile.webp",
"category": "image"
},
{
"name": "r_gBF0FuFpFPfSENHc4XI-desktop.webp",
"path": "image/r_gBF0FuFpFPfSENHc4XI-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/2e4ab451-df52-4f04-8af0-db2e789e58bb/r_gBF0FuFpFPfSENHc4XI-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/2e4ab451-df52-4f04-8af0-db2e789e58bb/r_gBF0FuFpFPfSENHc4XI-desktop.webp",
"link": "/api/img/r_gBF0FuFpFPfSENHc4XI-desktop.webp",
"category": "image"
},
{
"name": "r_gBF0FuFpFPfSENHc4XI-mobile.webp",
"path": "image/r_gBF0FuFpFPfSENHc4XI-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/1e2e8884-9da3-4610-9c57-8925740d4128/r_gBF0FuFpFPfSENHc4XI-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/1e2e8884-9da3-4610-9c57-8925740d4128/r_gBF0FuFpFPfSENHc4XI-mobile.webp",
"link": "/api/img/r_gBF0FuFpFPfSENHc4XI-mobile.webp",
"category": "image"
},
{
"name": "SQqSobKRg3ShvgPw_H41h-desktop.webp",
"path": "image/SQqSobKRg3ShvgPw_H41h-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4360cb84-f82a-4a68-afd3-65decd912f30/SQqSobKRg3ShvgPw_H41h-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/4360cb84-f82a-4a68-afd3-65decd912f30/SQqSobKRg3ShvgPw_H41h-desktop.webp",
"link": "/api/img/SQqSobKRg3ShvgPw_H41h-desktop.webp",
"category": "image"
},
{
"name": "SQqSobKRg3ShvgPw_H41h-mobile.webp",
"path": "image/SQqSobKRg3ShvgPw_H41h-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c808dff8-2e8a-4358-af03-4a838c9a6d6c/SQqSobKRg3ShvgPw_H41h-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c808dff8-2e8a-4358-af03-4a838c9a6d6c/SQqSobKRg3ShvgPw_H41h-mobile.webp",
"link": "/api/img/SQqSobKRg3ShvgPw_H41h-mobile.webp",
"category": "image"
},
{
"name": "TDQReg1lQ73s39crXW0ra-desktop.webp",
"path": "image/TDQReg1lQ73s39crXW0ra-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/04d15638-31ed-440f-9fa0-bb30d71bbc59/TDQReg1lQ73s39crXW0ra-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/04d15638-31ed-440f-9fa0-bb30d71bbc59/TDQReg1lQ73s39crXW0ra-desktop.webp",
"link": "/api/img/TDQReg1lQ73s39crXW0ra-desktop.webp",
"category": "image"
},
{
"name": "TDQReg1lQ73s39crXW0ra-mobile.webp",
"path": "image/TDQReg1lQ73s39crXW0ra-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/da174313-329c-4156-88e2-fc929325dfff/TDQReg1lQ73s39crXW0ra-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/da174313-329c-4156-88e2-fc929325dfff/TDQReg1lQ73s39crXW0ra-mobile.webp",
"link": "/api/img/TDQReg1lQ73s39crXW0ra-mobile.webp",
"category": "image"
},
{
"name": "TTur8BttDlAS9UgZVe3M8-desktop.webp",
"path": "image/TTur8BttDlAS9UgZVe3M8-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/32fe30ab-0d7b-4ada-8d5d-993baf23545c/TTur8BttDlAS9UgZVe3M8-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/32fe30ab-0d7b-4ada-8d5d-993baf23545c/TTur8BttDlAS9UgZVe3M8-desktop.webp",
"link": "/api/img/TTur8BttDlAS9UgZVe3M8-desktop.webp",
"category": "image"
},
{
"name": "TTur8BttDlAS9UgZVe3M8-mobile.webp",
"path": "image/TTur8BttDlAS9UgZVe3M8-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/85c5ecb0-2fb5-4431-af11-0c851e52de4e/TTur8BttDlAS9UgZVe3M8-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/85c5ecb0-2fb5-4431-af11-0c851e52de4e/TTur8BttDlAS9UgZVe3M8-mobile.webp",
"link": "/api/img/TTur8BttDlAS9UgZVe3M8-mobile.webp",
"category": "image"
},
{
"name": "TWdNTZZbTOhFTNJGGPDyG-desktop.webp",
"path": "image/TWdNTZZbTOhFTNJGGPDyG-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d606d946-fdf9-41b9-b0bd-1421b2ec6843/TWdNTZZbTOhFTNJGGPDyG-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d606d946-fdf9-41b9-b0bd-1421b2ec6843/TWdNTZZbTOhFTNJGGPDyG-desktop.webp",
"link": "/api/img/TWdNTZZbTOhFTNJGGPDyG-desktop.webp",
"category": "image"
},
{
"name": "TWdNTZZbTOhFTNJGGPDyG-mobile.webp",
"path": "image/TWdNTZZbTOhFTNJGGPDyG-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/46859e6a-ebfc-4124-adfe-320953256fe5/TWdNTZZbTOhFTNJGGPDyG-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/46859e6a-ebfc-4124-adfe-320953256fe5/TWdNTZZbTOhFTNJGGPDyG-mobile.webp",
"link": "/api/img/TWdNTZZbTOhFTNJGGPDyG-mobile.webp",
"category": "image"
},
{
"name": "TXknK9CSRSxwvM2hPW6BO-desktop.webp",
"path": "image/TXknK9CSRSxwvM2hPW6BO-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/af38b038-0d38-4222-be29-09cb81054ce7/TXknK9CSRSxwvM2hPW6BO-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/af38b038-0d38-4222-be29-09cb81054ce7/TXknK9CSRSxwvM2hPW6BO-desktop.webp",
"link": "/api/img/TXknK9CSRSxwvM2hPW6BO-desktop.webp",
"category": "image"
},
{
"name": "TXknK9CSRSxwvM2hPW6BO-mobile.webp",
"path": "image/TXknK9CSRSxwvM2hPW6BO-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/eab1c384-aafa-438f-ac0f-003ddd51c9a5/TXknK9CSRSxwvM2hPW6BO-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/eab1c384-aafa-438f-ac0f-003ddd51c9a5/TXknK9CSRSxwvM2hPW6BO-mobile.webp",
"link": "/api/img/TXknK9CSRSxwvM2hPW6BO-mobile.webp",
"category": "image"
},
{
"name": "U7rePDZq5E59z-Eo9tLBe-desktop.webp",
"path": "image/U7rePDZq5E59z-Eo9tLBe-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/a2858ed9-8bb6-47cd-9e1b-831928a0389f/U7rePDZq5E59z-Eo9tLBe-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/a2858ed9-8bb6-47cd-9e1b-831928a0389f/U7rePDZq5E59z-Eo9tLBe-desktop.webp",
"link": "/api/img/U7rePDZq5E59z-Eo9tLBe-desktop.webp",
"category": "image"
},
{
"name": "U7rePDZq5E59z-Eo9tLBe-mobile.webp",
"path": "image/U7rePDZq5E59z-Eo9tLBe-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/1f4a189d-d312-46ef-a68c-c0c7261860d0/U7rePDZq5E59z-Eo9tLBe-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/1f4a189d-d312-46ef-a68c-c0c7261860d0/U7rePDZq5E59z-Eo9tLBe-mobile.webp",
"link": "/api/img/U7rePDZq5E59z-Eo9tLBe-mobile.webp",
"category": "image"
},
{
"name": "uDxAalFV0qRv_RrW9flM8-mobile.webp",
"path": "image/uDxAalFV0qRv_RrW9flM8-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/5f006c3c-47f5-4e48-8bdd-7fbe005bf810/uDxAalFV0qRv_RrW9flM8-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/5f006c3c-47f5-4e48-8bdd-7fbe005bf810/uDxAalFV0qRv_RrW9flM8-mobile.webp",
"link": "/api/img/uDxAalFV0qRv_RrW9flM8-mobile.webp",
"category": "image"
},
{
"name": "uE2QwpbcXyBWxVYqCWQQT-desktop.webp",
"path": "image/uE2QwpbcXyBWxVYqCWQQT-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/edf73617-214b-44df-960a-dd68f0bad97a/uE2QwpbcXyBWxVYqCWQQT-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/edf73617-214b-44df-960a-dd68f0bad97a/uE2QwpbcXyBWxVYqCWQQT-desktop.webp",
"link": "/api/img/uE2QwpbcXyBWxVYqCWQQT-desktop.webp",
"category": "image"
},
{
"name": "uE2QwpbcXyBWxVYqCWQQT-mobile.webp",
"path": "image/uE2QwpbcXyBWxVYqCWQQT-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d7f5d738-b18f-44c8-92bb-8e526f47d9ee/uE2QwpbcXyBWxVYqCWQQT-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/d7f5d738-b18f-44c8-92bb-8e526f47d9ee/uE2QwpbcXyBWxVYqCWQQT-mobile.webp",
"link": "/api/img/uE2QwpbcXyBWxVYqCWQQT-mobile.webp",
"category": "image"
},
{
"name": "v7Ac2xQvTiJy-HYh1AxF4-desktop.webp",
"path": "image/v7Ac2xQvTiJy-HYh1AxF4-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/3e1b8dd9-2bf5-4daf-9dd9-dd687e9b2f2c/v7Ac2xQvTiJy-HYh1AxF4-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/3e1b8dd9-2bf5-4daf-9dd9-dd687e9b2f2c/v7Ac2xQvTiJy-HYh1AxF4-desktop.webp",
"link": "/api/img/v7Ac2xQvTiJy-HYh1AxF4-desktop.webp",
"category": "image"
},
{
"name": "v7Ac2xQvTiJy-HYh1AxF4-mobile.webp",
"path": "image/v7Ac2xQvTiJy-HYh1AxF4-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/44c78026-f802-46f3-8ec2-271f0f001f7a/v7Ac2xQvTiJy-HYh1AxF4-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/44c78026-f802-46f3-8ec2-271f0f001f7a/v7Ac2xQvTiJy-HYh1AxF4-mobile.webp",
"link": "/api/img/v7Ac2xQvTiJy-HYh1AxF4-mobile.webp",
"category": "image"
},
{
"name": "wh79hF4HTZMEFtYc-OfZg-mobile.webp",
"path": "image/wh79hF4HTZMEFtYc-OfZg-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/b4b4378e-76ad-4b15-84cf-00178553b3d4/wh79hF4HTZMEFtYc-OfZg-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/b4b4378e-76ad-4b15-84cf-00178553b3d4/wh79hF4HTZMEFtYc-OfZg-mobile.webp",
"link": "/api/img/wh79hF4HTZMEFtYc-OfZg-mobile.webp",
"category": "image"
},
{
"name": "x0_-siY2V8IehBzo4_uph-desktop.webp",
"path": "image/x0_-siY2V8IehBzo4_uph-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7f82bcea-e7c6-4cde-9701-8d3afe49c0f8/x0_-siY2V8IehBzo4_uph-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/7f82bcea-e7c6-4cde-9701-8d3afe49c0f8/x0_-siY2V8IehBzo4_uph-desktop.webp",
"link": "/api/img/x0_-siY2V8IehBzo4_uph-desktop.webp",
"category": "image"
},
{
"name": "x0_-siY2V8IehBzo4_uph-mobile.webp",
"path": "image/x0_-siY2V8IehBzo4_uph-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c4b23ebc-3915-4102-a25c-4e2f6da0d097/x0_-siY2V8IehBzo4_uph-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/c4b23ebc-3915-4102-a25c-4e2f6da0d097/x0_-siY2V8IehBzo4_uph-mobile.webp",
"link": "/api/img/x0_-siY2V8IehBzo4_uph-mobile.webp",
"category": "image"
},
{
"name": "y78xZ2axTOjz87gRKjVAf-desktop.webp",
"path": "image/y78xZ2axTOjz87gRKjVAf-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/180d0c29-c93e-4bbe-b399-7e6a34fbeb49/y78xZ2axTOjz87gRKjVAf-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/180d0c29-c93e-4bbe-b399-7e6a34fbeb49/y78xZ2axTOjz87gRKjVAf-desktop.webp",
"link": "/api/img/y78xZ2axTOjz87gRKjVAf-desktop.webp",
"category": "image"
},
{
"name": "y78xZ2axTOjz87gRKjVAf-mobile.webp",
"path": "image/y78xZ2axTOjz87gRKjVAf-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/71b5091a-ebcd-4d4c-9aae-1b7e548051fc/y78xZ2axTOjz87gRKjVAf-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/71b5091a-ebcd-4d4c-9aae-1b7e548051fc/y78xZ2axTOjz87gRKjVAf-mobile.webp",
"link": "/api/img/y78xZ2axTOjz87gRKjVAf-mobile.webp",
"category": "image"
},
{
"name": "YdCBnK-bWxlyHjwsk4Qie-desktop.webp",
"path": "image/YdCBnK-bWxlyHjwsk4Qie-desktop.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/bf6f2e11-b328-4da1-bda7-81af2336d03f/YdCBnK-bWxlyHjwsk4Qie-desktop.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/bf6f2e11-b328-4da1-bda7-81af2336d03f/YdCBnK-bWxlyHjwsk4Qie-desktop.webp",
"link": "/api/img/YdCBnK-bWxlyHjwsk4Qie-desktop.webp",
"category": "image"
},
{
"name": "YdCBnK-bWxlyHjwsk4Qie-mobile.webp",
"path": "image/YdCBnK-bWxlyHjwsk4Qie-mobile.webp",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/9d7e5232-3b30-4ead-9482-1fed3a86245a/YdCBnK-bWxlyHjwsk4Qie-mobile.webp"
"path": "image",
"downloadUrl": "https://cld-dkr-makuro-seafile.wibudev.com/seafhttp/files/9d7e5232-3b30-4ead-9482-1fed3a86245a/YdCBnK-bWxlyHjwsk4Qie-mobile.webp",
"link": "/api/img/YdCBnK-bWxlyHjwsk4Qie-mobile.webp",
"category": "image"
}
]
]

View File

@@ -1,49 +1,92 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
import prisma from "@/lib/prisma";
import { Client } from "minio";
import { getAllPublicCdnUrls } from "./lib/create_file_share_folder";
const minio = new Client({
endPoint: process.env.MINIO_ENDPOINT!,
accessKey: process.env.MINIO_ACCESS_KEY!,
secretKey: process.env.MINIO_SECRET_KEY!,
useSSL: process.env.MINIO_USE_SSL === "true",
});
const BUCKET = process.env.MINIO_BUCKET!;
function guessMimeType(fileName: string): string {
const ext = fileName.split(".").pop()?.toLowerCase() ?? "";
const map: Record<string, string> = {
webp: "image/webp",
jpg: "image/jpeg",
jpeg: "image/jpeg",
png: "image/png",
gif: "image/gif",
mp3: "audio/mpeg",
mp4: "audio/mp4",
pdf: "application/pdf",
};
return map[ext] ?? "application/octet-stream";
}
export default async function seedAssets() {
const images = await getAllPublicCdnUrls();
console.log("📂 Seeding assets dari MinIO...");
const stream = minio.listObjects(BUCKET, "image/", true);
let seeded = 0;
let updated = 0;
let skipped = 0;
for await (const obj of stream) {
if (!obj.name) continue;
const fileName = obj.name.replace("image/", "");
if (!fileName) continue;
const mimeType = guessMimeType(fileName);
for (const img of images) {
try {
// Check if the image already exists by name
const existingImage = await prisma.fileStorage.findUnique({
where: { name: img.name },
const existing = await prisma.fileStorage.findUnique({
where: { name: fileName },
});
if (!existingImage) {
// Only create if it doesn't exist
await prisma.fileStorage.create({
data: {
name: img.name,
category: "image",
mimeType: "image/webp",
link: img.cdnUrl,
path: "images",
realName: img.name,
isActive: true,
},
});
console.log(`✅ Created new image: ${img.name}`);
} else {
console.log(` Image already exists, skipping: ${img.name}`);
if (existing) {
// Perbaiki link lama yang masih pakai Seafile URL atau format lama
if (!existing.link?.startsWith("/api/img/")) {
await prisma.fileStorage.update({
where: { name: fileName },
data: { link: `/api/img/${fileName}`, path: "image" },
});
console.log(` 🔄 Updated: ${fileName}`);
updated++;
} else {
skipped++;
}
continue;
}
await prisma.fileStorage.create({
data: {
name: fileName,
realName: fileName,
path: "image",
mimeType,
category: "image",
link: `/api/img/${fileName}`,
isActive: true,
},
});
console.log(` ✓ Seeded: ${fileName}`);
seeded++;
} catch (err) {
console.log(`❌ Failed to seed asset ${img.name}:`, JSON.stringify(err));
console.error(` ✗ Error: ${fileName}`, err);
}
}
console.log("🎉 Image seeding completed");
console.log(`\n🎉 Asset seeding selesai — seeded: ${seeded}, updated: ${updated}, skipped: ${skipped}`);
}
if (import.meta.main) {
seedAssets()
.then(() => {
console.log("seed assets success");
})
.then(() => prisma.$disconnect())
.catch((err) => {
console.log("gagal seed assets", JSON.stringify(err));
console.error("gagal seed assets", err);
prisma.$disconnect();
process.exit(1);
});
}

View File

@@ -1,41 +1,28 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
import fs from "fs/promises";
import path from "path";
import { nanoid } from "nanoid";
import sharp from "sharp";
import zlib from "zlib";
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
import minio, { MINIO_BUCKET } from "@/lib/minio";
const fileStorageCreate = async (context: Context) => {
const body = (await context.body) as {
name: string;
file: File;
};
const body = (await context.body) as { name: string; file: File };
const file = body.file;
const name = body.name;
if (!file) return { status: 400, body: "No file uploaded" };
if (!name) return { status: 400, body: "No name provided" };
if (!UPLOAD_DIR) return { status: 500, body: "UPLOAD_DIR is not defined" };
const isImage = file.type.startsWith("image/");
const isAudio = file.type.startsWith("audio/");
const category = isImage ? "image" : isAudio ? "audio" : "document";
const prefix = category === "image" ? "image" : category === "audio" ? "audio" : "documents";
const pathName = category === "image" ? "images" : category === "audio" ? "audio" : "documents";
const rootPath = path.join(UPLOAD_DIR, pathName);
await fs.mkdir(rootPath, { recursive: true });
// Convert File ke Buffer
const buffer = Buffer.from(await file.arrayBuffer());
let finalName = nanoid();
let finalMimeType = file.type;
if (isImage) {
// Simpan sebagai WebP untuk kompresi maksimal
const mobileBuffer = await sharp(buffer)
.resize({ width: 720 })
.webp({ quality: 80 })
@@ -49,40 +36,29 @@ const fileStorageCreate = async (context: Context) => {
const mobileName = `${finalName}-mobile.webp`;
const desktopName = `${finalName}-desktop.webp`;
await fs.writeFile(path.join(rootPath, mobileName), mobileBuffer);
await fs.writeFile(path.join(rootPath, desktopName), desktopBuffer);
await minio.putObject(MINIO_BUCKET, `${prefix}/${mobileName}`, mobileBuffer, mobileBuffer.length, { "Content-Type": "image/webp" });
await minio.putObject(MINIO_BUCKET, `${prefix}/${desktopName}`, desktopBuffer, desktopBuffer.length, { "Content-Type": "image/webp" });
// Simpan metadata untuk versi desktop sebagai default
finalName = desktopName;
finalMimeType = "image/webp";
} else if (isAudio) {
// Simpan file audio tanpa kompresi
const ext = file.name.split(".").pop() || "mp3";
finalName = `${finalName}.${ext}`;
await fs.writeFile(path.join(rootPath, finalName), buffer);
await minio.putObject(MINIO_BUCKET, `${prefix}/${finalName}`, buffer, buffer.length, { "Content-Type": file.type });
} else {
// Jika file adalah PDF, simpan tanpa kompresi
if (file.type === "application/pdf") {
await fs.writeFile(path.join(rootPath, finalName), buffer);
}
// Jika file lain, kompres dengan gzip
else {
const gzBuffer = zlib.gzipSync(buffer);
const compressedName = `${finalName}.gz`;
await fs.writeFile(path.join(rootPath, compressedName), gzBuffer);
finalName = compressedName;
finalMimeType = "application/gzip";
}
const ext = file.name.split(".").pop() || "bin";
finalName = `${finalName}.${ext}`;
await minio.putObject(MINIO_BUCKET, `${prefix}/${finalName}`, buffer, buffer.length, { "Content-Type": file.type });
}
const data = await prisma.fileStorage.create({
data: {
name: finalName,
realName: file.name,
path: pathName, // Store relative path (e.g., "images", "audio", "documents")
path: prefix,
mimeType: finalMimeType,
category,
link: `/api/fileStorage/findUnique/${finalName}`,
link: isImage ? `/api/img/${finalName}` : `/api/fileStorage/findUnique/${finalName}`,
},
});

View File

@@ -1,60 +1,26 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
import fs from "fs/promises";
import path from "path";
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
import minio, { MINIO_BUCKET } from "@/lib/minio";
const fileStorageDelete = async (context: Context) => {
const { params } = context;
const id = (context.params as { id: string })?.id;
const id = params?.id as string;
if (!id) return { status: 400, body: "ID file tidak ditemukan" };
if (!id) {
return {
status: 400,
body: "ID file tidak ditemukan",
};
}
const file = await prisma.fileStorage.findUnique({ where: { id } });
if (!UPLOAD_DIR) {
return {
status: 500,
body: "UPLOAD_DIR belum dikonfigurasi",
};
}
// Cek file dari database
const file = await prisma.fileStorage.findUnique({
where: { id },
});
if (!file) {
return {
status: 404,
body: "File tidak ditemukan di database",
};
}
const filePath = path.join(UPLOAD_DIR, file.path, file.name);
if (!file) return { status: 404, body: "File tidak ditemukan di database" };
try {
// Hapus file dari filesystem
await fs.unlink(filePath);
await minio.removeObject(MINIO_BUCKET, `${file.path}/${file.name}`);
} catch (err) {
console.error("Gagal hapus file:", err);
// Tetap lanjutkan hapus dari database meskipun file fisik tidak ditemukan
console.error("Gagal hapus file dari MinIO:", err);
// Tetap lanjutkan hapus dari database
}
// Hapus dari database
await prisma.fileStorage.delete({
where: { id },
});
await prisma.fileStorage.delete({ where: { id } });
return {
message: "File berhasil dihapus",
deletedId: id,
};
return { message: "File berhasil dihapus", deletedId: id };
};
export default fileStorageDelete;

View File

@@ -1,44 +1,36 @@
import prisma from "@/lib/prisma";
import { Context } from "elysia";
import fs from "fs/promises";
import path from "path";
const UPLOAD_DIR = process.env.WIBU_UPLOAD_DIR;
import minio, { MINIO_BUCKET } from "@/lib/minio";
const fileStorageFindUnique = async (context: Context) => {
const { name } = context.params;
const data = await prisma.fileStorage.findUnique({
where: {
name,
},
});
const data = await prisma.fileStorage.findUnique({ where: { name } });
if (!data) {
context.set.status = "No Content";
return {
status: 404,
message: "File not found",
};
context.set.status = "Not Found";
return { status: 404, message: "File not found" };
}
if (!UPLOAD_DIR) {
context.set.status = "Internal Server Error";
return {
status: 500,
message: "UPLOAD_DIR is not defined",
try {
const stream = await minio.getObject(MINIO_BUCKET, `${data.path}/${data.name}`);
const chunks: Buffer[] = [];
for await (const chunk of stream) {
chunks.push(Buffer.from(chunk));
}
const file = Buffer.concat(chunks);
context.set.headers = {
"Content-Type": data.mimeType,
"Content-Length": String(file.length),
"Cache-Control": "public, max-age=3600, stale-while-revalidate=600",
};
return file;
} catch {
context.set.status = "Not Found";
return { status: 404, message: "File not found in storage" };
}
console.log(data);
const file = await fs.readFile(path.join(UPLOAD_DIR, data.path, data.name));
context.set.headers = {
"Content-Type": data.mimeType,
"Content-Length": file.length,
};
return file;
};
export default fileStorageFindUnique;