├── .gitignore ├── Dockerfile ├── Makefile ├── README.md ├── Sync_Update.sh ├── config └── config.go ├── docker-entrypoint.sh ├── go.mod ├── list └── m3u.go ├── liveITV ├── config.go └── itv.go ├── livePhoenix ├── config.go └── phoenix.go ├── main.go ├── update └── update.go └── utils └── commons.go /.gitignore: -------------------------------------------------------------------------------- 1 | # Go Modules 2 | /go.sum 3 | 4 | # 编译缓存目录 5 | /build/ 6 | /bin/ 7 | /dist/ 8 | 9 | # VSCode 编辑器配置 10 | .vscode/ 11 | .idea/ 12 | *.code-workspace 13 | 14 | # OS 文件 15 | .DS_Store 16 | Thumbs.db 17 | 18 | # 日志文件 19 | *.log 20 | 21 | # 临时文件 22 | *.tmp 23 | *.swp -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use the official Golang image as the build base 2 | FROM --platform=$BUILDPLATFORM golang:1.23 AS builder 3 | 4 | # Set the Go working directory 5 | WORKDIR /app 6 | 7 | # Copy go.mod and go.sum files for dependency management optimization 8 | COPY go.mod go.sum ./ 9 | 10 | # Download dependencies 11 | RUN go mod download 12 | 13 | # Copy source code 14 | COPY . . 15 | 16 | # Compile the Go program 17 | ARG TARGETOS TARGETARCH 18 | RUN CGO_ENABLED=0 GOOS=$TARGETOS GOARCH=$TARGETARCH go build -trimpath -ldflags="-s -w" -o /app/itv . 19 | 20 | # Runtime image 21 | FROM alpine:latest 22 | 23 | # Adding the utilities tools to create the container 24 | RUN apk --no-cache --update add tzdata 25 | 26 | RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime 27 | RUN echo "Asia/Shanghai" > /etc/timezone 28 | 29 | # Set the working directory in the container 30 | WORKDIR /app 31 | 32 | # Copy the contents 33 | COPY --from=builder /app/itv /app/itv 34 | 35 | # Expose port 8123 36 | EXPOSE 8123 37 | 38 | # Add entrypoint script 39 | ADD docker-entrypoint.sh / 40 | RUN chmod +x /docker-entrypoint.sh 41 | 42 | # Define entrypoint 43 | ENTRYPOINT ["/docker-entrypoint.sh"] -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 项目名称 2 | PROJECT_NAME := itv 3 | 4 | # 目标平台 5 | PLATFORMS := linux_amd64 linux_arm64 linux_armv7 windows_amd64 darwin_amd64 darwin_arm64 6 | 7 | # Go 编译器设置 8 | # GO := go 9 | GO := garble 10 | 11 | # 定义 LDFLAGS 12 | LDFLAGS := "-s -w" 13 | 14 | # 生成的文件存放目录 15 | BUILD_DIR := build 16 | 17 | # 生成文件名 18 | define BUILD_OUTPUT 19 | $(BUILD_DIR)/$(PROJECT_NAME)_$(if $(findstring armv7,$1),linux_armv7,$1)$(if $(findstring windows,$1),.exe) 20 | endef 21 | 22 | # 根据目标平台进行编译 23 | all: $(PLATFORMS) 24 | 25 | $(PLATFORMS): 26 | @mkdir -p $(BUILD_DIR) 27 | GOOS=$(word 1, $(subst _, ,$@)) \ 28 | GOARCH=$(if $(findstring armv7,$@),arm,$(word 2, $(subst _, ,$@))) \ 29 | CGO_ENABLED=0 $(GO) build -ldflags=$(LDFLAGS) -o $(call BUILD_OUTPUT,$@) 30 | 31 | # 清理编译文件 32 | clean: 33 | rm -rf $(BUILD_DIR) 34 | 35 | .PHONY: all clean $(PLATFORMS) 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # easy-TVframework-go 2 | #### 可用itv服务器IP在 liveITV/config.go 中配置,当前配置为示例不可直接使用。 3 | 4 | ## Golang 多平台构建支持 5 | go install mvdan.cc/garble@latest 6 | 7 | ## Docker 多平台构建支持 8 | docker buildx create --name mybuilder --use --driver docker-container 9 | docker buildx inspect --bootstrap 10 | 11 | ## 编译二进制可执行文件&执行 12 | ### 全平台 13 | make 14 | 15 | ### 指定平台 16 | make linux_amd64 17 | 18 | ### 运行二进制文件 19 | itv_linux_amd64 -token=itv 20 | 21 | ## 构建多平台镜像并推送至HUB仓库 22 | docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t g12777/easy-TV:latest --push . 23 | 24 | ## Docker部署运行 25 | docker run -d --restart always -p 8123:8123 --name easy-TV g12777/easy-TV:latest -token=mytoken 26 | 27 | ## 编辑 Sync_Update.sh 39行 指定升级服务器SSH 28 | #### 检查升级路径在config中配置 29 | #### version与线上不一致会触发升级 30 | -------------------------------------------------------------------------------- /Sync_Update.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "=========编译二进制文件=========" 4 | 5 | make linux_amd64 6 | make linux_arm64 7 | make linux_armv7 8 | 9 | version=$(grep 'const Version' config/config.go | awk -F'"' '{print $2}') 10 | 11 | output_file="build/latest_version.json" 12 | echo "{" > "$output_file" 13 | echo " \"version\": \"$version\"," >> "$output_file" 14 | echo " \"hash\": {" >> "$output_file" 15 | echo "=========计算文件MD5值=========" 16 | 17 | first=true 18 | for file in build/*; do 19 | if [ -f "$file" ] && ([[ "$(basename "$file")" == "itv_linux_amd64" ]] || [[ "$(basename "$file")" == "itv_linux_arm64" ]] || [[ "$(basename "$file")" == "itv_linux_armv7" ]]); then 20 | # 计算 MD5 21 | md5=$(md5sum "$file" | awk '{print $1}') 22 | 23 | # 写入 JSON 24 | echo " \"$(basename "$file")\": \"${md5}\"," >> "$output_file" 25 | 26 | # 生成 tar.gz 压缩包 27 | tar -czf "build/$(basename "$file").tar.gz" -C build "$(basename "$file")" 28 | fi 29 | done 30 | 31 | echo " }" >> "$output_file" 32 | echo "}" >> "$output_file" 33 | 34 | # sed -i ':a;N;$!ba;s/,\n}/\n}/' "$output_file" 35 | sed -i ':a;N;$!ba;s/, *\n *}/\n }/g' "$output_file" 36 | 37 | echo "=========推送文件至服务器=========" 38 | 39 | scp -P 22 build/*.tar.gz build/*.json root@123.123.123.123:/www/wwwroot/app 40 | 41 | echo "=========清除临时文件=========" 42 | 43 | rm build/*.tar.gz build/*.json 44 | 45 | echo "=========完毕!=========" 46 | -------------------------------------------------------------------------------- /config/config.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | // 基础配置 4 | const Version = "20250331.0000" 5 | const Port = "8123" 6 | const Debug bool = false 7 | 8 | // 自动升级配置 9 | const Update bool = false 10 | const VersionCheckURL = "https://abc.com/app/latest_version.json" 11 | const BinaryDownloadBaseURL = "https://abc.com/app/" 12 | 13 | // 运行配置 14 | var Token string = "" 15 | var Province string = "" 16 | var Operator string = "" 17 | 18 | // 省份列表 19 | var ProvinceList = map[string]string{ 20 | "北京": "Live", 21 | "天津": "Live", 22 | "河北": "Live", 23 | "山西": "Live", 24 | "内蒙": "Live", 25 | "辽宁": "Live", 26 | "吉林": "Live", 27 | "黑龙江": "Live", 28 | "上海": "Live", 29 | "江苏": "Live", 30 | "浙江": "Live", 31 | "安徽": "Live", 32 | "福建": "Live", 33 | "江西": "Live", 34 | "山东": "Live", 35 | "河南": "Live", 36 | "湖北": "Live", 37 | "湖南": "Live", 38 | "广东": "Live", 39 | "广西": "Live", 40 | "海南": "Live", 41 | "重庆": "Live", 42 | "四川": "Live", 43 | "贵州": "Live", 44 | "云南": "Live", 45 | "西藏": "Live", 46 | "陕西": "Live", 47 | "甘肃": "Live", 48 | "青海": "Live", 49 | "宁夏": "Live", 50 | "新疆": "Live", 51 | "香港": "Live", 52 | "澳门": "Live", 53 | "台湾": "Live", 54 | } 55 | 56 | // 运营商列表 57 | var OperatorList = map[string]string{ 58 | "电信": "中国电信", 59 | "联通": "中国联通", 60 | "移动": "中国移动", 61 | } 62 | -------------------------------------------------------------------------------- /docker-entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Exit on non defined variables and on non zero exit codes 4 | set -eu 5 | 6 | # Execute the compiled application with any provided arguments 7 | exec /app/itv "$@" -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module easy-itv 2 | 3 | go 1.23 4 | 5 | require github.com/gin-gonic/gin v1.10.0 6 | 7 | require ( 8 | github.com/bytedance/sonic v1.11.6 // indirect 9 | github.com/bytedance/sonic/loader v0.1.1 // indirect 10 | github.com/cloudwego/base64x v0.1.4 // indirect 11 | github.com/cloudwego/iasm v0.2.0 // indirect 12 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 13 | github.com/gabriel-vasile/mimetype v1.4.3 // indirect 14 | github.com/gin-contrib/sse v0.1.0 // indirect 15 | github.com/go-playground/locales v0.14.1 // indirect 16 | github.com/go-playground/universal-translator v0.18.1 // indirect 17 | github.com/go-playground/validator/v10 v10.20.0 // indirect 18 | github.com/goccy/go-json v0.10.2 // indirect 19 | github.com/json-iterator/go v1.1.12 // indirect 20 | github.com/klauspost/cpuid/v2 v2.2.7 // indirect 21 | github.com/leodido/go-urn v1.4.0 // indirect 22 | github.com/mattn/go-isatty v0.0.20 // indirect 23 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 24 | github.com/modern-go/reflect2 v1.0.2 // indirect 25 | github.com/pelletier/go-toml/v2 v2.2.2 // indirect 26 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 27 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 28 | github.com/ugorji/go/codec v1.2.12 // indirect 29 | golang.org/x/arch v0.8.0 // indirect 30 | golang.org/x/crypto v0.23.0 // indirect 31 | golang.org/x/net v0.25.0 // indirect 32 | golang.org/x/sys v0.20.0 // indirect 33 | golang.org/x/text v0.15.0 // indirect 34 | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect 35 | google.golang.org/protobuf v1.34.1 // indirect 36 | gopkg.in/yaml.v3 v3.0.1 // indirect 37 | ) 38 | -------------------------------------------------------------------------------- /list/m3u.go: -------------------------------------------------------------------------------- 1 | package list 2 | 3 | import ( 4 | "easy-itv/config" 5 | "easy-itv/liveITV" 6 | "easy-itv/livePhoenix" 7 | "fmt" 8 | "net/http" 9 | ) 10 | 11 | type Tvm3u struct { 12 | } 13 | 14 | func (t *Tvm3u) GetTvM3u(w http.ResponseWriter, hostname string) { 15 | fmt.Fprintln(w, "#EXTM3U x-tvg-url=\"https://e.erw.cc/all.xml\" atchup=\"append\" catchup-source=\"?playseek=${(b)yyyyMMddHHmmss}-${(e)yyyyMMddHHmmss}\"") 16 | fmt.Fprintln(w, "#EXT-X-VERSION "+config.Version) 17 | 18 | // ITV央视 19 | if liveITV.Enable && liveITV.Enable_Yangshi { 20 | // itv央视 21 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV1\" tvg-name=\"CCTV1\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV1.png\" group-title=\"央视频道\",CCTV1") 22 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV1.m3u8?token="+config.Token) 23 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV2\" tvg-name=\"CCTV2\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV2.png\" group-title=\"央视频道\",CCTV2") 24 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV2.m3u8?token="+config.Token) 25 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV3\" tvg-name=\"CCTV3\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV3.png\" group-title=\"央视频道\",CCTV3") 26 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV3.m3u8?token="+config.Token) 27 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV4\" tvg-name=\"CCTV4\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV4.png\" group-title=\"央视频道\",CCTV4") 28 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV4.m3u8?token="+config.Token) 29 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV5\" tvg-name=\"CCTV5\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV5.png\" group-title=\"央视频道\",CCTV5") 30 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV5.m3u8?token="+config.Token) 31 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV5+\" tvg-name=\"CCTV5+\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV5+.png\" group-title=\"央视频道\",CCTV5+") 32 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV5+.m3u8?token="+config.Token) 33 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV6\" tvg-name=\"CCTV6\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV6.png\" group-title=\"央视频道\",CCTV6") 34 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV6.m3u8?token="+config.Token) 35 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV7\" tvg-name=\"CCTV7\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV7.png\" group-title=\"央视频道\",CCTV7") 36 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV7.m3u8?token="+config.Token) 37 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV8\" tvg-name=\"CCTV8\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV8.png\" group-title=\"央视频道\",CCTV8") 38 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV8.m3u8?token="+config.Token) 39 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV9\" tvg-name=\"CCTV9\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV9.png\" group-title=\"央视频道\",CCTV9") 40 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV9.m3u8?token="+config.Token) 41 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV10\" tvg-name=\"CCTV10\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV10.png\" group-title=\"央视频道\",CCTV10") 42 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV10.m3u8?token="+config.Token) 43 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV11\" tvg-name=\"CCTV11\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV11.png\" group-title=\"央视频道\",CCTV11") 44 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV11.m3u8?token="+config.Token) 45 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV12\" tvg-name=\"CCTV12\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV12.png\" group-title=\"央视频道\",CCTV12") 46 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV12.m3u8?token="+config.Token) 47 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV13\" tvg-name=\"CCTV13\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV13.png\" group-title=\"央视频道\",CCTV13") 48 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV13.m3u8?token="+config.Token) 49 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV14\" tvg-name=\"CCTV14\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV14.png\" group-title=\"央视频道\",CCTV14") 50 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV14.m3u8?token="+config.Token) 51 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV15\" tvg-name=\"CCTV15\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV15.png\" group-title=\"央视频道\",CCTV15") 52 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV15.m3u8?token="+config.Token) 53 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV16\" tvg-name=\"CCTV16\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV16.png\" group-title=\"央视频道\",CCTV16") 54 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV16.m3u8?token="+config.Token) 55 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV16\" tvg-name=\"CCTV16\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV16.png\" group-title=\"央视频道\",CCTV16 4K") 56 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV16-4K.m3u8?token="+config.Token) 57 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"CCTV17\" tvg-name=\"CCTV17\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/CCTV17.png\" group-title=\"央视频道\",CCTV17") 58 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/CCTV17.m3u8?token="+config.Token) 59 | } 60 | 61 | // 凤凰秀 62 | if livePhoenix.Enable { 63 | // 凤凰秀 64 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"凤凰资讯\" tvg-name=\"凤凰资讯\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/凤凰资讯.png\" group-title=\"卫视频道\",凤凰资讯") 65 | fmt.Fprintln(w, "http://"+hostname+"/phoenix/fhzx.flv?token="+config.Token) 66 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"凤凰中文\" tvg-name=\"凤凰中文\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/凤凰中文.png\" group-title=\"卫视频道\",凤凰中文") 67 | fmt.Fprintln(w, "http://"+hostname+"/phoenix/fhzw.flv?token="+config.Token) 68 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"凤凰香港\" tvg-name=\"凤凰香港\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/凤凰香港.png\" group-title=\"卫视频道\",凤凰香港") 69 | fmt.Fprintln(w, "http://"+hostname+"/phoenix/fhhk.flv?token="+config.Token) 70 | } 71 | 72 | // ITV卫视 73 | if liveITV.Enable && liveITV.Enable_Weishi { 74 | // itv卫视 75 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"北京卫视\" tvg-name=\"北京卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/北京卫视.png\" group-title=\"卫视频道\",北京卫视") 76 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/北京卫视.m3u8?token="+config.Token) 77 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"东方卫视\" tvg-name=\"东方卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/东方卫视.png\" group-title=\"卫视频道\",东方卫视") 78 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/东方卫视.m3u8?token="+config.Token) 79 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"湖南卫视\" tvg-name=\"湖南卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/湖南卫视.png\" group-title=\"卫视频道\",湖南卫视") 80 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/湖南卫视.m3u8?token="+config.Token) 81 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"江苏卫视\" tvg-name=\"江苏卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/江苏卫视.png\" group-title=\"卫视频道\",江苏卫视") 82 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/江苏卫视.m3u8?token="+config.Token) 83 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"浙江卫视\" tvg-name=\"浙江卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/浙江卫视.png\" group-title=\"卫视频道\",浙江卫视") 84 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/浙江卫视.m3u8?token="+config.Token) 85 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"安徽卫视\" tvg-name=\"安徽卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/安徽卫视.png\" group-title=\"卫视频道\",安徽卫视") 86 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/安徽卫视.m3u8?token="+config.Token) 87 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"东南卫视\" tvg-name=\"东南卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/东南卫视.png\" group-title=\"卫视频道\",东南卫视") 88 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/东南卫视.m3u8?token="+config.Token) 89 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"厦门卫视\" tvg-name=\"厦门卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/厦门卫视.png\" group-title=\"卫视频道\",厦门卫视") 90 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/厦门卫视.m3u8?token="+config.Token) 91 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"甘肃卫视\" tvg-name=\"甘肃卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/甘肃卫视.png\" group-title=\"卫视频道\",甘肃卫视") 92 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/甘肃卫视.m3u8?token="+config.Token) 93 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"广东卫视\" tvg-name=\"广东卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/广东卫视.png\" group-title=\"卫视频道\",广东卫视") 94 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/广东卫视.m3u8?token="+config.Token) 95 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"大湾区卫视\" tvg-name=\"大湾区卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/大湾区卫视.png\" group-title=\"卫视频道\",大湾区卫视") 96 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/大湾区卫视.m3u8?token="+config.Token) 97 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"三沙卫视\" tvg-name=\"三沙卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/三沙卫视.png\" group-title=\"卫视频道\",三沙卫视") 98 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/三沙卫视.m3u8?token="+config.Token) 99 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"广西卫视\" tvg-name=\"广西卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/广西卫视.png\" group-title=\"卫视频道\",广西卫视") 100 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/广西卫视.m3u8?token="+config.Token) 101 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"贵州卫视\" tvg-name=\"贵州卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/贵州卫视.png\" group-title=\"卫视频道\",贵州卫视") 102 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/贵州卫视.m3u8?token="+config.Token) 103 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"海南卫视\" tvg-name=\"海南卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/海南卫视.png\" group-title=\"卫视频道\",海南卫视") 104 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/海南卫视.m3u8?token="+config.Token) 105 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"河北卫视\" tvg-name=\"河北卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/河北卫视.png\" group-title=\"卫视频道\",河北卫视") 106 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/河北卫视.m3u8?token="+config.Token) 107 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"河南卫视\" tvg-name=\"河南卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/河南卫视.png\" group-title=\"卫视频道\",河南卫视") 108 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/河南卫视.m3u8?token="+config.Token) 109 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"黑龙江卫视\" tvg-name=\"黑龙江卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/黑龙江卫视.png\" group-title=\"卫视频道\",黑龙江卫视") 110 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/黑龙江卫视.m3u8?token="+config.Token) 111 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"湖北卫视\" tvg-name=\"湖北卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/湖北卫视.png\" group-title=\"卫视频道\",湖北卫视") 112 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/湖北卫视.m3u8?token="+config.Token) 113 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"吉林卫视\" tvg-name=\"吉林卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/吉林卫视.png\" group-title=\"卫视频道\",吉林卫视") 114 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/吉林卫视.m3u8?token="+config.Token) 115 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"延边卫视\" tvg-name=\"延边卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/延边卫视.png\" group-title=\"卫视频道\",延边卫视") 116 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/延边卫视.m3u8?token="+config.Token) 117 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"江西卫视\" tvg-name=\"江西卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/江西卫视.png\" group-title=\"卫视频道\",江西卫视") 118 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/江西卫视.m3u8?token="+config.Token) 119 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"辽宁卫视\" tvg-name=\"辽宁卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/辽宁卫视.png\" group-title=\"卫视频道\",辽宁卫视") 120 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/辽宁卫视.m3u8?token="+config.Token) 121 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"山东卫视\" tvg-name=\"山东卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/山东卫视.png\" group-title=\"卫视频道\",山东卫视") 122 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/山东卫视.m3u8?token="+config.Token) 123 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"山东教育卫视\" tvg-name=\"山东教育卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/山东教育卫视.png\" group-title=\"卫视频道\",山东教育卫视") 124 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/山东教育卫视.m3u8?token="+config.Token) 125 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"深圳卫视\" tvg-name=\"深圳卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/深圳卫视.png\" group-title=\"卫视频道\",深圳卫视") 126 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/深圳卫视.m3u8?token="+config.Token) 127 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"四川卫视\" tvg-name=\"四川卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/四川卫视.png\" group-title=\"卫视频道\",四川卫视") 128 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/四川卫视.m3u8?token="+config.Token) 129 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"天津卫视\" tvg-name=\"天津卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/天津卫视.png\" group-title=\"卫视频道\",天津卫视") 130 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/天津卫视.m3u8?token="+config.Token) 131 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"云南卫视\" tvg-name=\"云南卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/云南卫视.png\" group-title=\"卫视频道\",云南卫视") 132 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/云南卫视.m3u8?token="+config.Token) 133 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"重庆卫视\" tvg-name=\"重庆卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/重庆卫视.png\" group-title=\"卫视频道\",重庆卫视") 134 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/重庆卫视.m3u8?token="+config.Token) 135 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"内蒙古卫视\" tvg-name=\"内蒙古卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/内蒙古卫视.png\" group-title=\"卫视频道\",内蒙古卫视") 136 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/内蒙古卫视.m3u8?token="+config.Token) 137 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"宁夏卫视\" tvg-name=\"宁夏卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/宁夏卫视.png\" group-title=\"卫视频道\",宁夏卫视") 138 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/宁夏卫视.m3u8?token="+config.Token) 139 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"青海卫视\" tvg-name=\"青海卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/青海卫视.png\" group-title=\"卫视频道\",青海卫视") 140 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/青海卫视.m3u8?token="+config.Token) 141 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"山西卫视\" tvg-name=\"山西卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/山西卫视.png\" group-title=\"卫视频道\",山西卫视") 142 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/山西卫视.m3u8?token="+config.Token) 143 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"陕西卫视\" tvg-name=\"陕西卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/陕西卫视.png\" group-title=\"卫视频道\",陕西卫视") 144 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/陕西卫视.m3u8?token="+config.Token) 145 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"西藏卫视\" tvg-name=\"西藏卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/西藏卫视.png\" group-title=\"卫视频道\",西藏卫视") 146 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/西藏卫视.m3u8?token="+config.Token) 147 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"新疆卫视\" tvg-name=\"新疆卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/新疆卫视.png\" group-title=\"卫视频道\",新疆卫视") 148 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/新疆卫视.m3u8?token="+config.Token) 149 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"安多卫视\" tvg-name=\"安多卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/安多卫视.png\" group-title=\"卫视频道\",安多卫视") 150 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/安多卫视.m3u8?token="+config.Token) 151 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"兵团卫视\" tvg-name=\"兵团卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/兵团卫视.png\" group-title=\"卫视频道\",兵团卫视") 152 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/兵团卫视.m3u8?token="+config.Token) 153 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"康巴卫视\" tvg-name=\"康巴卫视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/康巴卫视.png\" group-title=\"卫视频道\",康巴卫视") 154 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/康巴卫视.m3u8?token="+config.Token) 155 | } 156 | 157 | // ITV数字频道 158 | if liveITV.Enable { 159 | // 地方数字 160 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"北京纪实科教\" tvg-name=\"北京纪实科教\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/北京纪实科教.png\" group-title=\"地方数字\",北京纪实科教") 161 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/北京纪实科教.m3u8?token="+config.Token) 162 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"卡酷少儿\" tvg-name=\"卡酷少儿\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/卡酷少儿.png\" group-title=\"地方数字\",卡酷少儿") 163 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/卡酷少儿.m3u8?token="+config.Token) 164 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"新闻综合\" tvg-name=\"新闻综合\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/上海新闻综合.png\" group-title=\"地方数字\",上海新闻综合") 165 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/上海新闻综合.m3u8?token="+config.Token) 166 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"东方影视\" tvg-name=\"东方影视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/东方影视.png\" group-title=\"地方数字\",东方影视") 167 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/东方影视.m3u8?token="+config.Token) 168 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"五星体育\" tvg-name=\"五星体育\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/五星体育.png\" group-title=\"地方数字\",五星体育") 169 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/五星体育.m3u8?token="+config.Token) 170 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"东方财经\" tvg-name=\"东方财经\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/东方财经.png\" group-title=\"地方数字\",东方财经") 171 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/东方财经.m3u8?token="+config.Token) 172 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"第一财经\" tvg-name=\"第一财经\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/第一财经.png\" group-title=\"地方数字\",第一财经") 173 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/第一财经.m3u8?token="+config.Token) 174 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"上海都市\" tvg-name=\"上海都市\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/上海都市.png\" group-title=\"地方数字\",上海都市") 175 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/上海都市.m3u8?token="+config.Token) 176 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"广东珠江\" tvg-name=\"广东珠江\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/广东珠江.png\" group-title=\"地方数字\",广东珠江") 177 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/广东珠江.m3u8?token="+config.Token) 178 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"浙江教科影视\" tvg-name=\"浙江教科影视\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/浙江教科影视.png\" group-title=\"地方数字\",浙江教科影视") 179 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/浙江教科影视.m3u8?token="+config.Token) 180 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"茶频道\" tvg-name=\"茶频道\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/茶频道.png\" group-title=\"地方数字\",茶频道") 181 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/茶频道.m3u8?token="+config.Token) 182 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"快乐垂钓\" tvg-name=\"快乐垂钓\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/快乐垂钓.png\" group-title=\"地方数字\",快乐垂钓") 183 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/快乐垂钓.m3u8?token="+config.Token) 184 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"金鹰卡通\" tvg-name=\"金鹰卡通\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/金鹰卡通.png\" group-title=\"地方数字\",金鹰卡通") 185 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/金鹰卡通.m3u8?token="+config.Token) 186 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"家庭理财\" tvg-name=\"家庭理财\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/家庭理财.png\" group-title=\"地方数字\",家庭理财") 187 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/家庭理财.m3u8?token="+config.Token) 188 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"东方大剧院\" tvg-name=\"东方大剧院\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/风尚音乐.png\" group-title=\"地方数字\",东方大剧院") 189 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/东方大剧院.m3u8?token="+config.Token) 190 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"电子竞技\" tvg-name=\"电子竞技\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/电子竞技.png\" group-title=\"地方数字\",电子竞技") 191 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/电子竞技.m3u8?token="+config.Token) 192 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"高清娱乐\" tvg-name=\"高清娱乐\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/高清娱乐.png\" group-title=\"地方数字\",高清娱乐") 193 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/高清娱乐.m3u8?token="+config.Token) 194 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"漫游世界\" tvg-name=\"漫游世界\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/漫游世界.png\" group-title=\"地方数字\",漫游世界") 195 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/漫游世界.m3u8?token="+config.Token) 196 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"热播精选\" tvg-name=\"热播精选\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/热播精选.png\" group-title=\"地方数字\",热播精选") 197 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/热播精选.m3u8?token="+config.Token) 198 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"探索纪录\" tvg-name=\"探索纪录\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/探索纪录.png\" group-title=\"地方数字\",探索纪录") 199 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/探索纪录.m3u8?token="+config.Token) 200 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"精品综合\" tvg-name=\"精品综合\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/精品综合.png\" group-title=\"地方数字\",精品综合") 201 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/精品综合.m3u8?token="+config.Token) 202 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"精品剧场\" tvg-name=\"精品剧场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/精品剧场.png\" group-title=\"地方数字\",精品剧场") 203 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/精品剧场.m3u8?token="+config.Token) 204 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"欧美影院\" tvg-name=\"欧美影院\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/欧美影院.png\" group-title=\"地方数字\",欧美影院") 205 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/欧美影院.m3u8?token="+config.Token) 206 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"少儿动漫\" tvg-name=\"少儿动漫\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/少儿动漫.png\" group-title=\"地方数字\",少儿动漫") 207 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/少儿动漫.m3u8?token="+config.Token) 208 | 209 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"求索动物\" tvg-name=\"求索动物\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/求索动物.png\" group-title=\"地方数字\",求索动物") 210 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/求索动物.m3u8?token="+config.Token) 211 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"求索纪录\" tvg-name=\"求索纪录\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/求索纪录.png\" group-title=\"地方数字\",求索纪录") 212 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/求索纪录.m3u8?token="+config.Token) 213 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"求索科学\" tvg-name=\"求索科学\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/求索科学.png\" group-title=\"地方数字\",求索科学") 214 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/求索科学.m3u8?token="+config.Token) 215 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"求索生活\" tvg-name=\"求索生活\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/求索生活.png\" group-title=\"地方数字\",求索生活") 216 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/求索生活.m3u8?token="+config.Token) 217 | 218 | // NewTV 219 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"哒啵电竞\" tvg-name=\"哒啵电竞\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV哒啵电竞.png\" group-title=\"NewTV\",哒啵电竞") 220 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/哒啵电竞.m3u8?token="+config.Token) 221 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"哒啵赛事\" tvg-name=\"哒啵赛事\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV哒啵赛事.png\" group-title=\"NewTV\",哒啵赛事") 222 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/哒啵赛事.m3u8?token="+config.Token) 223 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"黑莓电影\" tvg-name=\"黑莓电影\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV黑莓电影.png\" group-title=\"NewTV\",黑莓电影") 224 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/黑莓电影.m3u8?token="+config.Token) 225 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"黑莓动画\" tvg-name=\"黑莓动画\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV黑莓动画.png\" group-title=\"NewTV\",黑莓动画") 226 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/黑莓动画.m3u8?token="+config.Token) 227 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱情喜剧\" tvg-name=\"爱情喜剧\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV爱情喜剧.png\" group-title=\"NewTV\",爱情喜剧") 228 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱情喜剧.m3u8?token="+config.Token) 229 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"超级电视剧\" tvg-name=\"超级电视剧\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV超级电视剧.png\" group-title=\"NewTV\",超级电视剧") 230 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/超级电视剧.m3u8?token="+config.Token) 231 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"超级电影\" tvg-name=\"超级电影\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV超级电影.png\" group-title=\"NewTV\",超级电影") 232 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/超级电影.m3u8?token="+config.Token) 233 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"超级体育\" tvg-name=\"超级体育\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV超级体育.png\" group-title=\"NewTV\",超级体育") 234 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/超级体育.m3u8?token="+config.Token) 235 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"超级综艺\" tvg-name=\"超级综艺\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV超级综艺.png\" group-title=\"NewTV\",超级综艺") 236 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/超级综艺.m3u8?token="+config.Token) 237 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"潮妈辣婆\" tvg-name=\"潮妈辣婆\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV潮妈辣婆.png\" group-title=\"NewTV\",潮妈辣婆") 238 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/潮妈辣婆.m3u8?token="+config.Token) 239 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"东北热剧\" tvg-name=\"东北热剧\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV东北热剧.png\" group-title=\"NewTV\",东北热剧") 240 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/东北热剧.m3u8?token="+config.Token) 241 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"动作电影\" tvg-name=\"动作电影\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV动作电影.png\" group-title=\"NewTV\",动作电影") 242 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/动作电影.m3u8?token="+config.Token) 243 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"古装剧场\" tvg-name=\"古装剧场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV古装剧场.png\" group-title=\"NewTV\",古装剧场") 244 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/古装剧场.m3u8?token="+config.Token) 245 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"欢乐剧场\" tvg-name=\"欢乐剧场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV欢乐剧场.png\" group-title=\"NewTV\",欢乐剧场") 246 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/欢乐剧场.m3u8?token="+config.Token) 247 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"家庭剧场\" tvg-name=\"家庭剧场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV家庭剧场.png\" group-title=\"NewTV\",家庭剧场") 248 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/家庭剧场.m3u8?token="+config.Token) 249 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"金牌综艺\" tvg-name=\"金牌综艺\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV金牌综艺.png\" group-title=\"NewTV\",金牌综艺") 250 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/金牌综艺.m3u8?token="+config.Token) 251 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"惊悚悬疑\" tvg-name=\"惊悚悬疑\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV惊悚悬疑.png\" group-title=\"NewTV\",惊悚悬疑") 252 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/惊悚悬疑.m3u8?token="+config.Token) 253 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"精品大剧\" tvg-name=\"精品大剧\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV精品大剧.png\" group-title=\"NewTV\",精品大剧") 254 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/精品大剧.m3u8?token="+config.Token) 255 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"精品纪录\" tvg-name=\"精品纪录\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV精品纪录.png\" group-title=\"NewTV\",精品纪录") 256 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/精品纪录.m3u8?token="+config.Token) 257 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"精品萌宠\" tvg-name=\"精品萌宠\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV精品萌宠.png\" group-title=\"NewTV\",精品萌宠") 258 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/精品萌宠.m3u8?token="+config.Token) 259 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"精品体育\" tvg-name=\"精品体育\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV精品体育.png\" group-title=\"NewTV\",精品体育") 260 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/精品体育.m3u8?token="+config.Token) 261 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"军旅剧场\" tvg-name=\"军旅剧场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV军旅剧场.png\" group-title=\"NewTV\",军旅剧场") 262 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/军旅剧场.m3u8?token="+config.Token) 263 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"军事评论\" tvg-name=\"军事评论\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV军事评论.png\" group-title=\"NewTV\",军事评论") 264 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/军事评论.m3u8?token="+config.Token) 265 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"魅力潇湘\" tvg-name=\"魅力潇湘\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV魅力潇湘.png\" group-title=\"NewTV\",魅力潇湘") 266 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/魅力潇湘.m3u8?token="+config.Token) 267 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"农业致富\" tvg-name=\"农业致富\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV农业致富.png\" group-title=\"NewTV\",农业致富") 268 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/农业致富.m3u8?token="+config.Token) 269 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"武搏世界\" tvg-name=\"武搏世界\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV武搏世界.png\" group-title=\"NewTV\",武搏世界") 270 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/武搏世界.m3u8?token="+config.Token) 271 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"炫舞未来\" tvg-name=\"炫舞未来\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV炫舞未来.png\" group-title=\"NewTV\",炫舞未来") 272 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/炫舞未来.m3u8?token="+config.Token) 273 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"怡伴健康\" tvg-name=\"怡伴健康\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV怡伴健康.png\" group-title=\"NewTV\",怡伴健康") 274 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/怡伴健康.m3u8?token="+config.Token) 275 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"中国功夫\" tvg-name=\"中国功夫\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/NEWTV中国功夫.png\" group-title=\"NewTV\",中国功夫") 276 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/中国功夫.m3u8?token="+config.Token) 277 | 278 | // SiTV 279 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"动漫秀场\" tvg-name=\"动漫秀场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/动漫秀场.png\" group-title=\"SiTV\",动漫秀场") 280 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/动漫秀场.m3u8?token="+config.Token) 281 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"都市剧场\" tvg-name=\"都市剧场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/都市剧场.png\" group-title=\"SiTV\",都市剧场") 282 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/都市剧场.m3u8?token="+config.Token) 283 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"法治天地\" tvg-name=\"法治天地\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/法治天地.png\" group-title=\"SiTV\",法治天地") 284 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/法治天地.m3u8?token="+config.Token) 285 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"欢笑剧场\" tvg-name=\"欢笑剧场\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/欢笑剧场.png\" group-title=\"SiTV\",欢笑剧场") 286 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/欢笑剧场.m3u8?token="+config.Token) 287 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"金色学堂\" tvg-name=\"金色学堂\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/金色学堂.png\" group-title=\"SiTV\",金色学堂") 288 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/金色学堂.m3u8?token="+config.Token) 289 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"劲爆体育\" tvg-name=\"劲爆体育\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/劲爆体育.png\" group-title=\"SiTV\",劲爆体育") 290 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/劲爆体育.m3u8?token="+config.Token) 291 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"乐游\" tvg-name=\"乐游\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/乐游.png\" group-title=\"SiTV\",乐游") 292 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/乐游.m3u8?token="+config.Token) 293 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"魅力足球\" tvg-name=\"魅力足球\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/魅力足球.png\" group-title=\"SiTV\",魅力足球") 294 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/魅力足球.m3u8?token="+config.Token) 295 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"生活时尚\" tvg-name=\"生活时尚\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/生活时尚.png\" group-title=\"SiTV\",生活时尚") 296 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/生活时尚.m3u8?token="+config.Token) 297 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"游戏风云\" tvg-name=\"游戏风云\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/游戏风云.png\" group-title=\"SiTV\",游戏风云") 298 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/游戏风云.m3u8?token="+config.Token) 299 | 300 | // IHOT 301 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱谍战\" tvg-name=\"爱谍战\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱谍战.png\" group-title=\"IHOT\",爱谍战") 302 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱谍战.m3u8?token="+config.Token) 303 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱动漫\" tvg-name=\"爱动漫\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱动漫.png\" group-title=\"IHOT\",爱动漫") 304 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱动漫.m3u8?token="+config.Token) 305 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱科幻\" tvg-name=\"爱科幻\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱科幻.png\" group-title=\"IHOT\",爱科幻") 306 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱科幻.m3u8?token="+config.Token) 307 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱科学\" tvg-name=\"爱科学\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱科学.png\" group-title=\"IHOT\",爱科学") 308 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱科学.m3u8?token="+config.Token) 309 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱浪漫\" tvg-name=\"爱浪漫\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱浪漫.png\" group-title=\"IHOT\",爱浪漫") 310 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱浪漫.m3u8?token="+config.Token) 311 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱历史\" tvg-name=\"爱历史\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱历史.png\" group-title=\"IHOT\",爱历史") 312 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱历史.m3u8?token="+config.Token) 313 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱旅行\" tvg-name=\"爱旅行\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱旅行.png\" group-title=\"IHOT\",爱旅行") 314 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱旅行.m3u8?token="+config.Token) 315 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱奇谈\" tvg-name=\"爱奇谈\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱奇谈.png\" group-title=\"IHOT\",爱奇谈") 316 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱奇谈.m3u8?token="+config.Token) 317 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱赛车\" tvg-name=\"爱赛车\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱赛车.png\" group-title=\"IHOT\",爱赛车") 318 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱赛车.m3u8?token="+config.Token) 319 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱体育\" tvg-name=\"爱体育\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱体育.png\" group-title=\"IHOT\",爱体育") 320 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱体育.m3u8?token="+config.Token) 321 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱玩具\" tvg-name=\"爱玩具\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱玩具.png\" group-title=\"IHOT\",爱玩具") 322 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱玩具.m3u8?token="+config.Token) 323 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱喜剧\" tvg-name=\"爱喜剧\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱喜剧.png\" group-title=\"IHOT\",爱喜剧") 324 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱喜剧.m3u8?token="+config.Token) 325 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱悬疑\" tvg-name=\"爱悬疑\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱悬疑.png\" group-title=\"IHOT\",爱悬疑") 326 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱悬疑.m3u8?token="+config.Token) 327 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱幼教\" tvg-name=\"爱幼教\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱幼教.png\" group-title=\"IHOT\",爱幼教") 328 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱幼教.m3u8?token="+config.Token) 329 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"爱院线\" tvg-name=\"爱院线\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/IHOT爱院线.png\" group-title=\"IHOT\",爱院线") 330 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/爱院线.m3u8?token="+config.Token) 331 | 332 | // 咪视通 333 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"睛彩广场舞\" tvg-name=\"睛彩广场舞\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/睛彩广场舞.png\" group-title=\"咪视通\",睛彩广场舞") 334 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/睛彩广场舞.m3u8?token="+config.Token) 335 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"睛彩竞技\" tvg-name=\"睛彩竞技\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/睛彩竞技.png\" group-title=\"咪视通\",睛彩竞技") 336 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/睛彩竞技.m3u8?token="+config.Token) 337 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"睛彩篮球\" tvg-name=\"睛彩篮球\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/睛彩篮球.png\" group-title=\"咪视通\",睛彩篮球") 338 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/睛彩篮球.m3u8?token="+config.Token) 339 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"睛彩青少\" tvg-name=\"睛彩青少\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/睛彩青少.png\" group-title=\"咪视通\",睛彩青少") 340 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/睛彩青少.m3u8?token="+config.Token) 341 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-1") 342 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000005308.m3u8?token="+config.Token) 343 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-2") 344 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000005969.m3u8?token="+config.Token) 345 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-3") 346 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000007218.m3u8?token="+config.Token) 347 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-4") 348 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000008001.m3u8?token="+config.Token) 349 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-5") 350 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000008176.m3u8?token="+config.Token) 351 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-6") 352 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000008379.m3u8?token="+config.Token) 353 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-7") 354 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000010129.m3u8?token="+config.Token) 355 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-8") 356 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000010948.m3u8?token="+config.Token) 357 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-9") 358 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000028638.m3u8?token="+config.Token) 359 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-10") 360 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000001000031494.m3u8?token="+config.Token) 361 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-11") 362 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000005837.m3u8?token="+config.Token) 363 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-12") 364 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000020000011518.m3u8?token="+config.Token) 365 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-13") 366 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000020000011519.m3u8?token="+config.Token) 367 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-14") 368 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000020000011520.m3u8?token="+config.Token) 369 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-15") 370 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000020000011521.m3u8?token="+config.Token) 371 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-16") 372 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000020000011522.m3u8?token="+config.Token) 373 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-24") 374 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000000097.m3u8?token="+config.Token) 375 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-25") 376 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000002019.m3u8?token="+config.Token) 377 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-26") 378 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000002809.m3u8?token="+config.Token) 379 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-27") 380 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000003915.m3u8?token="+config.Token) 381 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-28") 382 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000004193.m3u8?token="+config.Token) 383 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-29") 384 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000006077.m3u8?token="+config.Token) 385 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-30") 386 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000006658.m3u8?token="+config.Token) 387 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-31") 388 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000009788.m3u8?token="+config.Token) 389 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-32") 390 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000010833.m3u8?token="+config.Token) 391 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-33") 392 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000011297.m3u8?token="+config.Token) 393 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-34") 394 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000011518.m3u8?token="+config.Token) 395 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-35") 396 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000012558.m3u8?token="+config.Token) 397 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-36") 398 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000012616.m3u8?token="+config.Token) 399 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-37") 400 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000015470.m3u8?token="+config.Token) 401 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-38") 402 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000015560.m3u8?token="+config.Token) 403 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-39") 404 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000017678.m3u8?token="+config.Token) 405 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-40") 406 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000019839.m3u8?token="+config.Token) 407 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-41") 408 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000021904.m3u8?token="+config.Token) 409 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-42") 410 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000023434.m3u8?token="+config.Token) 411 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-43") 412 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000025380.m3u8?token="+config.Token) 413 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-44") 414 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000027691.m3u8?token="+config.Token) 415 | fmt.Fprintln(w, "#EXTINF:-1,tvg-id=\"咪咕视频\" tvg-name=\"咪咕视频\" tvg-logo=\"https://gcore.jsdelivr.net/gh/taksssss/tv/icon/咪咕视频.png\" group-title=\"咪视通\",咪咕视频-45") 416 | fmt.Fprintln(w, "http://"+hostname+"/TVOD/3000000010000031669.m3u8?token="+config.Token) 417 | } 418 | } 419 | -------------------------------------------------------------------------------- /liveITV/config.go: -------------------------------------------------------------------------------- 1 | package liveITV 2 | 3 | import ( 4 | "fmt" 5 | "strings" 6 | "sync" 7 | ) 8 | 9 | var Enable bool = true 10 | var Debug bool = false 11 | 12 | var Enable_Yangshi bool = true 13 | var Enable_Weishi bool = true 14 | 15 | var WorkIP_bestzb string = "" 16 | var IPList_bestzb = []IPRecord{ 17 | {Address: "39.135.132.221", Fail: 0}, 18 | } 19 | 20 | var WorkIP_hnbblive string = "" 21 | var IPList_hnbblive = []IPRecord{ 22 | {Address: "39.135.132.221", Fail: 0}, 23 | } 24 | 25 | var WorkIP_fifalive string = "" 26 | var IPList_fifalive = []IPRecord{ 27 | {Address: "39.135.132.221", Fail: 0}, 28 | } 29 | 30 | var ChannelList = []ChannelRecord{ 31 | {Group: "央视", Tvgid: "CCTV1", Contentid: "5000000004000002226", Cdn: "bestzb", Quality: "$8M FHD"}, 32 | {Group: "央视", Tvgid: "CCTV2", Contentid: "5000000011000031101", Cdn: "bestzb", Quality: "$8M FHD"}, 33 | {Group: "央视", Tvgid: "CCTV3", Contentid: "5000000004000008883", Cdn: "bestzb", Quality: "$8M FHD"}, 34 | {Group: "央视", Tvgid: "CCTV4", Contentid: "5000000011000031102", Cdn: "bestzb", Quality: "$8M FHD"}, 35 | {Group: "央视", Tvgid: "CCTV5", Contentid: "5000000004000008885", Cdn: "bestzb", Quality: "$8M FHD"}, 36 | {Group: "央视", Tvgid: "CCTV5+", Contentid: "5000000011000031127", Cdn: "bestzb", Quality: "$8M FHD"}, 37 | {Group: "央视", Tvgid: "CCTV6", Contentid: "5000000004000008886", Cdn: "bestzb", Quality: "$8M FHD"}, 38 | {Group: "央视", Tvgid: "CCTV7", Contentid: "5000000011000031104", Cdn: "bestzb", Quality: "$8M FHD"}, 39 | {Group: "央视", Tvgid: "CCTV8", Contentid: "5000000004000008888", Cdn: "bestzb", Quality: "$8M FHD"}, 40 | {Group: "央视", Tvgid: "CCTV9", Contentid: "5000000011000288020", Cdn: "bestzb", Quality: "$8M FHD"}, 41 | {Group: "央视", Tvgid: "CCTV10", Contentid: "5000000004000012827", Cdn: "bestzb", Quality: "$8M FHD"}, 42 | {Group: "央视", Tvgid: "CCTV11", Contentid: "5000000011000031106", Cdn: "bestzb", Quality: "$8M FHD"}, 43 | {Group: "央视", Tvgid: "CCTV12", Contentid: "5000000011000031107", Cdn: "bestzb", Quality: "$8M FHD"}, 44 | {Group: "央视", Tvgid: "CCTV13", Contentid: "5000000011000031108", Cdn: "bestzb", Quality: "$8M FHD"}, 45 | {Group: "央视", Tvgid: "CCTV14", Contentid: "5000000004000006673", Cdn: "bestzb", Quality: "$8M FHD"}, 46 | {Group: "央视", Tvgid: "CCTV15", Contentid: "5000000011000031109", Cdn: "bestzb", Quality: "$8M FHD"}, 47 | {Group: "央视", Tvgid: "CCTV16", Contentid: "5000000008000023253", Cdn: "bestzb", Quality: "$8M FHD"}, 48 | {Group: "央视", Tvgid: "CCTV16-4K", Contentid: "5000000008000023254", Cdn: "bestzb", Quality: "$12M UHD HEVC"}, 49 | {Group: "央视", Tvgid: "CCTV17", Contentid: "5000000011000288014", Cdn: "bestzb", Quality: "$8M FHD"}, 50 | 51 | {Group: "卫视", Tvgid: "安徽卫视", Contentid: "5000000004000023002", Cdn: "bestzb", Quality: "$8M FHD"}, 52 | {Group: "卫视", Tvgid: "北京卫视", Contentid: "5000000004000031556", Cdn: "bestzb", Quality: "$8M FHD"}, 53 | {Group: "卫视", Tvgid: "东方卫视", Contentid: "5000000004000014098", Cdn: "bestzb", Quality: "$8M FHD"}, 54 | {Group: "卫视", Tvgid: "东南卫视", Contentid: "5000000004000010584", Cdn: "bestzb", Quality: "$8M FHD"}, 55 | {Group: "卫视", Tvgid: "甘肃卫视", Contentid: "5000000011000031121", Cdn: "bestzb", Quality: "$8M FHD"}, 56 | {Group: "卫视", Tvgid: "广东卫视", Contentid: "5000000004000014694", Cdn: "bestzb", Quality: "$8M FHD"}, 57 | {Group: "卫视", Tvgid: "广西卫视", Contentid: "5000000011000031118", Cdn: "bestzb", Quality: "$8M FHD"}, 58 | {Group: "卫视", Tvgid: "贵州卫视", Contentid: "5000000004000025843", Cdn: "bestzb", Quality: "$8M FHD"}, 59 | {Group: "卫视", Tvgid: "海南卫视", Contentid: "5000000004000006211", Cdn: "bestzb", Quality: "$8M FHD"}, 60 | {Group: "卫视", Tvgid: "河北卫视", Contentid: "5000000006000040016", Cdn: "bestzb", Quality: "$8M FHD"}, 61 | {Group: "卫视", Tvgid: "河南卫视", Contentid: "5000000011000031119", Cdn: "bestzb", Quality: "$8M FHD"}, 62 | {Group: "卫视", Tvgid: "黑龙江卫视", Contentid: "5000000004000025203", Cdn: "bestzb", Quality: "$8M FHD"}, 63 | {Group: "卫视", Tvgid: "湖北卫视", Contentid: "5000000004000014954", Cdn: "bestzb", Quality: "$8M FHD"}, 64 | {Group: "卫视", Tvgid: "湖南卫视", Contentid: "5000000004000006692", Cdn: "bestzb", Quality: "$8M FHD"}, 65 | {Group: "卫视", Tvgid: "吉林卫视", Contentid: "5000000011000031117", Cdn: "bestzb", Quality: "$8M FHD"}, 66 | {Group: "卫视", Tvgid: "江苏卫视", Contentid: "5000000004000019351", Cdn: "bestzb", Quality: "$8M FHD"}, 67 | {Group: "卫视", Tvgid: "江西卫视", Contentid: "5000000004000011210", Cdn: "bestzb", Quality: "$8M FHD"}, 68 | {Group: "卫视", Tvgid: "辽宁卫视", Contentid: "5000000004000011671", Cdn: "bestzb", Quality: "$8M FHD"}, 69 | {Group: "卫视", Tvgid: "三沙卫视", Contentid: "5000000011000288016", Cdn: "bestzb", Quality: "$8M FHD"}, 70 | {Group: "卫视", Tvgid: "山东卫视", Contentid: "5000000004000020424", Cdn: "bestzb", Quality: "$8M FHD"}, 71 | {Group: "卫视", Tvgid: "深圳卫视", Contentid: "5000000004000007410", Cdn: "bestzb", Quality: "$8M FHD"}, 72 | {Group: "卫视", Tvgid: "四川卫视", Contentid: "5000000004000006119", Cdn: "bestzb", Quality: "$8M FHD"}, 73 | {Group: "卫视", Tvgid: "天津卫视", Contentid: "5000000004000006827", Cdn: "bestzb", Quality: "$8M FHD"}, 74 | {Group: "卫视", Tvgid: "云南卫视", Contentid: "5000000011000031120", Cdn: "bestzb", Quality: "$8M FHD"}, 75 | {Group: "卫视", Tvgid: "浙江卫视", Contentid: "5000000004000007275", Cdn: "bestzb", Quality: "$8M FHD"}, 76 | {Group: "卫视", Tvgid: "重庆卫视", Contentid: "5000000004000025797", Cdn: "bestzb", Quality: "$8M FHD"}, 77 | {Group: "卫视", Tvgid: "内蒙古卫视", Contentid: "7331079758781182663", Cdn: "bestzb", Quality: "$2M SD"}, 78 | {Group: "卫视", Tvgid: "宁夏卫视", Contentid: "5000000006000040022", Cdn: "bestzb", Quality: "$4M SD"}, 79 | {Group: "卫视", Tvgid: "青海卫视", Contentid: "5000000006000040015", Cdn: "bestzb", Quality: "$4M FHD"}, 80 | {Group: "卫视", Tvgid: "山西卫视", Contentid: "5000000006000040023", Cdn: "bestzb", Quality: "$4M SD"}, 81 | {Group: "卫视", Tvgid: "陕西卫视", Contentid: "5000000006000040017", Cdn: "bestzb", Quality: "$4M SD"}, 82 | {Group: "卫视", Tvgid: "西藏卫视", Contentid: "5381760837640571168", Cdn: "bestzb", Quality: "$2M SD"}, 83 | {Group: "卫视", Tvgid: "新疆卫视", Contentid: "5000000006000040018", Cdn: "bestzb", Quality: "$4M SD"}, 84 | {Group: "卫视", Tvgid: "安多卫视", Contentid: "5000000006000022124", Cdn: "bestzb", Quality: "$2M SD"}, 85 | {Group: "卫视", Tvgid: "兵团卫视", Contentid: "5000000006000040020", Cdn: "bestzb", Quality: "$4M SD"}, 86 | {Group: "卫视", Tvgid: "康巴卫视", Contentid: "5000000003000001598", Cdn: "bestzb", Quality: "$2M SD"}, 87 | {Group: "卫视", Tvgid: "厦门卫视", Contentid: "5084893189220221988", Cdn: "bestzb", Quality: "$2M SD"}, 88 | {Group: "卫视", Tvgid: "大湾区卫视", Contentid: "2000000003000000045", Cdn: "hnbblive", Quality: "$4M SD"}, 89 | {Group: "卫视", Tvgid: "山东教育卫视", Contentid: "2000000003000000013", Cdn: "hnbblive", Quality: "$2M SD"}, 90 | {Group: "卫视", Tvgid: "延边卫视", Contentid: "2000000003000000049", Cdn: "hnbblive", Quality: "$4M SD"}, 91 | 92 | {Group: "数字", Tvgid: "北京纪实科教", Contentid: "2000000002000000065", Cdn: "hnbblive", Quality: "$8M FHD"}, 93 | {Group: "数字", Tvgid: "上海新闻综合", Contentid: "2000000002000000005", Cdn: "hnbblive", Quality: "$8M FHD"}, 94 | {Group: "数字", Tvgid: "上海都市", Contentid: "2000000002000000012", Cdn: "hnbblive", Quality: "$4M FHD"}, 95 | {Group: "数字", Tvgid: "第一财经", Contentid: "2000000002000000004", Cdn: "hnbblive", Quality: "$4M FHD"}, 96 | {Group: "数字", Tvgid: "东方财经", Contentid: "2000000002000000090", Cdn: "hnbblive", Quality: "$8M FHD"}, 97 | {Group: "数字", Tvgid: "东方影视", Contentid: "2000000002000000013", Cdn: "hnbblive", Quality: "$4M FHD"}, 98 | {Group: "数字", Tvgid: "五星体育", Contentid: "2000000002000000007", Cdn: "hnbblive", Quality: "$4M FHD"}, 99 | {Group: "数字", Tvgid: "广东珠江", Contentid: "2000000003000000033", Cdn: "hnbblive", Quality: "$3M HD"}, 100 | {Group: "数字", Tvgid: "浙江教科影视", Contentid: "2000000004000000001", Cdn: "hnbblive", Quality: "$2M SD"}, 101 | {Group: "数字", Tvgid: "茶频道", Contentid: "2000000002000000070", Cdn: "hnbblive", Quality: "$8M FHD"}, 102 | {Group: "数字", Tvgid: "快乐垂钓", Contentid: "2000000002000000067", Cdn: "hnbblive", Quality: "$8M FHD"}, 103 | {Group: "数字", Tvgid: "金鹰卡通", Contentid: "8919073838942247498", Cdn: "hnbblive", Quality: "$2M SD"}, 104 | {Group: "数字", Tvgid: "家庭理财", Contentid: "2000000002000000064", Cdn: "hnbblive", Quality: "$2M SD"}, 105 | {Group: "数字", Tvgid: "电子竞技", Contentid: "2000000004000000015", Cdn: "hnbblive", Quality: "$3M HD"}, 106 | {Group: "数字", Tvgid: "东方大剧院", Contentid: "2000000004000000004", Cdn: "hnbblive", Quality: "$3M HD"}, 107 | {Group: "数字", Tvgid: "高清娱乐", Contentid: "2000000004000000013", Cdn: "hnbblive", Quality: "$3M HD"}, 108 | {Group: "数字", Tvgid: "精品剧场", Contentid: "2000000004000000002", Cdn: "hnbblive", Quality: "$3M HD"}, 109 | {Group: "数字", Tvgid: "精品综合", Contentid: "2000000003000000008", Cdn: "hnbblive", Quality: "$4M FHD"}, 110 | {Group: "数字", Tvgid: "漫游世界", Contentid: "2000000004000000017", Cdn: "hnbblive", Quality: "$3M HD"}, 111 | {Group: "数字", Tvgid: "欧美影院", Contentid: "2000000004000000005", Cdn: "hnbblive", Quality: "$3M HD"}, 112 | {Group: "数字", Tvgid: "热播精选", Contentid: "2000000003000000016", Cdn: "hnbblive", Quality: "$4M FHD"}, 113 | {Group: "数字", Tvgid: "探索纪录", Contentid: "2000000004000000007", Cdn: "hnbblive", Quality: "$3M HD"}, 114 | {Group: "数字", Tvgid: "少儿动漫", Contentid: "2000000004000000003", Cdn: "hnbblive", Quality: "$3M HD"}, 115 | {Group: "数字", Tvgid: "卡酷少儿", Contentid: "7947519469029992015", Cdn: "hnbblive", Quality: "$2M SD"}, 116 | {Group: "数字", Tvgid: "求索动物", Contentid: "2000000004000000009", Cdn: "hnbblive", Quality: "$8M FHD"}, 117 | {Group: "数字", Tvgid: "求索纪录", Contentid: "2000000004000000010", Cdn: "hnbblive", Quality: "$8M FHD"}, 118 | {Group: "数字", Tvgid: "求索科学", Contentid: "2000000004000000011", Cdn: "hnbblive", Quality: "$8M FHD"}, 119 | {Group: "数字", Tvgid: "求索生活", Contentid: "2000000004000000008", Cdn: "hnbblive", Quality: "$8M FHD"}, 120 | 121 | {Group: "NewTV", Tvgid: "爱情喜剧", Contentid: "2000000003000000010", Cdn: "hnbblive", Quality: "$4M FHD"}, 122 | {Group: "NewTV", Tvgid: "超级电视剧", Contentid: "2000000003000000032", Cdn: "hnbblive", Quality: "$4M FHD"}, 123 | {Group: "NewTV", Tvgid: "超级电影", Contentid: "2000000003000000031", Cdn: "hnbblive", Quality: "$4M FHD"}, 124 | {Group: "NewTV", Tvgid: "超级体育", Contentid: "2000000003000000030", Cdn: "hnbblive", Quality: "$4M FHD"}, 125 | {Group: "NewTV", Tvgid: "超级综艺", Contentid: "2000000003000000029", Cdn: "hnbblive", Quality: "$4M FHD"}, 126 | {Group: "NewTV", Tvgid: "潮妈辣婆", Contentid: "2000000003000000018", Cdn: "hnbblive", Quality: "$4M FHD"}, 127 | {Group: "NewTV", Tvgid: "哒啵电竞", Contentid: "2000000003000000066", Cdn: "hnbblive", Quality: "$4M FHD"}, 128 | {Group: "NewTV", Tvgid: "哒啵赛事", Contentid: "2000000003000000040", Cdn: "hnbblive", Quality: "$4M FHD"}, 129 | {Group: "NewTV", Tvgid: "东北热剧", Contentid: "2000000003000000051", Cdn: "hnbblive", Quality: "$4M FHD"}, 130 | {Group: "NewTV", Tvgid: "动作电影", Contentid: "2000000003000000017", Cdn: "hnbblive", Quality: "$4M FHD"}, 131 | {Group: "NewTV", Tvgid: "古装剧场", Contentid: "2000000003000000024", Cdn: "hnbblive", Quality: "$4M FHD"}, 132 | {Group: "NewTV", Tvgid: "黑莓电影", Contentid: "2000000003000000001", Cdn: "hnbblive", Quality: "$4M FHD"}, 133 | {Group: "NewTV", Tvgid: "黑莓动画", Contentid: "2000000003000000002", Cdn: "hnbblive", Quality: "$4M FHD"}, 134 | {Group: "NewTV", Tvgid: "欢乐剧场", Contentid: "2000000003000000050", Cdn: "hnbblive", Quality: "$4M FHD"}, 135 | {Group: "NewTV", Tvgid: "家庭剧场", Contentid: "2000000003000000012", Cdn: "hnbblive", Quality: "$4M FHD"}, 136 | {Group: "NewTV", Tvgid: "金牌综艺", Contentid: "2000000003000000005", Cdn: "hnbblive", Quality: "$4M FHD"}, 137 | {Group: "NewTV", Tvgid: "惊悚悬疑", Contentid: "2000000003000000015", Cdn: "hnbblive", Quality: "$4M FHD"}, 138 | {Group: "NewTV", Tvgid: "精品大剧", Contentid: "2000000003000000020", Cdn: "hnbblive", Quality: "$4M FHD"}, 139 | {Group: "NewTV", Tvgid: "精品纪录", Contentid: "2000000003000000019", Cdn: "hnbblive", Quality: "$4M FHD"}, 140 | {Group: "NewTV", Tvgid: "精品萌宠", Contentid: "2000000003000000067", Cdn: "hnbblive", Quality: "$4M FHD"}, 141 | {Group: "NewTV", Tvgid: "精品体育", Contentid: "2000000003000000021", Cdn: "hnbblive", Quality: "$4M FHD"}, 142 | {Group: "NewTV", Tvgid: "军旅剧场", Contentid: "2000000003000000014", Cdn: "hnbblive", Quality: "$4M FHD"}, 143 | {Group: "NewTV", Tvgid: "军事评论", Contentid: "2000000003000000022", Cdn: "hnbblive", Quality: "$4M FHD"}, 144 | {Group: "NewTV", Tvgid: "魅力潇湘", Contentid: "2000000003000000041", Cdn: "hnbblive", Quality: "$4M FHD"}, 145 | {Group: "NewTV", Tvgid: "农业致富", Contentid: "2000000003000000003", Cdn: "hnbblive", Quality: "$4M FHD"}, 146 | {Group: "NewTV", Tvgid: "武搏世界", Contentid: "2000000003000000007", Cdn: "hnbblive", Quality: "$4M FHD"}, 147 | {Group: "NewTV", Tvgid: "炫舞未来", Contentid: "2000000003000000044", Cdn: "hnbblive", Quality: "$4M FHD"}, 148 | {Group: "NewTV", Tvgid: "怡伴健康", Contentid: "2000000003000000023", Cdn: "hnbblive", Quality: "$4M FHD"}, 149 | {Group: "NewTV", Tvgid: "中国功夫", Contentid: "2000000003000000009", Cdn: "hnbblive", Quality: "$4M FHD"}, 150 | 151 | {Group: "SiTV", Tvgid: "动漫秀场", Contentid: "2000000002000000009", Cdn: "hnbblive", Quality: "$4M FHD"}, 152 | {Group: "SiTV", Tvgid: "都市剧场", Contentid: "2000000002000000015", Cdn: "hnbblive", Quality: "$4M FHD"}, 153 | {Group: "SiTV", Tvgid: "法治天地", Contentid: "2000000002000000014", Cdn: "hnbblive", Quality: "$8M FHD"}, 154 | {Group: "SiTV", Tvgid: "欢笑剧场", Contentid: "2000000002000000016", Cdn: "hnbblive", Quality: "$4M FHD"}, 155 | {Group: "SiTV", Tvgid: "金色学堂", Contentid: "2000000002000000061", Cdn: "hnbblive", Quality: "$8M FHD"}, 156 | {Group: "SiTV", Tvgid: "劲爆体育", Contentid: "2000000002000000008", Cdn: "hnbblive", Quality: "$4M FHD"}, 157 | {Group: "SiTV", Tvgid: "乐游", Contentid: "2000000002000000092", Cdn: "hnbblive", Quality: "$8M FHD"}, 158 | {Group: "SiTV", Tvgid: "魅力足球", Contentid: "2000000002000000068", Cdn: "hnbblive", Quality: "$8M FHD"}, 159 | {Group: "SiTV", Tvgid: "生活时尚", Contentid: "2000000002000000006", Cdn: "hnbblive", Quality: "$4M FHD"}, 160 | {Group: "SiTV", Tvgid: "游戏风云", Contentid: "2000000002000000011", Cdn: "hnbblive", Quality: "$4M FHD"}, 161 | 162 | {Group: "IHOT", Tvgid: "爱谍战", Contentid: "2000000004000000038", Cdn: "hnbblive", Quality: "$8M FHD"}, 163 | {Group: "IHOT", Tvgid: "爱动漫", Contentid: "2000000004000000059", Cdn: "hnbblive", Quality: "$8M FHD"}, 164 | {Group: "IHOT", Tvgid: "爱科幻", Contentid: "2000000004000000033", Cdn: "hnbblive", Quality: "$8M FHD"}, 165 | {Group: "IHOT", Tvgid: "爱科学", Contentid: "2000000004000000047", Cdn: "hnbblive", Quality: "$8M FHD"}, 166 | {Group: "IHOT", Tvgid: "爱浪漫", Contentid: "2000000004000000035", Cdn: "hnbblive", Quality: "$8M FHD"}, 167 | {Group: "IHOT", Tvgid: "爱历史", Contentid: "2000000004000000046", Cdn: "hnbblive", Quality: "$8M FHD"}, 168 | {Group: "IHOT", Tvgid: "爱旅行", Contentid: "2000000004000000056", Cdn: "hnbblive", Quality: "$8M FHD"}, 169 | {Group: "IHOT", Tvgid: "爱奇谈", Contentid: "2000000004000000058", Cdn: "hnbblive", Quality: "$8M FHD"}, 170 | {Group: "IHOT", Tvgid: "爱赛车", Contentid: "2000000004000000055", Cdn: "hnbblive", Quality: "$8M FHD"}, 171 | {Group: "IHOT", Tvgid: "爱体育", Contentid: "2000000004000000060", Cdn: "hnbblive", Quality: "$8M FHD"}, 172 | {Group: "IHOT", Tvgid: "爱玩具", Contentid: "2000000004000000053", Cdn: "hnbblive", Quality: "$8M FHD"}, 173 | {Group: "IHOT", Tvgid: "爱喜剧", Contentid: "2000000004000000032", Cdn: "hnbblive", Quality: "$8M FHD"}, 174 | {Group: "IHOT", Tvgid: "爱悬疑", Contentid: "2000000004000000036", Cdn: "hnbblive", Quality: "$8M FHD"}, 175 | {Group: "IHOT", Tvgid: "爱幼教", Contentid: "2000000004000000049", Cdn: "hnbblive", Quality: "$8M FHD"}, 176 | {Group: "IHOT", Tvgid: "爱院线", Contentid: "2000000004000000034", Cdn: "hnbblive", Quality: "$8M FHD"}, 177 | 178 | {Group: "咪视通", Tvgid: "睛彩广场舞", Contentid: "3000000020000011523", Cdn: "FifastbLive", Quality: "$8M FHD"}, 179 | {Group: "咪视通", Tvgid: "睛彩竞技", Contentid: "3000000020000011528", Cdn: "FifastbLive", Quality: "$8M FHD"}, 180 | {Group: "咪视通", Tvgid: "睛彩篮球", Contentid: "3000000020000011529", Cdn: "FifastbLive", Quality: "$8M FHD"}, 181 | {Group: "咪视通", Tvgid: "睛彩青少", Contentid: "3000000020000011525", Cdn: "FifastbLive", Quality: "$8M FHD"}, 182 | {Group: "咪视通", Tvgid: "3000000001000005308", Contentid: "3000000001000005308", Cdn: "FifastbLive", Quality: "$8M FHD"}, 183 | {Group: "咪视通", Tvgid: "3000000001000005969", Contentid: "3000000001000005969", Cdn: "FifastbLive", Quality: "$8M FHD"}, 184 | {Group: "咪视通", Tvgid: "3000000001000007218", Contentid: "3000000001000007218", Cdn: "FifastbLive", Quality: "$8M FHD"}, 185 | {Group: "咪视通", Tvgid: "3000000001000008001", Contentid: "3000000001000008001", Cdn: "FifastbLive", Quality: "$8M FHD"}, 186 | {Group: "咪视通", Tvgid: "3000000001000008176", Contentid: "3000000001000008176", Cdn: "FifastbLive", Quality: "$8M FHD"}, 187 | {Group: "咪视通", Tvgid: "3000000001000008379", Contentid: "3000000001000008379", Cdn: "FifastbLive", Quality: "$8M FHD"}, 188 | {Group: "咪视通", Tvgid: "3000000001000010129", Contentid: "3000000001000010129", Cdn: "FifastbLive", Quality: "$8M FHD"}, 189 | {Group: "咪视通", Tvgid: "3000000001000010948", Contentid: "3000000001000010948", Cdn: "FifastbLive", Quality: "$8M FHD"}, 190 | {Group: "咪视通", Tvgid: "3000000001000028638", Contentid: "3000000001000028638", Cdn: "FifastbLive", Quality: "$8M FHD"}, 191 | {Group: "咪视通", Tvgid: "3000000001000031494", Contentid: "3000000001000031494", Cdn: "FifastbLive", Quality: "$8M FHD"}, 192 | {Group: "咪视通", Tvgid: "3000000010000000097", Contentid: "3000000010000000097", Cdn: "FifastbLive", Quality: "$5M FHD"}, 193 | {Group: "咪视通", Tvgid: "3000000010000002019", Contentid: "3000000010000002019", Cdn: "FifastbLive", Quality: "$5M FHD"}, 194 | {Group: "咪视通", Tvgid: "3000000010000002809", Contentid: "3000000010000002809", Cdn: "FifastbLive", Quality: "$5M FHD"}, 195 | {Group: "咪视通", Tvgid: "3000000010000003915", Contentid: "3000000010000003915", Cdn: "FifastbLive", Quality: "$5M FHD"}, 196 | {Group: "咪视通", Tvgid: "3000000010000004193", Contentid: "3000000010000004193", Cdn: "FifastbLive", Quality: "$5M FHD"}, 197 | {Group: "咪视通", Tvgid: "3000000010000005837", Contentid: "3000000010000005837", Cdn: "FifastbLive", Quality: "$8M FHD"}, 198 | {Group: "咪视通", Tvgid: "3000000010000006077", Contentid: "3000000010000006077", Cdn: "FifastbLive", Quality: "$5M FHD"}, 199 | {Group: "咪视通", Tvgid: "3000000010000006658", Contentid: "3000000010000006658", Cdn: "FifastbLive", Quality: "$5M FHD"}, 200 | {Group: "咪视通", Tvgid: "3000000010000009788", Contentid: "3000000010000009788", Cdn: "FifastbLive", Quality: "$5M FHD"}, 201 | {Group: "咪视通", Tvgid: "3000000010000010833", Contentid: "3000000010000010833", Cdn: "FifastbLive", Quality: "$5M FHD"}, 202 | {Group: "咪视通", Tvgid: "3000000010000011297", Contentid: "3000000010000011297", Cdn: "FifastbLive", Quality: "$5M FHD"}, 203 | {Group: "咪视通", Tvgid: "3000000010000011518", Contentid: "3000000010000011518", Cdn: "FifastbLive", Quality: "$5M FHD"}, 204 | {Group: "咪视通", Tvgid: "3000000010000012558", Contentid: "3000000010000012558", Cdn: "FifastbLive", Quality: "$5M FHD"}, 205 | {Group: "咪视通", Tvgid: "3000000010000012616", Contentid: "3000000010000012616", Cdn: "FifastbLive", Quality: "$5M FHD"}, 206 | {Group: "咪视通", Tvgid: "3000000010000015470", Contentid: "3000000010000015470", Cdn: "FifastbLive", Quality: "$5M FHD"}, 207 | {Group: "咪视通", Tvgid: "3000000010000015560", Contentid: "3000000010000015560", Cdn: "FifastbLive", Quality: "$5M FHD"}, 208 | {Group: "咪视通", Tvgid: "3000000010000019839", Contentid: "3000000010000019839", Cdn: "FifastbLive", Quality: "$5M FHD"}, 209 | {Group: "咪视通", Tvgid: "3000000010000021904", Contentid: "3000000010000021904", Cdn: "FifastbLive", Quality: "$5M FHD"}, 210 | {Group: "咪视通", Tvgid: "3000000010000023434", Contentid: "3000000010000023434", Cdn: "FifastbLive", Quality: "$5M FHD"}, 211 | {Group: "咪视通", Tvgid: "3000000010000025380", Contentid: "3000000010000025380", Cdn: "FifastbLive", Quality: "$5M FHD"}, 212 | {Group: "咪视通", Tvgid: "3000000010000027691", Contentid: "3000000010000027691", Cdn: "FifastbLive", Quality: "$5M FHD"}, 213 | {Group: "咪视通", Tvgid: "3000000010000031669", Contentid: "3000000010000031669", Cdn: "FifastbLive", Quality: "$5M FHD"}, 214 | {Group: "咪视通", Tvgid: "3000000020000011518", Contentid: "3000000020000011518", Cdn: "FifastbLive", Quality: "$8M FHD"}, 215 | {Group: "咪视通", Tvgid: "3000000020000011519", Contentid: "3000000020000011519", Cdn: "FifastbLive", Quality: "$8M FHD"}, 216 | {Group: "咪视通", Tvgid: "3000000020000011520", Contentid: "3000000020000011520", Cdn: "FifastbLive", Quality: "$8M FHD"}, 217 | {Group: "咪视通", Tvgid: "3000000020000011521", Contentid: "3000000020000011521", Cdn: "FifastbLive", Quality: "$8M FHD"}, 218 | {Group: "咪视通", Tvgid: "3000000020000011522", Contentid: "3000000020000011522", Cdn: "FifastbLive", Quality: "$8M FHD"}, 219 | } 220 | 221 | // 同步锁 222 | var mu sync.Mutex 223 | 224 | // Channel 结构体 225 | type ChannelRecord struct { 226 | Group string 227 | Tvgid string 228 | Contentid string 229 | Cdn string 230 | Quality string 231 | } 232 | 233 | // IP 结构体 234 | type IPRecord struct { 235 | Address string 236 | Fail int 237 | } 238 | 239 | // 更新 IP 列表 240 | func UpdateIPList(newIPs []IPRecord, ip_list *[]IPRecord) { 241 | mu.Lock() 242 | defer mu.Unlock() 243 | *ip_list = newIPs 244 | } 245 | 246 | // 获取 Fail 最小的 IP 247 | func GetBestIP(ip_list []IPRecord) IPRecord { 248 | mu.Lock() 249 | defer mu.Unlock() 250 | 251 | bestIP := ip_list[0] 252 | for _, ip := range ip_list { 253 | if ip.Fail < bestIP.Fail { 254 | bestIP = ip 255 | } 256 | } 257 | 258 | return bestIP 259 | } 260 | 261 | // 失败计数 +1 262 | func IncreaseFail(ipAddress string, ip_list []IPRecord) { 263 | // 去掉端口号 264 | addressWithoutPort := strings.Split(ipAddress, ":")[0] 265 | 266 | mu.Lock() 267 | defer mu.Unlock() 268 | 269 | for i, ip := range ip_list { 270 | if ip.Address == addressWithoutPort { 271 | ip_list[i].Fail++ 272 | // fmt.Printf("IP %s 的失败计数增加到 %d\n", addressWithoutPort, ip_list[i].Fail) 273 | break 274 | } 275 | } 276 | } 277 | 278 | // 打印 IP 列表 279 | func PrintIPList(ip_list []IPRecord) { 280 | mu.Lock() 281 | defer mu.Unlock() 282 | 283 | for _, ip := range ip_list { 284 | fmt.Printf(" IP: %s, Fail: %d\n", ip.Address, ip.Fail) 285 | } 286 | } 287 | -------------------------------------------------------------------------------- /liveITV/itv.go: -------------------------------------------------------------------------------- 1 | package liveITV 2 | 3 | import ( 4 | "context" 5 | "crypto/rand" 6 | "encoding/hex" 7 | "fmt" 8 | "io" 9 | "log" 10 | "net" 11 | "net/http" 12 | "regexp" 13 | "strings" 14 | "time" 15 | ) 16 | 17 | type Itv struct{} 18 | 19 | var logger = log.Default() 20 | 21 | const MYSEPERETOR = "ThisIsMySeperator" 22 | 23 | // 请求TS列表 24 | func (i *Itv) HandleMainRequest(w http.ResponseWriter, r *http.Request, cdn string, id string, playseek string) { 25 | myid := strings.ReplaceAll(id, ".m3u8", "") 26 | matches := FindChannelsByTvgid(myid) 27 | if len(matches) == 0 { 28 | http.Error(w, "ChanneId not found!", http.StatusInternalServerError) 29 | return 30 | } 31 | 32 | Contentid := matches[0].Contentid 33 | Channecdn := matches[0].Cdn 34 | 35 | startUrl := "http://gslbserv.itv.cmvideo.cn:80/1.m3u8?channel-id=" + Channecdn + "&Contentid=" + Contentid + "&livemode=1&stbId=" + randomHexString(32) 36 | 37 | data, redirectURL, err := getHTTPResponse(startUrl, Channecdn) 38 | if err != nil { 39 | http.Error(w, err.Error(), http.StatusInternalServerError) 40 | return 41 | } 42 | redirectPrefix := redirectURL[:strings.LastIndex(redirectURL, "/")+1] 43 | 44 | if len(data) > 0 { 45 | // 替换TS文件的链接 46 | golang := "http://" + r.Host + r.URL.Path 47 | 48 | re := regexp.MustCompile(`((?i).*?\.ts)`) 49 | data = re.ReplaceAllStringFunc(data, func(match string) string { 50 | if strings.HasPrefix(match, "http") { 51 | return golang + "?ts=" + match 52 | } else { 53 | return golang + "?ts=" + redirectPrefix + match 54 | } 55 | }) 56 | 57 | // 将&替换为自定义分隔符 58 | data = strings.ReplaceAll(data, "&", MYSEPERETOR) 59 | 60 | data = strings.ReplaceAll(data, "#EXTINF:10.0,", "#EXT-X-DISCONTINUITY#EXTINF:10.0,") 61 | 62 | w.Header().Set("Content-Disposition", "attachment;filename="+id) 63 | w.WriteHeader(http.StatusOK) 64 | w.Write([]byte(data)) 65 | } else { 66 | http.Error(w, "", http.StatusInternalServerError) 67 | return 68 | } 69 | } 70 | 71 | // 请求TS数据 72 | func (i *Itv) HandleTsRequest(w http.ResponseWriter, ts string) { 73 | // 将$替换回& 74 | ts = strings.ReplaceAll(ts, MYSEPERETOR, "&") 75 | 76 | // fmt.Println("ts=" + ts) 77 | 78 | // Read one piece and then write one piece 79 | w.Header().Set("Content-Type", "video/MP2T") 80 | _, _, err := handleTsHTTPResponse(ts, w) 81 | if err != nil { 82 | http.Error(w, err.Error(), http.StatusInternalServerError) 83 | return 84 | } 85 | } 86 | 87 | // TS列表 请求方法 88 | func getHTTPResponse(requestURL string, channecdn string) (string, string, error) { 89 | resp, err := FetchWithCustomResolver(requestURL) 90 | if err != nil || resp.StatusCode != 200 { 91 | maxRetries := 3 92 | retryDelay := 0 * time.Second 93 | 94 | for i := 0; i < maxRetries; i++ { 95 | resp, err = FetchWithCustomResolver(requestURL) 96 | if err != nil { 97 | if Debug { 98 | logger.Printf("GetM3U-%d Error: %v", i+2, err) 99 | } 100 | } else if resp.StatusCode == 200 { 101 | // 如果状态码是200,说明请求成功,退出循环 102 | break 103 | } 104 | 105 | if Debug { 106 | if resp != nil { 107 | logger.Printf("GetM3U-%d Code:%d", i+2, resp.StatusCode) 108 | } else { 109 | logger.Printf("GetM3U-%d Response is nil", i+2) 110 | } 111 | } 112 | 113 | // 如果响应状态码不是200,记录失败并增加失败计数 114 | switch { 115 | case strings.Contains(channecdn, "bestzb"): 116 | IncreaseFail(WorkIP_bestzb, IPList_bestzb) 117 | 118 | case strings.Contains(channecdn, "hnbblive"): 119 | IncreaseFail(WorkIP_hnbblive, IPList_hnbblive) 120 | 121 | case strings.Contains(channecdn, "FifastbLive"): 122 | IncreaseFail(WorkIP_fifalive, IPList_fifalive) 123 | 124 | } 125 | 126 | // 等待指定时间后再重试 127 | time.Sleep(retryDelay) 128 | } 129 | } 130 | 131 | if err != nil || resp.StatusCode != 200 { 132 | logger.Printf("GetM3U Failed") 133 | return "", "", err 134 | } else { 135 | redirectURL := resp.Header.Get("Location") 136 | if redirectURL == "" { 137 | redirectURL = requestURL 138 | } 139 | 140 | body, err := ReadResponseBody(resp) 141 | 142 | return body, redirectURL, err 143 | } 144 | } 145 | 146 | // TS数据 请求方法 147 | func handleTsHTTPResponse(requestURL string, w http.ResponseWriter) (string, string, error) { 148 | dialer := &net.Dialer{ 149 | Timeout: 10 * time.Second, 150 | } 151 | 152 | // 自定义resolver 153 | resolver := net.Resolver{ 154 | Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 155 | match, _ := regexp.MatchString(`^cache\.ott\..*\.itv\.cmvideo\.cn:80$`, address) 156 | if match { 157 | switch { 158 | case strings.Contains(address, "bestlive"): 159 | address = WorkIP_bestzb 160 | case strings.Contains(address, "hnbblive"): 161 | address = WorkIP_hnbblive 162 | case strings.Contains(address, "fifalive"): 163 | address = WorkIP_fifalive 164 | } 165 | 166 | if Debug { 167 | logger.Printf("TS:UseIP->%s", strings.Split(address, ":")[0]) 168 | } 169 | } 170 | 171 | return dialer.DialContext(ctx, network, address) 172 | }, 173 | } 174 | 175 | client := &http.Client{ 176 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 177 | return nil 178 | }, 179 | Transport: &http.Transport{ 180 | DialContext: resolver.Dial, 181 | }, 182 | } 183 | 184 | req, err := http.NewRequest("GET", requestURL, nil) 185 | if err != nil { 186 | fmt.Println("Error creating request:", err) 187 | } 188 | 189 | resp, err := client.Do(req) 190 | 191 | if err != nil { 192 | return "", "", err 193 | } 194 | defer resp.Body.Close() 195 | 196 | if resp.StatusCode != http.StatusOK { 197 | logger.Printf("TS Request Fail:%d", resp.StatusCode) 198 | return "", "", http.ErrServerClosed 199 | } 200 | 201 | redirectURL := resp.Header.Get("Location") 202 | if redirectURL == "" { 203 | redirectURL = requestURL 204 | } 205 | 206 | w.WriteHeader(http.StatusOK) 207 | _, err = io.Copy(w, resp.Body) 208 | 209 | if err != nil { 210 | return "", "", nil 211 | } 212 | 213 | return "", redirectURL, nil 214 | } 215 | 216 | // 使用自定义 DNS 解析器的 HTTP 请求方法,支持 302 重定向失败后重试 3 次 217 | func FetchWithCustomResolver(requestURL string) (*http.Response, error) { 218 | isDebug := false 219 | if Debug && isDebug { 220 | logger.Printf("RequestURL: %s", requestURL) 221 | } 222 | 223 | dialer := &net.Dialer{ 224 | Timeout: 10 * time.Second, 225 | } 226 | 227 | resolver := &net.Resolver{ 228 | Dial: func(ctx context.Context, network, address string) (net.Conn, error) { 229 | match, _ := regexp.MatchString(`^cache\.ott\..*\.itv\.cmvideo\.cn:80$`, address) 230 | if match { 231 | switch { 232 | case strings.Contains(address, "bestlive"): 233 | address = GetBestIP(IPList_bestzb).Address + ":80" 234 | WorkIP_bestzb = address 235 | case strings.Contains(address, "hnbblive"): 236 | address = GetBestIP(IPList_hnbblive).Address + ":80" 237 | WorkIP_hnbblive = address 238 | case strings.Contains(address, "fifalive"): 239 | address = GetBestIP(IPList_fifalive).Address + ":80" 240 | WorkIP_fifalive = address 241 | } 242 | 243 | if Debug { 244 | logger.Printf("M3U:GetBestIP->%s", strings.Split(address, ":")[0]) 245 | } 246 | } 247 | 248 | return dialer.DialContext(ctx, network, address) 249 | }, 250 | } 251 | 252 | client := &http.Client{ 253 | CheckRedirect: func(req *http.Request, via []*http.Request) error { 254 | if Debug && isDebug && len(via) > 0 { 255 | logger.Printf("Redirected to: %s", req.URL.String()) 256 | } 257 | return http.ErrUseLastResponse // 禁止自动跳转 258 | }, 259 | Transport: &http.Transport{ 260 | DialContext: resolver.Dial, 261 | }, 262 | } 263 | 264 | var lastResp *http.Response 265 | redirectCount := 0 // 记录 302 跳转次数 266 | 267 | // 重试 268 | for attempt := 1; attempt <= 3; attempt++ { 269 | req, err := http.NewRequest("GET", requestURL, nil) 270 | if err != nil { 271 | return nil, fmt.Errorf("error creating request: %w", err) 272 | } 273 | 274 | lastResp, err = client.Do(req) 275 | if err != nil { 276 | if Debug && isDebug { 277 | logger.Printf("请求失败: %v (尝试 %d/3)", err, attempt) 278 | } 279 | time.Sleep(1 * time.Second) // 等待重试 280 | continue 281 | } 282 | 283 | // 处理 302/301 重定向 284 | for lastResp.StatusCode == http.StatusFound || lastResp.StatusCode == http.StatusMovedPermanently { 285 | redirectURL := lastResp.Header.Get("Location") 286 | if redirectURL == "" { 287 | return nil, fmt.Errorf("error: no Location header in response (attempt %d)", attempt) 288 | } 289 | 290 | redirectCount++ 291 | if redirectCount > 20 { 292 | return nil, fmt.Errorf("too many redirects (max 6)") 293 | } 294 | 295 | if Debug && isDebug { 296 | logger.Printf("302 跳转 (%d): %s -> %s", redirectCount, requestURL, redirectURL) 297 | } 298 | 299 | requestURL = redirectURL // 更新 URL 继续请求 300 | req, err = http.NewRequest("GET", requestURL, nil) 301 | if err != nil { 302 | return nil, fmt.Errorf("error creating request after redirect: %w", err) 303 | } 304 | lastResp, err = client.Do(req) 305 | if err != nil { 306 | if Debug { 307 | logger.Printf("请求失败: %v (尝试 %d/3)", err, attempt) 308 | } 309 | time.Sleep(1 * time.Second) 310 | continue 311 | } 312 | } 313 | 314 | // 响应状态码不是 200 也重试 315 | if lastResp.StatusCode != http.StatusOK { 316 | if Debug && isDebug { 317 | logger.Printf("请求返回非200状态码: %d (尝试 %d/3)", lastResp.StatusCode, attempt) 318 | } 319 | continue 320 | } 321 | 322 | // 请求成功,返回响应 323 | return lastResp, nil 324 | } 325 | 326 | return nil, fmt.Errorf("exceeded maximum retries") 327 | } 328 | 329 | // 获取请求返回内容 330 | func ReadResponseBody(resp *http.Response) (string, error) { 331 | var builder strings.Builder 332 | _, err := io.Copy(&builder, resp.Body) 333 | if err != nil { 334 | return "", err 335 | } 336 | return builder.String(), nil 337 | } 338 | 339 | // 查找所有匹配 Tvgid 的记录 340 | func FindChannelsByTvgid(tvgid string) []ChannelRecord { 341 | var results []ChannelRecord 342 | for _, channel := range ChannelList { 343 | if channel.Tvgid == tvgid { 344 | results = append(results, channel) 345 | } 346 | } 347 | return results 348 | } 349 | 350 | // 生成指定位数的随机字符 351 | func randomHexString(length int) string { 352 | bytes := make([]byte, length/2) 353 | _, err := rand.Read(bytes) 354 | if err != nil { 355 | panic(err) 356 | } 357 | return hex.EncodeToString(bytes) 358 | } 359 | -------------------------------------------------------------------------------- /livePhoenix/config.go: -------------------------------------------------------------------------------- 1 | package livePhoenix 2 | 3 | var Enable bool = false 4 | var Debug bool = false 5 | 6 | var FengshowsClient string = "app(ios,5040718)" 7 | var FengshowsUserAgent string = "Mozilla/5.0 (iPhone; CPU iPhone OS 15_3 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/98.0.4758.85 Mobile/15E148 Safari/604.1" 8 | var FengshowsToken string = "" 9 | -------------------------------------------------------------------------------- /livePhoenix/phoenix.go: -------------------------------------------------------------------------------- 1 | package livePhoenix 2 | 3 | type Phoenix struct{} 4 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "easy-itv/config" 5 | "easy-itv/list" 6 | "easy-itv/liveITV" 7 | "easy-itv/livePhoenix" 8 | "easy-itv/update" 9 | "easy-itv/utils" 10 | "flag" 11 | "fmt" 12 | "log" 13 | "net/http" 14 | "regexp" 15 | "strings" 16 | "time" 17 | 18 | "github.com/gin-gonic/gin" 19 | ) 20 | 21 | var logger = log.Default() 22 | 23 | func setupRouter() *gin.Engine { 24 | gin.SetMode(gin.ReleaseMode) 25 | r := gin.New() // 不使用 gin.Default(),这样不会自动加载 Logger 和 Recovery 中间件 26 | r.Use(gin.Recovery()) // 恢复中间件,不使用 gin.Default()时必须手动加载 27 | 28 | r.HEAD("/", func(c *gin.Context) { 29 | c.String(http.StatusOK, "") 30 | }) 31 | 32 | r.GET("/", func(c *gin.Context) { 33 | c.String(http.StatusOK, utils.GetFormattedTime()) 34 | }) 35 | 36 | r.GET("/tv.m3u", func(c *gin.Context) { 37 | 38 | clientIP := c.ClientIP() 39 | urltoken := utils.DefaultQuery(c.Request, "token", "") 40 | 41 | if config.Token == "" || urltoken == config.Token { 42 | itvm3uobj := &list.Tvm3u{} 43 | if !config.Debug { 44 | c.Writer.Header().Set("Content-Type", "application/octet-stream") 45 | c.Writer.Header().Set("Content-Disposition", "attachment; filename=tv.m3u") 46 | } 47 | 48 | itvm3uobj.GetTvM3u(c.Writer, c.Request.Host) 49 | } else { 50 | logger.Printf("Token error:%s clientIP:%s GetM3U", urltoken, clientIP) 51 | c.String(http.StatusUnauthorized, "token error") 52 | } 53 | 54 | }) 55 | 56 | r.GET("/:path/:rid", func(c *gin.Context) { 57 | clientIP := c.ClientIP() 58 | path := c.Param("path") 59 | rid := c.Param("rid") 60 | ts := utils.DefaultQuery(c.Request, "ts", "") 61 | playtoken := utils.DefaultQuery(c.Request, "token", "") 62 | 63 | // token 验证 64 | if ts == "" && (config.Token != "" && playtoken != config.Token) { 65 | logger.Printf("Token error:%s clientIP:%s VIEW:%s", playtoken, clientIP, rid) 66 | c.String(http.StatusUnauthorized, "token error") 67 | return 68 | } 69 | 70 | switch path { 71 | case "TVOD": 72 | if !liveITV.Enable { 73 | c.String(http.StatusNotFound, "err!") 74 | return 75 | } 76 | 77 | itvobj := &liveITV.Itv{} 78 | cdn := utils.DefaultQuery(c.Request, "cdn", "") 79 | playseek := utils.DefaultQuery(c.Request, "playseek", "") 80 | ind := strings.Index(cdn, "?playseek=") 81 | 82 | //rebuild playseek and cdn 83 | if ind > -1 { 84 | playseek = cdn[ind+10:] 85 | cdn = cdn[0:ind] 86 | } 87 | if ts == "" { 88 | // 获取TS列表 89 | logger.Printf("Client IP:%s VIEW:%s", clientIP, rid) 90 | itvobj.HandleMainRequest(c.Writer, c.Request, cdn, rid, playseek) 91 | } else { 92 | // 获取TS数据 93 | itvobj.HandleTsRequest(c.Writer, ts) 94 | } 95 | 96 | case "phoenix": 97 | if !livePhoenix.Enable { 98 | c.String(http.StatusNotFound, "err!") 99 | return 100 | } 101 | 102 | logger.Printf("Client IP:%s VIEW:%s", clientIP, rid) 103 | // phxvobj := &livePhoenix.Phoenix{} 104 | // phxvobj.HandleMainRequest(c.Writer, c.Request, rid) 105 | } 106 | }) 107 | return r 108 | } 109 | 110 | func main() { 111 | fmt.Println("Version:", config.Version) 112 | 113 | // 接收token参数,允许为空 114 | flag.StringVar(&config.Token, "token", "", "Your token") 115 | flag.Parse() 116 | 117 | // 验证 118 | if config.Token != "" { 119 | // 正则表达式:只允许大小写字母和数字 120 | match, err := regexp.MatchString("^[a-zA-Z0-9]+$", config.Token) 121 | if err != nil { 122 | log.Fatal("Error in regex match:", err) 123 | } 124 | 125 | // 如果不匹配,打印错误信息并退出 126 | if !match { 127 | log.Fatal("Invalid token: Token can only contain letters and numbers") 128 | } 129 | 130 | fmt.Println("Local Token:", config.Token) 131 | } 132 | 133 | // 获取运行环境IP地址 134 | ip, province, operator := utils.GetIPInfo() 135 | fmt.Println("Local IPaddress:", ip) 136 | fmt.Println("Local Province:", province) 137 | fmt.Println("Local Operator:", operator) 138 | 139 | // 启动一个异步任务 例:获取全网通IP、YSP初始化缓存、…… 140 | go func() { 141 | // do some thing 142 | 143 | fmt.Println("AsyncTask:Done") 144 | }() 145 | 146 | // 创建通道用于停止定时任务 147 | done1 := make(chan bool) 148 | done2 := make(chan bool) 149 | 150 | // 启动定时任务 151 | if config.Update { 152 | go timedFunction1(done1, 1*time.Hour) //运行间隔 1小时 153 | } 154 | go timedFunction2(done2, 30*time.Minute) //运行间隔 30分钟 155 | 156 | fmt.Println("Started:", utils.GetFormattedTime()) 157 | 158 | // 启动WEB服务 159 | r := setupRouter() 160 | r.Run(":" + config.Port) 161 | 162 | // 发送停止信号 163 | done1 <- true 164 | done2 <- true 165 | } 166 | 167 | // 定时任务1 自动更新 168 | func timedFunction1(done <-chan bool, interval time.Duration) { 169 | // 创建一个定时器,每隔 interval 触发一次 170 | ticker := time.NewTicker(interval) 171 | defer ticker.Stop() 172 | 173 | for { 174 | select { 175 | case <-done: 176 | // 收到停止信号,退出函数 177 | return 178 | case <-ticker.C: 179 | if config.Debug { 180 | logger.Printf("检查更新...") 181 | } else { 182 | logger.Printf("......") 183 | } 184 | latest, err := update.GetLatestVersionInfo() 185 | if err != nil { 186 | if config.Debug { 187 | logger.Printf("获取最新版本失败:%v", err) 188 | } 189 | continue 190 | } 191 | 192 | // 检查是否需要更新 193 | if latest.Version <= config.Version { 194 | if config.Debug { 195 | logger.Printf("当前已是最新版本:%s", config.Version) 196 | } 197 | continue 198 | } 199 | 200 | if config.Debug { 201 | logger.Printf("发现新版本: %s ,正在下载...", latest.Version) 202 | } 203 | // 获取平台哈希值 204 | platformBinary := update.GetPlatformBinaryName(latest.Version) 205 | expectedHash, exists := latest.Hash[platformBinary] 206 | if !exists { 207 | if config.Debug { 208 | logger.Printf("未找到该平台的哈希值:%s", platformBinary) 209 | } 210 | continue 211 | } 212 | 213 | newBinary, err := update.DownloadNewBinary(latest.Version) 214 | if err != nil { 215 | if config.Debug { 216 | logger.Printf("下载失败:%v", err) 217 | } 218 | continue 219 | } 220 | 221 | // 替换并重启 222 | if config.Debug { 223 | logger.Printf("开始更新...") 224 | } 225 | err = update.ReplaceAndRestart(newBinary, config.Version, expectedHash) 226 | if err != nil { 227 | if config.Debug { 228 | logger.Printf("更新失败:%v", err) 229 | } 230 | } 231 | 232 | } 233 | } 234 | } 235 | 236 | // 定时任务2 例:更新全网通IP、更新YSP缓存、…… 237 | func timedFunction2(done <-chan bool, interval time.Duration) { 238 | // 创建一个定时器,每隔 interval 触发一次 239 | ticker := time.NewTicker(interval) 240 | defer ticker.Stop() 241 | 242 | for { 243 | select { 244 | case <-done: 245 | // 收到停止信号,退出函数 246 | return 247 | case <-ticker.C: 248 | // do some thing 249 | // liveITV.UpdateIPList(ipRecords, &liveITV.IPList_bestzb) 250 | 251 | logger.Println("Scheduled task has completed.") 252 | } 253 | } 254 | } 255 | -------------------------------------------------------------------------------- /update/update.go: -------------------------------------------------------------------------------- 1 | package update 2 | 3 | import ( 4 | "archive/tar" 5 | "compress/gzip" 6 | "crypto/md5" 7 | "easy-itv/config" 8 | "encoding/hex" 9 | "encoding/json" 10 | "fmt" 11 | "io" 12 | "log" 13 | "net/http" 14 | "os" 15 | "path/filepath" 16 | "runtime" 17 | "strings" 18 | "syscall" 19 | ) 20 | 21 | var logger = log.Default() 22 | 23 | type VersionInfo struct { 24 | Version string `json:"version"` 25 | Hash map[string]string `json:"hash"` 26 | } 27 | 28 | // 获取最新版本信息 29 | func GetLatestVersionInfo() (*VersionInfo, error) { 30 | resp, err := http.Get(config.VersionCheckURL) 31 | if err != nil { 32 | return nil, err 33 | } 34 | defer resp.Body.Close() 35 | 36 | data, err := io.ReadAll(resp.Body) 37 | if err != nil { 38 | return nil, err 39 | } 40 | 41 | var info VersionInfo 42 | err = json.Unmarshal(data, &info) 43 | if err != nil { 44 | return nil, err 45 | } 46 | 47 | return &info, nil 48 | } 49 | 50 | // 获取当前平台的二进制文件名称 51 | func GetPlatformBinaryName(version string) string { 52 | goos := runtime.GOOS 53 | goarch := runtime.GOARCH 54 | 55 | // 构建平台特定的二进制文件名称 56 | return fmt.Sprintf("itv_%s_%s", goos, goarch) 57 | } 58 | 59 | // 下载新版本的二进制文件 60 | func DownloadNewBinary(version string) (string, error) { 61 | 62 | // 根据当前平台获取正确的二进制文件名 63 | platformBinary := GetPlatformBinaryName(version) 64 | 65 | // 构建下载路径 66 | url := config.BinaryDownloadBaseURL + platformBinary + ".tar.gz" 67 | 68 | tempPath := filepath.Join(os.TempDir(), platformBinary) 69 | resp, err := http.Get(url) 70 | if err != nil { 71 | return "", err 72 | } 73 | defer resp.Body.Close() 74 | 75 | out, err := os.Create(tempPath + ".tar.gz") 76 | if err != nil { 77 | return "", err 78 | } 79 | defer out.Close() 80 | 81 | _, err = io.Copy(out, resp.Body) 82 | return tempPath, err 83 | } 84 | 85 | // 校验下载的文件哈希值是否匹配 (使用 MD5 校验) 86 | func VerifyFileHash(filePath, expectedHash string) error { 87 | // 打开文件 88 | file, err := os.Open(filePath) 89 | if err != nil { 90 | return err 91 | } 92 | defer file.Close() 93 | 94 | // 使用 MD5 计算文件哈希 95 | hash := md5.New() 96 | if _, err := io.Copy(hash, file); err != nil { 97 | return err 98 | } 99 | 100 | // 计算得到的哈希值 101 | computedHash := hex.EncodeToString(hash.Sum(nil)) 102 | if computedHash != expectedHash { 103 | return fmt.Errorf("hash mismatch: expected %s, got %s", expectedHash, computedHash) 104 | } 105 | return nil 106 | } 107 | 108 | // 删除临时文件 109 | func CleanUpTempFile(filePath string) error { 110 | err := os.Remove(filePath) 111 | if err != nil { 112 | return fmt.Errorf("删除临时文件失败: %v", err) 113 | } 114 | return nil 115 | } 116 | 117 | // 复制文件 118 | func CopyFile(src, dst string) error { 119 | sourceFile, err := os.Open(src) 120 | if err != nil { 121 | return err 122 | } 123 | defer sourceFile.Close() 124 | 125 | destinationFile, err := os.Create(dst) 126 | if err != nil { 127 | return err 128 | } 129 | defer destinationFile.Close() 130 | 131 | _, err = io.Copy(destinationFile, sourceFile) 132 | return err 133 | } 134 | 135 | // 解压 tar.gz 文件 136 | func ExtractTarGz(tarGzPath string) (string, error) { 137 | // 获取 tar.gz 所在目录 138 | destDir := filepath.Dir(tarGzPath) 139 | 140 | file, err := os.Open(tarGzPath) 141 | if err != nil { 142 | return "", err 143 | } 144 | defer file.Close() 145 | 146 | // 解压 gzip 147 | gzr, err := gzip.NewReader(file) 148 | if err != nil { 149 | return "", err 150 | } 151 | defer gzr.Close() 152 | 153 | // 读取 tar 154 | tr := tar.NewReader(gzr) 155 | var extractedFilePath string 156 | 157 | for { 158 | header, err := tr.Next() 159 | if err == io.EOF { 160 | break 161 | } 162 | if err != nil { 163 | return "", err 164 | } 165 | 166 | // 仅解压 itv_linux_* 文件 167 | baseName := filepath.Base(header.Name) 168 | if header.Typeflag == tar.TypeReg && strings.HasPrefix(baseName, "itv_linux_") { 169 | extractedFilePath = filepath.Join(destDir, baseName) 170 | outFile, err := os.Create(extractedFilePath) 171 | if err != nil { 172 | return "", err 173 | } 174 | defer outFile.Close() 175 | 176 | _, err = io.Copy(outFile, tr) 177 | if err != nil { 178 | return "", err 179 | } 180 | 181 | break 182 | } 183 | } 184 | 185 | if extractedFilePath == "" { 186 | return "", fmt.Errorf("未在 tar.gz 中找到 itv_linux_* 文件") 187 | } 188 | 189 | return extractedFilePath, nil 190 | } 191 | 192 | // 替换当前运行的二进制文件并重启 193 | func ReplaceAndRestart(newBinaryPath, version, expectedHash string) error { 194 | // 解压 tar.gz 195 | newBinaryPath, err := ExtractTarGz(newBinaryPath + ".tar.gz") 196 | if err != nil { 197 | return fmt.Errorf("解压失败: %v", err) 198 | } 199 | 200 | // 校验哈希值,确保文件完整性 201 | if err := VerifyFileHash(newBinaryPath, expectedHash); err != nil { 202 | return err 203 | } 204 | 205 | // 获取当前二进制文件路径 206 | currentBinary, err := os.Executable() 207 | if err != nil { 208 | return err 209 | } 210 | 211 | // 备份当前版本 212 | backupPath := filepath.Join(filepath.Dir(currentBinary), fmt.Sprintf("itv_%s", version)) 213 | 214 | // 尝试重命名当前文件作为备份 215 | if err := os.Rename(currentBinary, backupPath); err != nil { 216 | return fmt.Errorf("重命名当前文件失败: %v", err) 217 | } 218 | 219 | // 尝试将新版本复制到当前二进制文件 220 | if err := CopyFile(newBinaryPath, currentBinary); err != nil { 221 | // 回滚操作:如果替换失败,则恢复备份 222 | os.Rename(backupPath, currentBinary) 223 | return fmt.Errorf("替换新版本失败,回滚操作: %v", err) 224 | } 225 | 226 | // 尝试设置新文件的权限 227 | if err := os.Chmod(currentBinary, 0755); err != nil { 228 | // 回滚操作:如果权限设置失败,恢复备份 229 | os.Rename(backupPath, currentBinary) 230 | return fmt.Errorf("设置权限失败,回滚操作: %v", err) 231 | } 232 | 233 | // 删除临时文件 234 | if err := CleanUpTempFile(newBinaryPath); err != nil { 235 | return err 236 | } 237 | 238 | // 启动新版本 使用 syscall.Exec 替换当前进程,避免父进程退出 239 | if config.Debug { 240 | logger.Printf("更新成功 重启服务中...") 241 | } 242 | 243 | args := append([]string{currentBinary}, os.Args[1:]...) 244 | err = syscall.Exec(currentBinary, args, os.Environ()) 245 | if err != nil { 246 | // 回滚操作:如果启动失败,恢复备份 247 | os.Rename(backupPath, currentBinary) 248 | return fmt.Errorf("启动新版本失败,回滚操作: %v", err) 249 | } 250 | 251 | return nil 252 | } 253 | -------------------------------------------------------------------------------- /utils/commons.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "crypto/md5" 6 | "easy-itv/config" 7 | "encoding/base64" 8 | "encoding/hex" 9 | "encoding/json" 10 | "fmt" 11 | "io" 12 | "log" 13 | "net/http" 14 | "net/url" 15 | "regexp" 16 | "strings" 17 | "time" 18 | ) 19 | 20 | var logger = log.Default() 21 | 22 | // 获取本机信息 23 | func GetIPInfo() (string, string, string) { 24 | // 发起请求 25 | client := &http.Client{ 26 | Timeout: 30 * time.Second, // 设置超时时间为10秒 27 | } 28 | 29 | var resp *http.Response 30 | var err error 31 | maxRetries := 3 // 最大重试次数 32 | for i := 0; i < maxRetries; i++ { 33 | resp, err = client.Get("http://myip.ipip.net") 34 | if err == nil { 35 | defer resp.Body.Close() 36 | 37 | // 读取返回的内容 38 | body, err := io.ReadAll(resp.Body) 39 | if err != nil { 40 | return "异常", "异常", "异常" 41 | } 42 | 43 | // 将响应内容转换为字符串 44 | ipInfo := string(body) 45 | 46 | // 正则表达式提取 IP 地址 47 | ipRegex := regexp.MustCompile(`当前 IP:(\d+\.\d+\.\d+\.\d+)`) 48 | ipMatches := ipRegex.FindStringSubmatch(ipInfo) 49 | if len(ipMatches) < 2 { 50 | // fmt.Println("解析 IP 地址失败") 51 | return "未知", "未知", "未知" 52 | } 53 | 54 | // 获取 IP 地址 55 | ip := ipMatches[1] 56 | if ip == "" { 57 | // fmt.Println("IP 地址为空") 58 | return "未知", "未知", "未知" 59 | } 60 | 61 | // 查找 "来自于:" 之后的部分 62 | parts := strings.Split(ipInfo, "来自于:") 63 | if len(parts) < 2 { 64 | // fmt.Println("解析位置信息失败") 65 | return ip, "未知", "未知" 66 | } 67 | 68 | // 获取位置并去除多余的空格 69 | location := strings.TrimSpace(parts[1]) 70 | if location == "" { 71 | location = "未知" 72 | } 73 | 74 | province := "未知" 75 | if key, _, found := GetFromList(location, config.ProvinceList); found { 76 | province = key 77 | config.Province = province 78 | } 79 | 80 | operator := "未知" 81 | if key, _, found := GetFromList(location, config.OperatorList); found { 82 | operator = key 83 | config.Operator = key 84 | } 85 | 86 | return ip, province, operator 87 | } 88 | fmt.Printf("%d/%d: %v\n", i+1, maxRetries, err) 89 | time.Sleep(2 * time.Second) // 每次重试间隔 2 秒 90 | } 91 | return "", "", "" 92 | } 93 | 94 | // 通用查询列表 95 | func GetFromList(SearchKey string, SearchList map[string]string) (string, string, bool) { 96 | for key, code := range SearchList { 97 | if strings.Contains(SearchKey, key) { 98 | return key, code, true 99 | } 100 | } 101 | return "", "", false 102 | } 103 | 104 | // GetFormattedTime 获取当前时间并格式化为 "yyyy-MM-dd HH:mm:ss" 格式 105 | func GetFormattedTime() string { 106 | currentTime := time.Now() 107 | return currentTime.Format("2006-01-02 15:04:05") 108 | } 109 | 110 | // 获取 HTTP 请求的查询参数(query 参数) 111 | func DefaultQuery(r *http.Request, name string, defaultValue string) string { 112 | param := r.URL.Query().Get(name) 113 | if param == "" { 114 | return defaultValue 115 | } 116 | return param 117 | } 118 | 119 | // sendHttpRequest 发送 HTTP 请求 120 | func SendHttpRequest(requestUrl, method string, requestBody interface{}, requestHeader map[string]string, debugMode bool, isFormUrlEncoded bool) (int, string, error) { 121 | client := &http.Client{Timeout: 30 * time.Second} 122 | 123 | var reqBody io.Reader 124 | if requestBody != nil { 125 | if isFormUrlEncoded { 126 | // 处理 x-www-form-urlencoded 127 | data := url.Values{} 128 | if bodyMap, ok := requestBody.(map[string]string); ok { 129 | for key, value := range bodyMap { 130 | data.Set(key, value) 131 | } 132 | } 133 | reqBody = strings.NewReader(data.Encode()) 134 | } else { 135 | // 默认 JSON 处理 136 | jsonData, err := json.Marshal(requestBody) 137 | if err != nil { 138 | return 0, "", err 139 | } 140 | reqBody = bytes.NewBuffer([]byte(jsonData)) 141 | } 142 | } 143 | 144 | // 创建请求 145 | req, err := http.NewRequest(strings.ToUpper(method), requestUrl, reqBody) 146 | if err != nil { 147 | logger.Printf("NewRequest Error: %v", err) 148 | return 0, "", err 149 | } 150 | 151 | // 设置请求头 152 | for key, value := range requestHeader { 153 | // req.Header.Set(key, value) 154 | req.Header[key] = []string{value} // 直接赋值,避免 net/http 规范化 155 | } 156 | 157 | // 发送请求 158 | resp, err := client.Do(req) 159 | if err != nil { 160 | return 0, "", err 161 | } 162 | defer resp.Body.Close() 163 | 164 | // 读取响应 165 | respBody, err := io.ReadAll(resp.Body) 166 | if err != nil { 167 | logger.Printf("io.ReadAll Error: %v", err) 168 | return resp.StatusCode, "", err 169 | } 170 | 171 | if debugMode { 172 | fmt.Println("Request URL:", requestUrl) 173 | fmt.Println("Method:", method) 174 | fmt.Println("Request Header:", requestHeader) 175 | fmt.Println("Request Body:", requestBody) 176 | fmt.Println("HTTP Code:", resp.StatusCode) 177 | fmt.Println("Response Body:", string(respBody)) 178 | fmt.Println("------------------------") 179 | } 180 | 181 | return resp.StatusCode, string(respBody), nil 182 | } 183 | 184 | // Md5Encrypt 生成字符串的 MD5 值 185 | func Md5Encrypt(input string) string { 186 | hash := md5.New() 187 | hash.Write([]byte(input)) 188 | return hex.EncodeToString(hash.Sum(nil)) 189 | } 190 | 191 | // Base64 解码函数 192 | func DecodeBase64(encoded string) (string, error) { 193 | data, err := base64.StdEncoding.DecodeString(encoded) 194 | if err != nil { 195 | return "", err 196 | } 197 | return string(data), nil 198 | } 199 | --------------------------------------------------------------------------------