amazonUrl, PHP_URL_HOST)); if (! in_array($host, ['amazon.co.uk', 'www.amazon.co.uk', 'amazon.com', 'www.amazon.com'], true)) { $this->warn($filament->filamentName.': unsupported product host'); continue; } try { $html = Http::timeout(15)->withHeaders(['User-Agent' => 'Mozilla/5.0 HickLab3D/1.0']) ->get($filament->amazonUrl)->throw()->body(); if (! preg_match('/class="[^"]*a-price-whole[^"]*"[^>]*>([0-9,.]+)/', $html, $whole) || ! preg_match('/class="[^"]*a-price-fraction[^"]*"[^>]*>([0-9]{2})/', $html, $fraction)) { $this->warn($filament->filamentName.': price unavailable'); continue; } $price = (float) (str_replace(',', '', $whole[1]).'.'.$fraction[1]); if ($price <= 0) { continue; } preg_match('/class="[^"]*savingsPercentage[^"]*"[^>]*>[^0-9]*([0-9]+)%/', $html, $discount); $previous = FilamentPrice::where('filamentId', $filament->id)->orderByDesc('recordedAt')->orderByDesc('id')->first(); FilamentPrice::create([ 'filamentId' => $filament->id, 'price' => $price, 'currentDiscount' => ['discount' => ['value' => (int) ($discount[1] ?? 0), 'type' => 'percentage'], 'voucher' => ['value' => 0, 'type' => 'none']], ]); if ($previous && $price < (float) $previous->price) { $drops[] = $filament->filamentName.': £'.number_format((float) $previous->price, 2).' → £'.number_format($price, 2).' ('.$filament->amazonUrl.')'; } $this->line($filament->filamentName.': £'.number_format($price, 2)); } catch (Throwable $exception) { report($exception); $this->warn($filament->filamentName.': collection failed'); } } if ($drops) { $body = "HickLab3D filament price drops\n\n".implode("\n", $drops); foreach (User::where('alertEmails', true)->where('disabled', false)->pluck('email') as $email) { Mail::raw($body, fn ($message) => $message->to($email)->subject('HickLab3D filament price drops')); } } return self::SUCCESS; } }