ドキュメント管理に悩む3 Dropboxの応用
前回の結論で、公開するテキスト(html)ドキュメントをDropboxに置くことに決めた。
- 公開されてもよいoffice文書は Google Drive
- zipやアプリ、音楽、動画などの公のコンテンツやアーカイブは SkyDrive
- それ以外は Dropbox
Dropboxは publicフォルダに置いたhtmlファイルを
という感じでWebアクセスできる。これが他のサービスに無いありがたい機能だ。
しかし弱点は静的なファイルしか置けないこと。javascriptは動くが、サーバーサイドのスクリプトが動かない。
なので、たとえば「docs/ 以下のファイル一覧を表示」とか検索機能とかができない。そうなると「そういうことをやりたければpukiwikiだろ」という話になってループしてしまう。なんとかならないものか・・・。
そこで考えました。コンテンツはDropboxに置いておいて、Webサービスはレンタルサーバーが担えばいいんじゃないかと。
レンタルサーバーの WebAppが Dropbox のコンテンツを参照して、加工なりなんなりしてクライアントにレスポンスする。なかなかよいのでは!
Dropboxのプライベートなコンテンツにアクセスするには認証してAPIを叩く必要があるけど、パブリックなコンテンツはそんなもの不要。phpなりsinatraなりで簡単に実現できそう。
■やってみる
ドキュメント管理に悩む2
続き。
■各社サービスの違い
- 容量
- 利用規約(コンテンツの取り扱い)
- Web閲覧
容量は実はたいした問題ではなく、下の2つの方が重要。で、この2つの条件でサービスの使い分けが決まってしまう。
利用規約は、コンテンツの公開範囲に影響する。
- Google Drive, N Drive は、置いたコンテンツはサービスに利用されてもよいと認めることになる。GMailのようなもの。なので
- プライベートなコンテンツは置けない。(怖いので)
- 著作権的にまずいものは置けない。(法律的に)
- SkyDrive は、他のユーザーに公開するとそのユーザーはそのコンテンツを自由に扱ってよい、となる。またMSの他のサービスに(それとは分からないで)こっそり利用される。よって
- 著作権的にまずいものは公開してはいけない。
- プライベートなコンテンツは置きたくない。(気分的に)
- Dropboxは基本的にはローカルHDDやプライベートサーバーと同じ扱い。よって
- プライベートなコンテンツや著作権的にまずいものも置いてよい。
結果、SkyDriveは公開さえしなければDropboxに近い。ただしMSによるスキャンを認めるので気分的にはDropboxの方が安心。
ということで、公開範囲の観点では、今の利用方法からの移行は以下の通り。
- ブログやpukiwikiの記事, Dropboxの一部 → Google Drive, N Drive
- Dropboxの一部 → SkyDrive
- ローカルHDD, NAS, 自分宛のメール, Dropboxの一部 → Dropbox
■Web閲覧
続いてWeb閲覧の観点から。
- SkyDrive
- windowsアプリを入れることでローカルPCと同期できるが、Windows Vista以降。
- よってローカルのoffice文書を共有・公開するのには適している。
- 基本的に招待制
- パブリックなコンテンツは、フォルダごとにURL文字列を生成する
- ランダムな文字列なのでweb閲覧の使い勝手は悪い
- office文書を置いて、webで編集できる
- テキストのアップロードはできるがブラウザで編集できない
- Dropbox
- publicフォルダに置いていけば、その階層通りにwebアクセスできる。
- 基本、htmlのみ
- webで編集はできない
- Google Drive
- SkyDriveとほぼ同じ。違いは WindowsアプリがWindows XPも対象なこと。
- テキストのアップロードができない?(新規作成やアップロードは不可。アプリ経由ならできるかも)
- N Drive
ということで、dropbox とそれ以外、という使い分けになる。
- テキスト以外のDropbox,ローカルHDD, NASファイル → SkyDrive, Google Drive, N Drive
- ブログやpukiwikiの記事, テキストのDropbox, 自分宛のメール → Dropbox
公開範囲による使い分け
- ブログやpukiwikiの記事, Dropboxの一部 → Google Drive, N Drive
- Dropboxの一部 → SkyDrive
- ローカルHDD, NAS, 自分宛のメール, Dropboxの一部 → Dropbox
文書の種類による使い分け
- テキスト以外のDropbox,ローカルHDD, NASファイル → SkyDrive, Google Drive, N Drive
- ブログやpukiwikiの記事, テキストのDropbox, 自分宛のメール → Dropbox
以上からマトリックスを作る。
Dropbox | SkyDrive | Google Drive | N Drive | ||
---|---|---|---|---|---|
公開のtext(html) | ◎ | × | × | × | |
非公開のtext(html) | ◎ | △ | × | × | |
公開のoffice文書 | △ | ○ | ◎ | ? | |
非公開のoffice文書 | ○ | ◎ | × | × |
N Drive はよく分からず、使い勝手が他のサービスより悪そうなので選外。
SkyDriveはoffice文書のweb編集に強いが、Windows XP との同期が中途半端なのでこれでは意味がない。
Google Driveは公開のoffice文書なら使い勝手がよさそう。
■結論
- 公開されてもよいoffice文書は Google Drive
- zipやアプリ、音楽、動画などの公のコンテンツやアーカイブは SkyDrive
- それ以外は Dropbox
ドキュメント管理に悩む
以前から、自分用メモを色んなところに書きためてきている。
しかし保存場所や書式がその場その場でばらばらなので、いざ「これって前に調べてメモしたよな」と思っても見つけるのが難しくなってきた。
これじゃいかん。
具体的にどうなっているかというと、
こんなにある(´Д`;)
しかも保存形式がばらばらなので取り回しが効かない。たとえばpukiwikiで書いたメモを他に移すのって、pukiwiki書式で書いているので難しい。
保存する時にはそれなりに考えているはず。たとえば携帯からでも見たいものはpukiwikiに、とか。それにしても散らかりすぎている。
理想の形
じゃあどうなれば望ましいのか、ゴールイメージを書き起こしてみよう。
- 閲覧
- どこからでも見ることができる。
- フォルダ構造に沿って階層構造で見ることができる
- オーサリング(編集)
- ローカルのエディタで書ける
- 修正はweb上でもできる
- wiki書式で書ける
- 編集しながらリアルタイムにプレビューできる
- 記述の書式
- パブリッシュ(公開)
- エクスプローラでファイルを所定のフォルダに置くだけですむ
- もっと言えば、フォルダに置きながら編集できる
■既存サービスでは?
おそらく大きなポイントは「ローカルのエディタで編集→所定のフォルダに置けば公開」という要求だろう。たとえばpukiwikiは、この要件以外はほぼ満たしている。(あとは書式くらい。)
はてなダイアリーのようなブログもそうで、ローカルに書いたメモを「アップロード」するという一手間がかかる。
githubやbitbucketも同じで、これらは構成管理サービスの機能の一つという位置づけなので、ローカルで編集→pushという流れになるのが自然。
githubやbitbucketはリポジトリごとにwikiページを持ててそれはweb上で直接コンテンツを編集できるが、それならpukiwikiと変わらない。
「ローカルで編集〜」を満たすとなると利用できるサービスは限られる。Dropbox, EverNote, Google Drive のようなオンラインストレージ系だ。
オンラインストレージ系サービスが、そのストレージの中身をうまくwebで閲覧できれば目的が達成できるかもしれない。
すでに調べるまでもなく、これらのサービスでは単純なhtmlファイルならwebで閲覧できる。あとは残りの要求をどこまで満たせるか・・・。ということで、それを中心に調べることにした。続く。
ニコニコ動画のコメント(xml)を字幕ファイル(ssa)形式に変換
そんな神ツールが公開されている。
http://www6.atpages.jp/appsouko/work/smsub/
素晴らしい。
が、ときどきエラーになることがある。
調べてみると xml の chat エレメントの vpos 属性が負の値だとダメらしい。確かにエラーになる xml はそうなってる。
ということで python スクリプトで vpos が正の値のときだけコメントとして認識するように修正した。
280c280,281 < comments.append(NicoComment(text, time_, cmd, by_author)) --- > if time_ > 0: > comments.append(NicoComment(text, time_, cmd, by_author))
ruby 1.9 でATOKダイレクトを使う
ruby 1.9 の環境でATOKダイレクトプラグインをインストールしようとすると、以下のようなエラーが出てインストールすらできない。
セットアップ用件を満たすプラグインが存在しないため、セットアップを実行できません。
ロード中に以下のエラーが発生しました。
hoge.rb : [SCRIPT] スクリプトファイルのプラグインの文法チェックに失敗しました
調べてみると、どうもATOKダイレクトの本体が jcode.rb を必要としているらしい。
jcode.rb は 1.8 までは標準添付されていたが、1.9 では処理系が多言語対応したため不要になり、添付されていない。
そこで LOAD_PATH に適当に 1.8.x の jcode.rb を置く。これでインストールは成功する。
ただし、インストールは成功するものの 1.9 + jcode.rb というイレギュラーな環境では思わぬ副作用があるかもしれないので、できれば jcode.rb は空ファイルにしておきたい。
が、ATOKダイレクトが jcode.rb の関数を使っているので完全に空にはできない。
今のところ判明しているのは jlength。とりあえずこの関数だけ残して使い続けてみて、また別のプラグインで NoMethodError が出たときに追記していけばいいかと。
本当はATOKダイレクト自体が Ruby 1.9 に対応してくれるのが一番だけど、1.8 のことも考えると難しそうなので「最新版の言語を使う人間の宿命」としてこちら側が覚悟しないといけないのだろう。
言わずもがなだが、プラグインのスクリプト側が(jcodeに限らず)Ruby 1.9 に対応してないとどうしようもない。これも自助努力で対応すべし、と。
WikiPedia で脚注をポップアップ
絶対にあると思ってネットを探したら、意外にすぐに見つからなかったので。
// ==UserScript== // -*- mode:JScript; Encoding:utf8n -*- // @name Wikipedia.citePopup // @namespace http://d.hatena.ne.jp/p-arai/ // @description Add pop-up on reference to footnote // @include http://ja.wikipedia.org/wiki/* // // @author p-arai // @version 2009.02.17 (function () { // retrive array of cites var cites = new Array(); var lis = document.getElementsByTagName("li"); for (var i=0; i < lis.length; i++){ var li = lis[i]; if (li.id.match(/^cite_note-/)){ cites.push(li); } } // retrive and modify reference element var hrefs = document.getElementsByTagName("a"); for (var i=0; i < hrefs.length; i++){ var a = hrefs[i]; if (a.href.match(/#cite_note-(\d+)$/)){ var index = RegExp.$1; if (typeof a.textContent != "undefined") { a.title = cites[index].textContent.replace(/^[^]\s*/, ""); } else { a.title = cites[index].innerText.replace(/^[^]\s*/, ""); } } } })();
WikiPedia でタレントの写真を表示
Wikipedia でタレントを検索したら、Yahoo! タレントプロフィールから写真を貼り付ける greasemoney スクリプト。ただし誤爆多し。
http://ja.wikipedia.org/wiki/%E6%9C%A8%E6%9D%91%E3%82%AB%E3%82%A8%E3%83%A9
とか。なんでやねん。(アルゴリズム改良中)
// ==UserScript== // -*- mode:JScript; Encoding:utf8n -*- // @name wikipedia.yahooTalentImage // @namespace http://d.hatena.ne.jp/p-arai/ // @description Add pop-up on reference to footnote // @include http://ja.wikipedia.org/wiki/* // // @author p-arai // @version 2009.02.17 // --------------------------------------------------------- // This script is a derived version of wikipedia.googleimage // http://www.kagami.org/diary/2007-09-16-1.html // --------------------------------------------------------- (function () { var debug = false; var baseurl = 'http://search.yahoo.co.jp/search?p='; var word = document.title.replace(/\s+-\s+Wikipedia/, ""); var searchurl = baseurl + word + "+%E3%83%97%E3%83%AD%E3%83%95%E3%82%A3%E3%83%BC%E3%83%AB+talent.yahoo.co.jp"; var img = document.createElement('img'); img.alt = 'Yahoo: ' + word; var a = document.createElement('a'); a.appendChild(img); a.href = searchurl; var div = document.createElement('div'); div.appendChild(a); if (debug){ var debugArea = document.createElement('textarea'); div.appendChild(debugArea); } var h1 = document.getElementsByTagName('h1')[0]; h1.parentNode.insertBefore(div, h1.nextSibling); var profileURL; GM_xmlhttpRequest({ method: 'GET', url: searchurl, headers: { 'User-agent': 'Mozilla/4.0 (compatible)' }, onload: function(responseDetails) { var responseText = responseDetails.responseText.replace(/<\/b><b>/ig, ""); if (debug) debugArea.value = responseText; reProfileURL = new RegExp('talent.yahoo.co.jp/talent/.+?\.html', "i"); reProfileTitle = new RegExp(word + '.*?の<b>プロフィール', "i"); reImgL = new RegExp('http://i.yimg.jp/images/talent/large/.+?jpg', "i"); reImgM = new RegExp('http://i.yimg.jp/images/talent/medium/.+?jpg', "i"); if (responseText.match(reImgM)) { if (debug) window.alert("reImgM found."); // alert(responseText.match(reImgM)); img.src = RegExp.lastMatch.replace(/medium/, "large"); } else if (responseText.match(reProfileTitle) && responseText.match(reProfileURL)) { responseText.match(reProfileURL); if (debug) window.alert("rePofile found."); profileURL = 'http://' + RegExp.lastMatch; if (debug) alert("profileURL=" + profileURL); GM_xmlhttpRequest({ method: 'GET', url: profileURL, headers: { 'User-agent': 'Mozilla/4.0 (compatible)' }, onload: function(responseDetails) { if (debug) alert(responseDetails.responseText.match(reImgL)); if (responseDetails.responseText.match(reImgL)) { img.src = RegExp.lastMatch; } } }); } else { // no image if (debug) alert("no image"); } } }); })();