0.12.0-16 misc fixes
This commit is contained in:
1 parent
76b020d5c0
commit
5284dd2a43
30 files changed
+6955
-896
No files matched your search
@@ -1,7 +1,93 @@
|
||||
const settingsService = require('./settingsService');
|
||||
const logger = require('./logger').child('OMDB');
|
||||
|
||||
const OMDB_BASE_URL = 'https://www.omdbapi.com/';
|
||||
const OMDB_TIMEOUT_MS = 10000;
|
||||
const OMDB_MAX_ATTEMPTS = 2;
|
||||
const OMDB_RETRY_BASE_DELAY_MS = 300;
|
||||
|
||||
function normalizeOmdbTimeoutMs(value) {
|
||||
const parsed = Number(value);
|
||||
if (!Number.isFinite(parsed)) {
|
||||
return OMDB_TIMEOUT_MS;
|
||||
}
|
||||
return Math.max(1000, Math.trunc(parsed));
|
||||
}
|
||||
|
||||
function isRetryableOmdbError(error, aborted = false) {
|
||||
if (aborted) {
|
||||
return true;
|
||||
}
|
||||
const code = String(error?.code || '').trim().toUpperCase();
|
||||
if (code === 'ETIMEDOUT' || code === 'ECONNRESET' || code === 'ECONNABORTED') {
|
||||
return true;
|
||||
}
|
||||
const causeCode = String(error?.cause?.code || '').trim().toUpperCase();
|
||||
if (causeCode === 'UND_ERR_CONNECT_TIMEOUT' || causeCode === 'UND_ERR_HEADERS_TIMEOUT' || causeCode === 'UND_ERR_SOCKET') {
|
||||
return true;
|
||||
}
|
||||
const message = String(error?.message || '').toLowerCase();
|
||||
return message.includes('timed out') || message.includes('timeout');
|
||||
}
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise((resolve) => {
|
||||
setTimeout(resolve, ms);
|
||||
});
|
||||
}
|
||||
|
||||
class OmdbService {
|
||||
async requestJson(url, meta = {}, options = {}) {
|
||||
const timeoutMs = normalizeOmdbTimeoutMs(options?.timeoutMs);
|
||||
const maxAttempts = Math.max(1, Math.trunc(Number(options?.maxAttempts || OMDB_MAX_ATTEMPTS)));
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
||||
const controller = new AbortController();
|
||||
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
headers: {
|
||||
'Accept': 'application/json',
|
||||
'User-Agent': 'Ripster/1.0'
|
||||
},
|
||||
signal: controller.signal
|
||||
});
|
||||
if (!response.ok) {
|
||||
logger.warn('request:http-failed', {
|
||||
...meta,
|
||||
status: response.status,
|
||||
attempt,
|
||||
maxAttempts
|
||||
});
|
||||
return null;
|
||||
}
|
||||
return await response.json();
|
||||
} catch (error) {
|
||||
const aborted = error?.name === 'AbortError';
|
||||
const retryable = isRetryableOmdbError(error, aborted);
|
||||
const willRetry = retryable && attempt < maxAttempts;
|
||||
logger[willRetry ? 'info' : 'warn']('request:failed', {
|
||||
...meta,
|
||||
timeoutMs,
|
||||
aborted,
|
||||
retryable,
|
||||
attempt,
|
||||
maxAttempts,
|
||||
willRetry,
|
||||
message: error?.message || String(error)
|
||||
});
|
||||
if (willRetry) {
|
||||
await sleep(OMDB_RETRY_BASE_DELAY_MS * attempt);
|
||||
continue;
|
||||
}
|
||||
return null;
|
||||
} finally {
|
||||
clearTimeout(timer);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
async search(query) {
|
||||
if (!query || query.trim().length === 0) {
|
||||
return [];
|
||||
@@ -13,20 +99,18 @@ class OmdbService {
|
||||
if (!apiKey) {
|
||||
return [];
|
||||
}
|
||||
const timeoutMs = normalizeOmdbTimeoutMs(settings.omdb_timeout_ms);
|
||||
|
||||
const type = settings.omdb_default_type || 'movie';
|
||||
const url = new URL('https://www.omdbapi.com/');
|
||||
const url = new URL(OMDB_BASE_URL);
|
||||
url.searchParams.set('apikey', apiKey);
|
||||
url.searchParams.set('s', query.trim());
|
||||
url.searchParams.set('type', type);
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
logger.error('search:http-failed', { query, status: response.status });
|
||||
throw new Error(`OMDb Anfrage fehlgeschlagen (${response.status})`);
|
||||
const data = await this.requestJson(url, { query, action: 'search' }, { timeoutMs });
|
||||
if (!data || typeof data !== 'object') {
|
||||
return [];
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (data.Response === 'False' || !Array.isArray(data.Search)) {
|
||||
logger.warn('search:no-results', { query, response: data.Response, error: data.Error });
|
||||
return [];
|
||||
@@ -54,19 +138,17 @@ class OmdbService {
|
||||
if (!apiKey) {
|
||||
return null;
|
||||
}
|
||||
const timeoutMs = normalizeOmdbTimeoutMs(settings.omdb_timeout_ms);
|
||||
|
||||
const url = new URL('https://www.omdbapi.com/');
|
||||
const url = new URL(OMDB_BASE_URL);
|
||||
url.searchParams.set('apikey', apiKey);
|
||||
url.searchParams.set('i', normalizedId);
|
||||
url.searchParams.set('plot', 'full');
|
||||
|
||||
const response = await fetch(url);
|
||||
if (!response.ok) {
|
||||
logger.error('fetchByImdbId:http-failed', { imdbId: normalizedId, status: response.status });
|
||||
throw new Error(`OMDb Anfrage fehlgeschlagen (${response.status})`);
|
||||
const data = await this.requestJson(url, { imdbId: normalizedId, action: 'fetchByImdbId' }, { timeoutMs });
|
||||
if (!data || typeof data !== 'object') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
if (data.Response === 'False') {
|
||||
logger.warn('fetchByImdbId:not-found', { imdbId: normalizedId, error: data.Error });
|
||||
return null;
|
||||
|
||||
Reference in new issue
Block a user