<?php
$CHANNEL_LIST = array(
'J' => array(
'name' => '翡翠台',
'license' => '0958b9c657622c465a6205eb2252b8ed:2d2fd7b1661b1e28de38268872b48480',
'logo' => 'https://github.com/wanglindl/TVlogo/blob/main/img/TVB1.png?raw=true'
),
'JUHD' => array(
'name' => '翡翠台 4K',
'license' => '2c045f5adb26d391cc41cd01f00416fa:fc146771a9b096fc4cb57ffe769861be',
'logo' => 'https://github.com/wanglindl/TVlogo/blob/main/img/TVB1.png?raw=true'
),
'B' => array(
'name' => 'TVBplus',
'license' => '56603b65fa1d7383b6ef0e73b9ae69fa:5d9d8e957d2e45d8189a56fe8665aaaa',
'logo' => 'https://raw.githubusercontent.com/wanglindl/TVlogo/main/img/TVB3.png'
),
'P' => array(
'name' => '明珠台',
'license' => 'e04facdd91354deee318c674993b74c1:8f97a629de680af93a652c3102b65898',
'logo' => 'https://github.com/wanglindl/TVlogo/blob/main/img/TVB1.png?raw=true'
),
'CWIN' => array(
'name' => 'Super Free',
'license' => '0737b75ee8906c00bb7bb8f666da72a0:15f515458cdb5107452f943a111cbe89',
'logo' => ''
),
'TVG' => array(
'name' => '黄金翡翠台',
'license' => '8fe3db1a24969694ae3447f26473eb9f:5cce95833568b9e322f17c61387b306f',
'logo' => 'https://github.com/sparkssssssssss/epg/blob/main/logo/%E9%BB%84%E9%87%91%E7%BF%A1%E7%BF%A0%E5%8F%B0.png?raw=true'
),
'C' => array(
'name' => '无线新闻台',
'license' => '90a0bd01d9f6cbb39839cd9b68fc26bc:51546d1f2af0547f0e961995b60a32a1',
'logo' => 'https://raw.githubusercontent.com/wanglindl/TVlogo/main/img/TVB4.png'
),
'CTVE' => array(
'name' => '娱乐新闻台',
'license' => '6fa0e47750b5e2fb6adf9b9a0ac431a3:a256220e6c2beaa82f4ca5fba4ec1f95',
'logo' => 'https://github.com/sparkssssssssss/epg/blob/main/logo/%E5%A8%B1%E4%B9%90%E6%96%B0%E9%97%BB%E5%8F%B0.png?raw=true'
),
'PCC' => array(
'name' => '凤凰卫视中文台',
'license' => '7bca0771ba9205edb5d467ce2fdf0162:eb19c7e3cea34dc90645e33f983b15ab',
'logo' => 'https://raw.githubusercontent.com/wanglindl/TVlogo/main/img/Phoenix1.png'
),
'PIN' => array(
'name' => '凤凰卫视资讯台',
'license' => '83f7d313adfc0a5b978b9efa0421ce25:ecdc8065a46287bfb58e9f765e4eec2b',
'logo' => 'https://raw.githubusercontent.com/wanglindl/TVlogo/main/img/Phoenix2.png'
),
'PHK' => array(
'name' => '凤凰卫视香港台',
'license' => 'cde62e1056eb3615dab7a3efd83f5eb4:b8685fbecf772e64154630829cf330a3',
'logo' => 'https://raw.githubusercontent.com/wanglindl/TVlogo/main/img/Phoenix3.png'
),
'EVT1' => array(
'name' => 'myTV SUPER直播足球1台',
'license' => 'e8ca7903e25450d85cb32b3057948522:d5db5c03608f5f6c8a382c6abcb829e4',
'logo' => ''
)
);
function get_mytvsuper($channel) {
global $CHANNEL_LIST;
if (!array_key_exists($channel, $CHANNEL_LIST)) {
return '频道代号错误';
}
$api_token = 'eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJib3NzX2lkIjoiODUwNDY0NTgwIiwiZGV2aWNlX3Rva2VuIjoiWHp6anMzYTVKTms2TFpnZmJQeFZHR2QzIiwiZGV2aWNlX2lkIjoiTldGalptSmxNREF0TkRJNU5TMDBaakV3TFRrNFl6QXRNbUkwT0RCbFpXRTJaVEV3IiwiZGV2aWNlX3R5cGUiOiJ3ZWIiLCJkZXZpY2Vfb3MiOiJicm93c2VyIiwiZHJtX2lkIjoiTldGalptSmxNREF0TkRJNU5TMDBaakV3TFRrNFl6QXRNbUkwT0RCbFpXRTJaVEV3IiwiZXh0cmEiOnsicHJvZmlsZV9pZCI6MX0sImlhdCI6MTcwOTgwNTA3NywiZXhwIjoxNzA5ODA4Njc3fQ.XG-C6gWxLgbBRQ3ttKn68AKMQLOg6SxTpbmHxXl_qI2dbjd1eFFmwB9kD1yd2N_X8HxLPBwJukD4lygIKxbBGrQQDY_1vNd76TldllaeE2BC3fUtc-kAFOU4JwbUkfFYsWVm3v2JP-YGM2GGlhFqN_3170WDAi2Gq-R0tZckeFNWk7jOSShqkE0E7L3eqJ09sDG76R-PCbdpnCIxaY_NXtoYRfIoVQZA9QysExUyO6hQGUxLaTvJDtflX_ZM3OiqTMndHp1p0cDsINnpFokD6Yby5XS18RjQ-Dn1XJznj7-sRjlaGgyIIBoJjxsR2oD5S8teA5S6x7w3Dv6uTO3bWVV9J60E6jguGVqKnSYJ4Rx8A1TgyUTT_g57key6UFIiEhkHYqk7s3H01V-lHffNp5zDo9UrCdaO6maW_ZeA85ohR6P1PMh9EakQ5A-vok60s2oqyokKHfyrQvcodsI-MTC9mKegjJzgV2-HBgyylyj6B2ewvE4icDD25UdspWgbc33NrRpe_kgPxgVKF4cgKCD-S1AT3WrOaqKnPfPvhqmlciwlpZrUqZg09BqcazWPoyWAp2nqf93H6tlDqMrtAQgvft3Nd8-cM7jYx-WvzqRrCRpZ8vRSv11UdezKzR2Jm4H64KTWbs3GxB5vboZaeypdEzQW6PipPpftqRnNMQU'; // 请自行获取
$headers = array(
'Accept: application/json',
'Authorization: Bearer ' . $api_token,
'Accept-Language: zh-CN,zh-Hans;q=0.9',
'Host: user-api.mytvsuper.com',
'Origin: https://www.mytvsuper.com',
'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/16.5.2 Safari/605.1.15',
'Referer: https://www.mytvsuper.com/',
'X-Forwarded-For: 210.6.4.148' // 香港原生IP 210.6.4.148
);
$params = array(
'platform' => 'android_tv',
'network_code' => $channel
);
$url = 'https://user-api.mytvsuper.com/v1/channel/checkout?' . http_build_query($params);
$context = stream_context_create(array('http' => array('header' => implode("\r\n", $headers))));
$response = file_get_contents($url, false, $context);
if ($response === false) {
return '请求失败';
}
$response_json = json_decode($response, true);
$profiles = $response_json['profiles'];
$play_url = '';
foreach ($profiles as $profile) {
if ($profile['quality'] === 'high') {
$play_url = $profile['streaming_path'];
break;
}
}
if (empty($play_url)) {
return '未找到播放地址';
}
$play_url = explode('&p=', $play_url)[0];
$license_key =$CHANNEL_LIST[ $channel]['license'];
$channel_name =$CHANNEL_LIST[ $channel]['name'];
$channel_logo =$CHANNEL_LIST[ $channel]['logo'];
$m3u_content = "#EXTINF:-1 tvg-id=\"" .$channel . "\" tvg-logo=\"" .$channel_logo . "\"," .$channel_name . "\n";
$m3u_content .= "#KODIPROP:inputstream.adaptive.manifest_type=mpd\n";
$m3u_content .= "#KODIPROP:inputstream.adaptive.license_type=clearkey\n";
$m3u_content .= "#KODIPROP:inputstream.adaptive.license_key=" .$license_key . "\n";
$m3u_content .=$play_url . "\n";
return $m3u_content;
}
// 创建或打开文件用于写入
$m3u_file = fopen('mytvfree.m3u', 'w');
// 写入 M3U 文件的头部
fwrite($m3u_file, "#EXTM3U\n");
// 遍历所有频道并写入每个频道的 M3U 内容
foreach ($CHANNEL_LIST as $channel_code => $channel_info) {
$m3u_content = get_mytvsuper($channel_code);
fwrite($m3u_file, $m3u_content);
}
// 关闭文件
fclose($m3u_file);
echo "所有频道的 M3U 播放列表已生成并保存为 'mytvfree.m3u'。";
?>
偷懒找群友之前分享的改的,缺的logo自己可以加加,php运行生成m3u,可用crontab -e每天定时运行更新即可,或其他方式自行修改,不懂问GPT
感谢分享,我给修改一下,实现免翻直接看。
这些mpd源的视频流本身没有被墙,但是解密的key所在的域名是vercel-php-clearkey-hex-base64-json.vercel.app 这边被屏蔽,所以,只要反代这个接口就可以实现播放。
首先去准备一个php,用来反代key的文本
<?php
$url = $_GET['url'] ?? '';
if (strpos($url, 'http') !== 0) {
$url = base64_decode($url);
}
$html_code = pachongbo($url);
echo $html_code;
function pachongbo($url){
$headers = [
'User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36'];
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_TIMEOUT, 100);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
?>
php存放在海外服务器中,接着上面那份python代码我修改如下
原来代码中的
m3uContent += `#KODIPROP:inputstream.adaptive.license_key=${licenseKey}\n`;
修改为
m3u_content += f"#KODIPROP:inputstream.adaptive.license_key=http://【你自己的服务器ip】/【上面那个php代码】.php?url=" + base64.b64encode(
license_key.encode('utf-8')).decode('utf-8') + "\n"
此目的为反代key
再把上面的程序主体部分,定义为一个循环函数,接着让这个函数每2小时运行一次,或者你可以自己修改。
def pachongbo():
# 创建或打开文件用于写入
with open('mytvfree.m3u', 'w', encoding='utf-8') as m3u_file:
# 写入 M3U 文件的头部
m3u_file.write("#EXTM3U url-tvg=\"http://【你自己的服务器ip】/【上面那个php代码】.php?url=https://xmltv.bph.workers.dev\"\n")
# 遍历所有频道并写入每个频道的 M3U 内容
for channel_code in CHANNEL_LIST.keys():
m3u_content = get_mytvsuper(channel_code)
m3u_file.write(m3u_content)
print("所有频道的 M3U 播放列表已生成并保存为 'mytvfree.m3u'。")
while True:
pachongbo()
time.sleep(7200) #2小时*60分钟*60秒
不用反代,直接根据API接口返回的内容替换key(如果这个key永远不变),或者在github复刻 https://github.com/samleong123/vercel-php-clearkey-hex-base64-json 这个项目然后vercel部署一次加自定义域名就行,worker代码也替换掉链接就行。
他代码里面例如翡翠台的是
'license_key': 'https://vercel-php-clearkey-hex-base64-json.vercel.app/api/results.php?keyid=0958b9c657622c465a6205eb2252b8ed&key=2d2fd7b1661b1e28de38268872b48480'
你访问这个vercel搭建的接口之后,得到的内容是
{ "keys":[ { "kty":"oct", "k":"/BRncamwlvxMtX/+dphhvg", "kid":"LARfWtsm05HMQc0B8AQW+g" } ], "type":"temporary" }
直接全部频道一个个换就行了,就不用走这个接口了
以下观点更新:经过测试暂时不清楚是否为worker被墙所致
====
另外是,你代码里面提供的EPG,我今天(2024年6月10日12:15:16)用OTT发现部分频道读不出EPG,放在浏览器里面显示XML代码有误,搜索发现出现错误的地方是节目名有个字符“&”,疑似是没有做处理
浏览器报错: This page contains the following errors: error on line 269 at column 22: xmlParseEntityRef: no name Below is a rendering of the page up to the first error.
该行内容:
<title>Kiki & Nuna 知識寶庫[粵/普]</title>
哦哦,你的意思是 tivimate 不支持下面这种写法是吗?
#KODIPROP:inputstream.adaptive.license_type=clearkey
#KODIPROP:inputstream.adaptive.license_key=e8ca7903e25450d85cb32b3057948522:d5db5c03608f5f6c8a382c6abcb829e4
实际上走https://vercel-php-clearkey-hex-base64-json.vercel.app/api/results.php这个页面去转换也是多余的, ,因为现在来说那个lincense_key是固定的,获取一次后写死在m3u里面,没必要每次请求就走一次; 我是直接把转换代码写在worker里面
license怎么获取的,想增加其他台
"interactive_channels": [
{
"network_code": "C2",
"channel_no": "83II",
"name_tc": "互動窗2",
"name_en": "Interactive Window 2"
},
{
"network_code": "C3",
"channel_no": "83I",
"name_tc": "互動窗1",
"name_en": "Interactive Window 1"
}
],
这是C频道的子频道,logo就用C的logo,c2和c3不是24小时活跃的,只有有临时直播才会活跃,当活跃时,可以在web,tv,ios三端进行切换。