feat: Add comprehensive documentation suite and reorganize project structure
- Created complete documentation in docs/ directory - Added PROJECT_OVERVIEW.md with feature highlights and getting started guide - Added ARCHITECTURE.md with system design and technical details - Added SECURITY.md with comprehensive security implementation guide - Added DEVELOPMENT.md with development workflows and best practices - Added DEPLOYMENT.md with production deployment instructions - Added API.md with complete REST API documentation - Added CONTRIBUTING.md with contribution guidelines - Added CHANGELOG.md with version history and migration notes - Reorganized all documentation files into docs/ directory for better organization - Updated README.md with proper documentation links and quick navigation - Enhanced project structure with professional documentation standards
This commit is contained in:
352
f_core/f_classes/class.livechat.php
Normal file
352
f_core/f_classes/class.livechat.php
Normal file
@@ -0,0 +1,352 @@
|
||||
<?php
|
||||
/*******************************************************************************************************************
|
||||
| Software Name : EasyStream
|
||||
| Software Description : High End YouTube Clone Script with Videos, Shorts, Streams, Images, Audio, Documents, Blogs
|
||||
| Software Author : (c) Sami Ahmed
|
||||
|*******************************************************************************************************************
|
||||
|
|
||||
|*******************************************************************************************************************
|
||||
| This source file is subject to the EasyStream Proprietary License Agreement.
|
||||
|
|
||||
| By using this software, you acknowledge having read this Agreement and agree to be bound thereby.
|
||||
|*******************************************************************************************************************
|
||||
| Copyright (c) 2025 Sami Ahmed. All rights reserved.
|
||||
|*******************************************************************************************************************/
|
||||
|
||||
defined('_ISVALID') or header('Location: /error');
|
||||
|
||||
/**
|
||||
* Live Chat Management Class
|
||||
*
|
||||
* Handles live chat functionality for streams including:
|
||||
* - Message sending and retrieval
|
||||
* - Moderation actions (timeout, ban)
|
||||
* - Super chat donations
|
||||
* - Chat replay
|
||||
*/
|
||||
class VLiveChat
|
||||
{
|
||||
/**
|
||||
* Send a chat message
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param string $message Message content
|
||||
* @param string $type Message type (chat, super_chat, system)
|
||||
* @param float $super_chat_amount Amount if super chat
|
||||
* @return array Result
|
||||
*/
|
||||
public static function sendMessage($stream_key, $message, $type = 'chat', $super_chat_amount = null)
|
||||
{
|
||||
global $class_database, $cfg;
|
||||
|
||||
$usr_id = isset($_SESSION['USER_ID']) ? (int) $_SESSION['USER_ID'] : 0;
|
||||
|
||||
if ($usr_id == 0) {
|
||||
return ['success' => false, 'error' => 'Must be logged in to chat'];
|
||||
}
|
||||
|
||||
// Check if chat is enabled
|
||||
$settings = self::getChatSettings($stream_key);
|
||||
if (!$settings['chat_enabled']) {
|
||||
return ['success' => false, 'error' => 'Chat is disabled for this stream'];
|
||||
}
|
||||
|
||||
// Check if user is banned or timed out
|
||||
if (self::isUserBanned($stream_key, $usr_id)) {
|
||||
return ['success' => false, 'error' => 'You are banned from this chat'];
|
||||
}
|
||||
|
||||
if (self::isUserTimedOut($stream_key, $usr_id)) {
|
||||
return ['success' => false, 'error' => 'You are timed out from this chat'];
|
||||
}
|
||||
|
||||
// Validate message length
|
||||
$max_length = (int) ($cfg['live_chat_max_length'] ?? 500);
|
||||
if (strlen($message) > $max_length) {
|
||||
return ['success' => false, 'error' => "Message too long (max {$max_length} characters)"];
|
||||
}
|
||||
|
||||
// Rate limiting
|
||||
$rate_limit = self::checkRateLimit($stream_key, $usr_id, $settings['slow_mode']);
|
||||
if (!$rate_limit['allowed']) {
|
||||
return ['success' => false, 'error' => $rate_limit['message']];
|
||||
}
|
||||
|
||||
// Sanitize message
|
||||
$message = htmlspecialchars($message, ENT_QUOTES, 'UTF-8');
|
||||
|
||||
// Insert message
|
||||
$sql = "INSERT INTO `db_live_chat_messages`
|
||||
(`stream_key`, `usr_id`, `message`, `message_type`, `super_chat_amount`)
|
||||
VALUES ('%s', %d, '%s', '%s', %s)";
|
||||
|
||||
$class_database->doQuery($sql,
|
||||
$stream_key,
|
||||
$usr_id,
|
||||
$message,
|
||||
$type,
|
||||
$super_chat_amount ? (float) $super_chat_amount : 'NULL'
|
||||
);
|
||||
|
||||
$msg_id = $class_database->insert_id();
|
||||
|
||||
return [
|
||||
'success' => true,
|
||||
'msg_id' => $msg_id,
|
||||
'message' => $message,
|
||||
'timestamp' => date('Y-m-d H:i:s')
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chat messages for a stream
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param int $limit Number of messages
|
||||
* @param int $since_id Get messages after this ID
|
||||
* @return array Messages
|
||||
*/
|
||||
public static function getMessages($stream_key, $limit = 50, $since_id = 0)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$since_clause = $since_id > 0 ? "AND m.msg_id > {$since_id}" : "";
|
||||
|
||||
$sql = "SELECT
|
||||
m.msg_id, m.message, m.message_type, m.super_chat_amount, m.timestamp,
|
||||
u.usr_id, u.usr_user, u.usr_dname, u.usr_key, u.usr_partner, u.usr_affiliate
|
||||
FROM `db_live_chat_messages` m
|
||||
JOIN `db_accountuser` u ON m.usr_id = u.usr_id
|
||||
WHERE m.stream_key = '%s'
|
||||
AND m.deleted = 0
|
||||
{$since_clause}
|
||||
ORDER BY m.msg_id DESC
|
||||
LIMIT %d";
|
||||
|
||||
$result = $class_database->doQuery($sql, $stream_key, $limit);
|
||||
|
||||
$messages = [];
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
$messages[] = [
|
||||
'msg_id' => $row['msg_id'],
|
||||
'user_id' => $row['usr_id'],
|
||||
'username' => $row['usr_user'],
|
||||
'display_name' => $row['usr_dname'],
|
||||
'user_key' => $row['usr_key'],
|
||||
'is_partner' => $row['usr_partner'] == 1,
|
||||
'is_affiliate' => $row['usr_affiliate'] == 1,
|
||||
'message' => $row['message'],
|
||||
'type' => $row['message_type'],
|
||||
'super_chat_amount' => $row['super_chat_amount'],
|
||||
'timestamp' => $row['timestamp'],
|
||||
'is_moderator' => self::isModerator($stream_key, $row['usr_id'])
|
||||
];
|
||||
}
|
||||
|
||||
return array_reverse($messages); // Return in chronological order
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a message (moderation)
|
||||
*
|
||||
* @param int $msg_id Message ID
|
||||
* @param int $moderator_id Moderator user ID
|
||||
* @return bool Success
|
||||
*/
|
||||
public static function deleteMessage($msg_id, $moderator_id)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$sql = "UPDATE `db_live_chat_messages`
|
||||
SET `deleted` = 1, `deleted_by` = %d
|
||||
WHERE `msg_id` = %d";
|
||||
|
||||
$class_database->doQuery($sql, $moderator_id, $msg_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Timeout a user
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param int $usr_id User to timeout
|
||||
* @param int $duration Duration in seconds
|
||||
* @param string $reason Reason
|
||||
* @param int $moderator_id Moderator user ID
|
||||
* @return bool Success
|
||||
*/
|
||||
public static function timeoutUser($stream_key, $usr_id, $duration, $reason, $moderator_id)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$expires_at = date('Y-m-d H:i:s', time() + $duration);
|
||||
|
||||
$sql = "INSERT INTO `db_live_chat_moderation`
|
||||
(`stream_key`, `usr_id`, `action`, `duration`, `reason`, `moderator_id`, `expires_at`)
|
||||
VALUES ('%s', %d, 'timeout', %d, '%s', %d, '%s')";
|
||||
|
||||
$class_database->doQuery($sql,
|
||||
$stream_key,
|
||||
$usr_id,
|
||||
$duration,
|
||||
$reason,
|
||||
$moderator_id,
|
||||
$expires_at
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ban a user from chat
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param int $usr_id User to ban
|
||||
* @param string $reason Reason
|
||||
* @param int $moderator_id Moderator user ID
|
||||
* @return bool Success
|
||||
*/
|
||||
public static function banUser($stream_key, $usr_id, $reason, $moderator_id)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$sql = "INSERT INTO `db_live_chat_moderation`
|
||||
(`stream_key`, `usr_id`, `action`, `reason`, `moderator_id`)
|
||||
VALUES ('%s', %d, 'ban', '%s', %d)";
|
||||
|
||||
$class_database->doQuery($sql, $stream_key, $usr_id, $reason, $moderator_id);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is banned
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param int $usr_id User ID
|
||||
* @return bool Is banned
|
||||
*/
|
||||
public static function isUserBanned($stream_key, $usr_id)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$sql = "SELECT COUNT(*) as count FROM `db_live_chat_moderation`
|
||||
WHERE `stream_key` = '%s' AND `usr_id` = %d AND `action` = 'ban'
|
||||
ORDER BY `mod_id` DESC LIMIT 1";
|
||||
|
||||
$result = $class_database->doQuery($sql, $stream_key, $usr_id);
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
return $row['count'] > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is timed out
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param int $usr_id User ID
|
||||
* @return bool Is timed out
|
||||
*/
|
||||
public static function isUserTimedOut($stream_key, $usr_id)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$sql = "SELECT COUNT(*) as count FROM `db_live_chat_moderation`
|
||||
WHERE `stream_key` = '%s'
|
||||
AND `usr_id` = %d
|
||||
AND `action` = 'timeout'
|
||||
AND `expires_at` > NOW()";
|
||||
|
||||
$result = $class_database->doQuery($sql, $stream_key, $usr_id);
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
return $row['count'] > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if user is a moderator
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param int $usr_id User ID
|
||||
* @return bool Is moderator
|
||||
*/
|
||||
public static function isModerator($stream_key, $usr_id)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$sql = "SELECT COUNT(*) as count FROM `db_live_chat_moderators`
|
||||
WHERE `stream_key` = '%s' AND `usr_id` = %d";
|
||||
|
||||
$result = $class_database->doQuery($sql, $stream_key, $usr_id);
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
return $row['count'] > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chat settings for stream
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @return array Settings
|
||||
*/
|
||||
public static function getChatSettings($stream_key)
|
||||
{
|
||||
global $class_database;
|
||||
|
||||
$sql = "SELECT * FROM `db_live_chat_settings` WHERE `stream_key` = '%s' LIMIT 1";
|
||||
$result = $class_database->doQuery($sql, $stream_key);
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
if (!$row) {
|
||||
// Return defaults
|
||||
return [
|
||||
'chat_enabled' => 1,
|
||||
'slow_mode' => null,
|
||||
'subscriber_only' => 0,
|
||||
'follower_only' => 0,
|
||||
'emotes_enabled' => 1,
|
||||
'links_allowed' => 0
|
||||
];
|
||||
}
|
||||
|
||||
return $row;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check rate limit
|
||||
*
|
||||
* @param string $stream_key Stream file key
|
||||
* @param int $usr_id User ID
|
||||
* @param int $slow_mode Slow mode seconds
|
||||
* @return array Result
|
||||
*/
|
||||
private static function checkRateLimit($stream_key, $usr_id, $slow_mode)
|
||||
{
|
||||
global $class_database, $cfg;
|
||||
|
||||
$rate_limit = max((int) ($cfg['live_chat_rate_limit'] ?? 2), (int) $slow_mode);
|
||||
|
||||
$sql = "SELECT MAX(timestamp) as last_message FROM `db_live_chat_messages`
|
||||
WHERE `stream_key` = '%s' AND `usr_id` = %d";
|
||||
|
||||
$result = $class_database->doQuery($sql, $stream_key, $usr_id);
|
||||
$row = $result->fetch_assoc();
|
||||
|
||||
if ($row['last_message']) {
|
||||
$last_time = strtotime($row['last_message']);
|
||||
$now = time();
|
||||
$diff = $now - $last_time;
|
||||
|
||||
if ($diff < $rate_limit) {
|
||||
$wait = $rate_limit - $diff;
|
||||
return [
|
||||
'allowed' => false,
|
||||
'message' => "Please wait {$wait} seconds before sending another message"
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return ['allowed' => true];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user