automatic 14.12.2 → 26.09
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 +5 -5
- data/README.md +669 -83
- data/VERSION +1 -1
- data/assets/siteinfo/items_all.json +60300 -52138
- data/automatic.gemspec +110 -248
- data/bin/automatic +20 -139
- data/config/feed2console.yml +10 -4
- data/config/feed2markdown.yml +41 -0
- data/doc/AI_TUTORIAL.md +542 -0
- data/doc/BASIC_DESIGN.md +547 -0
- data/doc/COPYING.LESSER +165 -0
- data/doc/DEPLOYMENT.md +830 -0
- data/doc/LICENSE.md +14 -0
- data/doc/PLUGINS.md +2015 -0
- data/doc/PLUGIN_DEVELOPMENT.md +86 -0
- data/doc/POLICY.md +962 -0
- data/doc/QUICKSTART.md +260 -0
- data/doc/RELEASING.md +394 -0
- data/doc/REQUIREMENTS.md +556 -0
- data/doc/VERSIONS +266 -0
- data/lib/automatic/cli.rb +270 -0
- data/lib/automatic/environment.rb +31 -5
- data/lib/automatic/feed_maker.rb +65 -25
- data/lib/automatic/feed_parser.rb +51 -35
- data/lib/automatic/http.rb +107 -0
- data/lib/automatic/log.rb +49 -18
- data/lib/automatic/opml.rb +3 -1
- data/lib/automatic/pipeline.rb +73 -32
- data/lib/automatic/recipe.rb +100 -17
- data/lib/automatic/version.rb +14 -1
- data/lib/automatic.rb +93 -20
- data/plugins/custom_feed/svn_log.rb +73 -32
- data/plugins/custom_feed/web.rb +348 -0
- data/plugins/filter/absolute_uri.rb +43 -27
- data/plugins/filter/accept.rb +38 -45
- data/plugins/filter/batch.rb +97 -0
- data/plugins/filter/claude.rb +217 -0
- data/plugins/filter/clear.rb +12 -8
- data/plugins/filter/description_link.rb +66 -51
- data/plugins/filter/full_feed.rb +170 -52
- data/plugins/filter/gemini.rb +216 -0
- data/plugins/filter/github_feed.rb +38 -26
- data/plugins/filter/ignore.rb +33 -44
- data/plugins/filter/image.rb +36 -25
- data/plugins/filter/image_source.rb +75 -52
- data/plugins/filter/join.rb +105 -0
- data/plugins/filter/kimi.rb +216 -0
- data/plugins/filter/limit.rb +57 -0
- data/plugins/filter/one.rb +19 -26
- data/plugins/filter/open_ai.rb +198 -0
- data/plugins/filter/present.rb +75 -0
- data/plugins/filter/rand.rb +16 -17
- data/plugins/filter/sakura_ai.rb +205 -0
- data/plugins/filter/sanitize.rb +29 -34
- data/plugins/filter/sort.rb +20 -27
- data/plugins/filter/tumblr_resize.rb +31 -23
- data/plugins/notify/ikachan.rb +86 -48
- data/plugins/provide/fluentd.rb +43 -24
- data/plugins/publish/amazon_s3.rb +79 -40
- data/plugins/publish/console.rb +19 -16
- data/plugins/publish/console_link.rb +20 -17
- data/plugins/publish/eject.rb +48 -26
- data/plugins/publish/fluentd.rb +50 -30
- data/plugins/publish/hatena_bookmark.rb +88 -71
- data/plugins/publish/instapaper.rb +69 -59
- data/plugins/publish/markdown.rb +278 -0
- data/plugins/publish/memcached.rb +35 -29
- data/plugins/store/database.rb +50 -48
- data/plugins/store/digest.rb +212 -0
- data/plugins/store/file.rb +107 -68
- data/plugins/store/full_text.rb +31 -28
- data/plugins/store/permalink.rb +18 -22
- data/plugins/subscription/feed.rb +34 -21
- data/plugins/subscription/link.rb +31 -32
- data/plugins/subscription/text.rb +40 -45
- data/plugins/subscription/tumblr.rb +55 -44
- data/plugins/subscription/xml.rb +40 -36
- metadata +112 -321
- data/Gemfile +0 -38
- data/Rakefile +0 -59
- data/doc/ChangeLog +0 -303
- data/doc/PLUGINS +0 -750
- data/doc/PLUGINS.ja +0 -753
- data/doc/README +0 -511
- data/doc/README.ja +0 -519
- data/plugins/filter/google_news.rb +0 -50
- data/plugins/publish/google_calendar.rb +0 -84
- data/plugins/publish/hipchat.rb +0 -46
- data/plugins/publish/pocket.rb +0 -45
- data/plugins/publish/twitter.rb +0 -58
- data/plugins/subscription/chan_toru.rb +0 -57
- data/plugins/subscription/g_guide.rb +0 -57
- data/plugins/subscription/pocket.rb +0 -51
- data/plugins/subscription/twitter.rb +0 -69
- data/plugins/subscription/twitter_search.rb +0 -50
- data/plugins/subscription/weather.rb +0 -33
- data/script/build +0 -84
- data/spec/fixtures/sampleFeeds.tsv +0 -1
- data/spec/fixtures/sampleFeeds2.tsv +0 -2
- data/spec/fixtures/sampleRecipe.yml +0 -24
- data/spec/lib/automatic/log_spec.rb +0 -32
- data/spec/lib/automatic/pipeline_spec.rb +0 -68
- data/spec/lib/automatic/recipe_spec.rb +0 -40
- data/spec/lib/automatic_spec.rb +0 -99
- data/spec/plugins/custom_feed/svn_log_spec.rb +0 -31
- data/spec/plugins/filter/absolute_uri_spec.rb +0 -61
- data/spec/plugins/filter/accept_spec.rb +0 -331
- data/spec/plugins/filter/clear_spec.rb +0 -49
- data/spec/plugins/filter/description_link_spec.rb +0 -138
- data/spec/plugins/filter/full_feed_spec.rb +0 -129
- data/spec/plugins/filter/github_feed_spec.rb +0 -55
- data/spec/plugins/filter/google_news_spec.rb +0 -69
- data/spec/plugins/filter/ignore_spec.rb +0 -328
- data/spec/plugins/filter/image_source_spec.rb +0 -89
- data/spec/plugins/filter/image_spec.rb +0 -65
- data/spec/plugins/filter/one_spec.rb +0 -71
- data/spec/plugins/filter/rand_spec.rb +0 -52
- data/spec/plugins/filter/sanitize_spec.rb +0 -153
- data/spec/plugins/filter/sort_spec.rb +0 -189
- data/spec/plugins/filter/tumblr_resize_spec.rb +0 -109
- data/spec/plugins/notify/ikachan_spec.rb +0 -58
- data/spec/plugins/provide/fluentd_spec.rb +0 -49
- data/spec/plugins/publish/amazon_s3_spec.rb +0 -40
- data/spec/plugins/publish/console_spec.rb +0 -30
- data/spec/plugins/publish/eject_spec.rb +0 -40
- data/spec/plugins/publish/fluentd_spec.rb +0 -40
- data/spec/plugins/publish/google_calendar_spec.rb +0 -83
- data/spec/plugins/publish/hatena_bookmark_spec.rb +0 -134
- data/spec/plugins/publish/hipchat_spec.rb +0 -69
- data/spec/plugins/publish/instapaper_spec.rb +0 -82
- data/spec/plugins/publish/memcached_spec.rb +0 -63
- data/spec/plugins/publish/pocket_spec.rb +0 -51
- data/spec/plugins/publish/twitter_spec.rb +0 -73
- data/spec/plugins/store/file_spec.rb +0 -58
- data/spec/plugins/store/full_text_spec.rb +0 -152
- data/spec/plugins/store/permalink_spec.rb +0 -206
- data/spec/plugins/subscription/chan_toru_spec.rb +0 -56
- data/spec/plugins/subscription/feed_spec.rb +0 -71
- data/spec/plugins/subscription/g_guide_spec.rb +0 -82
- data/spec/plugins/subscription/link_spec.rb +0 -72
- data/spec/plugins/subscription/pocket_spec.rb +0 -57
- data/spec/plugins/subscription/text_spec.rb +0 -84
- data/spec/plugins/subscription/tumblr_spec.rb +0 -74
- data/spec/plugins/subscription/twitter_search_spec.rb +0 -57
- data/spec/plugins/subscription/twitter_spec.rb +0 -73
- data/spec/plugins/subscription/weather_spec.rb +0 -44
- data/spec/plugins/subscription/xml_spec.rb +0 -84
- data/spec/spec_helper.rb +0 -106
- data/spec/user_dir/plugins/store/mock.rb +0 -16
- data/test/fixtures/sampleOPML.xml +0 -11
- data/test/integration/test_absoluteurl.yml +0 -25
- data/test/integration/test_activerecord.yml +0 -24
- data/test/integration/test_add_pocket.yml +0 -26
- data/test/integration/test_chan_toru.yml +0 -21
- data/test/integration/test_descriptionlink.yml +0 -21
- data/test/integration/test_fluentd.yml +0 -22
- data/test/integration/test_fulltext.yml +0 -30
- data/test/integration/test_google_news.yml +0 -21
- data/test/integration/test_googlealert.yml +0 -21
- data/test/integration/test_hatenabookmark.yml +0 -30
- data/test/integration/test_ignore.yml +0 -25
- data/test/integration/test_ignore2.yml +0 -22
- data/test/integration/test_image2local.yml +0 -33
- data/test/integration/test_instapaper.yml +0 -26
- data/test/integration/test_link2local.yml +0 -34
- data/test/integration/test_one.yml +0 -23
- data/test/integration/test_pocket.yml +0 -22
- data/test/integration/test_rand.yml +0 -21
- data/test/integration/test_sanitize.yml +0 -23
- data/test/integration/test_sort.yml +0 -36
- data/test/integration/test_svnlog.yml +0 -15
- data/test/integration/test_text2feed.yml +0 -36
- data/test/integration/test_tumblr2local.yml +0 -43
- data/test/integration/test_twitter_search.yml +0 -22
- data/test/integration/test_weather.yml +0 -19
- data/test/integration/test_xml2fluentd.yml +0 -21
- data/vendor/.gitkeep +0 -0
data/plugins/notify/ikachan.rb
CHANGED
|
@@ -1,87 +1,125 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
+
# Name:: Automatic::Plugin::Notify::Ikachan
|
|
3
|
+
# Author: id774 (More info: https://id774.net)
|
|
4
|
+
# Source Code:: https://github.com/id774/automaticruby
|
|
5
|
+
# License:: The GPL version 3, or LGPL version 3 (Dual License).
|
|
6
|
+
# Contact:: idnanashi@gmail.com
|
|
7
|
+
# Created:: Mar 7, 2012
|
|
8
|
+
# Updated:: Aug 15, 2026
|
|
9
|
+
# Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
|
|
10
|
+
#
|
|
11
|
+
# Description:: Posts each item to an IRC channel through an ikachan
|
|
12
|
+
# HTTP-to-IRC gateway, which the operator runs themselves.
|
|
2
13
|
|
|
3
|
-
require '
|
|
4
|
-
require '
|
|
5
|
-
require 'active_support/deprecation'
|
|
14
|
+
require 'net/http'
|
|
15
|
+
require 'uri'
|
|
6
16
|
|
|
7
17
|
module Automatic::Plugin
|
|
8
18
|
class Ikachan
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
require 'net/http'
|
|
12
|
-
require 'uri'
|
|
19
|
+
OPEN_TIMEOUT = 10
|
|
20
|
+
READ_TIMEOUT = 30
|
|
13
21
|
|
|
14
22
|
attr_accessor :params
|
|
15
23
|
|
|
16
24
|
def initialize
|
|
17
|
-
@params = {
|
|
18
|
-
"url" => "",
|
|
19
|
-
"port" => "",
|
|
20
|
-
"channels" => [],
|
|
21
|
-
"command" => "",
|
|
22
|
-
}
|
|
25
|
+
@params = { 'url' => '', 'port' => '', 'channels' => [], 'command' => '' }
|
|
23
26
|
end
|
|
24
27
|
|
|
25
|
-
def post(link, title =
|
|
26
|
-
message
|
|
27
|
-
uri
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
http.
|
|
34
|
-
|
|
35
|
-
if res.code == "200"
|
|
36
|
-
Automatic::Log.puts(:info, "Success: #{message}")
|
|
37
|
-
else
|
|
38
|
-
Automatic::Log.puts(:error, "#{res.code} Error: #{message}")
|
|
39
|
-
end
|
|
28
|
+
def post(link, title = '')
|
|
29
|
+
message = build_message(link, title)
|
|
30
|
+
uri = endpoint
|
|
31
|
+
|
|
32
|
+
start(uri) do |http|
|
|
33
|
+
channels.each do |channel|
|
|
34
|
+
# Join first, in case the gateway is not in the channel.
|
|
35
|
+
http.request(form('/join', channel: channel))
|
|
36
|
+
response = http.request(form(uri.path, channel: channel, message: message))
|
|
37
|
+
log(response, message)
|
|
40
38
|
end
|
|
41
39
|
end
|
|
42
40
|
end
|
|
43
41
|
|
|
44
42
|
private
|
|
45
43
|
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
# A gateway reached over https is spoken to over https. The earlier
|
|
45
|
+
# version built a plain connection whatever the URL said.
|
|
46
|
+
def start(uri, &block)
|
|
47
|
+
proxy = Net::HTTP.Proxy(ENV.fetch('PROXY', nil), 8080)
|
|
48
|
+
proxy.start(uri.host, uri.port,
|
|
49
|
+
use_ssl: uri.scheme == 'https',
|
|
50
|
+
open_timeout: OPEN_TIMEOUT,
|
|
51
|
+
read_timeout: READ_TIMEOUT, &block)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Form-encoded by Net::HTTP rather than interpolated into the body, so
|
|
55
|
+
# that a title carrying an ampersand or a space reaches the channel as it
|
|
56
|
+
# was written instead of splitting the request.
|
|
57
|
+
def form(path, params)
|
|
58
|
+
request = Net::HTTP::Post.new(path)
|
|
59
|
+
request.set_form_data(params)
|
|
60
|
+
request
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def channels
|
|
64
|
+
value = @params['channels']
|
|
65
|
+
value.is_a?(Array) ? value : value.to_s.split(',')
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def endpoint
|
|
69
|
+
URI.parse("#{@params['url']}:#{@params['port']}/#{@params['command']}")
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def log(response, message)
|
|
73
|
+
if response.code == '200'
|
|
74
|
+
Automatic::Log.puts(:info, "Success: #{message}")
|
|
75
|
+
else
|
|
76
|
+
Automatic::Log.puts(:error, "#{response.code} Error: #{message}")
|
|
77
|
+
end
|
|
48
78
|
end
|
|
49
79
|
|
|
50
80
|
def build_message(link, title)
|
|
51
|
-
message =
|
|
52
|
-
message += "#{title
|
|
53
|
-
message
|
|
54
|
-
message
|
|
81
|
+
message = ''
|
|
82
|
+
message += "#{title} - " unless title.nil? || title.to_s.empty?
|
|
83
|
+
message + link.to_s
|
|
55
84
|
end
|
|
56
85
|
end
|
|
57
86
|
|
|
58
87
|
class NotifyIkachan
|
|
59
88
|
attr_accessor :ikachan
|
|
60
89
|
|
|
61
|
-
def initialize(config, pipeline=[])
|
|
62
|
-
@config = config
|
|
90
|
+
def initialize(config, pipeline = [])
|
|
91
|
+
@config = config || {}
|
|
63
92
|
@pipeline = pipeline
|
|
64
93
|
|
|
65
94
|
@ikachan = Ikachan.new
|
|
66
95
|
@ikachan.params = {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
96
|
+
'url' => @config['url'],
|
|
97
|
+
'port' => @config['port'] || '4979',
|
|
98
|
+
'channels' => channels,
|
|
99
|
+
'command' => @config['command'] || 'notice'
|
|
71
100
|
}
|
|
72
101
|
end
|
|
73
102
|
|
|
103
|
+
# Returns the pipeline unchanged: a Notify plugin sends a notification and
|
|
104
|
+
# nothing else.
|
|
74
105
|
def run
|
|
75
|
-
@pipeline.each
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
106
|
+
@pipeline.each do |feeds|
|
|
107
|
+
next if feeds.nil?
|
|
108
|
+
|
|
109
|
+
feeds.items.each do |feed|
|
|
110
|
+
Automatic::Log.puts('info', "Ikachan: [#{feed.link}] sending to #{channels.join(',')}...")
|
|
111
|
+
ikachan.post(feed.link, feed.title)
|
|
112
|
+
sleep(@config['interval'].to_i)
|
|
82
113
|
end
|
|
83
|
-
|
|
114
|
+
end
|
|
84
115
|
@pipeline
|
|
85
116
|
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
# Comma separated, with a leading '#' added where it is absent.
|
|
121
|
+
def channels
|
|
122
|
+
@config['channels'].to_s.split(',').map { |name| name.start_with?('#') ? name : "##{name}" }
|
|
123
|
+
end
|
|
86
124
|
end
|
|
87
125
|
end
|
data/plugins/provide/fluentd.rb
CHANGED
|
@@ -1,37 +1,56 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# Name::
|
|
3
|
-
# Author
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
2
|
+
# Name:: Automatic::Plugin::Provide::Fluentd
|
|
3
|
+
# Author: id774 (More info: https://id774.net)
|
|
4
|
+
# Source Code:: https://github.com/id774/automaticruby
|
|
5
|
+
# License:: The GPL version 3, or LGPL version 3 (Dual License).
|
|
6
|
+
# Contact:: idnanashi@gmail.com
|
|
7
|
+
# Created:: Jul 12, 2013
|
|
8
|
+
# Updated:: Aug 15, 2026
|
|
9
|
+
# Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
|
|
8
10
|
|
|
9
11
|
module Automatic::Plugin
|
|
10
12
|
class ProvideFluentd
|
|
11
|
-
|
|
13
|
+
Automatic.require_optional('fluent-logger', needed_by: 'ProvideFluentd')
|
|
12
14
|
|
|
13
|
-
def initialize(config, pipeline=[])
|
|
14
|
-
@config
|
|
15
|
+
def initialize(config, pipeline = [])
|
|
16
|
+
@config = config || {}
|
|
15
17
|
@pipeline = pipeline
|
|
16
|
-
@mode
|
|
17
|
-
@fluentd
|
|
18
|
-
host = @config['host'],
|
|
19
|
-
port = @config['port']) unless @mode == 'test'
|
|
18
|
+
@mode = @config['mode']
|
|
19
|
+
@fluentd = open_logger unless test?
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
+
# Posts each item's content_encoded to Fluentd, which must be something
|
|
23
|
+
# Fluentd accepts as a record. Distinct from PublishFluentd, which posts
|
|
24
|
+
# the item's fields.
|
|
22
25
|
def run
|
|
23
|
-
@pipeline.each
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
rescue
|
|
29
|
-
Automatic::Log.puts("error", "Fluent::Logger.post failed, the content_encoded of item may be not kind of Hash.")
|
|
30
|
-
end
|
|
31
|
-
}
|
|
32
|
-
end
|
|
33
|
-
}
|
|
26
|
+
@pipeline.each do |feeds|
|
|
27
|
+
next if feeds.nil?
|
|
28
|
+
|
|
29
|
+
feeds.items.each { |feed| post(feed) }
|
|
30
|
+
end
|
|
34
31
|
@pipeline
|
|
35
32
|
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def open_logger
|
|
37
|
+
Fluent::Logger::FluentLogger.open(nil,
|
|
38
|
+
host: @config['host'],
|
|
39
|
+
port: @config['port'].to_i)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def post(feed)
|
|
43
|
+
return if test?
|
|
44
|
+
|
|
45
|
+
@fluentd.post(@config['tag'], feed.content_encoded)
|
|
46
|
+
rescue StandardError => e
|
|
47
|
+
Automatic::Log.puts('error',
|
|
48
|
+
'Fluent::Logger.post failed, the content_encoded of item may ' \
|
|
49
|
+
"be not kind of Hash: #{e.message}")
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test?
|
|
53
|
+
@mode == 'test'
|
|
54
|
+
end
|
|
36
55
|
end
|
|
37
56
|
end
|
|
@@ -1,58 +1,97 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# Name::
|
|
3
|
-
# Author
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
2
|
+
# Name:: Automatic::Plugin::Publish::AmazonS3
|
|
3
|
+
# Author: id774 (More info: https://id774.net)
|
|
4
|
+
# Source Code:: https://github.com/id774/automaticruby
|
|
5
|
+
# License:: The GPL version 3, or LGPL version 3 (Dual License).
|
|
6
|
+
# Contact:: idnanashi@gmail.com
|
|
7
|
+
# Created:: Feb 24, 2014
|
|
8
|
+
# Updated:: Sep 9, 2026
|
|
9
|
+
# Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
|
|
8
10
|
|
|
9
11
|
module Automatic::Plugin
|
|
10
12
|
class PublishAmazonS3
|
|
11
13
|
require 'uri'
|
|
12
|
-
require 'aws-sdk'
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
15
|
+
FILE_URI_ESCAPER = URI::RFC2396_Parser.new
|
|
16
|
+
|
|
17
|
+
def initialize(config, pipeline = [])
|
|
18
|
+
@config = config || {}
|
|
16
19
|
@pipeline = pipeline
|
|
17
|
-
|
|
18
|
-
:access_key_id => @config['access_key'],
|
|
19
|
-
:secret_access_key => @config['secret_key']
|
|
20
|
-
)
|
|
21
|
-
@bucket = s3.buckets[@config['bucket_name']]
|
|
22
|
-
@mode = @config['mode']
|
|
20
|
+
@mode = @config['mode']
|
|
23
21
|
end
|
|
24
22
|
|
|
23
|
+
# Uploads the files whose link is a file URI, normally after StoreFile.
|
|
25
24
|
def run
|
|
26
|
-
@pipeline.each
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
uri = URI.parse(feed.link)
|
|
32
|
-
if uri.scheme == 'file'
|
|
33
|
-
upload_amazons3(uri.path, @config['target_path'])
|
|
34
|
-
else
|
|
35
|
-
Automatic::Log.puts("warn", "Skip feed due to uri scheme is not file.")
|
|
36
|
-
end
|
|
37
|
-
rescue
|
|
38
|
-
Automatic::Log.puts("error", "Error detected with #{feed.link} in uploading AmazonS3.")
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
}
|
|
42
|
-
end
|
|
43
|
-
}
|
|
25
|
+
@pipeline.each do |feeds|
|
|
26
|
+
next if feeds.nil?
|
|
27
|
+
|
|
28
|
+
feeds.items.each { |feed| publish(feed) }
|
|
29
|
+
end
|
|
44
30
|
@pipeline
|
|
45
31
|
end
|
|
46
32
|
|
|
47
33
|
private
|
|
48
34
|
|
|
49
|
-
def
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
35
|
+
def publish(feed)
|
|
36
|
+
return if feed.link.nil?
|
|
37
|
+
|
|
38
|
+
uri = URI.parse(feed.link)
|
|
39
|
+
if uri.scheme == 'file'
|
|
40
|
+
upload(file_path(uri))
|
|
41
|
+
else
|
|
42
|
+
Automatic::Log.puts('warn', 'Skip feed due to uri scheme is not file.')
|
|
43
|
+
end
|
|
44
|
+
rescue StandardError => e
|
|
45
|
+
Automatic::Log.puts('error',
|
|
46
|
+
"Error detected with #{feed.link} in uploading AmazonS3: #{e.message}")
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def file_path(uri)
|
|
50
|
+
FILE_URI_ESCAPER.unescape(uri.path.to_s)
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def upload(path)
|
|
54
|
+
key = target_key(path)
|
|
55
|
+
File.open(path, 'rb') { |body| s3.put_object(bucket: bucket, key: key, body: body) } unless test?
|
|
56
|
+
Automatic::Log.puts('info', "Uploaded: file #{path} to the key #{key} on #{bucket}.")
|
|
57
|
+
[path, key]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def target_key(path)
|
|
61
|
+
File.join(@config['target_path'].to_s, File.basename(path)).sub(%r{\A/}, '')
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def bucket
|
|
65
|
+
@config['bucket_name'].to_s
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test?
|
|
69
|
+
@mode == 'test'
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# AWS SDK for Ruby v3, which is the SDK AWS publishes and maintains. The
|
|
73
|
+
# gem is required here rather than at the top of the file, so that a
|
|
74
|
+
# Recipe running this plugin in `mode: test` -- and this plugin's own
|
|
75
|
+
# specs -- need neither the gem nor an account.
|
|
76
|
+
#
|
|
77
|
+
# Credentials are the Recipe's where it carries them, and the SDK's
|
|
78
|
+
# default chain -- environment, shared profile, instance role -- where it
|
|
79
|
+
# does not, which is the way to run this without a secret in a file.
|
|
80
|
+
def s3
|
|
81
|
+
@s3 ||= begin
|
|
82
|
+
Automatic.require_optional('aws-sdk-s3', needed_by: 'PublishAmazonS3')
|
|
83
|
+
Aws::S3::Client.new(**client_options)
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def client_options
|
|
88
|
+
options = {}
|
|
89
|
+
options[:region] = @config['region'].to_s unless @config['region'].nil?
|
|
90
|
+
unless @config['access_key'].nil?
|
|
91
|
+
options[:access_key_id] = @config['access_key'].to_s
|
|
92
|
+
options[:secret_access_key] = @config['secret_key'].to_s
|
|
93
|
+
end
|
|
94
|
+
options
|
|
56
95
|
end
|
|
57
96
|
end
|
|
58
97
|
end
|
data/plugins/publish/console.rb
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# Name::
|
|
3
|
-
# Author
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
2
|
+
# Name:: Automatic::Plugin::Publish::Console
|
|
3
|
+
# Author: id774 (More info: https://id774.net)
|
|
4
|
+
# Source Code:: https://github.com/id774/automaticruby
|
|
5
|
+
# License:: The GPL version 3, or LGPL version 3 (Dual License).
|
|
6
|
+
# Contact:: idnanashi@gmail.com
|
|
7
|
+
# Created:: Feb 23, 2012
|
|
8
|
+
# Updated:: Aug 15, 2026
|
|
9
|
+
# Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
|
|
8
10
|
|
|
9
11
|
module Automatic::Plugin
|
|
10
12
|
class PublishConsole
|
|
11
13
|
require 'pp'
|
|
12
14
|
|
|
13
|
-
def initialize(config, pipeline=[])
|
|
14
|
-
@config
|
|
15
|
+
def initialize(config, pipeline = [])
|
|
16
|
+
@config = config || {}
|
|
15
17
|
@pipeline = pipeline
|
|
16
|
-
|
|
18
|
+
# Held in an instance variable rather than written to $stdout directly,
|
|
19
|
+
# so that a spec can substitute it. See doc/PLUGINS.md section 3.6.
|
|
20
|
+
@output = $stdout
|
|
17
21
|
end
|
|
18
22
|
|
|
23
|
+
# Prints each item, the plugin to end a Recipe with while writing it.
|
|
19
24
|
def run
|
|
20
|
-
@pipeline.each
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
end
|
|
26
|
-
}
|
|
25
|
+
@pipeline.each do |feeds|
|
|
26
|
+
next if feeds.nil?
|
|
27
|
+
|
|
28
|
+
feeds.items.each { |feed| @output.puts(feed.pretty_inspect) }
|
|
29
|
+
end
|
|
27
30
|
@pipeline
|
|
28
31
|
end
|
|
29
32
|
end
|
|
@@ -1,29 +1,32 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# Name::
|
|
3
|
-
# Author
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
2
|
+
# Name:: Automatic::Plugin::Publish::ConsoleLink
|
|
3
|
+
# Author: soramugi (More info: http://soramugi.net)
|
|
4
|
+
# Source Code:: https://github.com/id774/automaticruby
|
|
5
|
+
# License:: The GPL version 3, or LGPL version 3 (Dual License).
|
|
6
|
+
# Contact:: idnanashi@gmail.com
|
|
7
|
+
# Created:: Jun 02, 2013
|
|
8
|
+
# Updated:: Aug 15, 2026
|
|
9
|
+
# Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
|
|
8
10
|
|
|
9
11
|
module Automatic::Plugin
|
|
10
12
|
class PublishConsoleLink
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
def initialize(config, pipeline=[])
|
|
14
|
-
@config = config
|
|
13
|
+
def initialize(config, pipeline = [])
|
|
14
|
+
@config = config || {}
|
|
15
15
|
@pipeline = pipeline
|
|
16
|
-
@output
|
|
16
|
+
@output = $stdout
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
# Prints each item's link, one per line, and nothing else. Useful in a
|
|
20
|
+
# pipe, which is why an item whose link a filter has blanked prints
|
|
21
|
+
# nothing rather than an empty line.
|
|
19
22
|
def run
|
|
20
|
-
@pipeline.each
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
23
|
+
@pipeline.each do |feeds|
|
|
24
|
+
next if feeds.nil?
|
|
25
|
+
|
|
26
|
+
feeds.items.each do |feed|
|
|
27
|
+
@output.puts(feed.link) unless feed.link.nil?
|
|
25
28
|
end
|
|
26
|
-
|
|
29
|
+
end
|
|
27
30
|
@pipeline
|
|
28
31
|
end
|
|
29
32
|
end
|
data/plugins/publish/eject.rb
CHANGED
|
@@ -1,42 +1,64 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
|
-
# Name::
|
|
3
|
-
# Author
|
|
4
|
-
#
|
|
5
|
-
#
|
|
6
|
-
#
|
|
7
|
-
#
|
|
8
|
-
#
|
|
2
|
+
# Name:: Automatic::Plugin::Publish::Eject
|
|
3
|
+
# Author: soramugi (More info: http://soramugi.net)
|
|
4
|
+
# Source Code:: https://github.com/id774/automaticruby
|
|
5
|
+
# License:: The GPL version 3, or LGPL version 3 (Dual License).
|
|
6
|
+
# Contact:: idnanashi@gmail.com
|
|
7
|
+
# Created:: Jun 9, 2013
|
|
8
|
+
# Updated:: Aug 15, 2026
|
|
9
|
+
# Copyright:: Copyright (c) 2012-2026 Automatic Ruby Developers.
|
|
9
10
|
|
|
10
11
|
module Automatic::Plugin
|
|
11
12
|
class PublishEject
|
|
13
|
+
# The command that opens the tray and the command that closes it again,
|
|
14
|
+
# per platform, as argument vectors. Nothing here goes through a shell.
|
|
15
|
+
COMMANDS = {
|
|
16
|
+
'eject' => [%w[eject], %w[eject -t]], # GNU/Linux
|
|
17
|
+
'drutil' => [%w[drutil tray eject], %w[drutil tray close]] # macOS
|
|
18
|
+
}.freeze
|
|
12
19
|
|
|
13
|
-
def initialize(config, pipeline=[])
|
|
14
|
-
@config = config
|
|
20
|
+
def initialize(config, pipeline = [])
|
|
21
|
+
@config = config || {}
|
|
15
22
|
@pipeline = pipeline
|
|
16
23
|
end
|
|
17
24
|
|
|
25
|
+
# Opens and closes the optical drive once per item. A physical
|
|
26
|
+
# notification, and the plugin that needs a machine with a tray.
|
|
18
27
|
def run
|
|
19
|
-
@pipeline.each
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
end
|
|
29
|
-
}
|
|
28
|
+
@pipeline.each do |feeds|
|
|
29
|
+
next if feeds.nil?
|
|
30
|
+
|
|
31
|
+
feeds.items.each do |feed|
|
|
32
|
+
next if feed.link.nil?
|
|
33
|
+
|
|
34
|
+
eject
|
|
35
|
+
Automatic::Log.puts('info', "Eject: #{feed.link}")
|
|
36
|
+
sleep(@config['interval'].to_i)
|
|
30
37
|
end
|
|
31
|
-
|
|
38
|
+
end
|
|
32
39
|
@pipeline
|
|
33
40
|
end
|
|
34
41
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
private
|
|
43
|
+
|
|
44
|
+
def eject
|
|
45
|
+
commands = COMMANDS[command_name]
|
|
46
|
+
if commands.nil?
|
|
47
|
+
Automatic::Log.puts('warn', 'No eject command found on this system.')
|
|
48
|
+
return
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
commands.each { |command| system(*command) }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# Looked up on PATH rather than by running `which` in a shell.
|
|
55
|
+
def command_name
|
|
56
|
+
@command_name ||= COMMANDS.keys.find { |name| executable?(name) }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def executable?(name)
|
|
60
|
+
ENV['PATH'].to_s.split(File::PATH_SEPARATOR).any? do |dir|
|
|
61
|
+
File.executable?(File.join(dir, name))
|
|
40
62
|
end
|
|
41
63
|
end
|
|
42
64
|
end
|