import
sys
import
os
from
urllib.parse
import
urlparse
from
PyQt5.QtWidgets
import
(QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout, QLabel, QLineEdit,
QPushButton, QTextEdit,
QFileDialog, QMessageBox)
from
PyQt5.QtCore
import
QProcess, QByteArray
class
M3U8Downloader(QMainWindow):
def
__init__(
self
):
super
().__init__()
self
.log_text
=
QTextEdit()
self
.download_btn
=
QPushButton(
'开始下载'
)
self
.browse_btn
=
QPushButton(
'浏览...'
)
self
.path_input
=
QLineEdit()
self
.filename_input
=
QLineEdit()
self
.url_input
=
QLineEdit()
self
.current_dir
=
os.path.dirname(os.path.abspath(__file__))
self
.initUI()
self
.process
=
QProcess(
self
)
self
.process.readyReadStandardOutput.connect(
self
.handle_stdout)
self
.process.readyReadStandardError.connect(
self
.handle_stderr)
self
.process.finished.connect(
self
.process_finished)
def
initUI(
self
):
self
.setWindowTitle(
'M3U8视频下载器'
)
self
.setGeometry(
100
,
100
,
800
,
600
)
central_widget
=
QWidget()
self
.setCentralWidget(central_widget)
main_layout
=
QVBoxLayout()
url_layout
=
QHBoxLayout()
self
.url_input.setPlaceholderText(
'输入M3U8视频链接...'
)
self
.url_input.textChanged.connect(
self
.update_filename)
url_layout.addWidget(QLabel(
'视频链接:'
))
url_layout.addWidget(
self
.url_input)
filename_layout
=
QHBoxLayout()
self
.filename_input.setPlaceholderText(
'自动生成文件名'
)
filename_layout.addWidget(QLabel(
'保存名称:'
))
filename_layout.addWidget(
self
.filename_input)
path_layout
=
QHBoxLayout()
default_download_dir
=
os.path.join(
self
.current_dir,
'download'
)
os.makedirs(default_download_dir, exist_ok
=
True
)
self
.path_input.setText(default_download_dir)
self
.browse_btn.clicked.connect(
self
.select_output_dir)
path_layout.addWidget(QLabel(
'保存路径:'
))
path_layout.addWidget(
self
.path_input)
path_layout.addWidget(
self
.browse_btn)
self
.download_btn.clicked.connect(
self
.start_download)
self
.log_text.setReadOnly(
True
)
main_layout.addLayout(url_layout)
main_layout.addLayout(filename_layout)
main_layout.addLayout(path_layout)
main_layout.addWidget(
self
.download_btn)
main_layout.addWidget(QLabel(
'下载日志:'
))
main_layout.addWidget(
self
.log_text)
central_widget.setLayout(main_layout)
def
update_filename(
self
):
url
=
self
.url_input.text().strip()
if
not
url:
self
.filename_input.setText('')
return
parsed
=
urlparse(url)
path
=
parsed.path
base_name
=
os.path.basename(path)
if
'.'
in
base_name:
name
=
os.path.splitext(base_name)[
0
]
else
:
name
=
'output'
self
.filename_input.setText(f
"{name}.mp4"
)
def
select_output_dir(
self
):
directory
=
QFileDialog.getExistingDirectory(
self
,
'选择保存路径'
)
if
directory:
self
.path_input.setText(directory)
def
start_download(
self
):
url
=
self
.url_input.text().strip()
save_dir
=
self
.path_input.text().strip()
filename
=
self
.filename_input.text().strip()
if
not
url:
QMessageBox.warning(
self
,
'错误'
,
'请输入有效的M3U8链接'
)
return
if
not
os.path.exists(save_dir):
QMessageBox.warning(
self
,
'错误'
,
'保存路径不存在'
)
return
if
not
filename.lower().endswith(
'.mp4'
):
filename
+
=
'.mp4'
args
=
[
'--save-name'
, f
'{filename[:-4]}'
,
'--tmp-dir'
, f
'{os.path.join(save_dir, '
temp
')}'
,
'--save-dir'
, f
'{save_dir}'
,
'--ffmpeg-binary-path'
, f
'{os.path.join(self.current_dir, "bin", "ffmpeg.exe")}'
,
'--del-after-done'
,
'--force-ansi-console'
,
'--auto-select'
,
f
'{url}'
]
self
.log_text.clear()
self
.log(f
'开始下载:{url}'
)
self
.log(f
'保存路径:{os.path.join(save_dir, filename)}'
)
self
.download_btn.setEnabled(
False
)
executable_path
=
os.path.join(
self
.current_dir,
'bin'
,
'N_m3u8DL-RE.exe'
)
self
.process.start(executable_path, args)
def
handle_stdout(
self
):
data
=
self
.process.readAllStandardOutput()
self
.log(QByteArray(data).data().decode(
'utf-8'
, errors
=
'ignore'
))
def
handle_stderr(
self
):
data
=
self
.process.readAllStandardError()
self
.log(QByteArray(data).data().decode(
'utf-8'
, errors
=
'ignore'
), error
=
True
)
def
process_finished(
self
, exit_code):
self
.download_btn.setEnabled(
True
)
if
exit_code
=
=
0
:
self
.log(f
'下载完成!文件保存为:{self.filename_input.text()}'
)
else
:
self
.log(f
'下载失败,错误码:{exit_code}'
)
def
log(
self
, message, error
=
False
):
color
=
'red'
if
error
else
'black'
self
.log_text.append(f
'<span style="color:{color}">{message}</span>'
)
if
__name__
=
=
'__main__'
:
app
=
QApplication(sys.argv)
window
=
M3U8Downloader()
screen_resolution
=
app.desktop().screenGeometry()
window_resolution
=
window.geometry()
left
=
(screen_resolution.width()
-
window_resolution.width())
/
2
top
=
(screen_resolution.height()
-
window_resolution.height())
/
2
window.move(
int
(left),
int
(top))
window.show()
sys.exit(app.exec_())