Files
easystream-main/f_core/f_classes/class.livechat.php
SamiAhmed7777 0b7e2d0a5b 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
2025-10-21 00:39:45 -07:00

353 lines
11 KiB
PHP

<?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];
}
}