PHP下载m3u8,合并视频

2023-11-16

主要使用CURL获取请求,代码:

将代码保存为m3u8-download.php,然后执行:

如果下载速度比较慢,要把Curl的超时时间设置长一点,防止出现超时丢数据。

c:\>php m3u8-download.php -u http://xxx/xxx.m3u8 -o 要保存为的文件名
<?php

if (!function_exists('curl_init')) {
    println('need Curl module. please install it!', true);
}

$options = getopt('u:o:b:rh');
if (isset($options['h'])) {
    $help = <<<EOT
-h 帮助
-u m3u8的URL
-o 输出文件,默认:out.mp4
-b 每批网络请求的数量,默认:10
-r 保留下载的临时文件
EOT;
}

if (!isset($options['u'])) {
    println('no .m3u8 file url', true);
}

$u = $options['u'];
$o = isset($options['o']) ? $options['o'] : 'out.mp4';
$b = isset($options['b']) ? $options['b'] : 10;
$r = isset($options['r']);

$url_blocks = array();
$dir = dirname(__FILE__) . '/tmp/' . md5($u);
$ts_dir = $dir . '/ts';
$url_file = $dir . '/url.txt';
$response_file = $dir . '/response.txt';
$list_file = $dir . '/url_list.txt';
$pos_file = $dir . '/pos.txt';

$block_index = $index = 0;
if (file_exists($list_file)) {
    println('load index file...');
    $url_blocks = require($list_file);

    if (is_file($pos_file)) {
        $pos = file_get_contents($pos_file);
        list($block_index, $index) = explode(':', $pos);
    }
} else {
    println('read index file...');

    if (!file_exists($ts_dir)) {
        mkdir($ts_dir, 0775, true);
    }

    file_put_contents($url_file, $u);
    $response = $header = $body = '';
    if (httpGet($u, $response, $header, $body)) {
        file_put_contents($response_file, $response);

        $files = trim(preg_replace('/^#.+[\r\n]+/m', '', $body));
        $urls = preg_split("/[\r\n]+/", $files);

        $block = array();
        foreach ($urls as $key => $item) {
            $block[] = fixUrl($u, $item);
            if (($key + 1) % $b == 0) {
                $url_blocks[] = $block;
                $block = array();
            }
        }
        $url_blocks[] = $block;

        file_put_contents($list_file, '<?php return ' . var_export($url_blocks, true) . ';');
    }
}

//print_r($url_blocks);
//exit;


if ($url_blocks) {
    println('download, please wait...');

    $max = count($url_blocks);
    for ($i = $block_index; $i < $max; $i++) {
        $contents = httpMultiGet($url_blocks[$i]);
        if ($contents) {
            foreach ($contents as $content) {
                file_put_contents($ts_dir . '/' . $index . '.ts', $content);
                file_put_contents($pos_file, $i . ':' . $index);
                $index++;
            }
        } else {
            $i--; // 有请求失败的,重试
        }
        progress($max, $i + 1);
    }

    println('merge file...');
    $fp = fopen($o, 'wb');
    if ($fp) {
        for ($i = 0; $i < $index; $i++) {
            $content = file_get_contents($ts_dir . '/' . $i . '.ts');
            fwrite($fp, $content);
            progress($index, $i + 1);
        }
        fclose($fp);
    }

    if (!$r) {
        println('clean tmp file...');
        for ($i = 0; $i < $index; $i++) {
            unlink($ts_dir . '/' . $i . '.ts');
        }
        unlink($pos_file);
        unlink($response_file);
    }

    println('done.', true);
} else {
    println('get index file fail.', true);
}

// ===============================
// functions
// ===============================

function println($string, $exit = false)
{
    echo $string . "\r\n";
    if ($exit) {
        exit();
    }
}

function progress($max, $current, $message = '')
{
    $p = 0;
    if ($current) {
        $p = round($current / $max * 100, 2);
    }
    printf("progress: [%-50s] %d%% {$message}\r", str_repeat('#', ceil($p / 2)), $p);
    if ($current == $max) {
        echo "\n";
    }
}

function fixUrl($current, $target)
{
    $target = str_replace('\\', '/', $target);
    if (false === strpos($target, '://')) {
        $current = str_replace('\\', '/', $current);

        $url_parts = parse_url($current);
        $host = $url_parts['scheme'] . '://' . $url_parts['host'] . (isset($url_parts['port']) ? ':' . $url_parts['port'] : '') . '/';

        if (0 === strpos($target, '//')) {
            return $url_parts['scheme'] . ':' . $target;
        } else {
            if (0 === strpos($target, '/')) {
                $url_path = '';
            } else {
                if (isset($url_parts['path'])) {
                    $url_path = $url_parts['path'];
                    if (false !== strpos($url_path, '.')) {
                        $url_path = (false !== ($pos = strrpos($url_path, '/'))) ? substr($url_path, 0, $pos + 1) : $url_path;
                    }
                }
            }

            $parts = explode('/', $url_path . $target);
            $arcv = array();
            foreach ($parts as $value) {
                if ($value !== '' && $value != '.') {
                    if ($value == '..') {
                        array_pop($arcv);
                    } else {
                        $arcv[] = $value;
                    }
                }
            }

            return $host . implode('/', $arcv);
        }
    }
    return $target;
}

function mkCurlHandler($url)
{
    $curl = curl_init();
    curl_setopt($curl, CURLOPT_HEADER, true);  //表示需要response header
    curl_setopt($curl, CURLOPT_NOBODY, false);
    curl_setopt($curl, CURLOPT_AUTOREFERER, true);
    curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($curl, CURLOPT_FOLLOWLOCATION, true);
    curl_setopt($curl, CURLOPT_CUSTOMREQUEST, 'GET');
    curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (X11; Linux x86_64; rv:71.0) Gecko/20100101 Firefox/71.0');
    curl_setopt($curl, CURLOPT_TIMEOUT, 120); // 时间长一些防止超时
    curl_setopt($curl, CURLOPT_REFERER, $url);
    curl_setopt($curl, CURLOPT_URL, $url);
    return $curl;
}

function httpGet($url, &$response, &$response_header, &$response_body)
{
    $curl = mkCurlHandler($url);
    $response = curl_exec($curl);
    $info = curl_getinfo($curl);

    $status = false;
    if ($info['http_code'] == 200) {
        $parts = explode("\r\n\r\n", $response, 2);
        if (count($parts) > 1) {
            list($response_header, $response_body) = $parts;
            $status = true;
        }
    }

    curl_close($curl);
    return $status;
}

function httpMultiGet($urls)
{
    $bodys = array();
    $handlers = array();
    $mh = curl_multi_init();
    foreach ($urls as $i => $url) {
        $handler = mkCurlHandler($url);
        curl_multi_add_handle($mh, $handler);
        $handlers[$i] = $handler;
    }

    $active = null;
    do {
        $mrc = curl_multi_exec($mh, $active);
    } while ($mrc == CURLM_CALL_MULTI_PERFORM);

    while ($active && $mrc == CURLM_OK) {  //直到出错或者全部读写完毕  
        if (curl_multi_select($mh) != -1) { // 防止CPU过高
            do {
                $mrc = curl_multi_exec($mh, $active);
            } while ($mrc == CURLM_CALL_MULTI_PERFORM);
        }
    }

    foreach ($handlers as $i => $handler) {
        //获取当前解析的cURL的相关传输信息
        //$info = curl_multi_info_read($mh);
        $heards = curl_getinfo($handler);
        $response = curl_multi_getcontent($handler);
        if ($heards['http_code'] == 200) {
            $parts = explode("\r\n\r\n", $response, 2);
            if (count($parts) > 1) {
                list($response_header, $response_body) = $parts;
                $bodys[] = $response_body;
                if ($response_body == '') {
                    return array();
                }
            } else {
                return array();
            }
        }

        curl_multi_remove_handle($mh, $handler);
        curl_close($handler);
    }

    curl_multi_close($mh);
    return $bodys;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PHP下载m3u8,合并视频 的相关文章

  • 将 XML 数据提取到 php [重复]

    这个问题在这里已经有答案了 我正在尝试从 XML 文件中提取数据 http freegeoip net xml google com http freegeoip net xml google com 您可以看到该文件的内容类似于
  • PHP if in_array 表示多个值

    我有一个由 3 到 12 个值之间的任意位置生成的数组 它根据帐户信息生成该数组 result ad gt user gt groups user username 我想检查这个数组是否有多个值 大约 4 或 5 个 如果其中有任何一个值
  • 在 PHP 中验证约 400MB 的大型 XML 文件

    我有一个很大的 XML 文件 大约 400MB 在开始处理之前我需要确保它的格式正确 我尝试的第一件事是类似于下面的内容 这很棒 因为我可以找出 XML 是否格式不正确以及 XML 的哪些部分 不好 doc simplexml load s
  • 同一页面中多个表单上的 Google 隐形 ReCaptcha - PHP

    我正在我的 php 网站上关注这个 Invisible ReCaptcha 文档 http www pinnacleinternet com installing invisible recaptcha http www pinnaclei
  • MySQL:更新所有行将字段设置为0,但将一行的字段设置为1

    是否有一种有效的方法将行字段的选择更新为 0 但根据 ID 将其中一行设置为 1 基本上 我在数据库中有多个对象 我想在其中一个 inuse 之间切换 因此查询将其中一行 按 id 设置为 inuse 1 将其他行设置为 inuse 0 谢
  • 命令运行时从 shell_exec 命令获取输出

    我正在编写一个 PHP 脚本网页 该网页旨在接受先前上传到服务器的 JFFS2 图像的文件名 然后 该脚本将使用映像重新刷新服务器上的分区 并输出结果 我一直在用这个 tmp shell exec update flash v filena
  • 上传非常大的文件(>5GB)

    我需要你的帮助 我想用 HTML JQuery 和 PHP 创建一个上传脚本 是否可以编写一个可以上传非常大的文件 gt 5 GB 的脚本 我已经尝试使用 FileReader FormData 和 Blobs 但即使使用这些 我也无法上传
  • phpunit --debug 仍然只显示点

    我想查看 phpunit 运行期间当前执行的测试 我用 debugparam 但仍然只得到点 phpunit debug PHPUnit 3 7 19 by Sebastian Bergmann Configuration read fro
  • 如何在 Yii 中设置 returnUrl 值

    我正在使用 Yii 我遇到的问题是Yii app gt user gt returnUrl 它总是让我回到index php page 由于我不知道用户从哪个页面访问了当前页面 如何将其值设置为请求当前页面的页面 您可以使用Yii app
  • 如何在MySQL选择查询中编写正则表达式?

    我尝试过这个表达 b word w b i比较一个word对照其他单词列表来查找重复项 我用了preg math all 效果很好 我想做同样的事情 但这次检查从 mysql 数据库检索到的单词 这是我写的 SELECT FROM tabl
  • PHP 中两个关联多维数组的值求和

    我正在尝试对两个关联数组的值求和 这是第一个数组 Array Jan 01 2013 gt Array COM gt 100 RES gt 200 Oct 28 2014 gt Array COM gt 300 RES gt 400 这是第
  • 迁移时未找到 Laravel 致命错误类

    我已经跑了artisan migrate reset 我删除了一些迁移文件 因为我不再需要这些表 I ran composer dump autoload其次是artisan dump autoload I ran artisan migr
  • 我可以在 Laravel 5.2 中创建一个继承自 User 的新类吗?

    我对 Laravel 还很陌生 使用的是迄今为止的最新版本 5 2 因此我遇到了以下困境 我知道 Laravel 附带了一个User开箱即用的类 但我想开发一个系统 在其中我可以有另外两种类型的用户 称为Researcher and Adm
  • 正则表达式:如何表达没有下划线的 \w

    有没有简洁的表达方式 w but without 即 w 中包含的所有字符 除了 我问这个是因为我正在寻找最简洁的方式来表达域名验证 域名可以包含小写和大写字母 数字 句号和破折号 但不能包含下划线 w 包括以上所有内容 加上下划线 那么
  • Laravel 更新雄辩事件:获取数据

    我一直在读有关雄辩事件的文章 与模型的每次交互都有一个事件 创建 创建 更新 更新 保存 保存 删除 删除 恢复 恢复 我想知道模型更新后的数据以及之前的数据 是否可以 因为文档没有太多关于如何使用这些事件的信息 您正在寻找getDirty
  • 如何找出当前正在运行的 PHP 可执行文件?

    在 PHP 程序内部 我想知道执行它的二进制文件的位置 Perl 有 X以此目的 PHP 中有等效的吗 这样它就可以使用自身执行子 PHP 进程 而不是硬编码路径或假设 php 是正确的 UPDATE 我使用的是lighttpd FastC
  • 无法下载 Windows 版 Composer SSL:握手超时

    这是我尝试安装 Windows 版 Composer 时得到的结果 The https getcomposer org versions https getcomposer org versions 无法下载文件 SSL 握手超时 无法启用
  • TCPDF - 来自 mysql 的打印表显示重复的第一行

    我是 TCPDF 的新手 我面临的小问题是所有输出数据都显示同一行 我的意思是第一条记录重复数据库中存在的总数据 行 的次数 这是我的代码 tbl header
  • 多个数据库连接

    我有三张桌子 categories content info and content The categories表包含类别的id及其 IDparent类别 The content info包含两列 entry id帖子的 ID 和cat
  • 未找到教义列:1054“字段列表”中未知列“s.features”

    我在站点表中添加了一个新列 features 并使用 Doctrine 重新生成了模型 此代码导致错误 siteTable Doctrine Core getTable Site site siteTable gt findOneByNam

随机推荐

  • 制作HTML5百科页面

    先建一个index html 首页 代码如下 p align center a href page01 html target self img src images index jpg alt 传智播客设计学院UI设计师 a p 首页的效
  • java学习之路——第一次java(java的入门)

    java学习之路 第一次java java的入门 一 什么是java java语言是一种强类型的语言 其中包含一套基本的符号 这些符号构成了java语言的表示符和关键字 是一个跨平台的面向对象的程序设计语言 由Sun Microsystem
  • 离散数学第一章总结

    离散数学第一章 1 公式类型 1 重言式 也是永真式 公式真值恒为1 2 矛盾式 永假式 真值恒为0 3 可满足式 不是矛盾式的就都是可满足式 重言式一定是可满足式 2 成真赋值与成假赋值 也叫成真指派与成假指派 一组原子的取值 真值指派
  • Tensorflow计算、数据和运行模型

    参考书籍 Tensorflow实战Google深度学习框架 郑泽宇等 Tensorflow是一款谷歌开源的深度学习工具 与其他深度学习工具 比如caffe Deeplearning4j等 相比 其受关注度和欢迎程度尤为突出 在谷歌内部 Te
  • 02-Node.js—Buffer(缓冲器)

    文章目录 1 概念 2 特点 3 创建Buffer 3 1 Buffer alloc 3 2 Buffer allocUnsafe 3 3 Buffer from 4 操作Buffer 4 1 Buffer 与字符串的转化 4 2 Buff
  • H264实时编码及NALU,RTP传输

    原文引用地址 http wmnmtm blog 163 com blog static 382457142011920102618122 fromdm fromSearch isFromSearchEngine yes H264实时编码及N
  • linux中find命令详解,Linux下的find指令详解

    在Linux下有很多查找指令 locate whereis which find 在这些查找指令中功能最强大的当属find指令了 find命令在目录结构中搜索文件 并执行指定的操作 Linux下find命令提供了相当多的查找条件 功能很强大
  • linux shell数据重定向(输入重定向与输出重定向)详细分析

    在了解重定向之前 我们先来看看linux 的文件描述符 linux文件描述符 可以理解为linux跟踪打开文件 而分配的一个数字 这个数字有点类似c语言操作文件时候的句柄 通过句柄就可以实现文件的读写操作 用户可以自定义文件描述符范围是 3
  • Vue计算属性:简化数据处理和视图更新的利器

    一 计算属性的基本使用 计算属性 一个特殊属性 值依赖于另外一些数据动态计算出来 计算属性特点 函数内使用的变量改变 重新计算结果返回 注意 计算属性必须定义在computed节点中 计算属性必须是一个function 计算属性必须有返回值
  • 基于STM32通过RTC唤醒低功耗模式

    一 低功耗模式 1 简介 通俗的来讲低功耗模式就是降低单片机的运行功耗 STM32F10xxx有三种低功耗模式 1 睡眠模式 Cortex M3 内核停止 所有外设包括 Cortex M3 核心的外设 如 NVIC 系统时 钟 SysTic
  • 解决Go-CQhttp无法登录(服务器如何登录)的问题

    既然你能看到这篇帖子 说明你一定对这个东西不陌生了 这是某讯的登录检查机制 解决方法 也很简单 保证手机与电脑处于同一wifi以内 那这时候有人叫要问了 可是我明明开了wifi 为什么还是登陆不了呢 麻烦你不要一边开wifi一边开数据 别问
  • 大数据技术炙手可热 专业人才短缺成发展掣肘

    大数据技术炙手可热 专业人才短缺成发展掣肘 2011 11 25 09 29 1765次阅读 已有0条评论 发表评论 来源 CSDN编译 作者 李智 收藏到我的网摘 导读 尽管还存在安全等问题 但Hadoop已经为部署在大企业中的大型项目做
  • 防止内存泄露 Linux下用Valgrind做检查

    用C C 开发其中最令人头疼的一个问题就是内存管理 有时候为了查找一个内存泄漏或者一个内存访问越界 需要要花上好几天时间 如果有一款工具能够帮助我们做这件事情就好了 valgrind正好就是这样的一款工具 Valgrind是一款基于模拟li
  • 数据建模,ODS模型分析

    根据ODS系统解决的不同的数据问题 将ODS模型将数据按三层进行管理 分别针对细节级数据 汇总型数据和分析型数据 每个区域有自己的管理重点 下面分别介绍 基础数据层 FDM FOUNDATION DATA MODLE 来源于标准化的各源系统
  • 计算机视觉基础:自适应阈值分割(Computer Vision Fundamentals: Adaptive Threshold Segmentation)

    前言 阈值分割方法虽然简单 但是如果场景简单 还是可以尝试使用的 因为其消耗的时间较少 同时 也可以作为一个baseline来验证提出的新算法是否有效 对于阈值分割 我们认为没有理由讲了 这里主要介绍两种自适应阈值分割方法 实际工程应用过程
  • 3dmax出现白屏解决方法

    3DMax 卡死 白屏 渲染死机问题总结 Deveuper的博客 CSDN博客 3dmax一渲染完就卡死 修改设置
  • 区块链技术的创新周期在不断缩短吗?

    有业内人士指出 区块链技术的发展可能要经过高峰 低谷和平复的过程 这也对金融监管部门提出了挑战 要在鼓励金融创新和防范风险之间找到平衡 从有利因素来看 区块链技术的创新周期在不断缩短 据介绍 金融科技定义是指技术驱动的金融创新 包括新业务模
  • 剑指 Offer 32 - II. 从上到下打印二叉树 II

    剑指 Offer 32 II 从上到下打印二叉树 II 题目 题目链接 解题思路 具体思路 具体代码 题目 题目链接 https leetcode cn com problems cong shang dao xia da yin er c
  • vue父子组件在不同情况下生命周期的执行顺序

    在分析父子组件生命周期之前 我们先核实一次两个路由 不包含子组件 之间切换 其生命周期的执行顺序 在这用到两个路由 新闻路由和top路由 名字只做区分 没有其他含义 1 首先切换到新闻路由 执行顺序 beforeCreate gt crea
  • PHP下载m3u8,合并视频

    主要使用CURL获取请求 代码 将代码保存为m3u8 download php 然后执行 如果下载速度比较慢 要把Curl的超时时间设置长一点 防止出现超时丢数据 c gt php m3u8 download php u http xxx