diff --git a/README.md b/README.md index 806810a..91290e8 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,13 @@ # ShareX_Storage Simple tool to act as endpoint to upload files through ShareX to. + +## Requirements +* [PyYAML](https://pypi.org/project/PyYAML/) +* [pycryptodomex](https://pypi.org/project/pycryptodomex/) +* [aiohttp](https://pypi.org/project/aiohttp/) + ++ [thumbnail](https://pypi.org/project/thumbnail/) (optional) ++ [unoconv](https://github.com/unoconv/unoconv) (optional) ++ [ffmpeg](https://www.ffmpeg.org/) (optional) ++ [imagemagick](https://imagemagick.org/index.php) (optional) ++ [curl](https://curl.se/) (optional) diff --git a/config.yaml b/config.yaml index 19d02bb..bbcf0aa 100644 --- a/config.yaml +++ b/config.yaml @@ -27,3 +27,18 @@ base_url: 'https://your-domain.net/f/' # Should file extensions be appended to the generated links. # Links always work with or without file extensions (like puush.me). show_ext: True + +# Should a frontend to view and manage uploads be exposed? +frontend: True + +# Should thumbnails of uploaded files be created for frontend viewing. +thumbnails: True + +# Directory for storing thumbnails +thumbnail_path: 'data/thumbs' + +# Strategy for creating thumbnails. Possible values are: +# on-upload: Creates a thumbnail when uploading a file. +# on-request: Creates a thumbnail when requested by the frontend. +# both: Creates a thumbnail on request if one hasn't been created on upload. +thumbnail_strategy: 'both' diff --git a/requirements.txt b/requirements.txt index 3c5f52e..49957da 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,4 @@ PyYAML pycryptodomex -aiohttp \ No newline at end of file +aiohttp +thumbnail diff --git a/sharex_server.py b/sharex_server.py index e806a53..175543d 100644 --- a/sharex_server.py +++ b/sharex_server.py @@ -10,6 +10,16 @@ from Cryptodome.Cipher import AES from Cryptodome.Util import Padding from aiohttp import web, hdrs +from thumbnail import generate_thumbnail + +ThumbnailOptions = { + 'trim': False, + 'height': 300, + 'width': 300, + 'quality': 85, + 'type': 'thumbnail' +} + class AppConfig: _instance = None @@ -36,6 +46,10 @@ class AppConfig: self.show_ext = data.get('show_ext', True) self.max_filesize = data.get('max_filesize', '1024 ** 2 * 100') # Default 100 MB self.base_url = data.get('base_url', 'http://localhost/f/') + self.frontend = data.get('frontend', False) + self.thumbnails = data.get('thumbnails', False) + self.thumbnail_path = data.get('thumbnail_path', '/data/thumbs') + self.thumbnail_strategy = data.get('thumbnail_strategy', 'both') self.validate_config() @@ -52,6 +66,9 @@ class AppConfig: if not os.path.isdir(self.data_path): os.mkdir(self.data_path) + if not os.path.isdir(self.thumbnail_path): + os.mkdir(self.thumbnail_path) + self.base_url = f"{self.base_url.strip("/ \t\r\n")}" @staticmethod @@ -100,7 +117,7 @@ async def handle_upload(req): os.mkdir(f'{conf.data_path}') for _ in range(100): - hb = os.urandom(conf.url_hash_len//2) + hb = os.urandom(conf.url_hash_len // 2) h = hb.hex() if h not in file_db: break @@ -119,7 +136,11 @@ async def handle_upload(req): c = AES.new(conf.del_crypt_key, AES.MODE_CBC) hb = Padding.pad(hb, AES.block_size) del_h = (c.encrypt(hb) + c.iv).hex() + local_thname = f'{conf.thumbnail_path}/{h}_{filename}.png' + generate_thumbnail(local_fname, local_thname, ThumbnailOptions) + return web.Response(text=f'{{"file_link":"{conf.base_url}/{h}{ext}",' + f'"thumb_link":"{conf.base_url}/thumb/{h}{ext}",' f'"delete_link":"{conf.base_url}/del/{del_h}"}}', status=200) os.unlink(local_fname) @@ -169,6 +190,18 @@ async def handle_download(req): }) +async def handle_thumbnail(req): + fhash = req.match_info.get('hash', '').split('.', 1)[0] + if fhash not in file_db: + return web.Response(text='file not found', status=404) + + ## TODO: If thumbnail doesn't exist, generate new thumbnail + + return web.FileResponse(f"{conf.thumbnail_path}/{fhash}_{file_db[fhash]}", headers={ + hdrs.CONTENT_DISPOSITION: f'inline;filename="{file_db[fhash]}"' + }) + + def main(): for file in os.listdir(f"{conf.data_path}"): try: @@ -185,6 +218,7 @@ def main(): app.router.add_post(base_path + '/post', handle_upload) app.router.add_get(base_path + '/del/{hash}', handle_delete) app.router.add_get(base_path + '/{hash}', handle_download) + app.router.add_get(base_path + '/thumb/{hash}', handle_thumbnail) web.run_app(app, port=80)