経緯、タブをoneTabに貯め過ぎて、整理が不可能に。
気づいたら1000個ぐらい。縦に長過ぎて整理が不可能。折り畳めないしマージもできない。
じゃあ、ブックマークに戻そう。がきっかけ。
oneTabに使えるエクスポート機能は無い
- まずChromeに取り込むには、特定形式の
bookmarks.html
にする必要ある。- Chromeからブックマークを書き出した時のファイル。
- NETSCAPE-Bookmark-file-1形式?
- oneTabに簡易の書き出し機能はあるが、これは単純なURL改行のリスト。
- そもそも日付情報が無い。
- 日付は重要なので捨てたくない。
- まあ、便利なエクスポート機能あるとユーザー出て行きやすいから。
- あえて付けなかったり(想像)、有料にしたりしてるのをよく見る。
表示部分からデータを解析する。
- 表示部分には日付データがちゃんと残ってる。
- ターゲットはChrome拡張なので、Bookmarkletは使えない。
-
ctrl+shift+I
で開発者ツールのconsoleからやる。- 複数行のコードを弄るのは大変なので、ソース→スペニットを使って作る。
- 試行錯誤して・・・出来た。
この記事投稿してから気づいた大失態
- oneTabのローカルストレージにJSONでデータが保存してあった!
- なので表示から解析する必要がなかった。
- でもまあ、書き出したものは同じだし、面倒くさいからそのままでいいか。
スクリプトの使い方
- 下のコードをコピーして、ontab開いて、開発者ツールのコンソールに貼り付けて実行。
- ただそういう攻撃もあるらしいので、軽くソースを読んでからのほうがいいらしい。
- 出来たhtmlファイルを、Chrome→ブックマークマネージャ→インポート
- スクリプトの主な機能
- Chromeにインポートできる形式のhtmlを書き出す。
- ブックマークにoneTabでの作成日を付与。
- faviconも書き出す。
/* eslint no-undef: "error" */
//便利関数
var log = console.log
, qsa = (s, o = document) => [...o.querySelectorAll(s)]
, qs = (s, o = document) => o.querySelector(s)
function saveTextToFile(fileName, text) {
const blob = new Blob([text], {type: 'text/plan'})
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = fileName
link.click()
}
//dataURL化
function getBase64(img) {
var cvs = document.createElement('canvas')
cvs.width = img.naturalWidth
cvs.height = img.naturalHeight
var ctx = cvs.getContext('2d')
ctx.drawImage(img, 0, 0)
//枠つけ
// ctx.lineWidth = cvs.width / 3
// ctx.strokeStyle = '#0f0c'
// ctx.strokeRect(0, 0, cvs.width, cvs.height)
//canvas要素をBase64化する
return cvs.toDataURL('image/png')
}
function oneTab2html() {
//表示から解析してdataに入れる。
var data = qsa('.tabGroup').map((v) => {
let dateText = qsa('div', v).find(v => v.innerHTML.startsWith('作成日時')).textContent.slice(5)
let unixtime = new Date(dateText).getTime() / 1000
let obj = {
tabs: null,
title: (qs('.tabGroupTitleText', v).textContent.trim() + '_' || '') + dateText,
time: unixtime,
}
obj.tabs = qsa('.tab', v).map(v => ({
url: qs('a', v).href,
title: qs('a', v).textContent,
favicon: (() => {
let el = qs('img:nth-child(1)', v)
if (el && el.src.startsWith('chrome://'))
return getBase64(el) //''//
return ''
})(),
}))
return obj
})
//dataからhtmlに書き出す
var folders = ''
data.forEach(v => {
folders += ` <DT><H3 ADD_DATE="${v.time}" >${v.title}</H3>\n`
folders += ' <DL>\n'
v.tabs.forEach(a =>
folders += ` <DT><A HREF="${a.url}" ADD_DATE="${v.time}" ICON="${a.favicon}">${a.title}</A>\n`
)
folders += ' </DL>\n'
})
var html = `<!DOCTYPE NETSCAPE-Bookmark-file-1>
<!-- This is an automatically generated file.
It will be read and overwritten.
DO NOT EDIT! -->
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<TITLE>Bookmarks</TITLE>
<H1>Bookmarks</H1>
<DL><p>
${folders}
</DL><p>
`
//ファイルとして保存
saveTextToFile('OneTab→bookmarks.html', html)
return true
}
oneTab2html() && '完了'
#インポート後、日付が書き出せてるか、確認する方法
- 素のChromeでは、ブックマークの作成日を確認する方法は見つからなかった。
- なので以下の拡張機能を使いました。
#自分用の雑記、試行錯誤のおおよそ時系列。
- chromeから書き出したhtmlファイルを色々試す
-
a
のadd_date
属性にUNIX時間を入れるらしい。 - その他ブックマークのほうがネストが浅くて分かりやすい。
-
H3
をフォルダと認識- フォルダにも
add_date
時間を付けれる、LAST_MODIFIED
も
- フォルダにも
-
ICON="data:image/png;base64,
- base64のiconデータも渡せる。
- インポート
- インポート時はブックマークツールバーに入れられる
- ブックマークツールバーが空の時以外は、
インポートしたブックマーク
フォルダが作られそこに収まる。- そのフォルダが存在する時は、同名のフォルダが作られる。
- エクスポート時のフォルダ名が同じものは一つにマージされる、ブックマークは両方残る。
-
- oneTabの表示から解析
- googleとかoverflowとか一部のサイトはfaviconのsrcが無く、よくわからない。放置。
[{tabs:[{href,title,favicon},],time:UNIX時間,title:フォルダ名},]
- みたいな形式にまず変換。
- 出来上がったhtmlをctrl+s保存するために、window.open()を使う。
- Chromeはブックマークのインポート形式がhtmlだから。
- about:blankでは
ctrl+s
の保存できなかった。なぜぇ。 - example.com開いて書き換えれば?→セキュリティー的に無理
- もういいや、onetabの画面を直接書き換えてしまえ。
- ctrl+sは可能だったが、
- 保存した瞬間ファイルが削除される怪奇現象。chrome-ext://だからぽい。
- about:blankにhtml表示させて、そのouterHTMLをコピーしよう
- document.documentElement.outerHTMLをcopy()して、htmlに貼り付けた。
- V1.html完成
- V1.htmlインポートしみてる
- インポート失敗。まあそうか・・・。
- インポートしてみるも数個の登録されるだけでおかしい。
- Chromeが書き出したファイルと見比べると、Chromeはタグが大文字。!?
- Chrome書き出しファイルを小文字にしてインポートテスト→反応なし。
- タグは大文字必須?!
- 大文字にしてからhtmlにparseしてからコピーすると、タグが小文字になってしまう。
- タグと属性だけ大文字にするの・・・めんどくさいからparseするのやめよう。
- html→保存、でなく直接書き出すことにした。
- Chrome書き出しファイルを雛形にして書き出してコピー→htmlファイルに貼り付け。
- V2.html完成
- インポートするも、反映されない。
- href←これも大文字必須だった。疲れた。もう全部大文字にしよう。
- 修正版を読み込ます→成功・・・日付がおかしい。
- ブックマークの日付を調べるにはそれっぽい拡張が必要。
- UNIX時間はミリ秒じゃなく秒だった。
- インポート成功!!
- とりあえず機能的に完成。
- ここまで来たら、Chromeが書き出したファイルで最小化を調べてる
- pタグを消してみる、問題なし、
- フォルダ前のdl dt 削除、OK
-
<h3>
のフォルダより前は全部不要。文字コードはutf8なら削除できる。 -
<DL><DT>
は改行無いと読み込まない→まじかあ。HTMLのこと詳しくないけど。 - タイトルやH1は必要無い。
- なんでこんな不親切な仕様なんだろう、超かしこ集団が作ってるブラウザなのに。
- ADD_DATEはミリ秒じゃないく秒。10桁ぐらい。
- て検索すると情報が少し出てくる。
- favicon取り込み(やらなくてもいい)
- ついでにfaviconに色つけてみようかな。
- そしたら、リンク開く→アイコン更新で、visited的なことできそう。
- そもそも更新されるのかな?
- とりあえず取り込もう
- canvas作ったにimg貼り付ける、naturalWidthを初めて知る。
- base64化で、toData()→エラー
- クロスドメイン問題にひっかかった・・・別オリジンのimg貼り付けがあかんらしい。
- ダメ元で.setAttribute("crossorigin","anonymous")
- 画像が壊れマーク。エラーは出なくなった。返り値は空に・・・。
- DOMでスクリーンショット取れるとか聞いたことある、それはどうか?
- そもそもクロスドメインで全部弾かれてないんじゃないか?
- onetabオリジン→chrome-extension://burabura
- icon1→chrome://burabrua
- icon2→
https://s2.googleusercontent.com
- ちゃんと調べるとhttp系だけが弾かれてる。じゃあこっち捨てよう。
- 完成、iconに色枠が付→見ると消えた。
- この機能要らない。
- 気づいたこと
- ブックマークマネージャーだと同じfaviconは共通表示されてた。
- ツールバーだと共通表示されない。初めて気づいた。
- いままで後で読む、の区別にこの挙動を利用してた。
- 別のQiitaのBookmarkletの記事を読んでたら、偶然、ファイル保存の仕方を知る。
- Qiitaへ投稿
- onetabのローカルストレージにJSON発見。
- 個別のタブデータに日付情報は無し。
- faviconもChromeURLでfavicon返すのに突っ込めばよさそう。
- favicon返しに使えない例外の判定は作る必要ありそう。
bookmarks.htmlの最小構成を検証した結果
<H3 ADD_DATE="1617199649" LAST_MODIFIED="0">フォルダ1</H3>
<DL>
<DT><A HREF="https://news.google.com/" ADD_DATE="1606126600" ICON="data:image/png;base64,burabura=">ニュース</A>
</DL>
#手間取った点
- Chrome開発者ツールのスペニットで作ってみた。
- サジェスト効かないし、コーフォドーマットが汚すぎて読みづらい。
- インポート形式の仕様がもっとゆるいと思い込み、試す→弾かれる、の繰り返しに疲れた。
- 最初から完コピを目指すべきだった。
- 軽い気持ちでワンライナーや、アロー関数オブジェクト返しを多様。
- アイテムが多い上に例外多くて、そこでエラーでとまると、どこでエラーが起きたか分かりにくい。
- console.assrtを使うべきかな。
- テンプレートリテラルの中でforEachとかすると、凄く読みづらい。
- join()ぐらいまでにすべき。
#参考にさせてもらったページ
- ブックマークレット・コンソールを使って Webページ内の複数の指定要素のテキストをファイルに保存 - Qiita