cable8mm/youtube
cable8mm/youtube is a Laravel/PHP package for integrating YouTube content into your app. It provides convenient helpers for parsing YouTube URLs, extracting video IDs, and generating embed and thumbnail links, making it easy to work with videos in Blade views or application code.
composer require cable8mm/youtube — the service provider and facade are auto-discovered, so there is usually nothing to register in config/app.php.config/ and its service provider (vendor/cable8mm/youtube/src/...ServiceProvider.php). Publish config only if you need to override transport/cache/locale behaviour: php artisan vendor:publish --provider="Cable8mm\Youtube\...ServiceProvider".src/ directory rather than copying snippets from older blog posts or the pre-5.1 README — the old monolithic Youtube class is now split into a client, a decoder, and resource objects.use Cable8mm\Youtube\Facades\Youtube; // verify exact facade namespace in 5.1.x
$video = Youtube::get($request->input('url'));
$video->title;
$video->duration; // check whether seconds or formatted string
$video->thumbnail;
Persist the normalised fields on your model and you have the classic "link preview / video card" feature working in an afternoon.
Inject the client, don't reach for the facade. The v5.1.1 split into client/decoder/resources exists precisely so you can type-hint the client in a constructor and let the container resolve it. This makes unit testing trivial and survives future internal reshuffles better than static calls scattered through controllers.
final class VideoMetadataService
{
public function __construct(private \Cable8mm\Youtube\Client $client) {}
public function forUrl(string $url): VideoData
{
$resource = $this->client->get($url);
return new VideoData(
id: $resource->id,
title: $resource->title,
duration: (int) $resource->duration,
);
}
}
Map the package resource to your own DTO. Never let the package's resource object leak into Blade templates or API responses. Extract the handful of fields you actually use into your own value object or Eloquent cast. When the package renames a property, you fix one mapper instead of forty views.
Normalise URLs before calling. Accept youtu.be/…, /shorts/…, /embed/…, /live/…, and URLs with ?t=/&list= noise, then reduce to the bare video ID. A small YoutubeUrl::videoId($input) helper at the edge of your app keeps the client call predictable and lets you reject junk before it costs you a request.
Cache aggressively, keyed by video ID. Public video metadata changes rarely. Cache::remember("yt:{$id}", now()->addHours(6), fn () => $service->forUrl($url)) cuts latency and dodges throttling on list pages that render many thumbnails.
Push bulk work onto the queue. Importing a channel, backfilling thumbnails, or re-checking dead links should be a job with $tries, backoff(), and failed() handling. One job per video ID, not one job for a list — you get per-item retries and useful failure records.
Wrap calls in a single boundary with your own exception type. Catch whatever the client throws (network, decode, unsupported URL) and rethrow as VideoUnavailableException. Your controllers and jobs then never need to know the package's exception hierarchy — which is exactly the kind of thing a refactor release like 5.1.1 can quietly rearrange.
Testing. Bind a fake implementation of the client interface (or a stub decoder, if the package exposes one) in the container during tests. Because the decoder is now a separate concern, you can also unit-test parsing against a stored fixture response without any HTTP at all — a genuine improvement over the pre-5.1 monolithic design.
5.1.1) performed a structural refactor. Semver says nothing here should break, but splitting one class into three commonly breaks: subclasses of Youtube, instanceof checks, container bindings that resolved the concrete class, and PHPUnit mocks of the facade root. Run your suite and grep for extends Youtube and new Youtube( before deploying. If you subclassed anything, pin 5.1.0 until you've migrated.str_replace on a duration, a guarded isset() on a property that was sometimes missing — search for them and remove them; they may now be actively wrong.PT1H2M3S (ISO 8601), others a pre-formatted string. Don't assume; verify once and store your canonical form (integer seconds) in the database. Formatting belongs in your presenter.php artisan config:clear locally — a stale cached config is the usual reason "the package ignores my setting".How can I help you explore Laravel packages today?