「利用者:KJP-System/common.js」の版間の差分

提供: KPOP JPWiki
ナビゲーションに移動 検索に移動
編集の要約なし
編集の要約なし
 
(同じ利用者による、間の7版が非表示)
1行目: 1行目:
console.log('KJP personal JS loaded');
window.KJPTEST = 123;
/**
/**
  * KJP Harness
  * KJP Harness
  * Owner-side maintenance helpers for KPOP JPWiki.
  * Owner-side maintenance helpers for KPOP JPWiki.
  *
  *
* ResourceLoader-compatible version.
  * - No automatic edits
  * - No automatic edits
  * - dryRun by default
  * - dryRun by default
16行目: 13行目:


lastBackup: [],
lastBackup: [],
reloadCommonCss: function () {
var id = 'kjp-harness-common-css';
var old = document.getElementById(id);


async getSource(title) {
if (old) {
const api = new mw.Api();
old.parentNode.removeChild(old);
}


const data = await api.get({
var link = document.createElement('link');
action: 'query',
link.id = id;
prop: 'revisions',
link.rel = 'stylesheet';
rvprop: 'content|ids|timestamp',
link.href =
rvslots: 'main',
mw.util.getUrl('MediaWiki:Common.css', {
titles: title,
action: 'raw',
formatversion: 2
ctype: 'text/css',
v: Date.now()
});
});


const page = data.query.pages[0];
document.head.appendChild(link);


return {
console.log('KJP Harness: Common.css reloaded.');
title: page.title,
},
pageid: page.pageid,
revid: page.revisions?.[0]?.revid,
timestamp: page.revisions?.[0]?.timestamp,
text: page.revisions?.[0]?.slots?.main?.content ?? ''
};
},


async inspect(pages, needle) {
wrapEntityPages: function (options) {
const results = [];
var self = this;
var api = new mw.Api();


for (const title of pages) {
var pages = options.pages;
try {
var summary = options.summary || 'KJP Harness: wrap entity pages';
const page = await this.getSource(title);
var dryRun =
const count = page.text.split(needle).length - 1;
typeof options.dryRun === 'boolean'
? options.dryRun
: true;


results.push({
var startFrom =
title,
'<includeonly>\n__NOTOC__\n__NOEDITSECTION__';
matches: count,
revid: page.revid
});
} catch (e) {
results.push({
title,
matches: 'ERROR',
revid: null
});


console.error(title, e);
var startTo =
}
'<includeonly>\n__NOTOC__\n__NOEDITSECTION__\n<div class="kjp-entity-page">';
}


console.table(results);
var endFrom = '</includeonly>';
return results;
var endTo = '</div>\n</includeonly>';
},


async bulkReplace({
var plan = [];
pages,
var backups = [];
from,
var chain = Promise.resolve();
to,
summary = 'KJP Harness bulk patch',
expectedMatches = 1,
dryRun = true
}) {
const api = new mw.Api();
const plan = [];
const backups = [];


for (const title of pages) {
pages.forEach(function (title) {
try {
chain = chain.then(function () {
const page = await this.getSource(title);
return self.getSource(title).then(function (page) {


if (page.text.includes(to)) {
if (page.text.indexOf('class="kjp-entity-page"') !== -1) {
plan.push({
plan.push({
title,
title: title,
status: 'SKIP_ALREADY_DONE'
status: 'SKIP_ALREADY_DONE'
});
});
continue;
return;
}
}


const count = page.text.split(from).length - 1;
var startCount =
page.text.split(startFrom).length - 1;


if (count !== expectedMatches) {
var endCount =
page.text.split(endFrom).length - 1;
 
if (startCount !== 1 || endCount !== 1) {
plan.push({
plan.push({
title,
title: title,
status: 'SKIP_MATCH_COUNT',
status: 'SKIP_STRUCTURE',
matches: count
startMatches: startCount,
endMatches: endCount
});
});
continue;
return;
}
}


plan.push({
plan.push({
title,
title: title,
status: dryRun ? 'READY' : 'PATCH'
status: dryRun ? 'READY' : 'PATCH'
});
});


if (!dryRun) {
if (dryRun) {
return;
}
 
backups.push({
title: title,
revid: page.revid,
text: page.text
});
 
var updated = page.text
.replace(startFrom, startTo)
.replace(endFrom, endTo);
 
return api.postWithToken('csrf', {
action: 'edit',
title: title,
text: updated,
summary: summary,
minor: true,
basetimestamp: page.timestamp,
formatversion: 2
});
}).catch(function (e) {
plan.push({
title: title,
status: 'ERROR'
});
 
console.error(title, e);
});
});
});
 
return chain.then(function () {
if (!dryRun) {
self.lastBackup = backups;
}
 
console.table(plan);
 
if (dryRun) {
console.log(
'DRY RUN: Entityページは変更されていません。'
);
} else {
console.log(
'WRAP完了。バックアップ: ' +
backups.length +
'件'
);
}
 
return plan;
});
},
 
getSource: function (title) {
var api = new mw.Api();
 
return api.get({
action: 'query',
prop: 'revisions',
rvprop: 'content|ids|timestamp',
rvslots: 'main',
titles: title,
formatversion: 2
}).then(function (data) {
var page = data.query.pages[0];
var revision = null;
var text = '';
 
if (page.revisions && page.revisions.length > 0) {
revision = page.revisions[0];
 
if (
revision.slots &&
revision.slots.main &&
typeof revision.slots.main.content === 'string'
) {
text = revision.slots.main.content;
}
}
 
return {
title: page.title,
pageid: page.pageid,
revid: revision ? revision.revid : null,
timestamp: revision ? revision.timestamp : null,
text: text
};
});
},
 
inspect: function (pages, needle) {
var self = this;
var results = [];
var chain = Promise.resolve();
 
pages.forEach(function (title) {
chain = chain.then(function () {
return self.getSource(title).then(function (page) {
var count = page.text.split(needle).length - 1;
 
results.push({
title: title,
matches: count,
revid: page.revid
});
}).catch(function (e) {
results.push({
title: title,
matches: 'ERROR',
revid: null
});
 
console.error(title, e);
});
});
});
 
return chain.then(function () {
console.table(results);
return results;
});
},
 
bulkReplace: function (options) {
var self = this;
var api = new mw.Api();
 
var pages = options.pages;
var from = options.from;
var to = options.to;
 
var summary = options.summary || 'KJP Harness bulk patch';
 
var expectedMatches =
typeof options.expectedMatches === 'number'
? options.expectedMatches
: 1;
 
var dryRun =
typeof options.dryRun === 'boolean'
? options.dryRun
: true;
 
var plan = [];
var backups = [];
var chain = Promise.resolve();
 
pages.forEach(function (title) {
chain = chain.then(function () {
 
return self.getSource(title).then(function (page) {
 
if (page.text.indexOf(to) !== -1) {
plan.push({
title: title,
status: 'SKIP_ALREADY_DONE'
});
 
return;
}
 
var count = page.text.split(from).length - 1;
 
if (count !== expectedMatches) {
plan.push({
title: title,
status: 'SKIP_MATCH_COUNT',
matches: count
});
 
return;
}
 
plan.push({
title: title,
status: dryRun ? 'READY' : 'PATCH'
});
 
if (dryRun) {
return;
}
 
backups.push({
backups.push({
title,
title: title,
revid: page.revid,
revid: page.revid,
text: page.text
text: page.text
});
});


const updated = page.text.replace(from, to);
var updated = page.text.replace(from, to);


await api.postWithToken('csrf', {
return api.postWithToken('csrf', {
action: 'edit',
action: 'edit',
title,
title: title,
text: updated,
text: updated,
summary,
summary: summary,
minor: true,
minor: true,
basetimestamp: page.timestamp,
basetimestamp: page.timestamp,
formatversion: 2
formatversion: 2
});
});
}
}).catch(function (e) {
plan.push({
title: title,
status: 'ERROR'
});


} catch (e) {
console.error(title, e);
plan.push({
title,
status: 'ERROR'
});
});
});
});
return chain.then(function () {


console.error(title, e);
if (!dryRun) {
self.lastBackup = backups;
}
}
}


if (!dryRun) {
console.table(plan);
this.lastBackup = backups;
}


console.table(plan);
if (dryRun) {
console.log('DRY RUN: Wikiは変更されていません。');
} else {
console.log(
'PATCH完了。バックアップ: ' +
backups.length +
'件'
);
}


console.log(
return plan;
dryRun
});
? 'DRY RUN: Wikiは変更されていません。'
: `PATCH完了。バックアップ: ${backups.length}件`
);
 
return plan;
}
}
};
};


console.log('KJP Harness loaded.');
console.log('KJP Harness loaded.');
// KJP Harness: audit public guidance pages
KJPHarness.auditPublicPages = function () {
    var pages = [
        {
            title: 'Help:編集ガイド',
            required: ['編集の基本方針', '出典', 'やってはいけない編集']
        },
        {
            title: 'Help:出典ガイド',
            required: ['信頼性Tier', 'Evidence', 'S — Primary / Official']
        },
        {
            title: 'Project:方針',
            required: ['基本原則', '存命人物に関する情報', 'サイト管理']
        },
        {
            title: 'Project:画像利用方針',
            required: ['基本原則', 'フォトカード画像', '権利者からの申立て']
        },
        {
            title: 'KPOP JPWikiについて',
            required: ['KPOP JPWikiが目指すもの', 'EXPLORE', 'COMMUNITY']
        },
        {
    title: 'Project:利用規約',
    required: [
        '適用範囲',
        '禁止行為',
        '投稿内容の権利',
        'プライバシー'
    ]
},
{
    title: 'Project:免責事項',
    required: [
        '情報の正確性について',
        '公式サイトとの関係',
        '広告について',
        '損害等について'
    ]
},
        {
    title: 'Project:プライバシーポリシー',
    required: [
        '収集する可能性のある情報',
        'Cookie等について',
        '広告について',
        '第三者への提供'
    ]
},
        {
            title: 'Project:お問い合わせ',
            required: [
                'サイトに関する問い合わせ',
                '著作権・画像・その他の権利に関する申立て',
                'セキュリティ上の問題'
            ]
        }
    ];
    return Promise.all(
        pages.map(function (page) {
            return KJPHarness.getSource(page.title).then(function (source) {
                var text = source && typeof source.text === 'string'
                    ? source.text
                    : '';
                var missing = page.required.filter(function (requiredText) {
                    return text.indexOf(requiredText) === -1;
                });
                return {
                    page: page.title,
                    exists: !!source && !!source.pageid,
                    length: text.length,
                    requiredSections: missing.length === 0 ? 'OK' : 'NG',
                    missing: missing.join(', ')
                };
            }).catch(function (error) {
                return {
                    page: page.title,
                    exists: false,
                    length: 0,
                    requiredSections: 'ERROR',
                    missing: String(error)
                };
            });
        })
    ).then(function (results) {
        console.table(results);
        return results;
    });
};

2026年8月25日 (火) 21:24時点における最新版

/**
 * KJP Harness
 * Owner-side maintenance helpers for KPOP JPWiki.
 *
 * ResourceLoader-compatible version.
 * - No automatic edits
 * - dryRun by default
 * - exact-match validation
 * - keeps an in-memory backup of the last patch
 */

window.KJPHarness = {

	lastBackup: [],
	
	reloadCommonCss: function () {
	var id = 'kjp-harness-common-css';
	var old = document.getElementById(id);

	if (old) {
		old.parentNode.removeChild(old);
	}

	var link = document.createElement('link');
	link.id = id;
	link.rel = 'stylesheet';
	link.href =
		mw.util.getUrl('MediaWiki:Common.css', {
			action: 'raw',
			ctype: 'text/css',
			v: Date.now()
		});

	document.head.appendChild(link);

	console.log('KJP Harness: Common.css reloaded.');
},

wrapEntityPages: function (options) {
	var self = this;
	var api = new mw.Api();

	var pages = options.pages;
	var summary = options.summary || 'KJP Harness: wrap entity pages';
	var dryRun =
		typeof options.dryRun === 'boolean'
			? options.dryRun
			: true;

	var startFrom =
		'<includeonly>\n__NOTOC__\n__NOEDITSECTION__';

	var startTo =
		'<includeonly>\n__NOTOC__\n__NOEDITSECTION__\n<div class="kjp-entity-page">';

	var endFrom = '</includeonly>';
	var endTo = '</div>\n</includeonly>';

	var plan = [];
	var backups = [];
	var chain = Promise.resolve();

	pages.forEach(function (title) {
		chain = chain.then(function () {
			return self.getSource(title).then(function (page) {

				if (page.text.indexOf('class="kjp-entity-page"') !== -1) {
					plan.push({
						title: title,
						status: 'SKIP_ALREADY_DONE'
					});
					return;
				}

				var startCount =
					page.text.split(startFrom).length - 1;

				var endCount =
					page.text.split(endFrom).length - 1;

				if (startCount !== 1 || endCount !== 1) {
					plan.push({
						title: title,
						status: 'SKIP_STRUCTURE',
						startMatches: startCount,
						endMatches: endCount
					});
					return;
				}

				plan.push({
					title: title,
					status: dryRun ? 'READY' : 'PATCH'
				});

				if (dryRun) {
					return;
				}

				backups.push({
					title: title,
					revid: page.revid,
					text: page.text
				});

				var updated = page.text
					.replace(startFrom, startTo)
					.replace(endFrom, endTo);

				return api.postWithToken('csrf', {
					action: 'edit',
					title: title,
					text: updated,
					summary: summary,
					minor: true,
					basetimestamp: page.timestamp,
					formatversion: 2
				});
			}).catch(function (e) {
				plan.push({
					title: title,
					status: 'ERROR'
				});

				console.error(title, e);
			});
		});
	});

	return chain.then(function () {
		if (!dryRun) {
			self.lastBackup = backups;
		}

		console.table(plan);

		if (dryRun) {
			console.log(
				'DRY RUN: Entityページは変更されていません。'
			);
		} else {
			console.log(
				'WRAP完了。バックアップ: ' +
				backups.length +
				'件'
			);
		}

		return plan;
	});
},

	getSource: function (title) {
		var api = new mw.Api();

		return api.get({
			action: 'query',
			prop: 'revisions',
			rvprop: 'content|ids|timestamp',
			rvslots: 'main',
			titles: title,
			formatversion: 2
		}).then(function (data) {
			var page = data.query.pages[0];
			var revision = null;
			var text = '';

			if (page.revisions && page.revisions.length > 0) {
				revision = page.revisions[0];

				if (
					revision.slots &&
					revision.slots.main &&
					typeof revision.slots.main.content === 'string'
				) {
					text = revision.slots.main.content;
				}
			}

			return {
				title: page.title,
				pageid: page.pageid,
				revid: revision ? revision.revid : null,
				timestamp: revision ? revision.timestamp : null,
				text: text
			};
		});
	},

	inspect: function (pages, needle) {
		var self = this;
		var results = [];
		var chain = Promise.resolve();

		pages.forEach(function (title) {
			chain = chain.then(function () {
				return self.getSource(title).then(function (page) {
					var count = page.text.split(needle).length - 1;

					results.push({
						title: title,
						matches: count,
						revid: page.revid
					});
				}).catch(function (e) {
					results.push({
						title: title,
						matches: 'ERROR',
						revid: null
					});

					console.error(title, e);
				});
			});
		});

		return chain.then(function () {
			console.table(results);
			return results;
		});
	},

	bulkReplace: function (options) {
		var self = this;
		var api = new mw.Api();

		var pages = options.pages;
		var from = options.from;
		var to = options.to;

		var summary = options.summary || 'KJP Harness bulk patch';

		var expectedMatches =
			typeof options.expectedMatches === 'number'
				? options.expectedMatches
				: 1;

		var dryRun =
			typeof options.dryRun === 'boolean'
				? options.dryRun
				: true;

		var plan = [];
		var backups = [];
		var chain = Promise.resolve();

		pages.forEach(function (title) {
			chain = chain.then(function () {

				return self.getSource(title).then(function (page) {

					if (page.text.indexOf(to) !== -1) {
						plan.push({
							title: title,
							status: 'SKIP_ALREADY_DONE'
						});

						return;
					}

					var count = page.text.split(from).length - 1;

					if (count !== expectedMatches) {
						plan.push({
							title: title,
							status: 'SKIP_MATCH_COUNT',
							matches: count
						});

						return;
					}

					plan.push({
						title: title,
						status: dryRun ? 'READY' : 'PATCH'
					});

					if (dryRun) {
						return;
					}

					backups.push({
						title: title,
						revid: page.revid,
						text: page.text
					});

					var updated = page.text.replace(from, to);

					return api.postWithToken('csrf', {
						action: 'edit',
						title: title,
						text: updated,
						summary: summary,
						minor: true,
						basetimestamp: page.timestamp,
						formatversion: 2
					});
				}).catch(function (e) {
					plan.push({
						title: title,
						status: 'ERROR'
					});

					console.error(title, e);
				});
			});
		});

		return chain.then(function () {

			if (!dryRun) {
				self.lastBackup = backups;
			}

			console.table(plan);

			if (dryRun) {
				console.log('DRY RUN: Wikiは変更されていません。');
			} else {
				console.log(
					'PATCH完了。バックアップ: ' +
					backups.length +
					'件'
				);
			}

			return plan;
		});
	}
};

console.log('KJP Harness loaded.');

// KJP Harness: audit public guidance pages
KJPHarness.auditPublicPages = function () {
    var pages = [
        {
            title: 'Help:編集ガイド',
            required: ['編集の基本方針', '出典', 'やってはいけない編集']
        },
        {
            title: 'Help:出典ガイド',
            required: ['信頼性Tier', 'Evidence', 'S — Primary / Official']
        },
        {
            title: 'Project:方針',
            required: ['基本原則', '存命人物に関する情報', 'サイト管理']
        },
        {
            title: 'Project:画像利用方針',
            required: ['基本原則', 'フォトカード画像', '権利者からの申立て']
        },
        {
            title: 'KPOP JPWikiについて',
            required: ['KPOP JPWikiが目指すもの', 'EXPLORE', 'COMMUNITY']
        },
        {
    title: 'Project:利用規約',
    required: [
        '適用範囲',
        '禁止行為',
        '投稿内容の権利',
        'プライバシー'
    ]
},
{
    title: 'Project:免責事項',
    required: [
        '情報の正確性について',
        '公式サイトとの関係',
        '広告について',
        '損害等について'
    ]
},
        {
    title: 'Project:プライバシーポリシー',
    required: [
        '収集する可能性のある情報',
        'Cookie等について',
        '広告について',
        '第三者への提供'
    ]
},
        {
            title: 'Project:お問い合わせ',
            required: [
                'サイトに関する問い合わせ',
                '著作権・画像・その他の権利に関する申立て',
                'セキュリティ上の問題'
            ]
        }
    ];

    return Promise.all(
        pages.map(function (page) {
            return KJPHarness.getSource(page.title).then(function (source) {
                var text = source && typeof source.text === 'string'
                    ? source.text
                    : '';

                var missing = page.required.filter(function (requiredText) {
                    return text.indexOf(requiredText) === -1;
                });

                return {
                    page: page.title,
                    exists: !!source && !!source.pageid,
                    length: text.length,
                    requiredSections: missing.length === 0 ? 'OK' : 'NG',
                    missing: missing.join(', ')
                };
            }).catch(function (error) {
                return {
                    page: page.title,
                    exists: false,
                    length: 0,
                    requiredSections: 'ERROR',
                    missing: String(error)
                };
            });
        })
    ).then(function (results) {
        console.table(results);
        return results;
    });
};