|
|
@ -1,7 +1,20 @@ |
|
|
|
#!/usr/bin/env python |
|
|
|
#!/usr/bin/env python |
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
# -*- coding: utf-8 -*- |
|
|
|
|
|
|
|
|
|
|
|
# (c) envrm |
|
|
|
# Copyright (C) 2019, Maxim Lihachev, <envrm@yandex.ru> |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# This program is free software: you can redistribute it and/or modify |
|
|
|
|
|
|
|
# it under the terms of the GNU General Public License as published by |
|
|
|
|
|
|
|
# the Free Software Foundation, either version 3 of the License, or |
|
|
|
|
|
|
|
# (at your option) any later version. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# This program is distributed in the hope that it will be useful, |
|
|
|
|
|
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
|
|
|
|
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
|
|
|
|
|
|
# GNU General Public License for more details. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# You should have received a copy of the GNU General Public License |
|
|
|
|
|
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
|
|
|
|
|
|
|
|
# |
|
|
|
# |
|
|
|
# pip install vk_api |
|
|
|
# pip install vk_api |
|
|
@ -27,6 +40,7 @@ from email.mime.text import MIMEText |
|
|
|
|
|
|
|
|
|
|
|
############################################################################ |
|
|
|
############################################################################ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def usage(): |
|
|
|
def usage(): |
|
|
|
print ''' |
|
|
|
print ''' |
|
|
|
vkdigest — сценарий для получения сообщений из сообществ vk.com |
|
|
|
vkdigest — сценарий для получения сообщений из сообществ vk.com |
|
|
@ -46,26 +60,28 @@ def usage(): |
|
|
|
|
|
|
|
|
|
|
|
############################################################################ |
|
|
|
############################################################################ |
|
|
|
|
|
|
|
|
|
|
|
#Конфигурационный файл |
|
|
|
|
|
|
|
|
|
|
|
# Конфигурационный файл |
|
|
|
CONFIG_FILE = os.path.join(os.path.dirname(__file__), os.pardir, 'conf/vkdigest.ini') |
|
|
|
CONFIG_FILE = os.path.join(os.path.dirname(__file__), os.pardir, 'conf/vkdigest.ini') |
|
|
|
|
|
|
|
|
|
|
|
#Вывод на экран |
|
|
|
# Вывод на экран |
|
|
|
# -c | --cli |
|
|
|
# -c | --cli |
|
|
|
CLI_OUTPUT = True |
|
|
|
CLI_OUTPUT = True |
|
|
|
|
|
|
|
|
|
|
|
#Вывод в файл |
|
|
|
# Вывод в файл |
|
|
|
# -f <filename> |
|
|
|
# -f <filename> |
|
|
|
# --file <filename> |
|
|
|
# --file <filename> |
|
|
|
FILE_OUTPUT = False |
|
|
|
FILE_OUTPUT = False |
|
|
|
|
|
|
|
|
|
|
|
#Отправка почты по умолчанию |
|
|
|
# Отправка почты по умолчанию |
|
|
|
SEND_MAIL = False |
|
|
|
SEND_MAIL = False |
|
|
|
|
|
|
|
|
|
|
|
#Путь до css-файла |
|
|
|
# Путь до css-файла |
|
|
|
CSS_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'css/vkdigest.css')) |
|
|
|
CSS_FILE = os.path.abspath(os.path.join(os.path.dirname(__file__), os.path.pardir, 'css/vkdigest.css')) |
|
|
|
|
|
|
|
|
|
|
|
############################################################################ |
|
|
|
############################################################################ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def readConfig(config_file): |
|
|
|
def readConfig(config_file): |
|
|
|
'''Чтение конфигурационного файла''' |
|
|
|
'''Чтение конфигурационного файла''' |
|
|
|
global settings |
|
|
|
global settings |
|
|
@ -74,22 +90,27 @@ def readConfig(config_file): |
|
|
|
settings.read(config_file) |
|
|
|
settings.read(config_file) |
|
|
|
return settings |
|
|
|
return settings |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def opt(parameter): |
|
|
|
def opt(parameter): |
|
|
|
'''Получение опции из файла''' |
|
|
|
'''Получение опции из файла''' |
|
|
|
setting = parameter.split(":") |
|
|
|
setting = parameter.split(":") |
|
|
|
return settings.get(setting[0], setting[1]) |
|
|
|
return settings.get(setting[0], setting[1]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def enabled(opt): |
|
|
|
def enabled(opt): |
|
|
|
return opt.lower() in ("yes", "true", "t", "1") |
|
|
|
return opt.lower() in ("yes", "true", "t", "1") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def timestamp_to_date(timestamp, fmt='%Y-%m-%d %H:%M:%S'): |
|
|
|
def timestamp_to_date(timestamp, fmt='%Y-%m-%d %H:%M:%S'): |
|
|
|
'''Преобразование временного штампа в читаемую дату''' |
|
|
|
'''Преобразование временного штампа в читаемую дату''' |
|
|
|
return datetime.datetime.fromtimestamp(int(timestamp)).strftime(fmt) |
|
|
|
return datetime.datetime.fromtimestamp(int(timestamp)).strftime(fmt) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def today(): |
|
|
|
def today(): |
|
|
|
'''Текущая дата''' |
|
|
|
'''Текущая дата''' |
|
|
|
return int(datetime.datetime.strptime(datetime.datetime.today().strftime('%Y-%m-%d'), '%Y-%m-%d').strftime("%s")) |
|
|
|
return int(datetime.datetime.strptime(datetime.datetime.today().strftime('%Y-%m-%d'), '%Y-%m-%d').strftime("%s")) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def u(string): |
|
|
|
def u(string): |
|
|
|
return string.encode('utf-8') |
|
|
|
return string.encode('utf-8') |
|
|
|
|
|
|
|
|
|
|
@ -97,11 +118,16 @@ def u(string): |
|
|
|
|
|
|
|
|
|
|
|
def make_title(): |
|
|
|
def make_title(): |
|
|
|
'''Заголовок страницы и тема письма''' |
|
|
|
'''Заголовок страницы и тема письма''' |
|
|
|
return MAIL_SUBJECT.format(URL=opt('mail:url'), COMMENT=opt('mail:comment'), DATE=timestamp_to_date(today(), '%Y-%m-%d')) |
|
|
|
return MAIL_SUBJECT.format(URL=opt('mail:url'), |
|
|
|
|
|
|
|
COMMENT=opt('mail:comment'), |
|
|
|
|
|
|
|
DATE=timestamp_to_date(today(), |
|
|
|
|
|
|
|
'%Y-%m-%d')) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#Псевдоним для функции send_email |
|
|
|
# Псевдоним для функции send_email |
|
|
|
make_subject = make_title |
|
|
|
make_subject = make_title |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def send_email(message): |
|
|
|
def send_email(message): |
|
|
|
'''Отправка письма с дайжестом''' |
|
|
|
'''Отправка письма с дайжестом''' |
|
|
|
subject = make_subject() |
|
|
|
subject = make_subject() |
|
|
@ -109,7 +135,7 @@ def send_email(message): |
|
|
|
try: |
|
|
|
try: |
|
|
|
msg = MIMEText(message, 'html') |
|
|
|
msg = MIMEText(message, 'html') |
|
|
|
msg['Subject'] = subject |
|
|
|
msg['Subject'] = subject |
|
|
|
msg['From'] = opt('mail:sender') |
|
|
|
msg['From'] = opt('mail:sender') |
|
|
|
|
|
|
|
|
|
|
|
conn = SMTP(opt('mail:SMTPserver')) |
|
|
|
conn = SMTP(opt('mail:SMTPserver')) |
|
|
|
conn.set_debuglevel(False) |
|
|
|
conn.set_debuglevel(False) |
|
|
@ -120,7 +146,7 @@ def send_email(message): |
|
|
|
conn.quit() |
|
|
|
conn.quit() |
|
|
|
|
|
|
|
|
|
|
|
except Exception, exc: |
|
|
|
except Exception, exc: |
|
|
|
sys.exit( "mail failed; %s" % str(exc) ) |
|
|
|
sys.exit("mail failed; %s" % str(exc)) |
|
|
|
|
|
|
|
|
|
|
|
############################################################################ |
|
|
|
############################################################################ |
|
|
|
|
|
|
|
|
|
|
@ -134,39 +160,48 @@ def auth(login, password): |
|
|
|
print(error_msg) |
|
|
|
print(error_msg) |
|
|
|
return |
|
|
|
return |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def only_today(wall, date=None): |
|
|
|
def only_today(wall, date=None): |
|
|
|
'''Записи за указанную дату''' |
|
|
|
'''Записи за указанную дату''' |
|
|
|
return [post for post in wall if post['date'] >= today()] |
|
|
|
return [post for post in wall if post['date'] >= today()] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_group_url(group): |
|
|
|
def get_group_url(group): |
|
|
|
'''Адрес группы''' |
|
|
|
'''Адрес группы''' |
|
|
|
return group.split(' ')[0] |
|
|
|
return group.split(' ')[0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_group_name(url): |
|
|
|
def get_group_name(url): |
|
|
|
'''HTTP-имя группы''' |
|
|
|
'''HTTP-имя группы''' |
|
|
|
return url.split('/')[-1] |
|
|
|
return url.split('/')[-1] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_photos(attachments): |
|
|
|
def get_photos(attachments): |
|
|
|
'''Получение ссылок на изображения''' |
|
|
|
'''Получение ссылок на изображения''' |
|
|
|
return [attachment['photo'] for attachment in attachments if attachment['type'] == 'photo'] |
|
|
|
return [attachment['photo'] for attachment in attachments if attachment['type'] == 'photo'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_documents(attachments): |
|
|
|
def get_documents(attachments): |
|
|
|
'''Получение ссылок на документы''' |
|
|
|
'''Получение ссылок на документы''' |
|
|
|
return [attachment['doc'] for attachment in attachments if attachment['type'] == 'doc'] |
|
|
|
return [attachment['doc'] for attachment in attachments if attachment['type'] == 'doc'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_links(attachments): |
|
|
|
def get_links(attachments): |
|
|
|
'''Получение ссылок''' |
|
|
|
'''Получение ссылок''' |
|
|
|
return [attachment['link'] for attachment in attachments if attachment['type'] == 'link'] |
|
|
|
return [attachment['link'] for attachment in attachments if attachment['type'] == 'link'] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def group_info(name): |
|
|
|
def group_info(name): |
|
|
|
'''Информация о сообществе''' |
|
|
|
'''Информация о сообществе''' |
|
|
|
#TODO: если репост со страницы пользователя, то вставляет название группы |
|
|
|
# TODO: если репост со страницы пользователя, то вставляет название группы |
|
|
|
return vk.groups.getById(group_ids=name)[0] |
|
|
|
return vk.groups.getById(group_ids=name)[0] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wall_url(group_id, post_id): |
|
|
|
def wall_url(group_id, post_id): |
|
|
|
'''Ссылка на конкретный пост''' |
|
|
|
'''Ссылка на конкретный пост''' |
|
|
|
return "http://vk.com/wall" + str(group_id) + '_' + str(post_id) |
|
|
|
return "http://vk.com/wall" + str(group_id) + '_' + str(post_id) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wall(name): |
|
|
|
def wall(name): |
|
|
|
'''Получение записей со стены сообщества''' |
|
|
|
'''Получение записей со стены сообщества''' |
|
|
|
id = group_info(get_group_name(name))['id'] |
|
|
|
id = group_info(get_group_name(name))['id'] |
|
|
@ -180,6 +215,7 @@ def wall(name): |
|
|
|
|
|
|
|
|
|
|
|
############################################################################ |
|
|
|
############################################################################ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def html_toc(groups): |
|
|
|
def html_toc(groups): |
|
|
|
'''Содержание дайжеста со ссылками на группы''' |
|
|
|
'''Содержание дайжеста со ссылками на группы''' |
|
|
|
HTML.h2("Сообщества:") |
|
|
|
HTML.h2("Сообщества:") |
|
|
@ -194,6 +230,7 @@ def html_toc(groups): |
|
|
|
HTML.br() |
|
|
|
HTML.br() |
|
|
|
HTML.hr() |
|
|
|
HTML.hr() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def groups_info(input_file): |
|
|
|
def groups_info(input_file): |
|
|
|
'''Информация о группах, перечисленных в файле''' |
|
|
|
'''Информация о группах, перечисленных в файле''' |
|
|
|
f = open(input_file, "r") |
|
|
|
f = open(input_file, "r") |
|
|
@ -205,8 +242,8 @@ def groups_info(input_file): |
|
|
|
|
|
|
|
|
|
|
|
for group in groups: |
|
|
|
for group in groups: |
|
|
|
if group.strip(): |
|
|
|
if group.strip(): |
|
|
|
url = get_group_url(group) |
|
|
|
url = get_group_url(group) |
|
|
|
MAIL_URL = url |
|
|
|
MAIL_URL = url |
|
|
|
|
|
|
|
|
|
|
|
if '#' in group: |
|
|
|
if '#' in group: |
|
|
|
MAIL_COMMENT = group.split('#')[1] |
|
|
|
MAIL_COMMENT = group.split('#')[1] |
|
|
@ -214,6 +251,7 @@ def groups_info(input_file): |
|
|
|
group_info_html(url) |
|
|
|
group_info_html(url) |
|
|
|
wall_html(url) |
|
|
|
wall_html(url) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def group_info_html(name): |
|
|
|
def group_info_html(name): |
|
|
|
'''Информация о группе в формате HTML''' |
|
|
|
'''Информация о группе в формате HTML''' |
|
|
|
group_name = get_group_name(name) |
|
|
|
group_name = get_group_name(name) |
|
|
@ -231,6 +269,7 @@ def group_info_html(name): |
|
|
|
HTML.br() |
|
|
|
HTML.br() |
|
|
|
HTML.hr() |
|
|
|
HTML.hr() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def wall_html(name): |
|
|
|
def wall_html(name): |
|
|
|
'''Сообщения со стены сообщества в формате HTML''' |
|
|
|
'''Сообщения со стены сообщества в формате HTML''' |
|
|
|
info = wall(name) |
|
|
|
info = wall(name) |
|
|
@ -238,20 +277,21 @@ def wall_html(name): |
|
|
|
for post in info: |
|
|
|
for post in info: |
|
|
|
if post['text'] or ('attachments' in post): |
|
|
|
if post['text'] or ('attachments' in post): |
|
|
|
post_html(post) |
|
|
|
post_html(post) |
|
|
|
#Репост |
|
|
|
# Репост |
|
|
|
elif 'copy_history' in post: |
|
|
|
elif 'copy_history' in post: |
|
|
|
post_html(post['copy_history'][0], True) |
|
|
|
post_html(post['copy_history'][0], True) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def post_html(content, repost=False): |
|
|
|
def post_html(content, repost=False): |
|
|
|
'''Информация о посте в формате HTML''' |
|
|
|
'''Информация о посте в формате HTML''' |
|
|
|
HTML.div(class_="post") |
|
|
|
HTML.div(class_="post") |
|
|
|
|
|
|
|
|
|
|
|
if repost: |
|
|
|
if repost: |
|
|
|
original_group = group_info(abs(content['owner_id'])) |
|
|
|
original_group = group_info(abs(content['owner_id'])) |
|
|
|
original_name = u(original_group['name']) |
|
|
|
original_name = u(original_group['name']) |
|
|
|
original_url = wall_url(content['from_id'], content['id']) |
|
|
|
original_url = wall_url(content['from_id'], content['id']) |
|
|
|
|
|
|
|
|
|
|
|
#Дата поста |
|
|
|
# Дата поста |
|
|
|
HTML.h4() |
|
|
|
HTML.h4() |
|
|
|
|
|
|
|
|
|
|
|
if enabled(opt('digest:add_links')): |
|
|
|
if enabled(opt('digest:add_links')): |
|
|
@ -261,10 +301,10 @@ def post_html(content, repost=False): |
|
|
|
|
|
|
|
|
|
|
|
HTML.h4.close() |
|
|
|
HTML.h4.close() |
|
|
|
|
|
|
|
|
|
|
|
#Текст поста |
|
|
|
# Текст поста |
|
|
|
HTML.p(tuple(u(content['text']).splitlines())) |
|
|
|
HTML.p(tuple(u(content['text']).splitlines())) |
|
|
|
|
|
|
|
|
|
|
|
#Документы |
|
|
|
# Документы |
|
|
|
if 'attachments' in content: |
|
|
|
if 'attachments' in content: |
|
|
|
for photo in get_photos(content['attachments']): |
|
|
|
for photo in get_photos(content['attachments']): |
|
|
|
HTML.a(_.img(src=u(photo['photo_130'])), href=u(photo['photo_604'])) |
|
|
|
HTML.a(_.img(src=u(photo['photo_130'])), href=u(photo['photo_604'])) |
|
|
@ -276,18 +316,19 @@ def post_html(content, repost=False): |
|
|
|
HTML.ul(_.li(_.a(u(link['title']), href=u(link['url'])))) |
|
|
|
HTML.ul(_.li(_.a(u(link['title']), href=u(link['url'])))) |
|
|
|
|
|
|
|
|
|
|
|
HTML.br() |
|
|
|
HTML.br() |
|
|
|
HTML.div.close() #<div class="post"> |
|
|
|
HTML.div.close() # <div class="post"> |
|
|
|
HTML.hr() |
|
|
|
HTML.hr() |
|
|
|
|
|
|
|
|
|
|
|
############################################################################ |
|
|
|
############################################################################ |
|
|
|
|
|
|
|
|
|
|
|
#Чтение файла настроек |
|
|
|
|
|
|
|
|
|
|
|
# Чтение файла настроек |
|
|
|
settings = [] |
|
|
|
settings = [] |
|
|
|
readConfig(CONFIG_FILE) |
|
|
|
readConfig(CONFIG_FILE) |
|
|
|
|
|
|
|
|
|
|
|
MAIL_SUBJECT = opt('mail:subject') |
|
|
|
MAIL_SUBJECT = opt('mail:subject') |
|
|
|
|
|
|
|
|
|
|
|
#Учётная запись vk.com |
|
|
|
# Учётная запись vk.com |
|
|
|
vk = auth(opt('vk:username'), opt('vk:password')) |
|
|
|
vk = auth(opt('vk:username'), opt('vk:password')) |
|
|
|
|
|
|
|
|
|
|
|
############################################################################ |
|
|
|
############################################################################ |
|
|
@ -306,19 +347,26 @@ url = False |
|
|
|
CLI_OUTPUT_FLAG = False |
|
|
|
CLI_OUTPUT_FLAG = False |
|
|
|
|
|
|
|
|
|
|
|
for option, arg in opts: |
|
|
|
for option, arg in opts: |
|
|
|
if option in ('-h', '--help'): usage() |
|
|
|
if option in ('-h', '--help'): |
|
|
|
elif option in ('-f', '--file'): input_file = arg |
|
|
|
usage() |
|
|
|
elif option in ('-u', '--url'): url = arg |
|
|
|
elif option in ('-f', '--file'): |
|
|
|
elif option in ('-s', '--subj'): MAIL_SUBJECT = arg |
|
|
|
input_file = arg |
|
|
|
elif option in ('-t', '--title'): MAIL_SUBJECT = arg |
|
|
|
elif option in ('-u', '--url'): |
|
|
|
|
|
|
|
url = arg |
|
|
|
|
|
|
|
elif option in ('-s', '--subj'): |
|
|
|
|
|
|
|
MAIL_SUBJECT = arg |
|
|
|
|
|
|
|
elif option in ('-t', '--title'): |
|
|
|
|
|
|
|
MAIL_SUBJECT = arg |
|
|
|
elif option in ('-o', '--out'): |
|
|
|
elif option in ('-o', '--out'): |
|
|
|
FILE_OUTPUT = arg |
|
|
|
FILE_OUTPUT = arg |
|
|
|
CLI_OUTPUT = False |
|
|
|
CLI_OUTPUT = False |
|
|
|
elif option in ('-m', '--mail'): |
|
|
|
elif option in ('-m', '--mail'): |
|
|
|
SEND_MAIL = True |
|
|
|
SEND_MAIL = True |
|
|
|
CLI_OUTPUT = False |
|
|
|
CLI_OUTPUT = False |
|
|
|
elif option in ('-c', '--cli'): CLI_OUTPUT_FLAG = True |
|
|
|
elif option in ('-c', '--cli'): |
|
|
|
else: usage() |
|
|
|
CLI_OUTPUT_FLAG = True |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
usage() |
|
|
|
|
|
|
|
|
|
|
|
if CLI_OUTPUT_FLAG: |
|
|
|
if CLI_OUTPUT_FLAG: |
|
|
|
CLI_OUTPUT = True |
|
|
|
CLI_OUTPUT = True |
|
|
@ -350,8 +398,7 @@ if SEND_MAIL: |
|
|
|
|
|
|
|
|
|
|
|
if FILE_OUTPUT: |
|
|
|
if FILE_OUTPUT: |
|
|
|
with open(FILE_OUTPUT, 'w') as outfile: |
|
|
|
with open(FILE_OUTPUT, 'w') as outfile: |
|
|
|
outfile.write(HTML()) |
|
|
|
outfile.write(HTML()) |
|
|
|
|
|
|
|
|
|
|
|
if CLI_OUTPUT: |
|
|
|
if CLI_OUTPUT: |
|
|
|
print HTML |
|
|
|
print HTML |
|
|
|
|
|
|
|
|
|
|
|