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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +54 -6
- data/examples/README.md +5 -0
- data/examples/interact.rb +6 -2
- data/examples/reply.rb +1 -2
- data/lib/elephrame/bot.rb +60 -5
- data/lib/elephrame/mix/bots.rb +20 -2
- data/lib/elephrame/rest/bots.rb +13 -0
- data/lib/elephrame/rest/rest.rb +8 -1
- data/lib/elephrame/streaming/bots.rb +10 -1
- data/lib/elephrame/streaming/streaming.rb +66 -2
- data/lib/elephrame/util/status.rb +16 -0
- data/lib/elephrame/version.rb +1 -1
- data/lib/elephrame.rb +4 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9bacbf531fa6368eb2e401e3492192eb9ae230966edc62f3971f3566430b64f5
|
4
|
+
data.tar.gz: 8a09ce7796b7acd043f73195fd7511eda01cd8f5abf6de2aa081f17aec1fa46c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f836c9f830ea5a24a52f8e708b96a6e26ecfff5c03182b0ccbf98787442f9ab4b9508bdd2ff9a340cd318723d265f97bd07506725048d2b2313bd86cd5451e99
|
7
|
+
data.tar.gz: 356c31e481d1d7892759fed57dbc41610364624e60725c23ff53f788a2245e66e5a6843f88ab4cf7295065dcfcf193a8f252167f57f9c89195482714543a548d
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,8 +1,13 @@
|
|
1
1
|
# Elephrame
|
2
2
|
|
3
|
-
|
3
|
+
[](https://badge.fury.io/rb/elephrame)
|
4
|
+
[RubyDoc](https://www.rubydoc.info/github/theZacAttacks/elephrame/)
|
4
5
|
|
5
|
-
|
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
|
-
|
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`.
|
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/
|
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/
|
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).
|
data/examples/README.md
ADDED
@@ -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
|
-
|
7
|
-
|
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
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
|
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
|
-
|
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
|
|
data/lib/elephrame/mix/bots.rb
CHANGED
@@ -4,11 +4,24 @@ require_relative '../bot'
|
|
4
4
|
|
5
5
|
module Elephrame
|
6
6
|
module Bots
|
7
|
-
|
8
|
-
|
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
|
data/lib/elephrame/rest/bots.rb
CHANGED
@@ -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()
|
data/lib/elephrame/rest/rest.rb
CHANGED
@@ -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
|
+
|
data/lib/elephrame/version.rb
CHANGED
data/lib/elephrame.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
require 'moostodon'
|
2
|
-
require_relative
|
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
|
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-
|
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:
|