elephrame 0.2.0 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 898b60769d6d1b3e6cb144017948786c46b39a7afcde1a73da8858f91d8ae425
4
- data.tar.gz: fc7e8caf3197c2a4634b325c0535f8d9a05c01e17cc05bc0d13a2ffc35f0ffc5
3
+ metadata.gz: 9bacbf531fa6368eb2e401e3492192eb9ae230966edc62f3971f3566430b64f5
4
+ data.tar.gz: 8a09ce7796b7acd043f73195fd7511eda01cd8f5abf6de2aa081f17aec1fa46c
5
5
  SHA512:
6
- metadata.gz: 70f4e752ecb1eb3dfc24304539c1c291b7b00a8052a4356858105fc305e83895306f5ae2ca449bccccdd64b26aeafbfe044b69fe78c34a02bb620e0d609fef37
7
- data.tar.gz: e94ab3417ab4f45bca3b4e63ba62077932611191fa3eaab634c79fee7981575388dabb3f1b24974fe5a6c9ba5d95b4000c36bcf59aecfd16091ddf640b82f257
6
+ metadata.gz: f836c9f830ea5a24a52f8e708b96a6e26ecfff5c03182b0ccbf98787442f9ab4b9508bdd2ff9a340cd318723d265f97bd07506725048d2b2313bd86cd5451e99
7
+ data.tar.gz: 356c31e481d1d7892759fed57dbc41610364624e60725c23ff53f788a2245e66e5a6843f88ab4cf7295065dcfcf193a8f252167f57f9c89195482714543a548d
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- elephrame (0.2.0)
4
+ elephrame (0.3.2)
5
5
  moostodon (~> 0.2.0)
6
6
  rufus-scheduler
7
7
 
data/README.md CHANGED
@@ -1,8 +1,13 @@
1
1
  # Elephrame
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/elephrame`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ [![Gem Version](https://badge.fury.io/rb/elephrame.svg)](https://badge.fury.io/rb/elephrame)
4
+ [RubyDoc](https://www.rubydoc.info/github/theZacAttacks/elephrame/)
4
5
 
5
- TODO: Delete this and the text above, and describe your gem
6
+ Elephant-Framework
7
+
8
+ A framework that helps simplify the creation of bots for mastodon/pleroma
9
+
10
+ Uses [rufus-scheduler](https://github.com/jmettraux/rufus-scheduler) in the backend
6
11
 
7
12
  ## Installation
8
13
 
@@ -20,20 +25,63 @@ Or install it yourself as:
20
25
 
21
26
  $ gem install elephrame
22
27
 
28
+ ## Quickstart
29
+
30
+ bot that posts "i'm gay" every three hours:
31
+
32
+ ```ruby
33
+ require 'elephrame'
34
+
35
+ my_bot = Elephrame::Bots::Periodic.new '3h'
36
+
37
+ my_bot.run { |bot|
38
+ bot.post("i'm gay")
39
+ }
40
+ ```
41
+
42
+ $ INSTANCE="https://mastodon.social" TOKEN="your_access_token" ruby bot.rb
43
+
44
+ Check the [examples](https://github.com/theZacAttacks/elephrame/tree/master/examples) directory for more example bots
45
+
46
+ ### Bot Types
47
+
48
+ So far the framework support 4 bot types: Periodic, Interact, PeroidInteract, Reply
49
+
50
+ - `Periodic` supports posting on a set schedule
51
+ - `Interact` supports callbacks for each type of interaction (favorites, boosts, replies, follows)
52
+ - `PeriodInteract` supports both of the above (I know, this isn't a good name)
53
+ - `Reply` only supports replying to mentions
54
+
55
+ The string passed to `Periodic` and `PeroidInteract` must be either a 'Duration' string or a 'Cron' string, as parsable by [fugit](https://github.com/floraison/fugit)
56
+
23
57
  ## Usage
24
58
 
25
- TODO: Write usage instructions here
59
+ All the documentation is over at [RubyDoc](https://www.rubydoc.info/github/theZacAttacks/elephrame/)!
60
+
61
+ Every place that accepts a block provides access to the bot object. This allows for easy access to some provided helper methods, as well as the actual mastodon access object.
62
+
63
+ Exposed methods from bot object:
64
+
65
+ - `client` this is the underlying mastodon rest client we use in the backend. use this to make custom calls to the api for which we don't provide a helper
66
+ - `username` the name of the bot as fetched by verify_credentials
67
+ - `strip_html` (defaults to true) if set, the framework will automatically strip all html symbols from the post content
68
+ - `post(content, visibility: 'unlisted', spoiler: '', reply_id: '', media: [])` this provides an easy way to post statuses from inside code blocks
69
+ - `reply(content)` a shorthand method to reply to the last mention (Note: doesn't automatically @ the other user/s)
70
+ - `find_ancestor(id, depth = 10, stop_at = 1)` looks backwards through reply chains for the most recent post the bot made starting at post `id` until it hits `depth` number of posts, or finds `stop_at` number of it's own posts
71
+ - `no_bot?(account_id)` returns true if user with `account_id` has some form of "#NoBot" in their bio
72
+
73
+ (See RubyDocs for source code documentation)
26
74
 
27
75
  ## Development
28
76
 
29
77
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
30
78
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
79
+ To install this gem onto your local machine, run `bundle exec rake install`.
32
80
 
33
81
  ## Contributing
34
82
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/elephrame. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
83
+ Bug reports and pull requests are welcome on GitHub at https://github.com/theZacAttacks/elephrame. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
36
84
 
37
85
  ## Code of Conduct
38
86
 
39
- Everyone interacting in the Elephrame project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/[USERNAME]/elephrame/blob/master/CODE_OF_CONDUCT.md).
87
+ Everyone interacting in the Elephrame project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/theZacAttacks/elephrame/blob/master/CODE_OF_CONDUCT.md).
@@ -0,0 +1,5 @@
1
+ # Elephrame Examples
2
+
3
+ Follow the gem installation from the [main README](https://github.com/theZacAttacks/elephrame/tree/master/README.md) and then do the following, where `[file]` is one of the example ruby scripts
4
+
5
+ $ INSTANCE="https://mastodon.social" TOKEN="your_token_here" ruby [file]
data/examples/interact.rb CHANGED
@@ -3,8 +3,12 @@ require 'elephrame'
3
3
  interacter = Elephrame::Bots::Interact.new
4
4
 
5
5
  interacter.on_reply { |bot, post|
6
- bot.post("@#{post.account.acct} Thanks for helping me test stuff :3",
7
- reply_id: post.id, visibility: post.visibility)
6
+
7
+ #bot.post("@#{post.account.acct} Thanks for helping me test stuff :3",
8
+ # reply_id: post.id, visibility: post.visibility)
9
+
10
+ ## this can be simplified to one line
11
+ bot.reply("@#{post.account.acct} Thanks for helping me test stuff :3")
8
12
  }
9
13
 
10
14
  interacter.on_fave { |bot, notif|
data/examples/reply.rb CHANGED
@@ -3,6 +3,5 @@ require 'elephrame'
3
3
  replier = Elephrame::Bots::Reply.new
4
4
 
5
5
  replier.run { |bot, mention|
6
- bot.post("@#{mention.account.acct} hey!", reply_id: mention.id,
7
- visibility: mention.visibility)
6
+ bot.reply("@#{mention.account.acct} hey!")
8
7
  }
data/lib/elephrame/bot.rb CHANGED
@@ -1,19 +1,39 @@
1
1
  module Elephrame
2
2
  module Bots
3
-
3
+
4
+ ##
4
5
  # a superclass for other bots
5
- # holds common functions and the rest api client
6
+ # holds common functions and variables
7
+
6
8
  class BaseBot
7
- attr_reader :client
9
+ attr_reader :client, :username
10
+ attr_accessor :strip_html
8
11
 
12
+ ##
13
+ # Sets up our REST client, gets and saves our username, sets default
14
+ # value for strip_html (true)
15
+ #
16
+ # @return [Elephrame::Bots::BaseBot]
17
+
9
18
  def initialize
10
19
  @client = Mastodon::REST::Client.new(base_url: ENV['INSTANCE'],
11
20
  bearer_token: ENV['TOKEN'])
21
+ @username = @client.verify_credentials().acct
22
+ @strip_html = true
12
23
  end
24
+
25
+ ##
26
+ # Creates a post, uploading media if need be
27
+ #
28
+ # @param text [String] text to post
29
+ # @param visibility [String] visibility level
30
+ # @param spoiler [String] text to use as content warning
31
+ # @param reply_id [String] id of post to reply to
32
+ # @param media [Array<String>] array of file paths
13
33
 
14
34
  def post(text, visibility: 'unlisted', spoiler: '', reply_id: '', media: [])
15
35
 
16
- if not media.empty?
36
+ unless media.empty?
17
37
  media.collect! {|m|
18
38
  @client.upload_media(m).id
19
39
  }
@@ -28,8 +48,43 @@ module Elephrame
28
48
 
29
49
  @client.create_status text, options
30
50
  end
31
- end
32
51
 
52
+
53
+ ##
54
+ # Finds most recent post by bot in the ancestors of a provided post
55
+ #
56
+ # @param id [String] post to base search off of
57
+ # @param depth [Integer] max number of posts to search
58
+ # @param stop_at [Integer] defines which ancestor to stop at
59
+ #
60
+ # @return [Mastodon::Status]
61
+
62
+ def find_ancestor(id, depth = 10, stop_at = 1)
63
+ depth.each {
64
+ post = @client.status(id) unless id.nil?
65
+ id = post.id
66
+
67
+ stop_at -= 1 if post.account.acct == @username
68
+
69
+ return post if stop_at.zero?
70
+ }
71
+
72
+ return nil
73
+ end
74
+
75
+ ##
76
+ # Checks to see if a user has some form of "#NoBot" in their bio
77
+ # (so we can make make friendly bots easier!)
78
+ #
79
+ # @param account_id [String] id of account to check bio
80
+ #
81
+ # @return [Bool]
82
+
83
+ def no_bot? account_id
84
+ @client.account(account_id).note =~ /#?NoBot/i
85
+ end
86
+
87
+ end
33
88
  end
34
89
  end
35
90
 
@@ -4,11 +4,24 @@ require_relative '../bot'
4
4
 
5
5
  module Elephrame
6
6
  module Bots
7
- # a bot that posts things on an interval
8
- # but can also respond to interactions
7
+
8
+ ##
9
+ # a bot that posts things on an interval but can also respond
10
+ # to interactions
11
+ #
12
+ # requires on_* variables to be set before running, otherwise the bot
13
+ # won't react to interactions
14
+
9
15
  class PeriodInteract < BaseBot
10
16
  include Elephrame::Scheduler
11
17
  include Elephrame::AllInteractions
18
+
19
+ ##
20
+ # creates a new PeriodInteract bot
21
+ #
22
+ # @param intv [String] string specifying interval to post
23
+ #
24
+ # @return [Elephrame::Bots::PeriodInteract]
12
25
 
13
26
  def initialize intv
14
27
  super()
@@ -16,6 +29,11 @@ module Elephrame
16
29
  setup_scheduler intv
17
30
  setup_streaming
18
31
  end
32
+
33
+ ##
34
+ # Runs the bot. requires a block for periodic post logic, but relies on
35
+ # on_* functions for interaction logic. See Elephrame::AllInteractions
36
+ # for more details.
19
37
 
20
38
  def run
21
39
  run_scheduled &Proc.new
@@ -3,10 +3,23 @@ require_relative '../bot'
3
3
 
4
4
  module Elephrame
5
5
  module Bots
6
+
7
+ ##
6
8
  # a bot that runs commands based off of
7
9
  # an interval or a cron string
10
+
8
11
  class Periodic < BaseBot
9
12
  include Elephrame::Scheduler
13
+
14
+ ##
15
+ # creates a new Periodic bot
16
+ #
17
+ # @param intv [String] string specifying interval to post.
18
+ # ex: '3h' (every 3 hours) '20m' (every 20 minutes)
19
+ # '00 12 * * *' (every day at 12:00)
20
+ # '00 00 25 12 *' (midnight on christmas)
21
+ #
22
+ # @return [Elephrame::Bots::Periodic]
10
23
 
11
24
  def initialize intv
12
25
  super()
@@ -2,7 +2,11 @@ module Elephrame
2
2
  module Scheduler
3
3
  attr :scheduler, :interval
4
4
  attr_reader :schedule
5
-
5
+
6
+ ##
7
+ # Creates a new scheduler
8
+ #
9
+ # @param intv [String] string specifying interval to post
6
10
  def setup_scheduler intv
7
11
  require 'rufus-scheduler'
8
12
 
@@ -10,6 +14,9 @@ module Elephrame
10
14
  @interval = intv
11
15
  @scheduler = Rufus::Scheduler.new
12
16
  end
17
+
18
+ ##
19
+ # Runs the schedule. Requires a block to be passed to it.
13
20
 
14
21
  def run_scheduled
15
22
  @scheduler.repeat @interval do |j|
@@ -4,7 +4,12 @@ require_relative '../bot'
4
4
  module Elephrame
5
5
  module Bots
6
6
 
7
+ ##
7
8
  # a bot that can respond to all interactions
9
+ #
10
+ # Call on_fave, on_follow, on_reply, or on_boost with a block
11
+ # before calling run. Otherwise bot will do nothing.
12
+
8
13
  class Interact < BaseBot
9
14
  include Elephrame::Streaming
10
15
  include Elephrame::AllInteractions
@@ -16,9 +21,13 @@ module Elephrame
16
21
  end
17
22
  end
18
23
 
24
+
25
+ ##
19
26
  # a bot that only replies when mentioned
27
+ #
20
28
  # run accepts a block, but also supports
21
- # use of on_reply
29
+ # use of on_reply (See Elephrame::AllInteractions for more details)
30
+
22
31
  class Reply < BaseBot
23
32
  include Elephrame::Streaming
24
33
  include Elephrame::Reply
@@ -2,23 +2,69 @@ module Elephrame
2
2
  module Streaming
3
3
  attr :streamer
4
4
 
5
+ ##
6
+ # Creates the stream client
7
+
5
8
  def setup_streaming
6
9
  @streamer = Mastodon::Streaming::Client.new(base_url: ENV['INSTANCE'],
7
10
  bearer_token: ENV['TOKEN'])
8
11
  end
12
+
9
13
  end
10
-
14
+
15
+
11
16
  module Reply
12
- attr :on_reply
17
+ attr :on_reply, :mention_data
13
18
 
19
+ ##
20
+ # Sets on_reply equal to +block+
21
+
14
22
  def on_reply &block
15
23
  @on_reply = block
16
24
  end
17
25
 
26
+ ##
27
+ # Replies to the last mention the bot recieved using the mention's
28
+ # visibility and spoiler with +text+
29
+ #
30
+ # *DOES NOT AUTOMATICALLY INCLUDE @'S*
31
+ #
32
+ # @param text [String] text to post as a reply
33
+
34
+ def reply(text)
35
+
36
+ # maybe also @ everyone from the mention? idk that seems like a bad idea tbh
37
+ post(text, @mention_data[:vis], @mention_data[:spoiler],
38
+ @mention_data[:id])
39
+ end
40
+
41
+ ##
42
+ # Stores select data about a post into a hash for later use
43
+ #
44
+ # @param mention [Mastodon::Status] the most recent mention the bot received
45
+
46
+ def store_mention_data(mention)
47
+ @mention_data = {
48
+ id: mention.id,
49
+ vis: mention.visibility,
50
+ spoiler: mention.spoiler_text,
51
+ mentions: mention.mentions
52
+ }
53
+ end
54
+
55
+ ##
56
+ # Starts a loop that checks for mentions from the authenticated user account
57
+ # running a supplied block or, if a block is not provided, on_reply
58
+
18
59
  def run_reply
19
60
  @streamer.user do |update|
20
61
  next unless update.kind_of? Mastodon::Notification and update.type == 'mention'
21
62
 
63
+ # this makes it so .content calls strip instead
64
+ update.status.class.module_eval { alias_method :content, :strip } if @strip_html
65
+
66
+ store_mention_data update.status
67
+
22
68
  if block_given?
23
69
  yield(self, update.status)
24
70
  else
@@ -30,21 +76,35 @@ module Elephrame
30
76
  alias_method :run, :run_reply
31
77
  end
32
78
 
79
+
33
80
  module AllInteractions
34
81
  include Elephrame::Reply
35
82
  attr :on_fave, :on_boost, :on_follow
83
+
84
+ ##
85
+ # Sets on_fave equal to +block+
36
86
 
37
87
  def on_fave &block
38
88
  @on_fave = block
39
89
  end
90
+
91
+ ##
92
+ # Sets on_boost to +block+
40
93
 
41
94
  def on_boost &block
42
95
  @on_boost = block
43
96
  end
97
+
98
+ ##
99
+ # Sets on_follow to +block+
44
100
 
45
101
  def on_follow &block
46
102
  @on_follow = block
47
103
  end
104
+
105
+ ##
106
+ # Starts a loop that checks for any notifications for the authenticated
107
+ # user, running the appropriate stored proc when needed
48
108
 
49
109
  def run_interact
50
110
  @streamer.user do |update|
@@ -53,6 +113,10 @@ module Elephrame
53
113
  case update.type
54
114
 
55
115
  when 'mention'
116
+
117
+ # this makes it so .content calls strip instead
118
+ update.status.class.module_eval { alias_method :content, :strip } if @strip_html
119
+ store_mention_data update.status
56
120
  @on_reply.call(self, update.status) unless @on_reply.nil?
57
121
 
58
122
  when 'reblog'
@@ -0,0 +1,16 @@
1
+ module Mastodon
2
+ class Status
3
+ alias_method :rcontent, :content
4
+
5
+ ##
6
+ # Strips all html tags out of +content+
7
+ #
8
+ # @return [String]
9
+
10
+ def strip
11
+ rcontent.gsub(/<\/p><p>/, "\n")
12
+ .gsub(/<("[^"]*"|'[^']*'|[^'">])*>/, '')
13
+ end
14
+ end
15
+ end
16
+
@@ -1,3 +1,3 @@
1
1
  module Elephrame
2
- VERSION = "0.2.0"
2
+ VERSION = "0.3.2"
3
3
  end
data/lib/elephrame.rb CHANGED
@@ -1,5 +1,8 @@
1
1
  require 'moostodon'
2
- require_relative 'elephrame/version'
2
+ require_relative 'elephrame/util/status'
3
+
4
+ require_relative 'elephrame/version'
3
5
  require_relative 'elephrame/streaming/bots'
4
6
  require_relative 'elephrame/rest/bots'
5
7
  require_relative 'elephrame/mix/bots'
8
+
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: elephrame
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zac
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-11-29 00:00:00.000000000 Z
11
+ date: 2018-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -98,6 +98,7 @@ files:
98
98
  - bin/console
99
99
  - bin/setup
100
100
  - elephrame.gemspec
101
+ - examples/README.md
101
102
  - examples/combined.rb
102
103
  - examples/interact.rb
103
104
  - examples/periodic.rb
@@ -109,6 +110,7 @@ files:
109
110
  - lib/elephrame/rest/rest.rb
110
111
  - lib/elephrame/streaming/bots.rb
111
112
  - lib/elephrame/streaming/streaming.rb
113
+ - lib/elephrame/util/status.rb
112
114
  - lib/elephrame/version.rb
113
115
  homepage: https://github.com/theZacAttacks/elephrame
114
116
  licenses: