2020-06-19 11:59:25 +05:00
|
|
|
<?php
|
|
|
|
|
|
|
|
namespace App;
|
|
|
|
|
2023-01-02 16:29:05 +00:00
|
|
|
use App\Concerns\FilteredByLetter;
|
|
|
|
use App\Concerns\MediaFilters;
|
2023-05-01 16:52:52 +01:00
|
|
|
use App\Enums\MangaTypeEnum;
|
2020-07-05 12:26:49 +05:00
|
|
|
use App\Http\HttpHelper;
|
2023-01-02 16:29:05 +00:00
|
|
|
use Carbon\CarbonImmutable;
|
2022-12-21 18:30:20 +00:00
|
|
|
use Database\Factories\MangaFactory;
|
|
|
|
use Illuminate\Support\Facades\App;
|
2023-05-01 16:52:52 +01:00
|
|
|
use Jikan\Helper\Constants;
|
2020-06-19 11:59:25 +05:00
|
|
|
use Jikan\Jikan;
|
2020-07-05 12:26:49 +05:00
|
|
|
use Jikan\Request\Manga\MangaRequest;
|
2022-12-04 11:38:11 +00:00
|
|
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
2020-06-19 11:59:25 +05:00
|
|
|
|
2022-06-08 17:05:12 +01:00
|
|
|
class Manga extends JikanApiSearchableModel
|
2020-06-19 11:59:25 +05:00
|
|
|
{
|
2023-01-02 16:29:05 +00:00
|
|
|
use HasFactory, MediaFilters, FilteredByLetter;
|
2022-12-04 11:38:11 +00:00
|
|
|
|
2023-05-01 16:52:52 +01:00
|
|
|
protected array $filters = [
|
|
|
|
"order_by", "status", "type", "sort", "max_score", "min_score", "score", "start_date", "end_date", "magazine",
|
|
|
|
"magazines", "letter", "genres", "genres_exclude", "sfw", "unapproved", "kids"
|
|
|
|
];
|
2020-06-19 11:59:25 +05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The attributes that are mass assignable.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $fillable = [
|
2023-02-11 16:32:16 +00:00
|
|
|
'mal_id', 'url', 'title', 'title_english', 'title_japanese', 'title_synonyms', 'titles',
|
|
|
|
'images', 'status', 'type', 'volumes', 'chapters', 'publishing', 'published', 'rank', 'score',
|
|
|
|
'scored_by', 'popularity', 'members', 'favorites', 'synopsis', 'background', 'related',
|
|
|
|
'genres', 'explicit_genres', 'themes', 'demographics', 'authors', 'serializations',
|
2023-05-01 16:52:52 +01:00
|
|
|
'createdAt', 'modifiedAt', 'approved'
|
2020-06-19 11:59:25 +05:00
|
|
|
];
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The accessors to append to the model's array form.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
2023-02-11 16:32:16 +00:00
|
|
|
protected $appends = ['themes'];
|
2020-06-19 11:59:25 +05:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The table associated with the model.
|
|
|
|
*
|
|
|
|
* @var string
|
|
|
|
*/
|
|
|
|
protected $table = 'manga';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The attributes excluded from the model's JSON form.
|
|
|
|
*
|
|
|
|
* @var array
|
|
|
|
*/
|
|
|
|
protected $hidden = [
|
2020-07-23 03:00:16 +05:00
|
|
|
'_id', 'expiresAt', 'request_hash'
|
2020-06-19 11:59:25 +05:00
|
|
|
];
|
|
|
|
|
2023-01-21 23:24:11 +00:00
|
|
|
public function __construct(array $attributes = [])
|
|
|
|
{
|
|
|
|
parent::__construct($attributes);
|
|
|
|
$this->displayNameFieldName = "title";
|
|
|
|
}
|
|
|
|
|
2023-01-02 16:29:05 +00:00
|
|
|
/** @noinspection PhpUnused */
|
2023-01-27 21:51:39 +00:00
|
|
|
public function filterByStartDate(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query, CarbonImmutable $value): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
2023-01-02 16:29:05 +00:00
|
|
|
{
|
2023-06-11 06:58:24 +05:00
|
|
|
return $query
|
|
|
|
->where("published.from", ">=",
|
|
|
|
$value->setTime(0, 0)
|
|
|
|
->setTimezone(new \DateTimeZone('UTC'))
|
|
|
|
->toAtomString()
|
|
|
|
);
|
2023-01-02 16:29:05 +00:00
|
|
|
}
|
|
|
|
|
2023-06-25 14:37:39 +01:00
|
|
|
/** @noinspection PhpUnused */
|
|
|
|
public function filterByType(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query, MangaTypeEnum $value): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
|
|
|
{
|
|
|
|
return $query->where("type", $value->label);
|
|
|
|
}
|
|
|
|
|
2023-01-02 16:29:05 +00:00
|
|
|
/** @noinspection PhpUnused */
|
2023-01-27 21:51:39 +00:00
|
|
|
public function filterByEndDate(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query, CarbonImmutable $value): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
2023-01-02 16:29:05 +00:00
|
|
|
{
|
2023-06-11 06:58:24 +05:00
|
|
|
return $query
|
|
|
|
->where("published.to", "<=",
|
|
|
|
$value->setTime(0, 0)
|
|
|
|
->setTimezone(new \DateTimeZone('UTC'))
|
|
|
|
->toAtomString()
|
|
|
|
);
|
2023-01-02 16:29:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
public function filterByMagazine(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query, string $value): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
|
|
|
{
|
|
|
|
if (empty($value)) {
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
|
|
|
$magazine = (int)$value;
|
|
|
|
return $query
|
2023-07-15 14:44:42 +01:00
|
|
|
->where('serializations.mal_id', $magazine);
|
2023-01-02 16:29:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @noinspection PhpUnused */
|
|
|
|
public function filterByMagazines(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query, string $value): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
|
|
|
{
|
|
|
|
if (empty($value)) {
|
|
|
|
return $query;
|
|
|
|
}
|
|
|
|
|
2024-04-10 18:59:30 +01:00
|
|
|
/** @var \Illuminate\Support\Collection $magazines */
|
2023-07-15 14:44:42 +01:00
|
|
|
$magazines = collect(explode(',', $value))->filter()->map(fn($x) => (int)$x)->toArray();
|
2023-01-02 16:29:05 +00:00
|
|
|
|
2024-04-10 18:59:30 +01:00
|
|
|
return $query->whereIn("serializations.mal_id", $magazines);
|
2023-01-02 16:29:05 +00:00
|
|
|
}
|
|
|
|
|
2023-05-01 16:52:52 +01:00
|
|
|
/** @noinspection PhpUnused */
|
|
|
|
public function scopeExceptItemsWithAdultRating(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
|
|
|
{
|
|
|
|
return $query
|
|
|
|
->where("type", "!=", MangaTypeEnum::doujin()->label)
|
|
|
|
->where("demographics.mal_id", "!=", Constants::GENRE_MANGA_HENTAI)
|
2023-06-11 13:36:14 +01:00
|
|
|
->where("demographics.mal_id", "!=", Constants::GENRE_MANGA_EROTICA)
|
|
|
|
->where("genres.mal_id", "!=", Constants::GENRE_MANGA_HENTAI);
|
2023-05-01 16:52:52 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/** @noinspection PhpUnused */
|
|
|
|
public function scopeExceptKidsItems(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
|
|
|
{
|
|
|
|
return $query
|
|
|
|
->where("demographics.mal_id", "!=", Constants::GENRE_MANGA_KIDS);
|
|
|
|
}
|
|
|
|
|
|
|
|
/** @noinspection PhpUnused */
|
|
|
|
public function scopeOnlyKidsItems(\Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder $query): \Laravel\Scout\Builder|\Illuminate\Database\Eloquent\Builder
|
|
|
|
{
|
|
|
|
return $query
|
|
|
|
->where("demographics.mal_id", Constants::GENRE_MANGA_KIDS);
|
|
|
|
}
|
|
|
|
|
2020-07-05 12:26:49 +05:00
|
|
|
public static function scrape(int $id)
|
|
|
|
{
|
|
|
|
$data = app('JikanParser')->getManga(new MangaRequest($id));
|
|
|
|
|
|
|
|
return HttpHelper::serializeEmptyObjectsControllerLevel(
|
|
|
|
json_decode(
|
|
|
|
app('SerializerV4')
|
|
|
|
->serialize($data, 'json'),
|
|
|
|
true
|
|
|
|
)
|
|
|
|
);
|
|
|
|
}
|
2022-06-08 17:05:12 +01:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Converts the model to an index-able data array.
|
|
|
|
*
|
|
|
|
* @return array
|
|
|
|
*/
|
|
|
|
public function toSearchableArray(): array
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'id' => (string) $this->mal_id,
|
2023-01-30 20:41:39 +00:00
|
|
|
'mal_id' => (int) $this->mal_id,
|
2022-06-08 17:05:12 +01:00
|
|
|
'start_date' => $this->convertToTimestamp($this->published['from']),
|
|
|
|
'end_date' => $this->convertToTimestamp($this->published['to']),
|
|
|
|
'title' => $this->title,
|
2022-10-03 20:04:39 +01:00
|
|
|
'title_transformed' => $this->simplifyStringForSearch($this->title),
|
2022-10-03 23:20:39 +05:00
|
|
|
'title_english' => $this->title_english ?? "",
|
2022-10-03 20:04:39 +01:00
|
|
|
'title_english_transformed' => $this->simplifyStringForSearch($this->title_english),
|
2022-06-08 17:05:12 +01:00
|
|
|
'title_japanese' => $this->title_japanese,
|
2022-10-03 20:04:39 +01:00
|
|
|
'title_japanese_transformed' => $this->simplifyStringForSearch($this->title_japanese),
|
2023-06-27 14:22:52 +01:00
|
|
|
'title_synonyms' => collect($this->titles ?? [])
|
|
|
|
->filter(fn($v, $k) => !in_array($v["type"], ["Default", "English", "Japanese"]))
|
|
|
|
->pluck("title")
|
|
|
|
->values()
|
|
|
|
->all(),
|
2022-06-08 17:05:12 +01:00
|
|
|
'type' => $this->type,
|
|
|
|
'chapters' => $this->chapters,
|
|
|
|
'volumes' => $this->volumes,
|
|
|
|
'status' => $this->status,
|
|
|
|
'publishing' => $this->publishing,
|
|
|
|
'score' => $this->score,
|
|
|
|
'rank' => $this->rank,
|
|
|
|
'popularity' => $this->popularity,
|
|
|
|
'members' => $this->members,
|
|
|
|
'favorites' => $this->favorites,
|
|
|
|
'synopsis' => $this->synopsis,
|
2023-05-01 16:52:52 +01:00
|
|
|
'approved' => $this->approved ?? false,
|
2022-06-08 17:05:12 +01:00
|
|
|
'magazines' => $this->getMalIdsOfField($this->magazines),
|
|
|
|
'genres' => $this->getMalIdsOfField($this->genres),
|
|
|
|
'explicit_genres' => $this->getMalIdsOfField($this->explicit_genres)
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-05-20 23:23:51 +01:00
|
|
|
public function getCollectionSchema(): array
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'name' => $this->searchableAs(),
|
|
|
|
'fields' => [
|
|
|
|
[
|
|
|
|
'name' => '.*',
|
|
|
|
'type' => 'auto',
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'name' => 'title',
|
|
|
|
'type' => 'string',
|
|
|
|
'optional' => false,
|
|
|
|
'infix' => true,
|
|
|
|
'sort' => true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'name' => 'title_transformed',
|
|
|
|
'type' => 'string',
|
|
|
|
'optional' => false,
|
|
|
|
'infix' => true,
|
|
|
|
'sort' => true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'name' => 'title_japanese',
|
|
|
|
'type' => 'string',
|
|
|
|
'optional' => true,
|
|
|
|
'locale' => 'jp',
|
|
|
|
'infix' => true,
|
|
|
|
'sort' => false
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'name' => 'title_japanese_transformed',
|
|
|
|
'type' => 'string',
|
|
|
|
'optional' => true,
|
|
|
|
'locale' => 'jp',
|
|
|
|
'infix' => true,
|
|
|
|
'sort' => false
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'name' => 'title_english',
|
|
|
|
'type' => 'string',
|
|
|
|
'optional' => true,
|
|
|
|
'infix' => true,
|
|
|
|
'sort' => true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'name' => 'title_english_transformed',
|
|
|
|
'type' => 'string',
|
|
|
|
'optional' => true,
|
|
|
|
'infix' => true,
|
|
|
|
'sort' => true
|
|
|
|
],
|
|
|
|
[
|
|
|
|
'name' => 'title_synonyms',
|
|
|
|
'type' => 'string[]',
|
|
|
|
'optional' => true,
|
|
|
|
'infix' => true,
|
|
|
|
'sort' => false
|
|
|
|
]
|
|
|
|
]
|
|
|
|
];
|
|
|
|
}
|
|
|
|
|
2023-02-11 16:32:16 +00:00
|
|
|
/** @noinspection PhpUnused */
|
|
|
|
public function getThemesAttribute()
|
2022-06-08 17:05:12 +01:00
|
|
|
{
|
2023-02-11 16:32:16 +00:00
|
|
|
$result = [];
|
|
|
|
if (array_key_exists("themes", $this->attributes)) {
|
|
|
|
$result = $this->attributes["themes"];
|
|
|
|
}
|
|
|
|
|
|
|
|
return $result;
|
2022-06-08 17:05:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
public function typesenseQueryBy(): array
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
'title',
|
2022-10-03 23:20:39 +05:00
|
|
|
'title_transformed',
|
2022-06-08 17:05:12 +01:00
|
|
|
'title_english',
|
2022-10-03 23:20:39 +05:00
|
|
|
'title_english_transformed',
|
2022-06-08 17:05:12 +01:00
|
|
|
'title_japanese',
|
2022-10-03 23:20:39 +05:00
|
|
|
'title_japanese_transformed',
|
2023-03-10 22:41:51 +00:00
|
|
|
'title_synonyms',
|
2022-06-08 17:05:12 +01:00
|
|
|
];
|
|
|
|
}
|
2022-06-18 15:03:50 +01:00
|
|
|
|
|
|
|
public function getTypeSenseQueryByWeights(): string|null
|
|
|
|
{
|
2023-07-09 10:50:18 +01:00
|
|
|
return "2,2,1,1,3,3,1";
|
2022-06-18 15:03:50 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns which fields the search index should sort on when searching
|
|
|
|
* @return array|null
|
|
|
|
*/
|
|
|
|
public function getSearchIndexSortBy(): array|null
|
|
|
|
{
|
|
|
|
return [
|
|
|
|
[
|
2023-07-09 10:50:18 +01:00
|
|
|
"field" => "_text_match(buckets:".text_match_buckets().")",
|
2022-10-03 23:20:39 +05:00
|
|
|
"direction" => "desc"
|
|
|
|
],
|
|
|
|
[
|
2023-06-26 18:42:51 +01:00
|
|
|
"field" => "popularity",
|
|
|
|
"direction" => "asc"
|
2022-10-03 23:20:39 +05:00
|
|
|
],
|
2023-06-26 18:42:51 +01:00
|
|
|
[
|
|
|
|
"field" => "rank",
|
|
|
|
"direction" => "asc"
|
|
|
|
]
|
2022-06-18 15:03:50 +01:00
|
|
|
];
|
|
|
|
}
|
2022-12-21 18:30:20 +00:00
|
|
|
|
|
|
|
protected static function newFactory()
|
|
|
|
{
|
|
|
|
return App::make(MangaFactory::class);
|
|
|
|
}
|
2022-06-08 17:05:12 +01:00
|
|
|
}
|