155 lines
4.3 KiB
PHP
155 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace App\Entity;
|
|
|
|
class Note
|
|
{
|
|
const HIGHLIGHT_PATTERN = '/<span\s+([^>]*)>(.*?)<\/span>/i';
|
|
const HIGHLIGHT_ATTR_KANJI = 'style="color: rgb(255, 78, 8);"';
|
|
|
|
protected ?int $id;
|
|
protected ?int $mod;
|
|
protected string $model;
|
|
protected string $profile;
|
|
protected array $cardIds = [];
|
|
protected array $fields = [];
|
|
protected array $tags = [];
|
|
|
|
|
|
// -------------------------------------------------- Getters & setters ---
|
|
|
|
public function getId(): int
|
|
{
|
|
return $this->id;
|
|
}
|
|
public function setId(int $id): static
|
|
{
|
|
$this->id = $id;
|
|
return $this;
|
|
}
|
|
public function getModel(): string
|
|
{
|
|
return $this->model;
|
|
}
|
|
|
|
public function getFields(): array
|
|
{
|
|
return $this->fields;
|
|
}
|
|
public function setFields(array $fields): static
|
|
{
|
|
$this->fields = $fields;
|
|
return $this;
|
|
}
|
|
/** @return list<string> */
|
|
public function getTags(): array
|
|
{
|
|
return $this->tags;
|
|
}
|
|
|
|
|
|
// ------------------------------------------------------- Anki-related ---
|
|
|
|
public static function fromAnki(array $noteInfo): static
|
|
{
|
|
$note = new static();
|
|
|
|
[
|
|
'noteId' => $note->id,
|
|
'mod' => $note->mod,
|
|
'profile' => $note->profile,
|
|
'tags' => $note->tags,
|
|
'modelName' => $note->model,
|
|
'cards' => $note->cardIds,
|
|
] = $noteInfo;
|
|
|
|
// the fields array key value comes with an order fields that is
|
|
// already maintained by PHP since arrays are ordered dictionaries.
|
|
// So we can safely just drop it.
|
|
//
|
|
// REVIEW: Having said that, maybe ordering the array before throwing
|
|
// the order would be advisable.
|
|
$note->fields = array_map(fn($x) => $x['value'], $noteInfo['fields']);
|
|
|
|
return $note;
|
|
}
|
|
|
|
public function toAnki(): array
|
|
{
|
|
return [
|
|
'id' => $this->id,
|
|
];
|
|
}
|
|
|
|
|
|
// ---------------------------------------------------- Derived methods ---
|
|
|
|
public function getCreatedAt(): \DateTimeImmutable
|
|
{
|
|
$timestamp = ceil($this->id / 1000);
|
|
return \DateTimeImmutable::createFromFormat('U', $timestamp);
|
|
}
|
|
|
|
public function getUpdatedAt(): \DateTimeImmutable
|
|
{
|
|
return \DateTimeImmutable::createFromFormat('U', $this->mod);
|
|
}
|
|
|
|
|
|
// -------------------------------------------------- Utility functions ---
|
|
|
|
protected static function stringHighlight(string $haystack, string $needle): string
|
|
{
|
|
$replace = sprintf(
|
|
'<span %s>%s</span>',
|
|
self::HIGHLIGHT_ATTR_KANJI,
|
|
$needle,
|
|
);
|
|
|
|
return str_replace($needle, $replace, strip_tags($haystack));
|
|
}
|
|
|
|
protected static function parseMediaInfo(string $notes): ?array
|
|
{
|
|
$matches = null;
|
|
|
|
// Parse the notes fields. It can be in the form of
|
|
// series-name_S01 EP07 (11h22m33s44ms)
|
|
// or
|
|
// movie-name EP (11h22m33s44ms)
|
|
if (1 !== preg_match(
|
|
'/(?<name>[0-9A-Za-z\-_]+)(_S)?(?<season>\d*) EP(?<episode>\d*) \((?<time>.*)\)/n',
|
|
$notes,
|
|
$matches,
|
|
)) {
|
|
return null;
|
|
}
|
|
|
|
// Remove number-indexed matches, cast numbers to integers
|
|
$matches = [
|
|
'name' => $matches['name'],
|
|
'time' => $matches['time'],
|
|
// NOTE: intval returns 0 if not a number, which is false-like
|
|
'season' => intval($matches['season']) ?: null,
|
|
'episode' => intval($matches['episode']) ?: null,
|
|
];
|
|
|
|
// Parse time into a DateInterval and replace it in the matches array
|
|
$time = new \DateInterval('PT0S');
|
|
|
|
preg_match('/(\d+)ms/', $matches['time'], $milliseconds);
|
|
preg_match('/(\d+)s/', $matches['time'], $seconds);
|
|
preg_match('/(\d+)m/', $matches['time'], $minutes);
|
|
preg_match('/(\d+)h/', $matches['time'], $hours);
|
|
|
|
if ($milliseconds[1] ?? false) $time->f = $milliseconds[1] * 1000;
|
|
if ($seconds[1] ?? false) $time->s = $seconds[1];
|
|
if ($minutes[1] ?? false) $time->i = $minutes[1];
|
|
if ($hours[1] ?? false) $time->h = $hours[1];
|
|
|
|
$matches['time'] = $time;
|
|
|
|
return $matches;
|
|
}
|
|
}
|