Skip to content

Commit

Permalink
feat(epg): 未配置EPG接口时(channelProgramAPI),将自动进行尝试。
Browse files Browse the repository at this point in the history
  • Loading branch information
super321 committed Dec 31, 2024
1 parent b33f6e1 commit 74a5a5c
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 19 deletions.
22 changes: 11 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ IPTV工具,功能列表如下:
}
```

| 字段 | 说明 |
|-------------------|--------------------------------------------------------------------------------------------------------------------------|
| key | 不是Authenticator,而是生成Authenticator的秘钥,每个IPTV机顶盒可能都不同,可通过工具根据某次抓包获取的Authenticator反向破解key,具体见下面的使用介绍。 |
| interfaceName | 设备的网络接口名称,和ip字段二选一,优先使用该字段的值。当工具运行在软路由上时,可通过配置自动获取指定接口的IPv4地址。用于获取软路由上某接口被自动分配的IPTV线路的IP地址。 |
| serverHost | 工具请求的IPTV服务器地址,注意需要走IPTV专用网络才能访问通。 |
| ip | 客户端的ip,可任意配置,生成Authenticator所需。当interfaceName已配置时,优先通过interfaceName获取。 |
| channelProgramAPI | 请求频道节目信息的API接口,目前只支持两种:`liveplay_30``gdhdpublic`,缺省为`liveplay_30` |
| 字段 | 说明 |
|-------------------|------------------------------------------------------------------------------------------------------|
| key | 不是Authenticator,而是生成Authenticator的秘钥,每个IPTV机顶盒可能都不同,可通过工具根据某次抓包获取的Authenticator反向破解key,具体见下面的使用介绍。 |
| interfaceName | 设备的网络接口名称,和ip字段二选一,优先使用该字段的值。当工具运行在软路由上时,可通过配置自动获取指定接口的IPv4地址。用于获取软路由上某接口被自动分配的IPTV线路的IP地址。 |
| serverHost | 工具请求的IPTV服务器地址,注意需要走IPTV专用网络才能访问通。 |
| ip | 客户端的ip,可任意配置,生成Authenticator所需。当interfaceName已配置时,优先通过interfaceName获取。 |
| channelProgramAPI | 请求频道节目信息的API接口,目前只支持两种:`liveplay_30``gdhdpublic`。<br/>未配置时,工具将自动进行尝试。 |
| 其他字段 | 均可通过抓包获取(注意x-requested-with可通过抓包HTTP请求头拿到)。 必填字段:userID,stbType,stbVersion,stbID,mac,softwareVersion |

### 使用介绍
Expand Down Expand Up @@ -98,10 +98,10 @@ http://IP:PORT/channel/m3u?csFormat={format}&multiFirst={multiFirst}

1. 参数csFormat可指定回看catchup-source的请求格式,非必填。可选值如下:

|| 是否缺省 | 说明 |
|---|------|-------------------------------------------------------|
| 0 || `?playseek=${(b)yyyyMMddHHmmss}-${(e)yyyyMMddHHmmss}` |
| 1 || `?playseek={utc:YmdHMS}-{utcend:YmdHMS}` |
|| 是否缺省 | 说明 |
|---|------|-------------------------------------------------------|
| 0 || `?playseek=${(b)yyyyMMddHHmmss}-${(e)yyyyMMddHHmmss}` |
| 1 || `?playseek={utc:YmdHMS}-{utcend:YmdHMS}` |

2. 参数multiFirst:当频道存在多个URL地址时,是否优先使用组播地址。可选值:`true``false`。非必填,缺省为`true`

Expand Down
35 changes: 32 additions & 3 deletions internal/app/iptv/ct/epg.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ import (
"context"
"errors"
"iptv/internal/app/iptv"

"go.uber.org/zap"
)

var ErrParseChProgList = errors.New("failed to parse channel program list")
var ErrChProgListIsEmpty = errors.New("the list of programs is empty")
var (
ErrParseChProgList = errors.New("failed to parse channel program list")
ErrChProgListIsEmpty = errors.New("the list of programs is empty")
ErrEPGApiNotFound = errors.New("epg api not found")
)

const (
chProgAPILiveplay = "liveplay_30"
Expand Down Expand Up @@ -36,10 +41,15 @@ func (c *Client) GetAllChannelProgramList(ctx context.Context, channels []iptv.C
case chProgAPIGdhdpublic:
progList, err = c.getGdhdpublicChannelProgramList(ctx, token, &channel)
default:
progList, err = c.getLiveplayChannelProgramList(ctx, token, &channel)
// 自动选择调用EPG的API接口
progList, err = c.getChannelProgramListByAuto(ctx, token, &channel)
}

if err != nil {
if errors.Is(err, ErrEPGApiNotFound) {
c.logger.Error("Failed to get channel program list.", zap.Error(err))
break
}
c.logger.Sugar().Warnf("Failed to get the program list for channel %s. Error: %v", channel.ChannelName, err)
continue
}
Expand All @@ -49,3 +59,22 @@ func (c *Client) GetAllChannelProgramList(ctx context.Context, channels []iptv.C

return epg, nil
}

// getChannelProgramListByAuto 自动选择调用EPG的API接口
func (c *Client) getChannelProgramListByAuto(ctx context.Context, token *Token, channel *iptv.Channel) (*iptv.ChannelProgramList, error) {
progList, err := c.getLiveplayChannelProgramList(ctx, token, channel)
if !errors.Is(err, ErrEPGApiNotFound) {
c.logger.Info("An available EPG API was found.", zap.String("channelProgramAPI", chProgAPILiveplay))
c.config.ChannelProgramAPI = chProgAPILiveplay
return progList, err
}

progList, err = c.getGdhdpublicChannelProgramList(ctx, token, channel)
if !errors.Is(err, ErrEPGApiNotFound) {
c.logger.Info("An available EPG API was found.", zap.String("channelProgramAPI", chProgAPIGdhdpublic))
c.config.ChannelProgramAPI = chProgAPIGdhdpublic
return progList, err
}

return nil, err
}
8 changes: 7 additions & 1 deletion internal/app/iptv/ct/epg_gdhdpublic.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package ct
import (
"context"
"encoding/json"
"errors"
"fmt"
"io"
"iptv/internal/app/iptv"
Expand Down Expand Up @@ -47,6 +48,9 @@ func (c *Client) getGdhdpublicChannelProgramList(ctx context.Context, token *Tok
// 获取指定日期的节目单列表
dateProgram, err := c.getGdhdpublicChannelDateProgram(ctx, token, channel.ChannelID, dateStr)
if err != nil {
if errors.Is(err, ErrEPGApiNotFound) {
return nil, err
}
c.logger.Sugar().Warnf("Failed to get the program list for channel %s on %s. Error: %v", channel.ChannelName, dateStr, err)
continue
}
Expand Down Expand Up @@ -97,7 +101,9 @@ func (c *Client) getGdhdpublicChannelDateProgram(ctx context.Context, token *Tok
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
return nil, ErrEPGApiNotFound
} else if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http status code: %d", resp.StatusCode)
}

Expand Down
10 changes: 6 additions & 4 deletions internal/app/iptv/ct/epg_liveplay.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ func (c *Client) getLiveplayChannelProgramList(ctx context.Context, token *Token
}
defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
if resp.StatusCode == http.StatusNotFound {
return nil, ErrEPGApiNotFound
} else if resp.StatusCode != http.StatusOK {
return nil, fmt.Errorf("http status code: %d", resp.StatusCode)
}

Expand All @@ -59,7 +61,7 @@ func (c *Client) getLiveplayChannelProgramList(ctx context.Context, token *Token
}

// 解析节目单
dateProgramList, err := parseFTTHChannelProgramList(matches[1])
dateProgramList, err := parseLiveplayChannelProgramList(matches[1])
if err != nil {
return nil, err
}
Expand All @@ -71,8 +73,8 @@ func (c *Client) getLiveplayChannelProgramList(ctx context.Context, token *Token
}, nil
}

// parseFTTHChannelProgramList 解析频道节目单列表
func parseFTTHChannelProgramList(rawData []byte) ([]iptv.DateProgram, error) {
// parseLiveplayChannelProgramList 解析频道节目单列表
func parseLiveplayChannelProgramList(rawData []byte) ([]iptv.DateProgram, error) {
// 动态解析Json
var rawArray []any
err := json.Unmarshal(rawData, &rawArray)
Expand Down

0 comments on commit 74a5a5c

Please sign in to comment.