9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

HerokuAdvent Calendar 2017

Day 17

(多分)Twitterでアカウント規制されなくなる使い方

Last updated at Posted at 2017-12-17

経緯

なんか最近Twitterの規制が強くなったのか、やたらと色んな人のTwitterアカウントが凍結される事例が散見されます。

恐らくですが、何らかの禁止ワードが含まれていると、自動的にロックされるのではないかと予測されますが、何かしらユーザとして対処できるものはないかと考えておりましたが。
つい先日、くろば・U先生がTwitterで

と言うようなことを仰られ、以下のアイデアがピンと閃きました。

  1. 適当なCRUD機能を持つWebアプリをHerokuに作る
  2. ImageMagickでテキストを画像に変換する
  3. 変換された画像をCloudinaryにアップロードする
  4. アップロードされた画像のURLを取得してTwitterに投稿

思いつきのレベルだったんですが、ちょっと調べてみるとHerokuはImageMagickが使えるとのことなので、RMagick経由で画像生成してみたら行けるんじゃない? というノリで作ってみました。

作ったものは以下の通りです。
「Hagaki」
https://hagakipost.herokuapp.com/

Twitterアカウントでログインし、適当なテキストをツイート後、作成されたページからTweetボタンを押すとTwitterCard設定がされたURLがTwitterに投稿されます。

Webアプリの作成

ここらあたりは普通のRailsアプリとして作成します。
方法はググれば幾らも出てくるので省略しますが、Rails5.1で作ってみました。
ぶっちゃけBootstrap使いたいだけなのにWebpackerが矢鱈メンドかった。。

単純なCRUDなのでscaffoldで生成してもいいですが、今回は画像の生成とアップロードを間に挟むので少し手を加えています。
モデルはこんな感じにしてます。

  create_table "tweets", force: :cascade do |t|
    t.integer "user_id"
    t.text "content", null: false
    t.string "public_id", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.text "pic"
    t.index ["user_id"], name: "index_tweets_on_user_id"
  end

最初マルチテナントで考えていたので、ユーザ:Tweetが1:Nで考えていたのですが、結局無理そう(後述)なのでこの設定は削除する予定です。
public_idはCloudinaryにアップロードした画像のID指定に、picはアップロードした画像情報(これも後述)を格納します。
正直、picの中にpublic_idが含まれるので重複していると言えばそうですが、、(あんまりCloudinaryの仕様を調べずに設計してしまった)

画像生成の仕組みはこんな感じです。

  def create_image(content, public_id)
    content = content.scan(/.{1,#{20}}/).join('\n') # テキストを20文字で改行する
    image = Image.new(640, 480) # 画像サイズは640x480の決め打ち
    draw = Draw.new
    draw.font = Rails.root.join('.fonts/ipaexg.ttf').to_s # フォント指定(後述)
    draw.pointsize = 24
    draw.annotate(image, 640, 480, 50, 50, content)
    image.write("/tmp/#{public_id}.png") # 画像をtmpの下に書き出す
  end

Herokuのデフォルト状態だと日本語を表示するフォントがないので、別途用意する必要があります。
今回はIPAのフォントを使用しました。
Rails.rootの直下に.fonts/ディレクトリを作ってそこに入れています。

Cloudinaryへのアップロード、画像削除処理は以下の通り。

  def upload_image(public_id)
    Cloudinary::Uploader.upload("/tmp/#{public_id}.png", :public_id => public_id) if Rails.env.production?
  end

  def destroy_image(public_id)
    Cloudinary::Uploader.destroy(public_id) if Rails.env.production?
  end

Cloudinary::Uploader.uploadの成功時は以下のようなパラメータが返ってくるので、picカラムにjson形式で保存しておきます。

参考 : https://cloudinary.com/documentation/upload_images#data_upload_options

{
 public_id: 'sample',
 version: '1312461204',
 width: 864,
 height: 564,
 format: 'jpg',
 created_at: '2017-08-10T09:55:32Z',
 resource_type: 'image',
 tags: [], 
 bytes: 9597, 
 type: 'upload', 
 etag: 'd1ac0ee70a9a36b14887aca7f7211737', 
 url: 'https://res.cloudinary.com/demo/image/upload/v1312461204/sample.jpg',
 secure_url: 'https://res.cloudinary.com/demo/image/upload/v1312461204/sample.jpg',
 signature: 'abcdefgc024acceb1c1baa8dca46717137fa5ae0c3',
 original_filename: 'sample'
}

後は表示画面で、Tweetボタンを設置します。

<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
(略)
<a href="https://twitter.com/share" class="twitter-share-button" data-text="<%= @image_url %>" data-size="large">Tweet</a> 

後はボタンを押せば投稿される、、、のですが、

スクリーンショット 2017-12-17 15.08.56.png

画像が展開されない!!!

という致命的な欠陥を抱えているので、画像を見える形で投稿する場合は、以下の修正が必要になります。

OGP TwitterCardの設定

上記で設定した画像をOGPを設定したページのURLに設定することで、表示が可能になります。

新規で追加するURLだと/tweets/:id/imageという具合に設定します。

内容は以下の通りです。

<!DOCTYPE html>
<head prefix="og: http://ogp.me/ns# fb: http://ogp.me/ns/fb# article: http://ogp.me/ns/article#">
  <head>
    <meta property="og:title" content="hagaki" />
    <meta property="og:type" content="" />
    <meta property="og:url" content="https://hagakipost.herokuapp.com/" />
    <meta property="og:image" content="<%=@image_url %>" />
    <meta property="og:site_name"  content="hagaki" />
    <meta property="og:description" content="hagaki" />
 
    <!-- Twitter -->
    <meta name="twitter:title" content="hagaki" />
    <meta name="twitter:description" content="hagaki" />
    <meta name="twitter:card" content="summary_large_image">
    <meta name="twitter:site" content="https://hagakipost.herokuapp.com/" />
    <meta name="twitter:creator" content="@<%=@user.nickname %>">
    <meta name="twitter:image" content="<%=@image_url %>" />

    <!-- facebook -->
    <meta property="fb:app_id" content="<%=ENV['FACEBOOK_APP_ID'] %>" />
  </head>
  <body>
    <%= image_tag(@image_url) %>
  </body>
</html>

この設定後に投稿すると

twittercard.png

という具合にTwitterCardで表示してくれます。

別案・TwitterAPIを使う

TwitterAPIのクレデンシャルを開発者サイトから取得し、RubyからTwitterの投稿が出来る準備をします。

ライブラリ
https://github.com/sferik/twitter

上記の画像生成までの手順は同じで、作成した画像を以下の手順でTwitterに投稿します。

t = TwitterAPI::Client.new({
  :consumer_key => 'YOUR_CONSUMER_KEY',
  :consumer_secret => 'YOUR_CONSUMER_SECRET',
  :token => 'YOUR_ACCESS_TOKEN',
  :token_secret => 'YOUR_ACCESS_SECRET'
}) # クライアント設定

image = File.open("/tmp/#{public_id}.png", 'rb').read
t.media_upload({'media' => image})

ただしこの方法だとTwitterのクレデンシャルを登録したアカウントに限られます。。

結論

もうMastodonでやればいいんじゃないのではないでしょうか。。。

まだまだ直すところは山積みですが、とりあえず当初の課題は何とかクリアできました。

9
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?