Detect local video URLs in MediaUrlResolver

Recognizes mp4/webm/ogv/mov/m4v on URL path (case-insensitive, ignoring
query strings) and emits <video controls class="kb-video">.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yutaka Kurosaki
2026-05-09 10:41:29 +09:00
parent 6daa001388
commit 7e445eb2fe
2 changed files with 53 additions and 1 deletions
+21 -1
View File
@@ -4,11 +4,31 @@
class MediaUrlResolver class MediaUrlResolver
{ {
private const VIDEO_EXT = ['mp4', 'webm', 'ogv', 'mov', 'm4v'];
public function resolve(string $url): ?string public function resolve(string $url): ?string
{ {
if ($url === '') { if ($url === '') {
return null; return null;
} }
return null; return $this->detectVideo($url);
}
private function detectVideo(string $url): ?string
{
if (!in_array($this->getPathExtension($url), self::VIDEO_EXT, true)) {
return null;
}
$safe = htmlspecialchars($url, ENT_QUOTES, 'UTF-8');
return "<video src=\"{$safe}\" controls class=\"kb-video\"></video>";
}
private function getPathExtension(string $url): string
{
$path = parse_url($url, PHP_URL_PATH);
if ($path === null || $path === false) {
return '';
}
return strtolower(pathinfo($path, PATHINFO_EXTENSION));
} }
} }
@@ -35,4 +35,36 @@ public static function nonMediaUrls(): array
'youtu.be lookalike host' => ['https://example.com/youtu.be-fake/abc'], 'youtu.be lookalike host' => ['https://example.com/youtu.be-fake/abc'],
]; ];
} }
#[DataProvider('videoUrls')]
public function test_video_urls_produce_video_tag(string $url): void
{
$html = $this->resolver->resolve($url);
$this->assertNotNull($html);
$this->assertStringStartsWith('<video', $html);
$this->assertStringContainsString('controls', $html);
$this->assertStringContainsString('class="kb-video"', $html);
}
public static function videoUrls(): array
{
return [
'mp4' => ['/demo.mp4'],
'webm' => ['/demo.webm'],
'ogv' => ['/demo.ogv'],
'mov' => ['/demo.mov'],
'm4v' => ['/demo.m4v'],
'uppercase extension' => ['/demo.MP4'],
'with query string' => ['https://example.com/path/demo.mp4?token=abc'],
'absolute http' => ['https://example.com/demo.mp4'],
];
}
public function test_video_url_is_html_escaped(): void
{
$html = $this->resolver->resolve('/path/with"quote.mp4');
$this->assertNotNull($html);
$this->assertStringNotContainsString('"quote.mp4"', $html);
$this->assertStringContainsString('&quot;', $html);
}
} }