支持设置代理,包括http/socks5
parent
4705133ce7
commit
199fd9b9fc
|
|
@ -22,7 +22,7 @@
|
|||
* [x] windows、linux、mac都支持ffmpeg合并ts列表为mp4
|
||||
* [x] 充分测试后,使用 https://github.com/yapingcat/gomedia 代替ffmpeg进行格式转换
|
||||
* [x] 支持嵌套m3u8的url
|
||||
* [ ] 支持设置代理
|
||||
* [x] 支持设置代理
|
||||
* [ ] 支持从curl命令解析出需要的header、auth-basic、cookie等信息,正如 https://github.com/cxjava/m3u8-downloader 一样
|
||||
## 二次开发操作手册:
|
||||
* 如果只开发命令行版本, 则只需要修改*.go文件, 然后编译 cmd/main.go 即可
|
||||
|
|
|
|||
|
|
@ -33,6 +33,7 @@ func init() {
|
|||
rootCmd.Flags().StringVarP(&gRunReq.SaveDir, "SaveDir", "d", "", "文件保存路径(默认为当前路径)")
|
||||
rootCmd.Flags().StringVarP(&gRunReq.FileName, "FileName", "f", "", "文件名")
|
||||
rootCmd.Flags().IntVarP(&gRunReq.SkipTsCountFromHead, "SkipTsCountFromHead", "", 0, "跳过前面几个ts")
|
||||
rootCmd.Flags().StringVarP(&gRunReq.SetProxy, "SetProxy", "", "", "代理设置, http://127.0.0.1:8080, socks")
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ type RunDownload_Req struct {
|
|||
SaveDir string // "文件保存路径(默认为当前路径)"
|
||||
FileName string // 文件名
|
||||
SkipTsCountFromHead int // 跳过前面几个ts
|
||||
SetProxy string
|
||||
}
|
||||
|
||||
type downloadEnv struct {
|
||||
|
|
@ -246,12 +247,14 @@ var gOldEnv *downloadEnv
|
|||
var gOldEnvLocker sync.Mutex
|
||||
|
||||
func RunDownload(req RunDownload_Req) (resp RunDownload_Resp) {
|
||||
req.SetProxy = strings.ToLower(req.SetProxy)
|
||||
env := &downloadEnv{
|
||||
client: &http.Client{
|
||||
Transport: &http.Transport{
|
||||
TLSClientConfig: &tls.Config{
|
||||
InsecureSkipVerify: req.Insecure,
|
||||
},
|
||||
DialContext: newDialContext(req.SetProxy),
|
||||
},
|
||||
Timeout: time.Second * 10,
|
||||
},
|
||||
|
|
@ -577,7 +580,7 @@ func (this *downloadEnv) doGetRequest(urlS string) (data []byte, err error) {
|
|||
}
|
||||
req = req.WithContext(this.ctx)
|
||||
req.Header = this.header
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
resp, err := this.client.Do(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
|
|||
4
go.mod
4
go.mod
|
|
@ -3,11 +3,13 @@ module m3u8d
|
|||
go 1.17
|
||||
|
||||
require (
|
||||
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021
|
||||
github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2
|
||||
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123
|
||||
github.com/orestonce/go2cpp v0.0.0-20220605110533-c77a8dd7fdfd
|
||||
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171
|
||||
github.com/spf13/cobra v1.4.0
|
||||
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
|
|||
16
go.sum
16
go.sum
|
|
@ -1,12 +1,17 @@
|
|||
github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021 h1:EbF0UihnxWRcIMOwoVtqnAylsqcjzqpSvMdjF2Ud4rA=
|
||||
github.com/elazarl/goproxy v0.0.0-20220529153421-8ea89ba92021/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM=
|
||||
github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8=
|
||||
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
|
||||
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
|
||||
github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2 h1:AmGkuxSIOW0gA/jetY8d1DVV0cyQ08FMCxa1arkI6HQ=
|
||||
github.com/orestonce/cdb v0.0.0-20220528005855-d187c22240e2/go.mod h1:HMNNdA1LMQFJRwobtCzVevWcInFSo9rfs1fYeVYwU+c=
|
||||
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123 h1:AyAKqO7kC68OKiZk9GV4bUG+xMe1VQCy2CPbS9hvdY4=
|
||||
github.com/orestonce/go2cpp v0.0.0-20220507123906-b66d3600c123/go.mod h1:1fsOAZftk08/dOTRqlp6f/MVwaEKOhrnPUg0RtWiSdY=
|
||||
github.com/orestonce/go2cpp v0.0.0-20220605110533-c77a8dd7fdfd h1:q4MMzJG2Zdh9OLSiQfhPqL0/GGQ+B+SZmYDjbOjGW7Y=
|
||||
github.com/orestonce/go2cpp v0.0.0-20220605110533-c77a8dd7fdfd/go.mod h1:1fsOAZftk08/dOTRqlp6f/MVwaEKOhrnPUg0RtWiSdY=
|
||||
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171 h1:NnOl6HTrhrlTT7aaAybVOtq+fEztGFMoQtegckgwLdk=
|
||||
github.com/orestonce/gopool v0.0.0-20220508090328-d7d56d45b171/go.mod h1:MCQUrAPiG9/PTjHJuGqWLasKbIaG6z62KO6kfp90byM=
|
||||
github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc=
|
||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||
github.com/spf13/cobra v1.4.0 h1:y+wJpx64xcgO1V+RcnwW0LEHxTKRi2ZDPSBjWnrg88Q=
|
||||
github.com/spf13/cobra v1.4.0/go.mod h1:Wo4iy3BUC+X2Fybo0PDqwJIv3dNRiZLHQymsfxlB84g=
|
||||
|
|
@ -14,5 +19,12 @@ github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
|
|||
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6 h1:d9MplS5tlYkVzS20zFz47Hg82wvTnTk4Oafwo6j9Eb0=
|
||||
github.com/yapingcat/gomedia v0.0.0-20220619163023-5a5544262ef6/go.mod h1:WSZ59bidJOO40JSJmLqlkBJrjZCtjbKKkygEMfzY/kc=
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9 h1:Yqz/iviulwKwAREEeUd3nbBFn0XuyJqkoft2IlrvOhc=
|
||||
golang.org/x/net v0.0.0-20220617184016-355a448f1bc9/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||
|
|
|
|||
|
|
@ -83,53 +83,63 @@ RunDownload_Resp RunDownload(RunDownload_Req in0){
|
|||
std::string in;
|
||||
{
|
||||
{
|
||||
uint32_t tmp19 = in0.M3u8Url.length();
|
||||
char tmp20[4];
|
||||
tmp20[0] = (uint32_t(tmp19) >> 24) & 0xFF;
|
||||
tmp20[1] = (uint32_t(tmp19) >> 16) & 0xFF;
|
||||
tmp20[2] = (uint32_t(tmp19) >> 8) & 0xFF;
|
||||
tmp20[3] = (uint32_t(tmp19) >> 0) & 0xFF;
|
||||
in.append(tmp20, 4);
|
||||
uint32_t tmp22 = in0.M3u8Url.length();
|
||||
char tmp23[4];
|
||||
tmp23[0] = (uint32_t(tmp22) >> 24) & 0xFF;
|
||||
tmp23[1] = (uint32_t(tmp22) >> 16) & 0xFF;
|
||||
tmp23[2] = (uint32_t(tmp22) >> 8) & 0xFF;
|
||||
tmp23[3] = (uint32_t(tmp22) >> 0) & 0xFF;
|
||||
in.append(tmp23, 4);
|
||||
in.append(in0.M3u8Url);
|
||||
}
|
||||
{
|
||||
uint32_t tmp21 = in0.HostType.length();
|
||||
char tmp22[4];
|
||||
tmp22[0] = (uint32_t(tmp21) >> 24) & 0xFF;
|
||||
tmp22[1] = (uint32_t(tmp21) >> 16) & 0xFF;
|
||||
tmp22[2] = (uint32_t(tmp21) >> 8) & 0xFF;
|
||||
tmp22[3] = (uint32_t(tmp21) >> 0) & 0xFF;
|
||||
in.append(tmp22, 4);
|
||||
uint32_t tmp24 = in0.HostType.length();
|
||||
char tmp25[4];
|
||||
tmp25[0] = (uint32_t(tmp24) >> 24) & 0xFF;
|
||||
tmp25[1] = (uint32_t(tmp24) >> 16) & 0xFF;
|
||||
tmp25[2] = (uint32_t(tmp24) >> 8) & 0xFF;
|
||||
tmp25[3] = (uint32_t(tmp24) >> 0) & 0xFF;
|
||||
in.append(tmp25, 4);
|
||||
in.append(in0.HostType);
|
||||
}
|
||||
in.append((char*)(&in0.Insecure), 1);
|
||||
{
|
||||
uint32_t tmp23 = in0.SaveDir.length();
|
||||
char tmp24[4];
|
||||
tmp24[0] = (uint32_t(tmp23) >> 24) & 0xFF;
|
||||
tmp24[1] = (uint32_t(tmp23) >> 16) & 0xFF;
|
||||
tmp24[2] = (uint32_t(tmp23) >> 8) & 0xFF;
|
||||
tmp24[3] = (uint32_t(tmp23) >> 0) & 0xFF;
|
||||
in.append(tmp24, 4);
|
||||
uint32_t tmp26 = in0.SaveDir.length();
|
||||
char tmp27[4];
|
||||
tmp27[0] = (uint32_t(tmp26) >> 24) & 0xFF;
|
||||
tmp27[1] = (uint32_t(tmp26) >> 16) & 0xFF;
|
||||
tmp27[2] = (uint32_t(tmp26) >> 8) & 0xFF;
|
||||
tmp27[3] = (uint32_t(tmp26) >> 0) & 0xFF;
|
||||
in.append(tmp27, 4);
|
||||
in.append(in0.SaveDir);
|
||||
}
|
||||
{
|
||||
uint32_t tmp25 = in0.FileName.length();
|
||||
char tmp26[4];
|
||||
tmp26[0] = (uint32_t(tmp25) >> 24) & 0xFF;
|
||||
tmp26[1] = (uint32_t(tmp25) >> 16) & 0xFF;
|
||||
tmp26[2] = (uint32_t(tmp25) >> 8) & 0xFF;
|
||||
tmp26[3] = (uint32_t(tmp25) >> 0) & 0xFF;
|
||||
in.append(tmp26, 4);
|
||||
uint32_t tmp28 = in0.FileName.length();
|
||||
char tmp29[4];
|
||||
tmp29[0] = (uint32_t(tmp28) >> 24) & 0xFF;
|
||||
tmp29[1] = (uint32_t(tmp28) >> 16) & 0xFF;
|
||||
tmp29[2] = (uint32_t(tmp28) >> 8) & 0xFF;
|
||||
tmp29[3] = (uint32_t(tmp28) >> 0) & 0xFF;
|
||||
in.append(tmp29, 4);
|
||||
in.append(in0.FileName);
|
||||
}
|
||||
{
|
||||
char tmp27[4];
|
||||
tmp27[0] = (uint32_t(in0.SkipTsCountFromHead) >> 24) & 0xFF;
|
||||
tmp27[1] = (uint32_t(in0.SkipTsCountFromHead) >> 16) & 0xFF;
|
||||
tmp27[2] = (uint32_t(in0.SkipTsCountFromHead) >> 8) & 0xFF;
|
||||
tmp27[3] = (uint32_t(in0.SkipTsCountFromHead) >> 0) & 0xFF;
|
||||
in.append(tmp27, 4);
|
||||
char tmp30[4];
|
||||
tmp30[0] = (uint32_t(in0.SkipTsCountFromHead) >> 24) & 0xFF;
|
||||
tmp30[1] = (uint32_t(in0.SkipTsCountFromHead) >> 16) & 0xFF;
|
||||
tmp30[2] = (uint32_t(in0.SkipTsCountFromHead) >> 8) & 0xFF;
|
||||
tmp30[3] = (uint32_t(in0.SkipTsCountFromHead) >> 0) & 0xFF;
|
||||
in.append(tmp30, 4);
|
||||
}
|
||||
{
|
||||
uint32_t tmp31 = in0.SetProxy.length();
|
||||
char tmp32[4];
|
||||
tmp32[0] = (uint32_t(tmp31) >> 24) & 0xFF;
|
||||
tmp32[1] = (uint32_t(tmp31) >> 16) & 0xFF;
|
||||
tmp32[2] = (uint32_t(tmp31) >> 8) & 0xFF;
|
||||
tmp32[3] = (uint32_t(tmp31) >> 0) & 0xFF;
|
||||
in.append(tmp32, 4);
|
||||
in.append(in0.SetProxy);
|
||||
}
|
||||
}
|
||||
char *out = NULL;
|
||||
|
|
@ -138,21 +148,6 @@ RunDownload_Resp RunDownload(RunDownload_Req in0){
|
|||
RunDownload_Resp retValue;
|
||||
int outIdx = 0;
|
||||
{
|
||||
{
|
||||
uint32_t tmp28 = 0;
|
||||
uint32_t tmp29 = uint32_t(uint8_t(out[outIdx+0]) << 24);
|
||||
uint32_t tmp30 = uint32_t(uint8_t(out[outIdx+1]) << 16);
|
||||
uint32_t tmp31 = uint32_t(uint8_t(out[outIdx+2]) << 8);
|
||||
uint32_t tmp32 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
||||
tmp28 = tmp29 | tmp30 | tmp31 | tmp32;
|
||||
outIdx+=4;
|
||||
retValue.ErrMsg = std::string(out+outIdx, out+outIdx+tmp28);
|
||||
outIdx+=tmp28;
|
||||
}
|
||||
retValue.IsSkipped = (bool) out[outIdx];
|
||||
outIdx++;
|
||||
retValue.IsCancel = (bool) out[outIdx];
|
||||
outIdx++;
|
||||
{
|
||||
uint32_t tmp33 = 0;
|
||||
uint32_t tmp34 = uint32_t(uint8_t(out[outIdx+0]) << 24);
|
||||
|
|
@ -161,9 +156,24 @@ RunDownload_Resp RunDownload(RunDownload_Req in0){
|
|||
uint32_t tmp37 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
||||
tmp33 = tmp34 | tmp35 | tmp36 | tmp37;
|
||||
outIdx+=4;
|
||||
retValue.SaveFileTo = std::string(out+outIdx, out+outIdx+tmp33);
|
||||
retValue.ErrMsg = std::string(out+outIdx, out+outIdx+tmp33);
|
||||
outIdx+=tmp33;
|
||||
}
|
||||
retValue.IsSkipped = (bool) out[outIdx];
|
||||
outIdx++;
|
||||
retValue.IsCancel = (bool) out[outIdx];
|
||||
outIdx++;
|
||||
{
|
||||
uint32_t tmp38 = 0;
|
||||
uint32_t tmp39 = uint32_t(uint8_t(out[outIdx+0]) << 24);
|
||||
uint32_t tmp40 = uint32_t(uint8_t(out[outIdx+1]) << 16);
|
||||
uint32_t tmp41 = uint32_t(uint8_t(out[outIdx+2]) << 8);
|
||||
uint32_t tmp42 = uint32_t(uint8_t(out[outIdx+3]) << 0);
|
||||
tmp38 = tmp39 | tmp40 | tmp41 | tmp42;
|
||||
outIdx+=4;
|
||||
retValue.SaveFileTo = std::string(out+outIdx, out+outIdx+tmp38);
|
||||
outIdx+=tmp38;
|
||||
}
|
||||
}
|
||||
if (out != NULL) {
|
||||
free(out);
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#include <map>
|
||||
//Qt Creator 需要在xxx.pro 内部增加静态库的链接声明
|
||||
//LIBS += -L$$PWD -lm3u8d-impl
|
||||
|
||||
|
|
@ -13,18 +14,22 @@ struct RunDownload_Req{
|
|||
std::string SaveDir;
|
||||
std::string FileName;
|
||||
int32_t SkipTsCountFromHead;
|
||||
std::string SetProxy;
|
||||
RunDownload_Req(): Insecure(false),SkipTsCountFromHead(0){}
|
||||
};
|
||||
struct RunDownload_Resp{
|
||||
std::string ErrMsg;
|
||||
bool IsSkipped;
|
||||
bool IsCancel;
|
||||
std::string SaveFileTo;
|
||||
RunDownload_Resp(): IsSkipped(false),IsCancel(false){}
|
||||
};
|
||||
RunDownload_Resp RunDownload(RunDownload_Req in0);
|
||||
void CloseOldEnv();
|
||||
struct GetProgress_Resp{
|
||||
int32_t Percent;
|
||||
std::string Title;
|
||||
GetProgress_Resp(): Percent(0){}
|
||||
};
|
||||
GetProgress_Resp GetProgress();
|
||||
std::string GetWd();
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
|
|||
ui->pushButton_RunDownload->setEnabled(false);
|
||||
ui->checkBox_Insecure->setEnabled(false);
|
||||
ui->progressBar->setValue(0);
|
||||
ui->lineEdit_SetProxy->setEnabled(false);
|
||||
ui->pushButton_StopDownload->setEnabled(true);
|
||||
|
||||
m_syncUi.AddRunFnOn_OtherThread([this](){
|
||||
|
|
@ -62,6 +63,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
|
|||
req.SaveDir = ui->lineEdit_SaveDir->text().toStdString();
|
||||
req.FileName = ui->lineEdit_FileName->text().toStdString();
|
||||
req.SkipTsCountFromHead = ui->lineEdit_SkipTsCountFromHead->text().toInt();
|
||||
req.SetProxy = ui->lineEdit_SetProxy->text().toStdString();
|
||||
|
||||
m_syncUi.AddRunFnOn_OtherThread([req, this](){
|
||||
RunDownload_Resp resp = RunDownload(req);
|
||||
|
|
@ -75,6 +77,7 @@ void MainWindow::on_pushButton_RunDownload_clicked()
|
|||
ui->pushButton_RunDownload->setEnabled(true);
|
||||
ui->checkBox_Insecure->setEnabled(true);
|
||||
ui->pushButton_RunDownload->setText("开始下载");
|
||||
ui->lineEdit_SetProxy->setEnabled(true);
|
||||
ui->pushButton_StopDownload->setEnabled(false);
|
||||
if (resp.IsCancel) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>747</width>
|
||||
<height>247</height>
|
||||
<width>802</width>
|
||||
<height>260</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
|
@ -18,21 +18,21 @@
|
|||
<item>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>HostType</string>
|
||||
<string>代理设置</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="3">
|
||||
<widget class="QPushButton" name="pushButton_SaveDir">
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
<string>跳过前面几个TS</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="2">
|
||||
<widget class="QLineEdit" name="lineEdit_SkipTsCountFromHead"/>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_SaveDir"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
|
|
@ -41,17 +41,46 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_M3u8Url">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_SkipTsCountFromHead"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>保存位置</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_FileName">
|
||||
<property name="placeholderText">
|
||||
<string>all</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<item row="1" column="2">
|
||||
<widget class="QPushButton" name="pushButton_SaveDir">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>保存位置</string>
|
||||
<string>...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
@ -62,17 +91,7 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLineEdit" name="lineEdit_M3u8Url">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLineEdit" name="lineEdit_SaveDir"/>
|
||||
</item>
|
||||
<item row="4" column="2">
|
||||
<item row="5" column="1">
|
||||
<widget class="QComboBox" name="comboBox_HostType">
|
||||
<item>
|
||||
<property name="text">
|
||||
|
|
@ -86,10 +105,20 @@
|
|||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="label_6">
|
||||
<property name="text">
|
||||
<string>跳过前面几个TS</string>
|
||||
<string>HostType</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QLineEdit" name="lineEdit_SetProxy">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string>http://127.0.0.1:8080 socks5://127.0.0.1:1089</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,101 @@
|
|||
package m3u8d
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"golang.org/x/net/proxy"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func newDialContext(setProxy string) func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
return func(ctx context.Context, network, addr string) (net.Conn, error) {
|
||||
if setProxy == "" {
|
||||
return (&net.Dialer{}).DialContext(ctx, network, addr)
|
||||
} else if strings.HasPrefix(setProxy, "http") {
|
||||
return proxyByHttp(setProxy, ctx, addr)
|
||||
} else { // socks5
|
||||
urlObj, err := url.Parse(setProxy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
dialer, err := proxy.FromURL(urlObj, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return dialer.Dial(network, addr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func proxyByHttp(setProxy string, ctx context.Context, to string) (net.Conn, error) {
|
||||
// https://github.com/aidenesco/connect/blob/master/proxy.go
|
||||
urlObj, err := url.Parse(setProxy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var tConn net.Conn
|
||||
if strings.HasPrefix(setProxy, "https://") {
|
||||
host := urlObj.Host
|
||||
_, _, err = net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
host = host + ":443"
|
||||
}
|
||||
tConn, err = (&tls.Dialer{}).DialContext(ctx, "tcp", host)
|
||||
} else {
|
||||
host := urlObj.Host
|
||||
_, _, err = net.SplitHostPort(host)
|
||||
if err != nil {
|
||||
host = host + ":80"
|
||||
}
|
||||
tConn, err = (&net.Dialer{}).DialContext(ctx, "tcp", host)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
tConn.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
buf0 := bytes.NewBuffer(nil)
|
||||
buf0.WriteString(`CONNECT ` + to + ` HTTP/1.1` + "\r\n")
|
||||
|
||||
if u := urlObj.User; u != nil {
|
||||
username := u.Username()
|
||||
password, _ := u.Password()
|
||||
buf0.WriteString("Proxy-Authorization: Basic " + base64.StdEncoding.EncodeToString([]byte(username+":"+password)) + "\r\n")
|
||||
}
|
||||
buf0.WriteString("\r\n")
|
||||
_, err = tConn.Write(buf0.Bytes())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bufr := bufio.NewReader(tConn)
|
||||
|
||||
var response *http.Response
|
||||
response, err = http.ReadResponse(bufr, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
switch response.StatusCode {
|
||||
case http.StatusOK:
|
||||
return tConn, nil
|
||||
case http.StatusProxyAuthRequired:
|
||||
return nil, errors.New("connect: invalid or missing \"Proxy-Authorization\" header")
|
||||
default:
|
||||
return nil, fmt.Errorf("connect: unexpected CONNECT response status \"%s\" (expect 200 OK)", response.Status)
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue