php无人值守录制抖音直播
>为了家中老人,老人有的时候不在家,关注的主播直播内容就容易错过,用python是可以录制,但是家中老人还不会弄电脑,就衍生了这个项目-_-!# 原理
1. 安装ffmpeg
2. php解析抖音直播地址
3. php调用ffmpeg将转换过来的直播地址进行录制
4. 添加定时任务,定时调用脚本
# 安装ffmpeg
我的环境是centos7.x,先更新下yum,采用yum的方式进行安装ffmpeg,先更新下当前yum
```shell
yum -y update
```
安装Nux Dextop Yum 源**(慎重操作)**
```shell
sudo rpm --import http://li.nux.ro/download/nux/RPM-GPG-KEY-nux.ro
sudo rpm -Uvh http://li.nux.ro/download/nux/dextop/el7/x86_64/nux-dextop-release-0-5.el7.nux.noarch.rpm
```
安装FFmpeg 和 FFmpeg开发包
```shell
sudo yum install ffmpeg ffmpeg-devel -y
```
测试ffmpeg是否成功安装
```shell
ffmpeg
```
*这里补充下,我的环境是宝塔环境,宝塔之前的一键包安装ffmpeg已经失效了,问题很多,在这里不建议大家采用宝塔的一键包,我现在的安装方案是采用宝塔论坛 `CentOS7宝塔面板安装ffmpeg视频切片模块``yaojiu`的安装方式。
# 解析抖音直播地址
这里的抖音直播源解析是通过我前一段时间写的`php抖音直播源抓取`进行的解析,原理就是所有的信息都在 `window.__INIT_PROPS__`这个部分当中,而这部分内容是json结构的,所以我们只要将这部分代码转为能够读取的json然后进行调用就可以,需要的小伙伴自行观看。
这里放上thinkphp抓取抖音直播源的源码:
```php
<?php
/****抖音直播解析接口*******/
namespace app\controller;
use app\BaseController;
use think\facade\Request;
class Douyin extends BaseController
{
public function index(){
$url=Request::param('url');
$html=$this->get_douyin($url);
preg_match_all('/window.__INIT_PROPS__ =(.*)<\/script><\/head>/', $html, $jsmatch);
if(!empty($jsmatch)){
$content=json_decode($jsmatch,1);
if(!empty($content['/webcast/reflow/:id']['room']['stream_url']['hls_pull_url'])){
$data=array(
'code'=>200,
'success'=>true,
'data'=>array(
'url'=>$content['/webcast/reflow/:id']['room']['stream_url']['hls_pull_url'],
'title'=>$content['/webcast/reflow/:id']['room']['title'],
'id'=>$content['/webcast/reflow/:id']['room']['id'],
'status'=>$content['/webcast/reflow/:id']['room']['status']
)
);
echo json_encode($data);
}else{
$data=array(
'code'=>400,
'success'=>false,
'msg'=>'数据接口请求失败'
);
echo json_encode($data);
}
}
}
privateget_douyin($url,$post='',$cookie='', $returnCookie=0,$header=array(),$referer=''){
$curl = curl_init();
if(!empty($header)){
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_HEADER, 0);//返回response头部信息
}
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); // 跳过证书验证(https)的网站无法跳过,会报错
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 跳过证书验证
curl_setopt($curl, CURLOPT_USERAGENT, 'Mozilla/5.0 (Linux; U; Android 8.1.0; en-US; Nexus 6P Build/OPM7.181205.001) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/12.11.1.1197 Mobile Safari/537.36');
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($curl, CURLOPT_AUTOREFERER, 1);
curl_setopt($curl, CURLOPT_REFERER, $referer);
if($post) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($post));
}
if($cookie) {
curl_setopt($curl, CURLOPT_COOKIE, $cookie);
}
curl_setopt($curl, CURLOPT_HEADER, $returnCookie);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
$data = curl_exec($curl);
if (curl_errno($curl)) {
return curl_error($curl);
}
curl_close($curl);
if($returnCookie){
list($header, $body) = explode("\r\n\r\n", $data, 2);
preg_match_all("/Set\-Cookie:([^;]*);/", $header, $matches);
$info['cookie']= substr($matches, 1);
$info['content'] = $body;
return $info;
}else{
return $data;
}
}
}
```
传递回来的参数为:
```json
{"code":200,"success":true,"data":{"url":"http:\/\/pull-hls-l6.douyincdn.com\/stage\/stream-685625243370782751_or4\/index.m3u8","title":"jonasen\u6b63\u5728\u76f4\u64ad","id":6986527143291637000,"status":2}}
```
# php调用ffmpeg进行录制
php如果直接调用ffmpeg是不行的,我们需要执行proc_open,proc_get_status,proc_close命令,所以要将php.ini中对应的命令启用。
我这里做了个自动判断直播状态,传递回来的参数中如果status不等于2的情况下,代表当前录播已经停止,所以执行一次停止直播的命令,虽然ffmpeg在抖音关播以后会自动停止(亲测),但是保险期间还是做了一个容错。
以下是我用thinkphp5测试过后的代码:
```php
<?php
/****抖音直播录制接口*******/
namespace app\controller;
use app\BaseController;
use think\facade\Request;
class Live extends BaseController
{
public function index(){
$url=Request::param('url');
$status=Request::param('status');//停止录播传个任意参数
$apiUrl="http://xx/Douyin?url=".$url;//获取抖音直播的接口,见本博客
$returnData=file_get_contents($apiUrl);
$data=json_decode($returnData,true);
if($data['code']==200){
if($data['data']['status']==2){
if(!empty($status)){
if(!file_exists($data['data']['id'].".txt")){
echo "当前直播不存在";
die();
}
$pid=file_get_contents($data['data']['id'].".txt");
proc_close(proc_open('kill -9 '.$pid, array(), $pipes));//杀死进程
unlink($data['data']['id'].".txt");
echo "已停止录播";
exit();
}
//判断当前直播是否正在录屏中
if(file_exists($data['data']['id'].".txt")){
echo "当前直播正在进行中";
die();
}
//直播正在进行中
$command="ffmpeg -i ".$data['data']['url']." -c copy -bsf:a aac_adtstoasc -f mp4 /www/wwwroot/当前网站路径/public/upload/".$data['data']['id'].".mp4 >/dev/null 2>&1 &";
$process = proc_open($command, array(),$pipes); //执行录屏命令
$var = proc_get_status($process); //获取命令进程信息
$pid = intval($var['pid'])+1;//pid就是进程ID,$var['pid']得到的ID比实际的少1
$pidFile = fopen($data['data']['id'].".txt", "w+");//创建当前任务信息文档
fwrite($pidFile, $pid);
fclose($pidFile);
echo "正在录播";
}else{
$pid=file_get_contents($data['data']['id'].".txt");
proc_close(proc_open('kill -9 '.$pid, array(), $pipes));//杀死进程
unlink($data['data']['id'].".txt");
echo "已停止录播";
exit();
//结束
echo "直播已经结束";
}
}else{
echo "未获取到直播信息";
}
}
}
```
# 计划任务
在宝塔中添加定时任务,访问地址为:
![请输入图片描述](https://www.jonasen.cn/usr/uploads/2021/07/149438287.png)
# 相关网址
开始直播:
http://xxx.cn/Live?url=https://v.douyin.com/et3Nt53/
结束直播:
http://xxx.cn/Live?url=https://v.douyin.com/et3Nt53/&status=1 这里需要补充下,使用该脚本,可以同时录播多个直播。 题主有个问题期待回复就是怎么同时录制多个直播呢,开一个ffmpeg录制CPU就已经跑满了 两个ffmpeg进程电脑基本跑不动了? 这个怎么解决呢? wzyl 发表于 2021-7-21 13:58
php果然是世界上最好的编程语言赞一个
最好的编程语言,为啥这么说? 谢谢大佬 厉害厉害,这个6.省一大堆事 谢谢大佬 厉害厉害。。试一下效果 相当牛逼。 谢谢分享!学习了
谢谢大佬分享 php果然是世界上最好的编程语言赞一个 :lol 太牛逼了!!!