sunflower 0.2

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.
data/LICENSE ADDED
@@ -0,0 +1,4 @@
1
+ Sunflower is licensed under CC-BY-SA 3.0.
2
+
3
+ Author: matma.rex@gmail.com
4
+
data/README ADDED
@@ -0,0 +1,21 @@
1
+ Version: 0.2 alpha
2
+
3
+ >>> English:
4
+
5
+
6
+
7
+ >>> Polski:
8
+
9
+ ==============================
10
+ Nie edytuj żadnych plików .rb Notatnikiem - na początku plików zapisanych w Unikodzie dodaje on tzw. BOM, który powoduje wywalanie się Rubiego. Edytuj jest WordPadem lub, najlepiej, jakimś edytorem z kolorowaniem składni (np. Notepad++).
11
+ ==============================
12
+ Aby bot zawsze automatycznie się logował bez konieczności podawania hasła w pliku .rb, utwórz plik o nazwie "userdata" (bez rozszerzenia) i w treści wpisz (oddzielając enterem) kolejno URL do wiki, login i hasło. Wtedy Sunflower.new() i s.login() można wywoływać bez parametrów - z pustymi nawiasami.
13
+ ==============================
14
+
15
+ sunflower-core.rb to podstawowy plik z ramą bota. sunflower-commontasks.rb zawiera parę funkcji, które ułatwiający wykonywanie różnych zadań.
16
+
17
+ example-bot.rb to przykład bota; jest to niemal najkrótszy kod, który cokolwiek może zrobić, ten pobiera stronę, dodaje do niej "test" i zapisuje ją.
18
+
19
+ use-easy-bot.rb to skrypt pozwalający w zamierzeniu na uzycie bota laikom. Pobiera listę stron z pliku (należy ją stworzyć np. AWB i zapisać jako "Plaintext list" - tytuły stron oddzielone enterami), po czym w każdej wykonuje określone zmiany i zapisuje. Dokładniejszy opis jest w samym pliku, pamiętaj też, żeby zmienić oznaczone fragmenty. Komentarze zaczynają się od znaku "#".
20
+
21
+ W /scripts jest parę moich skryptów, niektóre moga się przydać, niektóre nie albo w ogóle nie działają.
@@ -0,0 +1,68 @@
1
+ require 'sunflower'
2
+
3
+
4
+ path = Sunflower.path
5
+
6
+
7
+
8
+ puts "Welcome to Sunflower's setup script."
9
+ puts ""
10
+
11
+ puts "If you set your home wiki and userdata, you will not have to enter it in every script."
12
+ puts "Your userdata will be saved (IN PLAINTEXT!) in this file:"
13
+ puts " #{path}"
14
+
15
+ puts ""
16
+
17
+ print "Enter your home wiki (for ex. en.wikipedia.org): "
18
+ home=gets.strip
19
+
20
+ print "Enter your bot's nick on the home wiki: "
21
+ nick=gets.strip
22
+
23
+ print "Enter your bot's password on home wiki (WILL BE SHOWN IN PLAINTEXT): "
24
+ pass=gets.strip
25
+
26
+ puts ""
27
+
28
+ worked = true
29
+ puts "Trying to connect with the data provided..."
30
+ begin
31
+ s=Sunflower.new home
32
+ s.login nick, pass
33
+ rescue
34
+ worked = false
35
+ error = $!.message
36
+ end
37
+
38
+ if worked
39
+ puts "It seems to work!"
40
+ puts "WARNING! USER DOES NOT HAVE BOT RIGHTS!" if !s.isBot?
41
+ else
42
+ puts "Whoops, it didn't work. The error message is:"
43
+ puts error
44
+ end
45
+
46
+ save = worked
47
+
48
+ if !worked
49
+ begin
50
+ print "Do you want to save the data anyway? [yn] "
51
+ ans = gets.strip
52
+ end until ans=~/[yn]/i
53
+
54
+ save = (ans.downcase=='y')
55
+ end
56
+
57
+ if save
58
+ f=File.open(path, "w")
59
+ f.write [home, nick, pass].join "\n"
60
+ f.close
61
+
62
+ puts "User data has been saved. Remember that your password is saved in plaintext!"
63
+ puts ""
64
+
65
+ puts "If you ever want to erase your login data, simply delete the file."
66
+ else
67
+ puts "User data has not been saved. You can run this setup again anytime."
68
+ end
data/example-bot.rb ADDED
@@ -0,0 +1,12 @@
1
+ # This is the most basic bot possible.
2
+
3
+ require 'sunflower-commontasks.rb'
4
+
5
+ s=Sunflower.new
6
+ s.login
7
+
8
+ $summary='Sunflower: test'
9
+
10
+ p=Page.get('Test')
11
+ p.write p.text+"\n\ntest"
12
+ p.save
@@ -0,0 +1,251 @@
1
+ # coding: utf-8
2
+ # extends Page with some methods letting easily perform common tasks
3
+
4
+ class Page
5
+ def execute commands
6
+ # executes methods on self
7
+ # "commands" is array of arrays
8
+ # page.execute([
9
+ # [:replace, 'something', 'whatever'],
10
+ # [:append, 'some things']
11
+ # ])
12
+ # equals to
13
+ # page.replace('something', 'whatever')
14
+ # page.append('some things')
15
+
16
+ # allowed modifiers:
17
+ # r, required
18
+ # oi:module, only-if:module
19
+ # !oi:module, only-if-not:module
20
+ # s:append to summary, summary:append to summary
21
+ originalText = self.text.dup
22
+
23
+ commands.each do |cmd|
24
+ f=cmd.shift
25
+ if f.class==Array
26
+ methodName=f.shift
27
+ modifiers=f.map{|i|
28
+ i+=':' if !i.include? ':'
29
+ i=i.split(':',-1)
30
+ i[0]=i[0].downcase.gsub(/[^a-z!]/,'')
31
+
32
+ i[0]='r' if i[0]=='required'
33
+ i[0]='oi' if i[0]=='onlyif'
34
+ i[0]='!oi' if i[0]=='onlyifnot'
35
+ i[0]='s' if i[0]=='summary'
36
+
37
+ type=i.shift
38
+ i=i.join(':')
39
+
40
+ [type,i]
41
+ }
42
+ modifiers=Hash[*(modifiers.flatten)]
43
+ else
44
+ methodName=f
45
+ modifiers={}
46
+ end
47
+
48
+ if modifiers['oi']
49
+ if !@modulesExecd.index(modifiers['oi'].strip)
50
+ next #skip this command
51
+ end
52
+ end
53
+ if modifiers['!oi']
54
+ if @modulesExecd.index(modifiers['oi'].strip)
55
+ next #skip this command
56
+ end
57
+ end
58
+
59
+ oldText=self.text
60
+ self.method(methodName).call(*cmd)
61
+ newText=self.text
62
+
63
+ @modulesExecd<<methodName if oldText!=newText
64
+
65
+ if modifiers['s'] && oldText!=newText
66
+ @summaryAppend<<modifiers['s'].strip
67
+ end
68
+
69
+ if modifiers['r'] && oldText==newText
70
+ self.text = originalText
71
+ break #reset text and stop executing commands
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+
78
+ def replace from, to, once=false
79
+ # replaces "from" with "to" in page text
80
+ # "from" may be regex
81
+ self.text = self.text.send( (once ? 'sub' : 'gsub'), from, to )
82
+ end
83
+ def gsub from, to
84
+ self.replace from, to
85
+ end
86
+ def sub from, to
87
+ self.replace from, to, true
88
+ end
89
+
90
+ def append txt, newlines=2
91
+ # appends newlines and text
92
+ # by default - 2 newlines
93
+ self.text = self.text.rstrip + ("\n"*newlines) + txt
94
+ end
95
+
96
+ def prepend txt, newlines=2
97
+ # prepends text and newlines
98
+ # by default - 2 newlines
99
+ self.text = txt + ("\n"*newlines) + self.text.lstrip
100
+ end
101
+
102
+ def code_cleanup
103
+ # simple, safe code cleanup
104
+ # use $alwaysDoCodeCleanup=true to do it automatically just before saving page
105
+ # based on Nux's cleaner: http://pl.wikipedia.org/wiki/Wikipedysta:Nux/wp_sk.js
106
+ str=self.text.gsub(/\r\n/,"\n")
107
+
108
+ str.gsub!(/\{\{\s*([^|{}]+ |uni|)stub2?(\|[^{}]+)?\}\}/i){
109
+ if $1=='sekcja '
110
+ '{{sekcja stub}}'
111
+ else
112
+ '{{stub}}'
113
+ end
114
+ }
115
+ str.gsub!(/\{\{\{(?:poprzednik|następca|pop|nast|lata|info|lang)\|(.+?)\}\}\}/i,'\1')
116
+ str.gsub!(/(={1,5})\s*Przypisy\s*\1\s*<references\s?\/>/){
117
+ if $1=='=' || $1=='=='
118
+ '{{Przypisy}}'
119
+ else
120
+ '{{Przypisy|stopień= '+$1+'}}'
121
+ end
122
+ }
123
+
124
+ # sklejanie skrótów linkowych
125
+ str.gsub!(/m\.? ?\[\[n\.? ?p\.? ?m\.?\]\]/, 'm [[n.p.m.]]');
126
+
127
+ # korekty dat - niepotrzebny przecinek
128
+ str.gsub!(/(\[\[[0-9]+ (stycznia|lutego|marca|kwietnia|maja|czerwca|lipca|sierpnia|września|października|listopada|grudnia)\]\]), (\[\[[0-9]{4}\]\])/i, '\1 \3');
129
+
130
+ # linkowanie do wieków
131
+ str.gsub!(/\[\[([XVI]{1,5}) [wW]\.?\]\]/, '[[\1 wiek|\1 w.]]');
132
+ str.gsub!(/\[\[([XVI]{1,5}) [wW]\.?\|/, '[[\1 wiek|');
133
+ str.gsub!(/\[\[(III|II|IV|VIII|VII|VI|IX|XIII|XII|XI|XIV|XV|XVIII|XVII|XVI|XIX|XXI|XX)\]\]/, '[[\1 wiek|\1]]');
134
+ str.gsub!(/\[\[(III|II|IV|VIII|VII|VI|IX|XIII|XII|XI|XIV|XV|XVIII|XVII|XVI|XIX|XXI|XX)\|/, '[[\1 wiek|');
135
+
136
+ # rozwijanie typowych linków
137
+ str.gsub!(/\[\[ang\.\]\]/, '[[język angielski|ang.]]');
138
+ str.gsub!(/\[\[cz\.\]\]/, '[[język czeski|cz.]]');
139
+ str.gsub!(/\[\[fr\.\]\]/, '[[język francuski|fr.]]');
140
+ str.gsub!(/\[\[łac\.\]\]/, '[[łacina|łac.]]');
141
+ str.gsub!(/\[\[niem\.\]\]/, '[[język niemiecki|niem.]]');
142
+ str.gsub!(/\[\[pol\.\]\]/, '[[język polski|pol.]]');
143
+ str.gsub!(/\[\[pl\.\]\]/, '[[język polski|pol.]]');
144
+ str.gsub!(/\[\[ros\.\]\]/, '[[język rosyjski|ros.]]');
145
+ str.gsub!(/\[\[(((G|g)iga|(M|m)ega|(K|k)ilo)herc|[GMk]Hz)\|/, '[[herc|');
146
+
147
+ # unifikacja nagłówkowa
148
+ str.gsub!(/[ \n\t]*\n'''? *(Zobacz|Patrz) (też|także):* *'''?[ \n\t]*/i, "\n\n== Zobacz też ==\n");
149
+ str.gsub!(/[ \n\t]*\n(=+) *(Zobacz|Patrz) (też|także):* *=+[ \n\t]*/i, "\n\n\\1 Zobacz też \\1\n");
150
+ str.gsub!(/[ \n\t]*\n'''? *((Zewnętrzn[ey] )?(Linki?|Łącza|Stron[ay]|Zobacz w (internecie|sieci))( zewn[eę]trzn[aey])?):* *'''?[ \n\t]*/i, "\n\n== Linki zewnętrzne ==\n");
151
+ str.gsub!(/[ \n\t]*\n(=+) *((Zewnętrzn[ey] )?(Linki?|Łącza|Stron[ay]|Zobacz w (internecie|sieci))( zewn[eę]trzn[aey])?):* *=+[ \n\t]*/i, "\n\n\\1 Linki zewnętrzne \\1\n");
152
+
153
+ # nagłówki
154
+ str.gsub!(/(^|\n)(=+) *([^=\n]*[^ :=\n])[ :]*=/, '\1\2 \3 ='); # =a= > = a =, =a:= > = a =
155
+ str.gsub!(/(^|\n)(=+[^=\n]+=+)[\n]{2,}/, "\\1\\2\n"); # jeden \n
156
+
157
+ # listy ze spacjami
158
+ str.gsub!(/(\n[#*:;]+)([^ \t\n#*:;{])/, '\1 \2');
159
+
160
+ # poprawa nazw przestrzeni i drobne okoliczne
161
+ str.gsub!(/\[\[(:?) *(image|grafika|file|plik) *: *([^ ])/i){'[['+$1+'Plik:'+$3.upcase}
162
+ str.gsub!(/\[\[(:?) *(category|kategoria) *: *([^ ])/i){'[['+$1+'Kategoria:'+$3.upcase}
163
+ str.gsub!(/\[\[ *(:?) *(template|szablon) *: *([^ ])/i){'[['+'Szablon:'+$3.upcase}
164
+ str.gsub!(/\[\[ *(:?) *(special|specjalna) *: *([^ ])/i){'[['+'Specjalna:'+$3.upcase}
165
+
166
+ 3.times { str.gsub!('{{stub}}{{stub}}', '{{stub}}') }
167
+
168
+ self.text = str
169
+ end
170
+
171
+ def friendly_infobox
172
+ # cleans up infoboxes
173
+ # might make mistakes! use at your own risk!
174
+ def makeFriendly(nazwa,zaw)
175
+ zaw.gsub!(/<!--.+?-->/,'')
176
+ nazwa=nazwa.gsub('_',' ').strip
177
+
178
+ #escapowanie parametrów
179
+ zaw.gsub!(/<<<(#+)>>>/,"<<<#\\1>>>")
180
+ #wewnętrzne szablony
181
+ while zaw=~/\{\{[^}]+\|[^}]+\}\}/
182
+ zaw.gsub!($&,$&.gsub(/\|/,'<<<#>>>'))
183
+ end
184
+ #wewnętrzne linki
185
+ while zaw=~/\[\[[^\]]+\|[^\]]+\]\]/
186
+ zaw.gsub!($&,$&.gsub(/\|/,'<<<#>>>'))
187
+ end
188
+
189
+ zaw.sub!(/\A\s*\|\s*/,'') #usunięcie pierwszego pipe'a
190
+ lines=zaw.split('|')
191
+
192
+ # te tablice przechowują odpowiednio nazwy i wartości kolejnych parametrów
193
+ names=[]
194
+ values=[]
195
+
196
+ for line in lines
197
+ line.gsub!(/<<<#>>>/,'|')
198
+ line.gsub!(/<<<#(#+)>>>/,"<<<\\1>>>") #odescapowanie
199
+
200
+ line=~/\A\s*(.+?)\s*=\s*([\s\S]*?)\s*\Z/
201
+ if $&==nil
202
+ next
203
+ end
204
+ name=$1.strip
205
+ value=$2.strip
206
+
207
+ names<<name
208
+ values<<value
209
+ end
210
+
211
+ zaw=''
212
+ names.each_index{|i|
213
+ zaw+=' | '+names[i]+' = '+values[i]+"\n"
214
+ }
215
+
216
+ # grupowane koordynaty
217
+ zaw.gsub!(/\s*\| minut/, ' | minut')
218
+ zaw.gsub!(/\s*\| sekund/, ' | sekund')
219
+
220
+ return '{{'+nazwa[0,1].upcase+nazwa[1,999]+"\n"+zaw+'}}'+"\n"
221
+ end
222
+
223
+ nstr=''
224
+ while str!=''
225
+ str=~/(\s*)\{\{([^|}]+[ _]infobo[^|}]+|[wW]ładca)((?:[^{}]|[^{}][{}][^{}]|\{\{(?:[^{}]|[^{}][{}][^{}]|\{\{[^{}]+\}\})+\}\})+)\}\}(?:\s*)/
226
+
227
+ spaces=($1!='' ? "\n" : '')
228
+ before=($`==nil ? '' : $`)
229
+ name=$2
230
+ inner=$3
231
+ match=$&
232
+ if match!=nil
233
+ result=makeFriendly(name,inner)
234
+ nstr+=before+spaces+result
235
+ else
236
+ nstr+=str
237
+ break
238
+ end
239
+
240
+ str=str.sub(before+match,'')
241
+ end
242
+
243
+ self.text = nstr
244
+ end
245
+
246
+ def change_category from, to
247
+ from=from.sub(/\A\s*([cC]ategory|[kK]ategoria):/, '').strip
248
+ to=to.sub(/\A\s*([cC]ategory|[kK]ategoria):/, '').strip
249
+ self.text = self.text.gsub!(/\[\[ *(?:[cC]ategory|[kK]ategoria) *: *#{Regexp.escape from} *(\|[^\]]+ *|)\]\]/){'[[Kategoria:'+to+$1.rstrip+']]'}
250
+ end
251
+ end
@@ -0,0 +1,253 @@
1
+ # coding: utf-8
2
+ require 'rest-client'
3
+ require 'json'
4
+ require 'cgi'
5
+
6
+ # Main class. To start working, you have to create new Sunflower:
7
+ # s = Sunflower.new('en.wikipedia.org')
8
+ # And then log in:
9
+ # s.login('Username','password')
10
+ #
11
+ # If you have ran setup, you can just use
12
+ # s = Sunflower.new.login
13
+ #
14
+ # Then you can request data from API using #API method.
15
+ # To log data to file, use #log method (works like puts, append new line if needed) of #log2 (like print).
16
+ # You can use multiple Sunflowers at once, to work on multiple wikis.
17
+ class Sunflower
18
+ # Path to user data file.
19
+ def self.path
20
+ File.join(ENV['HOME'], 'sunflower-userdata')
21
+ end
22
+
23
+ attr_accessor :cookie, :headers, :wikiURL, :warnings, :log
24
+
25
+ # Initialize a new Sunflower working on a wiki with given URL, for ex. "pl.wikipedia.org".
26
+ def initialize url=''
27
+ begin
28
+ r=File.read(Sunflower.path)
29
+ @userdata=r.split(/\r?\n/).map{|i| i.strip}
30
+ rescue
31
+ @userdata=[]
32
+ end
33
+
34
+ if url==''
35
+ if !@userdata.empty?
36
+ url=@userdata[0]
37
+ else
38
+ raise RuntimeError, 'Sunflower - initialize: no URL supplied and no userdata found!'
39
+ end
40
+ end
41
+
42
+ @warnings=true
43
+ @log=true
44
+
45
+ @wikiURL=url
46
+ @logData=''
47
+
48
+ @loggedin=false
49
+ end
50
+
51
+ # Call the API. Returns a hash of JSON response.
52
+ def API request
53
+ #$stderr.puts 'Warning: Sunflower: API request before logging in! ('+request+')' unless @loggedin || !@warnings
54
+ self.log 'http://'+@wikiURL+'/w/api.php?'+request+'&format=jsonfm'
55
+ resp = RestClient.get(
56
+ 'http://'+@wikiURL+'/w/api.php?'+request+'&format=json',
57
+ {:user_agent => 'Sunflower alpha', :cookies => @cookies}
58
+ )
59
+ JSON.parse resp.to_str
60
+ end
61
+
62
+ # Log in using given info.
63
+ def login user='', password=''
64
+ if user=='' || password==''
65
+ if !@userdata.empty?
66
+ user=@userdata[1] if user==''
67
+ password=@userdata[2] if password==''
68
+ else
69
+ raise RuntimeError, 'Sunflower - login: no user/pass supplied and no userdata found!'
70
+ end
71
+ end
72
+
73
+ if user.index(/[#<>\[\]\|\{\}]/)
74
+ raise RuntimeError, 'Sunflower - bad username!'
75
+ end
76
+
77
+
78
+ # 1. get the login token
79
+ response = RestClient.post(
80
+ 'http://'+@wikiURL+'/w/api.php?'+"action=login&lgname=#{user}&lgpassword=#{password}"+'&format=json',
81
+ nil,
82
+ {:user_agent => 'Sunflower alpha'}
83
+ )
84
+
85
+ @cookies = response.cookies
86
+ json = JSON.parse response.to_str
87
+ token, prefix = json['login']['token'], json['login']['cookieprefix']
88
+
89
+
90
+ # 2. actually log in
91
+ response = RestClient.post(
92
+ 'http://'+@wikiURL+'/w/api.php?'+"action=login&lgname=#{user}&lgpassword=#{password}&lgtoken=#{token}"+'&format=json',
93
+ nil,
94
+ {:user_agent => 'Sunflower alpha', :cookies => @cookies}
95
+ )
96
+
97
+ json = JSON.parse response.to_str
98
+
99
+ @cookies = @cookies.merge(response.cookies).merge({
100
+ "#{prefix}UserName" => json['login']['lgusername'].to_s,
101
+ "#{prefix}UserID" => json['login']['lguserid'].to_s,
102
+ "#{prefix}Token" => json['login']['lgtoken'].to_s
103
+ })
104
+
105
+
106
+ raise RuntimeError, 'Sunflower - unable to log in (no cookies received)!' if !@cookies
107
+
108
+
109
+ @loggedin=true
110
+ r=self.API('action=query&list=watchlistraw')
111
+ if r['error'] && r['error']['code']=='wrnotloggedin'
112
+ @loggedin=false
113
+ raise RuntimeError, 'Sunflower - unable to log in!'
114
+ end
115
+
116
+ r=self.API('action=query&list=allusers&aulimit=1&augroup=bot&aufrom='+user)
117
+ unless r['query']['allusers'][0]['name']==user
118
+ $stderr.puts 'Warning: Sunflower - this user does not have bot rights!' if @warnings
119
+ @haveBotRights=false
120
+ else
121
+ @haveBotRights=true
122
+ end
123
+
124
+ return self
125
+ end
126
+
127
+ def log2(t)
128
+ @logData+=t
129
+ if @log
130
+ f=File.open('log.txt','a')
131
+ f.write t
132
+ f.close
133
+ end
134
+ end
135
+
136
+ def log(t)
137
+ self.log2(t.to_s.chomp+"\n")
138
+ end
139
+
140
+ def isBot?
141
+ @haveBotRights
142
+ end
143
+ end
144
+
145
+ # Class representng single Wiki page. To load specified page, use #new/#get/#load method.
146
+ #
147
+ # If you are using multiple Sunflowers, you have to specify which wiki this page belongs to using second argument of function; you can pass whole URL (same as when creating new Sunflower) or just language code.
148
+ #
149
+ # To save page, use #save/#put method. Optional argument is new title page, if ommited, page is saved at old title. Summary can be passed as second parameter. If it's ommited, global variable $summary is used. If it's empty too, error is raised.
150
+ #
151
+ # To get Sunflower instance which this page belongs to, use #sunflower of #belongs_to.
152
+ class Page
153
+ attr_accessor :text
154
+
155
+ attr_reader :orig_text
156
+
157
+ attr_reader :sunflower
158
+ alias :belongs_to :sunflower
159
+
160
+ attr_reader :pageid, :ns, :title, :touched, :lastrevid, :counter, :length, :starttimestamp, :edittoken, :protection #prop=info
161
+
162
+ def initialize title='', wiki=''
163
+ raise RuntimeError, 'Sunflower - title invalid: '+title if title.index(/[#<>\[\]\|\{\}]/)
164
+
165
+ @modulesExecd=[] #used by sunflower-commontasks.rb
166
+ @summaryAppend=[] #used by sunflower-commontasks.rb
167
+
168
+ @title=title
169
+ wiki=wiki+'.wikipedia.org' if wiki.index('.')==nil && wiki!=''
170
+
171
+ if wiki==''
172
+ count=ObjectSpace.each_object(Sunflower){|o| @sunflower=o}
173
+ raise RuntimeError, 'Sunflower - you must pass wiki name if using multiple Sunflowers at once!' if count>1
174
+ else
175
+ ObjectSpace.each_object(Sunflower){|o| @sunflower=o if o.wikiURL==wiki}
176
+ end
177
+
178
+ if title==''
179
+ @text=''
180
+ @orig_text=''
181
+ return
182
+ end
183
+
184
+ r=@sunflower.API('action=query&prop=info&inprop=protection&intoken=edit&titles='+CGI.escape(@title))
185
+ r=r['query']['pages'][r['query']['pages'].keys[0] ]
186
+ r.each{|key,value|
187
+ self.instance_variable_set('@'+key, value)
188
+ }
189
+
190
+ r=@sunflower.API('action=query&prop=revisions&rvprop=content&titles='+CGI.escape(@title))
191
+
192
+ begin
193
+ @text=r['query']['pages'][@pageid.to_s]['revisions'][0]['*']
194
+ rescue Exception
195
+ @text=''
196
+ end
197
+ @orig_text=@text
198
+ end
199
+
200
+ def dumpto file
201
+ if file.respond_to? :write #probably file or IO
202
+ file.write @text
203
+ else #filename?
204
+ f=File.open(file.to_s, 'w')
205
+ f.write @text
206
+ f.close
207
+ end
208
+ end
209
+
210
+ def dump
211
+ self.dumpto @title.gsub(/[^a-zA-Z0-9\-]/,'_')+'.txt'
212
+ end
213
+
214
+ def save title=@title, summary=$summary
215
+ raise RuntimeError, 'Sunflower - title invalid: '+title if title.index(/[#<>\[\]\|\{\}]/)
216
+ raise RuntimeError, 'Sunflower - no summary!' if (summary==nil || summary=='') && @summaryAppend==[]
217
+
218
+ summary='' if summary==nil
219
+ for i in @summaryAppend.uniq
220
+ summary+=', '+i
221
+ end
222
+ summary.sub!(/^, /,'')
223
+
224
+
225
+ if @orig_text==@text && title==@title
226
+ @sunflower.log('Page '+title+' not saved - no changes.')
227
+ return
228
+ end
229
+
230
+
231
+
232
+ self.code_cleanup if $alwaysDoCodeCleanup && self.respond_to?('code_cleanup')
233
+
234
+ r=@sunflower.API("action=edit&bot=1&title=#{CGI.escape(title)}&text=#{CGI.escape(@text)}&summary=#{CGI.escape(summary)}&token=#{CGI.escape(@edittoken)}")# if @sunflower.isBot?
235
+ end
236
+ alias :put :save
237
+
238
+ def self.get title, wiki=''
239
+ Page.new(title, wiki)
240
+ end
241
+
242
+ def self.load title, wiki=''
243
+ Page.new(title, wiki)
244
+ end
245
+ end
246
+
247
+ class Hash
248
+ # just a lil patch
249
+ def first
250
+ self.values[0]
251
+ end
252
+ end
253
+