diff --git a/app/Stats/User.php b/app/Stats/User.php index 4bb45ad4b..0bde26f4f 100644 --- a/app/Stats/User.php +++ b/app/Stats/User.php @@ -62,6 +62,17 @@ class User extends \Gazelle\BaseObject { return $this->commentTotal[$page] ?? 0; } + public function historyUseragentTracker(): array { + $result = $this->pg()->executeParams(' + select useragent, total + from history_useragent_tracker + where id_user = $1 + order by useragent + ', $this->id + ); + return $result->fetchAll(\PGSQL_ASSOC); + } + /** * @see \Gazelle\Stats\Users::refresh() */ diff --git a/app/Stats/Users.php b/app/Stats/Users.php index 853013210..e4fc7899c 100644 --- a/app/Stats/Users.php +++ b/app/Stats/Users.php @@ -678,6 +678,30 @@ class Users extends \Gazelle\Base { return $processed; } + public function refreshUseragentTracker(): int { + // NB: useragents may be null if the initial announce from ocelot + // was lost, e.g. because of a deadlock or queue overflow. + $result = $this->pg()->execute(" + merge into history_useragent_tracker hut using ( + select xfu.uid as id_user, + coalesce(xfu.useragent, '') as useragent, + count(*) as total + from relay.xbt_files_users xfu + group by xfu.uid, xfu.useragent + ) as i on hut.id_user = i.id_user + and hut.useragent = i.useragent + when not matched and i.total > 0 then + insert ( id_user, useragent, total) + values (i.id_user, i.useragent, i.total) + when matched and i.total > 0 then + update set + total = i.total + when matched then + delete + "); + return $result->getAffectedRows(); + } + public function registerActivity(string $tableName, int $days): int { if ($days > 0) { self::$db->prepared_query(" diff --git a/app/Task/CommunityStats.php b/app/Task/CommunityStats.php index 567b1999f..08ea18c98 100644 --- a/app/Task/CommunityStats.php +++ b/app/Task/CommunityStats.php @@ -2,9 +2,14 @@ namespace Gazelle\Task; +use Gazelle\Stats\Users as UsersStats; +use Gazelle\Stats\TGroups as TGroupsStats; + class CommunityStats extends \Gazelle\Task { public function run(): void { - $this->processed = new \Gazelle\Stats\Users()->refresh() - + new \Gazelle\Stats\TGroups()->refresh(); + $usersStats = new UsersStats(); + $this->processed = new TGroupsStats()->refresh() + + $usersStats->refresh() + + $usersStats->refreshUseragentTracker(); } } diff --git a/app/User.php b/app/User.php index 8b7adb9df..26ace20e3 100644 --- a/app/User.php +++ b/app/User.php @@ -1389,14 +1389,6 @@ class User extends BaseAttrObject { return $new; } - public function clients(): array { - self::$db->prepared_query(' - SELECT DISTINCT useragent FROM xbt_files_users WHERE uid = ? - ', $this->id - ); - return self::$db->collect(0) ?: ['None']; - } - protected function getSingleValue($cacheKey, $query): string { $cacheKey .= '_' . $this->id; if ($this->forceCacheFlush || ($value = self::$cache->get_value($cacheKey)) === false) { diff --git a/misc/pg-migrations/20250901000000_torrent_client_useragent.php b/misc/pg-migrations/20250901000000_torrent_client_useragent.php new file mode 100644 index 000000000..35ccb9c51 --- /dev/null +++ b/misc/pg-migrations/20250901000000_torrent_client_useragent.php @@ -0,0 +1,23 @@ +table('history_useragent_tracker', ['id' => false, 'primary_key' => 'id_history_useragent_tracker']) + ->addColumn('id_history_useragent_tracker', 'integer', ['identity' => true]) + ->addColumn('id_user', 'integer') + ->addColumn('total', 'integer') + ->addColumn('useragent', 'string', ['length' => 100]) + ->save(); + $this->execute(" + create index hut_u_idx on history_useragent_tracker (id_user) + "); + } + + public function down(): void { + $this->table('history_useragent_tracker')->drop()->save(); + } +} diff --git a/templates/user/header.twig b/templates/user/header.twig index e409507e5..ad97818de 100644 --- a/templates/user/header.twig +++ b/templates/user/header.twig @@ -123,7 +123,14 @@ Last seen: {{ user.lastAccessRealtime }} Up: {{ user.uploadedSize|octet_size(3) }} Down: {{ user.downloadedSize|octet_size(3) }} Ratio: {{ ratio(user.uploadedSize, user.downloadedSize) }} (required {{ user.requiredRatio|number_format(2) }}) -Torrent clients: {{ user.clients|join('; ') }} +Torrent clients: +{% for u in user.stats.historyUseragentTracker %} +{{ u.useragent }} ({{ u.total }}) +{% else %} +None +{% endfor %} + + {% endif %}