m3u8d/curl.go

152 lines
2.8 KiB
Go

package m3u8d
import (
"bytes"
"net/http"
"strconv"
"strings"
"unicode"
)
type ParseCurl_Resp struct {
ErrMsg string
DownloadReq RunDownload_Req
}
func ParseCurlStr(s string) (resp ParseCurl_Resp) {
r := strings.NewReader(strings.ReplaceAll(s, "\\\n", ""))
var tmp []string
for {
b, _, err := r.ReadRune()
if err != nil {
break
}
if unicode.IsSpace(b) {
continue
}
if b == '"' || b == '\'' {
str := parseQuotedStr(r, b)
tmp = append(tmp, str)
} else {
var buf bytes.Buffer
buf.WriteRune(b)
for {
b, _, err = r.ReadRune()
if err != nil || unicode.IsSpace(b) {
break
}
buf.WriteRune(b)
}
tmp = append(tmp, buf.String())
}
}
if len(tmp) > 0 && strings.ToLower(tmp[0]) == "curl" {
tmp = tmp[1:]
}
return ParseCurl(tmp)
}
func parseQuotedStr(r *strings.Reader, b rune) string {
var buf bytes.Buffer
var prevHasQ = false
for {
nextB, _, err := r.ReadRune()
if err != nil {
break
}
if nextB == b && prevHasQ == false {
break
}
if nextB == '\\' && b == '"' && prevHasQ == false {
prevHasQ = true
continue
}
prevHasQ = false
buf.WriteRune(nextB)
}
return buf.String()
}
func ParseCurl(cmdList []string) (resp ParseCurl_Resp) {
header := http.Header{}
isHeader := false
isMethod := false
isProxy := false
for idx := 0; idx < len(cmdList); idx++ {
value := cmdList[idx]
if isHeader {
idx1 := strings.Index(value, ": ")
if idx1 >= 0 {
k := value[:idx1]
v := value[idx1+2:]
header.Set(k, v)
}
isHeader = false
continue
}
if isMethod {
if strings.ToUpper(value) != http.MethodGet {
resp.ErrMsg = "不支持的method: " + strconv.Quote(value)
return resp
}
isMethod = false
continue
}
if isProxy {
resp.DownloadReq.SetProxy = value
isProxy = false
continue
}
valueLow := strings.ToLower(value)
switch valueLow {
case "-h":
isHeader = true
case "--compressed":
case "-x":
if value == "-X" {
isMethod = true
} else {
isProxy = true
}
case "-k", "--insecure":
resp.DownloadReq.Insecure = true
default:
if strings.HasPrefix(valueLow, "-") { // 不认识的flag, 跳过
continue
}
if resp.DownloadReq.M3u8Url != "" {
resp.ErrMsg = "重复的url"
return resp
}
resp.DownloadReq.M3u8Url = value
}
}
resp.DownloadReq.HeaderMap = header
return resp
}
func RunDownload_Req_ToCurlStr(req RunDownload_Req) string {
if req.M3u8Url == "" {
return ""
}
var buf bytes.Buffer
buf.WriteString("curl " + strconv.Quote(req.M3u8Url))
if req.Insecure {
buf.WriteString(" \\\n -insecure")
}
if req.SetProxy != "" {
buf.WriteString(" \\\n -X " + req.SetProxy)
}
for key, vList := range req.HeaderMap {
if len(vList) == 0 {
continue
}
buf.WriteString(" \\\n -H ")
buf.WriteString(`'` + key + `: ` + vList[0] + `'`)
}
return buf.String()
}