207 lines
6.1 KiB
JavaScript
207 lines
6.1 KiB
JavaScript
/* global window, jQuery */
|
|
|
|
/**
|
|
* Movie Import toolbar button for luxtools.
|
|
*
|
|
* Fetches movie metadata from OMDb (client-side) and inserts/replaces
|
|
* a wiki markup block in the editor.
|
|
*
|
|
* The OMDb API key is intentionally passed to the browser via JSINFO.
|
|
* It will be visible in browser developer tools and network requests.
|
|
* This is an accepted tradeoff for this single-user LAN deployment.
|
|
*/
|
|
(function () {
|
|
'use strict';
|
|
|
|
var MARKER_BEGIN = '<!-- BEGIN MOVIE -->';
|
|
var MARKER_END = '<!-- END MOVIE -->';
|
|
|
|
/**
|
|
* Get the OMDb API key from JSINFO (set by PHP in action.php).
|
|
*/
|
|
function getApiKey() {
|
|
if (window.JSINFO && window.JSINFO.luxtools_omdb_apikey) {
|
|
return String(window.JSINFO.luxtools_omdb_apikey);
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Get localized string from DokuWiki's LANG object.
|
|
*/
|
|
function lang(key, fallback) {
|
|
if (window.LANG && window.LANG.plugins && window.LANG.plugins.luxtools &&
|
|
window.LANG.plugins.luxtools[key]) {
|
|
return String(window.LANG.plugins.luxtools[key]);
|
|
}
|
|
return fallback || key;
|
|
}
|
|
|
|
/**
|
|
* Extract the first heading from the editor text.
|
|
* DokuWiki headings use ====== Heading ====== syntax.
|
|
* Returns the heading text trimmed, or empty string.
|
|
*/
|
|
function extractFirstHeading(text) {
|
|
var match = text.match(/^={2,6}\s*(.+?)\s*={2,6}\s*$/m);
|
|
if (match && match[1]) {
|
|
return match[1].trim();
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* Parse a title string that may contain a trailing year in parentheses.
|
|
* e.g. "Project Hail Mary (2026)" -> { title: "Project Hail Mary", year: "2026" }
|
|
* e.g. "Inception" -> { title: "Inception", year: null }
|
|
*/
|
|
function parseTitleYear(raw) {
|
|
var match = raw.match(/^(.+?)\s*\((\d{4})\)\s*$/);
|
|
if (match) {
|
|
return { title: match[1].trim(), year: match[2] };
|
|
}
|
|
return { title: raw.trim(), year: null };
|
|
}
|
|
|
|
/**
|
|
* Fetch movie data from OMDb.
|
|
* Returns a Promise that resolves with the parsed JSON response.
|
|
*/
|
|
function fetchMovie(apiKey, title, year) {
|
|
var url = 'https://www.omdbapi.com/?apikey=' + encodeURIComponent(apiKey) +
|
|
'&type=movie&t=' + encodeURIComponent(title);
|
|
if (year) {
|
|
url += '&y=' + encodeURIComponent(year);
|
|
}
|
|
|
|
return jQuery.ajax({
|
|
url: url,
|
|
dataType: 'json',
|
|
timeout: 10000
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Build the wiki markup block for a movie.
|
|
*/
|
|
function buildMarkup(movie) {
|
|
var lines = [];
|
|
lines.push(MARKER_BEGIN);
|
|
|
|
// Poster image (omit if N/A or empty)
|
|
var poster = movie.Poster || '';
|
|
if (poster && poster !== 'N/A') {
|
|
lines.push('{{image>' + poster + '}}');
|
|
}
|
|
|
|
// Data table
|
|
lines.push('^ Title | ' + safe(movie.Title) + ' |');
|
|
lines.push('^ Year | ' + safe(movie.Year) + ' |');
|
|
lines.push('^ Runtime | ' + safe(movie.Runtime) + ' |');
|
|
lines.push('^ Genre | ' + safe(movie.Genre) + ' |');
|
|
lines.push('^ Director | ' + safe(movie.Director) + ' |');
|
|
lines.push('^ Actors | ' + safe(movie.Actors) + ' |');
|
|
lines.push('^ Plot | ' + safe(movie.Plot) + ' |');
|
|
|
|
lines.push(MARKER_END);
|
|
return lines.join('\n');
|
|
}
|
|
|
|
/**
|
|
* Return value for table cell, replacing N/A with empty string.
|
|
*/
|
|
function safe(val) {
|
|
if (!val || val === 'N/A') return '';
|
|
return String(val);
|
|
}
|
|
|
|
/**
|
|
* Get the editor textarea element by id.
|
|
*/
|
|
function getEditor(edid) {
|
|
var id = edid || 'wiki__text';
|
|
return document.getElementById(id);
|
|
}
|
|
|
|
/**
|
|
* Main import action: prompt for title, fetch from OMDb, insert/replace markup.
|
|
*/
|
|
function importMovie(edid) {
|
|
var apiKey = getApiKey();
|
|
if (!apiKey) {
|
|
alert(lang('movie_error_no_apikey', 'OMDb API key is not configured. Set it in Admin → luxtools.'));
|
|
return;
|
|
}
|
|
|
|
var editor = getEditor(edid);
|
|
if (!editor) return;
|
|
|
|
var text = editor.value || '';
|
|
var heading = extractFirstHeading(text);
|
|
var defaultTitle = heading || '';
|
|
|
|
var input = prompt(lang('movie_prompt', 'Enter movie title (optionally with year):'), defaultTitle);
|
|
if (input === null || input.trim() === '') return;
|
|
|
|
var parsed = parseTitleYear(input.trim());
|
|
|
|
fetchMovie(apiKey, parsed.title, parsed.year)
|
|
.done(function (data) {
|
|
if (!data || data.Response === 'False') {
|
|
var errMsg = (data && data.Error) ? data.Error : lang('movie_error_not_found', 'Movie not found.');
|
|
alert(errMsg);
|
|
return;
|
|
}
|
|
|
|
var markup = buildMarkup(data);
|
|
insertOrReplace(editor, markup);
|
|
})
|
|
.fail(function () {
|
|
alert(lang('movie_error_fetch', 'OMDb lookup failed.'));
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Insert movie markup into the editor, replacing an existing movie block if present.
|
|
*/
|
|
function insertOrReplace(editor, markup) {
|
|
var text = editor.value || '';
|
|
|
|
var beginIdx = text.indexOf(MARKER_BEGIN);
|
|
var endIdx = text.indexOf(MARKER_END);
|
|
|
|
if (beginIdx !== -1 && endIdx !== -1 && endIdx > beginIdx) {
|
|
// Replace existing block
|
|
var before = text.substring(0, beginIdx);
|
|
var after = text.substring(endIdx + MARKER_END.length);
|
|
editor.value = before + markup + after;
|
|
} else {
|
|
// Append after the first heading line, or at the end
|
|
var headingMatch = text.match(/^(={2,6}\s*.+?\s*={2,6}\s*)$/m);
|
|
if (headingMatch) {
|
|
var headingEnd = text.indexOf(headingMatch[0]) + headingMatch[0].length;
|
|
editor.value = text.substring(0, headingEnd) + '\n\n' + markup + text.substring(headingEnd);
|
|
} else {
|
|
editor.value = text + '\n\n' + markup;
|
|
}
|
|
}
|
|
|
|
// Trigger input event so DokuWiki knows the content changed
|
|
try {
|
|
editor.dispatchEvent(new Event('input', { bubbles: true }));
|
|
} catch (e) {
|
|
// IE fallback
|
|
}
|
|
}
|
|
|
|
// Register toolbar button action handler.
|
|
// DokuWiki toolbar looks for window.addBtnAction<Type> for custom button types.
|
|
window.addBtnActionLuxtoolsMovieImport = function ($btn, props, edid) {
|
|
$btn.on('click', function () {
|
|
importMovie(edid);
|
|
return false;
|
|
});
|
|
return 'luxtools-movie-import';
|
|
};
|
|
})();
|