anker/src/Entity/SentenceListeningNote.php

130 lines
3.8 KiB
PHP

<?php
namespace App\Entity;
class SentenceListeningNote extends Note
{
const MODEL_NAME = 'Japanese sentences listening';
private ?array $mediaInfo = [];
private ?Term $term = null;
// -------------------------------------------------- Getters & setters ---
public function getTerm(): Term
{
return $this->term;
}
public function setTerm(Term $term): static
{
$this->fields['VocabKanji'] = $term->getKanji();
$this->fields['VocabFurigana'] = $term->getReading();
$this->fields['VocabDef'] = $term->toAnkiVocabDef();
$this->fields['SentFurigana'] = ''; // We don't want to keep this
$this->fields['SentKanji'] = $this->stringHighlight(
$this->fields['SentKanji'],
$term->getKanji(),
);
$this->term = $term;
return $this;
}
// ------------------------------------------------------- Anki-related ---
public static function fromAnki(array $noteInfo): static
{
$note = parent::fromAnki($noteInfo);
if ($note->getModel() !== self::MODEL_NAME) {
throw new \Exception('Trying to parse wrong model');
}
$note->mediaInfo = self::parseMediaInfo($note->fields['Notes']);
// Set VocabKanji field
$note->term = Term::fromNoteFields($note->fields)[0] ?? null;
if ($note->term === null) {
throw new \Exception("Couldn't get term for Listening card");
}
return $note;
}
public static function fromNote(Note $origNote, Term $term): static
{
$slNote = new static();
foreach (get_object_vars($origNote) as $prop => $value) {
$slNote->$prop = $value;
}
// Related fields are updated using the setter
$slNote->setTerm($term);
// Reset relations and basic data
$slNote->id = null;
$slNote->model = self::MODEL_NAME;
$slNote->cardIds = [];
return $slNote;
}
public function toAnki(): array
{
return $this->fields;
}
// ---------------------------------------------------- Derived methods ---
public function isSentKanjiHighlighted(): bool
{
return str_contains(
$this->fields['SentKanji'],
self::HIGHLIGHT_ATTR_KANJI,
);
}
private 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;
}
}