-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathDownloadDialog.cpp
More file actions
174 lines (142 loc) · 5.16 KB
/
Copy pathDownloadDialog.cpp
File metadata and controls
174 lines (142 loc) · 5.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include "DownloadDialog.h"
#include <QFileInfo>
#include <QRegularExpression>
#include <QDebug>
DownloadDialog::DownloadDialog(QWidget* parent)
: QDialog(parent)
{
setWindowTitle("Download YouTube Video");
setModal(true); // block main window
setMinimumWidth(420);
m_titleLabel = new QLabel("Preparing download…");
m_statusLabel = new QLabel("Getting file name…");
m_progress = new QProgressBar;
m_progress->setRange(0, 0); // indetermined before downloading
m_cancelBtn = new QPushButton("Cancel");
connect(m_cancelBtn, &QPushButton::clicked, this, &DownloadDialog::onCancel);
auto* btnRow = new QHBoxLayout;
btnRow->addStretch();
btnRow->addWidget(m_cancelBtn);
auto* lay = new QVBoxLayout;
lay->addWidget(m_titleLabel);
lay->addWidget(m_statusLabel);
lay->addWidget(m_progress);
lay->addLayout(btnRow);
setLayout(lay);
}
void DownloadDialog::start(const QString& url, const QString& directory) {
m_url = url;
m_directory = directory;
startFilenameProbe();
}
void DownloadDialog::startFilenameProbe() {
if (m_filenameProc) {
m_filenameProc->deleteLater();
m_filenameProc = nullptr;
}
m_filenameProc = new QProcess(this);
// titled temmplate: resolved by yt-dlp
const QString outputTemplate = m_directory + "/%(title)s.%(ext)s";
QStringList args;
args << "--print" << "filename"
<< "--output" << outputTemplate
<< "--no-playlist" // força single video
<< m_url;
connect(m_filenameProc, &QProcess::readyReadStandardOutput,
this, &DownloadDialog::onFilenameStdOut);
connect(m_filenameProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &DownloadDialog::onFilenameFinished);
m_filenameProc->start("yt-dlp", args);
}
void DownloadDialog::onFilenameStdOut() {
const QString output = QString::fromUtf8(m_filenameProc->readAllStandardOutput()).trimmed();
if (output.isEmpty()) return;
QFileInfo fi(output);
QString baseName = fi.completeBaseName();
const QString ext = fi.suffix();
// sanitize only the baseName
QRegularExpression regex("[^a-zA-Z0-9_\\-\\.\\ ]");
baseName.replace(regex, "_");
m_predictedPath = m_directory + "/" + baseName + "." + ext;
qDebug() << "Predicted filename:" << m_predictedPath;
m_statusLabel->setText("File: " + baseName + "." + ext);
}
void DownloadDialog::onFilenameFinished(int exitCode, QProcess::ExitStatus status) {
Q_UNUSED(status);
m_filenameProc->deleteLater();
m_filenameProc = nullptr;
if (exitCode != 0 || m_predictedPath.isEmpty()) {
m_statusLabel->setText("Failed to get filename.");
emit downloadFailed("Failed to get filename.");
reject();
return;
}
// progress bar now determined
m_progress->setRange(0, 100);
m_progress->setValue(0);
m_titleLabel->setText("Downloading…");
m_statusLabel->setText("Starting download…");
startDownload();
}
void DownloadDialog::startDownload() {
if (m_downloadProc) {
m_downloadProc->deleteLater();
m_downloadProc = nullptr;
}
m_downloadProc = new QProcess(this);
QStringList args;
args << "--output" << m_predictedPath
<< "--no-playlist" // garante single video mesmo que link tenha params
<< "--newline" // progresso linha a linha no stderr
<< m_url;
connect(m_downloadProc, &QProcess::readyRead,
this, &DownloadDialog::onDownloadStdErr);
connect(m_downloadProc, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
this, &DownloadDialog::onDownloadFinished);
m_downloadProc->setProcessChannelMode(QProcess::MergedChannels); // unify stdout/stderr
m_downloadProc->start("yt-dlp", args);
}
void DownloadDialog::onDownloadStdErr() {
const QString chunk =
QString::fromUtf8(m_downloadProc->readAll());
// yt-dlp usa \r para reescrever a linha
static QRegularExpression re(R"((\d{1,3}(?:\.\d+)?)%)");
QRegularExpressionMatchIterator it = re.globalMatch(chunk);
double lastPercent = -1.0;
while (it.hasNext()) {
auto m = it.next();
lastPercent = m.captured(1).toDouble();
}
if (lastPercent >= 0.0) {
m_progress->setValue(static_cast<int>(lastPercent + 0.5));
m_statusLabel->setText(
QString("Downloading… %1%").arg(lastPercent, 0, 'f', 1)
);
}
}
void DownloadDialog::onDownloadFinished(int exitCode, QProcess::ExitStatus status) {
Q_UNUSED(status);
m_downloadProc->deleteLater();
m_downloadProc = nullptr;
if (exitCode == 0) {
m_progress->setValue(100);
m_statusLabel->setText("Download complete.");
m_downloadedPath = m_predictedPath;
emit downloadSucceeded(m_downloadedPath);
accept();
} else {
m_statusLabel->setText("Download failed.");
emit downloadFailed("Download failed.");
reject();
}
}
void DownloadDialog::onCancel() {
if (m_filenameProc) {
m_filenameProc->kill();
}
if (m_downloadProc) {
m_downloadProc->kill();
}
m_statusLabel->setText("Canceled by user.");
reject();
}