diff --git a/landing.html b/landing.html new file mode 100644 index 0000000..2a0256f --- /dev/null +++ b/landing.html @@ -0,0 +1,49 @@ + + +
+ + ++{name} File Upload and URL Shortener + +Welcome to the {name} file upload and URL shortening service. +This service allows you to easily upload files or shorten URLs for quick access. +Files are stored for {expiration_days} days, and URLs are shortened for convenient sharing. + +Usage: + +Upload a file: +curl -F file=@yourfile.ext {base_url}/ + +Shorten a URL: +curl -d "url=https://example.com" {base_url}/shorten + +Details: + +Files uploaded to this service are stored for {expiration_days} days or until they are automatically cleaned up. +The maximum file size is {max_file_size}MB. +URLs shortened with this service will redirect to the original URL for the same period. + +Examples: + +File upload: +curl -F file=@document.pdf {base_url}/ +Response: +{base_url}/abcdef + +URL shortening: +curl -d "url=https://example.com" {base_url}/shorten +Response: +{base_url}/ghijkl + +Disclaimer: + +This service is provided as-is with no guarantees. +Uploaded files and shortened URLs are not private and can be accessed by anyone with the link. +Use at your own risk. ++ + diff --git a/main.py b/main.py index 271ecc6..fd4a48f 100755 --- a/main.py +++ b/main.py @@ -1,67 +1,73 @@ -import os -import uuid -import time -import json -import threading -from flask import Flask, request, redirect, send_from_directory, abort +import os, uuid, time, json, sqlite3, threading +from flask import Flask, request, redirect, send_from_directory, abort, render_template_string app = Flask(__name__) -# config -UPLOAD_FOLDER = './uploads' -MAX_FILE_SIZE = 1024 * 1024 * 100 # last number = megabytes -EXPIRATION_TIME = 60 * 60 * 24 * 7 # last number = days -DATA_FILE = 'data.json' -URL_PREFIX = 'http://localhost:5000/' +with open('config.json') as f: + config = json.load(f) -if not os.path.exists(UPLOAD_FOLDER): - os.makedirs(UPLOAD_FOLDER) +UPLOAD_FOLDER = config['upload_folder'] +MAX_FILE_SIZE = config['max_file_size'] +EXPIRATION_TIME = config['expiration_time'] +DATA_FILE = config['data_file'] +URL_PREFIX = config['base_url'] +NAME = config['name'] + +os.makedirs(UPLOAD_FOLDER, exist_ok=True) + +def init_db(): + with sqlite3.connect(DATA_FILE) as conn: + conn.execute('CREATE TABLE IF NOT EXISTS files (key TEXT PRIMARY KEY, type TEXT NOT NULL, path TEXT, url TEXT, expiry REAL)') + +init_db() def load_data(): - if os.path.exists(DATA_FILE): - with open(DATA_FILE, 'r') as f: - return json.load(f) - return {} + with sqlite3.connect(DATA_FILE) as conn: + return {row[0]: {'type': row[1], 'path': row[2], 'url': row[3], 'expiry': row[4]} for row in conn.execute('SELECT * FROM files')} + +def save_data(): + with sqlite3.connect(DATA_FILE) as conn: + conn.execute('DELETE FROM files') + conn.executemany('INSERT INTO files VALUES (?, ?, ?, ?, ?)', + [(k, v['type'], v.get('path'), v.get('url'), v['expiry']) for k, v in data.items()]) data = load_data() -def save_data(): - with open(DATA_FILE, 'w') as f: - json.dump(data, f) - def cleanup_files(): while True: - time.sleep(60 * 60) + time.sleep(3600) now = time.time() - for key, item in list(data.items()): - if 'expiry' in item and now > item['expiry']: - try: - os.remove(item['path']) - except Exception as e: - print(f"Error removing file {item['path']}: {e}") - del data[key] + expired_keys = [k for k, v in data.items() if v['expiry'] < now] + for k in expired_keys: + if data[k]['type'] == 'file': + os.remove(data[k]['path']) + data.pop(k) save_data() threading.Thread(target=cleanup_files, daemon=True).start() +@app.route('/', methods=['GET']) +def landing_page(): + with open('landing.html') as f: + html = f.read().format( + name=NAME, + base_url=URL_PREFIX.rstrip('/'), + expiration_days=EXPIRATION_TIME // 86400, + max_file_size=MAX_FILE_SIZE // 1048576 + ) + return render_template_string(html) + @app.route('/', methods=['POST']) def upload_file(): file = request.files.get('file') - if not file: - return "No file uploaded\n", 400 - if file.content_length > MAX_FILE_SIZE: - return "File too large\n", 400 + if not file or file.content_length > MAX_FILE_SIZE: + return "No file uploaded or file too large\n", 400 - filename = file.filename key = uuid.uuid4().hex[:6] - filepath = os.path.join(UPLOAD_FOLDER, f"{key}_{filename}") + filepath = os.path.join(UPLOAD_FOLDER, f"{key}_{file.filename}") file.save(filepath) - data[key] = { - 'type': 'file', - 'path': filepath, - 'expiry': time.time() + EXPIRATION_TIME - } + data[key] = {'type': 'file', 'path': filepath, 'expiry': time.time() + EXPIRATION_TIME} save_data() return f"{URL_PREFIX}{key}\n" @@ -72,11 +78,7 @@ def shorten_url(): return "No URL provided\n", 400 key = uuid.uuid4().hex[:6] - data[key] = { - 'type': 'url', - 'url': url, - 'expiry': time.time() + EXPIRATION_TIME - } + data[key] = {'type': 'url', 'url': url, 'expiry': time.time() + EXPIRATION_TIME} save_data() return f"{URL_PREFIX}{key}\n" @@ -88,10 +90,9 @@ def get_content(key): if item['type'] == 'file': return send_from_directory(UPLOAD_FOLDER, os.path.basename(item['path'])) - elif item['type'] == 'url': + if item['type'] == 'url': return redirect(item['url']) - else: - abort(404) + abort(404) if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)