LoginSignup
4
1

More than 3 years have passed since last update.

短いURLでおねだりしよう

Last updated at Posted at 2019-07-16

背景

  • amazonの商品ページをチャットでやりとりする機会があり、長いURLがウザかった。メールに貼りつけると折り返されてURLが途切れてしまうこともあるかと(いまどき無い!?)


この時計いいよね:thumbsup:
https://www.amazon.co.jp/%E3%82%BF%E3%82%B0%E3%83%9B%E3%82%A4%E3%83%A4%E3%83%BC-CAR2A1L-BA0688-%E3%82%AD%E3%83%A3%E3%83%AA%E3%83%90%E3%83%BC%E3%83%9B%E3%82%A4%E3%83%A4%E3%83%BC01-%E3%82%A2%E3%82%A4%E3%83%AB%E3%83%88%E3%83%B3%E3%83%BB%E3%82%BB%E3%83%8A-%E4%B8%A6%E8%A1%8C%E8%BC%B8%E5%85%A5%E5%93%81/dp/B07P6VVPLV/ref=sr_1_3?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%82%A2%E3%82%A4%E3%83%AB%E3%83%88%E3%83%B3%E3%82%BB%E3%83%8A+%E3%82%BF%E3%82%B0%E3%83%9B%E3%82%A4%E3%83%A4%E3%83%BC&qid=1563237513&s=gateway&sr=8-3

これもいいよね:blush:
https://www.amazon.co.jp/%E3%82%BF%E3%82%B0%E3%83%BB%E3%83%9B%E3%82%A4%E3%83%A4%E3%83%BC-%E3%83%A1%E3%83%B3%E3%82%BA%E8%85%95%E6%99%82%E8%A8%88-%E3%82%AD%E3%83%A3%E3%83%AA%E3%83%90%E3%83%BC%E3%83%9B%E3%82%A4%E3%83%A4%E3%83%BC01-%E3%82%A2%E3%82%A4%E3%83%AB%E3%83%88%E3%83%B3%E3%83%BB%E3%82%BB%E3%83%8A%E9%99%90%E5%AE%9A-CAR2A1L-BA0688/dp/B077YCQ265/ref=sr_1_4?__mk_ja_JP=%E3%82%AB%E3%82%BF%E3%82%AB%E3%83%8A&keywords=%E3%82%A2%E3%82%A4%E3%83%AB%E3%83%88%E3%83%B3%E3%82%BB%E3%83%8A+%E3%82%BF%E3%82%B0%E3%83%9B%E3%82%A4%E3%83%A4%E3%83%BC&qid=1563237513&s=gateway&sr=8-4

  • wikiを引用するときもURLが長い

アイルトンセナ
https://ja.wikipedia.org/wiki/%E3%82%A2%E3%82%A4%E3%83%AB%E3%83%88%E3%83%B3%E3%83%BB%E3%82%BB%E3%83%8A

amazon, wiki のURLは短くできる。(≠短縮URL)

amazonは商品コードで表示できる
https://www.amazon.co.jp/dp/B07P6VVPLV
https://www.amazon.co.jp/dp/B077YCQ265

wikiは記事のidで表示できる
https://ja.wikipedia.org/?curid=4698

短縮URLはサービス経由で短くするので、サービス終了になると使えなくなってしまう。
以下はアイルトンセナのwikiのURLを短くしたもの
https://bit.ly/30tuVIC

amazon, wiki のURLを短くするツールはあったけどめんどくさい

chrome extension で短いURLをサクっとコピーできるようにしよう

3年ぶりくらいにchrome extension に着手。下記ブレストも参照

仕様

  • 右クリメニューでクリップボードにコピー
  • アイコンでクリップボードにコピー
  • 対象外のサイトでは右クリメニューを出さない
  • 対象外のサイトではアイコンを無効化 ← 実現できず@TODO

ブレスト

  • 右クリメニューはサクっと使えるので決まり。以前、作ったこともある。

  • 貼り付けが目的なので、クリップボードにコピーしたい。→調べたら可能だったので採用

  • アイコンは使用しないつもりが、勝手に表示されるので、押したらコピーできるようにした。

  • 右クリメニューを押したときコピーされたか分からないので、メッセージを出そうと思ったが、それもウザいので、対象のサイトのみ右クリメニューが出るようにした。

  • コピーできてないことがある(wikiのみ)ので、アイコンにコピー状況を表示するようにした。(原因は、contensとbackgroundの通信失敗)

  • 対象外のサイトでアイコン無効化ができなかった。エクステンションは他にも使用しており、アイコンは表示しないつもりなのでOK(^^;

  • アイコンでコピーもわりと便利。

  • スマホでも使いたい→無理でした

  • IEでも使いたい→しらん

ファイル構成

root_folder
│ manifest.json

├─html
│ options.html

├─img
│ icon-128x128.png
│ icon-16x16.png
│ icon-48x48.png

├─js
│ background.min.js
│ content.min.js

└─_locales
├─en
│ messages.json
└─ja
messages.json

ソース

  • manifest.json

permissions はトップドメインを*にできないため、https://www.amazon.*/* はエラーとなる。

manifest.json
{
  "name": "short url for amazon, wiki",
  "short_name": "short url",
  "version": "1.0.0",
  "manifest_version": 2,
  "description": "short url to clipboard",
  "author": "ctrlzr",
  "default_locale": "ja",
  "permissions": [
    "https://www.amazon.co.jp/*",
    "https://www.amazon.com/*",
    "https://www.amazon.it/*",
    "https://www.amazon.fr/*",
    "https://www.amazon.de/*",
    "https://www.amazon.es/*",
    "https://*.wikipedia.org/wiki/*",
    "activeTab",
    "background",
    "contextMenus",
    "clipboardWrite"
  ],
  "content_scripts": [{
    "matches": [
    "https://www.amazon.co.jp/*",
    "https://www.amazon.com/*",
    "https://www.amazon.it/*",
    "https://www.amazon.fr/*",
    "https://www.amazon.de/*",
    "https://www.amazon.es/*",
    "https://*.wikipedia.org/wiki/*"
],
    "js": ["js/content.min.js"]
  }],
  "background": {
    "scripts": ["js/background.min.js"]
  },
  "browser_action": {
    "default_icon": "img/icon-16x16.png",
    "default_title": "short url"
  },
  "options_ui": {
    "page": "html/options.html",
    "chrome_style": true
  },
  "icons": {
    "128": "img/icon-128x128.png",
    "48": "img/icon-48x48.png",
    "16": "img/icon-16x16.png"
  }
}
  • content.js

chrome.runtime.onMessage.addListener で background のメッセージを受け取り、wikiの記事idをhtml内から取得する。

content.js
chrome.runtime.onMessage.addListener(function(msg, sender, sendResponse) {
  var res = null;

  if (!msg.target) {
    // 
  } else {
    if ('wiki' === msg.target) {
      res = get_wgArticleId();
    } else {
      console.log(msg.target+' does not supprted');
    }
  }

  sendResponse(res);
});

function get_wgArticleId() {

  let scripts = document.querySelectorAll('script');
  for (let i=0; i<scripts.length; i++) {
    let script = scripts[i];
    let result = script.innerHTML.match(/"wgArticleId":(\d+)/);
    if (result) {
      return result[1];
    }
  }

    return null;
}
  • background.js

cm_click でasyncしてるのは、wikiでhtmlを捜索するのに、contents_script と通信するため。
どのイベントが走るか console.log で確認して必要なイベントを見極めた。
 chrome.tabs.onActivated:タブを切り替えたとき
 chrome.tabs.onUpdated:画面遷移、再読み込みしたとき
 chrome.browserAction.onClicked:アイコンをクリックしたとき

以下は非同期処理
 chrome.tabs.sendMessage
 chrome.tabs.getSelected

background.js

var cmid = null;

var cm_click = async function(data, tab) {

  var color = [0, 0xaa, 0, 100];

  let txt = await get_short_url[data.menuItemId].call(this, data.pageUrl, tab.id);
  if (!txt) {
    txt = data.pageUrl;
    color = [0xff, 0, 0, 100];
  }

  let textArea = document.createElement('textarea');
  textArea.value = txt;
  document.body.appendChild(textArea);
  textArea.select();
  document.execCommand('copy');
  document.body.removeChild(textArea);

  chrome.browserAction.setBadgeText({text:"copy", tabId: tab.id});
  chrome.browserAction.setBadgeBackgroundColor({color: color});
};

var icon_click = async function(tab) {

  var data = {
    menuItemId: "wiki",
    pageUrl: tab.url
  };

  cm_click(data, tab);
};


var get_short_url = {

  amazon: function(url) {
    let pos = url.indexOf('/dp/');
    if (-1 === pos) {
      return null;
    }
    let pos2 = url.indexOf('/', pos+4);
    if (-1 === pos2) {
      pos2 = url.indexOf('?', pos+4);
    }

    let id = null;
    if (-1 < pos2) {
      id = url.substring(pos+4, pos2);
    } else {  
      id = url.substring(pos+4);
    }

    let path = getBaseUrl(url)+'/dp/'+id;

    return path; 
  },
  wiki: function(url, tab_id) {
    return new Promise(function(resolve, reject) {
      chrome.tabs.sendMessage(tab_id, {target: "wiki"}, function(id) {
        if (id) {
          let path = getBaseUrl(url)+'/?curid='+id;
          resolve(path);
        } else {
          resolve(null);
        }
      });
    });
  }
};

function getBaseUrl(url) {
  let pos = url.indexOf('/', 8); 
  return url.substring(0,pos);
}

var cm = function() {
  chrome.tabs.getSelected(null,function(tab){
    let target = null;
    if (!tab.url) {
    } else if (tab.url.match(/^https:\/\/www\.amazon\.[^/]+\/([^\/]*\/|)dp\//)) {
      target = 'amazon';
    } else if (tab.url.match(/^https:\/\/.*\.wikipedia.org\//)) {
      target = 'wiki';
    } else {
//
    }

    if (cmid) {
      chrome.contextMenus.remove(cmid);
      cmid = null;
    }

    if (target) {
      let options = {
        id: target,
        title: "short url to clipboard",
        contexts: ['page'],
        onclick: cm_click
      };
      cmid = chrome.contextMenus.create(options);
    }
  });
}

chrome.tabs.onActivated.addListener(function (tabId) {
  cm();
});

chrome.tabs.onUpdated.addListener(function (tabId) {
  cm();
});

chrome.browserAction.onClicked.addListener(function(tab){
  if (!cmid) {
    return;
  }
  cm_click({menuItemId: cmid, pageUrl: tab.url}, tab);
});
  • その他のソースはほぼ使用していないので省略

注意点

公開は有料(5$)

限定公開は無料という情報もあったが、現在(2019年7月)は、有料。
20本まで5$

manifest.json の permissions に <all_urls> , tab を使用しない

chrome extension の公開には審査があり、<all_urls> にすると審査が長くなる。tab は activeTab を推奨される。権限ありありでどんなことができるかは、こちらを参照
ブラウザ拡張の権限でどこまで(悪いことを)できるのか?とその対策【デモあり】

permissions は適切に!

manifst.json内のpermissionsは必要最小限にすること。
紆余曲折はこちら
拡張外の何かを読み込む処理は、プライバシーポリシーに抵触するおそれあり。
localStorageは問題なし(たぶん

minifyは不要

PCでは通信量なんて気にするな、ということらしい。紆余曲折はこちら
手間暇かけて、というほどでもないけど、minifiyで拒否られるくらいなら、何もしないほうがいい。

document は content_scripts のみ

manifest.json の content_scripts に指定したjsのみ、documentを読める。
backend で document.getElementById('honya') としても想定した値は返らない。

tabs は background のみ

content_scripts 側で、chrome.tabs がエラーになってハマった。

非同期を前提に

普通にjsで書いていたら非同期通信を余儀なくされ、構成が変わってしまい、aync await で回避する羽目に。

自動更新は使えない

2017年12月以降、自動更新する機能は制限された。
以前は、manifest.json に update_url を記載すれば自動更新できた。らしい。

公開

思ったより審査に手間取ったので別にしました

chrome拡張の審査がとおらない

ようやく公開されました。まだ検索しても出ないのでurlを載せておきます。

short url for amazon, wiki

4
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1