💎
【令和6年保存版!】Rubyでライブラリ(gems)非依存でTwitter(X)・Bluesky・Misskeyに投稿するには
TwiterやBlueskyでは、ライブラリが提供されていますが、AWS Lambdaなどで容量を軽くしたいとか、Twitterのgemはメンテナンスされなくなってしまった、Misskeyに至ってはgemが提供されていないなどの理由で、外部ライブラリ非依存でコードを使いたい、そんなときにGPTさんたちに聞いたら教えてくれたのでメモとして残します。それぞれちゃんと動いています。
いずれも環境変数に認証情報をおいているほか、post_textに投稿内容を入れています。
Twitter(X)
140文字にカットしています。重複投稿は検出していません。
require 'net/http'
require 'uri'
require 'json'
require 'base64'
require 'openssl'
### 認証情報生成
# ここでは環境変数から取り出している
# Twitter認証情報
tw_consumer_key = ENV["tw_consumer_key"]
tw_consumer_secret = ENV["tw_consumer_secret"]
tw_access_token = ENV["tw_access_token"]
tw_access_token_secret = ENV["tw_access_token_secret"]
tw_create_tweet_url = "https://api.twitter.com/2/tweets"
### 投稿前準備完了
puts "投稿準備"
puts "投稿用テキスト: #{post_text}"
### Twitterへ投稿
# Twitterへの投稿
timestamp = Time.now.to_i
nonce = SecureRandom.hex
signature_params = {
oauth_consumer_key: tw_consumer_key,
oauth_nonce: nonce,
oauth_signature_method: 'HMAC-SHA1',
oauth_timestamp: timestamp,
oauth_token: tw_access_token,
oauth_version: '1.0'
}
signature_base_string = "POST&#{URI.encode_www_form_component(tw_create_tweet_url)}&#{URI.encode_www_form_component(signature_params.map { |k, v| "#{k}=#{v}" }.join('&'))}"
signing_key = "#{URI.encode_www_form_component(tw_consumer_secret)}&#{URI.encode_www_form_component(tw_access_token_secret)}"
signature = Base64.strict_encode64(OpenSSL::HMAC.digest('sha1', signing_key, signature_base_string))
headers = {
'Authorization' => "OAuth oauth_consumer_key=\"#{tw_consumer_key}\", oauth_nonce=\"#{nonce}\", oauth_signature=\"#{URI.encode_www_form_component(signature)}\", oauth_signature_method=\"HMAC-SHA1\", oauth_timestamp=\"#{timestamp}\", oauth_token=\"#{tw_access_token}\", oauth_version=\"1.0\"",
'Content-Type' => 'application/json'
}
body = {text: post_text.gsub(/〈[^〉]*〉/, "").slice(0, 140)}.to_json
uri = URI.parse(tw_create_tweet_url)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, headers)
request.body = body
puts "request.body: #{request.body}"
begin
twitter_response = http.request(request)
puts "twitterに投稿しました"
puts twitter_response.to_s
puts twitter_response.body.force_encoding("UTF-8")
# 投稿終わり
puts "投稿スクリプト終わり。Well done!"
rescue => e
puts "twitter投稿エラー"
puts twitter_response.to_s
puts twitter_response.body.force_encoding("UTF-8")
puts e.class
puts e.message
puts e.backtrace
end
Bluesky
require 'net/http'
require 'uri'
require 'json'
require 'base64'
require 'openssl'
### 認証情報生成
# ここでは環境変数から取り出している
# Bluesky認証情報
bs_username = ENV["bs_username"]
bs_password = ENV["bs_password"]
bs_pds_url = "https://bsky.social"
### 投稿前準備完了
puts "投稿準備"
puts "投稿用テキスト: #{post_text}"
###
# Blueskyへの投稿
uri = URI.parse("#{bs_pds_url}/xrpc/com.atproto.server.createSession")
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = true
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json')
request.body = { identifier: bs_username, password: bs_password }.to_json
response = http.request(request)
session = JSON.parse(response.body)
uri = URI.parse("#{bs_pds_url}/xrpc/com.atproto.repo.createRecord")
request = Net::HTTP::Post.new(uri.request_uri, 'Content-Type' => 'application/json', 'Authorization' => "Bearer #{session['accessJwt']}")
request.body = {
collection: 'app.bsky.feed.post',
repo: session['did'],
record: {
text: post_text,
createdAt: Time.now.utc.iso8601
}
}.to_json
begin
bluesky_response = http.request(request)
puts "blueskyに投稿しました"
puts bluesky_response.to_s
puts bluesky_response.body.to_s
rescue => e
puts "bluesky投稿エラー"
puts bluesky_response.to_s
puts bluesky_response.body.to_s
puts e.class
puts e.message
puts e.backtrace
return false
end
Misskey.io
require 'net/http'
require 'uri'
require 'json'
require 'base64'
require 'openssl'
### 認証情報生成
# ここでは環境変数から取り出している
# Misskey認証情報
mk_access_token = ENV["mk_access_token"]
### 投稿前準備完了
puts "投稿準備"
puts "投稿用テキスト: #{post_text}"
###
# misskeyへの投稿
uri = URI.parse("https://misskey.io/api/notes/create")
request = Net::HTTP::Post.new(uri)
request.content_type = "application/json"
request["Authorization"] = "Bearer #{mk_access_token}"
request.body = {"text": post_text}.to_json
req_options = {use_ssl: uri.scheme == "https"}
begin
response = Net::HTTP.start(uri.hostname, uri.port, req_options) do |http|
http.request(request)
end
if response.code == '200' then
# 投稿が成功しました
puts "Misskeyへの投稿が成功しました。"
else
puts "Misskeyへの投稿が失敗しました。"
raise
end
puts response.to_s
puts response.body.force_encoding("UTF-8")
# 投稿終わり
puts "投稿スクリプト終わり。Well done!"
rescue => e
puts "bluesky投稿エラー"
puts e.class
puts e.message
puts e.backtrace
puts response.to_s
puts response.body.force_encoding("UTF-8")
return false
end
Discussion