リンクにつながっているページを芋づる式に探して出力するbookmarklet
/emoji/warning.iconbrowserが応答なしになるので非推奨です
計算がめちゃくちゃ重い
2 hopまでなら大した計算量ではないんですけどね……
3 hopはやりすぎでした……
大量のリンクがページに書き込まれる
用途
telomereを維持して別projectにページをexportするUserScriptの前段階として使う
一気にリンクを書き出して、その中から必要なものを順次取り出す
全部を手動で貼り付けようとすると時間かかるし面倒
2020-10-22 07:24:59 実装を変える
search/titlesを用いる
ページ数が爆発的に増えても問題ない
仕様
発動すると、ページに含まれているリンクにつながっているページをすべて引き出して新しいページに書き出す
逆リンク・順リンクは問わず、つながっているページををすべて列挙する
深さを指定可能
既定では3 hop先まで取得するようにした
実装
telomereを維持して別projectにページをexportするUserScriptをベースにcodingした
code:bookmarklet.js
javascript:(()=>{let s=document.createElement("script");s.src='https://scrapbox.io/api/code/takker/リンクにつながっているページを芋づる式に探して出力するbookmarklet/bookmark.js';document.body.appendChild(s);})()
code:bookmark.js
javascript:(async() => {
if(document.domain !== 'scrapbox.io') return;
// 最初に全ページのリンクデータを取得する
const getAllLinkData = async () => {
const pages = [];
let followingId = null;
do {
const param = followingId === null ? '' : ?followingId=${followingId};
const res = await fetch(
https://scrapbox.io/api/pages/${scrapbox.Project.name}/search/titles${param}
);
followingId = res.headers.get('X-Following-Id');
pages.push(...(await res.json()));
} while (followingId);
return pages;
};
// 指定したページデータとページタイトル、リンク先ページと被リンク先ページの両方を集めたページタイトルのリストを返す
const get1hopLinks = (pages, title) => {
const links = pages.find(page => page.title === title)?.links ?? [];
const linkeds = pages.filter(page => page.links.some(link => link === title))
.map(page => page.title);
return [...new Set(...links, ...linkeds)];
}
console.log('loading page data...');
const linkData = await getAllLinkData();
console.log('Got all page data.');
let targetLink = scrapbox.Page.title;
let foundLinks = [];
// リンクを再帰的に検索する
for (const i of 1,2,3) {
const links = ...new Set(targetLink.flatMap(title => get1hopLinks(linkData,title)));
console.log(Got ${links.length} ${i}-hop links.);
foundLinks = new Set(...links,...foundLinks);
targetLink = links;
}
console.log(Found ${foundLinks.size} links.);
// 空リンクを除外する
console.log('Removing empty links...');
const existedTitles = new Set(scrapbox.Project.pages
.filter(page => page.exists && !page.title.includes('🆖PIRACY'))
.map(page => page.title));
const results = ...foundLinks
.filter((title, i) => {
if (existedTitles.has(title)) {
console.log([${i}]Found '${title}');
return true;
}
return false;
});
console.log(Output ${results.length} links);
const lines = results.map(link => [${link}]);
const e = a => encodeURIComponent(a);
window.open(https://scrapbox.io/${scrapbox.Project.name}/temporary_page_${new Date()}?body=${e(lines.join('\n'))});
})();
#2021-01-20 16:16:39
#2020-10-21 09:12:02
#2020-10-15 18:53:48