mirror of
https://github.com/OPSnet/Gazelle.git
synced 2026-01-16 18:04:34 -05:00
Add user_torrents ajax endpoint
This commit is contained in:
@@ -80,6 +80,32 @@ abstract class ArtistRole extends Base {
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the id of the first artist that would be shown in the renderRole
|
||||
* display. If it would be shown as "various ...", then it's the first
|
||||
* artist of that role type.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function primaryId(): int|null {
|
||||
$roleList = $this->roleList();
|
||||
$composerCount = count($roleList['composer'] ?? []);
|
||||
$conductorCount = count($roleList['conductor'] ?? []);
|
||||
$djCount = count($roleList['dj'] ?? []);
|
||||
$mainCount = count($roleList['main'] ?? []);
|
||||
|
||||
if ($djCount) {
|
||||
return $roleList['dj'][0]['id'];
|
||||
} elseif ($composerCount) {
|
||||
return $roleList['composer'][0]['id'];
|
||||
} elseif ($mainCount) {
|
||||
return $roleList['main'][0]['id'];
|
||||
} elseif ($conductorCount) {
|
||||
return $roleList['conductor'][0]['id'];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function renderRole(int $mode): string {
|
||||
$roleList = $this->roleList();
|
||||
$arrangerCount = count($roleList['arranger'] ?? []);
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
namespace Gazelle\Enum;
|
||||
|
||||
enum UserTorrentSearch: string {
|
||||
case seeding = 'seeding';
|
||||
case snatched = 'snatched';
|
||||
case uploaded = 'uploaded';
|
||||
case downloaded = 'downloaded';
|
||||
case leeching = 'leeching';
|
||||
case seeding = 'seeding';
|
||||
case snatched = 'snatched';
|
||||
case snatchedUnseeded = 'snatched-unseeded';
|
||||
case uploaded = 'uploaded';
|
||||
case uploadedUnseeded = 'uploaded-unseeded';
|
||||
}
|
||||
|
||||
91
app/Json/UserTorrents.php
Normal file
91
app/Json/UserTorrents.php
Normal file
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
namespace Gazelle\Json;
|
||||
|
||||
use Gazelle\Search\UserTorrent;
|
||||
use Gazelle\Enum\UserTorrentSearch;
|
||||
|
||||
class UserTorrents extends \Gazelle\Json {
|
||||
protected int $limit = 500;
|
||||
protected int $offset = 0;
|
||||
protected string $type = 'seeding';
|
||||
|
||||
public function __construct(
|
||||
protected \Gazelle\User $user,
|
||||
protected \Gazelle\User $viewer,
|
||||
protected \Gazelle\Manager\Torrent $torMan = new \Gazelle\Manager\Torrent(),
|
||||
) {}
|
||||
|
||||
public function setType(string $type): static {
|
||||
$this->type = $type;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setLimit(int $limit): static {
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOffset(int $offset): static {
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function payload(): array {
|
||||
switch ($this->type) {
|
||||
case 'downloaded':
|
||||
$userTorrent = new UserTorrent($this->user, UserTorrentSearch::downloaded);
|
||||
break;
|
||||
case 'leeching':
|
||||
$userTorrent = new UserTorrent($this->user, UserTorrentSearch::leeching);
|
||||
break;
|
||||
case 'seeding':
|
||||
$userTorrent = new UserTorrent($this->user, UserTorrentSearch::seeding);
|
||||
break;
|
||||
case 'snatched':
|
||||
$userTorrent = new UserTorrent($this->user, UserTorrentSearch::snatched);
|
||||
break;
|
||||
case 'snatched-unseeded':
|
||||
$userTorrent = new UserTorrent($this->user, UserTorrentSearch::snatchedUnseeded);
|
||||
break;
|
||||
case 'uploaded':
|
||||
$userTorrent = new UserTorrent($this->user, UserTorrentSearch::uploaded);
|
||||
break;
|
||||
case 'uploaded-unseeded':
|
||||
$userTorrent = new UserTorrent($this->user, UserTorrentSearch::uploadedUnseeded);
|
||||
break;
|
||||
default:
|
||||
json_error("bad type");
|
||||
}
|
||||
$userTorrent->setLimit($this->limit)->setOffset($this->offset);
|
||||
|
||||
return [
|
||||
"$this->type" => array_reduce(
|
||||
$userTorrent->idList(),
|
||||
function ($acc, $id) {
|
||||
$torrent = $this->torMan->findById($id);
|
||||
if ($torrent) {
|
||||
$item = [
|
||||
'groupId' => $torrent->groupId(),
|
||||
'torrentId' => $torrent->id(),
|
||||
'name' => $torrent->group()->name(),
|
||||
'torrentSize' => $torrent->size(),
|
||||
];
|
||||
|
||||
if ($torrent->group()->hasArtistRole()) {
|
||||
// artistId and artistName are returned mostly for compatibility with RED
|
||||
// as people should probably just use `artists` array principally.
|
||||
$item['artistId'] = $torrent->group()->artistRole()?->primaryId();
|
||||
$item['artistName'] = $torrent->group()->artistName();
|
||||
$item['artists'] = static::artistPayload($torrent->group());
|
||||
}
|
||||
$acc[] = $item;
|
||||
}
|
||||
return $acc;
|
||||
},
|
||||
[],
|
||||
),
|
||||
'total' => $userTorrent->total(),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,9 @@ use Gazelle\Enum\UserTorrentSearch;
|
||||
*/
|
||||
|
||||
class UserTorrent extends \Gazelle\Base {
|
||||
private int $limit;
|
||||
private int $offset;
|
||||
|
||||
public function __construct(
|
||||
protected \Gazelle\User $user,
|
||||
protected UserTorrentSearch $type,
|
||||
@@ -20,22 +23,74 @@ class UserTorrent extends \Gazelle\Base {
|
||||
return $this->type->value;
|
||||
}
|
||||
|
||||
public function idList(): array {
|
||||
self::$db->prepared_query("
|
||||
SELECT DISTINCT t.ID
|
||||
FROM torrents AS t "
|
||||
public function setLimit(int $limit): static {
|
||||
$this->limit = $limit;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setOffset(int $offset): static {
|
||||
$this->offset = $offset;
|
||||
return $this;
|
||||
}
|
||||
|
||||
protected function sql(): string {
|
||||
return "FROM torrents AS t "
|
||||
. match ($this->type) {
|
||||
UserTorrentSearch::downloaded => "
|
||||
INNER JOIN users_downloads AS ud ON (ud.TorrentID = t.ID)
|
||||
WHERE ud.UserID = ?
|
||||
ORDER BY ud.Time DESC",
|
||||
UserTorrentSearch::leeching => "
|
||||
INNER JOIN xbt_files_users AS xfu ON (xfu.fid = t.ID)
|
||||
WHERE xfu.active = 1 AND xfu.Remaining > 0 AND xfu.uid = ?
|
||||
ORDER BY from_unixtime(xfu.mtime - xfu.timespent) DESC",
|
||||
UserTorrentSearch::seeding => "
|
||||
INNER JOIN xbt_files_users AS xfu ON (t.ID = xfu.fid)
|
||||
WHERE xfu.remaining = 0
|
||||
AND xfu.uid = ?",
|
||||
WHERE xfu.remaining = 0 AND xfu.uid = ?
|
||||
ORDER BY from_unixtime(xfu.mtime - xfu.timespent) DESC",
|
||||
UserTorrentSearch::snatched => "
|
||||
INNER JOIN xbt_snatched AS x ON (t.ID = x.fid)
|
||||
WHERE x.uid = ?",
|
||||
default =>
|
||||
"WHERE t.UserID = ?",
|
||||
}, $this->user->id
|
||||
);
|
||||
INNER JOIN xbt_snatched AS xs ON (t.ID = xs.fid)
|
||||
WHERE xs.uid = ?
|
||||
ORDER BY from_unixtime(xs.tstamp) DESC",
|
||||
UserTorrentSearch::snatchedUnseeded => "
|
||||
INNER JOIN xbt_snatched AS xs ON (xs.fid = t.ID)
|
||||
LEFT JOIN xbt_files_users AS xfu USING (uid, fid)
|
||||
WHERE xfu.fid IS NULL AND xs.uid = ?
|
||||
ORDER BY from_unixtime(xs.tstamp) DESC",
|
||||
UserTorrentSearch::uploadedUnseeded => "
|
||||
LEFT JOIN xbt_files_users AS xfu ON (xfu.fid = t.ID AND xfu.uid = t.UserID)
|
||||
WHERE xfu.fid IS NULL AND t.UserID = ?
|
||||
ORDER BY t.created DESC",
|
||||
// UserTorrentSearch::uploaded
|
||||
default => "
|
||||
WHERE t.UserID = ?
|
||||
ORDER BY t.created DESC",
|
||||
};
|
||||
}
|
||||
|
||||
public function total(): int {
|
||||
return (int)self::$db->scalar("
|
||||
SELECT COUNT(DISTINCT t.ID)
|
||||
{$this->sql()}
|
||||
", $this->user->id);
|
||||
}
|
||||
|
||||
public function idList(): array {
|
||||
$sql = "
|
||||
SELECT DISTINCT t.ID
|
||||
{$this->sql()}";
|
||||
|
||||
$args = [$this->user->id];
|
||||
if (isset($this->limit)) {
|
||||
$sql .= "\nLIMIT ?";
|
||||
$args[] = $this->limit;
|
||||
}
|
||||
if (isset($this->offset)) {
|
||||
$sql .= "\nOFFSET ?";
|
||||
$args[] = $this->offset;
|
||||
}
|
||||
|
||||
self::$db->prepared_query($sql, ...$args);
|
||||
return self::$db->collect(0);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ exists for the sake of interoperability and may go away in the future.
|
||||
* [Upload](#upload)
|
||||
* [Download](#download)
|
||||
* [Add Log](#add-log)
|
||||
* [User Torrents](#user-torrents)
|
||||
* [Better](#better)
|
||||
* [Logchecker](#logchecker)
|
||||
* [Requests](#requests)
|
||||
@@ -1538,6 +1539,63 @@ __Note__: Must be the uploader of the torrent or moderator to add logs
|
||||
}
|
||||
```
|
||||
|
||||
### User Torrents
|
||||
|
||||
**URL:**
|
||||
`ajax.php?action=user_torrents&userid=<User ID>&type=<Type>`
|
||||
|
||||
__Note__: Must be the uploader of the torrent or moderator to add logs
|
||||
|
||||
**GET Arguments:**
|
||||
|
||||
`userid` - The user id to get torrents for (can also use `id`)
|
||||
`type` - Type of torrents to display (options are `downloaded`, `leeching`, `seeding`, `snatched`, `snatched-unseeded`, `uploaded`, `uploaded-unseeded`)
|
||||
`limit` - (Optional) Number of results to display (default: 500)
|
||||
`offset` - (Optional) Number of results to offset by (default: 0)
|
||||
`page` - (Optional) Page of results to show (default: 1)
|
||||
|
||||
__NOTE__: You can only provide one of `offset` or `page`. Offset is a number of
|
||||
rows to skip before starting to collect the result set, while page is the page
|
||||
number of results to retrieve, where `(page - 1) * limit == offset`.
|
||||
|
||||
**Response format:**
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "success",
|
||||
"response": {
|
||||
"uploaded": [
|
||||
{
|
||||
"groupId": 1,
|
||||
"torrentId": 1,
|
||||
"name": "Foo",
|
||||
"torrentSize": 12345,
|
||||
"artistId": 1,
|
||||
"artistName": "Bar",
|
||||
"artists": {
|
||||
"artists": [
|
||||
{
|
||||
"id": 1,
|
||||
"aliasid": 1,
|
||||
"name": "Bar",
|
||||
}
|
||||
]
|
||||
},
|
||||
},
|
||||
],
|
||||
"total": 1
|
||||
},
|
||||
"info": {
|
||||
"source": "Gazelle Dev",
|
||||
"version": 1
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
__NOTE__: For a torrent that has many main artists, `artistName` will be
|
||||
"Various ..." and the `artistId` will be the ID of the first main artist. It is
|
||||
recommended to use the `artists` field to get artist information.
|
||||
|
||||
## Better
|
||||
|
||||
**URL:**
|
||||
|
||||
@@ -257,6 +257,9 @@ switch ($Action) {
|
||||
case 'add_log':
|
||||
include_once __DIR__ . '/add_log.php';
|
||||
break;
|
||||
case 'user_torrents':
|
||||
include_once __DIR__ . '/user_torrents.php';
|
||||
break;
|
||||
default:
|
||||
// If they're screwing around with the query string
|
||||
json_error("failure");
|
||||
|
||||
48
sections/ajax/user_torrents.php
Normal file
48
sections/ajax/user_torrents.php
Normal file
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
/** @phpstan-var \Gazelle\User $Viewer */
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Gazelle;
|
||||
|
||||
if (!isset($_GET['type']) || !in_array($_GET['type'], ['snatched', 'snatched-unseeded', 'seeding', 'leeching', 'uploaded', 'uploaded-unseeded', 'downloaded'])) {
|
||||
json_error("bad type");
|
||||
}
|
||||
$type = (string)$_GET['type'];
|
||||
|
||||
foreach (['limit', 'offset', 'page'] as $key) {
|
||||
if (isset($_GET[$key]) && !ctype_digit($_GET[$key])) {
|
||||
json_error("non-numeric value for {$key}");
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($_GET['offset']) && isset($_GET['page'])) {
|
||||
json_error('can only use one of offset or page');
|
||||
}
|
||||
if (isset($_GET['offset']) && (int)$_GET['offset'] < 0) {
|
||||
json_error('invalid offset parameter, must be 0 or greater');
|
||||
}
|
||||
if (isset($_GET['page']) && (int)$_GET['page'] < 1) {
|
||||
json_error('invalid page parameter, must be 1 or greater');
|
||||
}
|
||||
|
||||
$limit = (int)($_GET['limit'] ?? 500);
|
||||
$offset = isset($_GET['page']) ? (int)($_GET['page'] - 1) * $limit : (int)($_GET['offset'] ?? 0);
|
||||
if ($limit < 1) {
|
||||
json_error('invalid limit parameter, must be 1 or greater');
|
||||
}
|
||||
|
||||
// We accept id to match RED, but userid is the better param name and matches user_recents
|
||||
$user = new Manager\User()->findById((int)($_GET['userid'] ?? $_GET['id'] ?? 0));
|
||||
if (is_null($user)) {
|
||||
json_error("bad userid");
|
||||
}
|
||||
if (!$user->propertyVisible($Viewer, str_replace('-unseeded', '', $type))) {
|
||||
json_error('user has hidden this');
|
||||
}
|
||||
|
||||
echo new Json\UserTorrents($user, $Viewer)
|
||||
->setType($type)
|
||||
->setLimit($limit)
|
||||
->setOffset($offset)
|
||||
->response();
|
||||
Reference in New Issue
Block a user