cleaned up Artist class

also fixed a bug in ajax/artist and a port in docker
This commit is contained in:
webhead
2020-09-29 16:46:53 +00:00
committed by Spine
parent 74e78d07dd
commit d22d701d04
6 changed files with 125 additions and 117 deletions

View File

@@ -2,40 +2,55 @@
namespace Gazelle;
use Requests;
use Torrents;
use OutOfBoundsException;
use UnexpectedValueException;
class Artist extends Base {
protected $id;
protected $revision;
protected $artistRole; // what different roles does an artist have
protected $nrGroups; // number of distinct groups
protected $groupRole; // what role does this artist have in a group
protected $groupList; // the release groups ordered by year and name
protected $sections; // their groups, gathered into sections
protected $id = 0;
protected $revisionId = 0;
protected $artistRole;
protected $nrGroups;
protected $groupRole;
/** Release groups ordered by year and name */
protected $groupList;
/** Their groups, gathered into sections */
protected $sections;
protected $discogsId;
protected $discogsName;
protected $discogsStem;
/** @var string|int */
protected $discogsSequence;
protected $discogsIsPreferred;
protected $homonyms;
protected $name;
protected $name = '';
protected $image;
protected $body;
/** @var bool|int */
protected $vanity;
protected $similar;
protected $similar = [];
protected $nrLeechers;
protected $nrSnatches;
protected $nrSeeders;
protected $nrTorrents;
const CACHE_PREFIX = 'artist_';
const DISCOGS_API_URL = 'https://api.discogs.com/artists/%d';
protected const CACHE_PREFIX = 'artist_';
protected const DISCOGS_API_URL = 'https://api.discogs.com/artists/%d';
public function __construct (int $id, $revision = false) {
/**
* Artist constructor.
* @param int $id
* @param int|null $revisionId
* @throws OutOfBoundsException
*/
public function __construct (int $id, $revisionId = null) {
parent::__construct();
$this->id = $id;
$this->revision = $revision;
$this->revisionId = $revisionId ?? 0;
$cacheKey = $this->cacheKey();
if (($info = $this->cache->get_value($cacheKey)) !== false) {
@@ -61,7 +76,7 @@ class Artist extends Base {
$this->db->prepared_query($sql, $args);
if (!$this->db->has_results()) {
throw new \Exception("Artist:not-found");
throw new OutOfBoundsException("Artist:not-found");
}
[$this->name, $this->image, $this->body, $this->vanity, $this->discogsId, $this->discogsName,
$this->discogsStem, $this->discogsSequence, $this->discogsIsPreferred
@@ -88,13 +103,12 @@ class Artist extends Base {
$this->cache->cache_value($cacheKey, [
$this->name, $this->image, $this->body, $this->vanity, $this->similar,
$this->discogsId, $this->discogsName, $this->discogsStem, $this->discogsSequence, $this->discogsIsPreferred, $this->homonyms
],
3600
], 3600
);
}
}
public function rename(int $userId, int $aliasId, string $name) {
public function rename(int $userId, int $aliasId, string $name): void {
$this->db->prepared_query("
INSERT INTO artists_alias
(ArtistID, Name, UserID, Redirect)
@@ -107,7 +121,7 @@ class Artist extends Base {
", $targetId, $aliasId
);
$this->db->prepared_query("
UPDATE artists_group SET Name = ? WHERE ArtistID = ?
UPDATE artists_group SET Name = ? WHERE ArtistID = ?
", $name, $this->id
);
@@ -116,14 +130,14 @@ class Artist extends Base {
SELECT GroupID FROM torrents_artists WHERE AliasID = ?
", $aliasId
);
$Groups = $this->db->collect('GroupID');
$groups = $this->db->collect('GroupID');
$this->db->prepared_query("
UPDATE IGNORE torrents_artists SET AliasID = ? WHERE AliasID = ?
", $targetId, $aliasId
);
foreach ($Groups as $GroupID) {
$this->cache->delete_value("groups_artists_$GroupID"); // Delete group artist cache
\Torrents::update_hash($GroupID);
foreach ($groups as $groupId) {
$this->cache->delete_value("groups_artists_$groupId"); // Delete group artist cache
Torrents::update_hash($groupId);
}
// process artists in requests
@@ -133,46 +147,34 @@ class Artist extends Base {
WHERE AliasID = ?
", $aliasId
);
$Requests = $this->db->collect('RequestID');
$requests = $this->db->collect('RequestID');
$this->db->prepared_query("
UPDATE IGNORE requests_artists SET AliasID = ? WHERE AliasID = ?
", $targetId, $aliasId
);
foreach ($Requests as $RequestID) {
$this->cache->delete_value("request_artists_$RequestID"); // Delete request artist cache
\Requests::update_sphinx_requests($RequestID);
foreach ($requests as $requestId) {
$this->cache->delete_value("request_artists_$requestId"); // Delete request artist cache
Requests::update_sphinx_requests($requestId);
}
}
public function cacheKey() {
public function cacheKey(): string {
// TODO: change to protected when sections/ajax/artist.php is refactored
if ($this->revision) {
return self::CACHE_PREFIX . $this->id . '_r' . $this->revision;
} else {
return self::CACHE_PREFIX . $this->id;
}
return self::CACHE_PREFIX . $this->id
. ($this->revisionId ? '_r' . $this->revisionId : '');
}
public function flushCache() {
public function flushCache(): void {
$this->cache->delete_value($this->cacheKey());
}
public function resolveAlias(string $name) {
$this->db->_prepared_query("
SELECT AliasID, ArtistID, Name, Redirect
FROM artists_alias
WHERE Name = ?
", $name
);
while ([$CloneAliasID, $CloneArtistID, $CloneAliasName, $CloneRedirect] = $this->db->next_record(MYSQLI_NUM, false)) {
if (!strcasecmp($CloneAliasName, $AliasName)) {
return [$CloneAliasID, $CloneArtistID, $CloneAliasName, $CloneRedirect];
}
}
return null;
}
public function resolveRedirect(int $redirectId) {
/**
* @param int $redirectId
* @return int
* @throws OutOfBoundsException
* @throws UnexpectedValueException
*/
public function resolveRedirect(int $redirectId): int {
[$foundId, $foundRedirectId] = $this->db->row("
SELECT ArtistID, Redirect
FROM artists_alias
@@ -180,14 +182,20 @@ class Artist extends Base {
", $redirectId
);
if (!$foundId) {
throw new \Exception("Artist:not-found");
throw new OutOfBoundsException("Artist:not-found");
}
elseif ($this->id != $foundId) {
throw new \Exception("Artist:not-redirected");
if ($this->id !== $foundId) {
throw new UnexpectedValueException("Artist:not-redirected");
}
return $foundRedirectId > 0 ? $foundRedirectId : $redirectId;
return $foundRedirectId > 0 ? (int) $foundRedirectId : $redirectId;
}
/**
* @param int $userId
* @param string $name
* @param int $redirect
* @return int|void
*/
public function addAlias(int $userId, string $name, int $redirect) {
$this->db->prepared_query("
INSERT INTO artists_alias
@@ -198,7 +206,7 @@ class Artist extends Base {
return $this->db->inserted_id();
}
public function removeAlias(int $aliasId) {
public function removeAlias(int $aliasId): void {
$this->db->prepared_query("
UPDATE artists_alias SET
ArtistID = ?,
@@ -208,18 +216,19 @@ class Artist extends Base {
);
}
public function getAlias($name) {
public function getAlias($name): int {
$alias = $this->db->scalar('
SELECT AliasID
FROM artists_alias
WHERE ArtistID = ?
AND ArtistID != AliasID
AND Name = ?',
$this->id, $name);
AND Name = ?
', $this->id, $name
);
return $alias ?: $this->id;
}
public function editableInformation() {
public function editableInformation(): array {
return $this->db->row("
SELECT
ag.Name,
@@ -232,10 +241,10 @@ class Artist extends Base {
LEFT JOIN artist_discogs AS dg ON (dg.artist_id = ag.ArtistID)
WHERE ag.ArtistID = ?
", $this->id
);
) ?? [];
}
public function redirects() {
public function redirects(): array {
$this->db->prepared_query("
SELECT AliasID as aliasId, Name as aliasName, UserID as userId, Redirect as redirectId
FROM artists_alias
@@ -245,8 +254,9 @@ class Artist extends Base {
return $this->db->to_array('aliasId', MYSQLI_ASSOC);
}
public function requests() {
if (($requests = $this->cache->get_value("artists_requests_" . $this->id)) === false) {
public function requests(): array {
$requests = $this->cache->get_value("artists_requests_" . $this->id);
if (empty($requests)) {
$this->db->prepared_query('
SELECT
r.ID,
@@ -271,7 +281,7 @@ class Artist extends Base {
return $requests;
}
public function loadArtistRole() {
public function loadArtistRole(): int {
$this->db->prepared_query('
SELECT ta.GroupID, ta.Importance as artistRole
FROM torrents_artists AS ta
@@ -301,24 +311,16 @@ class Artist extends Base {
return $nr;
}
public function hasRole($role) {
public function hasRole($role): bool {
return $this->artistRole[$role] > 0;
}
public function activeRoles() {
return array_filter($this->artistRole, function ($role) {return $role > 0;});
}
public function groupRole($groupId) {
return isset($this->groupRole[$groupId]) ? $this->groupRole[$groupId] : false;
}
public function groupIds() {
public function groupIds(): array {
/* this is needed to call \Torrents::get_groups() */
return $this->groupList;
return $this->groupList ?? [];
}
public function loadGroups($torrentGroupList) {
public function loadGroups(array $torrentGroupList): int {
$this->sections = [];
$this->nrGroups = 0;
$this->nrLeechers = 0;
@@ -362,60 +364,61 @@ class Artist extends Base {
return $this->nrGroups;
}
public function nrGroups() {
return $this->nrGroups;
public function nrGroups(): int {
return $this->nrGroups ?? 0;
}
public function nrLeechers() {
return $this->nrLeechers;
public function nrLeechers(): int {
return $this->nrLeechers ?? 0;
}
public function nrSnatches() {
return $this->nrSnatches;
public function nrSnatches(): int {
return $this->nrSnatches ?? 0;
}
public function nrSeeders() {
return $this->nrSeeders;
public function nrSeeders(): int {
return $this->nrSeeders ?? 0;
}
public function nrTorrents() {
return $this->nrTorrents;
public function nrTorrents(): int {
return $this->nrTorrents ?? 0;
}
public function sections() {
return $this->sections;
public function sections(): array {
return $this->sections ?? [];
}
public function name() {
public function name(): string {
return $this->name;
}
public function image() {
public function image(): ?string {
return $this->image;
}
public function body() {
public function body(): ?string {
return $this->body;
}
public function vanityHouse() {
public function vanityHouse(): bool {
return $this->vanity;
}
public function similarArtists() {
public function similarArtists(): array {
return $this->similar;
}
public function url() {
return sprintf('<a href="artist.php?id=%d">%s</a>',
$this->id, $this->name
);
public function url(): string {
return sprintf('<a href="artist.php?id=%d">%s</a>', $this->id, $this->name);
}
public function setDiscogsRelation(int $discogsId, int $userId) {
if ($this->discogsId == $discogsId) {
/**
* Sets the Discogs ID for the artist and returns the number of affected rows.
*/
public function setDiscogsRelation(int $discogsId, int $userId): int {
if ($this->discogsId === $discogsId) {
// don't blindly set the Discogs ID to something else if it's already set, or doesn't change
return;
return 0;
}
$curl = curl_init();
@@ -434,7 +437,7 @@ class Artist extends Base {
$result = curl_exec($curl);
if ($result === false || curl_getinfo($curl, CURLINFO_RESPONSE_CODE) !== 200) {
return null;
return 0;
}
/* Discogs names are e.g. "Spectrum (4)"
@@ -446,11 +449,10 @@ class Artist extends Base {
*/
$payload = json_decode($result);
$this->discogsName = $payload->name;
if (preg_match('/^(.*) \((\d+)\)$/', $this->discogsName, $match) ) {
if (preg_match('/^(.*) \((\d+)\)$/', $this->discogsName, $match)) {
$this->discogsStem = $match[1];
$this->discogsSequence = $match[2];
}
else {
} else {
$this->discogsStem = $this->discogsName;
$this->discogsSequence = 1;
}
@@ -460,20 +462,21 @@ class Artist extends Base {
INSERT INTO artist_discogs
(artist_discogs_id, artist_id, is_preferred, sequence, stem, name, user_id)
VALUES (?, ?, ?, ?, ?, ?, ?)
', $this->discogsId, $this->id, $this->homonymCount() == 0, $this->discogsSequence, $this->discogsStem, $this->discogsName, $userId
', $this->discogsId, $this->id, $this->homonymCount() == 0,
$this->discogsSequence, $this->discogsStem, $this->discogsName, $userId
);
$this->flushCache();
return $this->db->affected_rows();
}
public function homonymCount() {
public function homonymCount(): int {
return $this->db->scalar('
SELECT count(*) FROM artist_discogs WHERE stem = ?
', $this->discogsStem
);
}
public function removeDiscogsRelation() {
public function removeDiscogsRelation(): int {
$this->db->prepared_query('
DELETE FROM artist_discogs WHERE artist_id = ?
', $this->id
@@ -482,15 +485,15 @@ class Artist extends Base {
return $this->db->affected_rows();
}
public function discogsId() {
public function discogsId(): ?int {
return $this->discogsId;
}
public function discogsName() {
public function discogsName(): ?string {
return $this->discogsName;
}
public function discogsIsPreferred() {
public function discogsIsPreferred(): bool {
return $this->discogsIsPreferred;
}
@@ -500,9 +503,10 @@ class Artist extends Base {
* Collapse whitespace and directional markers, because people copypaste carelessly.
* TODO: make stricter, e.g. on all whitespace characters or Unicode normalisation
*
* @param string $ArtistName
* @param string $name
* @return string|null
*/
public static function sanitize(string $name) {
public static function sanitize(string $name): ?string {
// \u200e is &lrm;
$name = preg_replace('/^(?:\xE2\x80\x8E|\s)+/', '', $name);
$name = preg_replace('/(?:\xE2\x80\x8E|\s)+$/', '', $name);

View File

@@ -334,10 +334,10 @@ class DB_MYSQL {
* the two functions separately instead of this function.
*
* @param $Query
* @param array ...$Parameters
* @param mixed ...$Parameters
* @return bool|mysqli_result
*/
function prepared_query($Query, ...$Parameters) {
public function prepared_query($Query, ...$Parameters) {
$this->prepare($Query);
return $this->execute(...$Parameters);
}

View File

@@ -55,6 +55,7 @@ SET FOREIGN_KEY_CHECKS = 1;
'tags' => [],
'torrents_tags' => [],
'torrents' => [],
'torrents_leech_stats' => [],
];
$artists = [];
@@ -200,6 +201,9 @@ SET FOREIGN_KEY_CHECKS = 1;
'FreeLeechType' => 0
];
$insert_data['torrents_leech_stats'][] = [
'TorrentID' => count($insert_data['torrents']) + 1,
];
$i++;
}

View File

@@ -5,7 +5,6 @@ services:
build: .
ports:
- 8080:80
- 36000:3306
- 34000:34000
depends_on:
- memcached
@@ -24,6 +23,8 @@ services:
mysql:
image: mariadb:10.3
ports:
- 36000:3306
volumes:
- ./.docker/mysql/mysqld_sql_mode.cnf:/etc/mysql/conf.d/mysqld_sql_mode.cnf
- ./.docker/data/mysql:/var/lib/mysql

View File

@@ -37,7 +37,7 @@ if (!empty($_GET['revisionid'])) { // if they're viewing an old revision
$RevisionID = false;
}
$Artist = new \Gazelle\Artist($ArtistID, $Revision);
$Artist = new Gazelle\Artist($ArtistID, $RevisionID);
$cacheKey = $Artist->cacheKey();
$Data = $Cache->get_value($cacheKey);
if ($Data) {

View File

@@ -38,8 +38,7 @@ if ($_GET['action'] === 'revert') { // if we're reverting to a previous revision
}
if ($discogsId > 0) {
if ($discogsId != $artist->discogsId()) {
$artist->setDiscogsRelation($discogsId, $userId);
if ($discogsId != $artist->discogsId() && $artist->setDiscogsRelation($discogsId, $userId)) {
$summary[] = "Discogs relation set to $discogsId";
}
} else {