Web Analytics Made Easy -
StatCounter

めモらンだム・ヤード

自分用のアプリ設定やスクリプト類の備忘録・覚え書き(Memorandum) / 作った物のライセンスはCC BY-NC-SAで。 / 内容が古いまま、間違ったまま、書いている途中、途中で放置など、手入れはあまり行き届いていない庭 / 対象の仕様変更で動かなくなったもの多々。WorkFlowy向けは全滅したので削除 / 製作物のインストール及び使用は各自の責任で。使用によって、利用者および第三者に損害が発生したとしても、当方は一切責任を負いかねます

はてなブログにエントリを書き込む(新規/上書き)だけのアクション

エントリIDが指定されていれば上書き、されていなければ新規投稿となる。


writeHatenaEntryアクション単体では書き込めないので、Scriptable.appも使う。

Scriptable.appに保存するスクリプト「hatenaWrite」

// Drafts.appにコールバックする関数
function ReturnValueToDrafts(rO, x) {
  const rJ = JSON.stringify(rO)
  console.log(rJ)

  const rt = encodeURIComponent(rJ)
  const curl = `${params[x]}?result=${rt}`
  console.log(curl)
  Safari.open(curl)
}

// Draftsから渡されたパラメーターの読み込み
const params = args.queryParameters
console.log(params)

const url = params.url
const cdHatena = params.cdHatena
const method = params.method
const body = params.body


// はてなからエントリーを読み込む
const rq = new Request(url)
rq.headers = {'Content-Type': 'application/atom+xml', 'Authorization': `Basic ${
cdHatena}`}
rq.method = method
rq.body = body

let rXML
rXML = await rq.loadString()
const resp = rq.response

console.log(resp)
console.log(resp.statusCode)
if (resp.statusCode == 200 || resp.statusCode == 201) {
  // 書き込みが成功した場合
    console.log(rXML)

  // 受け取ったXMLから、エントリーのURLと、エントリーIDを含んだEdit用URLを抽出
  const xmlParser = new XMLParser(rXML)
  let entry_url = edit_url= ""
  xmlParser.didStartElement = (elmntNameS, attrbO) => {
    if (elmntNameS == "link") {
      const attrbA = Object.entries(attrbO)
      if ( attrbA.some(a => a[0] == "rel" && a[1] == "alternate") ) {
        entry_url = attrbA.find(a => a[0]  == "href")[1]
        console.log(entry_url)
      }
      if ( attrbA.some(a => a[0] == "rel" && a[1] == "edit") ) {
        edit_url = attrbA.find(a => a[0]  == "href")[1]
        console.log(edit_url)
      }
    }
  }
  xmlParser.parse()

  // Draftsに書き込み成功時のデータを返す
  const rO = {}
  rO.statusCode = resp.statusCode
  rO.entry_url = entry_url
  rO.edit_url = edit_url
  ReturnValueToDrafts(rO, "x-success")

} else {
    
  // Draftsに書き込み失敗時のデータを返す
  const rO = {}
  rO.statusCode = resp.statusCode
  rO.entry_url = rO.edit_url = ""
  ReturnValueToDrafts(rO, "x-error")
}

Script.complete()


注意点は、

  • updatedの値が無い場合は、書き込んだ日時が自動的に入力される。
  • 各項目、例えばentry_id:の後ろには、たとえ値が無くても半角スペースが必要。
  • categoryは、値がある場合は、たとえ1個だけでも[]で囲む。
  • draftyesだと下書き、noだと公開(公開範囲は公開範囲の設定による)
  • entry_idの値は、はてなブログから割り振られるものなので、手動で書き込まない。
  • custom_urlは、https://〜hate〜/entry/よりも後ろの部分。値が無い場合は、はてなブログの設定 > 詳細設定 > フォーマット の記事URLの設定に従い割り振られる。

はてなブログAtomPub APIの仕様の制限で、


カスタムURLについては カスタムURLを指定した、はてなブログAtomPubによる記事投稿 - いっしきまさひこBLOG を参考にした。


Drafts.appのスクリプトアクションには、

The runtime is not a browser-based runtime, and does not contain DOM scripting capabilities.

と書かれている通り「XMLHttpRequest」や「Fetch API」が実装されていない様子。
その代わり、「HTTP」というオブジェクトを使うみたい。
しかし、そのHTTPオブジェクトのリクエストの、HTTPボディのエンコードフォーマットは「json」と「form」の2種類しかない。
AtomPubのボディはXMLで書かれた「string」。
Drafts.app単体では、ボディの必要の無い「GET」(読み込みや一覧読み込み)は可能だが、ボディが必要な「POST」(新規投稿)や「PUT」(既存のエントリの上書き)は不可能なようだった。
そこで、Scriptable.appをx-callback-urlで呼んで送信するようにした。

iOSやiPadOSだけでなく、ベータ版のScriptable for Macでも動いた。(MacBook Air(M1, 2020)にて)


このテーマの目次

©︎ 2022 Sorashima