Files
gustavoo-me/wp-content/plugins/automatic-ai-posts/src/Modules/Images/DuckDuckGo.php
T
Gustavo 0ea3651fb5 Automatic AI Posts, setup automatizado e seeder de permalinks/avatar
Plugin automatic-ai-posts (v2.0.0)
- Pipeline completo: coleta de feeds RSS/Atom, filtro por IA, reescrita,
  categoria, imagem de capa e agendamento
- Página de configuração com teste real do provedor de IA
- Editor: botão para refazer imagem de capa e metadados, textos em PT-BR
- Ajuda com botão Pix (copia-e-cola + QR) e sem nota de avaliação
- Cache-busting por mtime nos assets do admin

Tema gustavoo-portfolio
- Marca do cabeçalho reduzida a "Gustavo"
- Suporte a título próprio da marca

Setup (docker/wp-init.sh, compose.yaml)
- Plugins de terceiros (Post Views Counter, Rank Math, Site Kit)
  instalados do WordPress.org em vez de versionados
- Falha explícita ao final se algum plugin obrigatório não instalar
- WPCLI_UID/WPCLI_GID configuráveis

Seeder do tema
- Links permanentes "Dia e nome" e avatar "Iniciais" aplicados
  apenas em instalação nova, com regravação do .htaccess
2026-11-02 13:33:30 -03:00

112 lines
3.1 KiB
PHP

<?php
namespace AAP\Modules\Images;
use AAP\Modules\Logs\Logger;
defined('ABSPATH') || exit;
/**
* DuckDuckGo image search (no API key required).
*
* The query itself is produced by the AI (see AiService::image_plan), so the
* blog owner's image instructions influence what is searched.
*/
final class DuckDuckGo {
private int $timeout;
public function __construct(int $timeout = 30) {
$this->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;
}
}