User:Dr. Thomas Liptak/common-new.js
Appearance
Note: After saving, you have to bypass your browser's cache to see the changes. Internet Explorer: press Ctrl-F5, Mozilla: hold down Shift while clicking Reload (or press Ctrl-Shift-R), Opera/Konqueror: press F5, Safari: hold down Shift + Alt while clicking Reload, Chrome: hold down Shift while clicking Reload.
| Documentation for this user script can be added at User:Dr. Thomas Liptak/common-new. |
/*
Persönliches SDC‑Werkzeug für Dr. Thomas Liptak
Version 2026‑01‑26‑D (Vollversion, Block 1/2)
– Keine doppelten Statements
– P170‑Block mit Qualifikatoren stabil
– Depicted‑Template zuverlässig eingefügt
– Manuelles Feld für P1071
– P6216 = Q50423863
– P571: EXIF > Wikitext, bei Fehler Fallback „somevalue“
*/
mw.loader.using(['mediawiki.api']).then(function () {
$(function () {
if (mw.config.get('wgNamespaceNumber') !== 6) return;
const api = new mw.Api();
const pageName = mw.config.get('wgPageName');
const pageId = mw.config.get('wgArticleId');
const entityId = 'M' + pageId;
/* ---------------- Debug-Fenster ---------------- */
const $debug = $('<div>').css({
border: '1px solid #aaa',
padding: '0.5em',
marginTop: '1em',
background: '#f0f0f0',
fontSize: '0.9em',
maxHeight: '200px',
overflowY: 'auto'
}).append('<b>Debug-Ausgabe:</b><br>');
function log(msg, color = 'black') {
$debug.append('<div style="color:' + color + '">' + msg + '</div>');
}
/* ---------------- Hilfsfunktionen ---------------- */
function getPageWikitext() {
return api.get({
action: 'query',
prop: 'revisions',
rvprop: 'content',
formatversion: 2,
titles: pageName
}).then(d => d.query.pages[0].revisions[0].content || '');
}
function getExistingClaims() {
return api.get({
action: 'wbgetentities',
ids: entityId,
props: 'claims'
}).then(d => d.entities[entityId].claims || {});
}
function getExifDate() {
const title = pageName.replace(/_/g, ' ');
return api.get({
action: 'query',
prop: 'imageinfo',
titles: title,
iiprop: 'metadata'
}).then(data => {
const page = Object.values(data.query.pages)[0];
const info = page.imageinfo && page.imageinfo[0];
if (!info || !info.metadata) return null;
let exif = null;
info.metadata.forEach(m => {
if (['DateTimeOriginal', 'DateTimeDigitized', 'DateTime'].includes(m.name)) {
exif = m.value;
}
});
if (!exif) return null;
const m = exif.match(/^(\d{4}):(\d{2}):(\d{2})/);
return m ? `${m[1]}-${m[2]}-${m[3]}` : null;
});
}
function getDateFromWikitext(wikitext) {
const m = wikitext.match(/\|date\s*=\s*([0-9]{4}(-[0-9]{2})?(-[0-9]{2})?)/);
return m ? m[1] : null;
}
function getLocationFromWikitext(wikitext) {
const m = wikitext.match(/\{\{Location\|([0-9.\-]+)\|([0-9.\-]+)\}\}/);
return m ? { lat: parseFloat(m[1]), lon: parseFloat(m[2]) } : null;
}
function reverseGeocode(lat, lon) {
const sparql = `
SELECT ?place WHERE {
?place wdt:P625 ?coord .
SERVICE wikibase:around {
?place wdt:P625 ?coord .
bd:serviceParam wikibase:center "Point(${lon} ${lat})"^^geo:wktLiteral .
bd:serviceParam wikibase:radius "5" .
}
} LIMIT 1`;
return $.ajax({
url: "https://query.wikidata.org/sparql",
data: { query: sparql, format: "json" },
headers: { "Accept": "application/sparql-results+json" }
}).then(res => {
const b = res.results.bindings;
if (!b.length) return null;
const q = b[0].place.value.match(/Q\d+/);
return q ? q[0] : null;
}).catch(() => null);
}
function getCategoryQIDs() {
const qids = [];
$('#mw-normal-catlinks a').each(function (i, el) {
if (i === 0) return;
const t = $(el).text().trim();
if (/^Q\d+$/.test(t)) qids.push(t);
});
return qids;
}
/* ---------------- SDC: Depicts (P180) ---------------- */
async function setDepicts(existing, depictsInput) {
const qids = getCategoryQIDs();
if (depictsInput) {
depictsInput.split(',').forEach(q => qids.push(q.trim()));
}
for (const q of qids) {
if (!/^Q\d+$/.test(q)) continue;
if (existing.P180 && existing.P180.some(c => c.mainsnak.datavalue.value.id === q)) continue;
log(`Setze P180: ${q}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P180",
snaktype: "value",
value: JSON.stringify({ "entity-type": "item", id: q })
});
log(`P180 ${q} gesetzt`, "green");
} catch {
log(`Fehler bei P180 ${q}`, "red");
}
}
}
/* ---------------- SDC: Ort (P276) ---------------- */
async function setLocation(existing, qid) {
if (!qid || !/^Q\d+$/.test(qid)) return;
if (existing.P276 && existing.P276.length > 0) return;
log(`Setze P276: ${qid}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P276",
snaktype: "value",
value: JSON.stringify({ "entity-type": "item", id: qid })
});
log("P276 gesetzt", "green");
} catch {
log("Fehler bei P276", "red");
}
}
/* ---------------- SDC: Koordinaten (P1259) ---------------- */
async function setCoordinates(existing, coords) {
if (!coords) return;
if (existing.P1259 && existing.P1259.length > 0) return;
log(`Setze P1259: ${coords.lat}, ${coords.lon}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P1259",
snaktype: "value",
value: JSON.stringify({
latitude: coords.lat,
longitude: coords.lon,
precision: 0.0001,
globe: "http://www.wikidata.org/entity/Q2"
})
});
log("P1259 gesetzt", "green");
} catch {
log("Fehler bei P1259", "red");
}
}
/* ---------------- SDC: Herstellungsort (P1071) ---------------- */
async function setOrigin(existing, manualQ, coords) {
if (existing.P1071 && existing.P1071.length > 0) return;
if (manualQ && /^Q\d+$/.test(manualQ)) {
log(`Setze P1071 (manuell): ${manualQ}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P1071",
snaktype: "value",
value: JSON.stringify({ "entity-type": "item", id: manualQ })
});
log("P1071 (manuell) gesetzt", "green");
} catch {
log("Fehler bei P1071 (manuell)", "red");
}
return;
}
if (!coords) return;
log("Reverse-Geocoding für P1071…");
const qid = await reverseGeocode(coords.lat, coords.lon);
if (!qid) {
log("Kein Ort gefunden", "red");
return;
}
log(`Setze P1071 (auto): ${qid}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P1071",
snaktype: "value",
value: JSON.stringify({ "entity-type": "item", id: qid })
});
log("P1071 (auto) gesetzt", "green");
} catch {
log("Fehler bei P1071 (auto)", "red");
}
}
/* ---------------- SDC: Datum (P571) ---------------- */
async function setDate(existing, exifDate, wikiDate) {
if (existing.P571 && existing.P571.length > 0) return;
const date = exifDate || wikiDate;
if (!date) return;
log(`Setze P571: ${date}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P571",
snaktype: "value",
value: JSON.stringify({
time: `+${date}T00:00:00Z`,
precision: 11,
timezone: 0,
calendarmodel: "http://www.wikidata.org/entity/Q1985727"
})
});
log("P571 gesetzt", "green");
return;
} catch {
log("API akzeptiert Datum nicht – Fallback somevalue", "orange");
}
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P571",
snaktype: "somevalue"
});
log("P571 (somevalue) gesetzt", "green");
} catch {
log("Fehler bei P571 (somevalue)", "red");
}
}
/* ---------------- SDC: Lizenz (P275) ---------------- */
async function setLicense(existing) {
if (existing.P275 && existing.P275.length > 0) return;
const license = "Q18199165";
log(`Setze P275: ${license}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P275",
snaktype: "value",
value: JSON.stringify({ "entity-type": "item", id: license })
});
log("P275 gesetzt", "green");
} catch {
log("Fehler bei P275", "red");
}
}
/* ---------------- SDC: Copyright-Status (P6216) ---------------- */
async function setCopyright(existing) {
if (existing.P6216 && existing.P6216.length > 0) return;
const status = "Q50423863";
log(`Setze P6216: ${status}`);
try {
await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P6216",
snaktype: "value",
value: JSON.stringify({ "entity-type": "item", id: status })
});
log("P6216 gesetzt", "green");
} catch {
log("Fehler bei P6216", "red");
}
}
/* ---------------- Wikitext: Depicted-Template ---------------- */
function buildDepictedTemplate(qid) {
return `{{Depicted|${qid}|infofield=yes}}`;
}
function findInsertionPoint(wikitext) {
const patterns = [
"|description=",
"|Description=",
"description =",
"{{Information"
];
for (const p of patterns) {
const idx = wikitext.indexOf(p);
if (idx !== -1) {
const lineEnd = wikitext.indexOf("\n", idx);
return lineEnd === -1 ? wikitext.length : lineEnd + 1;
}
}
const lower = wikitext.toLowerCase();
const catIndex = lower.indexOf("\n[[category:");
if (catIndex !== -1) return catIndex;
return wikitext.length;
}
async function updateWikitextDepicted(wikitext, originalQ) {
if (!originalQ) return;
if (/\{\{Depicted\|/i.test(wikitext)) return;
const template = buildDepictedTemplate(originalQ);
const pos = findInsertionPoint(wikitext);
const newText = wikitext.slice(0, pos) + template + "\n" + wikitext.slice(pos);
log(`Schreibe Depicted-Template: ${originalQ}`);
try {
await api.postWithToken("csrf", {
action: "edit",
title: pageName,
text: newText,
summary: "Depicted-Template aus SDC ergänzt",
minor: true
});
log("Wikitext aktualisiert", "green");
} catch {
log("Fehler beim Wikitext-Update", "red");
}
}
/* ---------------- SDC: Urheber (P170) – MediaInfo-kompatibel ---------------- */
async function setCreatorP170(existing) {
if (existing.P170 && existing.P170.length > 0) {
log("P170 existiert bereits.");
return;
}
log("Setze P170…");
let claimId = null;
try {
const res = await api.postWithToken("csrf", {
action: "wbcreateclaim",
entity: entityId,
property: "P170",
snaktype: "value",
value: JSON.stringify({ "entity-type": "item", id: "Q2500638" })
});
// MediaInfo liefert claim-id hier:
claimId = res.claim?.id || res.claimId || res["claim-id"];
if (!claimId) {
// Fallback: Claim-ID aus wbgetentities neu laden
const updated = await getExistingClaims();
const p170 = updated.P170?.[0];
claimId = p170?.id;
}
if (!claimId) {
log("Konnte Claim-ID für P170 nicht ermitteln.", "red");
return;
}
log("P170 gesetzt: " + claimId, "green");
} catch (e) {
log("Fehler bei P170", "red");
return;
}
/* Qualifikatoren */
const qualifiers = [
{ property: "P2093", value: JSON.stringify("Dr. Thomas Liptak") },
{ property: "P4174", value: JSON.stringify("Dr._Thomas_Liptak") },
{ property: "P2699", value: JSON.stringify("https://commons.wikimedia.org/wiki/User:Dr._Thomas_Liptak") },
{ property: "P3831", value: JSON.stringify({ "entity-type": "item", id: "Q33231" }) }
];
for (const q of qualifiers) {
try {
await api.postWithToken("csrf", {
action: "wbsetqualifier",
claim: claimId,
property: q.property,
snaktype: "value",
value: q.value
});
log(`Qualifikator ${q.property} gesetzt`, "green");
} catch {
log(`Fehler bei Qualifikator ${q.property}`, "red");
}
}
log("Urheber-Block (P170 + Qualifikatoren) fertig.", "green");
}
/* ---------------- UI ---------------- */
const $box = $('<div>').css({
border: '2px solid #ccc',
padding: '1em',
marginTop: '1em',
background: '#f8f8f8'
}).append('<h3>Meine SDC‑Werkzeuge</h3>');
const $depictsInput = $('<input>')
.attr('placeholder', 'Zusätzliche Depicts (Q-ID)')
.css({ width: '100%', marginBottom: '0.5em' });
const $locationInput = $('<input>')
.attr('placeholder', 'Aufnahmeort (P276, Q-ID, optional)')
.css({ width: '100%', marginBottom: '0.5em' });
const $originInput = $('<input>')
.attr('placeholder', 'Herstellungsort (P1071, Q-ID, optional)')
.css({ width: '100%', marginBottom: '0.5em' });
const $button = $('<button>')
.text('Meine SDC-Standarddaten setzen')
.css({
padding: '0.5em 1em',
background: '#36c',
color: 'white',
border: 'none',
cursor: 'pointer'
});
$box.append($depictsInput, $locationInput, $originInput, $button, $debug);
$('.mw-parser-output').prepend($box);
/* ---------------- Hauptlogik ---------------- */
$button.on('click', function () {
$button.prop('disabled', true).text('Bitte warten…');
$debug.html('<b>Debug-Ausgabe:</b><br>');
$.when(getPageWikitext(), getExifDate(), getExistingClaims())
.done(async function (wikitext, exifDate, existing) {
const coords = getLocationFromWikitext(wikitext);
const wikiDate = getDateFromWikitext(wikitext);
/* P180 */
log("Setze Depicts…");
await setDepicts(existing, $depictsInput.val());
existing = await getExistingClaims();
/* P276 */
log("Setze Ort (P276)…");
await setLocation(existing, $locationInput.val());
existing = await getExistingClaims();
/* P1259 */
log("Setze Koordinaten (P1259)…");
await setCoordinates(existing, coords);
existing = await getExistingClaims();
/* P1071 */
log("Setze Herstellungsort (P1071)…");
await setOrigin(existing, $originInput.val().trim(), coords);
existing = await getExistingClaims();
/* P571 */
log("Setze Datum (P571)…");
await setDate(existing, exifDate, wikiDate);
existing = await getExistingClaims();
/* P275 */
log("Setze Lizenz (P275)…");
await setLicense(existing);
existing = await getExistingClaims();
/* P6216 */
log("Setze Copyright (P6216)…");
await setCopyright(existing);
existing = await getExistingClaims();
/* P170 */
log("Setze Urheber (P170)…");
await setCreatorP170(existing);
existing = await getExistingClaims();
/* Depicted-Template */
let originalDepictsQ = null;
if (existing.P180 && existing.P180.length > 0) {
const first = existing.P180[0];
if (first.mainsnak && first.mainsnak.datavalue && first.mainsnak.datavalue.value) {
originalDepictsQ = first.mainsnak.datavalue.value.id;
}
}
log("Aktualisiere Wikitext (Depicted)…");
await updateWikitextDepicted(wikitext, originalDepictsQ);
log("Fertig!", "green");
$button.prop('disabled', false).text('Meine SDC-Standarddaten setzen');
});
});
});
});