wikian 0.1.0 → 0.1.5
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/.gitignore +1 -18
- data/Gemfile.lock +21 -0
- data/README.md +45 -19
- data/exe/wi +9 -0
- data/exe/wikian +2 -3
- data/lib/.gitignore +0 -0
- data/lib/wikian.rb +125 -4
- data/lib/wikian/get.rb +99 -0
- data/lib/wikian/post.rb +140 -0
- data/lib/wikian/search.rb +40 -0
- data/lib/wikian/subcommand.rb +74 -0
- data/lib/wikian/version.rb +2 -2
- metadata +10 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7641f6124dd8e9db31fa2dc7688146107db693d65d8347af57d45ee40205519
|
4
|
+
data.tar.gz: a9def9f5d7d2cc6a00c375f9e690e96aaf193a601359ae98fb1f4abea1f31402
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d7887e82d7f20332717314772cba3ca4bbb4d7cb54d5a1dab3235f1c248654949c3427feaa6915324b437117d0e87147c219a2acbed7654ddeb22c89541abc50
|
7
|
+
data.tar.gz: 37998e9226c13ddfa504921859e4da1f9f8e96a19edcc617faaf30a7a387d80fff4768e29c868f9ebfb363c168baaada1f3280cbc241c3f91c10c732e378c790
|
data/.gitignore
CHANGED
@@ -1,15 +1,6 @@
|
|
1
|
-
# files without extensions except directories
|
2
|
-
*
|
3
|
-
!/**/
|
4
|
-
!?*.*
|
5
|
-
|
6
1
|
# directories
|
7
|
-
.bundle/
|
8
|
-
_yardoc/
|
9
|
-
coverage/
|
10
2
|
doc/
|
11
3
|
pkg/
|
12
|
-
spec/reports/
|
13
4
|
tmp/
|
14
5
|
vendor/
|
15
6
|
|
@@ -22,6 +13,7 @@ vendor/
|
|
22
13
|
.*.swp
|
23
14
|
.DS_Store
|
24
15
|
.byebug
|
16
|
+
.byebugrc
|
25
17
|
.idea
|
26
18
|
.project
|
27
19
|
.rake*
|
@@ -46,12 +38,3 @@ secrets.yml
|
|
46
38
|
![MR]akefile
|
47
39
|
!bin/**/[^.]*
|
48
40
|
!exe/**/[^.]*
|
49
|
-
|
50
|
-
/.bundle/
|
51
|
-
/.yardoc
|
52
|
-
/_yardoc/
|
53
|
-
/coverage/
|
54
|
-
/doc/
|
55
|
-
/pkg/
|
56
|
-
/spec/reports/
|
57
|
-
/tmp/
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
wikian (0.1.5)
|
5
|
+
|
6
|
+
GEM
|
7
|
+
remote: https://rubygems.org/
|
8
|
+
specs:
|
9
|
+
minitest (5.14.2)
|
10
|
+
rake (12.3.3)
|
11
|
+
|
12
|
+
PLATFORMS
|
13
|
+
ruby
|
14
|
+
|
15
|
+
DEPENDENCIES
|
16
|
+
minitest (~> 5.0)
|
17
|
+
rake (~> 12.0)
|
18
|
+
wikian!
|
19
|
+
|
20
|
+
BUNDLED WITH
|
21
|
+
2.1.4
|
data/README.md
CHANGED
@@ -1,40 +1,66 @@
|
|
1
1
|
# Wikian
|
2
2
|
|
3
|
-
|
3
|
+
Want to be happier while editing wiki files?
|
4
|
+
Me too, that's why I use [Wikian](https://rubygems.org/gems/wikian):
|
4
5
|
|
5
|
-
|
6
|
+
```
|
7
|
+
$ gem install wikian
|
8
|
+
```
|
9
|
+
|
10
|
+
To use it create a Wikipedia account, then define and export the `WIKI_USER` and `SECRET_WIKI_PASS` variables in your `.bashrc`:
|
6
11
|
|
7
|
-
|
12
|
+
```bash
|
13
|
+
export WIKI_USER='Example_wiki_user_name'
|
14
|
+
export SECRET_WIKI_PASS='example_wiki_password'
|
15
|
+
```
|
8
16
|
|
9
|
-
|
17
|
+
Wikian works across [Wikimedia sites](https://meta.wikimedia.org/wiki/Our_projects) and follows the file naming convention:
|
10
18
|
|
11
|
-
```ruby
|
12
|
-
gem 'wikian'
|
13
19
|
```
|
20
|
+
<article_name>.<site>.wiki
|
21
|
+
```
|
22
|
+
|
23
|
+
Some valid file names:
|
14
24
|
|
15
|
-
|
25
|
+
```
|
26
|
+
Spider_Man.en.wikipedia.org.wiki
|
27
|
+
Spider_Man.es.wikipedia.org.wiki
|
28
|
+
excelsior.es.wiktionary.org.wiki
|
29
|
+
User:Example_User.www.mediawiki.org.wiki
|
30
|
+
```
|
16
31
|
|
17
|
-
|
32
|
+
#### Examples
|
18
33
|
|
19
|
-
|
34
|
+
To append some text to your Wiktionary user profile:
|
20
35
|
|
21
|
-
|
36
|
+
```bash
|
37
|
+
$ cat User:$WIKI_USER.en.wikitionary.org.wiki
|
22
38
|
|
23
|
-
|
39
|
+
== Last section==
|
40
|
+
testing
|
24
41
|
|
25
|
-
|
42
|
+
$ wi post -p User:$WIKI_USER.en.wikitionary.org.wiki
|
43
|
+
Article uploaded
|
44
|
+
```
|
26
45
|
|
27
|
-
|
46
|
+
To get an article's wikitext:
|
28
47
|
|
29
|
-
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
48
|
|
31
|
-
|
49
|
+
```
|
50
|
+
$ wi get -t
|
51
|
+
Creating template wiki.yml
|
32
52
|
|
33
|
-
|
53
|
+
$ wi g https://en.wikipedia.org/wiki/Wikipedia:Sandbox
|
54
|
+
Writing to Wikipedia:Sandbox.en.wikipedia.org.json
|
55
|
+
Writing to Wikipedia:Sandbox.en.wikipedia.org.wiki
|
56
|
+
```
|
34
57
|
|
35
|
-
|
58
|
+
You can then edit the the article in your favorite text editor and uploaded:
|
36
59
|
|
60
|
+
```bash
|
61
|
+
$ wi post Wikipedia:Sandbox.en.wikipedia.org.wiki
|
62
|
+
Article uploaded
|
63
|
+
```
|
37
64
|
|
38
|
-
|
65
|
+
Vim users should try out [mediawiki.vim](https://en.wikipedia.org/wiki/Help:Text_editor_support#Vim) which defines syntax highlighting and abbreviations for wikitext files.
|
39
66
|
|
40
|
-
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/exe/wi
ADDED
data/exe/wikian
CHANGED
data/lib/.gitignore
ADDED
File without changes
|
data/lib/wikian.rb
CHANGED
@@ -1,8 +1,129 @@
|
|
1
1
|
$LOAD_PATH.unshift __dir__
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'wikian/subcommand'
|
4
|
+
require 'wikian/get'
|
5
|
+
require 'wikian/post'
|
6
|
+
require 'wikian/search'
|
7
|
+
require 'wikian/version'
|
4
8
|
|
5
|
-
|
6
|
-
|
7
|
-
|
9
|
+
# stdlib
|
10
|
+
require 'fileutils'
|
11
|
+
require 'json'
|
12
|
+
require 'net/http'
|
13
|
+
require 'open-uri'
|
14
|
+
require 'yaml'
|
15
|
+
|
16
|
+
# external libraries
|
17
|
+
require 'byebug'
|
18
|
+
|
19
|
+
class Array
|
20
|
+
# return true if `self` and `elms` have any element in common
|
21
|
+
def have?(elms)
|
22
|
+
(self & elms).length > 0 ? true : false
|
23
|
+
end
|
24
|
+
alias_method :has?, :have?
|
25
|
+
end
|
26
|
+
|
27
|
+
class Hash
|
28
|
+
# return a query string representation of a hash
|
29
|
+
def to_query
|
30
|
+
URI.decode(URI.encode_www_form(self))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
class Wikian
|
35
|
+
class WikianError < StandardError; end
|
36
|
+
class UnknownSubcommandError < WikianError; end
|
37
|
+
|
38
|
+
attr_accessor :subcommand, :args
|
39
|
+
|
40
|
+
CONFIG_FILE = 'wiki.yml'
|
41
|
+
RESPONSE_FORMAT = 'json'
|
42
|
+
|
43
|
+
def initialize(*args)
|
44
|
+
@args = args
|
45
|
+
end
|
46
|
+
|
47
|
+
def run
|
48
|
+
if args.have?(%w(-h --help))
|
49
|
+
help
|
50
|
+
elsif args.have?(%w(-v --version))
|
51
|
+
version
|
52
|
+
end
|
53
|
+
|
54
|
+
@subcommand = args.shift
|
55
|
+
|
56
|
+
raise(UnknownSubcommandError, "Unkown Subcommand") unless %w(g p s get post search).include?(subcommand)
|
57
|
+
|
58
|
+
if subcommand[0] == 'g'
|
59
|
+
api = Wikian::Get.new(args)
|
60
|
+
api.doit
|
61
|
+
api.extract_wikitext
|
62
|
+
elsif subcommand[0] == 's'
|
63
|
+
api = Wikian::Search.new(args)
|
64
|
+
api.doit
|
65
|
+
else
|
66
|
+
api = Wikian::Post.new(args)
|
67
|
+
api.post
|
68
|
+
end
|
69
|
+
|
70
|
+
rescue UnknownSubcommandError => e
|
71
|
+
puts "#{e.class} #{e.message}"
|
72
|
+
end
|
73
|
+
|
74
|
+
def help
|
75
|
+
puts <<~eos
|
76
|
+
Usage:
|
77
|
+
wiki [options] <subcommand> [url|file]
|
78
|
+
|
79
|
+
Options:
|
80
|
+
-a, --append append the input file
|
81
|
+
-c, --captcha ID:MESSAGE captcha info
|
82
|
+
-d, --debug debug
|
83
|
+
-m, --message MESSAGE add a commit message (HIGHLY recommended)
|
84
|
+
-p, --prepend prepend the input file
|
85
|
+
-r, --remove-cookie remove API cookie
|
86
|
+
-t, --template create template configuration file
|
87
|
+
-v, --version
|
88
|
+
|
89
|
+
Subcommands:
|
90
|
+
g, get get wikitext file from a wikipedia article
|
91
|
+
p, post post wikitext file to a wikipedia article
|
92
|
+
s, search search wikitext file to a wikipedia article
|
93
|
+
|
94
|
+
Examples:
|
95
|
+
# create wiki.yml template
|
96
|
+
wiki -t
|
97
|
+
|
98
|
+
# download article and create response and wikitext files
|
99
|
+
wiki get https://en.wikipedia.org/wiki/Spider-Man
|
100
|
+
|
101
|
+
# upload file to English Wikipedia
|
102
|
+
wiki post Spider-Man.en.wikipedia.org.wiki
|
103
|
+
|
104
|
+
# upload file to Spanish Wikipedia
|
105
|
+
wiki post Spider-Man.es.wikipedia.org.wiki
|
106
|
+
|
107
|
+
# upload file to English Wiktionary
|
108
|
+
wiki file to Spider-Man.es.wiktionary.org.wiki
|
109
|
+
|
110
|
+
# append new section to article
|
111
|
+
wiki post -a Spider-Man-new-section.wiki
|
112
|
+
|
113
|
+
# heavy use of the API may require cache validation
|
114
|
+
wiki post -c 1234:someMessage spider-Man.wiki
|
115
|
+
|
116
|
+
Comments:
|
117
|
+
Posted files must follow the convention:
|
118
|
+
<article_name>.<host>.wiki
|
119
|
+
where <host> is a wikimedia site.
|
120
|
+
More info at: https://meta.wikimedia.org/wiki/Our_projects
|
121
|
+
eos
|
122
|
+
exit
|
123
|
+
end
|
124
|
+
|
125
|
+
def version
|
126
|
+
puts "wikian #{VERSION}"
|
127
|
+
exit
|
128
|
+
end
|
8
129
|
end
|
data/lib/wikian/get.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
class Wikian
|
2
|
+
class WikianGetError < StandardError; end
|
3
|
+
class ExtractWikiError < WikianGetError; end
|
4
|
+
class ArgumentRequiredError < WikianGetError; end
|
5
|
+
class BadUrlError < WikianGetError; end
|
6
|
+
|
7
|
+
class Get < Subcommand
|
8
|
+
attr_accessor :title
|
9
|
+
|
10
|
+
def initialize(args)
|
11
|
+
raise ArgumentRequiredError if args.empty?
|
12
|
+
|
13
|
+
super
|
14
|
+
|
15
|
+
url = URI(args.find{|arg| arg =~ URI.regexp})
|
16
|
+
|
17
|
+
raise BadUrlError unless url.path
|
18
|
+
|
19
|
+
@title = File.basename(url.path)
|
20
|
+
|
21
|
+
@output_file = title + '.' + url.host
|
22
|
+
|
23
|
+
@params.merge!('titles' => title, 'format' => Wikian::RESPONSE_FORMAT)
|
24
|
+
|
25
|
+
@query = @params.to_query
|
26
|
+
|
27
|
+
@api_url = URI("https://#{url.host}/w/api.php?#{query}")
|
28
|
+
rescue => e
|
29
|
+
puts "#{e.class} #{e.message} in #{__FILE__}"
|
30
|
+
exit
|
31
|
+
end
|
32
|
+
|
33
|
+
# extract wikitext from the response file and save it into a `.wiki` file
|
34
|
+
#
|
35
|
+
# return: nil
|
36
|
+
def extract_wikitext
|
37
|
+
if !res['content-type'].match?('json') || !(pages = JSON.parse(res.body).dig('query','pages'))
|
38
|
+
raise ExtractWikiError, 'JSON response has no pages'
|
39
|
+
end
|
40
|
+
|
41
|
+
create_wiki = -> (title, revisions) do
|
42
|
+
revisions.each do |revision|
|
43
|
+
wiki_file= File.basename(response_file, File.extname(response_file)) + '.wiki'
|
44
|
+
if revision['revid'].nil? && revisions.size > 1
|
45
|
+
STDERR.puts "Warning: you should specify 'revid' in #{Wikian::CONFIG_FILE} to prevent overriding different revisions"
|
46
|
+
end
|
47
|
+
File.open(wiki_file,'w') do |f|
|
48
|
+
content = revision.dig('slots', 'main', 'content') ||
|
49
|
+
revision.dig('slots', '*') ||
|
50
|
+
revision.dig('*')
|
51
|
+
STDERR.puts "Warning: nil 'content' in #{Wikian::CONFIG_FILE}" unless content
|
52
|
+
STDERR.puts "Writing to #{wiki_file}"
|
53
|
+
f.puts content
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# this is ugly, but Wikipedia is inconsistent in their JSON value for 'pages'. Sometimes it's a hash, sometimes it's an array.
|
59
|
+
if pages.respond_to? :keys
|
60
|
+
byebug
|
61
|
+
create_wiki.call(pages.values.first['title'], pages.values.first['revisions'])
|
62
|
+
else
|
63
|
+
pages.each do |page|
|
64
|
+
create_wiki.call(page['title'], page['revisions'])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
rescue => e
|
69
|
+
puts "An error occurred while extracting the wikitext",
|
70
|
+
"Try using a new config file by pasing the '-t' option.",
|
71
|
+
"Or pass '-d' option for debugging"
|
72
|
+
exit
|
73
|
+
end
|
74
|
+
|
75
|
+
def template
|
76
|
+
<<~eos
|
77
|
+
meta:
|
78
|
+
headers:
|
79
|
+
user-agent: Wikian
|
80
|
+
api:
|
81
|
+
action:
|
82
|
+
- query
|
83
|
+
prop:
|
84
|
+
- revisions
|
85
|
+
rvprop:
|
86
|
+
- content
|
87
|
+
#rvsection:
|
88
|
+
# - 0
|
89
|
+
# - 2
|
90
|
+
rvslots:
|
91
|
+
- main
|
92
|
+
formatversion:
|
93
|
+
- 2
|
94
|
+
format:
|
95
|
+
- json
|
96
|
+
eos
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/lib/wikian/post.rb
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
class Wikian
|
2
|
+
class WikianPostError < StandardError; end
|
3
|
+
class WikiFileError < WikianPostError; end
|
4
|
+
|
5
|
+
class Post
|
6
|
+
attr_accessor :args, :baseurl, :header, :input_file, :debug, :login_token,
|
7
|
+
:login_cookie, :csrf_token, :csrf_cookie, :query, :body_text, :username
|
8
|
+
|
9
|
+
def initialize(args)
|
10
|
+
@args = args
|
11
|
+
|
12
|
+
# input wikitext file
|
13
|
+
@input_file = args.find{|f| File.exist? f}
|
14
|
+
raise WikiFileError unless input_file
|
15
|
+
|
16
|
+
site = input_file.match(/\.(.*)\.wiki/)[1]
|
17
|
+
|
18
|
+
@baseurl = "https://#{site}/w/api.php"
|
19
|
+
|
20
|
+
@header = {}
|
21
|
+
|
22
|
+
@username = ENV['WIKI_USER']
|
23
|
+
|
24
|
+
@debug = (args & %w(-d --debug)).length > 0 ? true : false
|
25
|
+
rescue => e
|
26
|
+
puts "#{e.class} in #{__FILE__}"
|
27
|
+
exit
|
28
|
+
end
|
29
|
+
|
30
|
+
def post
|
31
|
+
# remove expired cookie
|
32
|
+
if expired_cookie? || args.have?(%w(-r --remove-cookie))
|
33
|
+
FileUtils.rm_f(csrf_cookie_file)
|
34
|
+
end
|
35
|
+
|
36
|
+
# csrf_cookie can be reused among multiple requests. But csrf_token must be updated on each request
|
37
|
+
if File.exist?(csrf_cookie_file)
|
38
|
+
@csrf_cookie = File.read(csrf_cookie_file)
|
39
|
+
else
|
40
|
+
get_login_token
|
41
|
+
|
42
|
+
get_csrf_cookie
|
43
|
+
end
|
44
|
+
get_csrf_token
|
45
|
+
|
46
|
+
build_query_string
|
47
|
+
|
48
|
+
upload_article
|
49
|
+
end
|
50
|
+
|
51
|
+
# check if the cookie is expired (older than an hour)
|
52
|
+
def expired_cookie?
|
53
|
+
File.exist?(csrf_cookie_file) && ((Time.now - File.open(csrf_cookie_file).stat.ctime)/3600 > 1)
|
54
|
+
end
|
55
|
+
|
56
|
+
def csrf_cookie_file
|
57
|
+
'csrf_cookie'
|
58
|
+
end
|
59
|
+
|
60
|
+
def remove_cookie_metadata(cookie)
|
61
|
+
cookie.gsub(/secure;|path=.*?[,;]|httponly[;,]|samesite=.*?[;,]|expires=.....*?[,;]|domain=.*?;|max-age=.*?[;,]/i,'').squeeze(' ')
|
62
|
+
end
|
63
|
+
|
64
|
+
def get_login_token
|
65
|
+
puts("Getting login token/cookie") if debug
|
66
|
+
url = URI("#{baseurl}?action=query&meta=tokens&format=json&type=login")
|
67
|
+
res = URI.open(url)
|
68
|
+
json = JSON.parse(res.read)
|
69
|
+
@login_token = json.dig('query','tokens','logintoken')
|
70
|
+
@login_cookie = remove_cookie_metadata(res.meta['set-cookie'])
|
71
|
+
puts(json) if debug
|
72
|
+
end
|
73
|
+
|
74
|
+
def get_csrf_cookie
|
75
|
+
puts("\nGetting csrf cookie using token #{login_token}") if debug
|
76
|
+
url = URI("#{baseurl}?action=login&lgname=#{username}&format=json")
|
77
|
+
req = Net::HTTP::Post.new(url, header.merge('cookie' => login_cookie, 'content-type' => 'application/x-www-form-urlencoded'))
|
78
|
+
req.set_form_data('lgpassword' => ENV['SECRET_WIKI_PASS'], 'lgtoken' => login_token)
|
79
|
+
http = Net::HTTP.new(url.host, url.port)
|
80
|
+
http.use_ssl = true
|
81
|
+
res=http.request(req)
|
82
|
+
@csrf_cookie = remove_cookie_metadata(res['set-cookie'])
|
83
|
+
File.write(csrf_cookie_file, @csrf_cookie)
|
84
|
+
puts(res.body) if debug
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_csrf_token
|
88
|
+
puts("\nGetting csrf token using csrf cookies") if debug
|
89
|
+
url = URI("#{baseurl}?action=query&meta=tokens&format=json&type=csrf")
|
90
|
+
res = URI.open(url, header.merge('cookie' => csrf_cookie))
|
91
|
+
json = JSON.parse(res.read)
|
92
|
+
@csrf_token = json.dig('query','tokens','csrftoken')
|
93
|
+
puts(json) if debug
|
94
|
+
end
|
95
|
+
|
96
|
+
def build_query_string
|
97
|
+
params={}
|
98
|
+
params['action'] = 'edit'
|
99
|
+
params['format'] = Wikian::RESPONSE_FORMAT
|
100
|
+
params['title'] = input_file.sub(/\..*/,'')
|
101
|
+
wikitext = File.read(input_file)
|
102
|
+
if args.have?(%w(-a --append))
|
103
|
+
params['appendtext'] = wikitext
|
104
|
+
elsif args.have?(%w(-p --prepend))
|
105
|
+
params['prependtext'] = wikitext
|
106
|
+
else
|
107
|
+
# pass the wikitext in request body
|
108
|
+
@body_text = wikitext
|
109
|
+
end
|
110
|
+
if args.include?('-c')
|
111
|
+
params['captchaid'], params['captchaword'] = args[args.index('-c')+1].split(':')
|
112
|
+
end
|
113
|
+
if args.include?('-m')
|
114
|
+
params['summary'] = args[args.index('-m')+1]
|
115
|
+
end
|
116
|
+
@query = URI.encode_www_form(params)
|
117
|
+
end
|
118
|
+
|
119
|
+
def upload_article
|
120
|
+
puts("\nUploading the wiki article using csrf token #{csrf_token}") if debug
|
121
|
+
url = URI("#{baseurl}?#{query}")
|
122
|
+
req = Net::HTTP::Post.new(url, header.merge('cookie' => csrf_cookie, 'content-type' => 'application/x-www-form-urlencoded'))
|
123
|
+
http = Net::HTTP.new(url.host, url.port)
|
124
|
+
req_body = body_text.nil? ? {token: csrf_token} : {token: csrf_token, text: body_text}
|
125
|
+
req.set_form_data(req_body)
|
126
|
+
http = Net::HTTP.new(url.host, url.port)
|
127
|
+
http.use_ssl = true
|
128
|
+
res=http.request(req)
|
129
|
+
json = JSON.parse(res.body)
|
130
|
+
puts(json) if debug
|
131
|
+
if json.dig('error')
|
132
|
+
puts "An error occurred while uploding the file",
|
133
|
+
"Try pasing the '-r' option to remove '#{csrf_cookie_file}'",
|
134
|
+
"Or pass '-d' option for debugging"
|
135
|
+
else
|
136
|
+
puts "Article uploaded"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Wikian
|
2
|
+
class WikianGetError < StandardError; end
|
3
|
+
class ArgumentRequiredError < WikianGetError; end
|
4
|
+
|
5
|
+
class Search < Subcommand
|
6
|
+
def initialize(args)
|
7
|
+
super
|
8
|
+
|
9
|
+
@output_file = yaml['api']['srsearch'].first
|
10
|
+
|
11
|
+
@params.merge!('format' => Wikian::RESPONSE_FORMAT)
|
12
|
+
|
13
|
+
@query = @params.to_query
|
14
|
+
|
15
|
+
@api_url = URI("https://#{yaml['meta']['site']}/w/api.php?#{query}")
|
16
|
+
rescue => e
|
17
|
+
puts "#{e.class} #{e.message} in #{__FILE__}"
|
18
|
+
exit
|
19
|
+
end
|
20
|
+
|
21
|
+
def template
|
22
|
+
<<~eos
|
23
|
+
# Get last 5 revisions of the Main Page.
|
24
|
+
meta:
|
25
|
+
site: en.wikipedia.org
|
26
|
+
headers:
|
27
|
+
user-agent: Wikian
|
28
|
+
api:
|
29
|
+
action:
|
30
|
+
- query
|
31
|
+
list:
|
32
|
+
- search
|
33
|
+
srsearch:
|
34
|
+
- Craig Noone
|
35
|
+
format:
|
36
|
+
- json
|
37
|
+
eos
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
#!/usr/bin/env -S ruby -W0
|
2
|
+
class Wikian
|
3
|
+
# class to be inherited by other Wikian classes
|
4
|
+
class Subcommand
|
5
|
+
attr_accessor :args, :res, :yaml, :query, :title, :api_url, :debug, :output_file
|
6
|
+
|
7
|
+
def initialize(args)
|
8
|
+
@args = args
|
9
|
+
|
10
|
+
if args.have?(%w(-t --template))
|
11
|
+
puts "Creating template #{Wikian::CONFIG_FILE}"
|
12
|
+
make_template
|
13
|
+
exit
|
14
|
+
end
|
15
|
+
|
16
|
+
@debug = (args & %w(-d --debug)).length > 0 ? true : false
|
17
|
+
|
18
|
+
@yaml=YAML.load(File.open(Wikian::CONFIG_FILE))
|
19
|
+
|
20
|
+
# some params like 'titles' can contain multiple entries joined by '|'. More info in Wikipedia API docs
|
21
|
+
@params = Hash[yaml['api'].keys.zip(yaml['api'].values.map{|arr| arr.join("|")})]
|
22
|
+
end
|
23
|
+
|
24
|
+
def make_template
|
25
|
+
if File.exist?(CONFIG_FILE)
|
26
|
+
puts "Overwrite existing '#{CONFIG_FILE}'? [yn]"
|
27
|
+
answer = STDIN.gets.chomp
|
28
|
+
(puts 'Bye'; exit) if answer != 'y'
|
29
|
+
end
|
30
|
+
|
31
|
+
File.open(CONFIG_FILE, 'w') do |f|
|
32
|
+
f.write template
|
33
|
+
end
|
34
|
+
exit
|
35
|
+
end
|
36
|
+
|
37
|
+
# HTTP response file name. Its extension depends on the 'content-type' header
|
38
|
+
def response_file
|
39
|
+
output_file + '.' + res['content-type'].split('/').last.sub(/;.*/,'')
|
40
|
+
end
|
41
|
+
|
42
|
+
# write response in to `response_file`
|
43
|
+
def write_response
|
44
|
+
STDERR.puts "Writing to #{response_file}"
|
45
|
+
File.open(response_file, 'w') do |f|
|
46
|
+
f.puts prettify(res.body)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def doit
|
51
|
+
puts api_url if debug
|
52
|
+
|
53
|
+
req = Net::HTTP::Get.new(api_url, yaml['meta']['headers'])
|
54
|
+
|
55
|
+
http = Net::HTTP.new(api_url.host, api_url.port)
|
56
|
+
|
57
|
+
http.use_ssl = true
|
58
|
+
|
59
|
+
@res=http.request(req)
|
60
|
+
|
61
|
+
write_response
|
62
|
+
rescue => e
|
63
|
+
puts "#{e.class} #{e.message} in #{__FILE__}"
|
64
|
+
exit
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
# if response is JSON prettify it, otherwise return it unchanged
|
70
|
+
def prettify(str)
|
71
|
+
res['content-type'].match?('json') ? JSON.pretty_generate(JSON.parse(str)) : str
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/wikian/version.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
VERSION = "0.1.
|
1
|
+
class Wikian
|
2
|
+
VERSION = "0.1.5"
|
3
3
|
end
|
metadata
CHANGED
@@ -1,19 +1,20 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wikian
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.5
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- sergioro
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-09-
|
11
|
+
date: 2020-09-11 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: Get and edit wikipedia articles
|
14
14
|
email:
|
15
15
|
- yo@sergioro.com
|
16
16
|
executables:
|
17
|
+
- wi
|
17
18
|
- wikian
|
18
19
|
extensions: []
|
19
20
|
extra_rdoc_files: []
|
@@ -21,13 +22,20 @@ files:
|
|
21
22
|
- ".gitignore"
|
22
23
|
- ".travis.yml"
|
23
24
|
- Gemfile
|
25
|
+
- Gemfile.lock
|
24
26
|
- LICENSE.txt
|
25
27
|
- README.md
|
26
28
|
- Rakefile
|
27
29
|
- bin/console
|
28
30
|
- bin/setup
|
31
|
+
- exe/wi
|
29
32
|
- exe/wikian
|
33
|
+
- lib/.gitignore
|
30
34
|
- lib/wikian.rb
|
35
|
+
- lib/wikian/get.rb
|
36
|
+
- lib/wikian/post.rb
|
37
|
+
- lib/wikian/search.rb
|
38
|
+
- lib/wikian/subcommand.rb
|
31
39
|
- lib/wikian/version.rb
|
32
40
|
- wikian.gemspec
|
33
41
|
homepage:
|