🌐

ブログカードを自作するブックマークレットを作った

2020/09/21に公開

前回調べたことを実装してみた
https://zenn.dev/junki555/articles/c8cd60995eff719304b9

今回は note ( https://note.com/ ) をブログカード化するブックマークレットにする。
試しなのでいろんなサイトで使えるような汎用的な作りにはしていないし、
画像や概要の抜き出しも適当です。

JavaScriptコード

// ==ClosureCompiler==
// @output_file_name default.js
// @compilation_level SIMPLE_OPTIMIZATIONS
// @language_out ECMASCRIPT_2017
// ==/ClosureCompiler==
javascript:(
  function(){
    /* 正規化URL(canonical link)を取得 */
    function getCanonicalUrl() {
      var links = document.getElementsByTagName("link");
      for (var i = 0; i < links.length; i++) {
        if (links[i].rel) {
          if (links[i].rel.toLowerCase() == "canonical") {
              return links[i].href;
          }
        }
      }
      return '';
    };

    /* note側DOM 読み取り */
    const noteTitle = document.title;
    const noteInfo = document.getElementsByName('description')[0].content.trim();
    const canonicalUrl = getCanonicalUrl();

    /* imageオブジェクト準備 */
    const imageReader = new Image();
    imageReader.crossOrigin = "anonymous";
    const imgWidth = 85;

    /* Imageオブジェクトに読み込んでから実行 */
    imageReader.onload = () => {
      const imgType = imageReader.src.substring(5, imageReader.src.indexOf(';'));
      const imgHeight = imageReader.height * (imgWidth / imageReader.width);
      const canvas = document.createElement("canvas");
      canvas.width = imgWidth;
      canvas.height = imgHeight;
      const ctx = canvas.getContext("2d");
      ctx.drawImage(imageReader,0,0,imgWidth,imgHeight);
      const base64Image = canvas.toDataURL('image/jpeg');

      /* DOM構築 */
      const result = "<div class='blog_card'>"
      + "<a href='"+canonicalUrl+"' target='_blank' rel='noopener external'>"
      + "<img alt='"+noteTitle+"' src='"+base64Image+"' />"
      + "<span class='card_title'>"+noteTitle+"</span>"
      + "<span class='card_info'>"+noteInfo+"</span>"
      + "<span class='card_url'>&nbsp;"+canonicalUrl+"</span>"
      + "</a></div>";

      /* クリップボードにコピー */
      const copyFrom = document.createElement("textarea");
      copyFrom.textContent = result;
      const bodyElement = document.getElementsByTagName("body")[0];
      bodyElement.appendChild(copyFrom);
      copyFrom.select();
      document.execCommand("copy");
      bodyElement.removeChild(copyFrom);

      /* alert */
      alert(result);
    }

    const topImg = document.getElementsByTagName('figure')[0].childNodes[0];
    imageReader.src = topImg.src;
  }
)();

このままでもブックマークレットとして使えるが、
これを Google Closure Compiler ( https://closure-compiler.appspot.com/home ) でコンパイルしてブックマークレットして使いやすい状態にする

bookmarklet版

javascript:(function(){const d=document.title,g=document.getElementsByName("description")[0].content.trim(),e=function(){for(var b=document.getElementsByTagName("link"),a=0;a<b.length;a++)if(b[a].rel&&"canonical"==b[a].rel.toLowerCase())return b[a].href;return""}(),c=new Image;c.crossOrigin="anonymous";c.onload=()=>{c.src.substring(5,c.src.indexOf(";"));var b=85/c.width*c.height,a=document.createElement("canvas");a.width=85;a.height=b;a.getContext("2d").drawImage(c,0,0,85,b);b=a.toDataURL("image/jpeg");
b="<div class='blog_card'><a href='"+e+"' target='_blank' rel='noopener external'><img alt='"+d+"' src='"+b+"' /><span class='card_title'>"+d+"</span><span class='card_info'>"+g+"</span><span class='card_url'>&nbsp;"+e+"</span></a></div>";a=document.createElement("textarea");a.textContent=b;const f=document.getElementsByTagName("body")[0];f.appendChild(a);a.select();document.execCommand("copy");f.removeChild(a);alert(b)};const h=document.getElementsByTagName("figure")[0].childNodes[0];c.src=h.src})();

生成されたHTML

例に使った記事はこちら
https://note.com/junki555/n/nc957de69dc3b

<div class='blog_card'>
  <a href='https://note.com/junki555/n/nc957de69dc3b' target='_blank' rel='noopener external'>
  <img alt='マツリカに入社して感動したこととか|北山淳也|note' src='data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCAAsAFUDASIAAhEBAxEB/8QAGwABAQEBAAMBAAAAAAAAAAAAAAUGBwECBAj/xAAnEAACAgICAgICAwADAAAAAAABAgMEBQYAERIhBxMUMSIjMkFCUf/EABwBAAEEAwEAAAAAAAAAAAAAAAACAwQFAQYHCP/EAC8RAAIBAwMCBAMJAQAAAAAAAAECEQADIQQSMQVBE1FhcSIygQYUI5GhscHR4fD/2gAMAwEAAhEDEQA/AKvHKWC1/I7HbejjGpiWOMyn8q7DVTxBA9PM6qT2w9A9/s9ejy9c+Jt7pR15ZcXVeO3Vt3a7wZOrMs0NYAzlCkhDFQf8jtj03QPieuPpYu3F3IpI9q9r3uoaTT3PCvXVVvIsAeJ4J8gT7AmsfxzYW/incaOWrYi3VqxvczK4KvKbUZSWy3gQVAPmY/GWM+YXxHkAffrk67pOcp0cZdWNLTZe9ax1WvWDSTNPA0asviF9+RlUL12T79D13ltPdWdykR/n9ik2+p6O7t8O6p3cQQexP7KfyqBxza5f4g3nBZLCY7K4mWsM81OKCzLBMkEU1kdrDI7IPGRffko7I8T++uSMlpeZxlGxlJpsZJVrTvAzw5Ou7syyGMlYg/2lSw9Hw9jpv174NpryTuU4rFrqmivhTbuqd3GRmcY9ccc1B45pto0LJatgNf2SxlMZdp7JDJLVNOV3MZj8PNJO1ADKZApAJ6KsO/XLGV+E98w9C9krOOEtajjq2S+6t3PHNHKVBWN4wVZoyzefvoBGYEr0Sr7pfJICnGT7ESP0pB6xoAqMboAYkCTEkNtIE9w2DWB45b2bUsjqiYd8jPWkGbxcOWr/AEsx8YZWYKr9gdN/A9gdj9ezynT+KtyvYRdjghxIxxCEzy5ujGELr5KrBpgUYjv+LAN6Pr1xI091mKhSSPSnW6lo0tree6oVjAJIAJmIE95rI8cccZqbVHXs5b1rM1c5RhqzTVH8hFagWaGQEEMjo3oqVJB/59+iD0edD2Fdt+Rtro7Nh9E26PXhVr14a2OrORBUCBJoqzpH4BD3IF7B777YeyOcr5+o9H2347ra3RF61rf5IxlbGl3yQVqsSxRSuJUmQiRjMfMeETqHBRj0pJtemoNQGsu+1cH6/wDfx5VqH2ovt04prdPY8S6QUnOFMeoz5H3AyYPJtjyG7z2MBl9X0XK4HCa9KWwS/hySgTITNJM8jp4yyExF29eIWPrrpTz5dg2LGZulrvWrZaPUsTdk/Lss/c1y3P8AXJaH2hREreKKEQAdKPI/69dxxXybpsPx3hsRQ27GUMpj4rLR1rE4mjkR4pIYY/NwwCiSaAkShWCROzKFB5z3JTaduerbTrNHcsFhEr7xdzsLXWeOOWg8ZRDAqIS7evUYAPXX/o5Nv6cBfguglgDGIwAY9BiIxwO1UWg6m7XB4+kKLaYgMN5MFmUscEsTukGWyzHnNTZ/lXH5N6eaqazkhNU2Cjnsv9ZV61WtUJgqwwgKCB9TohaQjtwOv9dDNbVtmgbTde8mjWsNZmlPnJQvx/QEawXZ/wAcxe3+tvAAShfSnrmy0Ld9f1bXsrqVbd6r0snmJYoRkaNj6TTSCQq8oh6kRZ5TArAMSFVu167Bma7cFbK5+HV/lfEalkLNqAxijJcr4m1CI3LBZGQyKUY9AOAD5N4k9jjDl7qKDcB3ciFkHPGe/nIyfpU+wlnSXrjJp3Xw42NuugFSQMwp+XjaVYBVE4zXjMfJeK2bB5DXRq91cBgYoJdeMSJK1B4z4BrXY8XSZpO5O/8AsVA8vXKtv5Vwm4Y7NVrtPPQflYajUmjw+OgSGrHAIGllIVx/EyK6At6EZQev88maHmcXj9h2wZLdsJkMplaqV61zM1ppsVdkeVJJXm84y/kpQFC6BSw7ProN7alsdKn8jbBkti3bD5C9ex0lSG5PBMMTdmlEaNFOqxBxCqluukVe41PYUDtSXrjbdzj4pB44G4dj5cDyiDxTN7Q6e2bgt6dvwwHX55JPhkxKd2EsZmQSVkvXyWdw0nbsNg6l/Ts3lNoxmHTA0asFkCnMVMn1SlUH3M4Mnl4KQCVA/RPM3iNrwyaTe0rP4axOjWXyNC3VnEckFoxfWBIrKRJGel7Hoj+XR982usbZDr2/ZjLZjdtbs3kxhq469XxhlqxWSgigEP8AQPqjhDBmKp0Vj8QG765n/ljcsBsVyDDa5SqNj8O5Sper1FqCdGii+3+lQAimdZpVHrr7SOh+uMXmi2bpcbsiIGRxmCew+mI5mrHRWydSNGthvCMPu3vCnLQu5VxJAgQSC24QsVz/AI445U1uVOOOOFFOOOOFFOOOOFFOOOOFFOOOOFFOOOOFFf/Z' />
  <span class='card_title'>マツリカに入社して感動したこととか|北山淳也|note</span>
  <span class='card_info'>
  この記事は 祭り化 Advent Calendar 2019 2日目の記事&nbsp;です。 こんにちは、北山淳也です。 普段は五反田のマツリカでエンジニアをやっています。 1日目はVTRyoさんの「Web系企業からSaaSスタートアップに入社した理由と何ができるのかエントリ」でしたね。     
  Web系企業からSaaSスタートアップに入社した理由と何ができるのかエントリ - VTRyo Blogこの記事は 祭り化 Advent Calendar 2019 1日目の記事。 Hello Advent Calendar!blog.vtryo.me     VTRyoさんはマツリカの先
  </span>
  <span class='card_url'>
  &nbsp;https://note.com/junki555/n/nc957de69dc3b</span>
  </a>
</div>

画像をbase64化して埋め込んでるのでそこの部分が長い。

見た目を整える

上記HTMLに対してこんな感じのCSSをあてて見た目を整える。

body {
  width: 800px;
}

.blog_card {
  position: relative;
  width: 80%;
  border: 1px solid #ddd;
  border-radius: 7px;
  padding: 10px;
}

.blog_card:hover {
  box-shadow: 3px 3px 8px rgba(0,0,0,.2);
  transform: translateY(-4px);
}

.blog_card a {
  text-decoration: none;
}
.blog_card img {
  float: left;
  margin: 0 10px 10px 0;
}
.blog_card .card_title {
  display: block;
  font-size: 1.1em;
  color: #020202;
  font-weight: bold;
}
.blog_card .card_info {
  display: block;
  color: #050505;
  text-decoration: none;
}
.blog_card .card_url {
  clear: both;
  display: block;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  width: 80%;
  color: #AAAAAA;
}
.blog_card .card_url > img {
  float: none;
  margin: 0 5px 0 0;
}

最終結果

bookmarklet_ex.jpg

こんな感じ。悪くないんじゃないだろうか。

Discussion