kemonomachi-wanko 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c386e5f07a045d367717650f2f6fe54e2223b080
4
+ data.tar.gz: 90358f22e960700a46024b874a129cee3f2bfe17
5
+ SHA512:
6
+ metadata.gz: 4f70b0fd6c5fff57da833b5599a756f1256e4f55a38bdb1b15637d203b541ec8f82a62df6379c8d73281de4260ade511f9aa29cfa6862d0830818a1748566029
7
+ data.tar.gz: 88b87e0b9b1f8f1b86d91cb78f879be33f52a56cdc62b7dbf34105c02f7dc3ad6bccc652270a7d528d0897dc79e2c71b50896e89385cdafb9586509e8489ae7e
data/LICENSE ADDED
@@ -0,0 +1,14 @@
1
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
2
+ Version 2, December 2004
3
+
4
+ Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>
5
+
6
+ Everyone is permitted to copy and distribute verbatim or modified
7
+ copies of this license document, and changing it is allowed as long
8
+ as the name is changed.
9
+
10
+ DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
11
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
12
+
13
+ 0. You just DO WHAT THE FUCK YOU WANT TO.
14
+
data/README ADDED
@@ -0,0 +1,49 @@
1
+ Wanko - RSS Torrent Fetcher
2
+
3
+ Description
4
+ -----------
5
+
6
+ Fetches torrent file links from RSS feeds based on user-specified rules. The
7
+ links can be printed to stdout or sent to Transmission for download, or the
8
+ torrent files can be downloaded to a watchdir for processing by other torrent
9
+ clients.
10
+
11
+ Installation
12
+ ------------
13
+
14
+ wanko can be installed from RubyGems:
15
+
16
+ gem install kemonomachi+wanko
17
+
18
+ 'kemonomachi+' is used as a ghetto namespace, since RubyGems doesn't support
19
+ proper ones.
20
+
21
+ Usage
22
+ -----
23
+
24
+ wanko [options]
25
+
26
+ The optional -c switch specifies the configuration directory, which defaults to
27
+ $HOME/.wanko.
28
+
29
+ See 'wanko --help' for usage info.
30
+
31
+ Can be run manually, but creating a cron job to run it at regular intervals is
32
+ recommended. It is not a daemon.
33
+
34
+ Configuration
35
+ -------------
36
+
37
+ The config file is named 'config.yaml'. The example folder contains a full
38
+ example config. RSS feeds, default fetch directory, fetch method and rules can
39
+ be specified. Regexen are used to match torrents against rules.
40
+
41
+ The config directory also holds 'history.yaml', which contains already read RSS
42
+ items. This prevents fetching the same torrent multiple times.
43
+
44
+ About the Name
45
+ --------------
46
+
47
+ Wanko (わんこ) is Japanese for 'doggy'. Because it's small and it fetches
48
+ stuff for you.
49
+
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/ruby
2
+
3
+ require 'wanko'
4
+
5
+ options = Wanko::parse_cli_switches ARGV
6
+
7
+ options[:command].call options
8
+
@@ -0,0 +1,7 @@
1
+ require 'wanko/data'
2
+ require 'wanko/exception'
3
+ require 'wanko/fetch'
4
+ require 'wanko/read'
5
+ require 'wanko/wanko'
6
+ require 'wanko/write'
7
+
@@ -0,0 +1,73 @@
1
+ require 'terminal-table'
2
+
3
+ require 'wanko/read'
4
+ require 'wanko/wanko'
5
+ require 'wanko/write'
6
+
7
+ module Wanko
8
+ module Command
9
+ def self.fetch(options)
10
+ config = begin
11
+ Wanko::Read.config options[:config_dir]
12
+ rescue Errno::ENOENT
13
+ abort 'Config file not found, aborting...'
14
+ end
15
+
16
+ [:feeds, :rules].each do |key|
17
+ warn 'WARN: No #{key} specified.' if config[key].empty?
18
+ end
19
+
20
+ history = Wanko::Read.history options[:config_dir]
21
+
22
+ torrents, new_history = Wanko::check_feeds config[:feeds], config[:rules], history
23
+
24
+ config[:fetcher].call torrents
25
+
26
+ Wanko::Write.history options[:config_dir], new_history
27
+ end
28
+
29
+ def self.add(options)
30
+ config = begin
31
+ Wanko::Read.raw_config options[:config_dir]
32
+ rescue Errno::ENOENT
33
+ abort 'Config file not found, aborting...'
34
+ end
35
+
36
+ id = if config[:rules].empty?
37
+ 0
38
+ else
39
+ config[:rules].map {|x| x[:id]}.max + 1
40
+ end
41
+
42
+ rule = [id: id, regex: options[:regex], dir: options[:dir] || config[:base_dir]]
43
+
44
+ new_config = config.merge rules: config[:rules] + rule
45
+
46
+ Wanko::Write.config options[:config_dir], Wanko::Utility.stringify_keys(new_config)
47
+ end
48
+
49
+ def self.list(options)
50
+ config = begin
51
+ Wanko::Read.raw_config options[:config_dir]
52
+ rescue Errno::ENOENT
53
+ abort 'Config file not found, aborting...'
54
+ end
55
+
56
+ puts Terminal::Table.new(rows: config[:rules].map {|r| [r[:id], r[:regex], r[:dir]]},
57
+ headings: ['ID', 'Regex', 'Directory']) {align_column 0, :right}
58
+ end
59
+
60
+ def self.remove(options)
61
+ config = begin
62
+ Wanko::Read.raw_config options[:config_dir]
63
+ rescue Errno::ENOENT
64
+ abort 'Config file not found, aborting...'
65
+ end
66
+
67
+ new_rules = config[:rules].reject {|rule| options[:ids].include? rule[:id]}
68
+
69
+ Wanko::Write.config options[:config_dir], Wanko::Utility.stringify_keys(config.merge rules: new_rules)
70
+ end
71
+ end
72
+ end
73
+
@@ -0,0 +1,70 @@
1
+ require 'json'
2
+
3
+ module Wanko
4
+
5
+ # Data representations.
6
+ module Data
7
+
8
+ # Class for torrent data. Contains the name of and the link to a torrent,
9
+ # as well as the directory the torrent will be downloaded to.
10
+ class Torrent
11
+ def initialize(name, link, dir)
12
+ @name = name
13
+ @link = link
14
+ @dir = dir
15
+ end
16
+
17
+ attr_reader :name, :link, :dir
18
+
19
+ # Returns a Hash representation of this Torrent
20
+ def to_h()
21
+ {
22
+ name: name,
23
+ link: link,
24
+ dir: dir
25
+ }
26
+ end
27
+
28
+ # Returns a JSON representation of this Torrent
29
+ def to_json(state = nil)
30
+ to_h.to_json state
31
+ end
32
+ end
33
+
34
+ # Rule for matching against RSS items. Contains a regex for matching and a
35
+ # directory to download matched torrents to.
36
+ class Rule
37
+
38
+ # Public: Initialize a Rule object.
39
+ #
40
+ #regex - String or Regexp for matching.
41
+ #dir - Directory to download matched torrents to.
42
+ def initialize(regex, dir)
43
+ @regex = Regexp.new regex, Regexp::IGNORECASE
44
+ @dir = dir
45
+ end
46
+
47
+ attr_reader :regex, :dir
48
+
49
+ # Public: Match the regex of this Rule against a String
50
+ #
51
+ # str - String to match.
52
+ #
53
+ # Returns true if str matches, false otherwise.
54
+ def =~(str)
55
+ regex =~ str
56
+ end
57
+
58
+ # Public: Compare this Rule to another object.
59
+ #
60
+ # other - Object to compare this Rule to.
61
+ #
62
+ # Returns true if the regex and dir fields of this Rule are equal to
63
+ # the corresponding fields in other, false otherwise.
64
+ def ==(other)
65
+ regex == other.regex && dir == other.dir
66
+ end
67
+ end
68
+ end
69
+ end
70
+
@@ -0,0 +1,8 @@
1
+ module Wanko
2
+ class Error < StandardError
3
+ end
4
+
5
+ class ConfigError < Wanko::Error
6
+ end
7
+ end
8
+
@@ -0,0 +1,178 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ require 'open-uri'
4
+ require 'yaml'
5
+
6
+ require 'wanko/exception'
7
+ require 'wanko/utility'
8
+
9
+ module Wanko
10
+
11
+ # Functions for fetching torrents in different ways. Several functions have
12
+ # side-effects, and ::fetcher_for returns Lambdas that have side-effects.
13
+ module Fetch
14
+
15
+ # Public: Create a lambda that fetches torrents when called.
16
+ #
17
+ # config - Hash with options for how to fetch torrents. :name is always
18
+ # required and should be one of 'stdout', 'watchdir' and
19
+ # 'transmission'. Other options vary depending on the value of
20
+ # :name, as follows:
21
+ #
22
+ # name: 'stdout'
23
+ # :format - Serialization format. See ::serialize for values.
24
+ # name: 'transmission'
25
+ # :host - The daemon's host
26
+ # :port - The daemon's port
27
+ # :path - The daemon's path.
28
+ # :user - Username for Basic auth (optional)
29
+ # :password - Password for Basic auth (optional)
30
+ #
31
+ # Returns a fetcher Lambda.
32
+ # Raises Wanko::ConfigError if :name option is not recognized.
33
+ def self.fetcher_for(config)
34
+ case config[:name]
35
+ when 'stdout'
36
+ ->(torrents) {$stdout.puts serialize(config[:format], torrents)}
37
+ when 'watchdir'
38
+ ->(torrents) {to_watchdir torrents}
39
+ when 'transmission'
40
+ url = make_transmission_url config[:host], config[:port], config[:path]
41
+
42
+ auth = if config[:user] || config[:password]
43
+ config.select {|k, _| [:user, :password].include? k}
44
+ end
45
+
46
+ ->(torrents) {to_transmission url, auth, torrents}
47
+ else
48
+ raise Wanko::ConfigError, "Invalid fetcher name '#{config[:name]}'"
49
+ end
50
+ end
51
+
52
+ # Internal: Serialize torrents for the stdout fetcher.
53
+ #
54
+ # format - Name of serialization method to use. Should be either 'json',
55
+ # 'simple' or 'yaml'.
56
+ # torrents - Torrents to serialize.
57
+ #
58
+ # Returns a String representation of torrents, in the given format.
59
+ # Raises Wanko::ConfigError if format is not recognized.
60
+ def self.serialize(format, torrents)
61
+ case format
62
+ when 'json'
63
+ torrents.to_json
64
+ when 'simple'
65
+ torrents.map(&:link).join "\n"
66
+ when 'yaml', nil
67
+ Utility.stringify_keys(torrents.map &:to_h).to_yaml
68
+ else
69
+ raise Wanko::ConfigError, "Invalid format '#{format}' for stdout fetcher."
70
+ end
71
+ end
72
+
73
+ # Internal: Download torrent files to watch directories. Creates any
74
+ # nonexisting directories.
75
+ #
76
+ # torrents - Torrents to download.
77
+ #
78
+ # Returns nothing.
79
+ def self.to_watchdir(torrents)
80
+ torrents.each do |tor|
81
+ FileUtils.mkdir_p tor.dir
82
+
83
+ open tor.link do |remote|
84
+ File.binwrite File.join(tor.dir, "#{tor.name}.torrent"), remote.read
85
+ end
86
+ end
87
+ end
88
+
89
+ # Internal: Send RPC commands to Transmission daemon for downloading
90
+ # torrents.
91
+ #
92
+ # url - URI object containing the URL of the daemon
93
+ # auth - Hash with :user and :password for Basic auth, or falsey value
94
+ # for no authorization.
95
+ # torrents - Array of torrents to download.
96
+ #
97
+ # Returns nothing.
98
+ def self.to_transmission(url, auth, torrents)
99
+ return if torrents.empty?
100
+
101
+ requests = torrents.map {|torrent| make_post_request url, make_transmission_rpc_command(torrent), auth}
102
+
103
+ Net::HTTP.start url.host, url.port do |transmission|
104
+ send_transmission_requests transmission, requests
105
+ end
106
+ end
107
+
108
+ # Internal: Send requests to a Transmission daemon. If a 409 Conflict
109
+ # response is recieved, update the 'X-transmission-Session-Id' header of
110
+ # the request and resend it.
111
+ #
112
+ # transmission - Net::HTTP connection to a Transmission daemon.
113
+ # reqs - Net::HTTP::Post requests to send to Transmission.
114
+ #
115
+ # Returns nothing.
116
+ def self.send_transmission_requests(transmission, reqs)
117
+ session_id = ''
118
+
119
+ reqs.each do |req|
120
+ req['X-Transmission-Session-Id'] = session_id
121
+
122
+ response = transmission.request req
123
+
124
+ case response
125
+ when Net::HTTPConflict
126
+ session_id = response['X-Transmission-Session-Id']
127
+ redo
128
+ end
129
+ end
130
+ end
131
+
132
+ # Internal: Create a URI object for a Transmission daemon URL.
133
+ #
134
+ # host - Host part of the URL.
135
+ # port - Port part of the URL.
136
+ # path - Path part of the URL.
137
+ #
138
+ # Returns a URI object.
139
+ def self.make_transmission_url(host, port, path)
140
+ URI::HTTP.build host: host || '127.0.0.1',
141
+ port: port || 9091,
142
+ path: "#{path || '/transmission/'}rpc"
143
+ end
144
+
145
+ # Internal: Generate a JSON-encoded 'torrent-add' RPC command that can be
146
+ # sent to a Transmission daemon.
147
+ #
148
+ # torrent - Torrent to generate command for.
149
+ #
150
+ # Returns a String RPC command.
151
+ def self.make_transmission_rpc_command(torrent)
152
+ JSON.generate(
153
+ {
154
+ "method" => "torrent-add",
155
+ "arguments" => {
156
+ "filename" => torrent.link,
157
+ "download-dir" => torrent.dir
158
+ }
159
+ }
160
+ )
161
+ end
162
+
163
+ # Internal: Create an HTTP POST request.
164
+ #
165
+ # url - URL this request will be sent to.
166
+ # body - String with body data.
167
+ # auth - Hash with Basic auth data, or falsey value for no authorization.
168
+ #
169
+ # Returns a Net::HTTP::Post request
170
+ def self.make_post_request(url, body, auth)
171
+ request = Net::HTTP::Post.new url
172
+ request.body = body
173
+ request.basic_auth auth[:user], auth[:password] if auth
174
+ request
175
+ end
176
+ end
177
+ end
178
+
@@ -0,0 +1,88 @@
1
+ require 'yaml'
2
+
3
+ require 'wanko/data'
4
+ require 'wanko/fetch'
5
+ require 'wanko/utility'
6
+
7
+ module Wanko
8
+
9
+ # Functions to read in data from files, urls and similar.
10
+ # All functions can be considered to rely on external state.
11
+ module Read
12
+
13
+ # Public: Read a config file, create a fetcher lambda and convert the
14
+ # rules.
15
+ #
16
+ # dir - Path to the directory containing the config file.
17
+ #
18
+ # Returns a Hash containing the configuration.
19
+ def self.config(dir)
20
+ config = raw_config dir
21
+
22
+ config.merge(
23
+ fetcher: Fetch.fetcher_for({name: 'stdout'}.merge Hash config[:fetcher]),
24
+ rules: Array(config[:rules]).map {|rule| convert_rule rule, config[:base_dir]}
25
+ )
26
+ end
27
+
28
+ # Public: Read a config file and supply some sensible defaults.
29
+ #
30
+ # dir - Path to the directory containing the config file.
31
+ #
32
+ # Returns a Hash containing the configuration.
33
+ def self.raw_config(dir)
34
+ config = Utility.symbolize_keys(YAML.load_file File.join(dir, 'config.yaml')) || {}
35
+
36
+ config.merge(
37
+ feeds: Array(config[:feeds]),
38
+ base_dir: config[:base_dir] || File.join(Dir.home, 'downloads'),
39
+ rules: Array(config[:rules])
40
+ )
41
+ end
42
+
43
+ # Internal: Convert a rule Hash into a Rule object, making the path
44
+ # absolute.
45
+ #
46
+ # rule - Rule to convert. Has a required :regex entry and an optional
47
+ # :dir entry.
48
+ # base_dir - Directory to use as base for relative paths, or as download
49
+ # dir if the rule has no :dir entry.
50
+ #
51
+ # Returns an Array of converted Rules.
52
+ def self.convert_rule(rule, base_dir)
53
+ Data::Rule.new rule[:regex], File.absolute_path(rule[:dir] || '', base_dir)
54
+ end
55
+
56
+ # Public: Read an RSS feed history file.
57
+ #
58
+ # dir - Path to the directory containing the history file.
59
+ #
60
+ # Returns a Hash containing the history, or an empty Hash if the file does
61
+ # not exist.
62
+ def self.history(dir)
63
+ history = begin
64
+ YAML.load_file File.join(dir, 'history.yaml')
65
+ rescue Errno::ENOENT
66
+ {}
67
+ end
68
+
69
+ # This is OK, since history is treated as read-only.
70
+ history.default = []
71
+
72
+ history
73
+ end
74
+
75
+ # Public: Read an RSS feed.
76
+ #
77
+ # url - Location of the feed. Must be openable by OpenURI.
78
+ #
79
+ # Returns an RSS::Rss object, or nil if the feed couldn't be read.
80
+ def self.feed(url)
81
+ begin
82
+ open(url, read_timeout: 10) {|rss| RSS::Parser.parse rss}
83
+ rescue OpenURI::HTTPError, Timeout::Error, Errno::ECONNREFUSED, SocketError => ex
84
+ warn "WARN: #{url} --> #{ex}"
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,59 @@
1
+ module Wanko
2
+
3
+ # Various utility functions.
4
+ module Utility
5
+
6
+ # Public: Recursively convert all keys of a Hash using the supplied block.
7
+ # Array values are traversed and each entry is converted. If arg is any
8
+ # other kind of object it is left untouched. If the conversion results in
9
+ # duplicate keys, later keys will overwrite earlier ones.
10
+ #
11
+ # Convenience functions exist for some often used operations, see
12
+ # ::symbolize_keys and ::stringify_keys.
13
+ #
14
+ # arg - Object to convert.
15
+ # block - Block for converting the keys. Will be called with each key
16
+ # individually. Should return an object that can be used as a hash key.
17
+ #
18
+ # Examples
19
+ #
20
+ # Utility.convert_keys h, &:to_sym
21
+ #
22
+ # Utility.convert_keys(h) {|key| key.downcase.squeeze}
23
+ #
24
+ # Returns an object with converted hash keys.
25
+ def self.convert_keys(arg, &block)
26
+ case arg
27
+ when Hash
28
+ arg.each_with_object({}) { |(key, val), memo|
29
+ memo[yield(key)] = convert_keys(val, &block)
30
+ }
31
+ when Array
32
+ arg.map {|val| convert_keys val, &block}
33
+ else
34
+ arg
35
+ end
36
+ end
37
+
38
+ # Public: Recursively convert all keys in a Hash to Symbols. Does not check
39
+ # for duplicate keys. See ::convert_keys for more info.
40
+ #
41
+ # hash - Hash to convert. All keys must respond to #to_sym.
42
+ #
43
+ # Returns a structurally identical Hash with keys converted to Symbols.
44
+ def self.symbolize_keys(hash)
45
+ convert_keys hash, &:to_sym
46
+ end
47
+
48
+ # Public: Recursively convert all keys in a Hash to Strings. Does not check
49
+ # for duplicate keys. See ::convert_keys for more info.
50
+ #
51
+ # hash - Hash to convert. All keys must respond to #to_s.
52
+ #
53
+ # Returns a structurally identical Hash with keys converted to Strings.
54
+ def self.stringify_keys(hash)
55
+ convert_keys hash, &:to_s
56
+ end
57
+ end
58
+ end
59
+
@@ -0,0 +1,111 @@
1
+ require 'optparse'
2
+ require 'rss'
3
+
4
+ require 'wanko/command'
5
+ require 'wanko/data'
6
+ require 'wanko/read'
7
+
8
+ module Wanko
9
+
10
+ # Public: Parse cli switches. Exits and prints a usage message when given
11
+ # -h, --help or an invalid switch.
12
+ #
13
+ # args - Array of switches to parse. Will not be altered.
14
+ #
15
+ # Returns a Hash containing the parsed options.
16
+ def self.parse_cli_switches(args)
17
+ options = {
18
+ command: Command.method(:fetch),
19
+ config_dir: File.join(Dir.home, ".wanko")
20
+ }
21
+
22
+ parser = OptionParser.new do |parser|
23
+ parser.banner = 'Usage: wanko [options]'
24
+
25
+ parser.separator ''
26
+ parser.separator 'Options:'
27
+
28
+ parser.on '-c DIR', '--config_dir', 'Use a different config directory' do |dir|
29
+ options[:config_dir] = File.absolute_path dir
30
+ end
31
+
32
+ parser.on '-a REGEX', '--add', 'Add a fetch rule' do |regex|
33
+ options[:command] = Command.method :add
34
+ options[:regex] = regex
35
+ end
36
+
37
+ parser.on '-d DIR', '--directory', 'Optional directory for fetch rules added with -a' do |dir|
38
+ options[:dir] = dir
39
+ end
40
+
41
+ parser.on '-l', '--list', 'List all rules' do
42
+ options[:command] = Command.method :list
43
+ end
44
+
45
+ parser.on '-r ID', '--remove', Integer, 'Remove a fetch rule' do |id|
46
+ options[:command] = Command.method :remove
47
+ options[:ids] = [id]
48
+ end
49
+
50
+ parser.separator ''
51
+ parser.separator 'Other:'
52
+
53
+ parser.on '-h', '--help',
54
+ 'Show this message' do
55
+ puts parser
56
+ exit
57
+ end
58
+ end
59
+
60
+ begin
61
+ parser.parse args
62
+ rescue OptionParser::InvalidOption
63
+ puts parser
64
+ exit
65
+ end
66
+
67
+ options
68
+ end
69
+
70
+ # Public: Check RSS feeds for new torrents matching a set of rules, excluding
71
+ # already read items.
72
+ #
73
+ # urls - Array of feed urls to check.
74
+ # rules - Array of Rules to match against.
75
+ # history - Hash with urls mapped to Arrays of already read items. Will be
76
+ # accessed using the urls in the urls parameter. If a url is
77
+ # missing, an empty Array will be substituted.
78
+ #
79
+ # Returns a pair [[Torrent], Hash] of matched items and an updated history
80
+ def self.check_feeds(urls, rules, history)
81
+ matches, new_history = urls.map { |url|
82
+ feed = Read.feed(url) or next [[], {url => history[url]}]
83
+
84
+ [
85
+ match(feed, rules, Array(history[url])),
86
+ {url => feed.items.map {|item| item.guid.content}}
87
+ ]
88
+ }.transpose
89
+
90
+ [matches.flatten, new_history.reduce(:merge)]
91
+ end
92
+
93
+ # Internal: Match a set of rules against the items of an RSS feed, excluding
94
+ # already read items.
95
+ #
96
+ # feed - RSS object which items to search through.
97
+ # rules - Array of Rules.
98
+ # history - Array of GUIDs. Items found in this array will be rejected.
99
+ #
100
+ # Returns an Array of Torrents representing the matched items.
101
+ def self.match(feed, rules, history)
102
+ feed.items
103
+ .reject {|item| history.include? item.guid.content}
104
+ .product(rules)
105
+ .select {|item, rule| rule =~ item.title}
106
+ .map { |item, rule|
107
+ Data::Torrent.new item.title, item.link, rule.dir
108
+ }
109
+ end
110
+ end
111
+
@@ -0,0 +1,27 @@
1
+ require 'yaml'
2
+
3
+ module Wanko
4
+
5
+ # Functions for writing data out to files or similar. All functions can be
6
+ # considered to have destructive side-effects.
7
+ module Write
8
+
9
+ # Public: Write a YAML representation of an object to a file named
10
+ # 'history.yaml'.
11
+ #
12
+ # This function _will_ clobber an existing file.
13
+ #
14
+ # dir - Path of the directory to write the file in.
15
+ # history - Object to write out. Responds to #to_yaml.
16
+ #
17
+ # Returns nothing
18
+ def self.history(dir, history)
19
+ File.write File.join(dir, 'history.yaml'), history.to_yaml
20
+ end
21
+
22
+ def self.config(dir, config)
23
+ File.write File.join(dir, 'config.yaml'), config.to_yaml
24
+ end
25
+ end
26
+ end
27
+
metadata ADDED
@@ -0,0 +1,75 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: kemonomachi-wanko
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.2
5
+ platform: ruby
6
+ authors:
7
+ - Ookami Kenrou
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-04-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: terminal-table
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.6'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.6'
27
+ description: |2
28
+ Fetches torrent file links from RSS feeds based on user-specified rules. The
29
+ links can be printed to stdout or sent to Transmission for download, or the
30
+ torrent files can be downloaded to a watchdir for processing by other torrent
31
+ clients.
32
+ email: ookamikenrou@gmail.com
33
+ executables:
34
+ - wanko
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - LICENSE
39
+ - README
40
+ - bin/wanko
41
+ - lib/wanko.rb
42
+ - lib/wanko/command.rb
43
+ - lib/wanko/data.rb
44
+ - lib/wanko/exception.rb
45
+ - lib/wanko/fetch.rb
46
+ - lib/wanko/read.rb
47
+ - lib/wanko/utility.rb
48
+ - lib/wanko/wanko.rb
49
+ - lib/wanko/write.rb
50
+ homepage: https://github.com/kemonomachi/wanko
51
+ licenses:
52
+ - WTFPL
53
+ metadata: {}
54
+ post_install_message:
55
+ rdoc_options: []
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: 2.0.0
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ requirements:
69
+ - Transmission bittorrent client (optional)
70
+ rubyforge_project:
71
+ rubygems_version: 2.5.1
72
+ signing_key:
73
+ specification_version: 4
74
+ summary: RSS Torrent Fetcher
75
+ test_files: []