diff --git a/launcher/include/account.h b/launcher/include/account.h index 1ce7b91..851adfc 100644 --- a/launcher/include/account.h +++ b/launcher/include/account.h @@ -74,6 +74,8 @@ public: Q_INVOKABLE QString getPassword(); void setPassword(const QString &password); + void setAvatarUrl(const QString &url); + Q_INVOKABLE QString getOTP(); Q_INVOKABLE void setOTPSecret(const QString &secret); @@ -101,7 +103,6 @@ Q_SIGNALS: bool needsPasswordChanged(); private: - void fetchAvatar(); QCoro::Task<> fetchPassword(); /** diff --git a/launcher/include/accountmanager.h b/launcher/include/accountmanager.h index 1b2c25b..8e374fe 100644 --- a/launcher/include/accountmanager.h +++ b/launcher/include/accountmanager.h @@ -43,6 +43,8 @@ public: Q_SIGNALS: void accountsChanged(); + void accountAdded(Account *account); + void accountLodestoneIdChanged(Account *account); private: void insertAccount(Account *account); diff --git a/launcher/include/launchercore.h b/launcher/include/launchercore.h index d272152..a41ae45 100755 --- a/launcher/include/launchercore.h +++ b/launcher/include/launchercore.h @@ -99,7 +99,10 @@ public: Q_INVOKABLE BenchmarkInstaller *createBenchmarkInstaller(Profile *profile); Q_INVOKABLE BenchmarkInstaller *createBenchmarkInstallerFromExisting(Profile *profile, const QString &filePath); + /// Fetches the avatar for @p account + void fetchAvatar(Account *account); Q_INVOKABLE void clearAvatarCache(); + Q_INVOKABLE void refreshNews(); Q_INVOKABLE void refreshLogoImage(); diff --git a/launcher/src/account.cpp b/launcher/src/account.cpp index e306ce6..159b264 100644 --- a/launcher/src/account.cpp +++ b/launcher/src/account.cpp @@ -21,7 +21,6 @@ Account::Account(LauncherCore &launcher, const QString &key, QObject *parent) , m_key(key) , m_launcher(launcher) { - fetchAvatar(); fetchPassword(); } @@ -68,7 +67,6 @@ void Account::setLodestoneId(const QString &id) if (m_config.lodestoneId() != id) { m_config.setLodestoneId(id); m_config.save(); - fetchAvatar(); Q_EMIT lodestoneIdChanged(); } } @@ -191,6 +189,14 @@ void Account::setPassword(const QString &password) } } +void Account::setAvatarUrl(const QString &url) +{ + if (m_avatarUrl != url) { + m_avatarUrl = url; + Q_EMIT avatarUrlChanged(); + } +} + QString Account::getOTP() { const auto otpSecret = QCoro::waitFor(getKeychainValue(QStringLiteral("otp-secret"))); @@ -227,60 +233,6 @@ QString Account::getConfigPath() const return getConfigDir().absolutePath(); } -void Account::fetchAvatar() -{ - if (lodestoneId().isEmpty()) { - return; - } - - const QString cacheLocation = QStandardPaths::standardLocations(QStandardPaths::CacheLocation)[0] + QStringLiteral("/avatars"); - Utility::createPathIfNeeded(cacheLocation); - - const QString filename = QStringLiteral("%1/%2.jpg").arg(cacheLocation, lodestoneId()); - if (!QFile(filename).exists()) { - qDebug(ASTRA_LOG) << "Did not find lodestone character " << lodestoneId() << " in cache, fetching from Lodestone."; - - QUrl url; - url.setScheme(m_launcher.settings()->preferredProtocol()); - url.setHost(QStringLiteral("na.%1").arg(m_launcher.settings()->mainServer())); // TODO: NA isnt the only thing in the world... - url.setPath(QStringLiteral("/lodestone/character/%1").arg(lodestoneId())); - - const QNetworkRequest request(url); - Utility::printRequest(QStringLiteral("GET"), request); - - const auto reply = m_launcher.mgr()->get(request); - connect(reply, &QNetworkReply::finished, [this, filename, reply] { - const QString document = QString::fromUtf8(reply->readAll()); - if (!document.isEmpty()) { - const static QRegularExpression re( - QStringLiteral(R"lit(]*class=["|']frame__chara__face["|'][^>]*>\s*]*src=["|']([^"']*))lit")); - const QRegularExpressionMatch match = re.match(document); - - if (match.hasCaptured(1)) { - const QString newAvatarUrl = match.captured(1); - - const auto avatarRequest = QNetworkRequest(QUrl(newAvatarUrl)); - Utility::printRequest(QStringLiteral("GET"), avatarRequest); - - auto avatarReply = m_launcher.mgr()->get(avatarRequest); - connect(avatarReply, &QNetworkReply::finished, [this, filename, avatarReply] { - QFile file(filename); - file.open(QIODevice::ReadWrite); - file.write(avatarReply->readAll()); - file.close(); - - m_avatarUrl = QStringLiteral("file:///%1").arg(filename); - Q_EMIT avatarUrlChanged(); - }); - } - } - }); - } else { - m_avatarUrl = QStringLiteral("file:///%1").arg(filename); - Q_EMIT avatarUrlChanged(); - } -} - void Account::setKeychainValue(const QString &key, const QString &value) { if (m_launcher.isSteamDeck()) { diff --git a/launcher/src/accountmanager.cpp b/launcher/src/accountmanager.cpp index ec174cd..aa896a6 100644 --- a/launcher/src/accountmanager.cpp +++ b/launcher/src/accountmanager.cpp @@ -111,10 +111,14 @@ void AccountManager::deleteAccount(Account *account) void AccountManager::insertAccount(Account *account) { + connect(account, &Account::avatarUrlChanged, this, [this, account] { + Q_EMIT accountLodestoneIdChanged(account); + }); beginInsertRows(QModelIndex(), static_cast(m_accounts.size()), static_cast(m_accounts.size())); m_accounts.append(account); endInsertRows(); Q_EMIT accountsChanged(); + Q_EMIT accountAdded(account); } bool AccountManager::hasAnyAccounts() const diff --git a/launcher/src/launchercore.cpp b/launcher/src/launchercore.cpp index d8fed35..cd3d89f 100755 --- a/launcher/src/launchercore.cpp +++ b/launcher/src/launchercore.cpp @@ -40,6 +40,9 @@ LauncherCore::LauncherCore() m_accountManager = new AccountManager(*this, this); m_runner = new GameRunner(*this, this); + connect(m_accountManager, &AccountManager::accountAdded, this, &LauncherCore::fetchAvatar); + connect(m_accountManager, &AccountManager::accountLodestoneIdChanged, this, &LauncherCore::fetchAvatar); + connect(this, &LauncherCore::gameClosed, this, &LauncherCore::handleGameExit); #ifdef BUILD_SYNC @@ -154,6 +157,58 @@ BenchmarkInstaller *LauncherCore::createBenchmarkInstallerFromExisting(Profile * return new BenchmarkInstaller(*this, *profile, filePath, this); } +void LauncherCore::fetchAvatar(Account *account) +{ + if (account->lodestoneId().isEmpty()) { + return; + } + + const QString cacheLocation = QStandardPaths::standardLocations(QStandardPaths::CacheLocation)[0] + QStringLiteral("/avatars"); + Utility::createPathIfNeeded(cacheLocation); + + const QString filename = QStringLiteral("%1/%2.jpg").arg(cacheLocation, account->lodestoneId()); + if (!QFile(filename).exists()) { + qDebug(ASTRA_LOG) << "Did not find lodestone character " << account->lodestoneId() << " in cache, fetching from Lodestone."; + + QUrl url; + url.setScheme(settings()->preferredProtocol()); + url.setHost(QStringLiteral("na.%1").arg(settings()->mainServer())); // TODO: NA isnt the only thing in the world... + url.setPath(QStringLiteral("/lodestone/character/%1").arg(account->lodestoneId())); + + const QNetworkRequest request(url); + Utility::printRequest(QStringLiteral("GET"), request); + + const auto reply = mgr()->get(request); + connect(reply, &QNetworkReply::finished, [this, filename, reply, account] { + const QString document = QString::fromUtf8(reply->readAll()); + if (!document.isEmpty()) { + const static QRegularExpression re( + QStringLiteral(R"lit(]*class=["|']frame__chara__face["|'][^>]*>\s*]*src=["|']([^"']*))lit")); + const QRegularExpressionMatch match = re.match(document); + + if (match.hasCaptured(1)) { + const QString newAvatarUrl = match.captured(1); + + const auto avatarRequest = QNetworkRequest(QUrl(newAvatarUrl)); + Utility::printRequest(QStringLiteral("GET"), avatarRequest); + + auto avatarReply = mgr()->get(avatarRequest); + connect(avatarReply, &QNetworkReply::finished, [this, filename, avatarReply, account] { + QFile file(filename); + file.open(QIODevice::ReadWrite); + file.write(avatarReply->readAll()); + file.close(); + + account->setAvatarUrl(QStringLiteral("file:///%1").arg(filename)); + }); + } + } + }); + } else { + account->setAvatarUrl(QStringLiteral("file:///%1").arg(filename)); + } +} + void LauncherCore::clearAvatarCache() { const QString cacheLocation = QStandardPaths::standardLocations(QStandardPaths::CacheLocation)[0] + QStringLiteral("/avatars");