elephrame 0.2.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: