artaius 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,2 +1,3 @@
1
- .rake_tasks~
1
+ *~
2
+ *.gem
2
3
  Gemfile.lock
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
  ================
3
3
 
4
4
  * [https://github.com/kyrylo/artaius/][rkag]
5
+ * [Wiki][wiki]
5
6
 
6
7
  Description
7
8
  -----------
@@ -9,6 +10,11 @@ Description
9
10
  Artaius is a [King Arthur's Gold][kag] (KAG) IRC bot. Currently it's not
10
11
  suitable for a public use. Artaius dwells at #kag2d.ru@irc.quakenet.org.
11
12
 
13
+ Credits
14
+ -------
15
+
16
+ * Thanks to [dnmr][dnmr] for testing the bot
17
+
12
18
  License
13
19
  -------
14
20
 
@@ -17,3 +23,5 @@ The project uses Zlib License. See LICENSE file for more information.
17
23
  [logo]: http://img-fotki.yandex.ru/get/6210/98991937.9/0_7735e_6d44a25d_orig "Artaius logo"
18
24
  [rkag]: https://github.com/kyrylo/artaius/ "Home page"
19
25
  [kag]: http://kag2d.com/
26
+ [dnmr]: https://forum.kag2d.com/members/dnmr.23/
27
+ [wiki]: https://github.com/kyrylo/artaius/wiki
@@ -20,8 +20,9 @@ Gem::Specification.new do |s|
20
20
  s.add_runtime_dependency 'cinch', '~>2.0'
21
21
  s.add_runtime_dependency 'kag', '0.0.1'
22
22
  s.add_runtime_dependency 'r18n-desktop', '>=0.4.14'
23
- s.add_runtime_dependency 'sequel', '>=3.34.1'
24
- s.add_runtime_dependency 'sqlite3', '>=1.3.6'
23
+ s.add_runtime_dependency 'sequel', '>=3.34.1'
24
+ s.add_runtime_dependency 'sqlite3', '>=1.3.6'
25
+ s.add_runtime_dependency 'mechanize', '>=2.4'
25
26
 
26
27
  s.add_development_dependency 'rake'
27
28
  s.add_development_dependency 'minitest', '>=2.12.1'
@@ -38,3 +38,33 @@ archivarius:
38
38
  success: "Yay, registration complete! Enjoy KAG ;-)"
39
39
  m:
40
40
  reg: "reg"
41
+
42
+ scraper:
43
+ broken_link: "Uh oh! The link you just posted is broken."
44
+ title: "Title: %1"
45
+ h:
46
+ kag_forum: "KAG's forum: %1"
47
+
48
+ news_fetcher:
49
+ news: "News! %1 writes: \"%2\" → %3"
50
+ latest_news: "On %1 %2 wrote a post: \"%3\"."
51
+ read_post: "Read post: %1"
52
+ m:
53
+ news: "news"
54
+
55
+ informator:
56
+ kag_site: "https://www.kag2d.com/"
57
+ kag_wiki: "https://wiki.kag2d.com/"
58
+ kag_forum: "https://forum.kag2d.com/"
59
+ kag_manual: "https://kag2d.com/en/manual/"
60
+ kag_blog: "http://devlog.kag2d.com/"
61
+ kag_download: "https://kag2d.com/en/download/"
62
+ kag_bug_tracker: "https://bugs.kag2d.com/"
63
+ m:
64
+ site: "site"
65
+ wiki: "wiki"
66
+ forum: "forums"
67
+ manual: "manual"
68
+ blog: "blog"
69
+ download: "download"
70
+ bug_tracker: "bugs"
@@ -39,9 +39,39 @@ mixer:
39
39
  slots: "слоты"
40
40
 
41
41
  archivarius:
42
- exists: "%1, вы уже привязали свой аккаунт в КАГ-е к вашему логину в ИРЦ (%2)."
42
+ exists: "%1, вы уже привязали свой аккаунт в КАГ’е к вашему логину в ИРЦ (%2)."
43
43
  not_found: "Игрок %1 не существует. Опечатались?"
44
- authname_required: "Чтобы связать ваш аккаунт в КАГ-е и ИРЦ логин, вы должны авторизироваться на этом сервере или зарегистрировать свой ник."
45
- success: "Ура, регистрация завершена! Наслаждайтеь КАГ-ом ;-)"
44
+ authname_required: "Чтобы связать ваш аккаунт в КАГ’е и ИРЦ логин, вы должны авторизироваться на этом сервере или зарегистрировать свой ник."
45
+ success: "Ура, регистрация завершена! Наслаждайтеь КАГ’ом ;-)"
46
46
  m:
47
47
  reg: "регь"
48
+
49
+ scraper:
50
+ broken_link: "Опаньки! А вот эта ссылка не работает."
51
+ title: "Заголовок: %1"
52
+ h:
53
+ kag_forum: "Форум КАГ’а: %1"
54
+
55
+ news_fetcher:
56
+ news: "Новость! %1 пишет: \"%2\" → %3"
57
+ latest_news: "%1 %2 написал запись: \"%3\"."
58
+ read_post: "Читать запись: %1"
59
+ m:
60
+ news: "новости"
61
+
62
+ informator:
63
+ kag_site: "https://www.kag2d.com/"
64
+ kag_wiki: "https://wiki.kag2d.com/"
65
+ kag_forum: "https://forum.kag2d.com/"
66
+ kag_manual: "https://kag2d.com/en/manual/"
67
+ kag_blog: "http://devlog.kag2d.com/"
68
+ kag_download: "https://kag2d.com/en/download/"
69
+ kag_bug_tracker: "https://bugs.kag2d.com/"
70
+ m:
71
+ site: "сайт"
72
+ wiki: "вики"
73
+ forum: "форум"
74
+ manual: "справочник"
75
+ blog: "блог"
76
+ download: "скачать"
77
+ bug_tracker: "баги"
@@ -0,0 +1,25 @@
1
+ # Create initial schema for the table of news (tiles) from KAG development blog.
2
+ #
3
+ # +--------------+----------------------------+
4
+ # | Field | Description |
5
+ # +--------------+----------------------------+
6
+ # | id | News id number. |
7
+ # | title | News title. |
8
+ # | date | Date, when news were added.|
9
+ # | author | Author of the news. |
10
+ # | link | Link to post on the web. |
11
+ # +--------------+----------------------------+
12
+ #
13
+ Sequel.migration do
14
+ change do
15
+ create_table :news do
16
+ primary_key :id
17
+ String :title, :size => 255, :null => false
18
+ DateTime :date
19
+ String :author, :size => 32, :null => false
20
+ String :link, :null => false
21
+ DateTime :created_at
22
+ DateTime :updated_at
23
+ end
24
+ end
25
+ end
@@ -10,7 +10,13 @@ require_relative 'artaius/version'
10
10
 
11
11
  require_relative 'artaius/database'
12
12
  require_relative 'artaius/models/player'
13
+ require_relative 'artaius/models/news'
13
14
 
14
15
  require_relative 'artaius/plugins/identify'
15
16
  require_relative 'artaius/plugins/mixer'
16
17
  require_relative 'artaius/plugins/archivarius'
18
+ require_relative 'artaius/plugins/autovoicer'
19
+ require_relative 'artaius/plugins/autoopper'
20
+ require_relative 'artaius/plugins/scraper'
21
+ require_relative 'artaius/plugins/news_fetcher'
22
+ require_relative 'artaius/plugins/informator'
@@ -34,7 +34,12 @@ module Artaius
34
34
  c.plugins.plugins = [
35
35
  Artaius::Plugins::Identify,
36
36
  Artaius::Plugins::Mixer,
37
- Artaius::Plugins::Archivarius
37
+ Artaius::Plugins::Archivarius,
38
+ Artaius::Plugins::Autovoicer,
39
+ Artaius::Plugins::Autoopper,
40
+ Artaius::Plugins::Scraper,
41
+ Artaius::Plugins::NewsFetcher,
42
+ Artaius::Plugins::Informator
38
43
  ]
39
44
 
40
45
  # Set up plugins to be used.
@@ -0,0 +1,5 @@
1
+ module Artaius
2
+ class News < Sequel::Model(:news)
3
+ plugin :timestamps, :update_on_create => true
4
+ end
5
+ end
@@ -2,15 +2,5 @@ module Artaius
2
2
  # Internal: Represents KAG player.
3
3
  class Player < Sequel::Model(:players)
4
4
  plugin :timestamps, :update_on_create => true
5
-
6
- # Internal: Check database for given authname.
7
- #
8
- # irc_authname - The String, represents IRC authname of the player.
9
- #
10
- # Returns true if the given authname is in database or false otherwise.
11
- def self.exists?(irc_authname)
12
- filter(:irc_authname => irc_authname).select(:irc_authname).any?
13
- end
14
-
15
5
  end
16
6
  end
@@ -50,11 +50,13 @@ module Artaius
50
50
 
51
51
  protected
52
52
 
53
- # Internal: Ask database for whether the IRC authname is in it or not.
53
+ # Internal: Check database for given authname.
54
54
  #
55
- # Returns true, if the IRC authname is there of false otherwise.
55
+ # irc_authname - The String, represents IRC authname of the player.
56
+ #
57
+ # Returns true if the given authname is in database or false otherwise.
56
58
  def already_exists?(irc_authname)
57
- Player.exists?(irc_authname)
59
+ Player.filter(:irc_authname => irc_authname).select(:irc_authname).any?
58
60
  end
59
61
 
60
62
  end
@@ -0,0 +1,22 @@
1
+ module Artaius
2
+ module Plugins
3
+ class Autoopper
4
+ # Gives an op for everyone, who has a Guard role in King Arthur's Gold
5
+ # and registered.
6
+ include Cinch::Plugin
7
+
8
+ listen_to :join
9
+
10
+ def listen(m)
11
+ return if m.user.nick == bot.nick
12
+
13
+ m.channel.op(m.user) if guard?(m.user.authname)
14
+ end
15
+
16
+ def guard?(irc_authname)
17
+ Player.filter(:irc_authname => irc_authname).select_map(:role).first == 2
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ module Artaius
2
+ module Plugins
3
+ # Gives a voice for everyone, who has a premium account in King Arthur's
4
+ # Gold and registered.
5
+ class Autovoicer
6
+ include Cinch::Plugin
7
+
8
+ listen_to :join
9
+
10
+ def listen(m)
11
+ return if m.user.nick == bot.nick
12
+
13
+ m.channel.voice(m.user) if premium?(m.user.authname)
14
+ end
15
+
16
+ def premium?(irc_authname)
17
+ Player.filter(:irc_authname => irc_authname).select_map(:premium).first
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,31 @@
1
+ module Artaius
2
+ module Plugins
3
+ # Provides useful links to KAG resources and maybe some other related
4
+ # information.
5
+ class Informator
6
+ include Cinch::Plugin
7
+
8
+ set react_on: :channel
9
+
10
+ methods = [:site, :wiki, :forum, :manual, :blog, :download, :bug_tracker]
11
+
12
+ methods.each do |method|
13
+ pattern = I18n.informator.m.send(method)
14
+ instance_eval <<-EVAL
15
+ match /#{pattern}$/,
16
+ method: :#{method},
17
+ use_suffix: false
18
+ EVAL
19
+ end
20
+
21
+ methods.each do |method|
22
+ class_eval <<-EVAL
23
+ def #{method}(m)
24
+ m.reply I18n.informator.kag_#{method}
25
+ end
26
+ EVAL
27
+ end
28
+
29
+ end
30
+ end
31
+ end
@@ -35,7 +35,6 @@ module Artaius
35
35
  # seconds).
36
36
  PENDING_DELAY = 300
37
37
 
38
-
39
38
  set react_on: :channel
40
39
 
41
40
  match /#{I18n.mixer.m.game}(\s([2-9]|[1-9][0-9]))?$/,
@@ -50,7 +49,7 @@ module Artaius
50
49
  #
51
50
  # Returns nothing.
52
51
  def start_game(m, limit)
53
- return if @game or !Player.exists?(m.user.authname)
52
+ return if @game or !already_exists?(m.user.authname)
54
53
 
55
54
  @limit = if limit && !limit.empty?
56
55
  limit.to_i
@@ -73,7 +72,7 @@ module Artaius
73
72
  #
74
73
  # Returns nothing.
75
74
  def add_player(m)
76
- return if !@game or !Player.exists?(m.user.authname)
75
+ return if !@game or !already_exists?(m.user.authname)
77
76
 
78
77
  unless @game.players.map(&:irc_authname).include?(m.user.authname)
79
78
  @game.players << create_gamer(m)
@@ -86,15 +85,16 @@ module Artaius
86
85
  m.reply I18n.mixer.players(show_players)
87
86
  m.reply I18n.mixer.need_players(need_players)
88
87
  end
89
-
90
88
  end
91
89
 
92
90
  @timer.stop if @timer
93
91
 
94
- @timer = Timer(PENDING_DELAY, :shots => 1) do
92
+ @timer ||= Timer(PENDING_DELAY, shots: 1, start_automatically: false) do
95
93
  @game = nil
96
94
  Channel(m.channel.name).send I18n.mixer.game_cancelled
97
95
  end
96
+
97
+ @timer.start
98
98
  end
99
99
 
100
100
  match /#{I18n.mixer.m.cancel}$/,
@@ -330,6 +330,15 @@ module Artaius
330
330
  )
331
331
  end
332
332
 
333
+ # Internal: Check database for given authname.
334
+ #
335
+ # irc_authname - The String, represents IRC authname of the player.
336
+ #
337
+ # Returns true if the given authname is in database or false otherwise.
338
+ def already_exists?(irc_authname)
339
+ Player.filter(:irc_authname => irc_authname).select(:irc_authname).any?
340
+ end
341
+
333
342
  end
334
343
  end
335
344
  end
@@ -0,0 +1,92 @@
1
+ require 'rss'
2
+ require 'open-uri'
3
+
4
+ module Artaius
5
+ module Plugins
6
+ class NewsFetcher
7
+ include Cinch::Plugin
8
+
9
+ # Internal: RSS address of KAG development blog.
10
+ KAGDEV_RSS = 'http://devlog.kag2d.com/rss'
11
+
12
+ # Internal: Time lapse between checking RSS feed for new posts.
13
+ CHECK_TIME_LAPSE = 1800
14
+
15
+ set react_on: :channel
16
+
17
+ timer CHECK_TIME_LAPSE,
18
+ method: :send_news
19
+
20
+ # Internal: Send latest news on channels.
21
+ #
22
+ # Returns nothing.
23
+ def send_news
24
+ feed = RSS::Parser.parse open(KAGDEV_RSS).read
25
+ last_post_title = feed.channel.item.title
26
+
27
+ # Check, whether the latest title of the post at KAG development
28
+ # blog is still the same, as it was, when the fetcher checked it last
29
+ # time.
30
+ return if unchanged?(last_post_title)
31
+
32
+ item = feed.channel.item
33
+
34
+ last_post_date = item.pubDate
35
+ last_post_author = item.dc_creator
36
+ last_post_link = item.link
37
+
38
+ News.create(
39
+ :title => last_post_title,
40
+ :date => last_post_date,
41
+ :author => last_post_author,
42
+ :link => last_post_link
43
+ )
44
+
45
+ real_author = reveal_author(last_post_author)
46
+ short_link = open("http://clck.ru/--?url=#{last_post_link}").read
47
+
48
+ Bot::CHANNELS.each do |chan|
49
+ Channel(chan).send I18n.news_fetcher.news(real_author, last_post_title, short_link)
50
+ end
51
+ rescue SocketError
52
+ nil
53
+ end
54
+
55
+ match /#{I18n.news_fetcher.m.news}$/,
56
+ method: :latest_news,
57
+ use_suffix: false
58
+
59
+ # Internal: Send on the channel information about the latest post at KAG
60
+ # development blog and give a link to it.
61
+ #
62
+ # Returns nothing.
63
+ def latest_news(m)
64
+ news = News.order(:date).last
65
+
66
+ author = reveal_author(news.author)
67
+ date = I18n.localize(news.date, :full)
68
+
69
+ m.reply I18n.news_fetcher.latest_news(date, author, news.title)
70
+ m.reply I18n.news_fetcher.read_post(news.link)
71
+ end
72
+
73
+ protected
74
+
75
+ def unchanged?(title)
76
+ last = News.select(:title).order(:date).last
77
+ last and last.title == title
78
+ end
79
+
80
+ # Internal: Transform aliases of a blog author to his/her real nickname.
81
+ #
82
+ # Returns the transformed String.
83
+ def reveal_author(nick)
84
+ case nick
85
+ when 'lddev' then 'MM'
86
+ when '1bardesign' then 'Geti'
87
+ end
88
+ end
89
+
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,43 @@
1
+ require 'mechanize'
2
+
3
+ module Artaius
4
+ module Plugins
5
+ # Scraps web pages, that have <title> attribute.
6
+ class Scraper
7
+ include Cinch::Plugin
8
+
9
+ listen_to :channel,
10
+ method: :scrap_links
11
+
12
+ def scrap_links(m)
13
+ unless @agent
14
+ @agent = Mechanize.new
15
+ @agent.user_agent_alias = 'Linux Firefox'
16
+ end
17
+
18
+ URI.extract(m.message, %w[http https]) do |link|
19
+ begin
20
+ page = @agent.get(link)
21
+ uri = URI.parse(link)
22
+ rescue Mechanize::ResponseCodeError
23
+ m.reply I18n.scraper.broken_link and next
24
+ end
25
+
26
+ title = page.title.gsub(/[\x00-\x1f]*/, "").gsub(/[ ]{2,}/, " ").strip rescue nil
27
+
28
+ if title
29
+ case uri.host
30
+ when 'forum.kag2d.com'
31
+ pattern = / \| Page \d{1,4} \| King Arthur's Gold Forum$/
32
+ title.sub!(pattern, '')
33
+ m.reply I18n.scraper.h.kag_forum(title)
34
+ else
35
+ m.reply I18n.scraper.title(title)
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ end
42
+ end
43
+ end
@@ -1,3 +1,3 @@
1
1
  module Artaius
2
- VERSION = '0.2.0'
2
+ VERSION = '0.2.1'
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: artaius
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-05-10 00:00:00.000000000 Z
12
+ date: 2012-05-14 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: cinch
@@ -91,6 +91,22 @@ dependencies:
91
91
  - - ! '>='
92
92
  - !ruby/object:Gem::Version
93
93
  version: 1.3.6
94
+ - !ruby/object:Gem::Dependency
95
+ name: mechanize
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ! '>='
100
+ - !ruby/object:Gem::Version
101
+ version: '2.4'
102
+ type: :runtime
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ! '>='
108
+ - !ruby/object:Gem::Version
109
+ version: '2.4'
94
110
  - !ruby/object:Gem::Dependency
95
111
  name: rake
96
112
  requirement: !ruby/object:Gem::Requirement
@@ -160,13 +176,20 @@ files:
160
176
  - config/plugins/.gitignore
161
177
  - db/.gitignore
162
178
  - db/migrations/001_create_players.rb
179
+ - db/migrations/002_create_news_table.rb
163
180
  - lib/artaius.rb
164
181
  - lib/artaius/bot.rb
165
182
  - lib/artaius/database.rb
183
+ - lib/artaius/models/news.rb
166
184
  - lib/artaius/models/player.rb
167
185
  - lib/artaius/plugins/archivarius.rb
186
+ - lib/artaius/plugins/autoopper.rb
187
+ - lib/artaius/plugins/autovoicer.rb
168
188
  - lib/artaius/plugins/identify.rb
189
+ - lib/artaius/plugins/informator.rb
169
190
  - lib/artaius/plugins/mixer.rb
191
+ - lib/artaius/plugins/news_fetcher.rb
192
+ - lib/artaius/plugins/scraper.rb
170
193
  - lib/artaius/version.rb
171
194
  - spec/lib/artaius/bot_spec.rb
172
195
  - spec/lib/artaius/plugins/archivarius_spec.rb