updated to correct frature

This commit is contained in:
2025-07-15 13:55:52 +03:00
parent d30d065f44
commit 94f006d458
7 changed files with 1277 additions and 28 deletions

263
app.py
View File

@@ -8,7 +8,6 @@ from PIL import Image, ImageDraw
import qrcode
from qrcode.image.styledpil import StyledPilImage
from qrcode.image.styles.moduledrawers import RoundedModuleDrawer, CircleModuleDrawer, SquareModuleDrawer
from qrcode.image.styles.colorfills import SolidFillColorMask
from flask import Flask, request, jsonify, send_file, render_template
from flask_cors import CORS
@@ -24,6 +23,9 @@ os.makedirs(LOGOS_FOLDER, exist_ok=True)
# In-memory storage for QR codes (in production, use a database)
qr_codes_db = {}
# In-memory storage for dynamic link pages
link_pages_db = {}
class QRCodeGenerator:
def __init__(self):
self.default_settings = {
@@ -55,27 +57,28 @@ class QRCodeGenerator:
qr.add_data(data)
qr.make(fit=True)
# Choose module drawer based on style
module_drawer = None
if settings['style'] == 'rounded':
module_drawer = RoundedModuleDrawer()
elif settings['style'] == 'circle':
module_drawer = CircleModuleDrawer()
# For styled QR codes with custom module drawer
if settings['style'] != 'square':
# Choose module drawer based on style
module_drawer = None
if settings['style'] == 'rounded':
module_drawer = RoundedModuleDrawer()
elif settings['style'] == 'circle':
module_drawer = CircleModuleDrawer()
# Generate the styled image
img = qr.make_image(
image_factory=StyledPilImage,
module_drawer=module_drawer,
fill_color=settings['foreground_color'],
back_color=settings['background_color']
)
else:
module_drawer = SquareModuleDrawer()
# Create color mask
color_mask = SolidFillColorMask(
back_color=settings['background_color'],
front_color=settings['foreground_color']
)
# Generate the image
img = qr.make_image(
image_factory=StyledPilImage,
module_drawer=module_drawer,
color_mask=color_mask
)
# Generate standard image with custom colors
img = qr.make_image(
fill_color=settings['foreground_color'],
back_color=settings['background_color']
)
return img
@@ -109,8 +112,78 @@ class QRCodeGenerator:
print(f"Error adding logo: {e}")
return qr_img
# Initialize QR code generator
class LinkPageManager:
def __init__(self):
pass
def create_link_page(self, title="My Links", description="Collection of useful links"):
"""Create a new dynamic link page"""
page_id = str(uuid.uuid4())
page_data = {
'id': page_id,
'title': title,
'description': description,
'links': [],
'created_at': datetime.now().isoformat(),
'updated_at': datetime.now().isoformat(),
'view_count': 0
}
link_pages_db[page_id] = page_data
return page_id
def add_link(self, page_id, title, url, description=""):
"""Add a link to a page"""
if page_id not in link_pages_db:
return False
link_data = {
'id': str(uuid.uuid4()),
'title': title,
'url': url if url.startswith(('http://', 'https://')) else f'https://{url}',
'description': description,
'created_at': datetime.now().isoformat()
}
link_pages_db[page_id]['links'].append(link_data)
link_pages_db[page_id]['updated_at'] = datetime.now().isoformat()
return True
def update_link(self, page_id, link_id, title=None, url=None, description=None):
"""Update a specific link"""
if page_id not in link_pages_db:
return False
for link in link_pages_db[page_id]['links']:
if link['id'] == link_id:
if title is not None:
link['title'] = title
if url is not None:
link['url'] = url if url.startswith(('http://', 'https://')) else f'https://{url}'
if description is not None:
link['description'] = description
link_pages_db[page_id]['updated_at'] = datetime.now().isoformat()
return True
return False
def delete_link(self, page_id, link_id):
"""Delete a specific link"""
if page_id not in link_pages_db:
return False
links = link_pages_db[page_id]['links']
link_pages_db[page_id]['links'] = [link for link in links if link['id'] != link_id]
link_pages_db[page_id]['updated_at'] = datetime.now().isoformat()
return True
def increment_view_count(self, page_id):
"""Increment view count for a page"""
if page_id in link_pages_db:
link_pages_db[page_id]['view_count'] += 1
# Initialize managers
qr_generator = QRCodeGenerator()
link_manager = LinkPageManager()
@app.route('/')
def index():
@@ -282,5 +355,151 @@ def upload_logo():
except Exception as e:
return jsonify({'error': str(e)}), 500
# Dynamic Link Pages API Routes
@app.route('/api/create_link_page', methods=['POST'])
def create_link_page():
"""Create a new dynamic link page and QR code"""
try:
data = request.json
title = data.get('title', 'My Links')
description = data.get('description', 'Collection of useful links')
# Create the link page
page_id = link_manager.create_link_page(title, description)
# Create QR code pointing to the link page
page_url = f"{request.url_root}links/{page_id}"
settings = {
'size': data.get('size', 10),
'border': data.get('border', 4),
'foreground_color': data.get('foreground_color', '#000000'),
'background_color': data.get('background_color', '#FFFFFF'),
'style': data.get('style', 'square')
}
# Generate QR code
qr_img = qr_generator.generate_qr_code(page_url, settings)
# Convert to base64
img_buffer = io.BytesIO()
qr_img.save(img_buffer, format='PNG')
img_buffer.seek(0)
img_base64 = base64.b64encode(img_buffer.getvalue()).decode()
# Save QR code record
qr_id = str(uuid.uuid4())
qr_record = {
'id': qr_id,
'type': 'link_page',
'content': page_url,
'page_id': page_id,
'settings': settings,
'created_at': datetime.now().isoformat(),
'image_data': img_base64
}
qr_codes_db[qr_id] = qr_record
# Save image file
img_path = os.path.join(UPLOAD_FOLDER, f'{qr_id}.png')
qr_img.save(img_path)
return jsonify({
'success': True,
'qr_id': qr_id,
'page_id': page_id,
'page_url': page_url,
'edit_url': f"{request.url_root}edit/{page_id}",
'image_data': f'data:image/png;base64,{img_base64}',
'download_url': f'/api/download/{qr_id}'
})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/link_pages/<page_id>/links', methods=['POST'])
def add_link_to_page(page_id):
"""Add a link to a page"""
try:
data = request.json
title = data.get('title', '')
url = data.get('url', '')
description = data.get('description', '')
if not title or not url:
return jsonify({'error': 'Title and URL are required'}), 400
success = link_manager.add_link(page_id, title, url, description)
if success:
return jsonify({'success': True})
else:
return jsonify({'error': 'Page not found'}), 404
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/link_pages/<page_id>/links/<link_id>', methods=['PUT'])
def update_link_in_page(page_id, link_id):
"""Update a link in a page"""
try:
data = request.json
title = data.get('title')
url = data.get('url')
description = data.get('description')
success = link_manager.update_link(page_id, link_id, title, url, description)
if success:
return jsonify({'success': True})
else:
return jsonify({'error': 'Page or link not found'}), 404
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/link_pages/<page_id>/links/<link_id>', methods=['DELETE'])
def delete_link_from_page(page_id, link_id):
"""Delete a link from a page"""
try:
success = link_manager.delete_link(page_id, link_id)
if success:
return jsonify({'success': True})
else:
return jsonify({'error': 'Page or link not found'}), 404
except Exception as e:
return jsonify({'error': str(e)}), 500
@app.route('/api/link_pages/<page_id>')
def get_link_page(page_id):
"""Get link page data"""
if page_id in link_pages_db:
return jsonify(link_pages_db[page_id])
else:
return jsonify({'error': 'Page not found'}), 404
@app.route('/links/<page_id>')
def view_link_page(page_id):
"""Display the public link page"""
if page_id not in link_pages_db:
return "Page not found", 404
link_manager.increment_view_count(page_id)
page_data = link_pages_db[page_id]
return render_template('link_page.html', page=page_data)
@app.route('/edit/<page_id>')
def edit_link_page(page_id):
"""Display the edit interface for the link page"""
if page_id not in link_pages_db:
return "Page not found", 404
page_data = link_pages_db[page_id]
return render_template('edit_links.html', page=page_data)
if __name__ == '__main__':
app.run(debug=True, host='0.0.0.0', port=5000)