r38
r38
1if wiki=='namu':
2 api_url="wiki-api.namu.la"
3 wiki_url="namu.wiki"
4 discuss_doc="사용자:Ordeal"
5 APItoken='W8/tf8MdLpRUinfutKuF0ToCZdAFipkyrz0VsUD8EGs/ABgvvSjmw2ZY3T2mOxLQSltIPUHHEO2+m/5YHS8Wh1k/iv1cUnlJq0Je88Jt6hVG97rfvdks+Tm3+t6MfG8tKDi8pQzyLcqOrBXa5TZOH0eapjW35Jy+2VY5asHi/VM='
6elif wiki=='theseed':
7 api_url="theseed.io"
8 wiki_url="theseed.io"
9 discuss_doc="사용자:ego"
10 APItoken='AdBYWxvQPwVtkaNKwl2Ljp6OodJsTT9+mZis8OuhE0cUwvFYu6I//v3bVXs2o3JPTWuHxpLKLptOrOlqvrLAlGET86foepv5pO0l2y9yrXsz7AtAYeZmrW+LOsGebOzAPJDro+6Ixm1U+ZHuNv2W3xY7s5e92Y4A4S5lb07jCBo='
11else:
12 sys_stop=True
13 print('no wiki select')
r37
14
r38
15headers = {'Content-Type': 'application/json', 'Authorization': 'Bearer {}'.format(APItoken)}
16discuss_headers = {'User-Agent': 'Mozilla/5.0'}
17####
18sys_stop=False
19
20logger = logging.getLogger("wiki edit")
21discusslogger = logging.getLogger("discuss HTML")
22streamlogger = logging.getLogger("log stream")
23
24logging.addLevelName(11, "edit History")
25logging.editHistory = 11
26
27logging.addLevelName(31, "edit Fail")
28logging.editFail= 31
29
30logging.addLevelName(41, "edit Error")
31logging.editError = 41
32
33logging.addLevelName(35, "working Emergency Stop")
34logging.workingEmergencyStop = 35
35
36logging.addLevelName(25, "discuss Error")
37logging.discussError = 25
38
39logging.addLevelName(12, "discuss Load")
40logging.discussLoad = 12
41
42logger.setLevel(logging.DEBUG)
43discusslogger.setLevel(logging.INFO)
44
45formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
46stream_hander = logging.StreamHandler()
47stream_hander.setFormatter(formatter)
48streamlogger.addHandler(stream_hander)
49progStart_day=str(time.strftime('%Y %m %d', time.localtime()))
50progStart_time=str(time.strftime('%H %M %S', time.localtime()))
51
52if not os.path.exists('/content/drive/My Drive/Colab Notebooks/logs/{}'.format(progStart_day)):
53 os.makedirs('/content/drive/My Drive/Colab Notebooks/logs/{}'.format(progStart_day))
54os.makedirs('/content/drive/My Drive/Colab Notebooks/logs/{}/{}'.format(progStart_day,progStart_time))
55
56file_handler = logging.FileHandler('/content/drive/My Drive/Colab Notebooks/logs/{}/{}/wiki edit.log'.format(progStart_day,progStart_time))
57file_handler.setFormatter(formatter)
58logger.addHandler(file_handler)
59
60discuss_file_handler = logging.FileHandler('/content/drive/My Drive/Colab Notebooks/logs/{}/{}/discuss HTML.log'.format(progStart_day,progStart_time))
61discuss_file_handler.setFormatter(formatter)
62discusslogger.addHandler(discuss_file_handler)
63
64error_file_handler = logging.FileHandler('/content/drive/My Drive/Colab Notebooks/logs/{}/{}/error.log'.format(progStart_day,progStart_time))
65error_file_handler.setFormatter(formatter)
66streamlogger.addHandler(error_file_handler)
67
68class checkWikiThread():
69 async def alterResponseTry(self,response,wait_time=0.2):
70 try:
71 await response.html.arender(wait=wait_time)
72 html = await response.html.html
73 loadComple = re.search("토론",str(html))
74 if loadComple==None:
75 logger.log(logging.discussLoad, ('not Loding, wait_time: {}'.format(wait_time)))
76 print('not Loding, wait_time:',wait_time)
77 if wait_time>40:
78 discusslogger.log(logging.discussError,(html))
79 logger.log(logging.discussError, ("timeout, html log saved: {} discuss HTML.log".format(str(progStart_time))))
80 streamlogger.log(logging.discussError, ("timeout, html log saved: {} discuss HTML.log".format(str(progStart_time))))
81 html= await self.alterResponseTry(response,wait_time=float(wait_time+10))
82 else :
83 logger.log(logging.discussLoad, 'load comple')
84 return html
85 except Exception as ex:
86 logger.log(logging.discussError, ex)
87 streamlogger.log(logging.discussError, ex)
88 html= await self.alterResponseTry(response,wait_time)
89 return html
90 def __init__(self):
91 self.state=False
92 self.discuss_state = None
93 async def run(self):
94 self.state=True
95 response = await requests.get("https://{}/discuss/{}".format(wiki_url,discuss_doc),headers=discuss_headers, timeout=100)
96 html = response.text
97 loadComple = re.search("토론",str(html))
98 if loadComple==None:
99 logger.log(logging.discussLoad, 'not Loding, alter way start')
100 #print(html)
101 asession = await AsyncHTMLSession()
102 response = await asession.get("https://{}/discuss/{}".format(wiki_url,discuss_doc),headers=discuss_headers)
103 html= await self.alterResponseTry(response)
104 self.discuss_state = re.search("\/discuss\/[\w,%,:]*#s-1",str(html))
105 await time.sleep(30)
106 self.state = False
107
108def linkcheckchange(match_obj):
109 #구버전 기본값
110 #print(match_obj)
111 #print(match_obj[0])
112 #link = match_obj.group('link')
113 #anchor = match_obj.group('anchor')
114 #content = match_obj.group('content')
115 #namebar = match_obj.group('namebar')
116 #for target,replace in targets:
117 #if link==target:
118 #if content==None:
119 #내용이 없을경우 원래 링크가 내용이 됨
120 #content=link
121 #link=replace
122 #if anchor==None:
123 #anchor=''
124 #if namebar==None:
125 #namebar=''
126 #return '[[{}{}{}|{}]]'.format(namebar,link,anchor,content)
127 #
128 #[[]] 전용
129 first = match_obj.group('first')
130 link = match_obj.group('link')
131 middle = match_obj.group('middle')
132 detachBar = match_obj.group('detachBar')
133 content = match_obj.group('content')
134 last = match_obj.group('last')
135 anchor = match_obj.group('anchor')
136 if middle==None:
137 middle=''
138 for target in targets:
139 target_doc=target['document']
140 replace=target['replace']
141 if link==target_doc:
142 #내용이 없을경우 원래 링크가 내용이 됨
143 #content_replace bool 추가
144 if content==None and content_replace:
145 #혹시 모를 사고 예방
146 if detachBar==None:
147 content='|{}'.format(link)
148 else:
149 content='{}'.format(link)
150 elif content==None:
151 content=''
152 link=replace
153 return '{}{}{}{}{}'.format(first,link,middle,content,last)
154 return match_obj.group(0)
155def checkchange(match_obj):
156 #[[]] 제외 기본 변경
157 first = match_obj.group('first')
158 link = match_obj.group('link')
159 last = match_obj.group('last')
160 for target in targets:
161 target_doc=target['document']
162 replace=target['replace']
163 if link==target_doc:
164 link=replace
165 #print('hidden')
166 return '{}{}{}'.format(first,link,last)
167 return match_obj.group(0)
168def checkdelete(match_obj):
169 #분류 정리 전용
170 link = match_obj.group('link')
171 anchor = match_obj.group('anchor')
172 content = match_obj.group('content')
173 for target in targets:
174 target_doc=target['document']
175 replace=target['replace']
176 if link==target_doc:
177 if content==None:
178 #내용이 없을경우 원래 링크가 내용이 됨
179 content=link
180 link=replace
181 if anchor==None:
182 anchor=''
183 return ''
184 return match_obj.group(0)
185
186def edit_link(title, text):
187 link_patten=re.compile(r"(?P<first>\[\[(?P<namebar>(:)?))(?P<link>((\\\\)|(\\\#)|(\\\|)|(\\\[)|(\\\])|[^\[\]#|])*)(?P<middle>(?P<anchor>#((\\\\)|(\\\#)|(\\\|)|(\\\[)|(\\\])|[^\[\]#|])*)?(?P<detachBar>\|)?)(?(detachBar)(?P<content>((\\\\)|(\\\#)|(\\\|)|(\\\[)|(\\\])|[^\[\]|])*))(?P<last>\]\])")
188 otherMean_patten=re.compile(r"(?P<first>rd\d=)(?P<link>((\\\,)|(\\\\)|(\\\))|[^\,)])*)(?P<last>[,)])")
189 detailContent_patten=re.compile(r"(?P<first>문서명=)(?P<link>((\\\,)|(\\\\)|(\\\))|[^\,)])*)(?P<last>[,)])")
190 categoryMean_patten=re.compile(r"(?P<first>n\d=)(?P<link>((\\\,)|(\\\\)|(\\\))|[^\,)])*)(?P<last>[,)])")
191 top_patten=re.compile(r"(?P<first>top\d=)(?P<link>((\\\,)|(\\\\)|(\\\))|[^\,)])*)(?P<last>[,)])")
192 include_patten=re.compile(r"(?P<first>\[include\()(?P<link>((\\\,)|(\\\\)|(\\\))|[^\,)])*)(?P<last>((?P<comma>,)?)?(?(comma)((\\\,)|(\\\\)|(\\\))|[^)])*)\)\])")
193 redirect_patten=re.compile(r"(?P<first>#redirect )(?P<link>((\\\\)|(\\\#)|(\\\|)|(\\\[)|(\\\])|[^\[\]#|])*)(?P<last>(?P<anchor>#)?.*\n)")
194
195 normal_new_text=link_patten.sub(linkcheckchange,text)
196 new_text=otherMean_patten.sub(checkchange,normal_new_text)
197 new_text=detailContent_patten.sub(checkchange,new_text)
198 new_text=categoryMean_patten.sub(checkchange,new_text)
199 new_text=top_patten.sub(checkchange,new_text)
200 new_text=include_patten.sub(checkchange,new_text)
201 new_text=redirect_patten.sub(checkchange,new_text)
202 if normal_new_text!=new_text:
203 logger.log(logging.editHistory,('특수 변경 문서명: {}'.format(title)))
204 return new_text
205
206def backlinkchange():
207 data={}
208 data['edit']=[]
209 for target in targets:
210 target_doc=target['document']
211 replace=target['replace']
212 target_backlinks = []
213 backlink_value = ''
214
215 while True:
216 res = requests.get('https://{}/api/backlink/{}?from={}'.format(api_url,target_doc, backlink_value), headers = headers).json()
217 backlink_value=res['from']
218 for doc in res['backlinks']:
219 white=False
220 for white_doc in nontargets:
221 if doc['document'] == white_doc:
222 logger.info("화이트 리스트 문서 '{}' Pass".format(doc['document']))
223 white=True
224 break
225 if white:
226 continue
227 target_backlinks.append(doc['document'])
228 if backlink_value==None:
229 break
230 for doc in target_backlinks:
231 try:
232 res = requests.get('https://{}/api/edit/{}'.format(api_url,doc), headers = headers).json()
233 except:
234 res = requests.get('https://{}/api/edit/{}'.format(api_url,doc), headers = headers)
235 logger.log(logging.workingEmergencyStop, str(res.text))
236 streamlogger.log(logging.workingEmergencyStop, str(res.text))
237 exit()
238 try:
239 if not res['exists']:
240 continue
241 except:
242 logger.log(logging.editFail, ('문서명: {}'.format(doc),'res: {}'.format(res)))
243 streamlogger.log(logging.editFail, ('문서명: {}'.format(doc),'res: {}'.format(res)))
244 continue
245
246 token = res['token']
247 text = str(res['text'])
248 new_text = edit_link(doc, text)
249 res = requests.post('https://{}/api/edit/{}'.format(api_url,doc), json = {'text': new_text, 'log': log, 'token': token}, headers = headers)
250 try:
251 if res.json()['status'] != 'success':
252 logger.log(logging.editError, ('문서명: {}'.format(doc),'res: {}'.format(res.text)))
253 streamlogger.log(logging.editError, ('문서명: {}'.format(doc),'res: {}'.format(res.text)))
254 else:
255 data['edit'].append({
256 "doc": str(doc),
257 "rev": res.json()['rev'],
258 "text":text
259 })
260 logger.log(logging.editHistory,('문서명: {}'.format(doc),'rev: {}'.format(res.json()['rev'])))
261 except Exception as ex:
262 logger.critical(('문서명:',doc,'Error:',ex))
263 logger.log(logging.editError,(('문서명:',doc,'Error:',ex)))
264 streamlogger.critical(('문서명:',doc,'Error:',ex))
265 time.sleep(1)
266 with open('/content/drive/My Drive/Colab Notebooks/logs/{}/{}/edit_history.txt'.format(progStart_day,progStart_time), 'w') as outfile:
267 json.dump(data, outfile, indent=4, ensure_ascii=False)
268
269def revert():
270 data={}
271 data['edit']=[]
272 json_data = {}
273 with open('/content/drive/My Drive/Colab Notebooks/logs/{}/{}/edit_history.txt'.format(revert_day,revert_time), "r") as json_file:
274 json_data = json.load(json_file)
275 for target in json_data['edit']:
276 doc = target['doc']
277 try:
278 res = requests.get('https://{}/api/edit/{}'.format(api_url,doc), headers = headers).json()
279 except:
280 res = requests.get('https://{}/api/edit/{}'.format(api_url,doc), headers = headers)
281 logger.log(logging.workingEmergencyStop, str(res.text))
282 streamlogger.log(logging.workingEmergencyStop, str(res.text))
283 exit()
284 try:
285 if not res['exists']:
286 continue
287 except:
288 logger.log(logging.editFail, ('문서명: {}'.format(doc),'res: {}'.format(res)))
289 streamlogger.log(logging.editFail, ('문서명: {}'.format(doc),'res: {}'.format(res)))
290 continue
291
292 token = res['token']
293 text = str(res['text'])
294 new_text = target['text']
295 log=log+'(r{}으로 되돌림)'.format(str(int(target['rev'])-1))
296
297 res = requests.post('https://{}/api/edit/{}'.format(api_url,doc), json = {'text': new_text, 'log': log, 'token': token}, headers = headers)
298 if res.json()['status'] != 'success':
299 logger.log(logging.editError, ('문서명: {}'.format(doc),'res: {}'.format(res.text)))
300 streamlogger.log(logging.editError, ('문서명: {}'.format(doc),'res: {}'.format(res.text)))
301 else:
302 data['edit'].append({
303 "doc": str(doc),
304 "rev": res.json()['rev'],
305 "text":text
306 })
307 logger.log(logging.editHistory,('문서명: {}'.format(doc),'rev: {}'.format(res.json()['rev'])))
308
309 time.sleep(1)
310 with open('/content/drive/My Drive/Colab Notebooks/logs/{}/{}/edit_history.txt'.format(progStart_day,progStart_time), 'w') as outfile:
311 json.dump(data, outfile, indent=4, ensure_ascii=False)
312
313def customlinkchange():
314 data={}
315 data['edit']=[]
316 json_data = {}
317 for target, replace in targets:
318 for doc in custom_list:
319 doc = doc+'Music'
320 try:
321 res = requests.get('https://{}/api/edit/{}'.format(api_url,doc), headers = headers).json()
322 except:
323 res = requests.get('https://{}/api/edit/{}'.format(api_url,doc), headers = headers)
324 logger.log(logging.workingEmergencyStop, str(res.text))
325 streamlogger.log(logging.workingEmergencyStop, str(res.text))
326 exit()
327 try:
328 if not res['exists']:
329 continue
330 except:
331 logger.log(logging.editFail, ('문서명: {}'.format(doc),'res: {}'.format(res)))
332 streamlogger.log(logging.editFail, ('문서명: {}'.format(doc),'res: {}'.format(res)))
333 continue
334
335
336 token = res['token']
337 text = str(res['text'])
338 new_text = edit_link(doc, text)
339
340 res = requests.post('https://{}/api/edit/{}'.format(api_url,doc), json = {'text': new_text, 'log': log, 'token': token}, headers = headers)
341 if res.json()['status'] != 'success':
342 logger.log(logging.editError, ('문서명: {}'.format(doc),'res: {}'.format(res.text)))
343 streamlogger.log(logging.editError, ('문서명: {}'.format(doc),'res: {}'.format(res.text)))
344 else:
345 data['edit'].append({
346 "doc": str(doc),
347 "rev": res.json()['rev'],
348 "text":text
349 })
350 logger.log(logging.editHistory,('문서명: {}'.format(doc),'rev: {}'.format(res.json()['rev'])))
351
352 time.sleep(1)
353
354class runningThread(threading.Thread):
355 def __init__(self):
356 super().__init__()
357 self.state=False
358 def run(self):
359 self.state=True
360 logger.info('working start')
361 print('working start')
362 if mod=='normal':
363 backlinkchange()
364 elif mod=='revert':
365 if revert_day != '' or revert_day != '':
366 revert()
367 else:
368 print('revert 시간이 지정되지 않았습니다.')
369 log = '자동 편집 중 '
370 print('로그 변경됨:'+log+'(r{}으로 되돌림)'.format('int'))
371 elif mod=='custom':
372 customlinkchange()
373 else:
374 print('mod not select')
375 logger.info('working end')
376 print('working end')
377 self.state=False
378
379####
380checkDiscuss=checkWikiThread()
381custom_thread=runningThread()
382custom_thread.start()
383while True:
384 try:
385 if not checkDiscuss.state:
386 checkDiscuss.run()
387 if not custom_thread.state or sys_stop:
388 logger.info('System Stop')
389 print('system stop')
390 break
391 if checkDiscuss.discuss_state != None:
392 logger.log(logging.workingEmergencyStop, 'discuss normal, System Emergency Stop')
393 streamlogger.log(logging.workingEmergencyStop, 'discuss normal, System Emergency Stop')
394 break
395 except Exception as ex:
396 logger.critical(ex)
397 streamlogger.critical(ex)
398 break
399logging.shutdown()
400reload(logging)