|
本帖最后由 op351 于 2023-12-3 17:16 编辑
上一个帖子中 我们分析并复现了江苏电信iptv的用户认证,回看源的获取
https://www.right.com.cn/forum/thread-8314231-1-1.html
那么在我们获取到认证的回看源地址之后 应该如何便捷的在电视上进行播放呢?
这里就要用到本坛认证播放器之一tvbox
tvbox的功能之一便是通过抓取数据源来播放视频网站的视频 简单的说 tvbox内部可以实现一个爬虫
而江苏电信iptv这套认证并获取回看源的过程就可以用爬虫来完全模拟并重现
在开始分析之前让我们先看一下最终的效果
首页
七天回放详情页
回放视频播放页
以下内容需具备一定的编程基础
步骤1
下载猫影视TV客户端爬虫自定义接口工程,也就是现在的tvbox壳配置对应的爬虫生成工程
网址为https://github.com/CatVodTVOfficial/CatVodTVSpider
此工程生成的jar文件即为各位所熟知的tvbox的配置源里的第一个地址中的json文件中所引用的jar包
在json文件中,此jar包对应的配置为
"spider": "./xxxx.jar;md5;xxxx",
步骤2
下载AndroidStudio或intellij
这里我们以AndroidStudio为例进行分析
将CatVodTVSpider-master导入到AndroidStudio中
由于此工程没有导入junit测试框架 不利于我们编写代码之后的单元测试
所以首先需要导入junit4(不要导入junit5 不支持)
导入方法如下
1.切换导航目录到project模式
2.打开文件java/com/github/catvod/spider/Aidi.java
在文件中右键-Go to-Test
这里我们选择junit4 若工程中未安装 as会进行提示 按照提示进行安装即可
接下来我们点击ok,as会自动生成一个单元测试class
步骤3
在spider包下新建class 这里以JiangSutv为例
步骤4
在上一篇帖子中 江苏电信iptv认证的第一关便是CTCGetAuthInfo
在这一步中我们需要获取CTCGetAuthInfo的入参
新建方法 cTCGetAuthInfo
直接复制postman生成的java代码
- OkHttpClient client = new OkHttpClient().newBuilder()
- .build();
- MediaType mediaType = MediaType.parse("text/plain");
- RequestBody body = RequestBody.create(mediaType, "");
- Request request = new Request.Builder()
- .url("http://itv.jsinfo.net:8298/auth?UserID=xxxxx&Action=Login&Mode=MENU")
- .method("GET", body)
- .addHeader("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8")
- .addHeader("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; SkyworthBrowser) AppleWebKit/534.24 (KHTML, like Gecko) Safari/534.24 SkWebKit-JS-CTC")
- .addHeader("Accept-Encoding", "gzip,deflate")
- .addHeader("Accept-Language", "zh-cn,en-us,en")
- .build();
- Response response = client.newCall(request).execute();
复制代码 在获取到报文返回值之后,利用正则表达式提取CTCGetAuthInfo
- String body = response.body().string();
- Pattern authinfoPattern = Pattern.compile("CTCGetAuthInfo\\('(\\d*)'\\)");
- Matcher authinfoMatch = authinfoPattern.matcher(body);
- authinfoMatch.find();
- String authinfo = authinfoMatch.group(1);
- if (StringUtils.isNotEmpty(authinfo)) {
- return authinfo;
- }
复制代码 在获取到值authinfo之后进行返回
步骤5
在获取到authinfo之后,便开始对“任意8位数$CTCGetAuthInfo入参$iptv账号$序列号$ip地址$mac地址$$CTC”进行加密
这里出现了另一个问题,程序无法实时获取openwrt iptv口的ip
解决方法如下
利用openwrt的cgi接口获取
1.通过xshell连接openwrt
2.切换到/www/cgi-bin
3.新建文件iptvip
4.chmod+x
5.在文件中写入如下内容(ucode为openwrt22.03之后导入的新工具,22.03之前版本的openwrt请使用lua或其他工具实现)
- #!/usr/bin/env ucode
- 'use strict';
- import * as fs from 'fs';
- let fp = fs.popen('ubus call network.interface.iptv status | grep \'"address"\: "\' | grep -oE \'([0-9]{1,3}.){3}.[0-9]{1,3}\'');
- let iptvip = fp.read("all");
- print("Content-type: text/html\n\n");
- print(iptvip);
复制代码 6.保存,访问http://路由器地址/cgi-bin/iptvip 返回值即为iptv口的ip
下面我们回到加密
新建方法setAuthenticator
插入如下代码
- String ip = getIp();
- String authInfo = cTCGetAuthInfo();
- String str = "随机6位数$" + authInfo + "$" + userId + "$" + stbId + "$" + ip + "$" + mac + "$$CTC";
- byte[] result = encrypt(str.getBytes(), password);
- System.out.println("加密后:----" );
- System.out.println("加密后:----" + new String(byteToHex(result).toUpperCase()));
- Authenticator = new String(byteToHex(result).toUpperCase());
复制代码 getIp方法为http://路由器地址/cgi-bin/iptvip返回的ip值采集方法 这里不再详细展开 请自行利用postman生成的java代码实现
我们对encrypt方法进行展开描述
- static byte[] encrypt(byte[] datasource, String password) {
- try {
- DESKeySpec desKey = new DESKeySpec(password.getBytes());
- // 创建一个密匙工厂,然后用它把DESKeySpec转换成
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance("DES");
- SecretKey securekey = keyFactory.generateSecret(desKey);
- // Cipher对象实际完成加密操作
- Cipher cipher = Cipher.getInstance("DES/ECB/PKCS5Padding");
- // 用密匙初始化Cipher对象
- cipher.init(Cipher.ENCRYPT_MODE, securekey);
- // 现在,获取数据并加密
- // 正式执行加密操作
- return cipher.doFinal(datasource);
- } catch (Throwable e) {
- e.printStackTrace();
- }
- return null;
- }
复制代码 password为机顶盒密码 参考上一个帖子
最后的Authenticator赋值之前请将加密的byte数组转换为hex之后再转换为大写,实现方法请自行谷歌或百度搜索
在获取到Authenticator之后,即可请求uploadAuthInfo以获取usertoken
实现方法如cTCGetAuthInfo方法,先获取报文后,直接提取报文header中的Set-Cookie字段即可,不再赘述。
步骤6
JSESSIONID获取(setJSESSIONID方法)
1.请求getServiceList,利用正则提取返回报文body中的UserGroupNMB url值。
2.请求UserGroupNMB url,利用正则提取返回报文body中的loadbalance url值。
3.请求loadbalance url,直接提取返回报文head中的X-Frame-Sessionid值。
实现方法如cTCGetAuthInfo,不再赘述。
步骤七
新建iptvAuth方法
1.调用setAuthenticator设置usertoken
2.调用setJSESSIONID设置JSESSIONID
3.访问3个直播认证url完成认证
/iptvepg/function/funcportalauth.jsp
/iptvepg/function/frameset_judger.jsp
/iptvepg/function/frameset_builder.jsp
实现方法如cTCGetAuthInfo,不再赘述。
步骤八
新建huikan方法
1.访问huikan_detail
2.
访问get_channel_tvod_data
存储返回报文的body
步骤9
继承java/com/github/catvod/crawler/Spider.java
重写首页数据内容生成方法homeContent
1.调用huikan方法获取频道数据并转换成jsonarray对象 channelJson
2.遍历channelJson
- for(int i = 0;i < channelJson.length(); i++) {
- String channelName = channelJson.getJSONObject(i).get("name").toString();
- String channelId = channelJson.getJSONObject(i).get("chanid").toString();
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("vod_id", channelId);
- jsonObject.put("vod_name", channelName);
- jsonObject.put("vod_pic", "");
- jsonObject.put("vod_remarks", "");
- classes.put(jsonObject);
- }
- JSONObject result = new JSONObject();
- JSONObject jsonObject1 = new JSONObject();
- jsonObject1.put("type_id", "efef");
- jsonObject1.put("type_name", "test");
- JSONArray videos = new JSONArray();
- videos.put(jsonObject1);
- result.put("class", videos);
- if (filter) {
- // result.put("filters", filterConfig);
- }
- result.put("list", classes);
- return result.toString();
复制代码 这里我们设置vod_id和vod_name即可,分别代表channelJson中的chanid和name
特别注意的是 我们要在class标签下设置一个空的对象以避免首页数据不显示
在这个方法写完之后
我们即可进行第一次打包
打包完成后注意将md5也复制到spider值中
sites值如以下示例所示
- "sites": [
- {
- "key": "csp_JiangSutv",
- "name": "江苏IPTV",
- "type": 3,
- "api": "csp_JiangSutv",
- "searchable": 0,
- "quickSearch": 0,
- "filterable": 0
- }
- ],
复制代码 将json文件和jar包放置到网盘或个人网站或其他机顶盒可访问地址中
打开tvbox 设置源地址为你自己生成的json
示例使用了https://github.com/takagen99/Box 版tvbox
需要先进入设置界面 将推荐设置为站点推荐,关闭窗口预览
在以上设置完成后,你将解锁第一个成就 一个展示了所有可回看频道的首页 如下所示
下面我们进入详情页面的代码编写
我们需要重写spider的detailContent方法
- String currentChannel = ids.get(0);
- String currentChannelName = "";
- for (int i = 0; i < channelInfo.length(); i++) {
- if (channelInfo.getJSONObject(i).get("chanid").toString().equals(currentChannel)) {
- currentChannelName = channelInfo.getJSONObject(i).get("name").toString();
- }
- }
- vodList.put("vod_id", currentChannel);
- vodList.put("vod_name", currentChannelName);
- vodList.put("vod_pic", "");
- vodList.put("type_name", "");
- vodList.put("vod_year", "");
- vodList.put("vod_area", "");
- vodList.put("vod_remarks", "");
- vodList.put("vod_actor", "");
- vodList.put("vod_director", "");
- vodList.put("vod_content", "");
复制代码 1.从入参ids中获取当前用户所选择的频道id
2.遍历channelInfo,搜索获取id所对应的频道名currentChannelName
3.在vodlist中设置vod_id和vod_name,其他项置空
- Map<String, String> vod_play = new TreeMap<>();
- for (int index = 0; index > -7; index--){
- OkHttpClient client = new OkHttpClient().newBuilder()
- .build();
- Request request = new Request.Builder()
- .url("http://180.100.93.38:33200/iptvepg/frame224/datas/get_tvod_programe_data.jsp?channelid="+currentChannel+"&index="+Integer.toString(index)+"&channelName="+ URLEncoder.encode(currentChannelName,"GB2312"))
- .get()
- .addHeader("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; SkyworthBrowser) AppleWebKit/534.24 (KHTML, like Gecko) Safari/534.24 SkWebKit-JS-CTC")
- .addHeader("Accept", "*/*")
- .addHeader("Referer", "http://180.100.93.38:33200/iptvepg/frame224/huikan_detail.jsp?mixno=001")
- .addHeader("Accept-Encoding", "gzip,deflate")
- .addHeader("Accept-Language", "zh-cn,en-us,en")
- .addHeader("Cookie", "JSESSIONID=" + JSESSIONID)
- .build();
- Response response = client.newCall(request).execute();
- String pgString = response.body().string();
- JSONArray pgJson = new JSONArray(pgString);
- String playList = "";
- List<String> vodItems = new ArrayList<>();
- for(int i = 0;i < pgJson.length() - 1; i++) {
- if (pgJson.getJSONObject(i).get("Playable").toString().equals("false")) {
- continue;
- }
- String vodId = pgJson.getJSONObject(i).get("ContentId").toString() +
- "|" +
- currentChannel +
- "|" +
- currentChannelName +
- "|" +
- pgJson.getJSONObject(i).get("StartTime").toString() +
- "|" +
- pgJson.getJSONObject(i).get("EndTime").toString();
- String vodName = pgJson.getJSONObject(i).get("ProgramName").toString();
- vodItems.add(vodName + "$" + vodId);
- }
- if (vodItems.size() > 0)
- playList = String.join("#", vodItems);
- Calendar calendar = Calendar.getInstance();
- calendar.add(Calendar.DATE, index);
- vod_play.put((calendar.get(Calendar.MONTH) + 1) + "-" + calendar.get(Calendar.DAY_OF_MONTH), playList);
- }
- if (vod_play.size() > 0) {
- String vod_play_from = String.join("$$$", vod_play.keySet());
- String vod_play_url = String.join("$$$", vod_play.values());
- vodList.put("vod_play_from", vod_play_from);
- vodList.put("vod_play_url", vod_play_url);
- }
复制代码 4.遍历0到-6 对应七天回放
5.此处注意对currentChannelName进行GB2312格式的url编码以转换中文频道名,如江苏卫视HD
6.在设置vodId时,需要将频道名currentChannelName ,开始时间StartTime,结束时间endtime也一并拼接赋值,方便后面播放视频接口调用。
7.vod_play的键值设置为当前日历值减去index,以显示几月几号的节目。
这一步完成之后进行打包,上传jar,改md5
完成之后,你将解锁第2个成就 一个展示了用户所选频道7天内所有节目的页面,切换日期来查看当天节目表 如下所示
下面我们进入视频播放的编写
重写spider的playcontent方法
- JSONObject result = new JSONObject();
- String[] idas = id.split("\\|");
- String channelID = idas[1];
- String contentId = idas[0];
- String channelName = idas[2];
- String stime = idas[3];
- String etime = idas[4];
- OkHttpClient client = new OkHttpClient().newBuilder()
- .build();
- Request request = new Request.Builder()
- .url("http://180.100.93.38:33200/iptvepg/frame224/get_tvod_url.jsp?contentId="+contentId+"&channelId="+channelID+"&stime=undefined&adPositionId=undefined")
- .get()
- .addHeader("User-Agent", "Mozilla/5.0 (X11; Linux x86_64; SkyworthBrowser) AppleWebKit/534.24 (KHTML, like Gecko) Safari/534.24 SkWebKit-JS-CTC")
- .addHeader("Accept", "*/*")
- .addHeader("Referer", "180.100.93.38:33200/iptvepg/frame224/channel_tvod_play.jsp?columnid=01&channelid="+channelID+"&index=-1&contentid="+contentId+"&stime="+stime+"&playtype=tvodplay&etime="+etime+"&channelname="+URLEncoder.encode(channelName,"GB2312"))
- .addHeader("Accept-Encoding", "gzip,deflate")
- .addHeader("Accept-Language", "zh-cn,en-us,en")
- .addHeader("Cookie", "JSESSIONID="+JSESSIONID)
- .build();
- Response response = client.newCall(request).execute();
- String body = response.body().string();
- Pattern tvodUrlPattern = Pattern.compile(""tvodUrl":"(.*)","orderParam");
- Matcher tvodUrlMatch = tvodUrlPattern.matcher(body);
- tvodUrlMatch.find();
- String tvodUrl = tvodUrlMatch.group(1);
- result.put("parse", "");
- result.put("playUrl", tvodUrl);
- result.put("url","");
- result.put("header", "");
- return result.toString();
复制代码 1.剥离入参id,以获得频道名,开始时间,结束时间
2.这里同样注意将频道名进行GB2312编码
3.利用正则表达式剥离播放rtsp链接
这一步即为最后一步,打包完成部署后。
你将解锁终极成就,在自建平台上观看江苏电信iptv 7天内的任意频道的任意节目 即点即看 自动完成认证 获取认证后的回看url
   
发帖注意事项
请勿胡乱发帖:https://www.right.com.cn/forum/thread-8307840-1-1.html
账户手机验证:https://www.right.com.cn/forum/home.php?mod=spacecp&ac=plugin&id=jzsjiale_sms:home
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
×
评分
-
查看全部评分
|