<?php

/*
|--------------------------------------------------------------------------
| CONFIG
|--------------------------------------------------------------------------
*/

$BOT_TOKEN = 'PUT_YOUR_BOT_TOKEN_HERE';

$CHAT_ID = -1003890654433;

$GROQ_API_KEY = 'PUT_YOUR_GROQ_API_KEY_HERE';

$TIMEZONE = 'Asia/Tehran';

$SENT_FILE = __DIR__ . '/sent.json';

$PAGES = [

    [
        'username' => 'DiscussingFilm',
        'topic_id' => 3
    ],

    [
        'username' => 'HollywoodHandle',
        'topic_id' => 13
    ],

    [
        'username' => 'FilmUpdates',
        'topic_id' => 33
    ],

    [
        'username' => 'indiewire',
        'topic_id' => 72
    ],

    [
        'username' => 'collider',
        'topic_id' => 74
    ],

    [
        'username' => 'hbo',
        'topic_id' => 76
    ],

];


/*
|--------------------------------------------------------------------------
| TIMEZONE
|--------------------------------------------------------------------------
*/

date_default_timezone_set($TIMEZONE);


/*
|--------------------------------------------------------------------------
| LOG
|--------------------------------------------------------------------------
*/

function logMessage($message)
{
    echo $message . PHP_EOL;
}


/*
|--------------------------------------------------------------------------
| HTTP GET
|--------------------------------------------------------------------------
*/

function httpGet($url)
{
    $ch = curl_init($url);

    curl_setopt_array($ch, [

        CURLOPT_RETURNTRANSFER => true,

        CURLOPT_FOLLOWLOCATION => true,

        CURLOPT_MAXREDIRS => 5,

        CURLOPT_CONNECTTIMEOUT => 15,

        CURLOPT_TIMEOUT => 30,

        CURLOPT_USERAGENT =>
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 Chrome/130 Safari/537.36',

        CURLOPT_HTTPHEADER => [
            'Accept: application/rss+xml, application/xml, text/xml, */*'
        ]

    ]);

    $body = curl_exec($ch);

    $error = curl_error($ch);

    $status = curl_getinfo(
        $ch,
        CURLINFO_HTTP_CODE
    );

    /*
     * PHP 8.5:
     * curl_close() deprecated.
     * Releasing the variable releases the handle.
     */
    $ch = null;

    return [

        'ok' =>
            $body !== false &&
            $status >= 200 &&
            $status < 400,

        'body' =>
            $body ?: '',

        'status' =>
            $status,

        'error' =>
            $error

    ];
}


/*
|--------------------------------------------------------------------------
| TELEGRAM
|--------------------------------------------------------------------------
*/

function telegram($method, $data)
{
    global $BOT_TOKEN;

    $url =
        "https://api.telegram.org/bot{$BOT_TOKEN}/{$method}";

    $ch = curl_init($url);

    curl_setopt_array($ch, [

        CURLOPT_POST => true,

        CURLOPT_POSTFIELDS => $data,

        CURLOPT_RETURNTRANSFER => true,

        CURLOPT_CONNECTTIMEOUT => 15,

        CURLOPT_TIMEOUT => 60

    ]);

    $response = curl_exec($ch);

    $error = curl_error($ch);

    $httpCode = curl_getinfo(
        $ch,
        CURLINFO_HTTP_CODE
    );

    $ch = null;


    if ($response === false) {

        return [

            'ok' => false,

            'error' => $error,

            'http_code' => $httpCode

        ];
    }


    $decoded =
        json_decode(
            $response,
            true
        );


    if (!is_array($decoded)) {

        return [

            'ok' => false,

            'error' => $response,

            'http_code' => $httpCode

        ];
    }


    return $decoded;
}


/*
|--------------------------------------------------------------------------
| GROQ TRANSLATION
|--------------------------------------------------------------------------
*/

function translateToPersian($title, $text)
{
    global $GROQ_API_KEY;

    $title = trim($title);

    $text = trim($text);


    /*
    |--------------------------------------------------------------------------
    | Original fallback
    |--------------------------------------------------------------------------
    */

    $original = $title;

    if (
        $text !== '' &&
        $text !== $title
    ) {

        $original .=
            "\n\n" .
            $text;
    }


    if ($original === '') {

        return [

            'success' => false,

            'text' => ''

        ];
    }


    $url =
        'https://api.groq.com/openai/v1/chat/completions';


    $input =
        "TITLE:\n" .
        $title .
        "\n\n" .
        "TEXT:\n" .
        $text;


    $payload = [

        'model' =>
            'llama-3.1-8b-instant',

        'messages' => [

            [

                'role' =>
                    'system',

                'content' =>
                    'Translate English movie and TV news into natural Persian. ' .
                    'Return ONLY the Persian translation. ' .
                    'Preserve movie, TV show, actor and character names naturally. ' .
                    'Do not add explanations. ' .
                    'Do not translate URLs. ' .
                    'Keep the same paragraph structure.'

            ],

            [

                'role' =>
                    'user',

                'content' =>
                    $input

            ]

        ],

        'temperature' =>
            0.2,

        'max_tokens' =>
            700

    ];


    /*
    |--------------------------------------------------------------------------
    | RETRY
    |--------------------------------------------------------------------------
    */

    for (
        $attempt = 1;
        $attempt <= 3;
        $attempt++
    ) {

        $ch =
            curl_init($url);


        curl_setopt_array($ch, [

            CURLOPT_POST =>
                true,

            CURLOPT_RETURNTRANSFER =>
                true,

            CURLOPT_CONNECTTIMEOUT =>
                15,

            CURLOPT_TIMEOUT =>
                60,

            CURLOPT_HTTPHEADER => [

                'Authorization: Bearer ' .
                $GROQ_API_KEY,

                'Content-Type: application/json'

            ],

            CURLOPT_POSTFIELDS =>
                json_encode(
                    $payload,
                    JSON_UNESCAPED_UNICODE
                )

        ]);


        $response =
            curl_exec($ch);


        $httpCode =
            curl_getinfo(
                $ch,
                CURLINFO_HTTP_CODE
            );


        $error =
            curl_error($ch);


        $ch = null;


        /*
        |--------------------------------------------------------------------------
        | CURL ERROR
        |--------------------------------------------------------------------------
        */

        if ($response === false) {

            logMessage(
                "GROQ CURL ERROR: {$error}"
            );

            sleep(3);

            continue;
        }


        $data =
            json_decode(
                $response,
                true
            );


        /*
        |--------------------------------------------------------------------------
        | RATE LIMIT
        |--------------------------------------------------------------------------
        */

        if ($httpCode === 429) {

            $wait = 15;


            if (
                isset(
                    $data['error']['message']
                )
            ) {

                logMessage(
                    'GROQ RATE LIMIT: ' .
                    $data['error']['message']
                );
            }


            logMessage(
                "Waiting {$wait}s..."
            );


            sleep($wait);

            continue;
        }


        /*
        |--------------------------------------------------------------------------
        | OTHER ERROR
        |--------------------------------------------------------------------------
        */

        if (
            $httpCode < 200 ||
            $httpCode >= 300
        ) {

            logMessage(
                "GROQ ERROR HTTP {$httpCode}"
            );

            logMessage(
                $response
            );


            return [

                'success' =>
                    false,

                'text' =>
                    $original

            ];
        }


        /*
        |--------------------------------------------------------------------------
        | TRANSLATION
        |--------------------------------------------------------------------------
        */

        $translated =
            $data['choices'][0]['message']['content']
            ?? null;


        if (
            is_string($translated) &&
            trim($translated) !== ''
        ) {

            return [

                'success' =>
                    true,

                'text' =>
                    trim($translated)

            ];
        }


        logMessage(
            'GROQ returned empty translation.'
        );

        break;
    }


    return [

        'success' =>
            false,

        'text' =>
            $original

    ];
}


/*
|--------------------------------------------------------------------------
| CLEAN TEXT
|--------------------------------------------------------------------------
*/

function cleanText($text)
{
    $text =
        strip_tags($text);


    $text =
        html_entity_decode(
            $text,
            ENT_QUOTES | ENT_HTML5,
            'UTF-8'
        );


    $text =
        preg_replace(
            '/\s+/u',
            ' ',
            $text
        );


    return trim($text);
}


/*
|--------------------------------------------------------------------------
| EXTRACT IMAGES
|--------------------------------------------------------------------------
*/

function extractImages($description)
{
    $images = [];


    preg_match_all(

        '/<img[^>]+src=["\']([^"\']+)["\']/i',

        $description,

        $matches

    );


    foreach (
        $matches[1] ?? []
        as $url
    ) {

        $url =
            html_entity_decode(
                $url,
                ENT_QUOTES | ENT_HTML5,
                'UTF-8'
            );


        if (
            !in_array(
                $url,
                $images,
                true
            )
        ) {

            $images[] =
                $url;
        }
    }


    return $images;
}


/*
|--------------------------------------------------------------------------
| VIDEO DETECTION
|--------------------------------------------------------------------------
*/

function hasVideo($description)
{
    return

        stripos(
            $description,
            '>Video<'
        ) !== false

        ||

        preg_match(
            '/<a[^>]+>.*?Video.*?<\/a>/is',
            $description
        );
}


/*
|--------------------------------------------------------------------------
| NITTER -> FXTWITTER
|--------------------------------------------------------------------------
*/

function toFxTwitter($url)
{
    $url =
        preg_replace(
            '/#.*$/',
            '',
            $url
        );


    return preg_replace(

        '/^https?:\/\/(?:www\.)?nitter\.net/i',

        'https://fxtwitter.com',

        $url

    );
}


/*
|--------------------------------------------------------------------------
| DATE
|--------------------------------------------------------------------------
*/

function parseDate($pubDate)
{
    global $TIMEZONE;

    $pubDate = trim($pubDate);


    if ($pubDate === '') {

        return '';
    }


    try {

        $date =
            new DateTime(
                $pubDate,
                new DateTimeZone('GMT')
            );


        $date->setTimezone(
            new DateTimeZone(
                $TIMEZONE
            )
        );


        $months = [

            1 => 'ژانویه',

            2 => 'فوریه',

            3 => 'مارس',

            4 => 'آوریل',

            5 => 'مه',

            6 => 'ژوئن',

            7 => 'ژوئیه',

            8 => 'اوت',

            9 => 'سپتامبر',

            10 => 'اکتبر',

            11 => 'نوامبر',

            12 => 'دسامبر'

        ];


        $day =
            $date->format('d');

        $month =
            $months[
                (int)$date->format('m')
            ];

        $year =
            $date->format('Y');

        $time =
            $date->format('H:i');


        return
            "{$day} {$month} {$year} - {$time}";

    } catch (Throwable $e) {

        return $pubDate;
    }
}


/*
|--------------------------------------------------------------------------
| BUILD CAPTION
|--------------------------------------------------------------------------
*/

function buildCaption($item)
{
    logMessage(
        'Translating...'
    );


    $translation =
        translateToPersian(

            $item['title'],

            $item['text']

        );


    /*
    |--------------------------------------------------------------------------
    | Translation success
    |--------------------------------------------------------------------------
    */

    if (
        $translation['success']
    ) {

        $caption =
            $translation['text'];

    } else {

        /*
        |--------------------------------------------------------------------------
        | Original English fallback
        |--------------------------------------------------------------------------
        */

        $caption =
            $translation['text'] .
            "\n\n⚠️ ترجمه ناموفق بود";
    }


    /*
    |--------------------------------------------------------------------------
    | DATE
    |--------------------------------------------------------------------------
    */

    if (
        $item['date'] !== ''
    ) {

        $caption .=
            "\n\n📅 " .
            $item['date'];
    }


    /*
    |--------------------------------------------------------------------------
    | SOURCE
    |--------------------------------------------------------------------------
    */

    if (
        $item['url'] !== ''
    ) {

        $sourceUrl =
            toFxTwitter(
                $item['url']
            );


        $caption .=
            "\n🔗 منبع: " .
            $sourceUrl;
    }


    return [

        'caption' =>
            $caption,

        'translation_failed' =>
            !$translation['success']

    ];
}


/*
|--------------------------------------------------------------------------
| TELEGRAM CAPTION LIMIT
|--------------------------------------------------------------------------
*/

function telegramCaption($caption)
{
    if (
        mb_strlen(
            $caption,
            'UTF-8'
        ) <= 1024
    ) {

        return $caption;
    }


    return
        mb_substr(
            $caption,
            0,
            1000,
            'UTF-8'
        ) .
        '...';
}


/*
|--------------------------------------------------------------------------
| SEND ALBUM
|--------------------------------------------------------------------------
|
| Telegram max = 10 media per group
|
*/

function sendAlbum($images, $caption, $topicId)
{
    global $CHAT_ID;


    /*
    |--------------------------------------------------------------------------
    | Split into chunks of 10
    |--------------------------------------------------------------------------
    */

    $chunks =
        array_chunk(
            $images,
            10
        );


    foreach (
        $chunks as $chunkIndex => $chunk
    ) {

        $media = [];


        foreach (
            $chunk as $index => $image
        ) {

            $photo = [

                'type' =>
                    'photo',

                'media' =>
                    $image

            ];


            /*
            |--------------------------------------------------------------------------
            | Caption only on first image of first album
            |--------------------------------------------------------------------------
            */

            if (
                $chunkIndex === 0 &&
                $index === 0
            ) {

                $photo['caption'] =
                    telegramCaption(
                        $caption
                    );
            }


            $media[] =
                $photo;
        }


        logMessage(
            'Sending album part ' .
            ($chunkIndex + 1) .
            '/' .
            count($chunks) .
            ' (' .
            count($chunk) .
            ' photos)'
        );


        $result =
            telegram(
                'sendMediaGroup',
                [

                    'chat_id' =>
                        $CHAT_ID,

                    'message_thread_id' =>
                        $topicId,

                    'media' =>
                        json_encode(
                            $media,
                            JSON_UNESCAPED_UNICODE |
                            JSON_UNESCAPED_SLASHES
                        )

                ]
            );


        if (
            !isset($result['ok']) ||
            $result['ok'] !== true
        ) {

            return $result;
        }


        /*
        |--------------------------------------------------------------------------
        | Small delay between album chunks
        |--------------------------------------------------------------------------
        */

        if (
            $chunkIndex <
            count($chunks) - 1
        ) {

            sleep(1);
        }
    }


    return [

        'ok' => true

    ];
}


/*
|--------------------------------------------------------------------------
| SEND POST
|--------------------------------------------------------------------------
*/

function sendPost($item, $topicId)
{
    global $CHAT_ID;


    /*
    |--------------------------------------------------------------------------
    | CAPTION
    |--------------------------------------------------------------------------
    */

    $captionData =
        buildCaption(
            $item
        );


    $caption =
        $captionData['caption'];


    /*
    |--------------------------------------------------------------------------
    | VIDEO
    |--------------------------------------------------------------------------
    */

    if (
        $item['has_video']
    ) {

        $videoUrl =
            toFxTwitter(
                $item['url']
            );


        logMessage(
            'Video URL: ' .
            $videoUrl
        );


        return telegram(
            'sendVideo',
            [

                'chat_id' =>
                    $CHAT_ID,

                'message_thread_id' =>
                    $topicId,

                'video' =>
                    $videoUrl,

                'caption' =>
                    telegramCaption(
                        $caption
                    )

            ]
        );
    }


    /*
    |--------------------------------------------------------------------------
    | IMAGES
    |--------------------------------------------------------------------------
    */

    if (
        !empty(
            $item['images']
        )
    ) {

        $images =
            $item['images'];


        /*
        |--------------------------------------------------------------------------
        | ONE IMAGE
        |--------------------------------------------------------------------------
        */

        if (
            count($images) === 1
        ) {

            return telegram(
                'sendPhoto',
                [

                    'chat_id' =>
                        $CHAT_ID,

                    'message_thread_id' =>
                        $topicId,

                    'photo' =>
                        $images[0],

                    'caption' =>
                        telegramCaption(
                            $caption
                        )

                ]
            );
        }


        /*
        |--------------------------------------------------------------------------
        | MULTIPLE IMAGES
        |--------------------------------------------------------------------------
        */

        return sendAlbum(

            $images,

            $caption,

            $topicId

        );
    }


    /*
    |--------------------------------------------------------------------------
    | TEXT
    |--------------------------------------------------------------------------
    */

    return telegram(
        'sendMessage',
        [

            'chat_id' =>
                $CHAT_ID,

            'message_thread_id' =>
                $topicId,

            'text' =>
                $caption

        ]
    );
}


/*
|--------------------------------------------------------------------------
| LOAD SENT
|--------------------------------------------------------------------------
*/

if (
    file_exists(
        $SENT_FILE
    )
) {

    $sent =
        json_decode(

            file_get_contents(
                $SENT_FILE
            ),

            true

        );


    if (
        !is_array($sent)
    ) {

        $sent = [];
    }

} else {

    $sent = [];
}


/*
|--------------------------------------------------------------------------
| START
|--------------------------------------------------------------------------
*/

logMessage(
    'START'
);


foreach (
    $PAGES
    as $page
) {

    $username =
        $page['username'];


    $topicId =
        $page['topic_id'];


    logMessage(
        "\n================================"
    );


    logMessage(
        "PAGE: {$username}"
    );


    /*
    |--------------------------------------------------------------------------
    | RSS
    |--------------------------------------------------------------------------
    */

    $rssUrl =
        'https://nitter.net/' .
        rawurlencode(
            $username
        ) .
        '/rss';


    logMessage(
        "RSS: {$rssUrl}"
    );


    $rss =
        httpGet(
            $rssUrl
        );


    if (
        !$rss['ok']
    ) {

        logMessage(
            "RSS ERROR: {$rss['status']}"
        );


        logMessage(
            $rss['error']
        );


        continue;
    }


    logMessage(
        'RSS OK'
    );


    logMessage(
        'RSS LENGTH: ' .
        strlen(
            $rss['body']
        )
    );


    /*
    |--------------------------------------------------------------------------
    | XML
    |--------------------------------------------------------------------------
    */

    libxml_use_internal_errors(
        true
    );


    $xml =
        simplexml_load_string(
            $rss['body']
        );


    if (
        $xml === false
    ) {

        logMessage(
            'XML ERROR'
        );

        continue;
    }


    $items =
        $xml->channel->item;


    logMessage(
        'FOUND: ' .
        count($items) .
        ' POSTS'
    );


    /*
    |--------------------------------------------------------------------------
    | ITEMS
    |--------------------------------------------------------------------------
    */

    foreach (
        $items
        as $rssItem
    ) {

        $id =
            trim(
                (string)$rssItem->guid
            );


        if (
            $id === ''
        ) {

            continue;
        }


        $uniqueId =
            $username .
            ':' .
            $id;


        /*
        |--------------------------------------------------------------------------
        | ALREADY SENT
        |--------------------------------------------------------------------------
        */

        if (
            isset(
                $sent[$uniqueId]
            )
        ) {

            continue;
        }


        /*
        |--------------------------------------------------------------------------
        | TITLE
        |--------------------------------------------------------------------------
        */

        $title =
            cleanText(
                (string)$rssItem->title
            );


        /*
        |--------------------------------------------------------------------------
        | DESCRIPTION
        |--------------------------------------------------------------------------
        */

        $description =
            (string)$rssItem->description;


        $text =
            cleanText(
                $description
            );


        /*
        |--------------------------------------------------------------------------
        | Remove Video word
        |--------------------------------------------------------------------------
        */

        $text =
            preg_replace(
                '/\bVideo\b/i',
                '',
                $text
            );


        $text =
            trim(
                $text
            );


        /*
        |--------------------------------------------------------------------------
        | URL
        |--------------------------------------------------------------------------
        */

        $postUrl =
            trim(
                (string)$rssItem->link
            );


        /*
        |--------------------------------------------------------------------------
        | DATE
        |--------------------------------------------------------------------------
        */

        $date =
            parseDate(
                (string)$rssItem->pubDate
            );


        /*
        |--------------------------------------------------------------------------
        | MEDIA
        |--------------------------------------------------------------------------
        */

        $images =
            extractImages(
                $description
            );


        $video =
            hasVideo(
                $description
            );


        /*
        |--------------------------------------------------------------------------
        | ITEM
        |--------------------------------------------------------------------------
        */

        $item = [

            'id' =>
                $id,

            'title' =>
                $title,

            'text' =>
                $text,

            'url' =>
                $postUrl,

            'date' =>
                $date,

            'images' =>
                $images,

            'has_video' =>
                $video

        ];


        logMessage(
            "\nSending: {$id}"
        );


        logMessage(
            'Video: ' .
            (
                $video
                    ? 'YES'
                    : 'NO'
            )
        );


        logMessage(
            'Images: ' .
            count($images)
        );


        if (
            $date !== ''
        ) {

            logMessage(
                'Date: ' .
                $date
            );
        }


        /*
        |--------------------------------------------------------------------------
        | SEND
        |--------------------------------------------------------------------------
        */

        $result =
            sendPost(
                $item,
                $topicId
            );


        /*
        |--------------------------------------------------------------------------
        | SUCCESS
        |--------------------------------------------------------------------------
        */

        if (
            isset(
                $result['ok']
            ) &&
            $result['ok'] === true
        ) {

            logMessage(
                'TELEGRAM: OK'
            );


            /*
            |--------------------------------------------------------------------------
            | Keep in RAM
            |--------------------------------------------------------------------------
            */

            $sent[$uniqueId] =
                time();

        } else {

            logMessage(
                'TELEGRAM ERROR:'
            );


            logMessage(

                json_encode(

                    $result,

                    JSON_UNESCAPED_UNICODE |
                    JSON_PRETTY_PRINT

                )

            );
        }


        /*
        |--------------------------------------------------------------------------
        | Delay
        |--------------------------------------------------------------------------
        */

        sleep(2);
    }
}


/*
|--------------------------------------------------------------------------
| WRITE SENT ONCE
|--------------------------------------------------------------------------
*/

if (
    file_put_contents(

        $SENT_FILE,

        json_encode(

            $sent,

            JSON_UNESCAPED_UNICODE |
            JSON_PRETTY_PRINT

        ),

        LOCK_EX

    ) === false
) {

    logMessage(
        'WARNING: Could not write sent.json'
    );

} else {

    logMessage(
        'sent.json updated'
    );
}


logMessage(
    "\nDONE"
);