memorandums

日々の生活で問題解決したこと、知ってよかったことなどを自分が思い出すために記録しています。

ローカルのファイルをDropBoxにアップロードするクイックアクション(Mac)

背景

大学が契約している電子ジャーナルにアクセスするには学内ネットワークからアクセスする必要があります。学外からあれこれやって学内ネットワークに入りそこからで論文PDFをダウンロードして自分のPCに持ってくるまで。。。手間が必要でした。ちょっとした手間なんですが、これ何とかできたらいいのになぁ〜と思っていました。

で、最近、使い方がわかったクイックアクションで アップロードしたいファイルを右クリックしてメニューを選択したらクラウドストレージにアップロードできちゃう という素敵なことができたら、とあれこれやってみたログになります。

クイックアクションの作り方

このタイトルでたどり着く方がほとんどでしょうから先に結論を書きます。

(1)Automatorを起動してクイックアクションを作ります。

ちなみに作り方等々については、以下に多めに書いていますのでわからなければそちらを参考にしてください。

memorandums.hatenablog.com

(2)以下のように設定します。①を画面にように選択し、②のように「シェルスクリプトを実行」をドラッグ&ドロップします。③をRubyにして(Pythonは意地でも使わない、嘘💦)、④を画面にように選択し、⑤に以下のコードを貼り付けます。

DROPBOX_API_TOKEN = 'DropBoxから取得したアクセストークンをここにコピペします'

require 'dropbox_api'
db_client = DropboxApi::Client.new(DROPBOX_API_TOKEN)

ARGV.each do |f|
  db_client.upload(
    sprintf('/%s', f.split("/")[-1]),
    IO.read(f),
    :mode => :overwrite
  )
end

(3)DropBoxからアクセストークンを取得する

詳しくは以下のエントリーに書かれていますので参照してください。

tamulab.jp

といっても参照するのは手間かもしれませんので、以下に引用させていただきます。この記事はもう6年くらい前の記事ですが、現在のところ動作するようです。

ちなみに、やりたいことは、自分のDropBoxアカウントにアプリを作成して、そのアプリを使うためのアクセストークンを取得する、です。

事前準備としてDropboxにアプリを登録してアクセストークンを取得しておきます。Dropbox App Consoleを開いて Create app ボタンからアプリを追加します。 Dropbox API と Dropbox Business APIの選択がありますが、Dropbox APIを選択します。 次にアクセス権についてアプリ専用フォルダのみにするのか、アカウント単位にするのかと聞かれますが、ここは App folder を選ぶ方をオススメします。 App folder にするとDropboxのルートに アプリ というフォルダが作成され、さらにそのなかにアプリ名のフォルダが追加されます。このアプリ名のフォルダのみが作成したアプリから操作可能な領域になります。 作成したらアプリの設定画面で Generated access token のところにある Generate ボタンを押すと新しいトークンが発行されるので控えておきます。

(4)Ruby 2.6 のgemにライブラリ(dropbox_api)をインストールする

以下のコマンドでインストールできるはずですが。。。できません。

sudo gem install dropbox_api

上記のAutomatorの設定で/usr/bin/rubyを選択したと思います。これはバージョン2.6でMacにデフォルトで入っているバージョンになります。古いやつです。rbenvで入れたやつを動かそうとしたのですがどうもうまく行きませんでした。途中まではいい感じに行ったのですが。。。

で、本来であれば(Ruby環境が新しければ)上記のinstallコマンドで入ってくれるのですが、Ruby 2.6の環境では、dropbox_apiが使用している依存ライブラリのが相違があっていくつかのライブラリが古いためインストールできないと言われます。なので、gem install時に出てくるガイドにしたがって個別にちょっと新しいバージョンをいれます。もしかすると環境によって変わるかもしれませんが、以下、参考まで。

sudo gem install multi_xml -v 0.6.0
sudo gem install faraday-net_http -v 3.0.2
sudo gem install faraday -v 2.8.1

このあとに以下を実行します。

sudo gem install dropbox_api

ちなみに、MacのOSが古いといろいろと問題がでてきます。ちょっとここには書きませんが。。。

クイックアクションの実行方法

アップロードしたいファイルを右クリックして上記で作成したクイックアクションの名前を選択します。すると、うまくいけば、ファイルがDropboxにアップロードされて、Dropboxフォルダ内のアプリフォルダ内にファイルが同期されると思います。

その他

この作業を通してハマったこと知ったことを書いておきます。

UploadWriteFailedErrorがなかなか取れなくてハマったこと

サイトからRubyのコードをコピペして使わせていただいたのですが、そのコードの中の以下の部分は

    sprintf('/%s', f.split("/")[-1]),

もともと

    sprintf('/%s', f),

と書かれていました。fに何か入るかというと、クイックアクションで複数ファイルを選択して右クリックしたときも動作するようにしているため、そのファイル名がフルパスで入ってくるんですね。これは知っていました。

ちなみに後のコードで実行すると以下のようなエラーメッセージが表示されました。gemのソースコードも読んでみたのですが、どうもこの例外がでる条件がよくわかりません。知識がなかったのでroot権限で実行されるのかななどとあれこれやってみたのですがわかりませんでした。

格闘すること1,2時間くらい。ある記事を見ていて アップロードするときのパスの指定が違うよ というのを見て「なるほど」と思ったんです。パスなんて指定しているつもりがなかったのです。デバッグのときにはrubyで直接実行していたのでパス名はつきませんでした。でも、上記にも書いた通り クイックアクションでファイルを選択した場合はフルパスでファイル名が渡される んです。つまり、このアップロードするときのファイル名にパスがついた状態でリクエストが作成されるため、WriteエラーとしてDropbox側がエラーを返すという寸法だったようです。なるほどなぁ。。。

で、フルパスからパス情報を取り除いてファイル名だけにするように f.split("/")[-1] と書いてうまく行ったんですわ。気づかないものです。

Automatorをデバッグするテク

Automatorはバックグラウンドで処理されるため、シェルスクリプトやRubyの実行途中の情報を確認することができません。なんとなく実行しては結果を見てデバッグするしかないと思いました。

調べてみると方法はあるようで。Apple Scriptを使う手があるんですね。なるほどです。

例えば、上のコードでリクエスト情報を作っているところで中身を確認したいとしましょう。sprintfの結果を変数にいれて、その値を以下のようにすれば通知欄で確認することができます。こんなこと誰が考えるんでしょうね。。。素晴らしいです。

  a = sprintf('/%s', f)
  `osascript -e "display notification \\"#{a}\\""`

シェルスクリプトとして実行する場合の例はネットにもたくさんあったのですが、Rubyで実行する場合はなぜかうまくいきませんでした。変数の値の展開の部分です。

ポイントはエスケープシーケンスのためのバックスラッシュ自体をエスケープ処理する必要がある、つまり\と2つ重ねる必要があるというところですね。これポイントです。

今日もなかなかニッチな話を書いてきましたが、これでやっとPDFをワンタップ(+選択)でDropboxにアップロードできるようになりました。めでたしめでたし。