Fijxu/patchy
3
19
Fork
You've already forked patchy
6

Use patchy as a image host service #15

Open
opened 2025年11月06日 09:10:24 +01:00 by zw963 · 6 comments
Contributor
Copy link

Hi, I want to use patchy as a image host service for my website.

Currently, I use a free image host, like freeimage.host, I can upload image use HTTP API as
describe in this link, it's works! but, because freeimage.host have a really bad AI image detection, which mistakes pictures of puppies for adult content, there are several free candidate, e.g. Imgur, ImgBB, but both of them invisible in the China homeland.

So, I have to consider use a individual image service for image host service only.

  1. paste in the browser
  2. upload a image into somewhere use this service.
  3. generate a link for show in a <img ... > tag

I test patchy from the command line, it's works!

image

But, some suggestions:

  1. When I upload same one image once again, it generate a new id and url instead, but I prefer not upload exists image and return old url directly instead, cloud services usually do like this to save space.

  2. deploy patchy failed if only copy patchy binary to somewhere, because no locales/en.json file exists.

2025年11月06日T04:55:38.479261Z NOTICE - Config: Config file 'config/config.yml' was not found, using the default uploader configuration
2025年11月06日T04:55:38.479262Z NOTICE - Config, Note: You can ignore this error safely if you use environment variables to configure the uploader!
Unhandled exception: Error opening file with mode 'r': 'locales/en.json': No such file or directory (File::NotFoundError)
 from /home/zw963/Crystal/share/crystal/src/crystal/system/unix/file.cr:13:7 in 'open'
 from /home/zw963/Crystal/share/crystal/src/file.cr:176:20 in 'new_internal'
 from /home/zw963/Crystal/share/crystal/src/file.cr:536:12 in 'read'
 from /home/zw963/Crystal/git/patchy/src/helpers/i18n.cr:15:21 in 'load_all_locales'
 from /home/zw963/Crystal/git/patchy/src/helpers/i18n.cr:9:11 in '__crystal_main'
 from /home/zw963/Crystal/share/crystal/src/crystal/main.cr:129:5 in 'main'
 from /home/zw963/Crystal/share/crystal/src/crystal/system/unix/main.cr:10:3 in 'main'
 from /usr/lib/libc.so.6 in '??'
 from /usr/lib/libc.so.6 in '__libc_start_main'
 from ./patchy in '_start'
 from ???

I consider you can use baked_file_system to add this config file into binary, or more simple but naive solution, compile files in locales into binary when compile-time, then mount it directly when running it use baked_file_system_mounter (because I consider files in locales folder rarely changes)

I will try to update my website use patchy instead, and update suggestion here if I found it useful.

Thanks

Hi, I want to use patchy as a image host service for my website. Currently, I use a free image host, like [freeimage.host](https://freeimage.host/api), I can upload image use HTTP API as describe in this link, it's works! but, because freeimage.host have a really bad AI image detection, which mistakes pictures of puppies for adult content, there are several free candidate, e.g. Imgur, ImgBB, but both of them invisible in the China homeland. So, I have to consider use a individual image service for image host service only. 1. paste in the browser 2. upload a image into somewhere use this service. 3. generate a link for show in a <img ... > tag I test patchy from the command line, it's works! ![image](/attachments/b6ba20f2-0e12-4a85-812f-bfcafde637ee) But, some suggestions: 1. When I upload same one image once again, it generate a new id and url instead, but I prefer not upload exists image and return old url directly instead, cloud services usually do like this to save space. 2. deploy patchy failed if only copy `patchy` binary to somewhere, because no `locales/en.json` file exists. ``` 2025年11月06日T04:55:38.479261Z NOTICE - Config: Config file 'config/config.yml' was not found, using the default uploader configuration 2025年11月06日T04:55:38.479262Z NOTICE - Config, Note: You can ignore this error safely if you use environment variables to configure the uploader! Unhandled exception: Error opening file with mode 'r': 'locales/en.json': No such file or directory (File::NotFoundError) from /home/zw963/Crystal/share/crystal/src/crystal/system/unix/file.cr:13:7 in 'open' from /home/zw963/Crystal/share/crystal/src/file.cr:176:20 in 'new_internal' from /home/zw963/Crystal/share/crystal/src/file.cr:536:12 in 'read' from /home/zw963/Crystal/git/patchy/src/helpers/i18n.cr:15:21 in 'load_all_locales' from /home/zw963/Crystal/git/patchy/src/helpers/i18n.cr:9:11 in '__crystal_main' from /home/zw963/Crystal/share/crystal/src/crystal/main.cr:129:5 in 'main' from /home/zw963/Crystal/share/crystal/src/crystal/system/unix/main.cr:10:3 in 'main' from /usr/lib/libc.so.6 in '??' from /usr/lib/libc.so.6 in '__libc_start_main' from ./patchy in '_start' from ??? ``` I consider you can use [baked_file_system](https://github.com/schovi/baked_file_system) to add this config file into binary, or more simple but naive solution, compile files in `locales` into binary when compile-time, then mount it directly when running it use [baked_file_system_mounter](https://github.com/crystal-china/baked_file_system_mounter) (because I consider files in locales folder rarely changes) I will try to update my website use patchy instead, and update suggestion here if I found it useful. Thanks
220 KiB
Owner
Copy link
  1. When I upload same one image once again, it generate a new id and url instead, but I prefer not upload exists image and return old url directly instead, cloud services usually do like this to save space.

I actually thought about that when I implemented checksumming, but let's say for example, if user 1 uploads file a, and then user 2 uploads a, it would count as a re-upload of the same file where the upload date and deletion time would be affected. Someone could just keep uploading the same file over and over before it gets deleted from the server (if it's configured to be temporary by setting a deletion time) and get a permanent ID.

I have no problem in adding deduplication for files so I'll add it when I can.

  1. deploy patchy failed if only copy patchy binary to somewhere, because no locales/en.json file exists.

Right, I'll try to add the locales too, I'm not sure if its going to work but it should work ;)


If you have any other suggestions, feel free to tell me those. I'm always happy to help ;)

>1. When I upload same one image once again, it generate a new id and url instead, but I prefer not upload exists image and return old url directly instead, cloud services usually do like this to save space. I actually thought about that when I implemented checksumming, but let's say for example, if user 1 uploads file `a`, and then user 2 uploads `a`, it would count as a re-upload of the same file where the upload date and deletion time would be affected. Someone could just keep uploading the same file over and over before it gets deleted from the server (if it's configured to be temporary by setting a deletion time) and get a permanent ID. I have no problem in adding deduplication for files so I'll add it when I can. >2. deploy patchy failed if only copy patchy binary to somewhere, because no locales/en.json file exists. Right, I'll try to add the locales too, I'm not sure if its going to work but it should work ;) --- If you have any other suggestions, feel free to tell me those. I'm always happy to help ;)
Owner
Copy link

if user 1 uploads file a, and then user 2 uploads a, it would count as a re-upload of the same file where the upload date and deletion time would be affected.

Oh and user 2 would be able to delete the file that use 1 uploader since it will return its delete key as response. That can be solved by not returning the delete key if the file is uploaded again, but is not possible to know if the user uploading file a is going to be the same person or a different one. So not really worth the effort.

What can be made is just adding a new file entry to the database but pointing to the same file. Each duplicated upload will have its own ID but they all share the same file in the filesystem, and if the file gets deleted, what is going to be deleted is the file entry in the database and not the file itself since it will be used by other file entry.

That seems to be the best solution

>if user 1 uploads file a, and then user 2 uploads a, it would count as a re-upload of the same file where the upload date and deletion time would be affected. Oh and user 2 would be able to delete the file that use 1 uploader since it will return its delete key as response. That can be solved by not returning the delete key if the file is uploaded again, but is not possible to know if the user uploading file `a` is going to be the same person or a different one. So not really worth the effort. What can be made is just adding a new file entry to the database but pointing to the same file. Each duplicated upload will have its own ID but they all share the same file in the filesystem, and if the file gets deleted, what is going to be deleted is the file entry in the database and not the file itself since it will be used by other file entry. That seems to be the best solution
Author
Contributor
Copy link

Oops, thanks for explain, I never consider use cases like update date and delete uploaded file, maybe need re-consider the tradeoff if face those many complicated situations.

Oops, thanks for explain, I never consider use cases like `update date` and `delete uploaded file`, maybe need re-consider the tradeoff if face those many complicated situations.
Author
Contributor
Copy link

One more suggestion, I meet file permissions issue on production, which make upload failed, silently, without any meanful warning, expect 403, with Failed to process upload.

So, I have to comment following line out, to check where the problem come from

https://codeberg.org/Fijxu/patchy/src/branch/master/src/routes/public/upload.cr#L67-L68

Then, I get useful log like following:

Nov 06 20:59:57 stuent111 patchy[1467731]: 2025年11月06日 20:59:56 +08:00 ERROR kemal: Error opening file with mode 'wb': './data/files/rQCfs.png': Permission denied
Nov 06 20:59:57 stuent111 patchy[1467731]: 2025年11月06日 20:59:57 +08:00 INFO kemal: 500 POST /-/upload 1618.24ms

So, I consider we don't add rescue here, because kemal do that for us, patchy server not broken, instead, just return 500 with useful error log.

Thanks

One more suggestion, I meet file permissions issue on production, which make upload failed, silently, without any meanful warning, expect 403, with `Failed to process upload`. So, I have to comment following line out, to check where the problem come from https://codeberg.org/Fijxu/patchy/src/branch/master/src/routes/public/upload.cr#L67-L68 Then, I get useful log like following: ``` Nov 06 20:59:57 stuent111 patchy[1467731]: 2025年11月06日 20:59:56 +08:00 ERROR kemal: Error opening file with mode 'wb': './data/files/rQCfs.png': Permission denied Nov 06 20:59:57 stuent111 patchy[1467731]: 2025年11月06日 20:59:57 +08:00 INFO kemal: 500 POST /-/upload 1618.24ms ``` So, I consider we don't add rescue here, because kemal do that for us, patchy server not broken, instead, just return 500 with useful error log. Thanks
Author
Contributor
Copy link

Hi, one more suggestion:

When upload successful, the return json like following:

"link":"http://127.0.0.1:8080/ERg23",
"linkExt":"http://127.0.0.1:8080/ERg23.jpg",
"directLink":"http://127.0.0.1:8080/-/file/ERg23", 
"thumbnail_link":"http://127.0.0.1:8080/-/thumbnail/",
...

I added a nginx config like following to serve image directly from my website.

 server {
 server_name upload.crystal-china.org;
 root /home/crystal_china/apps/patchy/data;
 # ...
}

So, when visit the image use directLink directly,

https://upload.crystal-china.org/files/HiQBN,

Above will get a 404 error, but if with full ext name,

https://upload.crystal-china.org/files/HiQBN.png

It is works!

So, following is the suggestion:

  1. Can we add the ext name to directLink?
  2. Can we replace -/file to /files here to match the folder struct?
    more in-depth,a nested folder struct is better than place all files in same folder. e.g. 127.0.0.1:8080/files/2025/11/HiQBN.png, to group images into month.

Thanks

Hi, one more suggestion: When upload successful, the return json like following: ``` "link":"http://127.0.0.1:8080/ERg23", "linkExt":"http://127.0.0.1:8080/ERg23.jpg", "directLink":"http://127.0.0.1:8080/-/file/ERg23", "thumbnail_link":"http://127.0.0.1:8080/-/thumbnail/", ... ``` I added a nginx config like following to serve image directly from my website. ``` server { server_name upload.crystal-china.org; root /home/crystal_china/apps/patchy/data; # ... } ``` So, when visit the image use directLink directly, https://upload.crystal-china.org/files/HiQBN, Above will get a 404 error, but if with full ext name, https://upload.crystal-china.org/files/HiQBN.png It is works! So, following is the suggestion: 1. Can we add the ext name to directLink? 2. Can we replace `-/file` to `/files` here to match the folder struct? more in-depth,a nested folder struct is better than place all files in same folder. e.g. `127.0.0.1:8080/files/2025/11/HiQBN.png`, to group images into month. Thanks
Author
Contributor
Copy link

Use patchy as a image host service works now (for current patchy version), if anyone interest in, can check following code.

github.com/crystal-china/website@35e8eb1b75/src/actions/api/upload.cr

This is the nginx settings, use patchy is far far fast than use a external service.

Use patchy as a image host service works now (for current patchy version), if anyone interest in, can check following code. https://github.com/crystal-china/website/blob/35e8eb1b75ab9928fafebe430e2b5b93afafe9a8/src/actions/api/upload.cr This is the [nginx](https://github.com/crystal-china/website/blob/10ab38d6a5bf0153003b5685f5c49d0f8d66b91c/nginx/conf.d/crystal-china.org.conf#L48-L56) settings, use patchy is far far fast than use a external service.
Sign in to join this conversation.
No Branch/Tag specified
master
url-upload
exif
0.9.9
0.9.8
0.9.7
0.9.5
0.9.3
0.9.2
0.9.0
0.8.9
0.8.8
0.8.7
0.8.6
0.8.2
0.8.1
Milestone
Clear milestone
No items
No milestone
Projects
Clear projects
No items
No project
Assignees
Clear assignees
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
Fijxu/patchy#15
Reference in a new issue
Fijxu/patchy
No description provided.
Delete branch "%!s()"

Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?