-
Notifications
You must be signed in to change notification settings - Fork 12
/
Copy pathwiki.js
459 lines (395 loc) · 16.7 KB
/
wiki.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
/**
* @name CeL function for MediaWiki (Wikipedia / 維基百科)
*
* @fileoverview 本檔案包含了 MediaWiki 自動化作業用的程式庫,主要用於編寫[[維基百科:機器人]]
* ([[WP:{{{name|{{int:Group-bot}}}}}|{{{name|{{int:Group-bot}}}}}]])。
*
* TODO:<code>
wiki_API.work() 遇到 Invalid token 之類問題,中途跳出 abort 時,無法紀錄。應將紀錄顯示於 console 或 local file。
wiki_API.page() 整合各 action=query 至單一公用 function。
[[mw:Manual:Pywikibot/zh]]
[[mw:Help:OAuth]]
https://www.mediawiki.org/wiki/OAuth/Owner-only_consumers
https://meta.wikimedia.org/wiki/Steward_requests/Miscellaneous#OAuth_permissions
[[m:Special:OAuthConsumerRegistration/propose]] (using an owner-only consumers) get (consumer_key, consumer_secret, access_token, access_secret)
Wikimedia REST API
https://www.mediawiki.org/wiki/RESTBase
https://zh.wikipedia.org/w/index.php?title=title&action=history&hilight=123,456
-{zh-hans:访问;zh-hant:訪問;zh-tw:瀏覽}-量
https://wikitech.wikimedia.org/wiki/Analytics/PageviewAPI
https://en.wikipedia.org/wiki/Wikipedia:Pageview_statistics
https://dumps.wikimedia.org/other/pagecounts-raw/
https://tools.wmflabs.org/pageviews
https://wikitech.wikimedia.org/wiki/Analytics/Data/Pagecounts-raw
https://meta.wikimedia.org/wiki/Research:Page_view
WikiData Remote editor
http://tools.wmflabs.org/widar/
get user infomation:
https://www.mediawiki.org/w/api.php?action=help&modules=query%2Busers
https://zh.wikipedia.org/w/api.php?action=query&format=json&list=users&usprop=blockinfo|groups|implicitgroups|rights|editcount|registration|emailable|gender|centralids|cancreate&usattachedwiki=zhwiki&ususers=username|username
https://www.mediawiki.org/w/api.php?action=help&modules=query%2Busercontribs
https://zh.wikipedia.org/w/api.php?action=query&format=json&list=usercontribs&uclimit=1&ucdir=newer&ucprop=ids|title|timestamp|comment|parsedcomment|size|sizediff|flags|tags&ucuser=username
對Action API的更改,請訂閱
https://lists.wikimedia.org/pipermail/mediawiki-api-announce/
雙重重定向/重新導向/転送
特別:二重リダイレクト
Special:DoubleRedirects
Special:BrokenRedirects
https://www.mediawiki.org/w/api.php?action=help&modules=query%2Bquerypage
[[mw:User:Duplicatebug/API Overview/action]]
https://test.wikipedia.org/w/api.php?action=query&list=querypage&qppage=DoubleRedirects&qplimit=max
gadgets 小工具 [[Wikipedia:Tools]], [[Category:Wikipedia scripts]], [[mw:ResourceLoader/Core modules]]
[[Special:MyPage/common.js]] [[使用說明:維基用戶腳本開發指南]]
// ---------------------------------------------------------
// https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.loader
mediaWiki.loader.load('https://kanasimi.github.io/CeJS/ce.js')
CeL.run('application.net.wiki');
CeL.wiki.page('Wikipedia:機器人',function(page_data){console.log(page_data);},{redirects:true,section:0})
// wikibits從2013年就棄用
// https://www.mediawiki.org/wiki/ResourceLoader/Legacy_JavaScript#wikibits.js
// NG: importScript('User:cewbot/*.js');
你可以在維基媒體的wiki網站URL最後增加?safemode=1來關閉你個人的CSS和JavaScript。範例:https://zh.wikipedia.org/wiki/文學?safemode=1。上面一行意思是你可以測試是否是你的使用者腳本或套件造成問題,而不必解除安裝。
</code>
*
* @see https://github.com/siddharthvp/mwn
*/
// More examples: see /_test suite/test.js
// Wikipedia bots demo: https://github.com/kanasimi/wikibot
// JavaScript MediaWiki API for ECMAScript 2017+ :
// https://github.com/kanasimi/wikiapi
'use strict';
// 'use asm';
// --------------------------------------------------------------------------------------------
// 不採用 if 陳述式,可以避免 Eclipse JSDoc 與 format 多縮排一層。
typeof CeL === 'function' && CeL.run({
// module name
name : 'application.net.wiki',
// .includes() @ CeL.data.code.compatibility
// .between() @ CeL.data.native
// .append() @ CeL.data.native
require : 'data.code.compatibility.|data.native.'
// (new Date).format('%4Y%2m%2d'), (new Date).format() @ CeL.data.date
// optional 選用: .show_value() @ CeL.interact.DOM, CeL.application.debug
// optional 選用: CeL.wiki.cache(): CeL.application.platform.nodejs.fs_mkdir()
// optional 選用: CeL.wiki.traversal(): CeL.application.platform.nodejs
// optional 選用: wiki_API.work(): gettext():
// optional 選用: CeL.application.storage
// CeL.application.locale.gettext()
// CeL.date.String_to_Date(), Julian_day(), .to_millisecond(): CeL.data.date
+ '|data.date.',
// 設定不匯出的子函式。
no_extend : '*',
// 為了方便格式化程式碼,因此將 module 函式主體另外抽出。
code : module_code
});
function module_code(library_namespace) {
// requiring
// --------------------------------------------------------------------------------------------
// https://github.com/Microsoft/TypeScript/wiki/JSDoc-support-in-JavaScript
/**
* web Wikipedia / 維基百科 用的 functions。<br />
* 可執行環境: node.js, JScript。
*
* TODO: new wiki_API(API_URL || login_options);<br />
* wiki_session.login(user_name, password, API_URL);
*
* @param {String}user_name
* user name
* @param {String}password
* user password
* @param {String}[API_URL]
* language code or API Endpoint URL
*
* @returns {wiki_API} wiki site API
* @template wiki_API
*
* @constructor
*/
function wiki_API(user_name, password, API_URL) {
if (!this || this.constructor !== wiki_API) {
return wiki_API.query.apply(null, arguments);
}
// TODO: this.login(user_name, password, API_URL);
var login_options;
if (API_URL && typeof API_URL === 'object') {
// session = new wiki_API(user_name, password, login_options);
login_options = API_URL;
API_URL = null;
} else if (!API_URL && !password && user_name
&& typeof user_name === 'object') {
// session = new wiki_API(login_options);
login_options = user_name;
user_name = null;
// console.log(login_options);
} else {
login_options = Object.create(null);
}
user_name = user_name || login_options.user_name;
password = password || login_options.password;
API_URL = API_URL || login_options.API_URL/* || login_options.project */;
// console.trace([ user_name, password, API_URL ]);
library_namespace.debug('URL of service endpoint: ' + API_URL
+ ', default language: ' + wiki_API.language, 3, 'wiki_API');
// action queue 佇列。應以 append,而非整個換掉的方式更改。
this.actions = [];
// @see wiki_API.prototype.next
if (login_options.is_running) {
// Is calling from wiki_API.login()
// login 前便執行其他作業,可能導致 Session=deleted。 e.g., running
// login_options.configuration_adapter() @ 20201008.fix_anchor.js
if (typeof login_options.is_running === 'string')
this.actions.unshift([ login_options.is_running ]);
// 執行權交給 wiki_API.login()。
this.running = true;
}
// 權杖
this.token = {
// lgusername
lgname : user_name,
// user_password
lgpassword : password
};
// console.trace(API_URL);
if (!API_URL && !('language' in this)
// wikidata 不設定 language。
&& !this[wiki_API.KEY_HOST_SESSION]) {
API_URL = wiki_API.language;
// 假若未設定 API_URL 或 user_name,那就不初始化。等 .login 才初始化。
// 若想基本的初始化,最起碼必須設定 API_URL。
login_options.need_initialize = password && user_name;
} else if (!('need_initialize' in login_options)) {
login_options.need_initialize = true;
}
if ('use_SQL' in login_options) {
this.use_SQL = login_options.use_SQL;
} else if (API_URL
// assert: typeof API_URL === 'string'
&& API_URL.includes('://')) {
// assert: Not MediaWiki server. Is outer server.
this.use_SQL = false;
}
// console.trace(API_URL);
// setup session, as wiki site of pywikibot.Site().
if (API_URL) {
// e.g., 'cmn'
if (API_URL in wiki_API.language_code_to_site_alias)
API_URL = wiki_API.language_code_to_site_alias[API_URL];
wiki_API.setup_API_language(this /* session */, API_URL);
wiki_API.setup_API_URL(this /* session */, API_URL);
}
[ 'site_name', 'data_API_URL', 'SPARQL_API_URL',
// Must after wiki_API.setup_API_language()!
'language' ]
//
.forEach(function(property) {
if (property in login_options)
this[property] = login_options[property];
}, this);
// console.trace(this);
this.general_parameters = Object.clone(wiki_API.general_parameters);
library_namespace.import_options(login_options,
// @see CeL.application.net.wiki.namespace
wiki_API.general_parameters_normalizer, this.general_parameters);
if (library_namespace.is_WWW(true) && window.location
// For non-authenticated requests, specify the value *. This
// will cause the Access-Control-Allow-Origin header to be set,
// but Access-Control-Allow-Credentials will be false and all
// user-specific data will be restricted.
&& this.general_parameters.origin !== '*') {
var host;
if (!window.location.host
// e.g., locale file: window.location.host===""
|| (host = new URL(this.API_URL).host)
&& host !== window.location.host
&& host !== this.general_parameters.origin) {
library_namespace.warn([ 'wiki_API: ', {
// gettext_config:{"id":"you-may-need-to-set-$1-=-$2"}
T : [ 'You may need to set %1 = %2!',
//
'.origin', JSON.stringify(host) ]
} ]);
}
}
if (login_options.localStorage_prefix_key && wiki_API.has_storage) {
// assert: typeof login_options.localStorage_prefix_key === 'string'
// ||
// typeof login_options.localStorage_prefix_key === 'number'
this.localStorage_prefix = [ library_namespace.Class,
wiki_API.site_name(this),
login_options.localStorage_prefix_key, '' ]
// '.'
.join(library_namespace.env.module_name_separator);
}
// ------------------------------------------------
// pre-loading functions
// https://stackoverflow.com/questions/39007637/javascript-set-vs-array-performance
// https://jsbench.me/3pkjlwzhbr/1
// .API_parameters[modules.path].parameter_Map = parameter Map
// @see get_API_parameters()
this.API_parameters = Object.create(null);
// wiki_session.redirects_data[redirect_from] = {String}redirect_to
// = main page title without "Template:" prefix
// @see CeL.application.net.wiki.task ,
// CeL.application.net.wiki.namespace
this.redirects_data = Object.create(null);
// 不存在的頁面。 non-existent pages
this.nonexistent_pages = Object.create(null);
// @see wiki_API.check_stop()
this.task_control_status = Object.create(null);
// @see wiki_API.prototype.next
this.checking_stop_now = Object.create(null);
if (login_options.need_initialize) {
this.run_after_initializing = [];
// 注意: new wiki_API() 後之操作,應該採 wiki_session.run()
// 的方式,確保此時已經執行過 pre-loading functions @ function wiki_API():
// wiki_session.siteinfo(), wiki_session.adapt_task_configurations()
this.run(initialize_wiki_API, login_options);
} else {
// e.g.,
// wiki = new CeL.wiki; ...; wiki.login(login_options);
}
}
function initialize_wiki_API(options) {
var session = this;
// console.trace(session.actions);
// console.trace(session.running);
// if (session.API_URL)
session.siteinfo(load_template_functions);
// console.trace(session.actions);
// console.trace(session.running);
function load_template_functions() {
// console.trace(session);
// @see CeL.application.net.wiki.template_functions
if (session.load_template_functions)
session.load_template_functions(null,
//
adapt_task_configurations);
else
adapt_task_configurations();
}
function adapt_task_configurations() {
// console.trace(options);
if (options.task_configuration_page) {
session.adapt_task_configurations(
options.task_configuration_page,
function(configuration) {
// console.trace(configuration);
if (options.configuration_adapter)
options.configuration_adapter(configuration);
initialization_complete();
});
} else {
initialization_complete();
}
}
function initialization_complete() {
library_namespace.debug(wiki_API.site_name(session) + ': '
+ '初始化程序登錄完畢。' + '添加之前登錄的 ' + session.actions.length
+ ' 個程序到佇列中。', 1, 'initialization_complete');
session.actions.append(session.run_after_initializing);
delete session.run_after_initializing;
// console.trace(session.actions);
}
}
initialize_wiki_API.is_initializing_process = true;
/**
* 檢查若 value 為 session。
*
* @param value
* value to test. 要測試的值。
*
* @returns {Boolean} value 為 session。
*/
function is_wiki_API(value) {
return value
&& ((value instanceof wiki_API) || value.API_URL && value.token);
}
// ------------------------------------------------------------------------
// export 導出.
// @static
Object.assign(wiki_API, {
is_wiki_API : is_wiki_API
});
if (library_namespace.is_WWW(true) && typeof mw === 'object' && mw
&& typeof mw.config === 'object'
&& typeof mw.config.get === 'function'
&& typeof mediaWiki === "object" && mediaWiki === mw) {
wiki_API.mw_web_session = true;
}
// 等執行再包含入必須的模組。
this.finish = function(name_space, waiting, sub_modules_to_full_module_path) {
var sub_modules = [ 'namespace', 'parser', 'query', 'page',
'page.Page', 'Flow', 'list', 'edit', 'task', 'parser.wikitext',
'parser.section', 'parser.misc', 'parser.evaluate' ];
// ------------------------------------------------------------------------
// auto import SQL 相關函數 @ Toolforge。
// function setup_wmflabs()
// only for node.js.
if (library_namespace.platform.nodejs) {
/** {String}Wikimedia Toolforge name. CeL.wiki.wmflabs */
wiki_API.wmflabs =
// inside Toolforge/Kubernetes
// https://wikitech.wikimedia.org/wiki/Help:Toolforge/Kubernetes
library_namespace.env.TOOL_DATA_DIR
// 2023/12 將作業從 Grid Engine 遷移到 Kubernetes
// https://github.com/kanasimi/wikibot/issues/50
&& library_namespace.env.KUBERNETES_PORT
//
// https://wikitech.wikimedia.org/wiki/Help:Toolforge/FAQ#How_can_I_detect_if_I.27m_running_in_Cloud_VPS.3F_And_which_project_.28tools_or_toolsbeta.29.3F
|| require('fs').existsSync('/etc/wmflabs-project')
// e.g., 'tools-bastion-05'.
// if use `process.env.INSTANCEPROJECT`,
// you may get 'tools' or 'tools-login'.
&& (library_namespace.env.INSTANCENAME
// 以 /usr/bin/jsub 執行時可得。
// e.g., 'tools-exec-1210.eqiad.wmflabs'
|| library_namespace.env.HOSTNAME || true);
}
if (wiki_API.wmflabs) {
// import CeL.application.net.wiki.Toolforge
sub_modules.push('Toolforge');
}
// --------------------------------------------------------------------
// Essential dependency chain
library_namespace.debug({
T :
// gettext_config:{"id":"load-the-main-functions-and-necessary-dependencies-to-operate-mediawiki"}
'Load the main functions and necessary dependencies to operate MediaWiki.'
}, 1, 'wiki_API');
// library_namespace.set_debug(2);
library_namespace.run(sub_modules_to_full_module_path(sub_modules),
// The `wiki_API.mw_web_session` is a session that operates in a web
// environment. For example, the Wikipedia widget.
function() {
if (wiki_API.mw_web_session) {
wiki_API.mw_web_session = new wiki_API({
API_URL :
// mediaWiki.config.get('wgServer')
location.origin
// https://www.mediawiki.org/wiki/Manual:$wgScriptPath
+ mediaWiki.config.get('wgScriptPath')
// https://www.mediawiki.org/wiki/Manual:Api.php
+ '/api.php',
localStorage_prefix_key : 'mw_web_session'
});
// fill tokens
for ( var token_name in mediaWiki.user.tokens.values) {
wiki_API.mw_web_session.token[
// 'csrfToken' → 'csrftoken'
token_name.toLowerCase()]
//
= mediaWiki.user.tokens.values[token_name];
}
// 預設對所有網站會使用相同的 cookie
// @see
// https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/mw.Api
}
library_namespace.debug({
// gettext_config:{"id":"all-wiki-submodules-are-loaded"}
T : 'All wiki submodules are loaded.'
}, 1, 'wiki_API');
}, waiting);
return waiting;
};
return wiki_API;
}