Skip to content

Commit

Permalink
支持使用时间跳过
Browse files Browse the repository at this point in the history
  • Loading branch information
orestonce committed Sep 7, 2024
1 parent 84067ca commit fd4cdf9
Show file tree
Hide file tree
Showing 7 changed files with 198 additions and 10 deletions.
72 changes: 67 additions & 5 deletions api.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ import (
"crypto/sha256"
"crypto/tls"
"encoding/hex"
"errors"
"fmt"
"math"
"net/http"
"net/url"
"os"
Expand Down Expand Up @@ -70,10 +72,16 @@ type SkipTsUnit struct {
EndIdx uint32 // 包含
}

type SkipByTimeUnit struct {
StartSec uint32
EndSec uint32
}

type SkipTsInfo struct {
HttpCodeList []int
SkipList []SkipTsUnit
IfHttpCodeMergeTs bool
SkipByTimeList []SkipByTimeUnit
}

func ParseSkipTsExpr(expr string) (info SkipTsInfo, errMsg string) {
Expand All @@ -85,6 +93,7 @@ func ParseSkipTsExpr(expr string) (info SkipTsInfo, errMsg string) {
singleRe := regexp.MustCompile(`^([0-9]+)$`)
betweenRe := regexp.MustCompile(`^([0-9]+) *- *([0-9]+)$`)
httpCodeRe := regexp.MustCompile(`^http.code *= *([0-9]+)$`)
betweenTimeRe := regexp.MustCompile(`^time *: *(\d{2}:\d{2}:\d{2}) *- *(\d{2}:\d{2}:\d{2})$`)

for _, one := range list {
one = strings.TrimSpace(one)
Expand Down Expand Up @@ -119,6 +128,16 @@ func ParseSkipTsExpr(expr string) (info SkipTsInfo, errMsg string) {
} else if one == `if-http.code-merge_ts` {
info.IfHttpCodeMergeTs = true
ok = true
} else if groups = betweenTimeRe.FindStringSubmatch(one); len(groups) > 0 {
startSec, err1 := getTimeSecFromStr(groups[1])
endSec, err2 := getTimeSecFromStr(groups[2])
if err1 == nil && err2 == nil && startSec < endSec {
ok = true
info.SkipByTimeList = append(info.SkipByTimeList, SkipByTimeUnit{
StartSec: startSec,
EndSec: endSec,
})
}
}
if ok == false {
return info, "parse expr part invalid " + strconv.Quote(one)
Expand All @@ -132,6 +151,20 @@ func ParseSkipTsExpr(expr string) (info SkipTsInfo, errMsg string) {
return info, ""
}

func getTimeSecFromStr(str string) (sec uint32, err error) {
var h, m, s uint32

_, err = fmt.Sscanf(str, `%d:%d:%d`, &h, &m, &s)
if err != nil {
return 0, err
}
if m >= 60 || s >= 60 {
return 0, errors.New("invalid str " + strconv.Quote(str))
}
sec = h*60*60 + m*60 + s
return sec, nil
}

func maxUint32(a uint32, b uint32) uint32 {
if a > b {
return a
Expand Down Expand Up @@ -313,7 +346,7 @@ func (this *DownloadEnv) runDownload(req StartDownload_Req, skipInfo SkipTsInfo)
this.setErrMsg("获取ts列表错误: " + errMsg)
return
}
tsList = skipApplyFilter(tsList, skipInfo.SkipList, req.Skip_EXT_X_DISCONTINUITY)
tsList = skipApplyFilter(tsList, skipInfo, req.Skip_EXT_X_DISCONTINUITY)
if len(tsList) <= 0 {
this.setErrMsg("需要下载的文件为空")
return
Expand Down Expand Up @@ -422,23 +455,52 @@ func (this *DownloadEnv) runDownload(req StartDownload_Req, skipInfo SkipTsInfo)
this.setSaveFileTo(name, false)
return
}
func isSkipByTsTime(beginSec float64, endSec float64, list []SkipByTimeUnit) bool {
for _, unit := range list {
newBegin := math.Max(float64(unit.StartSec), beginSec)
newEnd := math.Min(float64(unit.EndSec), endSec)

func skipApplyFilter(list []TsInfo, skipList []SkipTsUnit, skip_EXT_X_DISCONTINUITY bool) (after []TsInfo) {
isSkip := func(idx uint32) bool {
for _, unit := range skipList {
if newEnd > newBegin {
return true
}
}
return false
}

func skipApplyFilter(list []TsInfo, skipInfo SkipTsInfo, skip_EXT_X_DISCONTINUITY bool) (after []TsInfo) {
var hasEmptyExtinf bool
for _, ts := range list {
if ts.TimeSec < 1e-5 {
hasEmptyExtinf = true
}
}
isSkipByTsIndex := func(idx uint32) bool {
for _, unit := range skipInfo.SkipList {
if unit.StartIdx <= idx && idx <= unit.EndIdx {
return true
}
}
return false
}

var timeBegin float64
var timeEnd float64

for idx, ts := range list {
if isSkip(uint32(idx) + 1) {
if idx > 0 {
timeBegin += list[idx-1].TimeSec
}
timeEnd += ts.TimeSec

if isSkipByTsIndex(uint32(idx) + 1) {
continue
}
if skip_EXT_X_DISCONTINUITY && ts.Between_EXT_X_DISCONTINUITY {
continue
}
if hasEmptyExtinf == false && isSkipByTsTime(timeBegin, timeEnd, skipInfo.SkipByTimeList) {
continue
}
after = append(after, ts)
}
return after
Expand Down
52 changes: 52 additions & 0 deletions api_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,55 @@ func TestFindUrlInStr(t *testing.T) {
t.Fail()
}
}

func TestSkip(t *testing.T) {
skip := isSkipByTsTime(10, 20, []SkipByTimeUnit{
{
StartSec: 0,
EndSec: 6,
},
})
if skip {
t.Fatal()
}

skip = isSkipByTsTime(10, 20, []SkipByTimeUnit{
{
StartSec: 6,
EndSec: 11,
},
})
if skip == false {
t.Fatal()
}

skip = isSkipByTsTime(10, 20, []SkipByTimeUnit{
{
StartSec: 12,
EndSec: 17,
},
})
if skip == false {
t.Fatal()
}

skip = isSkipByTsTime(10, 20, []SkipByTimeUnit{
{
StartSec: 18,
EndSec: 28,
},
})
if skip == false {
t.Fatal()
}

skip = isSkipByTsTime(10, 20, []SkipByTimeUnit{
{
StartSec: 21,
EndSec: 28,
},
})
if skip {
t.Fatal()
}
}
14 changes: 13 additions & 1 deletion download.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ import (
type TsInfo struct {
Name string
Url string
Seq uint64 // 如果是aes加密并且没有iv, 这个seq需要充当iv
Seq uint64 // 如果是aes加密并且没有iv, 这个seq需要充当iv
TimeSec float64 // 此ts片段占用多少秒
Between_EXT_X_DISCONTINUITY bool
SkipByHttpCode bool
HttpCode int
Expand Down Expand Up @@ -156,6 +157,8 @@ func getTsList(beginSeq uint64, m38uUrl string, body string) (tsList []TsInfo, e
index := 0

var between_EXT_X_DISCONTINUITY = false // 正在跳过 #EXT-X-DISCONTINUITY 标签间的ts
var timeSec float64
var reExtInf = regexp.MustCompile(`^#EXTINF *: *([0-9.]+)`)

for _, line := range splitLineWithTrimSpace(body) {
line = strings.TrimSpace(line)
Expand All @@ -165,6 +168,13 @@ func getTsList(beginSeq uint64, m38uUrl string, body string) (tsList []TsInfo, e
}
continue
}
if groups := reExtInf.FindStringSubmatch(line); len(groups) > 0 {
f, err := strconv.ParseFloat(groups[1], 64)
if err == nil {
timeSec = f
}
continue
}
if !strings.HasPrefix(line, "#") && line != "" {
index++
var after string
Expand All @@ -177,7 +187,9 @@ func getTsList(beginSeq uint64, m38uUrl string, body string) (tsList []TsInfo, e
Url: after,
Seq: beginSeq + uint64(index-1),
Between_EXT_X_DISCONTINUITY: between_EXT_X_DISCONTINUITY,
TimeSec: timeSec,
})
timeSec = 0
}
}
return tsList, ""
Expand Down
25 changes: 24 additions & 1 deletion download_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func TestParseSkipTsExpr2(t *testing.T) {
if errMsg != "" {
panic(errMsg)
}
reflect.DeepEqual(list, []SkipTsUnit{
ok := reflect.DeepEqual(list, []SkipTsUnit{
{
StartIdx: 1,
EndIdx: 1,
Expand All @@ -68,6 +68,29 @@ func TestParseSkipTsExpr2(t *testing.T) {
EndIdx: 1000000000,
},
})
if ok == false {
t.Fatal()
}
}

func TestParseSkipTsExpr3(t *testing.T) {
info, errMsg := ParseSkipTsExpr("12-17, time:01:23:45-12:34:56,time:00:00:00-00:00:43")
if errMsg != "" {
t.Fatal(errMsg)
}
ok := reflect.DeepEqual(info.SkipByTimeList, []SkipByTimeUnit{
{
StartSec: (1 * 60 * 60) + (23 * 60) + 45,
EndSec: (12 * 60 * 60) + (34 * 60) + 56,
},
{
StartSec: 0,
EndSec: 43,
},
})
if ok == false {
t.Fatal()
}
}

func TestUrlHasSuffix(t *testing.T) {
Expand Down
39 changes: 38 additions & 1 deletion m3u8_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ func TestM3u8Parse3(t *testing.T) {
if errMsg != "" {
t.Fatal(errMsg)
}
after := skipApplyFilter(list, nil, true)
after := skipApplyFilter(list, SkipTsInfo{}, true)
if len(after) != 11 {
t.Fatal()
}
Expand Down Expand Up @@ -171,3 +171,40 @@ const m3u8Sample3 = `#EXTM3U
0001414.ts
#EXT-X-ENDLIST
`

func TestM3u8Parse4(t *testing.T) {
beginSeq := parseBeginSeq([]byte(m3u8Sample4))
list, errMsg := getTsList(beginSeq, `https://www.example.com`, m3u8Sample4)
if errMsg != "" {
t.Fatal(errMsg)
}
after := skipApplyFilter(list, SkipTsInfo{
SkipByTimeList: []SkipByTimeUnit{
{
StartSec: 6,
EndSec: 10,
},
},
}, false)
if len(after) != 3 || after[0].Seq != 0 || after[1].Seq != 3 || after[2].Seq != 4 {
t.Fatal(after)
}
}

const m3u8Sample4 = `#EXTM3U
#EXT-X-VERSION:3
#EXT-X-TARGETDURATION:6
#EXT-X-PLAYLIST-TYPE:VOD
#EXT-X-MEDIA-SEQUENCE:0
#EXT-X-KEY:METHOD=AES-128,URI="key.key"
#EXTINF:5.867,
1.ts
#EXTINF:2.933,
2.ts
#EXTINF:2.933,
3.ts
#EXTINF:2.933,
4.ts
#EXTINF:2.933,
5.ts
#EXT-X-ENDLIST`
2 changes: 2 additions & 0 deletions m3u8d-qt/mainwindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ MainWindow::MainWindow(QWidget *parent) :
ui->setupUi(this);

ui->lineEdit_SaveDir->setPlaceholderText(QString::fromStdString(GetWd()));
ui->lineEdit_TsTempDir->setPlaceholderText(QString::fromStdString(GetWd()));

m_timer = new QTimer(this);
connect(m_timer, &QTimer::timeout, [this](){
//更新ui1
Expand Down
4 changes: 2 additions & 2 deletions m3u8d-qt/mainwindow.ui
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@
<item row="7" column="1">
<widget class="QLineEdit" name="lineEdit_TsTempDir">
<property name="placeholderText">
<string>默认为保存位置</string>
<string/>
</property>
</widget>
</item>
Expand All @@ -97,7 +97,7 @@
<item row="3" column="1">
<widget class="QLineEdit" name="lineEdit_SkipTsExpr">
<property name="placeholderText">
<string>1,92-100,http.code=403,if-http.code-merge_ts</string>
<string>1,92-100,http.code=403,if-http.code-merge_ts,time:00:05:12-00:07:20</string>
</property>
</widget>
</item>
Expand Down

0 comments on commit fd4cdf9

Please sign in to comment.