mirror of
https://gitee.com/spark-store-project/spark-store
synced 2025-12-20 11:11:36 +08:00
chore:下载metalink
This commit is contained in:
0
CMakeLists.txt
Normal file
0
CMakeLists.txt
Normal file
@@ -9,8 +9,8 @@ set(CMAKE_AUTORCC ON)
|
|||||||
set(CMAKE_CXX_STANDARD 17)
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets)
|
find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network)
|
||||||
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets)
|
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network)
|
||||||
|
|
||||||
set(PROJECT_SOURCES
|
set(PROJECT_SOURCES
|
||||||
main.cpp
|
main.cpp
|
||||||
@@ -47,7 +47,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
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.
|
# 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
|
# If you are developing for iOS or macOS you should consider setting an
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
#include <QProgressBar>
|
#include <QProgressBar>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QApplication> // 包含 QApplication 头文件
|
#include <QApplication> // 包含 QApplication 头文件
|
||||||
|
#include <QDir> // 添加 QDir 头文件
|
||||||
|
|
||||||
AppDelegate::AppDelegate(QObject *parent) : QStyledItemDelegate(parent), m_downloadManager(new DownloadManager(this))
|
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);
|
QRect cancelButtonRect(rect.right() - 70, rect.top() + (rect.height() - 20) / 2, 60, 20);
|
||||||
if (cancelButtonRect.contains(mouseEvent->pos())) {
|
if (cancelButtonRect.contains(mouseEvent->pos())) {
|
||||||
// 修正方法调用,假设 DownloadManager 有 killProcess 方法
|
// 修正方法调用,假设 DownloadManager 有 cancelDownload 方法
|
||||||
if (m_downloadManager->isRunning()) {
|
m_downloadManager->cancelDownload();
|
||||||
m_downloadManager->killProcess();
|
m_isDownloading = false;
|
||||||
m_isDownloading = false;
|
emit updateDisplay(); // 触发重绘
|
||||||
emit updateDisplay(); // 触发重绘
|
|
||||||
}
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 更新按钮区域
|
// 更新按钮区域
|
||||||
QRect buttonRect(rect.right() - 80, rect.top() + (rect.height() - 30) / 2, 70, 30);
|
QRect buttonRect(rect.right() - 80, rect.top() + (rect.height() - 30) / 2, 70, 30);
|
||||||
if (buttonRect.contains(mouseEvent->pos())) {
|
if (buttonRect.contains(mouseEvent->pos())) {
|
||||||
// 修改这里:使用Qt::UserRole +1获取包名
|
|
||||||
QString packageName = index.data(Qt::UserRole + 1).toString();
|
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_isDownloading = true;
|
||||||
m_progress = 0;
|
m_progress = 0;
|
||||||
m_downloadManager->startDownload(packageName);
|
m_downloadManager->startDownload(downloadUrl, outputPath);
|
||||||
emit updateDisplay(); // 触发重绘
|
emit updateDisplay(); // 触发重绘
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,29 +14,49 @@ QVariant AppListModel::data(const QModelIndex &index, int role) const
|
|||||||
if (!index.isValid() || index.row() >= m_data.size())
|
if (!index.isValid() || index.row() >= m_data.size())
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const QJsonObject obj = m_data.at(index.row()).toObject();
|
const QVariantMap &map = m_data.at(index.row()); // 直接访问 QVariantMap
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
return obj["name"].toString();
|
return map.value("name");
|
||||||
case Qt::UserRole + 1: // 包名
|
case Qt::UserRole + 1: // 包名
|
||||||
return obj["package"].toString();
|
return map.value("package");
|
||||||
case Qt::UserRole + 2: // 当前版本
|
case Qt::UserRole + 2: // 当前版本
|
||||||
return obj["current_version"].toString();
|
return map.value("current_version");
|
||||||
case Qt::UserRole + 3: // 新版本
|
case Qt::UserRole + 3: // 新版本
|
||||||
return obj["new_version"].toString();
|
return map.value("new_version");
|
||||||
case Qt::UserRole + 4: // 图标路径
|
case Qt::UserRole + 4: // 图标路径
|
||||||
return obj["icon"].toString();
|
return map.value("icon");
|
||||||
case Qt::UserRole + 5: // 文件大小
|
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:
|
default:
|
||||||
return QVariant();
|
return QVariant();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AppListModel::setUpdateData(const QJsonArray &data)
|
void AppListModel::setUpdateData(const QJsonArray &updateInfo)
|
||||||
{
|
{
|
||||||
beginResetModel();
|
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();
|
endResetModel();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ public:
|
|||||||
void setUpdateData(const QJsonArray &data);
|
void setUpdateData(const QJsonArray &data);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QJsonArray m_data;
|
QList<QVariantMap> m_data; // 修改类型为 QList<QVariantMap>
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // APPLISTMODEL_H
|
#endif // APPLISTMODEL_H
|
||||||
|
|||||||
@@ -381,9 +381,14 @@ QJsonArray aptssUpdater::getUpdateInfoAsJson()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 在构建JSON对象时添加新字段(在jsonObj中添加):
|
// 在构建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"];
|
jsonObj["sha512"] = packageInfo[packageName]["sha512"];
|
||||||
|
|
||||||
jsonArray.append(jsonObj);
|
jsonArray.append(jsonObj);
|
||||||
}
|
}
|
||||||
qDebug()<<jsonArray;
|
qDebug()<<jsonArray;
|
||||||
|
|||||||
@@ -1,80 +1,68 @@
|
|||||||
#include "downloadmanager.h"
|
#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+)%\))");
|
qDebug() << "接收到的下载 URL:" << url; // 检查 URL 是否正确传递
|
||||||
connect(m_process, &QProcess::readyReadStandardOutput, this, &DownloadManager::onProcessReadyRead);
|
|
||||||
connect(m_process, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), this, &DownloadManager::onProcessFinished);
|
// 验证 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) {
|
if (bytesTotal > 0) {
|
||||||
m_process->kill();
|
int progress = static_cast<int>((bytesReceived * 100) / bytesTotal);
|
||||||
// 原代码
|
emit downloadProgress(progress);
|
||||||
// m_process->waitForFinished();
|
|
||||||
|
|
||||||
// 修改后增加超时处理
|
|
||||||
if (!m_process->waitForFinished(5000)) {
|
|
||||||
qWarning() << "进程终止超时";
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DownloadManager::startDownload(const QString &appName)
|
void DownloadManager::onDownloadFinished()
|
||||||
{
|
{
|
||||||
// 输出开始下载的日志
|
if (m_reply->error() == QNetworkReply::NoError) {
|
||||||
QString program = "aptss";
|
QString outputPath = m_reply->property("outputPath").toString();
|
||||||
QStringList arguments;
|
QFile file(outputPath);
|
||||||
arguments << "download" << "--print-uris" << appName;
|
if (file.open(QIODevice::WriteOnly)) {
|
||||||
|
file.write(m_reply->readAll());
|
||||||
qDebug() << "执行命令:" << program << arguments.join(" ");
|
file.close();
|
||||||
m_process->start(program, arguments);
|
qDebug() << "文件已保存到路径:" << outputPath; // 输出保存路径
|
||||||
}
|
emit downloadFinished(true);
|
||||||
|
|
||||||
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);
|
|
||||||
} else {
|
} else {
|
||||||
// qDebug() << "未匹配行:" << line;
|
qWarning() << "无法保存文件到路径:" << outputPath;
|
||||||
|
emit downloadFinished(false);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// 如果最后不是完整的一行,保留最后一部分
|
|
||||||
if (!buffer.endsWith('\n') && !buffer.endsWith('\r')) {
|
|
||||||
buffer = lines.last();
|
|
||||||
} else {
|
} else {
|
||||||
buffer.clear();
|
qWarning() << "下载失败:" << m_reply->errorString();
|
||||||
}
|
emit downloadFinished(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_reply->deleteLater();
|
||||||
void DownloadManager::onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
m_reply = nullptr;
|
||||||
{
|
}
|
||||||
bool success = (exitStatus == QProcess::NormalExit && exitCode == 0);
|
|
||||||
emit downloadFinished(success);
|
void DownloadManager::cancelDownload()
|
||||||
}
|
{
|
||||||
|
if (m_reply) {
|
||||||
bool DownloadManager::isRunning() const
|
m_reply->abort(); // 取消当前下载
|
||||||
{
|
m_reply->deleteLater();
|
||||||
return m_process->state() == QProcess::Running;
|
m_reply = nullptr;
|
||||||
}
|
emit downloadFinished(false); // 发送下载失败信号
|
||||||
|
|
||||||
void DownloadManager::killProcess()
|
|
||||||
{
|
|
||||||
if (m_process->state() == QProcess::Running) {
|
|
||||||
m_process->kill();
|
|
||||||
m_process->waitForFinished();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,30 +2,28 @@
|
|||||||
#define DOWNLOADMANAGER_H
|
#define DOWNLOADMANAGER_H
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QProcess>
|
#include <QNetworkAccessManager>
|
||||||
#include <QRegularExpression>
|
#include <QNetworkReply>
|
||||||
|
|
||||||
class DownloadManager : public QObject
|
class DownloadManager : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DownloadManager(QObject *parent = nullptr);
|
explicit DownloadManager(QObject *parent = nullptr);
|
||||||
~DownloadManager();
|
void startDownload(const QString &url, const QString &outputPath);
|
||||||
|
void cancelDownload(); // 添加取消下载的方法
|
||||||
void startDownload(const QString &appName);
|
|
||||||
bool isRunning() const; // 声明 isRunning 方法
|
|
||||||
void killProcess(); // 声明 killProcess 方法
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void downloadProgress(int progress);
|
void downloadProgress(int progress); // 下载进度信号
|
||||||
void downloadFinished(bool success);
|
void downloadFinished(bool success); // 下载完成信号
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onProcessReadyRead();
|
void onDownloadProgress(qint64 bytesReceived, qint64 bytesTotal);
|
||||||
void onProcessFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
void onDownloadFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QProcess *m_process;
|
QNetworkAccessManager m_networkManager;
|
||||||
QRegularExpression m_progressRegex;
|
QNetworkReply *m_reply = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DOWNLOADMANAGER_H
|
#endif // DOWNLOADMANAGER_H
|
||||||
|
|||||||
@@ -152,6 +152,11 @@ void MainWindow::checkUpdates()
|
|||||||
QJsonArray updateInfo = updater.getUpdateInfoAsJson();
|
QJsonArray updateInfo = updater.getUpdateInfoAsJson();
|
||||||
m_model->setUpdateData(updateInfo);
|
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()
|
MainWindow::~MainWindow()
|
||||||
|
|||||||
Reference in New Issue
Block a user