WangQiFei

蒸 馏 器


思想提纯
  • 首页
  • 归档
  • 标签
  • 关于
  •     

© 2024  by  Wangqifei

直播源的获取终极方案

发布于 2024-10-25 12:10 iptv 

很久没有更新了,最近大量的空闲时间在搞直播源的问题,从开始的寻找直播源、整理直播源逐步开始了自己搭直播源、扒直播源。目前整体方案已经比较稳定了。
内容主要分两部分一部分:

  1. 使用docker安装pixman搭建直播源
  2. 获取各省市组播源列表,并更新可用直播源地址
    第一个方案,此前Docker安装pixman搭建直播源特意做过详细的介绍,这里不再赘述。目前自用的也是一个聚合版本的itv列表,聚合了moveonjoy 、 thetvapp 以及港台的频道列表。只是需要对itv配置单独的host文件实现dns映射解决网络问题,配置稍复杂,单比较稳定。网络问题的解决方案,文章里页做了详细的介绍,配置openwrt定时脚本以后日常不需要再额外维护。
    第二个方案,这里重点作介绍.

实现的具体思路

  1. 从tongkiang.us或者iptvsearch获取各省份的各运营商的组播源列表;
  2. 使用 fofa.info获取各省份各运营商当前可用的组播源地址,并保持对第一步获取的列表中组播源地址的更新。

组播源列表的获取

使用以下脚本可以获取各省份组播源列表,手动运行依次得到基础的列表就可以了,后续对该列表更新的需求就没那么频繁了。
脚本运行需要确保yt-dlp安装的是最新版本,不然提取信息时可能会出错(我在代码里其实页加入了对旧版的支持,不要问为什么)
要注意一些常用的命令在各环境下使用的差异,代码中也增加了黑名单的功能,避免一些有速度的无效地址影响结果,需要自行微调。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#!/bin/bash
# 定义31个省份城市参数
declare -A cities
cities["AnHui_mobile"]="%E5%AE%89%E5%BE%BD%E7%A7%BB%E5%8A%A8"
cities["AnHui_unicom"]="%E5%AE%89%E5%BE%BD%E8%81%94%E9%80%9A"
cities["AnHui_telecom"]="%E5%AE%89%E5%BE%BD%E7%94%B5%E4%BF%A1"

cities["BeiJing_mobile"]="%E5%8C%97%E4%BA%AC%E7%A7%BB%E5%8A%A8"
cities["BeiJing_unicom"]="%E5%8C%97%E4%BA%AC%E8%81%94%E9%80%9A"
cities["BeiJing_telecom"]="%E5%8C%97%E4%BA%AC%E7%94%B5%E4%BF%A1"

cities["ChongQing_mobile"]="%E9%87%8D%E5%BA%86%E7%A7%BB%E5%8A%A8"
cities["ChongQing_unicom"]="%E9%87%8D%E5%BA%86%E8%81%94%E9%80%9A"
cities["ChongQing_telecom"]="%E9%87%8D%E5%BA%86%E7%94%B5%E4%BF%A1"

cities["FuJian_mobile"]="%E7%A6%8F%E5%BB%BA%E7%A7%BB%E5%8A%A8"
cities["FuJian_unicom"]="%E7%A6%8F%E5%BB%BA%E8%81%94%E9%80%9A"
cities["FuJian_telecom"]="%E7%A6%8F%E5%BB%BA%E7%94%B5%E4%BF%A1"

cities["GanSu_mobile"]="%E7%94%98%E8%82%83%E7%A7%BB%E5%8A%A8"
cities["GanSu_unicom"]="%E7%94%98%E8%82%83%E8%81%94%E9%80%9A"
cities["GanSu_telecom"]="%E7%94%98%E8%82%83%E7%94%B5%E4%BF%A1"

cities["GuangDong_mobile"]="%E5%B9%BF%E4%B8%9C%E7%A7%BB%E5%8A%A8"
cities["GuangDong_unicom"]="%E5%B9%BF%E4%B8%9C%E8%81%94%E9%80%9A"
cities["GuangDong_telecom"]="%E5%B9%BF%E4%B8%9C%E7%94%B5%E4%BF%A1"

cities["GuangXi_mobile"]="%E5%B9%BF%E8%A5%BF%E7%A7%BB%E5%8A%A8"
cities["GuangXi_unicom"]="%E5%B9%BF%E8%A5%BF%E8%81%94%E9%80%9A"
cities["GuangXi_telecom"]="%E5%B9%BF%E8%A5%BF%E7%94%B5%E4%BF%A1"

cities["GuangZhou_mobile"]="%E5%B9%BF%E5%B7%9E%E7%A7%BB%E5%8A%A8"
cities["GuangZhou_unicom"]="%E5%B9%BF%E5%B7%9E%E8%81%94%E9%80%9A"
cities["GuangZhou_telecom"]="%E5%B9%BF%E5%B7%9E%E7%94%B5%E4%BF%A1"

cities["GuiZhou_mobile"]="%E8%B4%B5%E5%B7%9E%E7%A7%BB%E5%8A%A8"
cities["GuiZhou_unicom"]="%E8%B4%B5%E5%B7%9E%E8%81%94%E9%80%9A"
cities["GuiZhou_telecom"]="%E8%B4%B5%E5%B7%9E%E7%94%B5%E4%BF%A1"

cities["HaiNan_mobile"]="%E6%B5%B7%E5%8D%97%E7%A7%BB%E5%8A%A8"
cities["HaiNan_unicom"]="%E6%B5%B7%E5%8D%97%E8%81%94%E9%80%9A"
cities["HaiNan_telecom"]="%E6%B5%B7%E5%8D%97%E7%94%B5%E4%BF%A1"

cities["HeBei_mobile"]="%E6%B2%B3%E5%8C%97%E7%A7%BB%E5%8A%A8"
cities["HeBei_unicom"]="%E6%B2%B3%E5%8C%97%E8%81%94%E9%80%9A"
cities["HeBei_telecom"]="%E6%B2%B3%E5%8C%97%E7%94%B5%E4%BF%A1"

cities["HeLongJiang_mobile"]="%E9%BB%91%E9%BE%99%E6%B1%9F%E7%A7%BB%E5%8A%A8"
cities["HeLongJiang_unicom"]="%E9%BB%91%E9%BE%99%E6%B1%9F%E8%81%94%E9%80%9A"
cities["HeLongJiang_telecom"]="%E9%BB%91%E9%BE%99%E6%B1%9F%E7%94%B5%E4%BF%A1"

cities["HeNan_mobile"]="%E6%B2%B3%E5%8D%97%E7%A7%BB%E5%8A%A8"
cities["HeNan_unicom"]="%E6%B2%B3%E5%8D%97%E8%81%94%E9%80%9A"
cities["HeNan_telecom"]="%E6%B2%B3%E5%8D%97%E7%94%B5%E4%BF%A1"

cities["HuBei_mobile"]="%E6%B9%96%E5%8C%97%E7%A7%BB%E5%8A%A8"
cities["HuBei_unicom"]="%E6%B9%96%E5%8C%97%E8%81%94%E9%80%9A"
cities["HuBei_telecom"]="%E6%B9%96%E5%8C%97%E7%94%B5%E4%BF%A1"

cities["HuNan_mobile"]="%E6%B9%96%E5%8D%97%E7%A7%BB%E5%8A%A8"
cities["HuNan_unicom"]="%E6%B9%96%E5%8D%97%E8%81%94%E9%80%9A"
cities["HuNan_telecom"]="%E6%B9%96%E5%8D%97%E7%94%B5%E4%BF%A1"

cities["JiLin_mobile"]="%E5%90%89%E6%9E%97%E7%A7%BB%E5%8A%A8"
cities["JiLin_unicom"]="%E5%90%89%E6%9E%97%E8%81%94%E9%80%9A"
cities["JiLin_telecom"]="%E5%90%89%E6%9E%97%E7%94%B5%E4%BF%A1"

cities["JiangSu_mobile"]="%E6%B1%9F%E8%8B%8F%E7%A7%BB%E5%8A%A8"
cities["JiangSu_unicom"]="%E6%B1%9F%E8%8B%8F%E8%81%94%E9%80%9A"
cities["JiangSu_telecom"]="%E6%B1%9F%E8%8B%8F%E7%94%B5%E4%BF%A1"

cities["JiangXi_mobile"]="%E6%B1%9F%E8%A5%BF%E7%A7%BB%E5%8A%A8"
cities["JiangXi_unicom"]="%E6%B1%9F%E8%A5%BF%E8%81%94%E9%80%9A"
cities["JiangXi_telecom"]="%E6%B1%9F%E8%A5%BF%E7%94%B5%E4%BF%A1"

cities["LiaoNing_mobile"]="%E8%BE%BD%E5%AE%81%E7%A7%BB%E5%8A%A8"
cities["LiaoNing_unicom"]="%E8%BE%BD%E5%AE%81%E8%81%94%E9%80%9A"
cities["LiaoNing_telecom"]="%E8%BE%BD%E5%AE%81%E7%94%B5%E4%BF%A1"

cities["NeiMengGu_mobile"]="%E5%86%85%E8%92%99%E7%A7%BB%E5%8A%A8"
cities["NeiMengGu_unicom"]="%E5%86%85%E8%92%99%E8%81%94%E9%80%9A"
cities["NeiMengGu_telecom"]="%E5%86%85%E8%92%99%E7%94%B5%E4%BF%A1"

cities["NingXia_mobile"]="%E5%AE%81%E5%A4%8F%E7%A7%BB%E5%8A%A8"
cities["NingXia_unicom"]="%E5%AE%81%E5%A4%8F%E8%81%94%E9%80%9A"
cities["NingXia_telecom"]="%E5%AE%81%E5%A4%8F%E7%94%B5%E4%BF%A1"

cities["QingHai_mobile"]="%E9%9D%92%E6%B5%B7%E7%A7%BB%E5%8A%A8"
cities["QingHai_unicom"]="%E9%9D%92%E6%B5%B7%E8%81%94%E9%80%9A"
cities["QingHai_telecom"]="%E9%9D%92%E6%B5%B7%E7%94%B5%E4%BF%A1"

cities["ShanDong_mobile"]="%E5%B1%B1%E4%B8%9C%E7%A7%BB%E5%8A%A8"
cities["ShanDong_unicom"]="%E5%B1%B1%E4%B8%9C%E8%81%94%E9%80%9A"
cities["ShanDong_telecom"]="%E5%B1%B1%E4%B8%9C%E7%94%B5%E4%BF%A1"

cities["ShanXi_mobile"]="%E5%B1%B1%E8%A5%BF%E7%A7%BB%E5%8A%A8"
cities["ShanXi_unicom"]="%E5%B1%B1%E8%A5%BF%E8%81%94%E9%80%9A"
cities["ShanXi_telecom"]="%E5%B1%B1%E8%A5%BF%E7%94%B5%E4%BF%A1"

cities["ShangHai_mobile"]="%E4%B8%8A%E6%B5%B7%E7%A7%BB%E5%8A%A8"
cities["ShangHai_unicom"]="%E4%B8%8A%E6%B5%B7%E8%81%94%E9%80%9A"
cities["ShangHai_telecom"]="%E4%B8%8A%E6%B5%B7%E7%94%B5%E4%BF%A1"

cities["SiChuan_mobile"]="%E5%9B%9B%E5%B7%9D%E7%A7%BB%E5%8A%A8"
cities["SiChuan_unicom"]="%E5%9B%9B%E5%B7%9D%E8%81%94%E9%80%9A"
cities["SiChuan_telecom"]="%E5%9B%9B%E5%B7%9D%E7%94%B5%E4%BF%A1"

cities["TianJin_mobile"]="%E5%A4%A9%E6%B4%A5%E7%A7%BB%E5%8A%A8"
cities["TianJin_unicom"]="%E5%A4%A9%E6%B4%A5%E8%81%94%E9%80%9A"
cities["TianJin_telecom"]="%E5%A4%A9%E6%B4%A5%E7%94%B5%E4%BF%A1"

cities["XiZang_mobile"]="%E8%A5%BF%E8%97%8F%E7%A7%BB%E5%8A%A8"
cities["XiZang_unicom"]="%E8%A5%BF%E8%97%8F%E8%81%94%E9%80%9A"
cities["XiZang_telecom"]="%E8%A5%BF%E8%97%8F%E7%94%B5%E4%BF%A1"

cities["XinJiang_mobile"]="%E6%96%B0%E7%96%86%E7%A7%BB%E5%8A%A8"
cities["XinJiang_unicom"]="%E6%96%B0%E7%96%86%E8%81%94%E9%80%9A"
cities["XinJiang_telecom"]="%E6%96%B0%E7%96%86%E7%94%B5%E4%BF%A1"

cities["YunNan_mobile"]="%E4%BA%91%E5%8D%97%E7%A7%BB%E5%8A%A8"
cities["YunNan_unicom"]="%E4%BA%91%E5%8D%97%E8%81%94%E9%80%9A"
cities["YunNan_telecom"]="%E4%BA%91%E5%8D%97%E7%94%B5%E4%BF%A1"

cities["ZheJiang_mobile"]="%E6%B5%99%E6%B1%9F%E7%A7%BB%E5%8A%A8"
cities["ZheJiang_unicom"]="%E6%B5%99%E6%B1%9F%E8%81%94%E9%80%9A"
cities["ZheJiang_telecom"]="%E6%B5%99%E6%B1%9F%E7%94%B5%E4%BF%A1"


URL="http://www.foodieguide.com/iptvsearch/hoteliptv.php"
URL2="http://www.foodieguide.com/iptvsearch/allllist.php"
RESPONSE_FILE="response.txt"
UNIQUE_SEARCH_RESULTS_FILE="unique_searchresults.txt"
SPEED_TEST_LOG="speedtest.log"
BEST_URL_RESPONSE_FILE="besturlresponse.txt"
SUMMARY_FILE="summary.txt"
YT_DLP_LOG="yt-dlp-output.log"
CURL_LOG="curl.log"

# 清空或创建日志文件
: >${SUMMARY_FILE}
: >${YT_DLP_LOG}
: >${CURL_LOG}

for CHANNEL_NAME in "${!cities[@]}"; do
IFS=':' read -r NET_VALUE <<<"${cities[$CHANNEL_NAME]}"
OUTPUT_FILE="./${CHANNEL_NAME}_NUM.txt"
## 获取当前可用的酒店源,数据较多,只获取前3页
echo "==== 开始获取数据: ${CHANNEL_NAME} ======" | tee -a "$SUMMARY_FILE"

# 清空响应文件
: >${RESPONSE_FILE}
: >${SPEED_TEST_LOG}
# 获取数据
# 第一页
curl -X POST "${URL}" \
-H "Accept-Language: en-CN,en;q=0.9,zh-CN;q=0.8,zh;q=0.7,en-GB;q=0.6,en-US;q=0.5" \
-d "saerch=${NET_VALUE}&Submit=+&names=Tom&city=HeZhou&url=Ca94122" \
--connect-timeout 5 \
--max-time 15 \
-o "$RESPONSE_FILE"

# # 2-2页面 数据太多,一页也就足够了,酌情调整
# for page in $(seq 2 2); do
# echo "第${page}页加载中"
# curl -G "${URL}" \
# -d "page=${page}" \
# -d "net=${NET_VALUE}" \
# --connect-timeout 5 \
# --max-time 15 \
# >>"$RESPONSE_FILE"
# done

## 提取源地址,并进行整理
tmp_file=$(mktemp)
# 使用 awk 处理文件
awk '
BEGIN { RS = "<div class=\"result\">" ; FS = "</div>" }
{
if ($0 !~ /暂时失效/) {
print "<div class=\"result\">" $0 "</div>"
}
}
' "$RESPONSE_FILE" >"${tmp_file}"
grep -oP '<b><img[^>]*>\K[^<]*' "${tmp_file}" | grep -v '盗链' | sed 's/ //g' | sort | uniq >"$UNIQUE_SEARCH_RESULTS_FILE"
echo " unique search result : " | tee -a "$SUMMARY_FILE"
cat "$UNIQUE_SEARCH_RESULTS_FILE" | tee -a "$SUMMARY_FILE"

# 剔除已知干扰地址,按需配置

## 筛选有效刑,测试每个源的下载速度,选择最优源
echo "==== 有效地址提取完成, 开始测速 ======" | tee -a "$SUMMARY_FILE"
line_count=$(wc -l <"$UNIQUE_SEARCH_RESULTS_FILE" | xargs)
echo "line count is ${line_count}"
i=0
: >validurlist.txt
echo "========= ${CHANNEL_NAME} ===测速日志==========" >>"$CURL_LOG"
while IFS= read -r url; do
i=$((i + 1))
:>curl.list

# 检查 validurlist.txt 是否达到 10 行,达到则跳出循环
if [ "$(wc -l < validurlist.txt)" -ge 10 ]; then
echo "validurlist.txt 已达到 10 行,跳出测速循环" | tee -a "$SUMMARY_FILE"
break
fi

echo "[第 ${i}/${line_count} 个]: ${url}" | tee -a "$SUMMARY_FILE"
# curllist=$(curl -G "${URL2}" -d "s=${url}" --compressed)
curl -X GET "${URL2}" \
-G \
--data-urlencode "s=${url}" \
--data-urlencode "y=y" \
--compressed \
--connect-timeout 5 \
--max-time 15 \
-o curl.list
# 保存 yt-dlp 输出到日志
echo -e "[第 ${i}/${line_count} 个]: ${url} curl.list" >>"$CURL_LOG"
sleep 0.1
if grep -q '暂时失效' curl.list; then
echo "暂时失效" | tee -a "$SUMMARY_FILE"
else
echo "地址有效" | tee -a "$SUMMARY_FILE"
echo "$(grep -oP "\s\Khttps?://${url}[^<]*" curl.list 2>/dev/null | head -n 1)" >>validurlist.txt

fi
done <"$UNIQUE_SEARCH_RESULTS_FILE"

# 剔除已知干扰地址
# sed -i '/epg.pw/d' validurlist.txt

# 测试每个源的下载速度
echo "==== 整理数据完成, 开始测速 ======" | tee -a "$SUMMARY_FILE"
lines=$(wc -l <validurlist.txt)
i=0
echo "========= ${CHANNEL_NAME} ===测速日志==========" >>"$YT_DLP_LOG"
while read -r url; do
i=$((i + 1))
# 检查 SPEED_TEST_LOG 中有效行数,剔除“测速失败”的行,达到 5 行则跳出循环
valid_speed_count=$(grep -v '测速失败' "$SPEED_TEST_LOG" | wc -l | xargs)
if [ "$valid_speed_count" -ge 5 ]; then
echo "SPEED_TEST_LOG 中有效测速行数已达到 5 行,跳出循环" | tee -a "$SUMMARY_FILE"
break
fi
echo "[第 ${i}/${lines} 个]: ${url}" | tee -a "$SUMMARY_FILE"
output=$(timeout 40 yt-dlp --ignore-config --no-cache-dir --output "output.ts" --download-archive new-archive.txt --external-downloader ffmpeg --external-downloader-args "ffmpeg:-t 5" "${url}" 2>&1)

# 保存 yt-dlp 输出到日志
echo "${output}" >>"$YT_DLP_LOG"
:>yt.tmp
echo "${output}" >yt.tmp

# 检查下载是否成功
if ! grep -qE "^\s?\[download\]\s+[0-9]+%" yt.tmp; then
echo "下载失败: ${url}" | tee -a "$SUMMARY_FILE"
echo "下载失败: ${url}" >>"$SPEED_TEST_LOG"
rm new-archive.txt output.ts
continue
fi

# 提取下载速度信息
speed=$(grep -P "^\s?\[download\]\s+[0-9]+%" yt.tmp | grep -oP 'at\s\K[0-9]+.*$|in\s\K[0-9]+:[0-9]+$')
speedinfo=$(grep -P "^\s?\[download\]\s+[0-9]+%" yt.tmp)

# 如果文件存在且大小合理,认为测速成功
if [ -s output.ts ]; then
echo "${speedinfo}" | tee -a "$SUMMARY_FILE"
echo "${speed} ${url}" >>"$SPEED_TEST_LOG"
else
echo "测速失败!!" | tee -a "$SUMMARY_FILE"
echo "测速失败: ${url}" >>"$SPEED_TEST_LOG"
fi
# 清理下载的文件
rm -f new-archive.txt output.ts
done < validurlist.txt

# 检查是否有有效的速度信息
if [ ! -s "$SPEED_TEST_LOG" ] || ! grep -v '失败' "$SPEED_TEST_LOG" | grep -q '[0-9]'; then
echo "没有找到有效的测速结果,跳过 ${CHANNEL_NAME}" | tee -a "$SUMMARY_FILE"
continue # 跳过当前循环,进入下一个频道的处理
fi

# 排序并选择速度最快的源地址
# 检查是否包含 MiB/s(yt-dlp执行的结果会有差异)
if grep -E 'MiB/s|KiB/s' "$SPEED_TEST_LOG"; then
echo "找到 MiB/s|KiB/s, 执行倒序排列" | tee -a "$SUMMARY_FILE"
# 将单位换算一致,使用bc比较方便
# sed -i 's/\([0-9.]*\)MiB\/s/echo "\1 * 1024" | bc KiB\/s/e' "$SPEED_TEST_LOG"
# 无法使用bc的使用awk将 MiB/s 转换为 KiB/s

awk '{
if ($1 ~ /MiB\/s/) {
# 提取数值部分并转换为 KiB/s
value = $1;
sub(/MiB\/s/, "", value); # 去掉单位
value = value * 1024; # 转换为 KiB
printf "%.2fKiB/s %s\n", value, $2; # 格式化输出
} else {
print $0; # 保留原样
}
}' "$SPEED_TEST_LOG" >speed_temp.log && mv speed_temp.log "$SPEED_TEST_LOG"

grep -v '失败' "$SPEED_TEST_LOG" | sort -n -r | awk '{print $2 " " $1}' >validurl.txt
else
echo "未找到MiB/s|KiB/s, 执行正序排列" | tee -a "$SUMMARY_FILE"
grep -v '失败' "$SPEED_TEST_LOG" | sort -n | awk '{print $2 " " $1}' >validurl.txt
fi

besturl=$(head -n 1 validurl.txt | sed -n 's|.*//\([^/]*\)/.*|\1|p')
echo "========== 最优源域名: ${besturl}" | tee -a "$SUMMARY_FILE"

# 获取 besturl 对应的直播源列表

echo "${besturl} 源列表获取中 " | tee -a "$SUMMARY_FILE"
curl -X GET "http://foodieguide.com/iptvsearch/allllist.php" \
-G \
--data-urlencode "s=${besturl}" \
--data-urlencode "y=y" \
--compressed \
--connect-timeout 6 \
--max-time 20 \
-o "$BEST_URL_RESPONSE_FILE"

# 提取频道名称和 m3u8 链接
echo "==== 提取频道名称和 m3u8 链接结果 ======" | tee -a "$SUMMARY_FILE"
grep -oP '^\s*<div style="float: left;"[^>]*>\K[^<]*(?=</div>)|\s\Khttps?[^<]*' "$BEST_URL_RESPONSE_FILE" |
awk '{
if ($0 ~ /http/) {
gsub(/ /, "", $0);
if (channel != "") {
print channel "," $0;
}
} else {
channel=$0;
}
}' >"$OUTPUT_FILE"

sed -i "1i ${CHANNEL_NAME},#genre#" "$OUTPUT_FILE"
line_count_output=$(($(wc -l < "$OUTPUT_FILE") - 1))
NEW_output="${OUTPUT_FILE//NUM/$line_count_output}"
mv "$OUTPUT_FILE" "$NEW_output"
echo " $NEW_output 已经更新完成" | tee -a "$SUMMARY_FILE"

# 在汇总文件中加入分隔行
echo "==== ${CHANNEL_NAME} 处理完成 ======" | tee -a "$SUMMARY_FILE"
echo "------------------------------" | tee -a "$SUMMARY_FILE"
rm ${RESPONSE_FILE} ${UNIQUE_SEARCH_RESULTS_FILE} ${SPEED_TEST_LOG} ${BEST_URL_RESPONSE_FILE} ${SUMMARY_FILE} ${YT_DLP_LOG} curl.list curl.log validurl.txt validurlist.txt yt.tmp
done

当前可用组播源地址的获取

fofa搜索关键词 udpxy && country="CN" && region="地区名称" && org="对应的运行商名称" && protocol="http"
可以参考酒店组播源的查找实例。 组播源的特点是udproxy代理 、 http服务,org主要也就是Chinanet 、China Unicom Beijing Province Network、CHINA UNICOM China169 Backbone具体哪个可以使用tonkiang获取直播列表中的地址反查下信息。

示例脚本里基本涵盖了国内的各个地区的数据。脚本中加入了bark通知。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
#!/bin/bash
# 使用fofa提取各省市组播源地址

# 执行全部
# city_choice=(0)
# 执行执行
city_choice=(2 32) # 指定多个选项时使用

# todo
# 提取现有地址参与测速

# 定义城市选项
declare -A cities
cities=(
[1]="AnHui_telecom_191 rtp/238.1.78.166:7200 安徽电信 'udpxy && country=\"CN\" && region=\"Anhui\" && org=\"Chinanet\" && protocol=\"http\"'"
[2]="BeiJing_unicom_145 rtp/239.3.1.129:8008 北京联通 'udpxy && country=\"CN\" && region=\"Beijing\" && org=\"China Unicom Beijing Province Network\" && protocol=\"http\"'"
[3]="ChongQing_telecom_161 rtp/235.254.196.249:1268 重庆电信 'udpxy && country=\"CN\" && region=\"Chongqing\" && org=\"Chinanet\" && protocol=\"http\"'"
[4]="ChongQing_unicom_77 udp/225.0.4.188:7980 重庆联通 'udpxy && country=\"CN\" && region=\"Chongqing\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[5]="FuJian_telecom_114 rtp/239.61.3.4:9542 福建电信 'udpxy && country=\"CN\" && region=\"Fujian\" && org=\"Chinanet\" && protocol=\"http\"'"
[6]="GanSu_telecom_105 udp/239.255.30.250:8231 甘肃电信 'udpxy && country=\"CN\" && region=\"Gansu\" && org=\"Chinanet\" && protocol=\"http\"'"
[7]="GuangDong_mobile_332 udp/239.77.1.19:5146 广东移动 'udpxy && country=\"CN\" && region=\"Guangdong\" && org=\"Chinanet\" && protocol=\"http\"'"
[8]="GuangDong_telecom_332 udp/239.77.1.19:5146 广东电信 'udpxy && country=\"CN\" && region=\"Guangdong\" && org=\"Chinanet\" && protocol=\"http\"'"
[9]="GuangDong_unicom_91 hls/80/index.m3u8 广东联通 'udpxy && country=\"CN\" && region=\"Guangdong\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[10]="GuangXi_telecom_163 udp/239.81.0.107:4056 广西电信 'udpxy && country=\"CN\" && region=\"Guangxi\" && org=\"Chinanet\" && protocol=\"http\"'"
[11]="HaiNan_telecom_217 rtp/239.253.64.14:5140 海南电信 'udpxy && country=\"CN\" && region=\"Hainan\" && org=\"Chinanet\" && protocol=\"http\"'"
[12]="HeBei_telecom_310 rtp/239.254.200.45:8008 河北电信 'udpxy && country=\"CN\" && region=\"Hebei\" && org=\"Chinanet\" && protocol=\"http\"'"
[13]="HeBei_unicom_313 rtp/239.253.92.154:6011 河北联通 'udpxy && country=\"CN\" && region=\"Hebei\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[14]="HeiLongJiang_178 udp/229.58.190.14:5000 黑龙江电信 'udpxy && country=\"CN\" && region=\"HeiLongJiang\" && org=\"Chinanet\" && protocol=\"http\"'"
[15]="HeNan_mobile_172 rtp/225.1.4.98:1127 河南移动 'udpxy && country=\"CN\" && region=\"Henan\" && org=\"Chinanet\" && protocol=\"http\"'"
[16]="HeNan_mobile_327 rtp/239.16.20.21:10210 河南移动 'udpxy && country=\"CN\" && region=\"Henan\" && org=\"Chinanet\" && protocol=\"http\"'"
[17]="HeNan_telecom_327 rtp/239.16.20.21:10210 河南电信 'udpxy && country=\"CN\" && region=\"Henan\" && org=\"Chinanet\" && protocol=\"http\"'"
[18]="HeNan_unicom_172 rtp/225.1.4.98:1127 河南联通 'udpxy && country=\"CN\" && region=\"Henan\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[19]="HuBei_telecom_90 rtp/239.69.1.40:9880 湖北电信 'udpxy && country=\"CN\" && region=\"Hubei\" && org=\"Chinanet\" && protocol=\"http\"'"
[20]="HuNan_telecom_282 udp/239.76.245.115:1234 湖南电信 'udpxy && country=\"CN\" && region=\"Hunan\" && org=\"Chinanet\" && protocol=\"http\"'"
[21]="JiangSu_telecom_276 rtp/239.49.8.107:8000 江苏电信 'udpxy && country=\"CN\" && region=\"Jiangsu\" && org=\"Chinanet\" && protocol=\"http\"'"
[22]="JiangXi_telecom_105 udp/239.252.220.63:5140 江西电信 'udpxy && country=\"CN\" && region=\"Jiangxi\" && org=\"Chinanet\" && protocol=\"http\"'"
[23]="JiLin_50 hls/1/index.m3u8 吉林电信 'udpxy && country=\"CN\" && region=\"Jilin\" && org=\"Chinanet\" && protocol=\"http\"'"
[24]="LiaoNing_unicom_133 rtp/232.0.0.126:1234 辽宁联通 'udpxy && country=\"CN\" && region=\"Liaoning\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[25]="NeiMengGu_telecom_219 udp/239.29.0.2:5000 内蒙古电信 'udpxy && country=\"CN\" && region=\"NeiMengGu\" && org=\"Chinanet\" && protocol=\"http\"'"
[26]="QingHai_unicom_221 udp/239.120.1.64:8332 青海联通 'udpxy && country=\"CN\" && region=\"Qinghai\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[27]="ShanDong_unicom_98 udp/239.253.254.77:8000 山东联通 'udpxy && country=\"CN\" && region=\"Shandong\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[28]="ShangHai_telecom_103 udp/239.45.3.209:5140 上海电信 'udpxy && country=\"CN\" && region=\"Shanghai\" && org=\"Chinanet\" && protocol=\"http\"'"
[29]="ShaanXi_telecom_123 rtp/239.112.205.59:5140 陕西电信 'udpxy && country=\"CN\" && region=\"Shaanxi\" && org=\"Chinanet\" && protocol=\"http\"'"
[30]="ShanXi_telecom_117 udp/239.1.1.7:8007 山西电信 'udpxy && country=\"CN\" && region=\"Shanxi\" && org=\"Chinanet\" && protocol=\"http\"'"
[31]="ShanXi_unicom_184 rtp/226.0.2.235:9792 山西联通 'udpxy && country=\"CN\" && region=\"Shanxi\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[32]="SiChuan_telecom_333 udp/239.93.0.169:5140 四川电信 'udpxy && country=\"CN\" && region=\"Sichuan\" && org=\"Chinanet\" && protocol=\"http\"'"
[33]="SiChuan_unicom_334 udp/239.93.0.169:5140 四川联通 'udpxy && country=\"CN\" && region=\"Sichuan\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[34]="TianJin_unicom_160 udp/225.1.1.111:5002 天津联通 'udpxy && country=\"CN\" && region=\"Tianjin\" && org=\"CHINA UNICOM China169 Backbone\" && protocol=\"http\"'"
[35]="XinJiang_telecom_195 udp/238.125.3.12:5140 新疆电信 'udpxy && country=\"CN\" && region=\"Xinjiang\" && org=\"Chinanet\" && protocol=\"http\"'"
[36]="YunNan_telecom_175 udp/239.200.200.178:8884 云南电信 'udpxy && country=\"CN\" && region=\"Yunnan\" && org=\"Chinanet\" && protocol=\"http\"'"
[37]="ZheJiang_telecom_320 udp/233.50.201.100:5140 浙江电信 'udpxy && country=\"CN\" && region=\"Zhejiang\" && org=\"Chinanet\" && protocol=\"http\"'"
)

# url编码函数
urlencode() {
# urlencode <string>
old_lang=$LANG
LANG=C
old_lc_collate=$LC_COLLATE
LC_COLLATE=C

local length="${#1}"
for ((i = 0; i < length; i++)); do
local c="${1:i:1}"
case $c in
[a-zA-Z0-9.~_-]) printf "$c" ;;
*) printf '%%%02X' "'$c" ;;
esac
done

LANG=$old_lang
LC_COLLATE=$old_lc_collate
}

# 定义处理城市的函数
process_city() {
local city=$1
local stream=$2
local channel_key=$3
local url_fofa=$4

# 使用城市名作为默认文件名,格式为 CityName.ip

# 检查目录下ip文件夹是否存在,不存在就创建
[ -d "./ip" ] || mkdir -p "./ip"

ipfile="ip/${city}_ip.txt"
validIP="ip/${city}_validIP.txt"
template="../multicastSource/${city}.txt"
rm -f $validIP 2>/dev/null

# 搜索最新 IP
echo "=============== fofa查找 ${city} 当前可用ip ================="
if ! curl -o search_result.html "$url_fofa"; then
echo "错误:当前无法获取 ${city} fofa数据"
failed_cities+=("$city")
return

fi
echo "$ipfile"
grep -E '^\s*[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+$' search_result.html | grep -oE '[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+' >"$ipfile"
rm -f search_result.html

# 遍历 IP 地址并测试
# while IFS= read -r ip; do
# tmp_ip=$(echo -n "$ip" | sed 's/:/ /')
# echo $tmp_ip
# output=$(nc -w 1 -v -z $tmp_ip 2>&1)
# echo $output
# if [[ $output == *"succeeded"* ]]; then
# echo "$output" | grep "succeeded" | awk -v ip="$ip" '{print ip}' >>"$validIP"
# fi
# done <"$ipfile"
# 遍历 IP 地址并测试 并发优化版本
# 设置最大并发数
MAX_PROCS=10
# 创建一个用于控制并发的管道
fifo="/tmp/$$.fifo"
mkfifo "$fifo"
exec 3<>"$fifo"
rm "$fifo"

# 初始化管道中并发槽位数量
for ((i = 0; i < MAX_PROCS; i++)); do
echo
done >&3

# 并发处理每个IP
while IFS= read -r ip; do
# 从并发槽位中取出一个令牌
read -u 3
{
# 提取 IP 和端口
tmp_ip="${ip//:/ }"
# 使用nc检测连通性
output=$(nc -w 1 -v -z $tmp_ip 2>&1)
# 检查是否连接成功
if [[ $output == *"succeeded"* ]]; then
echo "$ip" >>"$validIP"
fi
# 完成后归还一个令牌
echo >&3
} &
done <"$ipfile"
# 等待所有后台进程完成
wait
# 关闭管道
exec 3>&-

if [ ! -s "$validIP" ]; then
echo "当前无可用的ip,请稍候重试,继续测试下一个"
failed_cities+=("$city")
return
fi

echo "============= 检索到有效ip,开始测速 ==============="
ipinuse="$(grep -oPm 1 'http://\K[\d.]+:\d+' $template)"
if [ -z "$ipinuse" ]; then
echo "ipinuse 为空,直接测试新ip。"
else
sed -i "1i${ipinuse}" "$validIP"
echo "现有ip: ${ipinuse} 已加入 $validIP 测速队列。"
fi

linescount=$(wc -l <"$validIP")
echo "[$validIP]有效ip有 $linescount 个"

time=$(date +%Y%m%d%H%M%S)
i=0
valid_count=0 # 记录有效IP的计数
while IFS= read -r line; do
i=$((i + 1))
ip="$line"
url="http://$ip/$stream"

curl "$url" --connect-timeout 3 --max-time 10 -o /dev/null >fofa.tmp 2>&1
speed=$(head -n 3 fofa.tmp | awk '{print $NF}' | tail -n 1)
# touch fofa.md && cat fofa.tmp >> fofa.md

echo "第 $i/$linescount 个:$ip $speed"
echo "$ip $speed" >>"speedtest_${city}_$time.log"

if [[ $speed == *"M"* || $speed == *"k"* ]]; then
valid_count=$((valid_count + 1))
fi

# 如果有效IP数达到了10个,则终止循环
if [ "$valid_count" -ge 10 ]; then
echo "已找到10个有效IP,提前结束循环"
break
fi

done <"$validIP"

rm -f fofa.tmp

# 只取前 10 个有效的 IP 进行排序和保存
awk '/M|k/{print $2" "$1}' "speedtest_${city}_$time.log" | sort -n -r | uniq | head -n 10 >"ip/${city}_result.txt"

echo "speedtest_${city}_$time.log"
cat speedtest_${city}_$time.log
echo "ip/${city}_result.txt"
cat "ip/${city}_result.txt"
rm -f "speedtest_${city}_$time.log"

ip1=$(awk 'NR==1{print $2}' ip/${city}_result.txt)
# ip2=$(awk 'NR==2{print $2}' ip/${city}_result.txt)
# ip3=$(awk 'NR==3{print $2}' ip/${city}_result.txt)
# perl -i -pe "s/(?<=https?:\/\/)[^/]*/$ip1/g" "$template"
echo "bestIP: $ip1"
if [ -z "$ip1" ]; then
echo '当前无有效ip,执行下一个'
return # 如果 ip1 为空,则跳过当前迭代
fi
sed -Ei "s|(https?://)[^/]*|\1$ip1|g" "$template"
echo "$template 已更新!"
bash ../rtp2m3u.sh "$template"
echo "$template m3u 已更新!"
cat "$template" >>domestic.txt

echo -e "${city}:${ip1}" >>msg.txt
# …………

}

# 初始化文件
: >domestic.txt
: >msg.txt
failed_cities=()
# 处理选项
if [ ${#city_choice[@]} -eq 1 ] && [ ${city_choice[0]} -eq 0 ]; then
# 如果选择0,处理全部城市
for option in "${!cities[@]}"; do
IFS=' ' read -r city stream channel_key query <<<"${cities[$option]}"
url_fofa="https://fofa.info/result?qbase64=$(echo "$query" | tr -d "'" | base64 -w 0)"
process_city "$city" "$stream" "$channel_key" "$url_fofa"
done
else
# 处理指定的多个城市
for option in "${city_choice[@]}"; do
if [[ -n "${cities[$option]}" ]]; then
IFS=' ' read -r city stream channel_key query <<<"${cities[$option]}"
url_fofa="https://fofa.info/result?qbase64=$(echo "$query" | tr -d "'" | base64 -w 0)"
process_city "$city" "$stream" "$channel_key" "$url_fofa"
else
echo "选择无法匹配:请检查输入 $option。"
fi
done
fi

# domestic.txt频道处理

grep -vP '购|購物|单音轨|画中画|购物|测试|#genre#|https?-' domestic.txt | sed 's/CCTV\([^-]\)/CCTV-\1/g' | sed -E 's/[[:space:]]*(高清|HD|\[高清\]|\[超清\]|\[HDR\])//g' | awk -F, '!seen[$1]++' | sort -t, -k1,1 -V >tmp.list

# 异常处理
sed -i '/+/d; /CCTV-4 中文国际 欧洲/d; /CCTV-4 中文国际 美洲/d; /CCTV-4欧洲/d; /CCTV-4美洲/d; /CCTV-16 奥林匹克/d' tmp.list

echo '中央电视台,#genre#' >output.list
grep 'CCTV' tmp.list >>output.list

echo '卫视频道,#genre#' >>output.list
grep '卫视' tmp.list | sort -t, -k1,1 >>output.list

echo '香港,#genre#' >>output.list
grep -iE '凤凰|星空|channel-?v' tmp.list >>output.list


echo '其他频道,#genre#' >>output.list
grep -iEv 'CCTV|卫视|凤凰|星空|channel-?v|动画|动漫|少儿|儿童|卡通|炫动|baby|disney|nick|boomerang|cartoon|discovery-?family|[^党员]教育|课堂|空中|学习|学堂|中教|科教' tmp.list >>output.list

echo '教育,#genre#' >>output.list
grep -iE '[^党员]教育|课堂|空中|学习|学堂|中教|科教' tmp.list | sort -V >>output.list

echo '动画,#genre#' >>output.list
grep -iE '动画|动漫|少儿|儿童|卡通|炫动|baby|disney|nick|boomerang|cartoon|discovery-?family' tmp.list >>output.list

mv output.list domestic.txt

# bark通知
# cat msg.txt
sed -i "1i $(TZ='Asia/Shanghai' date +%Y/%m/%d/%H:%M:%S)\n国内直播源地址已更新:" msg.txt
echo "未更新城市列表: ${failed_cities[@]}" | sed 's/ / \ /g' >>msg.txt
msg_urlencode=$(urlencode "$(cat msg.txt)")
curl "https://bark服务器信息/github_actions/${msg_urlencode}?isArchive=1"
rm msg.txt tmp.list

 上一篇: sed awk 用法 

下一篇: 在serv00上使用frp实现内网穿透的示例 

© 2024  by  Wangqifei