• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    迪恩网络公众号

inox-ee/mstdn-app: Make mastodon client

原作者: [db:作者] 来自: 网络 收藏 邀请

开源软件名称(OpenSource Name):

inox-ee/mstdn-app

开源软件地址(OpenSource Url):

https://github.com/inox-ee/mstdn-app

开源编程语言(OpenSource Language):

JavaScript 98.2%

开源软件介绍(OpenSource Introduction):

※このREADMEはブログと同一のものです

Electron + ReactでMastodonクライアントを作る

Reactの勉強を始めて早1ヶ月。環境構築やAtomのクラッシュなどの困難を乗り越えた夏休み…

ようやくElectronまでたどり着いたのでMastodonクライアントを作ってみた。

ソースコードは「いまどきのJSプログラマーのためのNode.jsとReactアプリケーション(クジラ飛行船, 2017)」を参考にしています

環境

  • Windows 10 Home
  • Node.js v8.11.1
  • React v16.5.2
  • electron v3.0.0

まずはAPIを叩いてみる

アプリの認証(本来は「認可」というべきらしい。)

mastodon-apiを用いてMastodonのWeb API利用する。インスタンスは、Pixivが運営する https://pawoo.net にした。

このWeb APIはOAuth2という認証方法(*1)を行うため、以下の手順が必要。

  1. アプリをインスタンスに登録
  2. ユーザが認証し、アクセストークンを発行
  3. アクセストークンを用いてAPIにアクセス

正直mastodon-apiのライブラリがexampleファイルを用意してくれてるので適当にコピペすればおk。ということで割愛。

タイムラインの取得

先ほどのアクセストークンを利用して以下のようなプログラムを書くと簡単にタイムラインを表示できる

// MastodonのAPIクライアントの作成
const Mstdn = new Mastodon({
access_token: token,
timeout_ms: 60 * 1000,
api_url: instanceUri + '/api/v1/'
})

// タイムラインの読み込み
Mstdn.get('timelines/public', {})   
.then(res => {
    const data = res.data
    console.log(data)
})

ちなみにtimelines/homeにすればホームタイムラインが、timelines/publicにすれば公開タイムラインが表示されます。

トゥートしてみる

トゥートするのも簡単。そう、mastodon-apiならね。

// MastodonのAPIクライアントの作成
const Mstdn = new Mastodon({
  access_token: token,
  timeout_ms: 60 * 1000,
  api_url: instanceUri + '/api/v1/'
})

// Toot
let message = process.argv[2]
Mstdn.post('statuses',
  {status: message},
  (err, data, res) => {
    if (err) {
      console.error(err)
      return
    }
  })

結論:GETメソッドとPOSTメソッドが優秀すぎる。

アプリ成型

構成

構成はいたってシンプル。Electronを立ち上げ、アクティブになったらindex.htmlを読み込むだけ。

index.htmlからReactで書いたindex.jsxを呼んであげましょう。

Electronの立ち上げ

テンプレプログラムそのまま。ちなみにcreateWindow()のなかのprotocolでコロンを書き忘れ、2時間溶かしました。つらい。

// Electron
let mainWindow
app.on('ready', createWindow)
app.on('window-all-closed', () => app.quit())
app.on('activate', () => {
  if (mainWindow === null) createWindow()
})

// ウィンドウの作成
function createWindow () {
  mainWindow = new BrowserWindow({width: 600, height: 800})
  mainWindow.loadURL(url.format({
    pathname: path.join(__dirname, 'index.html'),
    protocol: 'file:',
    slashes: true
  }))
  mainWindow.on('closed', function () {
    mainWindow = null
  })
}

表示するページ

Electronから呼ばれるindex.htmlですが、のちのちindex.jsxをwebpackでビルドしてあげるので./out/index.jsを読み込むようにしてあげましょう。プログラムは割愛。

メインコンポネント

長すぎるので大幅に割愛してます。

  1. constructor()

まずはconstructor。loadInfo()内では、前項で取得したアクセストークンを読み込み、APIクライアントを作成。状態(state)にはトゥート内容を格納するtootdataと、タイムラインを構築するtimelinesを設定してあげる。

constructor(props) {
    super(props)
    this.apiUri = 'https://pawoo.net/api/v1/'
    this.loadInfo()
    this.state = {
        tootdata: '',
        timelines: []
    }
}
  1. componentWillMount()

そして次にコンポネントがマウントしたときの動作を書いたのですが、componentWillMount()ってReact v16.3.0以降は非推奨、v17.0.0から撤廃されるらしいですね…。

Deprecation warnings will be enabled with a future 16.x release, but the legacy lifecycles will continue to work until version 17. Even in version 17, it will still be possible to use them, but they will be aliased with an “UNSAFE_” prefix to indicate that they might cause issues. We have also prepared an automated script to rename them in existing code.

出典: React v16.3.0: New lifecycles and context API March 29, 2018 by Brian Vaughn

書き終わってからeslintに指摘されて気が付きました。ググってもイマイチ理解できなかったので新しいライフサイクルがどのようになるのか誰か教えて~

ちなみにcomponentWillMount内ではタイムラインを読み込むloadTimelines()を30秒に1回リロードしています。

  1. handleText(e) & tootFunc(e)

あと必要なのはトゥート処理。これも前項で紹介したPOSTメソッドを使い、「statuses」APIに投稿したのち、テキストボックスとタイムラインを更新してあげればよい。

  1. render()

いよいよ描画。アプリの顔を作っていきましょう。

デザインにはあまり凝らなかったので、とりあえずトップに投稿フォーム、その下にタイムラインを表示するという構成に。以下のようにプログラムすれば十分でしょう。タイムライン表示のrenderTimelines()は後述。

render () {
    return (
        <div>
            <div>
                <h1>Mastodon Client</h1>
                <textarea
                value={this.state.tootdata}
                onChange={e => this.handleText(e)} />
                <div>
                <button onClick={e => this.tootFunc(e)}>Toot</button>
                </div>
            </div>
            <div style={{marginTop: 120}}></div>
            {this.renderTimelines()}
        </div>
    )
}
  1. renderTimelines()

一番難しい、、、というか写経したあとなるほどな~って勉強してた()

タイムラインを構築するコツはmapメソッドを使うところですかね。あとGETメソッドで返ってくるHTTPレスポンスはHTMLタグで囲まれています(Reactではエスケープされる)。これをdangerouslySetInnerHTMLを利用して直接span要素に指定する という発想はなかった。というかそもそもプロパティが全く分からないのも苦労した…。下記参考リンクを見つけなければ迷宮入りしてたよ。(accountがトゥートした投稿者を表すオブジェクト、contentがトゥート内容)

というわけでプログラム。

renderTimelines () {
    const lines = this.state.timelines.map(e => {
        console.log(e)
        // when boosted
        let memo = null
        if (e.reblog) {
            memo = (<p>{e.account.display_name}さんがブーストしました</p>)
            e = e.reblog
        }
        // content every toot
        return (
        <div key={e.id}>
            <img src={e.account.avatar} />
            <div>{memo}{e.account.display_name}<span dangerouslySetInnerHTML={{__html: e.content}} /></div>
            <div style={{clear: 'both'}} />
        </div>
        )
    })
    return (
        <div>
            <h2>TimeLines</h2>
            {lines}
        </div>
    )
}

むずかしいね

  1. css

お好みで。

アプリの実行

あとはwebpackでビルドしてelectron .で実行してあげるだけ。

以下のように立ち上がったら完成です。

参考サイト一覧

API

OAuth2




鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
killua99/mastodon-docker: Mastodon 发布时间:2022-08-18
下一篇:
Fenntasy/mammut: Desktop client for Mastodon发布时间:2022-08-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap