<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns="http://purl.org/rss/1.0/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/rss">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/rss</link>
    <description></description>
    <title>Bookmarklets from Lhankor_Mhy</title>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jun3wcKygeAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jrLIsPyegeAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/hLHX8qPqyax_"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/kpTi_IGaguAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/kc329cjkgqAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jtaB0fa4gYAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/kLOm3rHEgeAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/kOGSsI-SgsAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/kNe6m5vsgKAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/j9W6maaGgKAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/j9W5qIj-gKAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/j7qesMCUgYAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jr-yw7yCgMAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jLrKiqvEgoAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jo3aqcTggKAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/hLHVoNuA3dNN"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jPCIrOH0gcAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/jIKH0YzigMAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/iuzX89CqgKAA"/>
        <rdf:li rdf:resource="https://let.hatelabo.jp/Lhankor_Mhy/let/g5G0hvbqmesR"/>
      </rdf:Seq>
    </items>
  </channel>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jun3wcKygeAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jun3wcKygeAA</link>
    <dc:date>2025-12-01T05:19:34Z</dc:date>
    <description>メールを開いてブックマークレットを使ってからページをクリックすると、メールのパーマリンクをクリップボードにコピーします。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] Gmailのパーマリンク取得</title>
    <content:encoded>&lt;a href="javascript:%28async%28%29%3D%3E%7Bconst%20targetDataAttributeName%3D%22data-message-id%22%3Bconst%20waitForEvent%3D%28eventTarget%2CeventType%29%3D%3Enew%20Promise%28%28%28resolve%2Creject%29%3D%3EeventTarget.addEventListener%28eventType%2Cresolve%2C%7Bonce%3Atrue%2Csignal%3AAbortSignal.timeout%281e4%29%7D%29%29%29%3Blet%20targetElement%3Ddocument.querySelector%28%60%5B%24%7BtargetDataAttributeName%7D%5D%60%29%3Bif%28%21targetElement%29%7Balert%28%22%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E9%96%8B%E3%81%84%E3%81%A6%E3%81%8B%E3%82%89%E3%83%96%E3%83%83%E3%82%AF%E3%83%9E%E3%83%BC%E3%82%AF%E3%83%AC%E3%83%83%E3%83%88%E3%82%92%E4%BD%BF%E3%81%A3%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%22%29%3Breturn%7Dconst%20e%3Dawait%20waitForEvent%28document%2C%27mousedown%27%29%3BtargetElement%3De.target.closest%28%60%5B%24%7BtargetDataAttributeName%7D%5D%60%29%3F%3FtargetElement%3Bconst%20threadId%3DBigInt%28targetElement%3F.getAttribute%28targetDataAttributeName%29.split%28%27%3A%27%29%5B1%5D%29.toString%2816%29%3Bnavigator.clipboard.writeText%28%60https%3A%2F%2Fmail.google.com%2Fmail%2Fu%2F0%2F%23all%2F%24%7BencodeURIComponent%28threadId%29%7D%60%29.then%28%28%28%29%3D%3Ealert%28%22%E3%83%A1%E3%83%BC%E3%83%AB%E3%81%AE%E3%83%91%E3%83%BC%E3%83%9E%E3%83%AA%E3%83%B3%E3%82%AF%E3%82%92%E3%82%AF%E3%83%AA%E3%83%83%E3%83%97%E3%83%9C%E3%83%BC%E3%83%89%E3%81%AB%E3%82%B3%E3%83%94%E3%83%BC%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%22%29%29%29.catch%28%28err%3D%3E%7Bconsole.error%28%22%E3%82%AF%E3%83%AA%E3%83%83%E3%83%97%E3%83%9C%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E3%82%B3%E3%83%94%E3%83%BC%E3%81%AB%E5%A4%B1%E6%95%97%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%22%2Cerr%29%3Balert%28%22%E3%82%AF%E3%83%AA%E3%83%83%E3%83%97%E3%83%9C%E3%83%BC%E3%83%89%E3%81%B8%E3%81%AE%E3%82%B3%E3%83%94%E3%83%BC%E3%81%AB%E5%A4%B1%E6%95%97%E3%81%97%E3%81%BE%E3%81%97%E3%81%9F%22%29%7D%29%29%7D%29%28%29%3B"&gt;Gmailのパーマリンク取得&lt;/a&gt;&lt;pre&gt;/*
 * @title Gmailのパーマリンク取得
 * @description メールを開いてブックマークレットを使ってからページをクリックすると、メールのパーマリンクをクリップボードにコピーします。
 * @include https://mail.google.com/
 * @license CC0
 * @javascript_url
 */

// HTML構造変わるの早い……

(async () =&amp;gt; {
    const targetDataAttributeName = &amp;quot;data-message-id&amp;quot;
    const waitForEvent = (eventTarget, eventType) =&amp;gt; new Promise((resolve, reject) =&amp;gt;
        eventTarget.addEventListener(eventType, resolve, { once: true, signal: AbortSignal.timeout(10000) })
    )

    let targetElement = document.querySelector(`[${targetDataAttributeName}]`);
    if (!targetElement) {
        alert(&amp;quot;メールを開いてからブックマークレットを使ってください&amp;quot;)
        return
    }

    const e = await waitForEvent(document, 'mousedown')
    targetElement = e.target.closest(`[${targetDataAttributeName}]`) ?? targetElement;
    const threadId = BigInt(targetElement?.getAttribute(targetDataAttributeName).split(':')[1]).toString(16)
    navigator.clipboard.writeText(`https://mail.google.com/mail/u/0/#all/${encodeURIComponent(threadId)}`)
        .then(() =&amp;gt; alert(&amp;quot;メールのパーマリンクをクリップボードにコピーしました&amp;quot;))
        .catch(err =&amp;gt; {
            console.error(&amp;quot;クリップボードへのコピーに失敗しました&amp;quot;, err)
            alert(&amp;quot;クリップボードへのコピーに失敗しました&amp;quot;)
        });

})()

&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jrLIsPyegeAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jrLIsPyegeAA</link>
    <dc:date>2025-11-28T09:31:53Z</dc:date>
    <description>はてなブックマークにログインしていれば、n年前のブクマページに移動します。IEでは動作せず。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] n年前のブクマを見る</title>
    <content:encoded>&lt;a href="javascript:const%20n%3D1%3Bconst%20nYearBefore%3Dnew%20Date%3BnYearBefore.setFullYear%28%28new%20Date%29.getFullYear%28%29-n%29%3Blocation.href%3D%60https%3A%2F%2Fb.hatena.ne.jp%2Fmy%2F%24%7BnYearBefore.toLocaleDateString%28%27ja-JP%27%2C%7Byear%3A%27numeric%27%2Cmonth%3A%272-digit%27%2Cday%3A%272-digit%27%7D%29.split%28%27%2F%27%29.join%28%27%27%29%7D%60%3B"&gt;n年前のブクマを見る&lt;/a&gt;&lt;pre&gt;/*
 * @title n年前のブクマを見る
 * @description はてなブックマークにログインしていれば、n年前のブクマページに移動します。IEでは動作せず。
 * @include http://*
 * @license CC0
 * @javascript_url
 */

const n=1 // n=1は1年前

const nYearBefore = new Date()
nYearBefore.setFullYear(new Date().getFullYear()-n)

location.href = 
    `https://b.hatena.ne.jp/my/${nYearBefore.toLocaleDateString('ja-JP', {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
    }).split('/').join('')}`
&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/hLHX8qPqyax_">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/hLHX8qPqyax_</link>
    <dc:date>2025-01-30T03:15:30Z</dc:date>
    <description>ページ内にある～.PDFというリンクすべてからPDFファイルを取得して、zipして一括ダウンロードします（ドメインの壁は越えられません）。保存名はファイル名またはリンクテキスト.pdfの選択です。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] リンクのPDFファイルをzipしてダウンロード</title>
    <content:encoded>&lt;a href="javascript:%28async%28%29%3D%3E%7Bconst%20sleep%3Dtime%3D%3Enew%20Promise%28%28resolve%3D%3EsetTimeout%28resolve%2Ctime%29%29%29%3Bawait%20import%28%27https%3A%2F%2Fcdnjs.cloudflare.com%2Fajax%2Flibs%2Fjszip%2F3.2.0%2Fjszip.min.js%27%29%3Bconst%7Bdefault%3A%7BsaveAs%3AsaveAs%7D%7D%3Dawait%20import%28%27https%3A%2F%2Fcdn.jsdelivr.net%2Fnpm%2Ffile-saver%402.0.5%2F%2Besm%27%29%3Bconst%20zip%3Dnew%20JSZip%3Bconst%20path%3D%27files%27%2BNumber%28new%20Date%29%2B%27%2F%27%3Basync%20function%20downloader%28element%29%7Bconst%20response%3Dawait%20fetch%28element.href%29%3Belement.style.backgroundColor%3D%27gray%27%3Bconst%20fileName%3DdecodeURIComponent%28%28isUseFileName%3Felement.href.match%28%2F%28%3F%3D%5B%5E%5C%2F%5D%2B%5C.pdf%29%5B%5E%5C%2F%5D%2B%5C.pdf%2F%29%3Aelement.textContent.match%28%2F%28%3F%3D%5B%5E%5C%2F%5D%2B%5C.pdf%29%5B%5E%5C%2F%5D%2B%5C.pdf%2F%29%29%3F%3Felement.textContent.trim%28%29%2B%22.pdf%22%29%3Bawait%20sleep%282e3%29%3Bif%28zip.file%28path%2BfileName%29%29%7BfileName%3DNumber%28new%20Date%29%2B%27_%27%2BfileName%7Dzip.file%28path%2BfileName%2Cawait%20response.blob%28%29%29%7Dconst%20isUseFileName%3Dconfirm%28%27URL%E3%81%AE%E3%83%95%E3%82%A1%E3%82%A4%E3%83%AB%E5%90%8D%E3%81%A7%E4%BF%9D%E5%AD%98%E3%81%97%E3%81%BE%E3%81%99%27%29%3Bfor%28let%20target%20of%20document.querySelectorAll%28%27a%5Bhref%2A%3D%22.pdf%22%5D%20%27%29%29%7Bawait%20downloader%28target%29.catch%28%28%28%29%3D%3E%7B%7D%29%29%7Dfor%28let%20target%20of%5B...document.querySelectorAll%28%27a%3Anot%28%5Bhref%2A%3D%22.pdf%22%5D%29%27%29%5D.filter%28%28e%3D%3Ee.textContent.includes%28%27pdf%27%29%7C%7Ce.textContent.includes%28%27PDF%27%29%29%29%29%7Bawait%20downloader%28target%29.catch%28%28e%3D%3E%7Bthrow%20e%7D%29%29%7Dconst%20content%3Dawait%20zip.generateAsync%28%7Btype%3A%22blob%22%7D%29%3BsaveAs%28content%2C%27files.zip%27%29%7D%29%28%29%3B"&gt;リンクのPDFファイルをzipしてダウンロード&lt;/a&gt;&lt;pre&gt;/*
 * @title リンクのPDFファイルをzipしてダウンロード
 * @description ページ内にある～.PDFというリンクすべてからPDFファイルを取得して、zipして一括ダウンロードします（ドメインの壁は越えられません）。保存名はファイル名またはリンクテキスト.pdfの選択です。
 * @include http://*
 * @license MIT License
 * @javascript_url
 */


(async () =&amp;gt; {
    const sleep = time =&amp;gt; new Promise(resolve =&amp;gt; setTimeout(resolve, time));
    await import('https://cdnjs.cloudflare.com/ajax/libs/jszip/3.2.0/jszip.min.js');
    const { default: { saveAs } } = await import('https://cdn.jsdelivr.net/npm/file-saver@2.0.5/+esm');

    const zip = new JSZip();

    const path = 'files' + Number(new Date()) + '/';

    async function downloader(element) {
        const response = await fetch(
            element.href,
        );
        element.style.backgroundColor = 'gray';
        const fileName = decodeURIComponent(
            (isUseFileName ?
                element.href.match(/(?=[^\/]+\.pdf)[^\/]+\.pdf/) :
                element.textContent.match(/(?=[^\/]+\.pdf)[^\/]+\.pdf/))
            ?? element.textContent.trim() + &amp;quot;.pdf&amp;quot;
        );
        await sleep(2000);

        if (zip.file(path + fileName)) { fileName = Number(new Date()) + '_' + fileName };
        zip.file(path + fileName, await response.blob());

    };

    const isUseFileName = confirm('URLのファイル名で保存します')

    for (let target of document.querySelectorAll('a[href*=&amp;quot;.pdf&amp;quot;] ')) { await downloader(target).catch(() =&amp;gt; { }) };
    for (let target of [...document.querySelectorAll('a:not([href*=&amp;quot;.pdf&amp;quot;])')].filter(e =&amp;gt; e.textContent.includes('pdf') || e.textContent.includes('PDF'))) { await downloader(target).catch(e =&amp;gt; { throw e }) };
    const content = await zip.generateAsync({ type: &amp;quot;blob&amp;quot; });
    saveAs(content, 'files.zip');

})()&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/kpTi_IGaguAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/kpTi_IGaguAA</link>
    <dc:date>2024-11-20T09:52:13Z</dc:date>
    <description>b.hatena.ne.jp ドメイン上で使用してください</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] あなたのファーストブクマはこれ</title>
    <content:encoded>&lt;a href="javascript:void%28async%28%29%3D%3E%7Bconst%20pageCount%3DMath.ceil%28Number%28%28new%20DOMParser%29.parseFromString%28await%28await%20fetch%28%60https%3A%2F%2Fb.hatena.ne.jp%2Fmy%2Fbookmark%60%29%29.text%28%29%2C%27text%2Fhtml%27%29.getElementsByClassName%28%27userprofile-status-count%27%29%5B0%5D.textContent.replace%28%2F%2C%2Fg%2C%27%27%29%29%2F20%29%3Blocation.href%3D%5B...%28new%20DOMParser%29.parseFromString%28await%28await%20fetch%28%60https%3A%2F%2Fb.hatena.ne.jp%2Fmy%2Fbookmark%3Fpage%3D%24%7BpageCount%7D%60%29%29.text%28%29%2C%27text%2Fhtml%27%29.querySelectorAll%28%27%5Bdata-gtm-click-label%3D%22user-my-reaction-permalink%22%5D%27%29%5D.at%28-1%29.href%7D%29%28%29%3B"&gt;あなたのファーストブクマはこれ&lt;/a&gt;&lt;pre&gt;/*
 * @title あなたのファーストブクマはこれ
 * @description b.hatena.ne.jp ドメイン上で使用してください
 * @include https://b.hatena.ne.jp/
 * @license CC0
 * @javascript_url
 */

void (async () =&amp;gt; {
    const pageCount = Math.ceil(Number(
        new DOMParser().parseFromString(
            await (await fetch(`https://b.hatena.ne.jp/my/bookmark`)).text(),
            'text/html'
        ).getElementsByClassName('userprofile-status-count')[0].textContent.replace(/,/g, '')
    ) / 20)
    location.href = [...new DOMParser().parseFromString(
        await (await fetch(`https://b.hatena.ne.jp/my/bookmark?page=${pageCount}`)).text(),
        'text/html'
    ).querySelectorAll('[data-gtm-click-label=&amp;quot;user-my-reaction-permalink&amp;quot;]')].at(-1).href
})()
&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/kc329cjkgqAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/kc329cjkgqAA</link>
    <dc:date>2024-10-16T07:49:53Z</dc:date>
    <description>ページ内カタカナをア段に変換します。元ネタ→https://anond.hatelabo.jp/20240801082705</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] *印度化計画</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2FLhankor_Mhy%2Flet%2Fkc329cjkgqAA.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;*印度化計画&lt;/a&gt;&lt;pre&gt;/*
 * @title *印度化計画
 * @description ページ内カタカナをア段に変換します。元ネタ→https://anond.hatelabo.jp/20240801082705
 * @include http://*
 * @license CC0
 * @require 
 */

(async () =&amp;gt; {
    await import('https://unpkg.com/wanakana')
    const indianize = str =&amp;gt;
        wanakana.toKana(
            wanakana.toRomaji(str, {
                convertLongVowelMark: false,
                upcaseKatakana: true
            }).replace(/[IUEO]/g, 'A')
        )

    const treeWalker = document.createTreeWalker(
        document.body,
        NodeFilter.SHOW_TEXT,
    );
    while (treeWalker.nextNode()) {
        const node = treeWalker.currentNode;
        node.data = node.data.replace(/\p{scx=Katakana}+/ug, indianize)
    }
})()&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jtaB0fa4gYAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jtaB0fa4gYAA</link>
    <dc:date>2024-03-28T03:21:28Z</dc:date>
    <description>コメントメタブと2階ブクマを展開します。説明→https://realtor-readyabooks.hatenablog.com/entry/2022/12/28/153626</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] はてなブックマークメタブ展開</title>
    <content:encoded>&lt;a href="javascript:%28async%28%29%3D%3E%7Bconst%20APIURL%3D%27https%3A%2F%2Fb.hatena.ne.jp%2Fentry%2Fjsonlite%2F%3Furl%3D%27%3Bdocument.body.insertAdjacentHTML%28%27beforeend%27%2C%60%5Cn%3Cstyle%3E%5Cn%5Bdata-metabu%5D%20%7B%5Cn%5Ctbackground-color%3A%20rgba%280%2C0%2C0%2C0.05%29%3B%5Cn%7D%5Cn%5Bdata-metabu%5D.focus%20%7B%5Cn%5Ctoutline%3Adotted%201px%3B%5Cn%7D%5Cn%23metahatebu-popover%7B%5Cn%20%20%20%20inset%3A%20auto%200%200%20auto%3B%5Cn%20%20%20%20opacity%3A%200.5%3B%5Cn%20%20%20%20border%3A%20none%3B%5Cn%20%20%20%20background-color%3A%20%23000%3B%5Cn%20%20%20%20color%3A%20%23fff%3B%5Cn%20%20%20%20position%3A%20fixed%3B%5Cn%7D%5Cn%3C%2Fstyle%3E%5Cn%3Cdialog%20popover%20id%3D%22metahatebu-popover%22%3E%E3%83%A1%E3%82%BF%E3%83%96%E3%81%82%E3%82%8A%E3%81%BE%E3%81%99%3Cbutton%20data-metabuprev%3E%E5%89%8D%3C%2Fbutton%3E%3Cbutton%20data-metabunext%3E%E6%AC%A1%3C%2Fbutton%3E%3C%2Fdialog%3E%5Cn%20%20%20%20%60%29%3Bdocument.querySelector%28%27.entry-comments%27%29.insertAdjacentHTML%28%27beforeend%27%2C%60%5Cn%3Cdiv%20class%3D%22entry-comment-contents%22%20id%3D%22upStairsSeat%22%3E%3C%2Fdiv%3E%5Cn%20%20%20%20%60%29%3Bconst%20metahatebuPopover%3Ddocument.getElementById%28%27metahatebu-popover%27%29%3BmetahatebuPopover.addEventListener%28%27click%27%2C%28%28i%3D-1%29%3D%3Eevent%3D%3E%7Bconst%20metabues%3Ddocument.querySelectorAll%28%27%5Bdata-metabu%5D%27%29%3Bif%28event.target.matches%28%27%5Bdata-metabuprev%5D%27%29%29i--%3Bif%28event.target.matches%28%27%5Bdata-metabunext%5D%27%29%29i%2B%2B%3Bi%3Dmetabues.length%3F%28i%2Bmetabues.length%29%25metabues.length%3A0%3Bmetabues%5Bi%5D.scrollIntoView%28%7Bbehavior%3A%22smooth%22%2Cblock%3A%22end%22%2Cinline%3A%22nearest%22%7D%29%3Bmetabues.forEach%28%28%28metabu%2Cj%29%3D%3Emetabu.classList.toggle%28%27focus%27%2Ci%3D%3Dj%29%29%29%7D%29%28%29%29%3Bconst%20metahatebuPopoverOpen%3D%28%29%3D%3E%7Bif%28HTMLElement.showPopover%29%7BmetahatebuPopover.showPopover%28%29%7Delse%7BmetahatebuPopover.show%28%29%7D%7D%3Bconst%20addBookmark%3Dfunction%28targetElement%2Cbookmark%2Ceid%29%7Bdocument.querySelector%28%60%5Bhref%3D%22%2Fentry%2F%24%7Beid%7D%2Fcomment%2F%24%7Bbookmark.user%7D%22%5D%60%29%3F.closest%28%27.entry-comment-contents%20%3E%20.entry-comment-contents%27%29.remove%28%29%3BtargetElement.insertAdjacentHTML%28%27beforeend%27%2Cdocument.getElementById%28%27autoloader-bookmark-item%27%29.textContent.replaceAll%28%27%3Cdiv%20class%3D%22entry-comment-contents%20%27%2C%27%3Cdiv%20data-metabu%3D%22metabu%22%20class%3D%22entry-comment-contents%20%27%29.replaceAll%28%27%7B%7Buser_name%7D%7D%27%2Cbookmark.user%29.replaceAll%28%27%7B%7Bbookmarked_url%7D%7D%27%2Cbookmark.url%29.replaceAll%28%27%7B%7Buser_page_path%7D%7D%27%2C%60%2F%24%7Bbookmark.user%7D%2F%60%29.replaceAll%28%27%7B%7B%20sort%20%7D%7D%27%2C%60recent%60%29.replaceAll%28%27%7B%7Bprofile_image_url%7D%7D%27%2C%60https%3A%2F%2Fcdn.profile-image.st-hatena.com%2Fusers%2F%24%7Bbookmark.user%7D%2Fprofile.png%60%29.replaceAll%28%27%7B%7B%20%23is_public%20%7D%7Dis-hidden%7B%7B%20%2Fis_public%20%7D%7D%27%2C%60is-hidden%60%29.replaceAll%28%27%7B%7B%7Bcomment_expanded%7D%7D%7D%27%2Cbookmark.comment%29.replaceAll%28%27%7B%7B%7Btags%7D%7D%7D%27%2C%60%3Cli%3E%24%7Bbookmark.tags.join%28%27%3Cli%3E%27%29%7D%60%29.replaceAll%28%27%7B%7Bcreated%7D%7D%27%2Cbookmark.timestamp%29.replaceAll%28%27%7B%7Bcomment_page_path%7D%7D%27%2C%60%2Fentry%2F%24%7Beid%7D%2Fcomment%2F%24%7Bbookmark.user%7D%60%29.replaceAll%28%27%7B%7B%23should_nofollow%7D%7Dnofollow%7B%7B%2Fshould_nofollow%7D%7D%27%2C%27nofollow%27%29.replaceAll%28%27%7B%7B%23enable_button%7D%7D%20is-enabled%7B%7B%2Fenable_button%7D%7D%27%2C%27is-enabled%27%29%29%3BmetahatebuPopoverOpen%28%29%7D%3Bconst%20targetURLs%3D%5Blocation.href%5D%2CupstairsBookmarksList%3D%5B%5D%3Bfor%28const%20targetURL%20of%20targetURLs%29%7Bconst%7Bbookmarks%3Abookmarks%2Centry_url%3Aentry_url%2Ceid%3Aeid%7D%3Dawait%28await%20fetch%28%60%24%7BAPIURL%7D%24%7BencodeURIComponent%28targetURL%29%7D%60%29%29.json%28%29%3F%3F%7Bentry_url%3Anull%7D%3Bif%28%21entry_url%29continue%3BtargetURLs.push%28entry_url%29%3BupstairsBookmarksList.push%28%5Bbookmarks%2Ceid%5D%29%7Dfunction%20addUpstairsBookmark%28targetElements%29%7Bif%28upstairsBookmarksList.length%29metahatebuPopoverOpen%28%29%3BupstairsBookmarksList.forEach%28%28upstairsBookmarks%3D%3E%7Bconst%5Bbookmarks%2Ceid%5D%3DupstairsBookmarks%3BupstairsBookmarks%5B0%5D%3Dbookmarks.filter%28%28bookmark%3D%3E%7Bconst%20targetUserBookmark%3DtargetElements.find%28%28element%3D%3Eelement.dataset%3F.userName%3D%3D%3Dbookmark.user%29%29%3Bif%28%21targetUserBookmark%29%7Bconst%20targetElement%3Ddocument.getElementById%28%27upStairsSeat%27%29%3BaddBookmark%28targetElement%2Cbookmark%2Ceid%29%3Breturn%20true%7Dconst%20targetElement%3D%5BtargetUserBookmark%2C...targetUserBookmark.querySelectorAll%28%60.entry-comment-contents%5Bdata-user-name%3D%22%24%7Bbookmark.user%7D%22%5D%60%29%5D.pop%28%29%3BaddBookmark%28targetElement%2Cbookmark%2Ceid%29%3Breturn%20false%7D%29%29%7D%29%29%7Dfunction%20addMetaBookmark%28targetElements%29%7BtargetElements.forEach%28%28async%20element%3D%3E%7Bconst%20targetURL%3Delement.querySelector%28%27%5Bdata-gtm-label%3D%22entry-recent-permalink%22%5D%27%29%3F.href%3Bif%28%21targetURL%29return%20undefined%3Bconst%7Bbookmarks%3Abookmarks%2Centry_url%3Aentry_url%2Ceid%3Aeid%7D%3Dawait%28await%20fetch%28%60%24%7BAPIURL%7D%24%7BencodeURIComponent%28targetURL%29%7D%60%29%29.json%28%29%3F%3F%7Bentry_url%3Anull%7D%3Bif%28%21entry_url%29return%20undefined%3Bbookmarks.forEach%28%28bookmark%3D%3E%7BaddBookmark%28element%2Cbookmark%2Ceid%29%7D%29%29%7D%29%29%7DaddUpstairsBookmark%28Array.from%28document.querySelectorAll%28%60.js-bookmarks-recent%20%5Bdata-user-name%5D%60%29%29%29%3BaddMetaBookmark%28Array.from%28document.querySelectorAll%28%60.js-bookmarks-recent%20%5Bdata-user-name%5D%60%29%29%29%3Bconst%20targetNode%3Ddocument.querySelector%28%27.js-bookmarks-recent%27%29%3Bconst%20upstairsBookmarkMutationConfig%3D%7BchildList%3Atrue%7D%3Bconst%20upstairsBookmarkMutationCallback%3Dfunction%28mutationsList%2Cobserver%29%7Bfor%28const%20mutation%20of%20mutationsList%29%7Bif%28mutation.type%3D%3D%3D%27childList%27%29%7BaddUpstairsBookmark%28Array.from%28mutation.addedNodes%29.filter%28%28node%3D%3Enode.dataset%3F.userName%29%29%29%7D%7D%7D%3Bconst%20upstairsBookmarkMutationObserver%3Dnew%20MutationObserver%28upstairsBookmarkMutationCallback%29%3BupstairsBookmarkMutationObserver.observe%28targetNode%2CupstairsBookmarkMutationConfig%29%3Bconst%20metaBookmarkMutationConfig%3D%7BchildList%3Atrue%2Csubtree%3Atrue%7D%3Bconst%20metaBookmarkMutationCallback%3Dfunction%28mutationsList%2Cobserver%29%7Bfor%28const%20mutation%20of%20mutationsList%29%7Bif%28mutation.type%3D%3D%3D%27childList%27%29%7BaddMetaBookmark%28Array.from%28mutation.addedNodes%29.filter%28%28node%3D%3Enode.dataset%3F.userName%29%29%29%7D%7D%7D%3Bconst%20metaBookmarkMutationObserver%3Dnew%20MutationObserver%28metaBookmarkMutationCallback%29%3BmetaBookmarkMutationObserver.observe%28targetNode%2CmetaBookmarkMutationConfig%29%7D%29%28%29%3B"&gt;はてなブックマークメタブ展開&lt;/a&gt;&lt;pre&gt;// ==UserScript==
// @name         はてなブックマークメタブ展開
// @title        はてなブックマークメタブ展開
// @namespace    https://let.hatelabo.jp/Lhankor_Mhy/let/jtaB0fa4gYAA
// @version      0.13.2
// @description  コメントメタブと2階ブクマを展開します。説明→https://realtor-readyabooks.hatenablog.com/entry/2022/12/28/153626
// @author       Lhankor_Mhy
// @match        https://b.hatena.ne.jp/entry/*
// @icon         https://b.hatena.ne.jp/favicon.ico
// @license      CC0
// @noframes
// @grant        none
// @javascript_url
// ==/UserScript==


(async () =&amp;gt; {
    const APIURL = 'https://b.hatena.ne.jp/entry/jsonlite/?url='

    document.body.insertAdjacentHTML('beforeend', `
&amp;lt;style&amp;gt;
[data-metabu] {
	background-color: rgba(0,0,0,0.05);
}
[data-metabu].focus {
	outline:dotted 1px;
}
#metahatebu-popover{
    inset: auto 0 0 auto;
    opacity: 0.5;
    border: none;
    background-color: #000;
    color: #fff;
    position: fixed;
}
&amp;lt;/style&amp;gt;
&amp;lt;dialog popover id=&amp;quot;metahatebu-popover&amp;quot;&amp;gt;メタブあります&amp;lt;button data-metabuprev&amp;gt;前&amp;lt;/button&amp;gt;&amp;lt;button data-metabunext&amp;gt;次&amp;lt;/button&amp;gt;&amp;lt;/dialog&amp;gt;
    `)
    document.querySelector('.entry-comments').insertAdjacentHTML('beforeend', `
&amp;lt;div class=&amp;quot;entry-comment-contents&amp;quot; id=&amp;quot;upStairsSeat&amp;quot;&amp;gt;&amp;lt;/div&amp;gt;
    `)

    // メタブありますポップオーバーのイベント設定
    const metahatebuPopover = document.getElementById('metahatebu-popover');
    metahatebuPopover.addEventListener('click', ((i = -1) =&amp;gt; event =&amp;gt; {
        const metabues = document.querySelectorAll('[data-metabu]');
        if (event.target.matches('[data-metabuprev]')) i--;
        if (event.target.matches('[data-metabunext]')) i++;
        i = metabues.length ? (i + metabues.length) % metabues.length : 0;
        metabues[i].scrollIntoView({ behavior: &amp;quot;smooth&amp;quot;, block: &amp;quot;end&amp;quot;, inline: &amp;quot;nearest&amp;quot; });
        metabues.forEach((metabu, j) =&amp;gt; metabu.classList.toggle('focus', i == j));
    })())

    // ポップオーバーフォールバック
    const metahatebuPopoverOpen = () =&amp;gt; {
        if (HTMLElement.showPopover) {
            metahatebuPopover.showPopover()
        } else {
            metahatebuPopover.show()
        }
    }

    // ブクマ展開（x-template再利用）
    const addBookmark = function (targetElement, bookmark, eid) {
        document.querySelector(`[href=&amp;quot;/entry/${eid}/comment/${bookmark.user}&amp;quot;]`)?.closest('.entry-comment-contents &amp;gt; .entry-comment-contents').remove();
        targetElement.insertAdjacentHTML(
            'beforeend',
            document.getElementById('autoloader-bookmark-item').textContent
                .replaceAll('&amp;lt;div class=&amp;quot;entry-comment-contents ', '&amp;lt;div data-metabu=&amp;quot;metabu&amp;quot; class=&amp;quot;entry-comment-contents ')
                .replaceAll('{{user_name}}', bookmark.user)
                .replaceAll('{{bookmarked_url}}', bookmark.url)
                .replaceAll('{{user_page_path}}', `/${bookmark.user}/`)
                .replaceAll('{{ sort }}', `recent`)
                .replaceAll('{{profile_image_url}}', `https://cdn.profile-image.st-hatena.com/users/${bookmark.user}/profile.png`)
                .replaceAll('{{ #is_public }}is-hidden{{ /is_public }}', `is-hidden`)
                .replaceAll('{{{comment_expanded}}}', bookmark.comment)
                .replaceAll('{{{tags}}}', `&amp;lt;li&amp;gt;${bookmark.tags.join('&amp;lt;li&amp;gt;')}`)
                .replaceAll('{{created}}', bookmark.timestamp)
                .replaceAll('{{comment_page_path}}', `/entry/${eid}/comment/${bookmark.user}`)
                .replaceAll('{{#should_nofollow}}nofollow{{/should_nofollow}}', 'nofollow')
                .replaceAll('{{#enable_button}} is-enabled{{/enable_button}}', 'is-enabled')

        )
        metahatebuPopoverOpen()
    }

    // 2階ブクマAPIコール
    const targetURLs = [location.href], upstairsBookmarksList = []
    for (const targetURL of targetURLs) {
        const { bookmarks, entry_url, eid } = (await (await fetch(`${APIURL}${encodeURIComponent(targetURL)}`)).json()) ?? { entry_url: null }
        if (!entry_url) continue
        targetURLs.push(entry_url)
        upstairsBookmarksList.push([bookmarks, eid])
    }

    // 2階ブクマをHTMLに展開
    function addUpstairsBookmark(targetElements) {
        if (upstairsBookmarksList.length) metahatebuPopoverOpen()
        upstairsBookmarksList.forEach(upstairsBookmarks =&amp;gt; {
            const [bookmarks, eid] = upstairsBookmarks;
            upstairsBookmarks[0] = bookmarks.filter(bookmark =&amp;gt; {
                const targetUserBookmark = targetElements.find(element =&amp;gt; element.dataset?.userName === bookmark.user)
                if (!targetUserBookmark) {
                    const targetElement = document.getElementById('upStairsSeat');
                    addBookmark(targetElement, bookmark, eid);
                    return true // 遅延読み込み後に再処理するかもしれないのでリストに残す
                }
                const targetElement = [targetUserBookmark, ...targetUserBookmark.querySelectorAll(`.entry-comment-contents[data-user-name=&amp;quot;${bookmark.user}&amp;quot;]`)].pop()
                addBookmark(targetElement, bookmark, eid)
                return false // 遅延読み込み後に再処理しないのでリストから削除する
            })
        })
    }

    // メタブをHTMLに展開
    function addMetaBookmark(targetElements) {
        targetElements.forEach(async element =&amp;gt; {
            const targetURL = element.querySelector('[data-gtm-label=&amp;quot;entry-recent-permalink&amp;quot;]')?.href
            if (!targetURL) return undefined
            const { bookmarks, entry_url, eid } = (await (await fetch(`${APIURL}${encodeURIComponent(targetURL)}`)).json()) ?? { entry_url: null }
            if (!entry_url) return undefined
            bookmarks.forEach(
                bookmark =&amp;gt; {
                    addBookmark(element, bookmark, eid)
                }
            )
        })
    }

    // 初回呼び出し
    addUpstairsBookmark(Array.from(document.querySelectorAll(`.js-bookmarks-recent [data-user-name]`)))
    addMetaBookmark(Array.from(document.querySelectorAll(`.js-bookmarks-recent [data-user-name]`)))

    // ブクマ遅延読み込み監視
    const targetNode = document.querySelector('.js-bookmarks-recent');

    const upstairsBookmarkMutationConfig = { childList: true };
    const upstairsBookmarkMutationCallback = function (mutationsList, observer) {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                addUpstairsBookmark(Array.from(mutation.addedNodes).filter(node =&amp;gt; node.dataset?.userName))
            }
        }
    };
    const upstairsBookmarkMutationObserver = new MutationObserver(upstairsBookmarkMutationCallback);
    upstairsBookmarkMutationObserver.observe(targetNode, upstairsBookmarkMutationConfig);

    const metaBookmarkMutationConfig = { childList: true, subtree: true };
    const metaBookmarkMutationCallback = function (mutationsList, observer) {
        for (const mutation of mutationsList) {
            if (mutation.type === 'childList') {
                addMetaBookmark(Array.from(mutation.addedNodes).filter(node =&amp;gt; node.dataset?.userName))
            }
        }
    };
    const metaBookmarkMutationObserver = new MutationObserver(metaBookmarkMutationCallback);
    metaBookmarkMutationObserver.observe(targetNode, metaBookmarkMutationConfig);

})()

&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/kLOm3rHEgeAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/kLOm3rHEgeAA</link>
    <dc:date>2024-03-12T03:15:07Z</dc:date>
    <description>Pocket のリンクから ?utm_source=pocket_saves などを外します。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] Pocket のトラッキングURLパラメータを外す</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2FLhankor_Mhy%2Flet%2FkLOm3rHEgeAA.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;Pocket のトラッキングURLパラメータを外す&lt;/a&gt;&lt;pre&gt;// ==UserScript==
// @name         Pocket のトラッキングURLパラメータを外す
// @title        Pocket のトラッキングURLパラメータを外す
// @namespace    https://let.hatelabo.jp/Lhankor_Mhy/let/kLOm3rHEgeAA
// @version      0.1.2
// @description  Pocket のリンクから ?utm_source=pocket_saves などを外します。
// @author       Lhankor_Mhy
// @license      CC0
// @match        https://getpocket.com/*
// @icon         https://www.google.com/s2/favicons?sz=64&amp;amp;domain=getpocket.com
// @run-at       document-idle
// @grant        none
// ==/UserScript==

{
    let timerId;
    new MutationObserver((mutationList, observer) =&amp;gt; {
        mutationList.forEach((mutation) =&amp;gt; {
            switch (mutation.type) {
                case &amp;quot;childList&amp;quot;:
                    clearTimeout(timerId);
                    timerId = setTimeout(omitTrackingParameter, 500)
                    break;
            }
        });
    }).observe(document.body, {
        childList: true,
        subtree: true,
    });
    const omitTrackingParameter = () =&amp;gt;
        document.querySelectorAll('a:where([data-testid=&amp;quot;image-link&amp;quot;],[data-testid=&amp;quot;content-block&amp;quot;],[data-testid=&amp;quot;view-original&amp;quot;],[data-testid=&amp;quot;publisher-link&amp;quot;])').forEach(el =&amp;gt; {
            const url = new URL(el.href);
            const searchPrams = url.searchParams;
            searchPrams.delete('utm_source');
            url.search = searchPrams.toString();
            el.href = url.href;
        })
}&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/kOGSsI-SgsAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/kOGSsI-SgsAA</link>
    <dc:date>2024-02-15T08:44:55Z</dc:date>
    <description>canonical URLではない場合にページ移動します。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] canonical URL に移動</title>
    <content:encoded>&lt;a href="javascript:%7Bconst%20canonical%3Ddocument.querySelector%28%27%5Brel%3Dcanonical%5D%27%29.href%3Bif%28location.href%21%3D%3Dcanonical%29location.href%3Dcanonical%3Bvoid%200%7D"&gt;canonical URL に移動&lt;/a&gt;&lt;pre&gt;/*
 * @title canonical URL に移動
 * @description canonical URLではない場合にページ移動します。
 * @include http://*
 * @license CC0
 * @javascript_url 
 */

{
    const canonical = document.querySelector('[rel=canonical]').href;
    if (location.href !== canonical) location.href = canonical;
    void 0;
}
&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/kNe6m5vsgKAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/kNe6m5vsgKAA</link>
    <dc:date>2024-01-31T08:34:19Z</dc:date>
    <description>はてなグリーンスターに縁をつけます。via: https://b.hatena.ne.jp/entry/4748592896526814671/comment/murlock</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] はてなグリーンスターに縁をつける</title>
    <content:encoded>&lt;a href="javascript:%7Blet%20timerId%3Bnew%20MutationObserver%28%28%28mutationList%2Cobserver%29%3D%3E%7BmutationList.forEach%28%28mutation%3D%3E%7Bswitch%28mutation.type%29%7Bcase%22childList%22%3AclearTimeout%28timerId%29%3BtimerId%3DsetTimeout%28replaceGreenStar%2C500%29%3Bbreak%7D%7D%29%29%7D%29%29.observe%28document.body%2C%7BchildList%3Atrue%2Csubtree%3Atrue%7D%29%3Bconst%20replaceGreenStar%3D%28%29%3D%3E%7Bdocument.querySelectorAll%28%27.hatena-star-star.green%20span%27%29%3F.forEach%28%28e%3D%3Ee.style.backgroundImage%3D%60url%28%22data%3Aimage%2Fsvg%2Bxml%2C%253Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20width%3D%2711%27%20height%3D%2710.299%27%20viewBox%3D%270%200%2011%2010.299%27%253E%253Cpath%20d%3D%27M-4785.954%2C1552.838l2.935%2C2.125-1.127%2C3.381a.352.352%2C0%2C0%2C0%2C.538.393l2.815-1.961h0l.2-.14%2C3.009%2C2.1a.353.353%2C0%2C0%2C0%2C.533-.4l-1.036-3.128v0l-.079-.24.2-.15%2C0%2C0%2C2.712-1.971a.352.352%2C0%2C0%2C0-.207-.638h-3.651l-.079-.238%2C0%2C0-1.075-3.218a.352.352%2C0%2C0%2C0-.667-.005l-1.167%2C3.464h-3.653A.353.353%2C0%2C0%2C0-4785.954%2C1552.838Z%27%20transform%3D%27translate%284786.096%20-1548.503%29%27%20fill%3D%27%252300d200%27%20stroke%3D%27%2523000%27%2F%253E%253C%2Fsvg%253E%22%29%60%29%29%7D%3BreplaceGreenStar%28%29%7D"&gt;はてなグリーンスターに縁をつける&lt;/a&gt;&lt;pre&gt;// ==UserScript==
// @name         はてなグリーンスターに縁をつける
// @title        はてなグリーンスターに縁をつける
// @namespace    https://let.hatelabo.jp/Lhankor_Mhy/let/kNe6m5vsgKAA
// @version      2024-01-31
// @description  はてなグリーンスターに縁をつけます。via: https://b.hatena.ne.jp/entry/4748592896526814671/comment/murlock
// @author       Lhankor_Mhy
// @match        https://b.hatena.ne.jp/entry/*
// @match        https://b.hatena.ne.jp/*/bookmark
// @icon         https://b.hatena.ne.jp/favicon.ico
// @license      CC0
// @noframes
// @grant        none
// @javascript_url
// ==/UserScript==

{
    let timerId;
    new MutationObserver((mutationList, observer) =&amp;gt; {
        mutationList.forEach((mutation) =&amp;gt; {
            switch (mutation.type) {
                case &amp;quot;childList&amp;quot;:
                    clearTimeout(timerId);
                    timerId = setTimeout(replaceGreenStar, 500)
                    break;
            }
        });
    }).observe(document.body, {
        childList: true,
        subtree: true,
    });

    const replaceGreenStar = () =&amp;gt; {
        document.querySelectorAll('.hatena-star-star.green span')?.forEach(e =&amp;gt;e.style.backgroundImage = `url(&amp;quot;data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='11' height='10.299' viewBox='0 0 11 10.299'%3E%3Cpath d='M-4785.954,1552.838l2.935,2.125-1.127,3.381a.352.352,0,0,0,.538.393l2.815-1.961h0l.2-.14,3.009,2.1a.353.353,0,0,0,.533-.4l-1.036-3.128v0l-.079-.24.2-.15,0,0,2.712-1.971a.352.352,0,0,0-.207-.638h-3.651l-.079-.238,0,0-1.075-3.218a.352.352,0,0,0-.667-.005l-1.167,3.464h-3.653A.353.353,0,0,0-4785.954,1552.838Z' transform='translate(4786.096 -1548.503)' fill='%2300d200' stroke='%23000'/%3E%3C/svg%3E&amp;quot;)`)
    }
    replaceGreenStar();
}

&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/j9W6maaGgKAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/j9W6maaGgKAA</link>
    <dc:date>2023-07-13T08:46:09Z</dc:date>
    <description>https://teratail.com/questions/ncsqe99mif6af6#reply-2mcicqlromm4lp</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] test bookmarklet</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2FLhankor_Mhy%2Flet%2Fj9W6maaGgKAA.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;test bookmarklet&lt;/a&gt;&lt;pre&gt;/*
 * @title test bookmarklet
 * @description https://teratail.com/questions/ncsqe99mif6af6#reply-2mcicqlromm4lp
 * @include http://*
 * @license MIT License
 * @require 
 */


void document.addEventListener('click',e=&amp;gt;alert(`${e.clientX},${e.clientY}`),{once:true})&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/j9W5qIj-gKAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/j9W5qIj-gKAA</link>
    <dc:date>2023-07-13T08:30:41Z</dc:date>
    <description>https://teratail.com/questions/ncsqe99mif6af6</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] test bookmarklet</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2FLhankor_Mhy%2Flet%2Fj9W5qIj-gKAA.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;test bookmarklet&lt;/a&gt;&lt;pre&gt;/*
 * @title test bookmarklet
 * @description https://teratail.com/questions/ncsqe99mif6af6
 * @include http://*
 * @license MIT License
 * @require 
 */



void document.elementFromPoint(400,0).click()
&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/j7qesMCUgYAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/j7qesMCUgYAA</link>
    <dc:date>2023-06-03T03:09:48Z</dc:date>
    <description>メタブタイトルが「...のコメント」となってしまうところを、元ページのタイトルに変更する。自分が公開ブクマをしていることが条件。ブクマ後リロード推奨。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] コメントメタブタイトル修正</title>
    <content:encoded>&lt;a href="javascript:void%28async%28%29%3D%3E%7Bif%28%21document.querySelector%28%27.entry-edit%27%29%29%7Balert%28%27%E5%85%AC%E9%96%8B%E3%83%96%E3%82%AF%E3%83%9E%E3%81%95%E3%82%8C%E3%81%A6%E3%81%84%E3%81%AA%E3%81%84%E3%82%88%E3%81%86%E3%81%AA%E3%81%AE%E3%81%A7%E5%A4%89%E6%9B%B4%E3%81%A7%E3%81%8D%E3%81%BE%E3%81%9B%E3%82%93%EF%BC%88%E3%83%96%E3%82%AF%E3%83%9E%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B%E5%A0%B4%E5%90%88%E3%81%AF%E3%83%AA%E3%83%AD%E3%83%BC%E3%83%89%E3%82%92%E3%81%97%E3%81%A6%E3%81%BF%E3%82%8B%E3%81%A8%E3%81%84%E3%81%84%E3%81%8B%E3%82%82%EF%BC%89%27%29%3Breturn%7D%7Bconst%20regexpEscape%3Ds%3D%3Es.replace%28%2F%5B%5C%5C%5E%24.%2A%2B%3F%28%29%5B%5C%5D%7B%7D%7C%5D%2Fg%2C%27%5C%5C%24%26%27%29%3Bconst%20regexp%3Dnew%20RegExp%28regexpEscape%28String.raw%60https%3A%2F%2Fb.hatena.ne.jp%2Fentry%2F%60%29%2BString.raw%60%5Cd%2B%2Fcomment%2F%60%29%3Bif%28%21regexp.test%28document.documentElement.dataset.entryUrl%29%29if%28%21confirm%28%27%E3%82%B3%E3%83%A1%E3%83%B3%E3%83%88%E3%83%A1%E3%82%BF%E3%83%96%E3%81%A7%E3%81%AF%E3%81%AA%E3%81%95%E3%81%9D%E3%81%86%E3%81%A7%E3%81%99%E3%81%8C%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%BE%E3%81%99%E3%81%8B%EF%BC%9F%27%29%29return%7Dconst%20pageTitle%3D%28new%20DOMParser%29.parseFromString%28await%28await%20fetch%28document.documentElement.dataset.entryUrl%29%29.text%28%29%2C%22text%2Fhtml%22%29.querySelector%28%27title%27%29.textContent%3Bif%28%21confirm%28%60%E3%82%BF%E3%82%A4%E3%83%88%E3%83%AB%E3%82%92%22%24%7BpageTitle%7D%22%E3%81%AB%E5%A4%89%E6%9B%B4%E3%81%97%E3%81%BE%E3%81%99%60%29%29return%3Bdocument.querySelector%28%27.entry-editModal-textInput%27%29.value%3DpageTitle%3Bdocument.querySelector%28%27.entry-editModal-decide%27%29.click%28%29%7D%29%28%29%3B"&gt;コメントメタブタイトル修正&lt;/a&gt;&lt;pre&gt;/*
 * @title コメントメタブタイトル修正
 * @description メタブタイトルが「...のコメント」となってしまうところを、元ページのタイトルに変更する。自分が公開ブクマをしていることが条件。ブクマ後リロード推奨。
 * @include https://b.hatena.ne.jp/entry/*comment/*
 * @license CC0
 * @javascript_url
 */


void (async () =&amp;gt; {
    if (!document.querySelector('.entry-edit')) {
        alert('公開ブクマされていないようなので変更できません（ブクマしている場合はリロードをしてみるといいかも）')
        return;
    }
    {
        const regexpEscape = s =&amp;gt; s.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&amp;amp;')
        const regexp = new RegExp(regexpEscape(String.raw`https://b.hatena.ne.jp/entry/`) + String.raw`\d+/comment/`)
        if (!regexp.test(document.documentElement.dataset.entryUrl)) if (!confirm('コメントメタブではなさそうですがタイトル変更しますか？')) return;
    }

    const pageTitle = new DOMParser().parseFromString(await (await fetch(document.documentElement.dataset.entryUrl)).text(), &amp;quot;text/html&amp;quot;).querySelector('title').textContent
    if (!confirm(`タイトルを&amp;quot;${pageTitle}&amp;quot;に変更します`)) return;

    document.querySelector('.entry-editModal-textInput').value = pageTitle
    document.querySelector('.entry-editModal-decide').click()
})()


&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jr-yw7yCgMAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jr-yw7yCgMAA</link>
    <dc:date>2022-11-22T06:18:45Z</dc:date>
    <description>比較したいブコメページを入力→コメントを比較したテキストをはてな記法で出力</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] 2つのブコメを比較（はてな記法版）</title>
    <content:encoded>&lt;a href="javascript:%28async%28%29%3D%3E%7Bconst%20regexpEscape%3Ds%3D%3Es.replace%28%2F%5B%5C%5C%5E%24.%2A%2B%3F%28%29%5B%5C%5D%7B%7D%7C%5D%2Fg%2C%27%5C%5C%24%26%27%29%3Bconst%20regexp%3Dnew%20RegExp%28regexpEscape%28%22https%3A%2F%2Fb.hatena.ne.jp%2Fentry%2F%22%29%2B%22%28s%2F%29%2A%28.%2B%29%22%29%3Bconst%20BtoURL%3Ds%3D%3Es.replace%28regexp%2C%28%28_%2Cp1%2Cp2%29%3D%3E%28p1%3F%22https%3A%2F%2F%22%3A%22http%3A%2F%2F%22%29%2Bp2%29%29%3Bconst%7Bbookmarks%3Abookmarks%2Ceid%3Aeid%7D%3Dawait%28await%20fetch%28%27https%3A%2F%2Fb.hatena.ne.jp%2Fentry%2Fjsonlite%2F%3Furl%3D%27%2BencodeURIComponent%28BtoURL%28prompt%28%27%E6%AF%94%E8%BC%83%E3%83%96%E3%82%AF%E3%83%9EURL%27%2C%27%27%29%29%29%29%29.json%28%29%3Bconst%7Bbookmarks%3AorigBookmarks%2Ceid%3AorigEid%7D%3Dawait%28await%20fetch%28%27https%3A%2F%2Fb.hatena.ne.jp%2Fentry%2Fjsonlite%2F%3Furl%3D%27%2BencodeURIComponent%28BtoURL%28location.href%29%29%29%29.json%28%29%3Bconst%20html%3Dbookmarks.flatMap%28%28bookmark%3D%3E%7Bconst%20origBookmark%3DorigBookmarks.find%28%28origBookmark%3D%3EorigBookmark.user%3D%3D%3Dbookmark.user%29%29%3Bif%28%21origBookmark%29return%5B%5D%3Breturn%5B%60%5Cn%3Cpre%3E%5Cn%2A%20%24%7Bbookmark.user%7D%5Cn%3E%3E%5Cn%24%7Bbookmark.comment%7D%5Cnhttps%3A%2F%2Fb.hatena.ne.jp%2Fentry%2F%24%7Beid%7D%2Fcomment%2F%24%7Bbookmark.user%7D%5Cn%3C%3C%5Cn%3E%3E%5Cn%24%7BorigBookmark.comment%7D%5Cnhttps%3A%2F%2Fb.hatena.ne.jp%2Fentry%2F%24%7BorigEid%7D%2Fcomment%2F%24%7BorigBookmark.user%7D%5Cn%3C%3C%5Cn%3C%2Fpre%3E%5Cn%20%20%20%20%20%20%20%20%60%5D%7D%29%29.join%28%27%27%29%3Bconst%20blob%3Dnew%20Blob%28%5Bhtml%5D%2C%7Btype%3A%22text%2Fhtml%3Bcharset%3Dutf-8%22%7D%29%3Bconst%20url%3DURL.createObjectURL%28blob%29%3Bwindow.open%28url%29%3BURL.revokeObjectURL%28url%29%7D%29%28%29%3B"&gt;2つのブコメを比較（はてな記法版）&lt;/a&gt;&lt;pre&gt;/*
 * @title 2つのブコメを比較（はてな記法版）
 * @description 比較したいブコメページを入力→コメントを比較したテキストをはてな記法で出力
 * @include https://b.hatena.ne.jp/entry/*
 * @license CC0
 * @javascript_url
 */

(async () =&amp;gt; {
    const regexpEscape = s =&amp;gt; s.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&amp;amp;')
    const regexp = new RegExp(regexpEscape(&amp;quot;https://b.hatena.ne.jp/entry/&amp;quot;) + &amp;quot;(s/)*(.+)&amp;quot;)
    const BtoURL = s =&amp;gt; s.replace(regexp, (_, p1, p2) =&amp;gt; (p1 ? &amp;quot;https://&amp;quot; : &amp;quot;http://&amp;quot;) + p2)

    const { bookmarks, eid } = (await (await fetch('https://b.hatena.ne.jp/entry/jsonlite/?url=' + encodeURIComponent(BtoURL(prompt('比較ブクマURL', ''))))).json())
    const { bookmarks: origBookmarks, eid: origEid } = (await (await fetch('https://b.hatena.ne.jp/entry/jsonlite/?url=' + encodeURIComponent(BtoURL(location.href)))).json())

    const html = bookmarks.flatMap(bookmark =&amp;gt; {
        const origBookmark = origBookmarks.find(origBookmark=&amp;gt;origBookmark.user===bookmark.user)
        if (!origBookmark) return []
        return [`
&amp;lt;pre&amp;gt;
* ${bookmark.user}
&amp;gt;&amp;gt;
${bookmark.comment}
https://b.hatena.ne.jp/entry/${eid}/comment/${bookmark.user}
&amp;lt;&amp;lt;
&amp;gt;&amp;gt;
${origBookmark.comment}
https://b.hatena.ne.jp/entry/${origEid}/comment/${origBookmark.user}
&amp;lt;&amp;lt;
&amp;lt;/pre&amp;gt;
        `]
    }).join('')   

    const blob = new Blob([html], { type: &amp;quot;text/html;charset=utf-8&amp;quot; })
    const url = URL.createObjectURL(blob)
    window.open(url)
    URL.revokeObjectURL(url)
})()&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jLrKiqvEgoAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jLrKiqvEgoAA</link>
    <dc:date>2022-11-18T09:09:55Z</dc:date>
    <description>比較したいブコメページを入力→コメントがユーザーごとに並ぶ</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] 2つのブコメを比較</title>
    <content:encoded>&lt;a href="javascript:%28async%28%29%3D%3E%7Bdocument.documentElement.scrollTop%3Ddocument.documentElement.scrollHeight%3Bconst%20regexpEscape%3Ds%3D%3Es.replace%28%2F%5B%5C%5C%5E%24.%2A%2B%3F%28%29%5B%5C%5D%7B%7D%7C%5D%2Fg%2C%27%5C%5C%24%26%27%29%3Bconst%20regexp%3Dnew%20RegExp%28regexpEscape%28%22https%3A%2F%2Fb.hatena.ne.jp%2Fentry%2F%22%29%2B%22%28s%2F%29%2A%28.%2B%29%22%29%3Bconst%20BtoURL%3Ds%3D%3Es.replace%28regexp%2C%28%28_%2Cp1%2Cp2%29%3D%3E%28p1%3F%22https%3A%2F%2F%22%3A%22http%3A%2F%2F%22%29%2Bp2%29%29%3Bconst%7Bbookmarks%3Abookmarks%2Ceid%3Aeid%7D%3Dawait%28await%20fetch%28%27https%3A%2F%2Fb.hatena.ne.jp%2Fentry%2Fjsonlite%2F%3Furl%3D%27%2BencodeURIComponent%28BtoURL%28prompt%28%27%E6%AF%94%E8%BC%83%E3%83%96%E3%82%AF%E3%83%9EURL%27%2C%27%27%29%29%29%29%29.json%28%29%3Bbookmarks.forEach%28%28bookmark%3D%3E%7Bconst%20targetElement%3Ddocument.querySelector%28%60.is-active.bookmarks-sort-panel%20%5Bdata-user-name%3D%22%24%7Bbookmark.user%7D%22%5D%20.entry-comment-text%60%29%3BtargetElement%3F.insertAdjacentHTML%3F.%28%27beforeend%27%2C%60%3Ca%20href%3D%22%2Fentry%2F%24%7Beid%7D%2Fcomment%2F%24%7Bbookmark.user%7D%22%20class%3D%22entry-comment-text%20js-bookmark-comment%22%20target%3D%22_blank%22%20style%3D%22display%3Ablock%3Bbackground-color%3Awheat%22%3E%24%7Bbookmark.comment%7D%3C%2Fa%3E%60%29%7D%29%29%7D%29%28%29%3B"&gt;2つのブコメを比較&lt;/a&gt;&lt;pre&gt;/*
 * @title 2つのブコメを比較
 * @description 比較したいブコメページを入力→コメントがユーザーごとに並ぶ
 * @include https://b.hatena.ne.jp/entry/*
 * @license CC0
 * @javascript_url
 */

(async () =&amp;gt; {
    document.documentElement.scrollTop = document.documentElement.scrollHeight
    const regexpEscape = s =&amp;gt; s.replace(/[\\^$.*+?()[\]{}|]/g, '\\$&amp;amp;')
    const regexp = new RegExp(regexpEscape(&amp;quot;https://b.hatena.ne.jp/entry/&amp;quot;) + &amp;quot;(s/)*(.+)&amp;quot;)
    const BtoURL = s =&amp;gt; s.replace(regexp, (_, p1, p2) =&amp;gt; (p1 ? &amp;quot;https://&amp;quot; : &amp;quot;http://&amp;quot;) + p2)

    const {bookmarks,eid} = (await (await fetch('https://b.hatena.ne.jp/entry/jsonlite/?url=' + encodeURIComponent(BtoURL(prompt('比較ブクマURL', ''))))).json())

    bookmarks.forEach(bookmark =&amp;gt; {
        const targetElement = document.querySelector(`.is-active.bookmarks-sort-panel [data-user-name=&amp;quot;${bookmark.user}&amp;quot;] .entry-comment-text`)
        targetElement?.insertAdjacentHTML?.('beforeend', `&amp;lt;a href=&amp;quot;/entry/${eid}/comment/${bookmark.user}&amp;quot; class=&amp;quot;entry-comment-text js-bookmark-comment&amp;quot; target=&amp;quot;_blank&amp;quot; style=&amp;quot;display:block;background-color:wheat&amp;quot;&amp;gt;${bookmark.comment}&amp;lt;/a&amp;gt;`)
    })
})()
&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jo3aqcTggKAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jo3aqcTggKAA</link>
    <dc:date>2022-09-22T04:46:28Z</dc:date>
    <description>なんか、パーセントエンコーディングがアレ←プロトコルでリダイレクトされてた</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] Amazon から Kinoppy</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2FLhankor_Mhy%2Flet%2Fjo3aqcTggKAA.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;Amazon から Kinoppy&lt;/a&gt;&lt;pre&gt;/*
 * @title Amazon から Kinoppy
 * @description なんか、パーセントエンコーディングがアレ←プロトコルでリダイレクトされてた
 * @include http://*
 * @license MIT License
 * @require 
 */


void (
//  location.href=&amp;quot;https://www.kinokuniya.co.jp/disp/CSfDispListPage_001.jsp?qs=true&amp;amp;ptk=01&amp;amp;q=&amp;quot;+JSON.parse(document.querySelector('[data-show-all-offers-display]').dataset.showAllOffersDisplay).asin
  location.href=&amp;quot;https://www.kinokuniya.co.jp/disp/CSfDispListPage_001.jsp?qs=true&amp;amp;ptk=03&amp;amp;q=&amp;quot;+encodeURIComponent(productTitle.textContent.trim())
)&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/hLHVoNuA3dNN">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/hLHVoNuA3dNN</link>
    <dc:date>2022-09-07T02:04:29Z</dc:date>
    <description>エントリページで動作します。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] 俺にスターつけてくれた人のブコメはどれ？</title>
    <content:encoded>&lt;a href="javascript:document.querySelector%28%27.is-my-bookmark%20.hatena-star-inner-count%27%29%3F.click%3F.%28%29%3Bvoid%20setTimeout%28%28%28%29%3D%3E%7Bdocument.querySelectorAll%28%27.is-my-bookmark%20.hatena-star-star%27%29.forEach%28%28function%28e%29%7Bconst%20targetUserName%3De.href.split%28%27%2F%27%29%5B3%5D%3Bconsole.log%28targetUserName%29%3Bvar%20target%3Ddocument.querySelectorAll%28%60.js-bookmarks-sort-panels%20%5Bdata-user-name%3D%24%7BtargetUserName%7D%5D%60%29%3Bif%28target%29target.forEach%28%28el%3D%3Eel.style.backgroundColor%3D%27%23ff9%27%29%29%7D%29%29%7D%29%2C2e3%29%3B"&gt;俺にスターつけてくれた人のブコメはどれ？&lt;/a&gt;&lt;pre&gt;/*
 * @title 俺にスターつけてくれた人のブコメはどれ？
 * @description エントリページで動作します。
 * @include http://http://b.hatena.ne.jp/entry/*
 * @license MIT License
 * @javascript_url 
 */

document.querySelector('.is-my-bookmark .hatena-star-inner-count')?.click?.()
void setTimeout(()=&amp;gt;{
  document.querySelectorAll('.is-my-bookmark .hatena-star-star').forEach(function(e){
    const targetUserName = e.href.split('/')[3]
    console.log(targetUserName)
    var target = document.querySelectorAll(`.js-bookmarks-sort-panels [data-user-name=${targetUserName}]`)
    if (target) target.forEach(el=&amp;gt;el.style.backgroundColor = '#ff9')
  })
},2000)&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jPCIrOH0gcAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jPCIrOH0gcAA</link>
    <dc:date>2022-01-04T04:20:31Z</dc:date>
    <description>テーブルクリックでCSVとしてダウンロード</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] Table to CSV</title>
    <content:encoded>&lt;a href="javascript:%7Bconst%20target%3Ddocument.querySelectorAll%28%27table%27%29%3Bconst%20dl%3Devent%3D%3E%7Bconst%20bom%3Dnew%20Uint8Array%28%5B239%2C187%2C191%5D%29%3Bconsole.log%28event.currentTarget%29%3Bconst%20a%3Ddocument.createElement%28%27a%27%29%3Ba.download%3D%27test.csv%27%3Ba.href%3DURL.createObjectURL%28new%20Blob%28%5Bbom%2CArray.from%28event.currentTarget.querySelectorAll%28%60tr%60%29%29.map%28%28r%3D%3E%5B...r.children%5D.map%28%28c%3D%3E%60%22%24%7Bc.innerText%7D%22%60%29%29.join%28%27%2C%27%29%29%29.join%28%27%5Cn%27%29%5D%2C%7Btype%3A%22text%2Fcsv%22%7D%29%29%3Ba.click%28%29%3BremoveEvent%28%29%7D%3Btarget.forEach%28%28table%3D%3E%7Btable.addEventListener%28%27click%27%2Cdl%29%7D%29%29%3Bconst%20removeEvent%3D%28%29%3D%3E%7Btarget.forEach%28%28table%3D%3E%7Btable.removeEventListener%28%27click%27%2Cdl%29%7D%29%29%7D%3Balert%28%27%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB%E3%82%92%E3%82%AF%E3%83%AA%E3%83%83%E3%82%AF%E3%81%97%E3%81%A6%E3%81%8F%E3%81%A0%E3%81%95%E3%81%84%27%29%7D"&gt;Table to CSV&lt;/a&gt;&lt;pre&gt;/*
 * @title Table to CSV
 * @description テーブルクリックでCSVとしてダウンロード
 * @include http://*
 * @license public domain
 * @javascript_url
 */


{
    const target = document.querySelectorAll('table');
    
    const dl = event =&amp;gt; {
        const bom = new Uint8Array([0xef, 0xbb, 0xbf]);
        console.log(event.currentTarget)
        const a = document.createElement('a');
        a.download = 'test.csv';
        a.href = URL.createObjectURL(
            new Blob([
                bom,
                Array.from(event.currentTarget.querySelectorAll(`tr`)).map(
                    r =&amp;gt; [...r.children].map(c =&amp;gt; `&amp;quot;${c.innerText}&amp;quot;`).join(',')
                ).join('\n')
            ],
                { type: &amp;quot;text/csv&amp;quot; }
            )
        )
        a.click();
        removeEvent();
    }

    target.forEach(table =&amp;gt; {
        table.addEventListener('click', dl)
    });
    
    const removeEvent = ()=&amp;gt;{
        target.forEach(table=&amp;gt;{
            table.removeEventListener('click', dl);
        })
    }
    alert('テーブルをクリックしてください')

}&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/jIKH0YzigMAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/jIKH0YzigMAA</link>
    <dc:date>2021-07-17T07:08:16Z</dc:date>
    <description>teratailのNG回答者リストをローカルに保存して、質問を見えなくする</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] teratail NG</title>
    <content:encoded>&lt;a href="javascript:%22https%3A%2F%2Flet.st-hatelabo.com%2FLhankor_Mhy%2Flet%2FjIKH0YzigMAA.bookmarklet.js%20%28arg%29%22.replace%28%2F%28%5CS%2B%29%5Cs%2B%28%5CS%2A%29%2F%2Cfunction%28s%2Curl%2Carg%29%7Bs%3Ddocument.createElement%28%22script%22%29%3Bs.charset%3D%22utf-8%22%3Bs.src%3Durl%2B%22%3Fs%3D%22%2BencodeURIComponent%28arg%29%3Bdocument.body.appendChild%28s%29%7D%29%3Bvoid%280%29%3B"&gt;teratail NG&lt;/a&gt;&lt;pre&gt;// ==UserScript==
// @title        teratail NG
// @name         teratail NG
// @namespace    http://let.hatelabo.jp/Lhankor_Mhy/let/jIKH0YzigMAA
// @version      0.1
// @description  teratailのNG回答者リストをローカルに保存して、質問を見えなくする
// @author       Lhankor_Mhy
// @match        https://teratail.com/
// @match        https://teratail.com/feed/*
// @match        https://teratail.com/tags/*
// @match        https://teratail.com/questions/*
// @icon         https://www.google.com/s2/favicons?domain=teratail.com
// @license      public domain
// @grant        none
// ==/UserScript==

(function () {
  'use strict';

  // CONST
  const localStorageKey = '63cc7db5-31e8-7c4f-6dbb-2210c1c056de';
  //const headers = new Headers({ 'Authorization': 'Bearer [APIToken]' });
  const headers = {};

  // pushState hack
  const pushState = history.pushState.bind(history);
  history.pushState = (...arg) =&amp;gt; {
    document.querySelectorAll('.boxContentWrap')?.forEach?.(NGEraser);
    pushState(...arg);
  }

  // NGID リストを取得
  const NGIDs = new Set(JSON.parse(localStorage.getItem(localStorageKey)));


  // 質問ユーザを localStorage から取得して返す、なければ API を叩いて localStorage にセットして返す
  const getQuestionUser = async questionId =&amp;gt; {

    let questionUserName = localStorage.getItem(`${localStorageKey}${questionId}`);

    if (!questionUserName) {
      questionUserName = (
        await (
          await fetch(`https://teratail.com/api/v1/questions/${questionId}`, {
            headers
          })
        ).json()
      ).question?.user?.display_name;
      questionUserName ??= '退会済みユーザー'; // 退会済みユーザーはAPIが値を返さない
      localStorage.setItem(`${localStorageKey}${questionId}`, questionUserName);
    }

    return questionUserName;

  }

  // 質問一覧のメインループ
  const NGEraser = (element) =&amp;gt; {
    element.querySelectorAll('.C-questionFeedItem').forEach(async e =&amp;gt; {

      const txtUpdateGenre = e.querySelector('.txtUpdateGenre')?.textContent;
      const questionId = e.querySelector('[data-question-id]').dataset.questionId;
      const txtUserName = e.querySelector('.txtUserName .C-textLink')?.textContent?.trim?.();

      // ユーザ名がない場合はgetQuestionUser、ある場合で、「分前にコメント」などがあればgetQuestionUser、または「分前に質問」「分前に質問を編集」などでなければgetQuestionUser
      const userName = txtUserName &amp;amp;&amp;amp; (!txtUpdateGenre || txtUpdateGenre.includes('質問')) ?
        txtUserName :
        await getQuestionUser(questionId);

      // localStorage に退会済みユーザー名が残っていたら表示する
      if (e.querySelector('.txtUserName')?.textContent?.trim?.() === '退会済みユーザー' &amp;amp;&amp;amp; userName !== '退会済みユーザー') e.querySelector('.txtUserName').textContent += `質問ユーザー：${userName}`;

      changeNGView(userName, e);
    });
  }

  // ?えんがちょボタン
  const addToggleNG = (element) =&amp;gt; {
    const toggleNG = document.createElement('span');
    const userName = element.querySelector('.c-userName__link').textContent.trim();
    toggleNG.dataset.userName = userName;
    toggleNG.textContent = '?';
    toggleNG.style.cursor = 'pointer';
    toggleNG.style.border = &amp;quot;1px solid gray&amp;quot;;
    toggleNG.style.borderRadius = &amp;quot;3px&amp;quot;;
    toggleNG.style.background = &amp;quot;lightgray&amp;quot;;
    toggleNG.addEventListener('click', toggleNGListener(userName));

    element.insertAdjacentElement('beforeend', toggleNG)

    changeNGView(toggleNG.dataset.userName, toggleNG.parentElement);
  }

  // NGID表示トグル処理
  const changeNGView = (userName, element) =&amp;gt; {
    if (NGIDs.has(userName)) {
      element.style.opacity = &amp;quot;0.1&amp;quot;;
    } else {
      element.style.opacity = &amp;quot;&amp;quot;;
    }
  }

  // ?えんがちょボタンのリスナ
  const toggleNGListener = userName =&amp;gt; event =&amp;gt; {
    if (NGIDs.has(userName)) {
      NGIDs.delete(userName);
    } else {
      NGIDs.add(userName);
    }
    changeNGView(userName, event.target.parentElement);
    localStorage.setItem(localStorageKey, JSON.stringify([...NGIDs]));
  }

  // init
  document.querySelectorAll('.boxContentWrap')?.forEach?.(NGEraser);
  document.querySelectorAll('.p-questioner')?.forEach?.(addToggleNG);


  //TODO APIの例外処理　ユーザーページにえんがちょボタンいれる？　ユーザー名変更に対応するは無理かな？

})();&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/iuzX89CqgKAA">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/iuzX89CqgKAA</link>
    <dc:date>2020-11-27T06:03:31Z</dc:date>
    <description>プルリクできればいいんだけど……　とりあえずフォーク。</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] Disable contextmenu blocking</title>
    <content:encoded>&lt;a href="javascript:%5B%27contextmenu%27%2C%27selectstart%27%2C%27copy%27%5D.forEach%28%28ev%3D%3Ewindow.addEventListener%28ev%2C%28e%3D%3Ee.stopPropagation%28%29%29%2Ctrue%29%29%29%3Bvoid%28document.head.appendChild%28document.createElement%28%27style%27%29%29.textContent%3D%27%2A%20%7B%20user-select%3A%20initial%20%21important%20%7D%27%29%3B"&gt;Disable contextmenu blocking&lt;/a&gt;&lt;pre&gt;/*
 * @title Disable contextmenu blocking
 * @description プルリクできればいいんだけど……　とりあえずフォーク。
 * @include http://*
 * @license CC0 https://creativecommons.org/publicdomain/zero/1.0/
 * @javascript_url
 */

['contextmenu', 'selectstart', 'copy'].forEach(ev =&amp;gt; window.addEventListener(ev, e =&amp;gt; e.stopPropagation(), true));
void (document.head.appendChild(document.createElement('style')).textContent = '* { user-select: initial !important }');&lt;/pre&gt;</content:encoded>
  </item>
  <item rdf:about="https://let.hatelabo.jp/Lhankor_Mhy/let/g5G0hvbqmesR">
    <link>https://let.hatelabo.jp/Lhankor_Mhy/let/g5G0hvbqmesR</link>
    <dc:date>2020-10-13T07:29:12Z</dc:date>
    <description>ページ途中へのフラグメント付きURL（#xxx）が欲しい時に</description>
    <dc:creator>Lhankor_Mhy</dc:creator>
    <title>[Let] id属性がある要素の後ろにアンカーリンクをつける</title>
    <content:encoded>&lt;a href="javascript:%7Bconst%20pipe%3Dx%3D%3Ef%3D%3Ef%3Fpipe%28f%28x%29%29%3Ax%3Bconst%20%24attr%3Dattr%3D%3Eval%3D%3Ee%3D%3E%7Bif%28val%3D%3Dnull%29return%20e.getAttribute%28attr%29%3Be.setAttribute%28attr%2Cval%29%3Breturn%20e%7D%3Bdocument.querySelectorAll%28%27%5Bid%5D%27%29.forEach%28%28e%3D%3Epipe%28document.createElement%28%27a%27%29%29%28e.appendChild.bind%28e%29%29%28%24attr%28%27href%27%29%28%22%23%22%2Be.id%29%29%28%29.textContent%3D%27%C2%B6%27%29%29%3Bdocument.querySelectorAll%28%27%5Bname%5D%27%29.forEach%28%28e%3D%3Epipe%28document.createElement%28%27a%27%29%29%28e.appendChild.bind%28e%29%29%28%24attr%28%27href%27%29%28%22%23%22%2Be.name%29%29%28%29.textContent%3D%27%C2%B6%27%29%29%3Bvoid%200%7D"&gt;id属性がある要素の後ろにアンカーリンクをつける&lt;/a&gt;&lt;pre&gt;/*
 * @title id属性がある要素の後ろにアンカーリンクをつける
 * @description ページ途中へのフラグメント付きURL（#xxx）が欲しい時に
 * @include http://*
 * @license MIT License
 * @javascript_url
 * @require 
 */

{
  const pipe = x =&amp;gt; f =&amp;gt; f ? pipe(f(x)) : x;  // via https://qiita.com/nagtkk/items/5c54ec418c1c71fa491a
  const $attr = attr =&amp;gt; val =&amp;gt; e =&amp;gt;{
    if ( val == null) return e.getAttribute(attr);
    e.setAttribute(attr, val);
    return e;
  };
  
  document.querySelectorAll('[id]').forEach( e =&amp;gt; 
    pipe( document.createElement('a') )
      ( e.appendChild.bind(e) )
      ( $attr( 'href' )( &amp;quot;#&amp;quot; + e.id ) )
      ().textContent = '¶'
  );
  
  document.querySelectorAll('[name]').forEach( e =&amp;gt; 
    pipe( document.createElement('a') )
      ( e.appendChild.bind(e) )
      ( $attr( 'href' )( &amp;quot;#&amp;quot; + e.name ) )
      ().textContent = '¶'
  );

  void 0;
}


&lt;/pre&gt;</content:encoded>
  </item>
</rdf:RDF>
