Class: Elephrame::Bots::BaseBot

Inherits:
Object
  • Object
show all
Defined in:
lib/elephrame/bot.rb

Overview

a superclass for other bots holds common methods and variables

Constant Summary collapse

NoBotRegex =
/#?NoBot/i
'https://fediverse.network/mastodon?build=gab'

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeElephrame::Bots::BaseBot

Sets up our REST client, gets and saves our username, sets default value for strip_html (true), and max_retries (5), failed


25
26
27
28
29
30
31
32
33
34
35
# File 'lib/elephrame/bot.rb', line 25

def initialize

  raise "Fuck off Gabber" if Net::HTTP.get(URI.parse(FNGabLink)).include? URI.parse(ENV['INSTANCE']).host
  
  @client = Mastodon::REST::Client.new(base_url: ENV['INSTANCE'],
                                       bearer_token: ENV['TOKEN'])
  @username = @client.verify_credentials().acct
  @strip_html = true
  @max_retries = 5
  @failed = { media: false, post: false }
end

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client


13
14
15
# File 'lib/elephrame/bot.rb', line 13

def client
  @client
end

#failedObject (readonly)

Returns the value of attribute failed


13
14
15
# File 'lib/elephrame/bot.rb', line 13

def failed
  @failed
end

#max_retriesObject

Returns the value of attribute max_retries


14
15
16
# File 'lib/elephrame/bot.rb', line 14

def max_retries
  @max_retries
end

#strip_htmlObject

Returns the value of attribute strip_html


14
15
16
# File 'lib/elephrame/bot.rb', line 14

def strip_html
  @strip_html
end

#usernameObject (readonly)

Returns the value of attribute username


13
14
15
# File 'lib/elephrame/bot.rb', line 13

def username
  @username
end

Class Method Details

.backup_method(method, new_name) ⇒ Object

A helper method that is a wrapper around alias_method (just to make some code easier to read)

Parameters:

  • method (Symbol)

    symbol with the name of a method

  • new_name (Symbol)

    symbol with the new name for the method


157
158
159
# File 'lib/elephrame/bot.rb', line 157

def self.backup_method(method, new_name)
  alias_method new_name, method
end

Instance Method Details

#fetch_account_id(account_name) ⇒ String

Gets the ID of an account given the user's handle or username

Parameters:

  • account_name (String)

    either the user's full handle or their username. E.g., [email protected], zac

Returns:

  • (String)

    ID of account


137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/elephrame/bot.rb', line 137

def ()
  name = .reverse.chomp('@').reverse
  search = @client.search("@#{name}")

  accounts = {}
  search.accounts.each do |acct|
    accounts[acct.acct] = acct.id
    accounts[acct.username] = acct.id
  end

  accounts[name]
end

#fetch_list_id(name) ⇒ Integer

Gets the ID of a list given the name

Parameters:

  • name (String)

    name of the list

Returns:

  • (Integer)

122
123
124
125
126
127
128
# File 'lib/elephrame/bot.rb', line 122

def fetch_list_id(name)
  lists = {}
  @client.lists.collect do |l|
    lists[l.title] = l.id
  end
  lists[name]
end

#find_ancestor(id, depth = 10, stop_at = 1) ⇒ Mastodon::Status

Finds most recent post by bot in the ancestors of a provided post

Parameters:

  • id (String)

    post to base search off of

  • depth (Integer) (defaults to: 10)

    max number of posts to search

  • stop_at (Integer) (defaults to: 1)

    defines which ancestor to stop at

Returns:


88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/elephrame/bot.rb', line 88

def find_ancestor(id, depth = 10, stop_at = 1)
  depth.times {
    post = @client.status(id) unless id.nil?
    id = post.in_reply_to_id

    stop_at -= 1 if post..acct == @username

    return post if stop_at.zero?
  }

  return nil
end

#no_bot?(account_id) ⇒ Bool

Checks to see if a user has some form of “#NoBot” in their bio or in their profile fields (so we can make making friendly bots easier!)

Parameters:

  • account_id (String)

    id of account to check bio

Returns:

  • (Bool)

109
110
111
112
113
# File 'lib/elephrame/bot.rb', line 109

def no_bot? 
  acct = @client.()
  acct.note =~ NoBotRegex ||
    acct.fields.any? {|f| f.name =~ NoBotRegex || f.value =~ NoBotRegex}
end

#post(text, visibility: 'unlisted', spoiler: '', reply_id: '', hide_media: false, media: []) ⇒ Object

Creates a post, uploading media if need be

Parameters:

  • text (String)

    text to post

  • visibility (String) (defaults to: 'unlisted')

    visibility level

  • spoiler (String) (defaults to: '')

    text to use as content warning

  • reply_id (String) (defaults to: '')

    id of post to reply to

  • hide_media (Bool) (defaults to: false)

    should we hide media?

  • media (Array<String>) (defaults to: [])

    array of file paths


47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/elephrame/bot.rb', line 47

def post(text, visibility: 'unlisted', spoiler: '',
         reply_id: '', hide_media: false, media: [])
  
  uploaded_ids = []
  unless media.size.zero?
    @failed[:media] = retry_if_needed {
      uploaded_ids = media.collect {|m|
        @client.upload_media(m).id
      }
    }
  end
  
  options = {
    visibility: visibility,
    spoiler_text: spoiler,
    in_reply_to_id: reply_id,
    media_ids: @failed[:media] ? [] : uploaded_ids,
    sensitive: hide_media
  }

  # create a unique key for the status
  #  this key prevents a status from being posted more than once
  #  SHOULD be unique enough, by smooshing time and content together
  idempotency = Digest::SHA256.hexdigest("#{Time.now}#{text}")
  
  @failed[:post] = retry_if_needed {
    options[:headers] = { "Idempotency-Key" => idempotency }
    @client.create_status text, options
  }
end