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 videos, chat with friends - Enhanced with real-time sync!
Loading...