diff --git a/.directory b/.directory new file mode 100644 index 0000000..97463f8 --- /dev/null +++ b/.directory @@ -0,0 +1,7 @@ +[Dolphin] +Timestamp=2024,10,21,18,10,45.565 +Version=4 +ViewMode=1 + +[Settings] +HiddenFilesShown=true diff --git a/2024-10-21T17:19:57,186481017+08:00.png b/2024-10-21T17:19:57,186481017+08:00.png new file mode 100644 index 0000000..225dd27 Binary files /dev/null and b/2024-10-21T17:19:57,186481017+08:00.png differ diff --git a/app.py b/app.py new file mode 100644 index 0000000..cd663d0 --- /dev/null +++ b/app.py @@ -0,0 +1,103 @@ +from flask import Flask, render_template, request, redirect, url_for, send_from_directory, session +from flask_socketio import SocketIO, emit +import os +from werkzeug.security import generate_password_hash, check_password_hash +from PIL import Image +from watchdog.observers import Observer +from watchdog.events import FileSystemEventHandler + +app = Flask(__name__) +app.config['SECRET_KEY'] = 'your_secret_key' # Replace with a strong secret key +socketio = SocketIO(app) + +app.config['UPLOAD_FOLDER'] = 'images' # Folder to store images +app.config['CACHE_FOLDER'] = 'cache' # Folder to store cached resized images +app.config['ALLOWED_EXTENSIONS'] = {'png', 'jpg', 'jpeg', 'gif'} + +# Fixed username and password +USERNAME = 'user' +PASSWORD = generate_password_hash('password') # Hashed password + +def allowed_file(filename): + return '.' in filename and \ + filename.rsplit('.', 1)[1].lower() in app.config['ALLOWED_EXTENSIONS'] + +def resize_image(image_path, cache_path, size=(800, 450)): + with Image.open(image_path) as img: + img.thumbnail(size) + img.save(cache_path) + +@app.route('/') +def index(): + return redirect(url_for('login')) + +@app.route('/login', methods=['GET', 'POST']) +def login(): + if request.method == 'POST': + username = request.form['username'] + password = request.form['password'] + if username == USERNAME and check_password_hash(PASSWORD, password): + session['logged_in'] = True + return redirect(url_for('gallery')) + else: + error = 'Invalid credentials' + return render_template('login.html', error=error) + return render_template('login.html') + +@app.route('/logout') +def logout(): + session.pop('logged_in', None) + return redirect(url_for('login')) + +@app.route('/gallery') +def gallery(): + if not session.get('logged_in'): + return redirect(url_for('login')) + + images = os.listdir(app.config['UPLOAD_FOLDER']) + cached_images = [] + + if not os.path.exists(app.config['CACHE_FOLDER']): + os.makedirs(app.config['CACHE_FOLDER']) + + for image in images: + image_path = os.path.join(app.config['UPLOAD_FOLDER'], image) + cache_path = os.path.join(app.config['CACHE_FOLDER'], image) + + if not os.path.exists(cache_path): + resize_image(image_path, cache_path) + + cached_images.append(image) + + return render_template('gallery.html', images=cached_images) + +@app.route('/images/') +def uploaded_file(filename): + return send_from_directory(app.config['CACHE_FOLDER'], filename) + +def emit_gallery_update(): + socketio.emit('update_gallery') + +class Watcher(FileSystemEventHandler): + def on_modified(self, event): + if not event.is_directory: + emit_gallery_update() + + def on_created(self, event): + if not event.is_directory: + emit_gallery_update() + + def on_deleted(self, event): + if not event.is_directory: + emit_gallery_update() + +if __name__ == '__main__': + observer = Observer() + observer.schedule(Watcher(), path=app.config['UPLOAD_FOLDER'], recursive=False) + observer.start() + try: + context = ('cert.pem', 'key.pem') # Replace with your self-signed certificate and key files + socketio.run(app, debug=True, ssl_context=context) + except KeyboardInterrupt: + observer.stop() + observer.join() \ No newline at end of file diff --git a/cache/101260155_p0.png b/cache/101260155_p0.png new file mode 100644 index 0000000..85fae69 Binary files /dev/null and b/cache/101260155_p0.png differ diff --git a/cache/1b3aa1b096a23fec1def6fc275b1f4b4.png b/cache/1b3aa1b096a23fec1def6fc275b1f4b4.png new file mode 100644 index 0000000..95aa162 Binary files /dev/null and b/cache/1b3aa1b096a23fec1def6fc275b1f4b4.png differ diff --git a/cache/97144634_p0.png b/cache/97144634_p0.png new file mode 100644 index 0000000..c029cb4 Binary files /dev/null and b/cache/97144634_p0.png differ diff --git a/cache/nextsec.png b/cache/nextsec.png new file mode 100644 index 0000000..7e17012 Binary files /dev/null and b/cache/nextsec.png differ diff --git a/cache/unnamed.jpg b/cache/unnamed.jpg new file mode 100644 index 0000000..5176e36 Binary files /dev/null and b/cache/unnamed.jpg differ diff --git a/cache/5月壁紙.png b/cache/5月壁紙.png new file mode 100644 index 0000000..a06cb8a Binary files /dev/null and b/cache/5月壁紙.png differ diff --git a/cert.pem b/cert.pem new file mode 100644 index 0000000..2679871 --- /dev/null +++ b/cert.pem @@ -0,0 +1,31 @@ +-----BEGIN CERTIFICATE----- +MIIFazCCA1OgAwIBAgIUb0qNrwGOHXUFLcFfOLwTwVXNv0cwDQYJKoZIhvcNAQEL +BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM +GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNDEwMjEwODI1MDdaFw0yNTEw +MjEwODI1MDdaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw +HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB +AQUAA4ICDwAwggIKAoICAQDO1dlQYMEErxhxJkPh6CQK4cZN0So9BP9d+ga85z0d +5Oooe0Z3KnJF/Eb4EFsMlFOYgXmqt4g5FbAyleYhi/m6yBSCNYidFuVPnuMQrTx5 +vr9/X8ZwiKVEJEqAS7fBN2BCu4qZPKj3R5fPnuvrUcMkdjpNGzXX9KVdNZEVoXfi +yGs25E1ksn+pLZQ+im/1jS9pIh+30Ush3YWFUM+jjZYlPnZjaz2hD/penUpySUUl +Oi90uC30HC1arPxAlS9zY0ja2kPeRKe77Q5WJi1ov0xSg8MYuGFRIc0oqh8EAeL6 +ZYODB46QMpXx90u9pwh/KtuxJ5Ai+A+6KHpGUP4Oihl20UnmuDMZCeonoE6fEH30 +eCol/5n0RUiYLQlJpvizfzN+a8PJhr/+xqcIeiCwfXE0yu1naU++voD1iCsql5pN +qA5AMHSb4Fnhw69UlQflDiMC/Eb5V7be0yRN8SXCakzzVD2WfUvVttrPkM/VucJw +4W7cZKJClefBzRwx3peBtzVFOT/be+8Lkawm4B/ZqJ4kNzhdVAgCK9cT56cA1LSH +cM+xRZWzTJvB140naIkTgdVtWGFqJN7Po0cGU+PjQQNvMIkUKL1EGmFQJAx06zYJ +QYOQ235jDdcEmYa8AhcIU/p0JeCaBv1/YfoInmoENsR2t6C/Uy8ZublfoUaAcTNM +NQIDAQABo1MwUTAdBgNVHQ4EFgQUA0DKfoR9KP3BCmEhahfkPfKBLskwHwYDVR0j +BBgwFoAUA0DKfoR9KP3BCmEhahfkPfKBLskwDwYDVR0TAQH/BAUwAwEB/zANBgkq +hkiG9w0BAQsFAAOCAgEAi0GuzhdF9gXYaUTHtHmHXyYbsjJXECc5ZH5ezJbHYjEz +PzWaMo34O91Ik3lSM8bWVYC7aovpigo81fKxGiRMdaBs6T2IROQDpiN+fR/kr2b+ +ZMYsS2ldd5jr9qnmDEWaPpxVeg4zTAGeMZIiQoHseMQUG9SDXpz/Pt/kYRiXRlp1 +WYV0aryUO6l2JEd92WjM5ULZYvpZgOMR/gWFTZ8U88A3OwbVifi7f+ntLSgA0YB2 +r5z2utlHhJTpdQsNl1yUxT4sX+/Rs0rmQoY6SXKySq+ZpslOfsumYSNIQ4gWA7xg +d3YWv0zu8AUp5Sx+t/zhpnuesd8HzbN1vM5bW5aqPxRl3bFaKRNNUKvmEc+YDPM+ +ZtuvQ8uINRHgedNCMaAruAqs8p3zc9gzuSvAhBIKYcjOT6VLlZwdHeE5KV624Iz8 +chbX5bvAKXbI3NALDvgKJPXiWGNSHMKkQwhXFk9xjrDaxCU/2NCw2W8aPq6PmWvZ +44aV6oNEPIbEJ6PcOOGVMalPDhrh0YgzXKlogDdECwTtAjMt7SiI/+E4OmmsiWw6 +txInD/nm/nDGBJ+jvu+gAN5c5VhpTt1Cib2C3U6+EqNen+wj5klFIoI0Zgf/H/se +7baUlqlSC2iZin2DqkQgIQsfnMscrhQa4pfgckfXn/8TaKSg4BLKw9xxmB/4ulo= +-----END CERTIFICATE----- diff --git a/images/101260155_p0.png b/images/101260155_p0.png new file mode 100644 index 0000000..e0c8e40 Binary files /dev/null and b/images/101260155_p0.png differ diff --git a/images/97144634_p0.png b/images/97144634_p0.png new file mode 100644 index 0000000..f2d2ba7 Binary files /dev/null and b/images/97144634_p0.png differ diff --git a/images/nextsec.png b/images/nextsec.png new file mode 100644 index 0000000..afeb81e Binary files /dev/null and b/images/nextsec.png differ diff --git a/images/unnamed.jpg b/images/unnamed.jpg new file mode 100644 index 0000000..e543a7a Binary files /dev/null and b/images/unnamed.jpg differ diff --git a/images/5月壁紙.png b/images/5月壁紙.png new file mode 100644 index 0000000..8f24194 Binary files /dev/null and b/images/5月壁紙.png differ diff --git a/key.pem b/key.pem new file mode 100644 index 0000000..33348cc --- /dev/null +++ b/key.pem @@ -0,0 +1,52 @@ +-----BEGIN PRIVATE KEY----- +MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQDO1dlQYMEErxhx +JkPh6CQK4cZN0So9BP9d+ga85z0d5Oooe0Z3KnJF/Eb4EFsMlFOYgXmqt4g5FbAy +leYhi/m6yBSCNYidFuVPnuMQrTx5vr9/X8ZwiKVEJEqAS7fBN2BCu4qZPKj3R5fP +nuvrUcMkdjpNGzXX9KVdNZEVoXfiyGs25E1ksn+pLZQ+im/1jS9pIh+30Ush3YWF +UM+jjZYlPnZjaz2hD/penUpySUUlOi90uC30HC1arPxAlS9zY0ja2kPeRKe77Q5W +Ji1ov0xSg8MYuGFRIc0oqh8EAeL6ZYODB46QMpXx90u9pwh/KtuxJ5Ai+A+6KHpG +UP4Oihl20UnmuDMZCeonoE6fEH30eCol/5n0RUiYLQlJpvizfzN+a8PJhr/+xqcI +eiCwfXE0yu1naU++voD1iCsql5pNqA5AMHSb4Fnhw69UlQflDiMC/Eb5V7be0yRN +8SXCakzzVD2WfUvVttrPkM/VucJw4W7cZKJClefBzRwx3peBtzVFOT/be+8Lkawm +4B/ZqJ4kNzhdVAgCK9cT56cA1LSHcM+xRZWzTJvB140naIkTgdVtWGFqJN7Po0cG +U+PjQQNvMIkUKL1EGmFQJAx06zYJQYOQ235jDdcEmYa8AhcIU/p0JeCaBv1/YfoI +nmoENsR2t6C/Uy8ZublfoUaAcTNMNQIDAQABAoICAACNhBnu7z4/Bo4rMBmMZztH +0Y52Efh/iPwwV+vt8ZCTjsOD8hYQV94oSL+9CUQk27DfnSf/aT0x3X/HELnl0d5g +2l3gd6t8sg5l+RwYhAPbNsneOl2NM2JXNbjzTXX81n/121Jl1n7oyamNp6cfhd8a +9yi0JOhyK42N9bfiMSt07sacNLlIMQLFcglN2PZTVKn2cAfPgxHXeqY4QhDhMV9q +ZoxhcJrNhQ3Kah6WEHbeGBO2fJs769XspDBwlISCELVA5JXDkWh51EKaIxy2D/2D +MBIAjAMzZlbTdGjHLPRlzHFFGS95NUb0hxPnvHGqJW63EBG/k99SkutF+JKN2i29 +da295AnXfESgatMEdXU7sCJPCMNE4XkLbMIelyM39Y5Vmw57xMchLjPoyqylKxF3 +EuiV5QghVMgIIL0yfK3bhNEvAuvmpPeZfZOE5H9FdIi16ms1kC2oEgHIk3vnbloP +w6BLX31UJHTij/LiNB7hQPEmviVGoeyMhsogdt5T8kqxML7M2rZFfMzwpyfjyzZY +2PmSP+uW+R7lfHLpAlPVdOLFLFD6t9OqiCABhNBkNnuje6mvRwaEHkI8XUZS+jv5 +SdtGxM866SFsxbE3Tg/JtH3QzA3jhYsRtcqDpiPJRpluDOl3dIZ2u2TJCjTtMxZm +7svKMmhg0p7bcMpv66IBAoIBAQD2vFNTUMsmxlZUBlvblobcHSCMGe0aDHe/YwMN +BOO5t9Lo4xA6nZTWScFE2Qtc37+ZTLranNx3PfXlmo6ycG4tC1c6wwTActAEN7mL +JTykzOSyV4j8hkjtdVQNghWMURKUW1s4xX+xsxbfK8E7KZ8bkhRvtIfWbqcwP+1G +HNzRLeWWC/xx18xHubwcsgs9z6b0ylTA1hXUNOjzbDFhggDkcTKd2P4tWKy04qFU +AHTsU60Bk02FAAjyurmDWteQ4Iqb82yLlG35iZin/lXXyVeQZdJBCnzsKA2Bzhi0 +ocXJ2ABUDzK0nawhbtUDOEl7XCCjiQ99Ep1SM7o/9EDvDNIBAoIBAQDWmf5O7wQw +UoijV2x9S4kQSx/wHrB26D9wt1mk66/Zj3buYmQEtMBIMzzmgYLF4NuOzrE2c8Ne +rqXmSLAg3ByGcKV8gxxCKUf0dGevBC2pBQyPcQlX8lgZCl/7iKpqpAR5EHKwTnxJ +S4GaeUGFMXaEOcdwt7Fm+EG2oYxKaYc3QjPB+DDkr0BJ88N3owWyvY+Ej8SF1R7L +Q4/XC+UexvDPG/oye6iFb+n2jj2OtVydHfi1kamxBnI4SFj9Zy4bjz753b6yTYVp +uWRel/LgcUHo/pAiZ79+XJHKa8qN9RHntpv2kh2l+7Vw91BOMbxqX4dkmra0O4Kv +3tOGZDYxR9I1AoIBAQDLIplniqj2r2v7mZCe5Pr61XAqaF3wiDs+coHcgh4KlPEr +k2WVHI+hLO/Vguv79qqDx8w+l85azcRY2DqLZk0PALs8QbrzxpLEJiy4Blw7QgU3 +XyIE5Xm9Jk+hH2wmLckiI2SjBNbwsgUuj5Ny5f18cXQp03PScx9qdfcfNjwGa8cN +FaktAQHKO3xIE711kjRebQYCDT/DihwP7Q9qu+GIMjn+Atyg8NSfx8YSpp2cw/c3 +yNKVoUW8sUZygqPfPz5ezraa5AT24PWxuY9rLPTOiUXlDoFy3Dbim49zh4yTdSYw +DqMsWHOSwvDUyc6VpW+ps/nwexbSyouYg7vCE8gBAoIBAQCBAyzueSS0hDmesQUI +witRP0ihC2Ic6fyRn7hlvEcIbQYbw8zLQ3rBLQR0svFSUp7L2JiS2r9eIXKc4Z/4 +8Tq42+mw1AVeBQE8Ber7PXDRxrZJWbQ7SfcKfsE7L2r8F0SVH31DXru7OIhevHzW +POk6Dp5GtjgRZjfjOnVjmtNuNf91oeaK5IyqqMAfIUNgtDMeh2um5XvQyPolVwJU +IVdNu00LommqZqBp2BNLwt49mnIVfc9dHDn4eg39sVT3voMmpddpy87jw0+Cyqh5 +o7zy/G7cMDDgH3iKD4lDFEzCV3aloivuyEbI9fUyPRY/gNSdd6FU8t3bKwNRLNej +gsDtAoIBAEgryqBpT13hmWPo+5ODEmtzrLFx+BT9neP170npn6aIhk1Qce7Bn6Pb +8VkbItciWmNsbMhq7TUcuXUZCYyNW+qET+6rVyoKwTtDFkw3DnvFfaUWTuBWYnqH +RMMc9r66VSI6tLP0TLY49UP0cGez5if2LjBzjDO4hjTmI8oKuEF2s0Ej0seOCkz9 +IVD0h8yCjH/Hri1Iaf5tIqUbi9lN3ynjMudcE2/RdWxOqTayo2tAIYrA21blqe2G +VLoY+Z/9uGRmdx8S+RDxUhWEfQXVp0Dh8qWY2BqBtHX2AOiAJLaFxUywne2VTzDM +XSganpYkLqJCS1lgaReUZcgjcBvBkco= +-----END PRIVATE KEY----- diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..fd7575e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +Flask +Werkzeug \ No newline at end of file diff --git a/static/gallery_styles.css b/static/gallery_styles.css new file mode 100644 index 0000000..2a01cbf --- /dev/null +++ b/static/gallery_styles.css @@ -0,0 +1,85 @@ +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #ffeeee 25%, #dce2ff 75%); + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + align-items: center; + min-height: 100vh; +} +h1 { + color: #333; + margin: 20px 0; + font-size: 24px; + text-align: center; +} +.gallery-container { + display: grid; + gap: 10px; + padding: 20px; + width: 100%; + max-width: 1200px; + box-sizing: border-box; +} + +/* Media queries for responsive padding */ +@media (max-width: 1199px) { + .gallery-container { + padding-left: 40px; + padding-right: 40px; + } +} +@media (max-width: 991px) { + .gallery-container { + padding-left: 30px; + padding-right: 30px; + } +} +@media (max-width: 767px) { + .gallery-container { + padding-left: 20px; + padding-right: 20px; + } +} + +.responsive-img { + width: 100%; + height: auto; + border: 2px solid #ddd; + border-radius: 5px; + box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); + transition: transform 0.2s; + aspect-ratio: 16 / 9; + object-fit: cover; + opacity: 0; + transition: opacity 0.5s ease-in-out, transform 0.2s; +} +.responsive-img.loaded { + opacity: 1; +} +.responsive-img:hover { + transform: scale(1.05); +} + +/* Media queries for responsive columns */ +@media (min-width: 1200px) { + .gallery-container { + grid-template-columns: repeat(4, 1fr); + } +} +@media (min-width: 992px) and (max-width: 1199px) { + .gallery-container { + grid-template-columns: repeat(3, 1fr); + } +} +@media (min-width: 768px) and (max-width: 991px) { + .gallery-container { + grid-template-columns: repeat(2, 1fr); + } +} +@media (max-width: 767px) { + .gallery-container { + grid-template-columns: 1fr; + } +} \ No newline at end of file diff --git a/static/login_styles.css b/static/login_styles.css new file mode 100644 index 0000000..6ada16e --- /dev/null +++ b/static/login_styles.css @@ -0,0 +1,62 @@ +body { + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + height: 100vh; +} +form h1 { + color: #333; + margin-bottom: 20px; + font-size: 24px; + text-align: center; +} +form { + background-color: #fff; + padding: 30px; + border-radius: 10px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + width: 350px; + display: flex; + flex-direction: column; + align-items: center; +} +form div { + margin-bottom: 20px; + width: 100%; +} +label { + margin-bottom: 5px; + color: #555; + font-size: 14px; +} +input[type="text"], input[type="password"] { + width: 100%; + padding: 12px; + border: 1px solid #ddd; + border-radius: 5px; + box-sizing: border-box; + font-size: 16px; +} +button { + padding: 12px; + background-color: #007BFF; + color: #fff; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; + font-size: 16px; + width: 100%; +} +button:hover { + background-color: #0056b3; + transform: scale(1.02); +} +.error { + color: red; + margin-bottom: 15px; + font-size: 14px; + text-align: center; +} \ No newline at end of file diff --git a/static/styles.css b/static/styles.css new file mode 100644 index 0000000..16d10e2 --- /dev/null +++ b/static/styles.css @@ -0,0 +1,65 @@ +/* Common styles */ +body { + font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; + background: linear-gradient(135deg, #ffeeee 25%, #dce2ff 75%); + margin: 0; + padding: 0; + display: flex; + justify-content: center; + align-items: center; + min-height: 100vh; +} +h1 { + color: #333; + margin: 20px 0; + font-size: 24px; + text-align: center; +} +form { + background-color: #fff; + padding: 30px; + border-radius: 10px; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); + width: 350px; + display: flex; + flex-direction: column; + align-items: center; +} +form div { + margin-bottom: 20px; + width: 100%; +} +label { + margin-bottom: 5px; + color: #555; + font-size: 14px; +} +input[type="text"], input[type="password"] { + width: 100%; + padding: 12px; + border: 1px solid #ddd; + border-radius: 5px; + box-sizing: border-box; + font-size: 16px; +} +button { + padding: 12px; + background-color: #007BFF; + color: #fff; + border: none; + border-radius: 5px; + cursor: pointer; + transition: background-color 0.3s, transform 0.2s; + font-size: 16px; + width: 100%; +} +button:hover { + background-color: #0056b3; + transform: scale(1.02); +} +.error { + color: red; + margin-bottom: 15px; + font-size: 14px; + text-align: center; +} \ No newline at end of file diff --git a/templates/gallery.html b/templates/gallery.html new file mode 100644 index 0000000..2608241 --- /dev/null +++ b/templates/gallery.html @@ -0,0 +1,34 @@ + + + + Image Gallery + + + + +

Image Gallery

+ + + + \ No newline at end of file diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 0000000..0b36d68 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,24 @@ + + + + Login + + + +
+

Login

+ {% if error %} +

Error: {{ error }}

+ {% endif %} +
+ + +
+
+ + +
+ +
+ + \ No newline at end of file