import os import json import threading import time from datetime import datetime, timezone from flask import Flask, request, jsonify, render_template_string from flask_cors import CORS from werkzeug.serving import run_simple import logging # Configure logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) app = Flask(__name__) app.config['SECRET_KEY'] = 'asdf#FGSgvasgf$5$WGT' # Enable CORS for all routes CORS(app) # Enhanced data storage with chat functionality and better time handling class EnhancedDataStore: def __init__(self, backup_file='enhanced_data_backup.json'): self.backup_file = backup_file self.data = { 'posts': [], 'comments': [], 'chat_messages': [], 'next_post_id': 1, 'next_comment_id': 1, 'next_chat_id': 1, 'app_version': '2.0.0', 'last_updated': datetime.utcnow().isoformat() } self.lock = threading.Lock() self.load_data() # Start background backup thread self.backup_thread = threading.Thread(target=self.periodic_backup, daemon=True) self.backup_thread.start() def get_utc_timestamp(self): """Get current UTC timestamp""" return datetime.utcnow().isoformat() + 'Z' def load_data(self): """Load data from backup file if it exists""" try: if os.path.exists(self.backup_file): with open(self.backup_file, 'r', encoding='utf-8') as f: loaded_data = json.load(f) # Migrate old data structure if needed if 'chat_messages' not in loaded_data: loaded_data['chat_messages'] = [] loaded_data['next_chat_id'] = 1 if 'app_version' not in loaded_data: loaded_data['app_version'] = '2.0.0' self.data.update(loaded_data) logger.info(f"Data loaded from {self.backup_file}: {len(self.data['posts'])} posts, {len(self.data['chat_messages'])} chat messages") else: logger.info("No backup file found, starting with empty data") except Exception as e: logger.error(f"Error loading data: {str(e)}") def save_data(self): """Save data to backup file""" try: with self.lock: self.data['last_updated'] = self.get_utc_timestamp() with open(self.backup_file, 'w', encoding='utf-8') as f: json.dump(self.data, f, ensure_ascii=False, indent=2) logger.info(f"Data saved to {self.backup_file}") except Exception as e: logger.error(f"Error saving data: {str(e)}") def periodic_backup(self): """Periodically backup data every 30 seconds""" while True: time.sleep(30) self.save_data() def add_post(self, name, note, youtube_link=''): """Add a new post with UTC timestamp""" try: with self.lock: post = { 'id': self.data['next_post_id'], 'name': str(name).strip(), 'note': str(note).strip(), 'youtube_link': str(youtube_link).strip(), 'likes': 0, 'created_at': self.get_utc_timestamp() } self.data['posts'].append(post) self.data['next_post_id'] += 1 self.save_data() logger.info(f"Post added: ID {post['id']}, Name: {post['name']}") return post except Exception as e: logger.error(f"Error adding post: {str(e)}") raise def get_posts(self): """Get all posts sorted by creation date (newest first)""" try: with self.lock: posts = sorted(self.data['posts'], key=lambda x: x['created_at'], reverse=True) logger.info(f"Retrieved {len(posts)} posts") return posts except Exception as e: logger.error(f"Error getting posts: {str(e)}") return [] def like_post(self, post_id): """Like a post""" try: with self.lock: for post in self.data['posts']: if post['id'] == post_id: post['likes'] += 1 self.save_data() logger.info(f"Post {post_id} liked, total likes: {post['likes']}") return post['likes'] logger.warning(f"Post {post_id} not found for liking") return None except Exception as e: logger.error(f"Error liking post {post_id}: {str(e)}") return None def add_comment(self, post_id, name, comment): """Add a comment to a post with UTC timestamp""" try: with self.lock: # Check if post exists post_exists = any(post['id'] == post_id for post in self.data['posts']) if not post_exists: logger.warning(f"Post {post_id} not found for commenting") return None comment_obj = { 'id': self.data['next_comment_id'], 'post_id': post_id, 'name': str(name).strip(), 'comment': str(comment).strip(), 'created_at': self.get_utc_timestamp() } self.data['comments'].append(comment_obj) self.data['next_comment_id'] += 1 self.save_data() logger.info(f"Comment added to post {post_id}") return comment_obj except Exception as e: logger.error(f"Error adding comment to post {post_id}: {str(e)}") return None def get_comments(self, post_id): """Get comments for a specific post""" try: with self.lock: comments = [c for c in self.data['comments'] if c['post_id'] == post_id] logger.info(f"Retrieved {len(comments)} comments for post {post_id}") return comments except Exception as e: logger.error(f"Error getting comments for post {post_id}: {str(e)}") return [] def add_chat_message(self, name, message): """Add a chat message with UTC timestamp""" try: with self.lock: chat_msg = { 'id': self.data['next_chat_id'], 'name': str(name).strip(), 'message': str(message).strip(), 'created_at': self.get_utc_timestamp() } self.data['chat_messages'].append(chat_msg) self.data['next_chat_id'] += 1 # Keep only last 100 chat messages to prevent memory issues if len(self.data['chat_messages']) > 100: self.data['chat_messages'] = self.data['chat_messages'][-100:] self.save_data() logger.info(f"Chat message added: ID {chat_msg['id']}, Name: {chat_msg['name']}") return chat_msg except Exception as e: logger.error(f"Error adding chat message: {str(e)}") return None def get_chat_messages(self, limit=50): """Get recent chat messages""" try: with self.lock: messages = sorted(self.data['chat_messages'], key=lambda x: x['created_at'], reverse=True)[:limit] messages.reverse() # Show oldest first logger.info(f"Retrieved {len(messages)} chat messages") return messages except Exception as e: logger.error(f"Error getting chat messages: {str(e)}") return [] def get_stats(self): """Get application statistics""" try: with self.lock: return { 'total_posts': len(self.data['posts']), 'total_comments': len(self.data['comments']), 'total_chat_messages': len(self.data['chat_messages']), 'total_likes': sum(post['likes'] for post in self.data['posts']), 'app_version': self.data.get('app_version', '2.0.0'), 'last_backup': self.get_utc_timestamp(), 'server_time': self.get_utc_timestamp() } except Exception as e: logger.error(f"Error getting stats: {str(e)}") return { 'total_posts': 0, 'total_comments': 0, 'total_chat_messages': 0, 'total_likes': 0, 'app_version': '2.0.0', 'last_backup': self.get_utc_timestamp(), 'server_time': self.get_utc_timestamp() } # Initialize enhanced data store data_store = EnhancedDataStore() # Keep-alive mechanism class KeepAlive: def __init__(self): self.last_activity = time.time() self.keep_alive_thread = threading.Thread(target=self.keep_alive_loop, daemon=True) self.keep_alive_thread.start() def update_activity(self): """Update last activity timestamp""" self.last_activity = time.time() def keep_alive_loop(self): """Keep the application active""" while True: time.sleep(300) # Every 5 minutes current_time = time.time() if current_time - self.last_activity < 3600: # If activity within last hour stats = data_store.get_stats() logger.info(f"Keep-alive: App v{stats['app_version']} is active. Stats: {stats}") time.sleep(300) # Initialize keep-alive keep_alive = KeepAlive() # Enhanced HTML Template with Chat Tab and Time Sync HTML_TEMPLATE = ''' Share YouTube v2.0 - Enhanced with Chat & Time Sync

Share YouTube v2.0

Share videos, chat with friends - Enhanced with real-time sync!

Syncing time with server...
0
Posts
0
Comments
0
Likes
0
Chat Messages

Shared Links

Live Chat

Loading...

Success!
An error occurred!
''' # Enhanced API Routes @app.route('/api/time', methods=['GET']) def get_server_time(): """Get server time for synchronization""" try: keep_alive.update_activity() return jsonify({ 'server_time': data_store.get_utc_timestamp(), 'timezone': 'UTC' }) except Exception as e: logger.error(f"Error getting server time: {str(e)}") return jsonify({'error': 'Failed to get server time'}), 500 @app.route('/api/posts', methods=['GET']) def get_posts(): """Get all posts""" try: keep_alive.update_activity() posts = data_store.get_posts() logger.info(f"API: Returning {len(posts)} posts") return jsonify(posts) except Exception as e: logger.error(f"API Error getting posts: {str(e)}") return jsonify({'error': 'Failed to get posts'}), 500 @app.route('/api/posts', methods=['POST']) def create_post(): """Create a new post""" try: keep_alive.update_activity() data = request.get_json() logger.info(f"API: Received post data: {data}") if not data: logger.warning("API: No JSON data received") return jsonify({'error': 'No data provided'}), 400 name = data.get('name', '').strip() note = data.get('note', '').strip() youtube_link = data.get('youtube_link', '').strip() if not name or not note: logger.warning(f"API: Missing required fields - name: {bool(name)}, note: {bool(note)}") return jsonify({'error': 'Name and note are required'}), 400 post = data_store.add_post(name=name, note=note, youtube_link=youtube_link) logger.info(f"API: Post created successfully: {post['id']}") return jsonify(post), 201 except Exception as e: logger.error(f"API Error creating post: {str(e)}") return jsonify({'error': f'Failed to create post: {str(e)}'}), 500 @app.route('/api/posts//like', methods=['POST']) def like_post(post_id): """Like a post""" try: keep_alive.update_activity() likes = data_store.like_post(post_id) if likes is None: logger.warning(f"API: Post {post_id} not found for liking") return jsonify({'error': 'Post not found'}), 404 logger.info(f"API: Post {post_id} liked, total likes: {likes}") return jsonify({'likes': likes}) except Exception as e: logger.error(f"API Error liking post {post_id}: {str(e)}") return jsonify({'error': 'Failed to like post'}), 500 @app.route('/api/posts//comments', methods=['GET']) def get_comments(post_id): """Get comments for a post""" try: keep_alive.update_activity() comments = data_store.get_comments(post_id) logger.info(f"API: Returning {len(comments)} comments for post {post_id}") return jsonify(comments) except Exception as e: logger.error(f"API Error getting comments for post {post_id}: {str(e)}") return jsonify({'error': 'Failed to get comments'}), 500 @app.route('/api/posts//comments', methods=['POST']) def add_comment(post_id): """Add a comment to a post""" try: keep_alive.update_activity() data = request.get_json() logger.info(f"API: Received comment data for post {post_id}: {data}") if not data: return jsonify({'error': 'No data provided'}), 400 name = data.get('name', '').strip() comment_text = data.get('comment', '').strip() if not name or not comment_text: logger.warning(f"API: Missing required fields - name: {bool(name)}, comment: {bool(comment_text)}") return jsonify({'error': 'Name and comment are required'}), 400 comment = data_store.add_comment(post_id=post_id, name=name, comment=comment_text) if comment is None: logger.warning(f"API: Post {post_id} not found for commenting") return jsonify({'error': 'Post not found'}), 404 logger.info(f"API: Comment added to post {post_id}") return jsonify(comment), 201 except Exception as e: logger.error(f"API Error adding comment to post {post_id}: {str(e)}") return jsonify({'error': 'Failed to add comment'}), 500 @app.route('/api/chat', methods=['GET']) def get_chat_messages(): """Get chat messages""" try: keep_alive.update_activity() messages = data_store.get_chat_messages() logger.info(f"API: Returning {len(messages)} chat messages") return jsonify(messages) except Exception as e: logger.error(f"API Error getting chat messages: {str(e)}") return jsonify({'error': 'Failed to get chat messages'}), 500 @app.route('/api/chat', methods=['POST']) def add_chat_message(): """Add a chat message""" try: keep_alive.update_activity() data = request.get_json() logger.info(f"API: Received chat message data: {data}") if not data: return jsonify({'error': 'No data provided'}), 400 name = data.get('name', '').strip() message = data.get('message', '').strip() if not name or not message: logger.warning(f"API: Missing required fields - name: {bool(name)}, message: {bool(message)}") return jsonify({'error': 'Name and message are required'}), 400 chat_msg = data_store.add_chat_message(name=name, message=message) if chat_msg is None: return jsonify({'error': 'Failed to add chat message'}), 500 logger.info(f"API: Chat message added: {chat_msg['id']}") return jsonify(chat_msg), 201 except Exception as e: logger.error(f"API Error adding chat message: {str(e)}") return jsonify({'error': 'Failed to add chat message'}), 500 @app.route('/api/stats', methods=['GET']) def get_stats(): """Get application statistics""" try: keep_alive.update_activity() stats = data_store.get_stats() logger.info(f"API: Returning stats: {stats}") return jsonify(stats) except Exception as e: logger.error(f"API Error getting stats: {str(e)}") return jsonify({'error': 'Failed to get stats'}), 500 # Health check endpoint @app.route('/health') def health_check(): """Health check endpoint""" try: keep_alive.update_activity() stats = data_store.get_stats() return jsonify({ 'status': 'healthy', 'timestamp': data_store.get_utc_timestamp(), 'stats': stats }) except Exception as e: logger.error(f"Health check error: {str(e)}") return jsonify({'status': 'unhealthy', 'error': str(e)}), 500 # Main route @app.route('/') def index(): keep_alive.update_activity() return render_template_string(HTML_TEMPLATE) # Error handlers @app.errorhandler(404) def not_found(error): logger.warning(f"404 error: {request.url}") return jsonify({'error': 'Not found'}), 404 @app.errorhandler(500) def internal_error(error): logger.error(f"500 error: {str(error)}") return jsonify({'error': 'Internal server error'}), 500 if __name__ == '__main__': port = int(os.environ.get('PORT', 7860)) logger.info(f"===== Enhanced Share YouTube App v2.0 Startup at {datetime.utcnow().strftime('%Y-%m-%d %H:%M:%S')} =====") logger.info(f"Starting enhanced server with chat and time sync on port {port}") logger.info(f"Data will be saved to: {data_store.backup_file}") # Load initial data and show stats initial_stats = data_store.get_stats() logger.info(f"Initial stats: {initial_stats}") # Run with threading enabled and proper error handling run_simple( hostname='0.0.0.0', port=port, application=app, use_reloader=False, use_debugger=False, threaded=True, processes=1 )