ごった煮Stream
ごった煮Stream用のScrapbox Privateプロジェクトを用意して、UserScriptから単純に複数のプロジェクトのstream apiを叩いてマージする 要改良だが、なんとなく雰囲気は掴めた
https://gyazo.com/2c27b6bfdd70416b27806883402c70fb
複数のScrapboxプロジェクトのStreamをある程度リアルタイムで追っかけたいときに便利そう
nishio.iconsta.icon基素.iconをごった煮すると面白い
RSSとの棲み分けは要検討
code:js
(() => {
if (scrapbox.Layout != "stream") {
console.log("NOT stream page");
return;
} else {
console.log("stream page");
}
// Helper関数
function createElementWithClassName(elementName, className) {
const element = document.createElement(elementName);
if (className) {
element.className = className;
}
return element;
}
async function main() {
// script実行日時(比較用に取得)
const currentDate = new Date();
// 既存Streamを削除
const divStream = document.querySelector(".stream");
divStream.style = "display:none;"; //読み込み完了まで非表示にする
if (divStream) {
divStream.removeChild(divStream.firstChild);
}
// 対象Stream一覧
const urls = [
]
// 対象Stream一覧からJSONデータを取得
const response = await Promise.all(urls.map(url => fetch(url)));
const streams = await Promise.all(response.map(res => res.json()));
// 対象Stream一覧から取得したJSONデータをマージ
const mergedPages = [];
for (const stream of streams) {
const pages = stream.pages;
for (const page of pages) {
// linesの中で最新updatedを取得してlatestUpdatedに追加
page.lines.sort((a, b) => {
return a.updated > b.updated ? 1 : -1
});
// マージ時のprojectName判断用に追加
}
mergedPages.push(...pages);
}
// 更新日順にソート
mergedPages.sort((a, b) => {
return a.latestUpdated < b.latestUpdated ? 1 : -1;
});
// 指定した範囲(分)の更新を取得・描画
const renderTimeRange = (from, to) => {
const beforeFrom = (currentDate - (-from * 60 * 1000));
const beforeTo = (currentDate - (-to * 60 * 1000));
console.log(from: ${new Date(beforeFrom)} to:${new Date(beforeTo)});
const pagesOfTimeRange = mergedPages.filter((page) => {
const latest = page.latestUpdated * 1000;
return beforeFrom <= latest && latest < beforeTo;
});
// console.log(pagesOfTimeRange);
if (pagesOfTimeRange.length === 0) { return; }
const h1TimeRange = createElementWithClassName("h1", "time-range");
h1TimeRange.textContent = ${-from}分以内の更新;
divStream.appendChild(h1TimeRange);
for (const page of pagesOfTimeRange) {
const a = document.createElement("a");
a.href = https://scrapbox.io/${page.projectName}/${page.title};
a.textContent = ${page.projectName}: ${page.title};
const divTitle = createElementWithClassName("div", "line line-title");
divTitle.appendChild(a);
const divLines = createElementWithClassName("div", "lines");
divLines.appendChild(divTitle);
const betweenLines = page.lines.filter(line => {
const latest = line.updated * 1000;
return beforeFrom <= latest && latest < beforeTo;
});
for (const line of betweenLines) {
const divLine = createElementWithClassName("div", "line");
divLine.textContent = line.text;
divLines.appendChild(divLine);
}
const divPage = createElementWithClassName("div", "page");
divPage.appendChild(divLines);
divStream.appendChild(divPage);
}
};
// 既存Streamを削除
if (divStream.firstChild) {
divStream.removeChild(divStream.firstChild);
}
divStream.style = ''; // display: none;を削除
renderTimeRange(-10, 0); // 10分前から今までの更新を追加
renderTimeRange(-30, -10); // 30分前から10分前までの更新を追加
renderTimeRange(-60, -30); // 60分前から30分前までの更新を追加
renderTimeRange(-180, -60); // 180分前から60分前までの更新を追加
renderTimeRange(-360, -180);// 360分前から180分前までの更新を追加
renderTimeRange(-720, -360);// 720分前から360分前までの更新を追加
}
main();
})();
:tiken:.icon
なるほど、Streamページ上の要素を書き換えてしまうのかsta.icon