130 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			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;
 | 
						|
    }
 | 
						|
}
 |