manga-tools 0.1.3 → 0.2.0
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/.github/FUNDING.yml +12 -0
- data/.rubocop.yml +6 -0
- data/Gemfile.lock +1 -1
- data/README.md +12 -0
- data/lib/manga/tools.rb +4 -0
- data/lib/manga/tools/cli.rb +23 -9
- data/lib/manga/tools/client.rb +57 -0
- data/lib/manga/tools/formatter.rb +44 -0
- data/lib/manga/tools/http.rb +29 -16
- data/lib/manga/tools/session.rb +59 -0
- data/lib/manga/tools/session_store.rb +60 -0
- data/lib/manga/tools/version.rb +1 -1
- metadata +7 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b4e6fa4035509554d7e20e8a8eba9c21b813bb8e68dc800b3c44a58419dfa2e0
|
|
4
|
+
data.tar.gz: 1ae99cc528222dcad3a93cfb36cc34ec86474a157a642f51223ff5b7daa082ac
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 58d66eea0fd9957cb9a2a563810b4397fb0d476b6d99a7f56b4a3668a22cea0351aa3eca8758d5bf267a04eb7b34c842340ed9e42875750f973eb164157df91e
|
|
7
|
+
data.tar.gz: a61b64bbf848a173b45a16698e6a7cc7da586a13c0a7c681ebc75555ea958421d3327541258f4b2ea989d5501234df94fb0b3c443be7d43769b775a02fd4b394
|
data/.github/FUNDING.yml
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# These are supported funding model platforms
|
|
2
|
+
|
|
3
|
+
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
|
|
4
|
+
patreon: yagihiro
|
|
5
|
+
open_collective: # Replace with a single Open Collective username
|
|
6
|
+
ko_fi: # Replace with a single Ko-fi username
|
|
7
|
+
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
|
|
8
|
+
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
|
|
9
|
+
liberapay: # Replace with a single Liberapay username
|
|
10
|
+
issuehunt: # Replace with a single IssueHunt username
|
|
11
|
+
otechie: # Replace with a single Otechie username
|
|
12
|
+
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
|
data/.rubocop.yml
CHANGED
|
@@ -19,11 +19,17 @@ AllCops:
|
|
|
19
19
|
Exclude:
|
|
20
20
|
- 'bin/*'
|
|
21
21
|
|
|
22
|
+
Lint/AmbiguousBlockAssociation:
|
|
23
|
+
Exclude:
|
|
24
|
+
- 'spec/**/*'
|
|
25
|
+
|
|
22
26
|
Metrics/AbcSize:
|
|
23
27
|
Max: 37
|
|
24
28
|
|
|
25
29
|
Metrics/BlockLength:
|
|
26
30
|
Max: 36
|
|
31
|
+
Exclude:
|
|
32
|
+
- 'spec/**/*'
|
|
27
33
|
|
|
28
34
|
Metrics/CyclomaticComplexity:
|
|
29
35
|
Max: 10
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
|
@@ -29,6 +29,18 @@ Or install it yourself as:
|
|
|
29
29
|
$ manga-tools search "ONE PIECE"
|
|
30
30
|
```
|
|
31
31
|
|
|
32
|
+
* Follow the specified title
|
|
33
|
+
|
|
34
|
+
```
|
|
35
|
+
$ manga-tools follow "key"
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
* Displays a list of the titles you are following
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
$ manga-tools follow-list
|
|
42
|
+
```
|
|
43
|
+
|
|
32
44
|
## Development
|
|
33
45
|
|
|
34
46
|
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
data/lib/manga/tools.rb
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative 'tools/cli'
|
|
4
|
+
require_relative 'tools/client'
|
|
5
|
+
require_relative 'tools/formatter'
|
|
4
6
|
require_relative 'tools/http'
|
|
7
|
+
require_relative 'tools/session'
|
|
8
|
+
require_relative 'tools/session_store'
|
|
5
9
|
require_relative 'tools/version'
|
|
6
10
|
|
|
7
11
|
module Manga
|
data/lib/manga/tools/cli.rb
CHANGED
|
@@ -2,27 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
require 'json'
|
|
4
4
|
require 'thor'
|
|
5
|
-
require_relative '
|
|
5
|
+
require_relative 'client'
|
|
6
|
+
require_relative 'formatter'
|
|
6
7
|
|
|
7
8
|
module Manga
|
|
8
9
|
module Tools
|
|
9
10
|
# CLI class
|
|
10
11
|
class CLI < Thor
|
|
12
|
+
HOST_OPTION = { aliases: '-h', desc: 'Specifies the host to connect to for development' }.freeze
|
|
13
|
+
|
|
11
14
|
def self.exit_on_failure?
|
|
12
15
|
true
|
|
13
16
|
end
|
|
14
17
|
|
|
15
18
|
desc 'search WORD', 'Search titles for a given WORD'
|
|
19
|
+
method_option :host, HOST_OPTION
|
|
16
20
|
def search(word)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
21
|
+
client = Manga::Tools::Client.new
|
|
22
|
+
results = client.search(word, options)
|
|
23
|
+
Manga::Tools::Formatter.display(:search, word, results)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc 'follow KEY', 'Follow a title for a given follow KEY'
|
|
27
|
+
method_option :host, HOST_OPTION
|
|
28
|
+
def follow(key)
|
|
29
|
+
client = Manga::Tools::Client.new
|
|
30
|
+
results = client.follow(key, options)
|
|
31
|
+
Manga::Tools::Formatter.display(:follow, key, results)
|
|
32
|
+
end
|
|
20
33
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
34
|
+
desc 'follow-list', 'Displays the follow list'
|
|
35
|
+
method_option :host, HOST_OPTION
|
|
36
|
+
def follow_list
|
|
37
|
+
client = Manga::Tools::Client.new
|
|
38
|
+
results = client.follow_list(options)
|
|
39
|
+
Manga::Tools::Formatter.display(:follow_list, results)
|
|
26
40
|
end
|
|
27
41
|
end
|
|
28
42
|
end
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'cgi'
|
|
4
|
+
require 'json'
|
|
5
|
+
require_relative 'http'
|
|
6
|
+
require_relative 'session'
|
|
7
|
+
|
|
8
|
+
module Manga
|
|
9
|
+
module Tools
|
|
10
|
+
# Client Application class
|
|
11
|
+
class Client
|
|
12
|
+
# @return [Manga::Tools::Session] a session instance
|
|
13
|
+
attr :session
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@session = Manga::Tools::Session.new
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Search `word` with options.
|
|
20
|
+
# @param word [String] search string
|
|
21
|
+
# @param options [Hash] command options from Thor
|
|
22
|
+
def search(word, options)
|
|
23
|
+
session.options = adapt_to_dev_env(options)
|
|
24
|
+
session.get("/publications?keyword=#{CGI.escape(word)}")
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Follow a title for a given follow `key`
|
|
28
|
+
# @param key [String] follow key
|
|
29
|
+
# @param options [Hash] command options from Thor
|
|
30
|
+
def follow(key, options)
|
|
31
|
+
params = { key: key }
|
|
32
|
+
session.options = adapt_to_dev_env(options)
|
|
33
|
+
session.post('/follows', params)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Displays the follow list
|
|
37
|
+
# @param options [Hash] command options from Thor
|
|
38
|
+
def follow_list(options)
|
|
39
|
+
session.options = adapt_to_dev_env(options)
|
|
40
|
+
session.get('/follows')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
def adapt_to_dev_env(options)
|
|
46
|
+
opts = options.dup
|
|
47
|
+
|
|
48
|
+
if opts[:host]
|
|
49
|
+
# If the `host` option is specified, it is assumed to be the development environment
|
|
50
|
+
opts[:session_file_name] = 'session-development.txt'
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
opts
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Manga
|
|
4
|
+
module Tools
|
|
5
|
+
# Formatter class
|
|
6
|
+
class Formatter
|
|
7
|
+
class << self
|
|
8
|
+
def display(command, *results)
|
|
9
|
+
case command
|
|
10
|
+
when :search
|
|
11
|
+
display_search(results)
|
|
12
|
+
when :follow
|
|
13
|
+
display_follow(results)
|
|
14
|
+
when :follow_list
|
|
15
|
+
display_follow_list(results)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
|
|
21
|
+
def display_search(results)
|
|
22
|
+
puts "Searching '#{results[0]}' ..."
|
|
23
|
+
results[1].each do |item|
|
|
24
|
+
puts "#{item['published_at']} [#{item['follow_key']}]: #{item['title']}"
|
|
25
|
+
end
|
|
26
|
+
puts 'Finished.'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def display_follow(results)
|
|
30
|
+
puts "Followed '#{results[1]['title']}'."
|
|
31
|
+
puts 'Finished.'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def display_follow_list(results)
|
|
35
|
+
puts 'Listing follow list...'
|
|
36
|
+
results[0].each do |item|
|
|
37
|
+
puts (item['title']).to_s
|
|
38
|
+
end
|
|
39
|
+
puts 'Finished.'
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
data/lib/manga/tools/http.rb
CHANGED
|
@@ -9,35 +9,48 @@ module Manga
|
|
|
9
9
|
# HTTP client class
|
|
10
10
|
module Http
|
|
11
11
|
# @param url [String] an url string, eg: `https://example.com`
|
|
12
|
+
# @param session_id [String, nil] A Session ID string or nil
|
|
12
13
|
# @return [Faraday::Connection] a connection object
|
|
13
|
-
def self.connection(url)
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
) do |f|
|
|
14
|
+
def self.connection(url, session_id)
|
|
15
|
+
headers = { 'User-Agent' => user_agent }
|
|
16
|
+
headers['X-Session-ID'] = session_id if session_id
|
|
17
|
+
|
|
18
|
+
@connection = Faraday.new(url: url, headers: headers) do |f|
|
|
18
19
|
# f.response :logger
|
|
20
|
+
f.response :raise_error
|
|
19
21
|
end
|
|
20
22
|
end
|
|
21
23
|
|
|
22
24
|
# @param url [String] an url string, eg: `https://example.com/path/to/object`
|
|
25
|
+
# @param session_id [String, nil] A Session ID string or nil
|
|
23
26
|
# @return [Faraday::Response] a response object
|
|
24
|
-
def self.get(url)
|
|
27
|
+
def self.get(url, session_id)
|
|
25
28
|
u = URI.parse(url)
|
|
26
|
-
connection(
|
|
29
|
+
connection(connection_url(u), session_id).get(u.request_uri)
|
|
27
30
|
end
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
32
|
+
def self.post(url, session_id, params)
|
|
33
|
+
u = URI.parse(url)
|
|
34
|
+
connection(connection_url(u), session_id).post do |req|
|
|
35
|
+
req.headers['Content-Type'] = 'application/json'
|
|
36
|
+
req.url u.request_uri
|
|
37
|
+
req.body = params.to_json
|
|
38
|
+
end
|
|
39
|
+
end
|
|
37
40
|
|
|
38
|
-
|
|
41
|
+
# @param url [URI] A URL instance.
|
|
42
|
+
# @return [String] Returns the URL to connect to.
|
|
43
|
+
#
|
|
44
|
+
# If the port is not a standard port (80 or 443), the port number is included.
|
|
45
|
+
def self.connection_url(url)
|
|
46
|
+
if [80, 443].include?(url.port)
|
|
47
|
+
"#{url.scheme}://#{url.host}"
|
|
48
|
+
else
|
|
49
|
+
"#{url.scheme}://#{url.host}:#{url.port}"
|
|
50
|
+
end
|
|
39
51
|
end
|
|
40
52
|
|
|
53
|
+
# @return [String] Returns a user agent string
|
|
41
54
|
def self.user_agent
|
|
42
55
|
@user_agent ||= "manga-tools #{Manga::Tools::VERSION}"
|
|
43
56
|
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'json'
|
|
4
|
+
require_relative 'http'
|
|
5
|
+
require_relative 'session_store'
|
|
6
|
+
|
|
7
|
+
module Manga
|
|
8
|
+
module Tools
|
|
9
|
+
# Network Session class (Session ID handling + HTTP CRUD handling)
|
|
10
|
+
class Session
|
|
11
|
+
DEFAULT_HOST = 'https://manga-tools-server.herokuapp.com'
|
|
12
|
+
|
|
13
|
+
# @return [Hash] options hash instance
|
|
14
|
+
attr :options
|
|
15
|
+
|
|
16
|
+
# @return [SessionStore] the session store instance
|
|
17
|
+
attr :store
|
|
18
|
+
|
|
19
|
+
def initialize
|
|
20
|
+
@store = Manga::Tools::SessionStore.new
|
|
21
|
+
@options = {}
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def options=(new_options)
|
|
25
|
+
@base_url = nil
|
|
26
|
+
@options = new_options
|
|
27
|
+
store.session_file_name = @options[:session_file_name] if @options[:session_file_name]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def get(path)
|
|
31
|
+
response = with_session { |session_id| Manga::Tools::Http.get(build_full_url(path), session_id) }
|
|
32
|
+
JSON.parse(response.body)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def post(path, params)
|
|
36
|
+
response = with_session { |session_id| Manga::Tools::Http.post(build_full_url(path), session_id, params) }
|
|
37
|
+
JSON.parse(response.body)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
private
|
|
41
|
+
|
|
42
|
+
def with_session
|
|
43
|
+
session_id = store.load
|
|
44
|
+
res = yield session_id
|
|
45
|
+
session_id = res.headers['X-Session-ID']
|
|
46
|
+
store.store(session_id) if session_id
|
|
47
|
+
res
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def base_url
|
|
51
|
+
@base_url ||= options[:host] ? "http://#{options[:host]}" : DEFAULT_HOST
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def build_full_url(path)
|
|
55
|
+
"#{base_url}#{path}"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
|
|
5
|
+
module Manga
|
|
6
|
+
module Tools
|
|
7
|
+
# A class on session retention.
|
|
8
|
+
class SessionStore
|
|
9
|
+
# @return [String] the session file name string
|
|
10
|
+
attr_writer :session_file_name
|
|
11
|
+
|
|
12
|
+
def initialize
|
|
13
|
+
create_session_dir_if_necessary
|
|
14
|
+
@session_file_name = 'session.txt'
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Store a session.
|
|
18
|
+
def store(session_id)
|
|
19
|
+
return if exists?
|
|
20
|
+
|
|
21
|
+
File.open(session_file_path, 'w') do |f|
|
|
22
|
+
f.write(session_id)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# @return [String, nil] Returns the session ID if the session is stored, otherwise it returns nil
|
|
27
|
+
def load
|
|
28
|
+
return nil unless exists?
|
|
29
|
+
|
|
30
|
+
File.read(session_file_path)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# @return [Boolean] true if the session exists, otherwise returns false.
|
|
34
|
+
def exists?
|
|
35
|
+
File.exist?(session_file_path)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# @return [String] the session file path
|
|
39
|
+
def session_file_path
|
|
40
|
+
"#{session_dir}/#{@session_file_name}"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
private
|
|
44
|
+
|
|
45
|
+
# @return [String] the root directory
|
|
46
|
+
def root_dir
|
|
47
|
+
@root_dir ||= "#{Dir.home}/.manga-tools"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# @return [String] the session directory
|
|
51
|
+
def session_dir
|
|
52
|
+
@session_dir ||= "#{root_dir}/session"
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def create_session_dir_if_necessary
|
|
56
|
+
FileUtils.mkdir_p(session_dir)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
data/lib/manga/tools/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: manga-tools
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Hiroki Yagita
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2020-
|
|
11
|
+
date: 2020-09-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: faraday
|
|
@@ -46,6 +46,7 @@ executables:
|
|
|
46
46
|
extensions: []
|
|
47
47
|
extra_rdoc_files: []
|
|
48
48
|
files:
|
|
49
|
+
- ".github/FUNDING.yml"
|
|
49
50
|
- ".github/workflows/ruby.yml"
|
|
50
51
|
- ".gitignore"
|
|
51
52
|
- ".rspec"
|
|
@@ -63,7 +64,11 @@ files:
|
|
|
63
64
|
- exe/manga-tools
|
|
64
65
|
- lib/manga/tools.rb
|
|
65
66
|
- lib/manga/tools/cli.rb
|
|
67
|
+
- lib/manga/tools/client.rb
|
|
68
|
+
- lib/manga/tools/formatter.rb
|
|
66
69
|
- lib/manga/tools/http.rb
|
|
70
|
+
- lib/manga/tools/session.rb
|
|
71
|
+
- lib/manga/tools/session_store.rb
|
|
67
72
|
- lib/manga/tools/version.rb
|
|
68
73
|
- manga-tools.gemspec
|
|
69
74
|
homepage: https://github.com/yagihiro/manga-tools
|