【TwitterAPI】「사치스러운 이름이네. 지금부터 너의 이름은 ○○이다.」【Ruby】

동기


  • 2019/8/16에 금요일 로드쇼에서 「천과 치히로의 은폐」가 방송되었다
  • 이전에 조금 유행한 update_name(트위터상에서, 리플라이에 반응해 자신의 Twitter 네임을 변경하는 것)이 UserStream의 폐지에 따라 구현이 곤란해지고 있어, 어떻게 든 REST API만으로 재현할 수 없는지 생각했다
  • 이 기사를보고 비슷한 것을 루비로 쓰려고했습니다

  • 모두 내 트위터의 이름을 자유롭게 바꿀 수 있습니다.

    환경과 사용한 것


  • macOS 10.14.5
  • Ruby 2.5.1
  • TwitterAPI … Twitter Developers에 등록되어 있다고 가정합니다.

  • 사양


  • "좋아, 지금부터 @fyhcu의 이름은 ○○이다."라는 리플라이를, 최신 50건의 리플라이로부터 정규 표현으로 찾아낸다. 대사는 조금 바꾸고 있습니다. (가능한 간단한 문장으로 하고 싶었기 때문에)
  • Twitter의 제한상, 이름이 50문자 이상이 되는 것은 설정할 수 없기 때문에 이것을 제외. 또한 이전에 후보에 오른 것도 제외. 후보가 되었는지 여부는 좋아하고 있는지 여부로 판단합니다.
  • 후보가 된 트윗을 배열에 저장하고 그 트윗을 좋아합니다. (이것으로 다음 움직일 때의 후보에 오르지 않게 됩니다)
  • 저장된 후보에서 임의로 선택합니다.
  • 이름을 해당 단어로 변경. 변경한 것을 트윗.

  • 결과







    구현



    메인 부분



    main.rb
    require_relative '../Privatekey/oauth_twitter'
    require_relative 'isfavorited'
    require 'timers' #定期実行用
    
    timers = Timers::Group.new
    
    timers.every(600){ #600秒 = 10分ごとに処理
    
      reply_array = [] #リプライを格納する配列
      random = 0 #改名候補ツイートから無作為に選ぶため
    
      reg1 = /^いいかい、今から@fyhcu の名前は(.*)だ。$/ #湯婆婆
    
      @client.mentions(count: 60).each do |reply|
        if (reg1 =~ reply.text) #湯婆婆になっているリプライを探す
          puts "-----------------------------------------------------------"
          puts reply.text
    
          #名前が50文字以上に設定されているツイートは除外
          if ($1.length >= 50)
            next #次の繰り返しに移動
          end
    
          #既に自分がふぁぼってるツイートは除外
          if isfavorited(reply.id)  == true
            puts "<<<<<<<この返信は既にいいねされています>>>>>>>>"
            next
          end
    
          reply_array << $1 #改名候補を格納
    
          @client.favorite(reply.id) #ツイートをいいね
    
        end
      end
    
      puts "-----------------------------------------------------------"
      time_f = Time.now.strftime("%F %X") #実行時間を記録
    
      if reply_array.size > 0 #改名候補がある時のみ
    
        random = rand(reply_array.size) #ランダムに数字を一つ選ぶ
        aftername = reply_array[random] #変更後の名前を決定
        puts "#{aftername}に改名決定です"
    
        @client.update_profile(:name => aftername) #改名
    
        tweet = "湯婆婆によって名前が#{aftername}に変えられました。"
        @client.update tweet
    
        #ログに書き込み
        File.open("../log/yubaba-app-log.txt", "a") do |text|
          text.puts(" => #{aftername}に改名 [#{time_f}]")
        end
    
      else #改名候補がない時(配列に何も格納されていない時)
    
        puts "改名候補がありませんでした。"
    
        #ログに書き込み
        File.open("../log/yubaba-app-log.txt", "a") do |text|   
          text.puts(" => 変化なし [#{time_f}]")
        end
      end
    }
    
    1000.times{ #1000回実行(この実装は良くなさそう)
      timers.wait
      puts Time.now.strftime("****************** %Rに実行しました ******************")
     }
    

    유파파 구문은 정규 표현식을 사용하여 픽업합니다. 정규 표현식에서 일치하고 특정 조건을 충족하는 응답 변경 후 이름 부분을 배열에 저장합니다. 정규식 그룹화()와 역참조$1,$2,...가 매우 유용했습니다. 다음의 후보에 들어가지 않게, @client.favorite(id)로 좋아합니다. UserStream이 움직이고 있었던 그 무렵의 update_name에 접근하고 싶기 때문에, 10분마다 정기 실행을 걸고 있습니다. Timer를 사용하고 있습니다만, 아마 좋지 않은 생각이 들기 때문에 조만간에 Heroku Scheduler라든지 사용할 수 있으면 좋겠습니다.

    또한 main.rb를 실행하면 터미널에 정규 표현식에 의해 픽업 된 트윗과 괜찮은지 여부를 표시합니다. 런타임에 개명의 유무에 관계없이 로그를 쓰도록 했습니다.

    ※이 코드의 그대로라면 일정 시간내에 2회 같은 이름으로 변경되면 2회째 이후 개명한 취지의 트윗이나 중복에 의해 트윗할 수 없는 상황이 되어 버립니다. 예외 처리로 어떻게든 할 수 있으면… (기분이 맞으면 실장합니다)

    isfavorite 메서드



    "자신이 있는 트윗에 대해 좋아하는가?"를 boolean으로 돌려주는 메소드가 없었기 때문에 자작했습니다. JSON.parse가 편리했습니다.

    isfavorited.rb
    require_relative '../Privatekey/oauth_twitter'
    require 'json' #JSON扱うためのgem
    require 'oauth'
    
    # ツイートに対して、自分がいいねしているか調べるメソッド
    
    def isfavorited(tweet_id)
      consumer = OAuth::Consumer.new(
        @client.consumer_key,
        @client.consumer_secret,
      )
    
      endpoint = OAuth::AccessToken.new(consumer, @client.access_token, @client.access_token_secret)
      responce = endpoint.get("https://api.twitter.com/1.1/statuses/show/#{tweet_id.to_s}.json")
      result = JSON.parse(responce.body)
      fav = result["favorited"]
    
    end
    
    https://api.twitter.com/1.1/statuses/show/#{tweet_id.to_s}.json"는 트윗(ID 지정)의 개별 정보를 얻을 수 있는 엔드포인트이며 응답은 JSON입니다.

    GET statuses/show/:id - TwitterDevelopers

    응답 본문에 있는 favorited: true(false)가 자신이 좋아하는지 여부를 나타냅니다. 이것을 끌어 내고 궁극적으로 boolean을 그대로 반환하도록합니다. 실제로, 이 2행이 있는 것만으로 상당히 여러가지 할 수 있다고 생각합니다.
    responce = endpoint.get("https://api.twitter.com/1.1/statuses/show/#{tweet_id.to_s}.json")
    result = JSON.parse(responce.body)
    

    감상



    의외로 쉽게 구현할 수있었습니다. 가득 놀 수 있기 때문에 만족합니다. 앞으로도 쓸모없는 것을 구현해 보려고 생각합니다.

    좋은 웹페이지 즐겨찾기