<?php
/**
 * 资源点采集器（独立脚本，由后台按钮 AJAX 调用）
 * 核心逻辑见 collect_lib.php
 */

ignore_user_abort(true);
set_time_limit(0);
date_default_timezone_set('PRC');
header('Content-Type: application/json; charset=utf-8');

require_once __DIR__ . '/collect_lib.php';

$action = isset($_GET['action']) ? $_GET['action'] : '';

if ($action === 'bind') {
    $r = bind_categories();
    echo json_encode($r);
    exit;
}

if ($action === 'collect') {
    // 每类采集条数：默认 1000，站长可输入，上限 5000
    $per = isset($_GET['per']) ? intval($_GET['per']) : 1000;
    if ($per < 1) $per = 1000;
    if ($per > 5000) $per = 5000;

    // 输入数不超过站内现有条数时，再采没有意义，直接提示站长改数字。
    // 例：站里每类都是 500 条，输入 400 -> 弹提示；输入 600 -> 每类补 100 条。
    $pre_type = @json_decode(@file_get_contents(__DIR__ . '/type.php'), true);
    if (is_array($pre_type) && !empty($pre_type)) {
        $pre_ids = array();
        foreach ($pre_type as $c) {
            $cid = (int)$c['id'];
            if ($cid > 0) $pre_ids[] = $cid;
        }
        if (!empty($pre_ids)) {
            $pre_counts = array();
            if (function_exists('ppq_read_type_counts')) {
                $pre_counts = ppq_read_type_counts($pre_ids);
            }
            $min_have = -1;
            foreach ($pre_ids as $cid) {
                if (isset($pre_counts[$cid])) {
                    $n = (int)$pre_counts[$cid];
                } else {
                    $items = @json_decode(@file_get_contents(__DIR__ . '/Home/' . $cid . '.txt'), true);
                    $n = is_array($items) ? count($items) : 0;
                }
                if ($min_have < 0 || $n < $min_have) $min_have = $n;
            }
            if ($min_have >= 0 && $per <= $min_have) {
                echo json_encode(array(
                    'ok'  => false,
                    'msg' => '网站里每个分类的视频数已达到或超过你输入的数字（当前最少 ' . $min_have . ' 条/类），请输入更大的数字。'
                ), JSON_UNESCAPED_UNICODE);
                exit;
            }
        }
    }

    // 记住站长这次填的"每类采集多少条"，下次打开后台输入框直接带出来
    $cfgFile = __DIR__ . '/Admin/Basic/AdminBasic.php';
    $cfgArr  = @json_decode((string)@file_get_contents($cfgFile), true);
    if (!is_array($cfgArr)) $cfgArr = array();
    $cfgArr['CollectPerCategory'] = $per;
    @file_put_contents($cfgFile, json_encode($cfgArr, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT));

    // Manual collection and the daily updater share the same status file and
    // Home/*.txt files. Serialize both jobs so their progress cannot mix.
    $collect_lock_fp = @fopen(__DIR__ . '/update.lock', 'c+');
    if (!$collect_lock_fp || !@flock($collect_lock_fp, LOCK_EX | LOCK_NB)) {
        if ($collect_lock_fp) @fclose($collect_lock_fp);
        echo json_encode(array('ok' => false, 'msg' => '已有采集或更新任务正在执行，请稍后再试'), JSON_UNESCAPED_UNICODE);
        exit;
    }
    register_shutdown_function(function() use ($collect_lock_fp) {
        @flock($collect_lock_fp, LOCK_UN);
        @fclose($collect_lock_fp);
    });

    // Acknowledge the AJAX request before detaching it. Without this response
    // jQuery treats the intentionally closed FastCGI request as a failure even
    // while the background collector continues and finishes successfully.
    echo json_encode(array('ok' => true, 'started' => true), JSON_UNESCAPED_UNICODE);
    if (function_exists('fastcgi_finish_request')) {
        if (ob_get_level()) { @ob_end_flush(); }
        fastcgi_finish_request();
    }

    $api = get_collection_api();
    if (!$api) { write_status(array('状态' => '失败', '原因' => '未配置采集点地址')); exit; }

    $type_raw = @json_decode(@file_get_contents(__DIR__ . '/type.php'), true);
    if (!is_array($type_raw) || empty($type_raw)) {
        write_status(array('状态' => '失败', '原因' => 'type.php 无分类数据，请先绑定分类'));
        exit;
    }

    // 请求时期望的每页条数。服务端不一定认（实测固定返回 20），
    // 实际每页条数与总页数一律以接口返回的 limit / pagecount 为准。
    $PAGE_LIMIT = 50;
    $MAX_PAGES  = 500;      // 翻页硬上限，防止接口异常时无限循环
    $PAGE_DELAY = 250000;   // 翻页间隔（微秒），避免请求过快被资源站限流
    $total_collected = 0;
    $start_time = date('Y-m-d H:i:s');
    $detail_fails = 0;

    write_status(array('状态' => '采集中', '开始时间' => $start_time, '总条数' => 0, '分类明细' => array()));

    if (!is_dir($HOME_DIR)) { mkdir($HOME_DIR, 0777, true); }

    // 采集永远只做增量：在现有数据上补到 $per 条，原有的一条不动。
    // 换资源点时的清空交给"绑定分类"——bind_categories() 一旦发现资源点地址
    // 或分类结构变了，会先把站内旧视频清干净再绑定，所以这里不需要"清空重采"。
    $mode = 'topup';

    foreach ($type_raw as $cat) {
        $cat_id   = (int)$cat['id'];
        $cat_name = isset($cat['name']) ? $cat['name'] : ('分类' . $cat_id);

        // topup 模式：从已有数据起步，只补差额
        $buffer = array();
        $id_map = array();
        if ($mode === 'topup') {
            $existing = @json_decode(@file_get_contents($HOME_DIR . '/' . $cat_id . '.txt'), true);
            if (is_array($existing)) {
                $buffer = $existing;
                foreach ($existing as $e) { $id_map[(string)$e['d_id']] = true; }
            }
        }
        $collected = count($buffer);
        $pg = 1;            // 页码独立递增，不再由累加量除以常量倒推
        $page_count = 0;    // 接口告知的总页数，0 表示尚未拿到
        $api_total  = 0;    // 接口告知的该分类资源总量
        $reached_end = false;

        while ($collected < $per && $pg <= $MAX_PAGES) {
            $j = json_decode(http_get($api . '/?ac=list&pg=' . $pg . '&limit=' . $PAGE_LIMIT . '&t=' . $cat_id), true);
            if (!$j || empty($j['list']) || !is_array($j['list'])) { $reached_end = true; break; }
            $list = $j['list'];
            if (empty($list)) { $reached_end = true; break; }

            if ($page_count <= 0) {
                $page_count = isset($j['pagecount']) ? (int)$j['pagecount'] : 0;
                $api_total  = isset($j['total']) ? (int)$j['total'] : 0;
            }

            foreach ($list as $item) {
                if ($collected >= $per) break;
                $vid = isset($item['vod_id']) ? $item['vod_id'] : 0;
                if (!$vid) continue;
                if ($mode === 'topup' && isset($id_map[(string)$vid])) continue; // 补齐模式：库里已有的跳过
                $play_url = '';
                $pic_url = parse_pic($item);
                if (!empty($item['vod_play_url'])) $play_url = parse_play_url($item['vod_play_url']);
                // Some resources omit vod_pic in their list endpoint but provide it
                // in the detail endpoint. Fetch details when either field is absent.
                if (!$play_url || !$pic_url) {
                    $dj = json_decode(http_get($api . '/?ac=detail&ids=' . $vid), true);
                    if ($dj && !empty($dj['list'][0])) {
                        $detail = $dj['list'][0];
                        if (!$play_url && !empty($detail['vod_play_url'])) $play_url = parse_play_url($detail['vod_play_url']);
                        if (!$pic_url) $pic_url = parse_pic($detail);
                    } elseif (!$play_url) { $detail_fails++; }
                }
                $play_url = ppq_resolve_play_url($play_url);
                $buffer[] = array(
                    'd_id' => (string)$vid, 'd_type' => (string)$cat_id,
                    'd_name' => isset($item['vod_name']) ? $item['vod_name'] : '',
                    'd_pic' => $pic_url,
                    'd_playurl' => $play_url,
                    'd_time' => isset($item['vod_time']) ? $item['vod_time'] : date('Y-m-d H:i:s')
                );
                $collected++;
            }

            // 已经翻到接口告知的最后一页，没有更多数据了
            if ($page_count > 0 && $pg >= $page_count) { $reached_end = true; break; }

            $pg++;
            usleep($PAGE_DELAY);
        }

        @file_put_contents($HOME_DIR . '/' . $cat_id . '.txt', json_encode($buffer, JSON_UNESCAPED_UNICODE));
        $total_collected += $collected;

        // 只有"确实翻到了最后一页"才叫资源到底；
        // 没采满又没到底，属于中途中断，不再笼统报"资源不足"。
        if ($collected >= $per) {
            $note = 'OK';
        } elseif ($reached_end) {
            $note = '已到资源末尾';
        } else {
            $note = '未采满，可能中途中断';
        }

        $status = @json_decode(@file_get_contents($STATUS_FILE), true);
        if (!is_array($status)) $status = array();
        $status['状态'] = '采集中';
        $status['总条数'] = $total_collected;
        $status['分类明细'][] = array(
            'name' => $cat_name, '期望' => $per, '实际' => $collected,
            '资源总量' => $api_total, '模式' => '增量补齐',
            '备注' => $note
        );
        write_status($status);
    }

    $status = @json_decode(@file_get_contents($STATUS_FILE), true);
    if (!is_array($status)) $status = array();
    $status['状态'] = '完成';
    $status['结束时间'] = date('Y-m-d H:i:s');
    $status['总条数'] = $total_collected;
    $status['播放地址获取失败数'] = $detail_fails;
    write_status($status);
    if (function_exists('ppq_write_type_counts')) ppq_write_type_counts();
    ppq_refresh_home_slots();
    exit;
}

// 默认：返回状态文件（前端展示用），并附带绑定状态
$status = @json_decode(@file_get_contents($STATUS_FILE), true);
if (!is_array($status)) $status = array('状态' => '无记录');
$status['is_bound'] = is_bound();
$status['bound_api'] = '';
$bs = @json_decode(@file_get_contents($TMP_DIR . '/bind_state.json'), true);
if (is_array($bs)) $status['bound_api'] = $bs['bound_api'];
echo json_encode($status);
exit;
