西瓜资源

西瓜资源是个好东西

地址:https://xgzy.tv/

可能是新影视资源站的原因,真就做到了承诺的:

高清画质,更新最快,国内cdn加速,秒拖秒播!

而且广告也少,只在10分钟左右插入了一段菠菜广告。通过AI帮助对比很容易就可以找到每个视频都是在第150-152个片段插入的广告,也就是说让AI把m3u8文件里的这三个片段删除就可以做到去广告的效果。

去广告效果演示:《给阿嬷的情书》

去广告代码如下:

<?php
/**
 * M3U8处理工具
 * 功能:
 * 1. 获取m3u8文件内容(自动跟随302跳转,以最终地址为基准;若为主m3u8则自动转到第一个子m3u8)
 * 2. 固定移除第150-152个片段(连同其关联的#EXTINF等标签行)
 * 3. 按HLS规范将片段相对地址补全为完整URL(/开头用域名,其余用m3u8所在目录)
 * 4. 输出处理后的m3u8内容
 */

// 兼容PHP 7.x的前缀检查函数
if (!function_exists('str_starts_with')) {
    function str_starts_with($haystack, $needle) {
        return substr($haystack, 0, strlen($needle)) === $needle;
    }
}

// 设置错误报告
ini_set('display_errors', 1);
error_reporting(E_ALL);

// 设置响应头
header('Content-Type: application/x-mpegURL');
header('Access-Control-Allow-Origin: *'); // 允许跨域访问

// 检查是否提供了m3u8 URL参数
if (!isset($_GET['url']) || empty($_GET['url'])) {
    die('请提供m3u8文件URL');
}

$m3u8Url = $_GET['url'];

/**
 * 获取m3u8文件内容(自动跟随跳转)
 * @param string $url m3u8文件URL
 * @return array|null ['content' => 文件内容, 'url' => 跟随跳转后的最终URL],失败返回null
 */
function getM3u8Content($url) {
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, $url);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); // 忽略SSL证书验证
    curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
    curl_setopt($ch, CURLOPT_TIMEOUT, 30);
    curl_setopt($ch, CURLOPT_HTTPHEADER, [
        'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36',
        'Accept: */*',
    ]);

    $content = curl_exec($ch);

    if (curl_errno($ch)) {
        error_log('获取m3u8失败: ' . curl_error($ch));
        curl_close($ch);
        return null;
    }

    $statusCode = curl_getinfo($ch, CURLINFO_RESPONSE_CODE);
    $effectiveUrl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
    curl_close($ch);

    // HTTP错误状态直接视为失败,避免把错误页当m3u8处理
    if ($statusCode >= 400) {
        error_log("获取m3u8失败: HTTP {$statusCode} - {$effectiveUrl}");
        return null;
    }

    // 内容校验:必须包含#EXTM3U标记
    if (strpos($content, '#EXTM3U') === false) {
        error_log("获取m3u8失败: 返回内容不是有效的m3u8格式 - {$effectiveUrl}");
        return null;
    }

    return ['content' => $content, 'url' => $effectiveUrl];
}

/**
 * 按HLS规范将相对地址解析为完整URL
 * - 绝对地址(http://、https://)直接返回
 * - 以/开头按域名根路径解析
 * - 其他相对路径按m3u8所在目录解析(支持../、./)
 * @param string $baseUrl m3u8文件URL(跳转后的最终地址)
 * @param string $relative 片段或子m3u8的地址
 * @return string 完整URL
 */
function resolveUrl($baseUrl, $relative) {
    if (str_starts_with($relative, 'http://') || str_starts_with($relative, 'https://')) {
        return $relative;
    }

    $parts = parse_url($baseUrl);
    $scheme = $parts['scheme'] ?? '';
    $host = $parts['host'] ?? '';
    $port = isset($parts['port']) ? ':' . $parts['port'] : '';
    $origin = "{$scheme}://{$host}{$port}";

    if (str_starts_with($relative, '/')) {
        return $origin . $relative;
    }

    // 取m3u8所在目录并拼接相对路径
    $path = $parts['path'] ?? '/';
    $dir = substr($path, 0, (int)strrpos($path, '/') + 1);

    // 规范化路径中的 ../ 和 ./
    $segments = explode('/', $dir . $relative);
    $resolved = [];
    foreach ($segments as $segment) {
        if ($segment === '..') {
            array_pop($resolved);
        } elseif ($segment !== '.') {
            $resolved[] = $segment;
        }
    }

    return $origin . implode('/', $resolved);
}

/**
 * 从主m3u8中提取第一个子m3u8地址(#EXT-X-STREAM-INF标签后的URI行)
 * @param string $content 主m3u8内容
 * @return string|null 子m3u8地址或null
 */
function getFirstStreamUri($content) {
    $lines = explode("\n", $content);
    $lineCount = count($lines);
    for ($i = 0; $i < $lineCount; $i++) {
        $trimmedLine = trim($lines[$i]);
        if (str_starts_with($trimmedLine, '#EXT-X-STREAM-INF')) {
            // 子m3u8地址为该标签后的下一个非空、非注释行
            for ($j = $i + 1; $j < $lineCount; $j++) {
                $uriLine = trim($lines[$j]);
                if ($uriLine !== '' && !str_starts_with($uriLine, '#')) {
                    return $uriLine;
                }
            }
        }
    }
    return null;
}

/**
 * 处理m3u8内容,移除第150-152个片段并将片段地址补全为完整URL
 * @param string $content m3u8文件内容
 * @param string $m3u8Url 该m3u8文件自身的URL(跳转后的最终地址)
 * @return string 处理后的m3u8内容
 */
function processM3u8Content($content, $m3u8Url) {
    // 固定移除第150-152个片段(从1开始计数)
    $removeFrom = 150;
    $removeTo = 152;

    // 按行分割内容
    $lines = explode("\n", $content);

    // 标记要删除的行
    $linesToDelete = [];

    // 找到要移除的片段及其关联的标签行(如#EXTINF、#EXT-X-BYTERANGE等)
    $segmentIndex = 0;
    $groupStart = 0; // 当前片段关联标签行的起始位置
    foreach ($lines as $index => $line) {
        $trimmedLine = trim($line);
        if ($trimmedLine !== '' && !str_starts_with($trimmedLine, '#')) {
            // 片段URI行
            $segmentIndex++;
            if ($segmentIndex >= $removeFrom && $segmentIndex <= $removeTo) {
                // 删除该片段的关联标签行及URI行(保留#EXT-X-DISCONTINUITY作为切割边界的编码切换提示)
                for ($j = $groupStart; $j <= $index; $j++) {
                    if (str_starts_with(trim($lines[$j]), '#EXT-X-DISCONTINUITY')) {
                        continue;
                    }
                    $linesToDelete[$j] = true;
                }
            }
            $groupStart = $index + 1;
        }
    }
    
    // 重新构建m3u8内容,同时为ts文件添加前缀
    $processedLines = [];
    foreach ($lines as $index => $line) {
        // 跳过要删除的行
        if (isset($linesToDelete[$index])) {
            continue;
        }
        
        // 将片段地址按HLS规范补全为完整URL
        $trimmedLine = trim($line);
        if (!empty($trimmedLine) && !str_starts_with($trimmedLine, '#')) {
            $processedLines[] = resolveUrl($m3u8Url, $trimmedLine);
        } else {
            $processedLines[] = $line;
        }
    }
    
    return implode("\n", $processedLines);
}

// 获取主m3u8内容
$master = getM3u8Content($m3u8Url);

if ($master === null) {
    die('无法获取m3u8文件内容');
}

// 以跟随跳转后的最终地址为基准
$m3u8Content = $master['content'];
$m3u8Url = $master['url'];

// 若为主m3u8(包含#EXT-X-STREAM-INF),则取第一个子m3u8地址并再次获取
if (strpos($m3u8Content, '#EXT-X-STREAM-INF') !== false) {
    $subM3u8Uri = getFirstStreamUri($m3u8Content);

    if ($subM3u8Uri === null) {
        die('主m3u8中未找到子m3u8地址');
    }

    // 按HLS规范解析子m3u8地址
    $subM3u8Url = resolveUrl($m3u8Url, $subM3u8Uri);

    // 获取子m3u8内容
    $sub = getM3u8Content($subM3u8Url);

    if ($sub === null) {
        die('无法获取子m3u8文件内容');
    }

    // 以子m3u8跳转后的最终地址为基准
    $m3u8Content = $sub['content'];
    $m3u8Url = $sub['url'];
}

// 处理m3u8内容
$processedContent = processM3u8Content($m3u8Content, $m3u8Url);

// 输出处理后的内容
echo $processedContent;

使用方法

将代码另存为xgzy.php,访问:xgzy.php?url=

例如放在网站根目录:

https://youdomain.com/xgzy.php?url=https://svip.xgplay17.com/2026-08-31/37579_YAI_uDcRGlnxTtKkyo/index.m3u8

后话

以前的电影天堂资源站刚开始也是承诺高速CDN、无广告,可能是因为运营成本大,没有盈利点,后来视频变卡了,也添加了菠菜广告。

也就是说,西瓜资源随着用户量增长,服务器成本和盈利压力可能会迫使站点削减 CDN 质量,视频广告规则也可能会变化,所以这个去广告的方法也不知道能用多久。

评论 (4)

2broear
2broear 2026-09-09 20:20

可以可以,感谢分享

xiao
xiao 作者 2026-09-10 01:11

ai写的代码,有点粗糙,反正思路没问题,可以再优化一下

花非花
花非花 2026-09-09 09:41

叫瓜的还挺多的,以前好像有个南瓜影视

xiao
xiao 作者 2026-09-10 01:09

什么时候出个苦瓜视频,哈哈