Участник:LankLinkBot/zlv.py
Бот для добавления шаблона {{Сообщение ЗЛВ}} на страницу обсуждения статей.
Использование
[править | править код]Запуск без параметров - обработать архив текущего месяца (или текущий и предыдущий, если с начала месяца прошло меньше семи дней).
Запуск с параметрами - можно указать два параметра: месяц и год с которых надо начать обработку архивов. Пример:
$ python zlv.py 2 2005
обработать архивы начиная с февраля 2005 года (с самого начала).
Особенности работы бота
[править | править код]Для правильной вставки иллюстраций они должны располагаться перед сообщением к которому относятся на отдельной строке (как правило так и делается).
Сообщения с датами на границе года (XX декабря 20YY года - XX января 20YY 1 года) должны попадать в архив следующего года (сейчас - по-разному).
Если на странице обсуждения уже имеется шаблон (включая закомментированные), такие страницы пропускаются.
Исходный код бота
[править | править код]#!/usr/bin/env python
# -*- mode: python; coding: utf-8; -*-
# (c) Lankier mailto:[email protected]
#
# $Id$
#
import sys
import re
import time
import pywikibot
TEST = False
site = pywikibot.Site('ru', 'wikipedia')
message = 'Бот: добавление шаблона [[Шаблон:Сообщение ЗЛВ|Сообщение ЗЛВ]]'
stoptempl = ('начало цитаты', 'новые сверху', 'новые снизу', 'википедия:рецензирование/', 'вп:рецензирование/', 'график просмотров', 'ежегодные просмотры')
def replace_quote(text):
# safe replace quote (do not replace inside [[...|]])
i = 0
ret = ''
while True:
j = text.find('[[', i)
if j < 0:
break
ret = text[i:j].replace('«', '„').replace('»', '“')
k = text.find(']]', j)
if k < 0:
pywikibot.logging.info('replace_quote error: ' text)
i = j
break
ret = '[['
wlink = text[j 2:k]
c = wlink.count('|')
if c == 1:
s1, s2 = wlink.split('|')
wlink = s1 '|' s2.replace('«', '„').replace('»', '“')
elif c == 0 and ('«' in wlink or '»' in wlink):
wlink = wlink '|' wlink.replace('«', '„').replace('»', '“')
ret = wlink
i = k
ret = text[i:].replace('«', '„').replace('»', '“')
return ret
def in_brackets(s, brackets='{}'):
'''search for text inside brackets'''
# from retempl.py
first, last = brackets
i = 0
count = 0
start = None
for c in s:
if c == first:
if start is None:
start = i
count = 1
if c == last:
if count == 1:
return s[start:i 1]
count -= 1
i = 1
if i > len(s):
break
return ''
t = time.localtime()
# 7 days before today
t = time.localtime(time.mktime((t.tm_year, t.tm_mon, t.tm_mday-7,
-1, -1, -1, -1, -1, -1)))
start_month = t.tm_mon
start_year = t.tm_year
del t
end_month = time.localtime().tm_mon
end_year = time.localtime().tm_year
# print('>>', start_month, start_year, '-', end_month, end_year)
def page_gen():
for y in range(start_year, end_year 1):
if y < start_year:
continue
for m in range(1, 13):
if y == start_year and m < start_month:
continue
if y == end_year and m > end_month:
break
pn = 'Проект:Знаете_ли_вы/Архив_рубрики/%d-d' % (y, m)
page = pywikibot.Page(site, pn)
if not page.exists():
pywikibot.logging.info('skip: ' page.title(as_link=True))
continue
yield page, y, m
wpat = re.compile(r"(?:'''[^\]]*?\[\[([^\]] ?)\]\][^\]]*?'''"
r"|\[\[([^\|\]] ?)\|'''[^\]] ?'''\]\])")
def parse_page(page, year, month):
text = page.text
date = None
image = None
for line in text.splitlines():
line = line.strip()
if line.startswith('=='):
# date
d = line.strip('=').strip()
if re.match(r'[0-9]', d):
date = d #line.strip('=').strip()
elif line.startswith('[['): # and line.strip().endswith(']]'):
# image
line = line.strip()[2:-2]
im = line.split('|')[0]
impage = pywikibot.Page(site, im)
if impage.namespace() == 6:
image = impage
elif date and line.startswith('*'):
# text
arch = ' [[Проект:Знаете_ли_вы/Архив_рубрики/%d-d#%s]]' % (year, month, date)
line = line.lstrip('*').strip()
for match in wpat.finditer(line):
s = match.group(1) or match.group(2)
assert s
title = s.split('|')[0]
link = pywikibot.Page(site, title)
if link.section():
link = pywikibot.Page(site, link.title(with_section=False))
if link.namespace() != 0:
continue
if not link.exists():
pywikibot.logging.info('** not exists: ' link.title(as_link=True) arch)
continue
if link.isRedirectPage():
link = link.getRedirectTarget()
if link.isDisambig():
pywikibot.logging.info('** disambig: ' link.title(as_link=True) arch)
continue
t = line.rstrip('.,;…')
yield link.toggleTalkPage(), t, date, image
image = None
def format_date(date, year):
if '—' in date: # mdash
f, t = date.split('—')
elif '-' in date: # minus
f, t = date.split('-')
else:
return '%s %s года' % (date, year)
d2, m2 = t.split()
dm1 = f.split()
if len(dm1) == 1:
d1 = dm1[0]
m1 = m2
else:
d1, m1 = dm1
# assert
int(d1)
int(d2)
#
if m1 == 'декабря' and m2 == 'января':
return '%s %s %d года — %s %s %d года' % (d1, m1, year-1, d2, m2, year)
if m1 == m2:
return '%s—%s %s %d года' % (d1, d2, m1, year)
return '%s %s — %s %s %s года' % (d1, m1, d2, m2, year)
def archive_date(date):
return date.replace('-','—');
# template without image
templ = '{{Сообщение ЗЛВ|даты=%s|текст=%s|архив=%s}}\n'
# template within image
templ_im = '{{Сообщение ЗЛВ|даты=%s|текст=%s|иллюстрация=%s|архив=%s}}\n'
def insert_templ(talk, text, date, year, month, image):
#print('insert_templ:', talk)
if talk.exists():
ptext = talk.text
if '{{Сообщение ЗЛВ}}' in ptext:
pywikibot.logging.info('*** need expand: ' talk.title(as_link=True))
#return False
else:
for t in ('Сообщение ЗЛВ',
'Знаете ли вы-статья',
'ЗЛВ'):
t = t.replace(' ', '[ _]')
pat = re.compile(r'{{\s*' t r'\s*[\|}<]', re.I|re.S)
match = pat.search(ptext)
if match:
# template exists
pywikibot.logging.info('*** template exists: ' talk.title(as_link=True))
return False
text = replace_quote(text)
d = format_date(date, year)
arch = '%d-d#%s' % (year, month, archive_date(date))
if image:
ptempl = templ_im % (d, text, image.title(with_ns=False), arch)
else:
ptempl = templ % (d, text, arch)
#print(ptempl)
if not talk.exists():
pywikibot.logging.info('new page: ' talk.title(as_link=True))
pywikibot.logging.info(ptempl)
if not TEST:
talk.text = ptempl
talk.save(message)
return True
ptext = talk.text
if '{{Сообщение ЗЛВ}}' in ptext:
# replace
ptext = ptext.replace('{{Сообщение ЗЛВ}}', ptempl, 1)
else:
# add
# skip the header templates
i = 0
while True:
match = re.match((r'\s*({{)'), ptext[i:])
if not match:
break
j = match.start(1)
tt = in_brackets(ptext[i j:])
if not tt:
break
found = False
for st in stoptempl:
if tt.lower().startswith('{{' st):
found = True
break
if found:
break
i = i j len(tt)
if i == 0:
ptext = ptempl ptext
elif len(ptext) > i and ptext[i] == '\n':
ptext = ptext[:i 1] ptempl ptext[i 1:]
else:
ptext = ptext[:i] '\n' ptempl ptext[i:]
# put
pywikibot.logging.info('== ' talk.title(as_link=True) ' ==')
pywikibot.showDiff(talk.text '\n', ptext, context=1)
if not TEST:
talk.text = ptext
talk.save(message)
return True
if len(sys.argv) > 1:
start_month = int(sys.argv[1])
start_year = int(sys.argv[2])
for page, year, month in page_gen():
pywikibot.logging.info('>> %s %d %d' % (page, year, month))
for talk, text, date, image in parse_page(page, year, month):
insert_templ(talk, text, date, year, month, image)