timeout = max(10, $timeout); } /** * @return string[] image URLs (best first) */ public function search(string $query, int $limit = 10): array { $query = trim($query); if ($query === '') { return []; } $encoded = urlencode($query); $token = $this->vqd($encoded); if ($token === '') { Logger::warn('DuckDuckGo: vqd token not found for "' . $query . '".', 'images'); return []; } return $this->fetch($encoded, $token, $limit); } private function vqd(string $encoded_query): string { $response = wp_remote_get( 'https://duckduckgo.com/?q=' . $encoded_query . '&iax=images&ia=images', [ 'timeout' => $this->timeout, 'user-agent' => 'Mozilla/5.0 (compatible; automatic-ai-posts/2.0)', ] ); if (is_wp_error($response)) { Logger::warn('DuckDuckGo: token request failed: ' . $response->get_error_message(), 'images'); return ''; } $body = (string) wp_remote_retrieve_body($response); if (preg_match('/vqd=([\d-]+)/', $body, $m)) { return $m[1]; } return ''; } /** * @return string[] */ private function fetch(string $encoded_query, string $token, int $limit): array { $url = add_query_arg([ 'l' => 'us-en', 'o' => 'json', 'q' => $encoded_query, 'vqd' => $token, 'f' => ',,,,,', 'p' => '1', ], 'https://duckduckgo.com/i.js'); $response = wp_remote_get($url, [ 'timeout' => $this->timeout, 'headers' => [ 'Referer' => 'https://duckduckgo.com/', 'User-Agent' => 'Mozilla/5.0 (compatible; automatic-ai-posts/2.0)', ], ]); if (is_wp_error($response)) { Logger::warn('DuckDuckGo: image request failed: ' . $response->get_error_message(), 'images'); return []; } $data = json_decode((string) wp_remote_retrieve_body($response), true); if (!isset($data['results']) || !is_array($data['results'])) { Logger::warn('DuckDuckGo: response without results.', 'images'); return []; } $urls = []; foreach ($data['results'] as $result) { $image = (string) ($result['image'] ?? ''); if ($image !== '') { $urls[] = $image; if (count($urls) >= $limit) { break; } } } return $urls; } }