NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==UserScript==
// @name wikipedia_similar_pages
// @namespace https://catherine.v0cyc1pp.com/
// @match https://*.wikipedia.org/wiki/*
// @author greg10
// @run-at document-end
// @license GPL-3.0-or-later
// @version 0.2
// @grant none
// @description 今見ているページの類似ページをページ下部に付ける
// ==/UserScript==
console.log("wikipedia_similar_pages");
function get_title_langcode() {
var langcode = "ja";
var title = "";
var matches = decodeURI(location.href).match(
"https?:\/\/([a-z]+)\.wikipedia\.org\/wiki\/([^#]*)",
);
if (matches) {
langcode = matches[1];
title = matches[2];
}
return { title: title, langcode: langcode };
}
function create_container() {
//--------------------------------------
// 一番外枠:misc_container
//--------------------------------------
var misc_container = document.createElement("div");
misc_container.id = "ruiji_container";
misc_container.className = "ruiji_container";
//misc_container.style.display = "flex";
//misc_container.style.flexFlow = "column";
//misc_container.style.position = 'fixed';
//misc_container.style.top = "85px";
//misc_container.style.left = 0;
//misc_container.style.right = "10px";
misc_container.style.borderStyle = "solid";
misc_container.style.borderColor = "green";
misc_container.style.borderWidth = "thin";
misc_container.style.padding = "4px";
// 追加
misc_container.innerHTML = "<h3>さらに読む</h3><p>処理中です...</p>";
var main_elem = document.querySelector(".mw-content-container");
main_elem.appendChild(misc_container);
return misc_container;
}
//JSONデータを引数に受け取ってDOM操作を行う関数を作成
function proc_json(misc_container, json, langcode) {
misc_container.innerHTML = "<h3>さらに読む</h3>\n";
const wrapper = document.createElement("div");
wrapper.className = "ruiji_cards";
misc_container.appendChild(wrapper);
for (var index in json.pages) {
var page = json.pages[index];
var title = page.title;
var url = "https://" + langcode + ".wikipedia.org/wiki/" + title;
var desc = page.description;
var thumburl = page.thumbnail ? page.thumbnail.url : null;
const card = document.createElement("a");
card.className = "ruiji_card";
card.href = url;
//card.target = "_blank"; // 別タブで開きたい場合
// サムネ
if (thumburl) {
const img = document.createElement("img");
img.src = thumburl;
img.className = "ruiji_thumb";
card.appendChild(img);
}
// 本文
const body = document.createElement("div");
body.className = "ruiji_body";
const titleEl = document.createElement("div");
titleEl.textContent = title;
titleEl.className = "ruiji_title";
body.appendChild(titleEl);
if (desc) {
const d = document.createElement("div");
d.textContent = desc;
d.className = "ruiji_desc";
body.appendChild(d);
}
card.appendChild(body);
wrapper.appendChild(card);
}
}
function proc(misc_container, title, langcode) {
var api =
"https://" +
langcode +
".wikipedia.org/w/rest.php/v1/search/page?q=morelike:" +
encodeURI(title) +
"&limit=10";
console.log("api=" + api);
//APIからJSONデータを取得する
fetch(api, {
method: "GET",
headers: {
"User-Agent":
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
},
})
.then((response) => {
return response.json(); //ここでBodyからJSONを返す
})
.then((result) => {
proc_json(misc_container, result, langcode); //取得したJSONデータを関数に渡す
})
.catch((e) => {
console.log(e); //エラーをキャッチし表示
});
}
function add_style() {
const style = document.createElement("style");
style.textContent = `
.ruiji_cards {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 10px;
}
.ruiji_card {
display: flex;
gap: 10px;
cursor: pointer;
border: 1px solid #ccc;
border-radius: 8px;
padding: 8px;
background: #fafafa;
transition: 0.2s;
text-decoration: none; /* ←追加 */
color: inherit; /* ←追加 */
}
.ruiji_card:hover {
background: #f0f0f0;
transform: translateY(-2px); /* ←ちょい浮かせると気持ちいい */
}
.ruiji_card:active {
transform: scale(0.98);
}
.ruiji_thumb {
width: 80px;
height: 80px;
object-fit: cover;
border-radius: 4px;
flex-shrink: 0;
}
.ruiji_body {
display: flex;
flex-direction: column;
font-size: 14px;
}
.ruiji_title {
font-weight: bold;
text-decoration: none;
margin-bottom: 4px;
}
.ruiji_desc {
color: #555;
font-size: 12px;
}
@media (prefers-color-scheme: dark) {
.ruiji_card {
background: #1e1e1e;
border: 1px solid #444;
color: #ddd;
}
.ruiji_card:hover {
background: #2a2a2a;
}
.ruiji_title {
color: #fff;
}
.ruiji_desc {
color: #aaa;
}
}
`;
document.head.appendChild(style);
}
function main() {
add_style(); // ←追加
var { title, langcode } = get_title_langcode();
/*
// 標準空間だけ対象にする
var ns = mw.config.get('wgNamespaceNumber')
if ( ns != 0 ) return;
*/
/*
// Content Script内で実行可能
const nsIdMeta = document.querySelector('meta[name="wgNamespaceNumber"]');
if (nsIdMeta) {
const nsId = parseInt(nsIdMeta.getAttribute('content'), 10);
console.log('Namespace ID:', nsId);
if ( nsId != 0 ) return;
}
*/
var ns = RLCONF["wgNamespaceNumber"];
console.log("ns=" + ns);
if (ns != 0) {
return;
}
var misc_container = create_container();
proc(misc_container, title, langcode);
}
main();