chore:下载metalink

This commit is contained in:
momen 2025-06-11 23:08:35 +08:00
parent c0e670f6c1
commit a2aadf44e3
9 changed files with 129 additions and 103 deletions

0
CMakeLists.txt Normal file
View File

View File

@ -9,8 +9,8 @@ set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network)
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network)
set(PROJECT_SOURCES
main.cpp
@ -47,7 +47,7 @@ else()
endif()
endif()
target_link_libraries(Spark-Update-Tool PRIVATE Qt${QT_VERSION_MAJOR}::Widgets)
target_link_libraries(Spark-Update-Tool PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${QT_VERSION_MAJOR}::Network)
# Qt for iOS sets MACOSX_BUNDLE_GUI_IDENTIFIER automatically since Qt 6.1.
# If you are developing for iOS or macOS you should consider setting an

View File

@ -5,6 +5,7 @@
#include <QProgressBar>
#include <QPushButton>
#include <QApplication> // 包含 QApplication 头文件
#include <QDir> // 添加 QDir 头文件
AppDelegate::AppDelegate(QObject *parent) : QStyledItemDelegate(parent), m_downloadManager(new DownloadManager(this))
{
@ -128,23 +129,32 @@ bool AppDelegate::editorEvent(QEvent *event, QAbstractItemModel *model, const QS
// 取消按钮区域
QRect cancelButtonRect(rect.right() - 70, rect.top() + (rect.height() - 20) / 2, 60, 20);
if (cancelButtonRect.contains(mouseEvent->pos())) {
// 修正方法调用,假设 DownloadManager 有 killProcess 方法
if (m_downloadManager->isRunning()) {
m_downloadManager->killProcess();
m_isDownloading = false;
emit updateDisplay(); // 触发重绘
}
// 修正方法调用,假设 DownloadManager 有 cancelDownload 方法
m_downloadManager->cancelDownload();
m_isDownloading = false;
emit updateDisplay(); // 触发重绘
return true;
}
} else {
// 更新按钮区域
QRect buttonRect(rect.right() - 80, rect.top() + (rect.height() - 30) / 2, 70, 30);
if (buttonRect.contains(mouseEvent->pos())) {
// 修改这里使用Qt::UserRole +1获取包名
QString packageName = index.data(Qt::UserRole + 1).toString();
QString downloadUrl = index.data(Qt::UserRole + 7).toString();
qDebug() << "从模型中获取的包名:" << packageName;
qDebug() << "从模型中获取的下载 URL:" << downloadUrl; // 检查模型中是否正确传递 URL
if (downloadUrl.isEmpty()) {
qWarning() << "下载 URL 为空,无法开始下载,包名:" << packageName;
return false;
}
QString outputPath = QString("%1/%2.metalink").arg(QDir::tempPath(), packageName);
m_isDownloading = true;
m_progress = 0;
m_downloadManager->startDownload(packageName);
m_downloadManager->startDownload(downloadUrl, outputPath);
emit updateDisplay(); // 触发重绘
return true;
}

View File

@ -14,29 +14,49 @@ QVariant AppListModel::data(const QModelIndex &index, int role) const
if (!index.isValid() || index.row() >= m_data.size())
return QVariant();
const QJsonObject obj = m_data.at(index.row()).toObject();
const QVariantMap &map = m_data.at(index.row()); // 直接访问 QVariantMap
switch (role) {
case Qt::DisplayRole:
return obj["name"].toString();
return map.value("name");
case Qt::UserRole + 1: // 包名
return obj["package"].toString();
return map.value("package");
case Qt::UserRole + 2: // 当前版本
return obj["current_version"].toString();
return map.value("current_version");
case Qt::UserRole + 3: // 新版本
return obj["new_version"].toString();
return map.value("new_version");
case Qt::UserRole + 4: // 图标路径
return obj["icon"].toString();
return map.value("icon");
case Qt::UserRole + 5: // 文件大小
return obj["size"].toVariant();
return map.value("size");
case Qt::UserRole + 6: // 描述
return map.value("description");
case Qt::UserRole + 7: // 下载 URL
return map.value("download_url"); // 返回下载 URL
default:
return QVariant();
}
}
void AppListModel::setUpdateData(const QJsonArray &data)
void AppListModel::setUpdateData(const QJsonArray &updateInfo)
{
beginResetModel();
m_data = data;
m_data.clear(); // 清空 QList<QVariantMap>
for (const auto &item : updateInfo) {
QJsonObject obj = item.toObject();
QVariantMap map;
map["package"] = obj["package"].toString();
map["name"] = obj["name"].toString();
map["current_version"] = obj["current_version"].toString();
map["new_version"] = obj["new_version"].toString();
map["icon"] = obj["icon"].toString();
map["size"] = obj["size"].toString();
map["download_url"] = obj["download_url"].toString(); // 确保设置下载 URL
m_data.append(map); // 添加到 QList<QVariantMap>
qDebug() << "设置到模型的包名:" << map["package"].toString();
qDebug() << "设置到模型的下载 URL:" << map["download_url"].toString(); // 检查设置的数据
}
endResetModel();
}

View File

@ -20,7 +20,7 @@ public:
void setUpdateData(const QJsonArray &data);
private:
QJsonArray m_data;
QList<QVariantMap> m_data; // 修改类型为 QList<QVariantMap>
};
#endif // APPLISTMODEL_H

View File

@ -381,9 +381,14 @@ QJsonArray aptssUpdater::getUpdateInfoAsJson()
}
// 在构建JSON对象时添加新字段在jsonObj中添加
jsonObj["download_url"] = packageInfo[packageName]["url"];
if (packageInfo[packageName].contains("url")) {
jsonObj["download_url"] = packageInfo[packageName]["url"];
qDebug() << "生成的下载 URL:" << packageInfo[packageName]["url"]; // 检查生成的 URL
} else {
qWarning() << "未找到下载 URL包名:" << packageName;
jsonObj["download_url"] = ""; // 设置为空字符串以避免崩溃
}
jsonObj["sha512"] = packageInfo[packageName]["sha512"];
jsonArray.append(jsonObj);
}
qDebug()<<jsonArray;

View File

@ -1,80 +1,68 @@
#include "downloadmanager.h"
#include <QDebug> // 包含 QDebug 头文件
#include <QFile>
#include <QDebug>
DownloadManager::DownloadManager(QObject *parent) : QObject(parent), m_process(new QProcess(this))
DownloadManager::DownloadManager(QObject *parent) : QObject(parent) {}
void DownloadManager::startDownload(const QString &url, const QString &outputPath)
{
m_progressRegex = QRegularExpression(R"(\((\d+)%\))");
connect(m_process, &QProcess::readyReadStandardOutput, this, &DownloadManager::onProcessReadyRead);
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &DownloadManager::onProcessFinished);
qDebug() << "接收到的下载 URL:" << url; // 检查 URL 是否正确传递
// 验证 URL 是否包含协议
QUrl metalinkUrl(url + ".metalink");
if (!metalinkUrl.isValid() || metalinkUrl.scheme().isEmpty()) {
qWarning() << "无效的 URL:" << metalinkUrl.toString();
emit downloadFinished(false);
return;
}
QNetworkRequest request(metalinkUrl);
m_reply = m_networkManager.get(request);
connect(m_reply, &QNetworkReply::downloadProgress, this, &DownloadManager::onDownloadProgress);
connect(m_reply, &QNetworkReply::finished, this, &DownloadManager::onDownloadFinished);
// 保存路径
m_reply->setProperty("outputPath", outputPath);
}
DownloadManager::~DownloadManager()
void DownloadManager::onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal)
{
if (m_process->state() == QProcess::Running) {
m_process->kill();
// 原代码
// m_process->waitForFinished();
// 修改后增加超时处理
if (!m_process->waitForFinished(5000)) {
qWarning() << "进程终止超时";
}
if (bytesTotal > 0) {
int progress = static_cast<int>((bytesReceived * 100) / bytesTotal);
emit downloadProgress(progress);
}
}
void DownloadManager::startDownload(const QString &appName)
void DownloadManager::onDownloadFinished()
{
// 输出开始下载的日志
QString program = "aptss";
QStringList arguments;
arguments << "download" << "--print-uris" << appName;
qDebug() << "执行命令:" << program << arguments.join(" ");
m_process->start(program, arguments);
}
void DownloadManager::onProcessReadyRead()
{
static QString buffer; // 缓存未处理的输出
buffer += QString::fromUtf8(m_process->readAllStandardOutput());
const QStringList lines = buffer.split(QRegularExpression("[\r\n]"), Qt::SkipEmptyParts);
for (const QString &line : lines) {
QRegularExpressionMatch match = m_progressRegex.match(line);
if (match.hasMatch()) {
int progress = match.captured(1).toInt();
qDebug() << "匹配进度:" << progress << "% => " << line;
emit downloadProgress(progress);
if (m_reply->error() == QNetworkReply::NoError) {
QString outputPath = m_reply->property("outputPath").toString();
QFile file(outputPath);
if (file.open(QIODevice::WriteOnly)) {
file.write(m_reply->readAll());
file.close();
qDebug() << "文件已保存到路径:" << outputPath; // 输出保存路径
emit downloadFinished(true);
} else {
// qDebug() << "未匹配行:" << line;
qWarning() << "无法保存文件到路径:" << outputPath;
emit downloadFinished(false);
}
}
// 如果最后不是完整的一行,保留最后一部分
if (!buffer.endsWith('\n') && !buffer.endsWith('\r')) {
buffer = lines.last();
} else {
buffer.clear();
}
}
void DownloadManager::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
{
bool success = (exitStatus == QProcess::NormalExit && exitCode == 0);
emit downloadFinished(success);
}
bool DownloadManager::isRunning() const
{
return m_process->state() == QProcess::Running;
}
void DownloadManager::killProcess()
{
if (m_process->state() == QProcess::Running) {
m_process->kill();
m_process->waitForFinished();
qWarning() << "下载失败:" << m_reply->errorString();
emit downloadFinished(false);
}
m_reply->deleteLater();
m_reply = nullptr;
}
void DownloadManager::cancelDownload()
{
if (m_reply) {
m_reply->abort(); // 取消当前下载
m_reply->deleteLater();
m_reply = nullptr;
emit downloadFinished(false); // 发送下载失败信号
}
}

View File

@ -2,30 +2,28 @@
#define DOWNLOADMANAGER_H
#include <QObject>
#include <QProcess>
#include <QRegularExpression>
#include <QNetworkAccessManager>
#include <QNetworkReply>
class DownloadManager : public QObject
{
Q_OBJECT
public:
explicit DownloadManager(QObject *parent = nullptr);
~DownloadManager();
void startDownload(const QString &appName);
bool isRunning() const; // 声明 isRunning 方法
void killProcess(); // 声明 killProcess 方法
void startDownload(const QString &url, const QString &outputPath);
void cancelDownload(); // 添加取消下载的方法
signals:
void downloadProgress(int progress);
void downloadFinished(bool success);
void downloadProgress(int progress); // 下载进度信号
void downloadFinished(bool success); // 下载完成信号
private slots:
void onProcessReadyRead();
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
void onDownloadFinished();
private:
QProcess *m_process;
QRegularExpression m_progressRegex;
QNetworkAccessManager m_networkManager;
QNetworkReply *m_reply = nullptr;
};
#endif // DOWNLOADMANAGER_H

View File

@ -151,7 +151,12 @@ void MainWindow::checkUpdates()
aptssUpdater updater;
QJsonArray updateInfo = updater.getUpdateInfoAsJson();
m_model->setUpdateData(updateInfo);
for (const auto &item : updateInfo) {
QJsonObject obj = item.toObject();
qDebug() << "模型设置的包名:" << obj["package"].toString();
qDebug() << "模型设置的下载 URL:" << obj["download_url"].toString(); // 检查模型数据
}
}
MainWindow::~MainWindow()