119 Commits

Author SHA1 Message Date
Sergey
4b6f01c18f Update README.md 2021-02-23 23:37:59 +03:00
Sergey
96b306c667 Update README.md 2017-09-10 02:53:56 +03:00
Sergey
dafe9a1d4e Update README.md 2017-09-10 02:52:47 +03:00
Sergey
9b254aa51b Update README.md 2017-09-10 02:50:40 +03:00
Sergey
16c51ca6bf Add files via upload 2017-09-10 02:49:39 +03:00
Sergey
07e287ce09 Merge pull request #6 from chimka-m/gh-pages
Обновление инструкции
2017-07-11 14:44:26 +03:00
Marina
5663b2eb68 Обновление инструкции 2017-07-11 14:42:05 +03:00
Sergey
d0ef969991 Update README.md 2017-07-10 01:55:03 +03:00
Sergey
975ac7b498 Update README.md 2017-07-09 15:42:24 +03:00
Sergey
c43a49a896 Update README.md 2017-07-09 15:40:10 +03:00
Sergey
5a7787714f Update README.md 2017-07-05 19:16:52 +03:00
Sergey
7adc464167 Update jekyll-theme-slate.scss 2017-07-03 21:50:44 +03:00
Sergey
4c4f906362 Update jekyll-theme-slate.scss 2017-07-03 21:44:32 +03:00
Sergey
9967a0e243 Update jekyll-theme-slate.scss 2017-07-03 21:43:03 +03:00
Sergey
957ddbb5ee Update jekyll-theme-slate.scss 2017-07-03 21:34:22 +03:00
Sergey
08c9de3a18 Update README.md 2017-07-03 20:15:55 +03:00
Sergey
b10c7ed50b Update README.md 2017-07-03 20:15:22 +03:00
Sergey
ef27a2bbc2 Update README.md 2017-07-03 18:59:37 +03:00
Sergey
cf2ef9699d Create google-analytics.html 2017-07-03 16:57:21 +03:00
Sergey
11425341a4 Update README.md 2017-07-03 13:12:55 +03:00
Sergey
4d1de3c0e8 Update _config.yml 2017-07-03 04:30:39 +03:00
Sergey
19fdd09807 Update README.md 2017-07-03 04:25:26 +03:00
Sergey
42e6824374 Update README.md 2017-07-03 04:23:35 +03:00
Sergey
7c390ad20c Update README.md 2017-07-03 04:20:49 +03:00
Sergey
1ebc24514a Update README.md 2017-07-03 03:48:37 +03:00
Sergey
4a70210611 Add files via upload 2017-07-03 03:42:51 +03:00
Sergey
a90103be60 Update README.md 2017-07-03 03:41:21 +03:00
Sergey
90959141aa Update README.md 2017-07-03 03:40:22 +03:00
Sergey
f8f3345e5e Update README.md 2017-07-03 03:38:49 +03:00
Sergey
f2cd1f2f2b Update README.md 2017-07-03 03:38:04 +03:00
Sergey
63884f27f5 Update README.md 2017-07-03 03:27:24 +03:00
Sergey
9c9db0f6c9 Delete rsz_sunset.jpg 2017-07-03 03:25:25 +03:00
Sergey
af1b80e530 Delete rsz_search.jpg 2017-07-03 03:25:17 +03:00
Sergey
e571d89f6b Delete rsz_dialogs.jpg 2017-07-03 03:25:11 +03:00
Sergey
98fb8eff9a Add files via upload 2017-07-03 03:24:57 +03:00
Sergey
b69db84f38 Update README.md 2017-07-03 03:22:50 +03:00
Sergey
cce30f8607 Add files via upload 2017-07-03 03:17:58 +03:00
Sergey
c6687a438d Delete rsz_forwardvk.png 2017-07-03 03:17:48 +03:00
Sergey
a6366b0364 Add files via upload 2017-07-03 03:16:48 +03:00
Sergey
bd02529577 Add files via upload 2017-07-03 02:51:04 +03:00
Sergey
ee27cd71f0 Add files via upload 2017-07-03 02:47:59 +03:00
Sergey
351bc0c0b5 Update README.md 2017-07-03 02:11:10 +03:00
Sergey
6aa79999de Update README.md 2017-07-03 02:05:09 +03:00
Sergey
ea60c6e8eb Update jekyll-theme-slate.scss 2017-07-03 02:03:29 +03:00
Sergey
0875f5d3ec Delete style.css 2017-07-03 02:01:21 +03:00
Sergey
0e4c2bcd04 Create rouge-github.scss 2017-07-03 01:58:14 +03:00
Sergey
94c368d37c Create jekyll-theme-slate.scss 2017-07-03 01:57:54 +03:00
Sergey
fdba66bf74 Create style.css 2017-07-03 01:53:50 +03:00
Sergey
332e85b746 Create style.scss 2017-07-03 01:53:36 +03:00
Sergey
3d7cea9ea3 Delete style.scss 2017-07-03 01:53:12 +03:00
Sergey
9877b37bd8 Delete style.css 2017-07-03 01:53:07 +03:00
Sergey
4854be2d54 Create style.css 2017-07-03 01:05:24 +03:00
Sergey
3f4f699414 Delete slate.scss 2017-07-03 01:04:27 +03:00
Sergey
a755851005 Delete rouge-github.scss 2017-07-03 01:04:00 +03:00
Sergey
bed0fa48c6 Create style.scss 2017-07-03 01:03:26 +03:00
Sergey
71940447c3 Create rouge-github.scss 2017-07-03 00:52:36 +03:00
Sergey
32e245d603 Create slate.scss 2017-07-03 00:52:18 +03:00
Sergey
c19ac8072e Update README.md 2017-07-03 00:50:35 +03:00
Sergey
4c17b25e25 Update README.md 2017-07-03 00:37:55 +03:00
Sergey
b4faa4871b Update README.md 2017-07-03 00:31:57 +03:00
Sergey
e456763ae3 revert 2017-07-03 00:30:04 +03:00
Sergey
6f1bba53bd Update README.md 2017-07-03 00:24:26 +03:00
Sergey
c39613b5fa Update README.md 2017-07-03 00:23:50 +03:00
Sergey
29f624ab63 Update README.md 2017-07-03 00:20:21 +03:00
Sergey
f9055a98a6 Update README.md 2017-07-03 00:19:59 +03:00
Sergey
bf5b7e1e65 Update README.md 2017-07-03 00:19:40 +03:00
Sergey
c8e383ba23 Update README.md 2017-07-03 00:13:51 +03:00
Sergey
e821889fc8 Update README.md 2017-07-03 00:13:33 +03:00
Sergey
775fed0dc6 Update README.md 2017-07-03 00:11:01 +03:00
Sergey
bb72f21273 Update README.md 2017-07-03 00:10:45 +03:00
Sergey
01634f8d91 Create README.md 2017-07-03 00:09:45 +03:00
Sergey
8501360e31 Update README.md 2017-07-03 00:09:20 +03:00
Sergey
496dd9870b Update README.md 2017-07-03 00:07:41 +03:00
Sergey
7578db792c Update README.md 2017-07-03 00:07:10 +03:00
Sergey
a05bb58737 Update README.md 2017-07-03 00:01:27 +03:00
Sergey
4bf5562a77 Update README.md 2017-07-02 23:37:05 +03:00
Sergey
4a76321df1 Update README.md 2017-07-02 23:26:34 +03:00
Sergey
23f417e984 Update README.md 2017-07-02 23:24:55 +03:00
Sergey
bfadd61553 Create README.md 2017-07-02 23:23:46 +03:00
Sergey
a79d2bb212 Update README.md 2017-07-02 23:06:07 +03:00
Sergey
1e0ac1bf42 Update README.md 2017-07-02 23:05:40 +03:00
Sergey
526640eea7 Update README.md 2017-07-02 23:02:44 +03:00
Sergey
e70837a6e7 Update README.md 2017-07-02 22:59:53 +03:00
Sergey
132cd2eb8d Update README.md 2017-07-02 22:58:19 +03:00
Sergey
d514fb3ad0 Update README.md 2017-07-02 22:54:34 +03:00
Sergey
1a3add8f92 Update README.md 2017-07-02 22:53:19 +03:00
Sergey
4279f2549e Update README.md 2017-07-02 22:51:46 +03:00
Sergey
691b18e625 Update README.md 2017-07-02 22:29:20 +03:00
Sergey
8eaadad5a7 Add files via upload 2017-07-02 22:28:41 +03:00
Sergey
172979b7c7 Delete documents.PNG 2017-07-02 22:26:52 +03:00
Sergey
869a748956 Delete dialogs.jpg 2017-07-02 22:26:47 +03:00
Sergey
871f69c5d7 Delete rsz_search.jpg 2017-07-02 22:26:42 +03:00
Sergey
bdca43555c Delete sticker.jpg 2017-07-02 22:26:37 +03:00
Sergey
2fdfa810d4 Delete sunset.jpg 2017-07-02 22:26:32 +03:00
Sergey
c72d8b7adf Add files via upload 2017-07-02 22:26:19 +03:00
Sergey
fae379f9b4 Add files via upload 2017-07-02 22:25:51 +03:00
Sergey
6364f41ce8 Update README.md 2017-07-02 22:13:01 +03:00
Sergey
98b4d0e0d7 Add files via upload 2017-07-02 22:12:45 +03:00
Sergey
5057b8a7c4 Update README.md 2017-07-02 22:10:15 +03:00
Sergey
c353355da5 Update README.md 2017-07-02 22:09:36 +03:00
Sergey
4e405a79ed Add files via upload 2017-07-02 22:05:00 +03:00
Sergey
d263380b80 Create sample.txt 2017-07-02 22:04:37 +03:00
Sergey
28a10393b0 Add files via upload 2017-07-02 21:59:31 +03:00
Sergey
514a2a5325 Delete image.png 2017-07-02 21:59:11 +03:00
Sergey
d0f21dfd10 Add files via upload 2017-07-02 21:57:11 +03:00
Sergey
3101d6636d Update _config.yml 2017-07-02 21:03:21 +03:00
Sergey
aff9a7d2eb Update README.md 2017-07-02 20:00:27 +03:00
Sergey
335b51397d Create LICENSE 2017-07-02 19:27:59 +03:00
Sergey
2da398486a Rename _config.yaml to _config.yml 2017-07-02 19:16:19 +03:00
Sergey
f92a2cb6e5 Create README.md 2017-07-02 19:15:15 +03:00
Sergey
b08fffea7e Create _config.yaml 2017-07-02 19:15:09 +03:00
Sergey
6ef93f949c Delete vk_messages.py 2017-07-02 19:13:43 +03:00
Sergey
308cb0a54b Delete credentials.py 2017-07-02 19:13:36 +03:00
Sergey
51b3fe5349 Delete bot.py 2017-07-02 19:13:31 +03:00
Sergey
08a0e1662e Delete app.json 2017-07-02 19:13:24 +03:00
Sergey
05b8410776 Delete README.md 2017-07-02 19:13:18 +03:00
Sergey
a2685c7ac7 Delete LICENSE 2017-07-02 19:13:11 +03:00
Sergey
537d7648fe Delete .gitignore 2017-07-02 19:13:05 +03:00
Sergey
1f2cc35306 Delete .gitattributes 2017-07-02 19:12:58 +03:00
35 changed files with 804 additions and 1330 deletions

17
.gitattributes vendored
View File

@@ -1,17 +0,0 @@
# Auto detect text files and perform LF normalization
* text=auto
# Custom for Visual Studio
*.cs diff=csharp
# Standard to msysgit
*.doc diff=astextplain
*.DOC diff=astextplain
*.docx diff=astextplain
*.DOCX diff=astextplain
*.dot diff=astextplain
*.DOT diff=astextplain
*.pdf diff=astextplain
*.PDF diff=astextplain
*.rtf diff=astextplain
*.RTF diff=astextplain

145
.gitignore vendored
View File

@@ -1,145 +0,0 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
*.egg-info/
.installed.cfg
*.egg
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*,cover
.hypothesis/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
# Flask instance folder
instance/
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
target/
# IPython Notebook
.ipynb_checkpoints
# pyenv
.python-version
# celery beat schedule file
celerybeat-schedule
# dotenv
.env
# virtualenv
venv/
ENV/
# Spyder project settings
.spyderproject
# Rope project settings
.ropeproject
# =========================
# Operating System Files
# =========================
# OSX
# =========================
.DS_Store
.AppleDouble
.LSOverride
# Thumbnails
._*
# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk
# Windows
# =========================
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Windows Installer files
*.cab
*.msi
*.msm
*.msp
# Windows shortcuts
*.lnk
# Bot credentials
credentials.py
# PyCharm project
.idea

30
LICENSE
View File

@@ -1,20 +1,16 @@
MIT License
Copyright (c) 2017 А. Сергей
Copyright (c) 2017 Sergey
Данная лицензия разрешает лицам, получившим копию данного программного обеспечения и сопутствующей документации
(в дальнейшем именуемыми «Программное Обеспечение»), безвозмездно использовать Программное Обеспечение без ограничений,
включая неограниченное право на использование, копирование, изменение, слияние, публикацию,
а также лицам, которым предоставляется данное Программное Обеспечение, при соблюдении следующих условий:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, and to permit persons to whom
the Software is furnished to do so, subject to the following conditions:
Указанное выше уведомление об авторском праве и данные условия должны быть включены во все копии или значимые части
данного Программного Обеспечения.
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
ДАННОЕ ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ ПРЕДОСТАВЛЯЕТСЯ «КАК ЕСТЬ», БЕЗ КАКИХ-ЛИБО ГАРАНТИЙ,
ЯВНО ВЫРАЖЕННЫХ ИЛИ ПОДРАЗУМЕВАЕМЫХ, ВКЛЮЧАЯ ГАРАНТИИ ТОВАРНОЙ ПРИГОДНОСТИ,
СООТВЕТСТВИЯ ПО ЕГО КОНКРЕТНОМУ НАЗНАЧЕНИЮ И ОТСУТСТВИЯ НАРУШЕНИЙ, НО НЕ ОГРАНИЧИВАЯСЬ ИМИ.
НИ В КАКОМ СЛУЧАЕ АВТОРЫ ИЛИ ПРАВООБЛАДАТЕЛИ НЕ НЕСУТ ОТВЕТСТВЕННОСТИ ПО КАКИМ-ЛИБО ИСКАМ,
ЗА УЩЕРБ ИЛИ ПО ИНЫМ ТРЕБОВАНИЯМ, В ТОМ ЧИСЛЕ, ПРИ ДЕЙСТВИИ КОНТРАКТА, ДЕЛИКТЕ ИЛИ ИНОЙ СИТУАЦИИ,
ВОЗНИКШИМ ИЗ-ЗА ИСПОЛЬЗОВАНИЯ ПРОГРАММНОГО ОБЕСПЕЧЕНИЯ ИЛИ ИНЫХ ДЕЙСТВИЙ С ПРОГРАММНЫМ ОБЕСПЕЧЕНИЕМ.

View File

@@ -1 +0,0 @@
bot: python3 bot.py

View File

@@ -1,28 +1,27 @@
### Новая версия в разработке!
Актуальная ветка разработки находится [здесь](https://github.com/Kylmakalle/tgvkbot/tree/async-dev)
# Общие функции
Подробнее в [чате](https://t.me/joinchat/BZq6jwxeTh04qBzilM5x3g)
- [Создание и развёртывание](installation/README.md)
- [Использование](usage/README.md)
- [Канал в Telegram](https://t.me/tg_vk) - обновления, поддержа
# tgvkbot
Бот позволяет получать и отправлять сообщения VK находясь в Telegram
Бот позволяет обмениваться сообщениями ВК используя Telegram, имеется возможность пересылки сообщений, а так же выбора диалога.
<p align="center"><img src ="assets/rsz_sunset (1).jpg" /></p>
https://www.asergey.me/tgvkbot
Поддерживаются различные вложения
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
<p align="center"><img src ="assets/documents.PNG" /></p>
[Ветка](https://github.com/Kylmakalle/tgvkbot/tree/webhook) для деплоя на локальной машине (поддерживаются вебхуки и лонгполлинг, закомментируйте и раскомментируйте нужные строки)
В том числе и аудиозаписи
<p align="center"><img src ="assets/vk_music.jpg" /></p>
Список диалогов
<p align="center"><img src ="assets/rsz_dialogs (1).jpg" /></p>
Настройка вебхуков по гайду от [@Groosha](https://www.gitbook.com/book/groosha/telegram-bot-lessons)
И поиск по диалогам
Бэкенд API для получения музыки через https://asergey.me/vkmusapi/
<p align="center"><img src ="assets/rsz_search (1).jpg" /></p>
https://gist.github.com/Kylmakalle/e63902025c527ac3610989530f4fa417
## Stay Tuned!
олноценные комментарии к коду будут чуть позже_
- [Создание и развёртывание](installation/README.md)
- [Использование](usage/README.md)
- [Канал в Telegram](https://t.me/tg_vk) - обновления, поддержа

4
_config.yml Normal file
View File

@@ -0,0 +1,4 @@
theme: jekyll-theme-slate
title: tgvkbot
description: 'Общайтесь ВКонтакте с помощью Telegram бота'
google_analytics: UA-101930895-1

View File

@@ -0,0 +1,10 @@
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','https://www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-101930895-1', 'auto');
ga('send', 'pageview');
</script>

View File

@@ -0,0 +1,425 @@
@import "rouge-github";
/*******************************************************************************
MeyerWeb Reset
*******************************************************************************/
html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font: inherit;
vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
ol, ul {
list-style: none;
}
table {
border-collapse: collapse;
border-spacing: 0;
}
/*******************************************************************************
Theme Styles
*******************************************************************************/
body {
box-sizing: border-box;
color:#373737;
background: #212121;
font-size: 20px;
font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif;
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
h1, h2, h3, h4, h5, h6 {
margin: 10px 0;
font-weight: 700;
color:#222222;
font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif;
letter-spacing: -1px;
}
h1 {
font-size: 36px;
font-weight: 700;
}
h2 {
padding-bottom: 10px;
font-size: 32px;
background: url('../images/bg_hr.png') repeat-x bottom;
}
h3 {
font-size: 24px;
}
h4 {
font-size: 21px;
}
h5 {
font-size: 18px;
}
h6 {
font-size: 16px;
}
p {
margin: 10px 0 15px 0;
}
footer p {
color: #f2f2f2;
}
a {
text-decoration: none;
color: #0F79D0;
text-shadow: none;
transition: color 0.5s ease;
transition: text-shadow 0.5s ease;
-webkit-transition: color 0.5s ease;
-webkit-transition: text-shadow 0.5s ease;
-moz-transition: color 0.5s ease;
-moz-transition: text-shadow 0.5s ease;
-o-transition: color 0.5s ease;
-o-transition: text-shadow 0.5s ease;
-ms-transition: color 0.5s ease;
-ms-transition: text-shadow 0.5s ease;
}
a:hover, a:focus {
text-decoration: underline;
font-weight:bold;
}
footer a {
color: #F2F2F2;
text-decoration: underline;
}
em {
font-style: italic;
}
strong {
font-weight: bold;
}
img {
position: relative;
margin: 0 auto;
max-width: 739px;
padding: 5px;
margin: 10px 0 10px 0;
border: 1px solid #ebebeb;
box-shadow: 0 0 5px #ebebeb;
-webkit-box-shadow: 0 0 5px #ebebeb;
-moz-box-shadow: 0 0 5px #ebebeb;
-o-box-shadow: 0 0 5px #ebebeb;
-ms-box-shadow: 0 0 5px #ebebeb;
}
p img {
display: inline;
margin: 0;
padding: 0;
vertical-align: middle;
text-align: center;
border: none;
}
pre, code {
color: #222;
background-color: #fff;
font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace;
font-size: 14px;
border-radius: 2px;
-moz-border-radius: 2px;
-webkit-border-radius: 2px;
}
pre {
padding: 10px;
box-shadow: 0 0 10px rgba(0,0,0,.1);
overflow: auto;
}
code {
padding: 3px;
margin: 0 3px;
box-shadow: 0 0 10px rgba(0,0,0,.1);
}
pre code {
display: block;
box-shadow: none;
}
blockquote {
color: #666;
margin-bottom: 20px;
padding: 0 0 0 20px;
border-left: 3px solid #bbb;
}
ul, ol, dl {
margin-bottom: 15px
}
ul {
list-style-position: inside;
list-style: disc;
padding-left: 20px;
}
ol {
list-style-position: inside;
list-style: decimal;
padding-left: 20px;
}
dl dt {
font-weight: bold;
}
dl dd {
padding-left: 20px;
font-style: italic;
}
dl p {
padding-left: 20px;
font-style: italic;
}
hr {
height: 1px;
margin-bottom: 5px;
border: none;
background: url('../images/bg_hr.png') repeat-x center;
}
table {
border: 1px solid #373737;
margin-bottom: 20px;
text-align: left;
}
th {
font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif;
padding: 10px;
background: #373737;
color: #fff;
}
td {
padding: 10px;
border: 1px solid #373737;
}
form {
background: #f2f2f2;
padding: 20px;
}
/*******************************************************************************
Full-Width Styles
*******************************************************************************/
.outer {
width: 100%;
}
.inner {
position: relative;
max-width: 640px;
padding: 20px 10px;
margin: 0 auto;
}
#forkme_banner {
display: block;
position: absolute;
top:0;
right: 10px;
z-index: 10;
padding: 10px 50px 10px 10px;
color: #fff;
background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%;
font-weight: 700;
box-shadow: 0 0 10px rgba(0,0,0,.5);
border-bottom-left-radius: 2px;
border-bottom-right-radius: 2px;
}
#header_wrap {
background: #212121;
background: -moz-linear-gradient(top, #373737, #212121);
background: -webkit-linear-gradient(top, #373737, #212121);
background: -ms-linear-gradient(top, #373737, #212121);
background: -o-linear-gradient(top, #373737, #212121);
background: linear-gradient(top, #373737, #212121);
}
#header_wrap .inner {
padding: 50px 10px 30px 10px;
}
#project_title {
margin: 0;
color: #fff;
font-size: 42px;
font-weight: 700;
text-shadow: #111 0px 0px 10px;
}
#project_tagline {
color: #fff;
font-size: 24px;
font-weight: 300;
background: none;
text-shadow: #111 0px 0px 10px;
}
#downloads {
position: absolute;
width: 210px;
z-index: 10;
bottom: -40px;
right: 0;
height: 70px;
background: url('../images/icon_download.png') no-repeat 0% 90%;
}
.zip_download_link {
display: block;
float: right;
width: 90px;
height:70px;
text-indent: -5000px;
overflow: hidden;
background: url(../images/sprite_download.png) no-repeat bottom left;
}
.tar_download_link {
display: block;
float: right;
width: 90px;
height:70px;
text-indent: -5000px;
overflow: hidden;
background: url(../images/sprite_download.png) no-repeat bottom right;
margin-left: 10px;
}
.zip_download_link:hover {
background: url(../images/sprite_download.png) no-repeat top left;
}
.tar_download_link:hover {
background: url(../images/sprite_download.png) no-repeat top right;
}
#main_content_wrap {
background: #f2f2f2;
border-top: 1px solid #111;
border-bottom: 1px solid #111;
}
#main_content {
padding-top: 40px;
}
#footer_wrap {
background: #212121;
}
/*******************************************************************************
Small Device Styles
*******************************************************************************/
@media screen and (max-width: 992px) {
img {
max-width: 100%;
}
}
@media screen and (max-width: 480px) {
body {
font-size:14px;
}
#downloads {
display: none;
}
.inner {
min-width: 300px;
max-width: 480px;
}
#project_title {
font-size: 32px;
}
h1 {
font-size: 28px;
}
h2 {
font-size: 24px;
}
h3 {
font-size: 21px;
}
h4 {
font-size: 18px;
}
h5 {
font-size: 14px;
}
h6 {
font-size: 12px;
}
code, pre {
font-size: 11px;
}
}

209
_sass/rouge-github.scss Normal file
View File

@@ -0,0 +1,209 @@
.highlight table td { padding: 5px; }
.highlight table pre { margin: 0; }
.highlight .cm {
color: #777772;
font-style: italic;
}
.highlight .cp {
color: #797676;
font-weight: bold;
}
.highlight .c1 {
color: #777772;
font-style: italic;
}
.highlight .cs {
color: #797676;
font-weight: bold;
font-style: italic;
}
.highlight .c, .highlight .cd {
color: #777772;
font-style: italic;
}
.highlight .err {
color: #a61717;
background-color: #e3d2d2;
}
.highlight .gd {
color: #000000;
background-color: #ffdddd;
}
.highlight .ge {
color: #000000;
font-style: italic;
}
.highlight .gr {
color: #aa0000;
}
.highlight .gh {
color: #797676;
}
.highlight .gi {
color: #000000;
background-color: #ddffdd;
}
.highlight .go {
color: #888888;
}
.highlight .gp {
color: #555555;
}
.highlight .gs {
font-weight: bold;
}
.highlight .gu {
color: #aaaaaa;
}
.highlight .gt {
color: #aa0000;
}
.highlight .kc {
color: #000000;
font-weight: bold;
}
.highlight .kd {
color: #000000;
font-weight: bold;
}
.highlight .kn {
color: #000000;
font-weight: bold;
}
.highlight .kp {
color: #000000;
font-weight: bold;
}
.highlight .kr {
color: #000000;
font-weight: bold;
}
.highlight .kt {
color: #445588;
font-weight: bold;
}
.highlight .k, .highlight .kv {
color: #000000;
font-weight: bold;
}
.highlight .mf {
color: #009999;
}
.highlight .mh {
color: #009999;
}
.highlight .il {
color: #009999;
}
.highlight .mi {
color: #009999;
}
.highlight .mo {
color: #009999;
}
.highlight .m, .highlight .mb, .highlight .mx {
color: #009999;
}
.highlight .sb {
color: #d14;
}
.highlight .sc {
color: #d14;
}
.highlight .sd {
color: #d14;
}
.highlight .s2 {
color: #d14;
}
.highlight .se {
color: #d14;
}
.highlight .sh {
color: #d14;
}
.highlight .si {
color: #d14;
}
.highlight .sx {
color: #d14;
}
.highlight .sr {
color: #009926;
}
.highlight .s1 {
color: #d14;
}
.highlight .ss {
color: #990073;
}
.highlight .s {
color: #d14;
}
.highlight .na {
color: #008080;
}
.highlight .bp {
color: #797676;
}
.highlight .nb {
color: #0086B3;
}
.highlight .nc {
color: #445588;
font-weight: bold;
}
.highlight .no {
color: #008080;
}
.highlight .nd {
color: #3c5d5d;
font-weight: bold;
}
.highlight .ni {
color: #800080;
}
.highlight .ne {
color: #990000;
font-weight: bold;
}
.highlight .nf {
color: #990000;
font-weight: bold;
}
.highlight .nl {
color: #990000;
font-weight: bold;
}
.highlight .nn {
color: #555555;
}
.highlight .nt {
color: #000080;
}
.highlight .vc {
color: #008080;
}
.highlight .vg {
color: #008080;
}
.highlight .vi {
color: #008080;
}
.highlight .nv {
color: #008080;
}
.highlight .ow {
color: #000000;
font-weight: bold;
}
.highlight .o {
color: #000000;
font-weight: bold;
}
.highlight .w {
color: #bbbbbb;
}
.highlight {
background-color: #f8f8f8;
}

View File

@@ -1,34 +0,0 @@
{
"name": "tgvkbot",
"description": "Бот позволяет получать и отправлять сообщения VK находясь в Telegram",
"repository": "https://github.com/Kylmakalle/tgvkbot",
"keywords": ["vk", "bot", "telegram"],
"website": "https://asergey.me/tgvkbot/",
"buildpacks":[
{
"url": "heroku/python"
}
],
"env": {
"TELEGRAM_TOKEN": {
"description": "Telegram bot API токен от https://t.me/BotFather",
"value": "123456789:AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLL"
},
"VK_APP": {
"description": "ID VK приложения из https://vk.com/apps?act=manage",
"required": true
}
},
"addons": [
{
"plan": "heroku-redis:hobby-dev",
"as": "Redis"
}
],
"formation": {
"bot": {
"quantity": 1,
"size": "free"
}
}
}

5
assets/css/style.scss Normal file
View File

@@ -0,0 +1,5 @@
---
---
@import "jekyll-theme-slate";
@import "style.css";

BIN
assets/dialogs.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

BIN
assets/documents.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 142 KiB

BIN
assets/forwardvk.PNG Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
assets/groupmessage.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
assets/privatemessage.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

BIN
assets/rsz_dialogs (1).jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

BIN
assets/rsz_forwardtg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
assets/rsz_groupmessage.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
assets/rsz_reply.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

BIN
assets/rsz_search (1).jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

BIN
assets/rsz_sunset (1).jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

1
assets/sample.txt Normal file
View File

@@ -0,0 +1 @@

BIN
assets/sticker.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

BIN
assets/sunset.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

BIN
assets/vk_music.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

721
bot.py
View File

@@ -1,721 +0,0 @@
import os
import re
import redis
import requests
import telebot
import threading
import time
import traceback
import ujson
import vk
import wget
from PIL import Image
from telebot import types
from credentials import token, vk_app_id
from vk_messages import VkMessage, VkPolling
vk_threads = {}
vk_dialogs = {}
VK_API_VERSION = '3.0'
FILE_URL = 'https://api.telegram.org/file/bot{0}/{1}'
vk_tokens = redis.from_url(os.environ.get("REDIS_URL"))
currentchat = {}
bot = telebot.AsyncTeleBot(token)
bot.remove_webhook()
link = 'https://oauth.vk.com/authorize?client_id={}&' \
'display=page&redirect_uri=https://oauth.vk.com/blank.html&scope=friends,messages,offline,docs,photos,video' \
'&response_type=token&v={}'.format(vk_app_id, VK_API_VERSION)
def get_pages_switcher(markup, page, pages):
if page != 0:
leftbutton = types.InlineKeyboardButton('', callback_data='page{}'.format(page - 1)) # callback
else:
leftbutton = types.InlineKeyboardButton('Поиск 🔍', callback_data='search')
if page + 1 < len(pages):
rightbutton = types.InlineKeyboardButton('', callback_data='page{}'.format(page + 1))
else:
rightbutton = None
if rightbutton:
markup.row(leftbutton, rightbutton)
else:
markup.row(leftbutton)
def replace_shields(text):
text = text.replace('&lt;', '<')
text = text.replace('&gt;', '>')
text = text.replace('&amp;', '&')
text = text.replace('&copy;', '©')
text = text.replace('&reg;', '®')
text = text.replace('&laquo;', '«')
text = text.replace('&raquo;', '«')
text = text.replace('&deg;', '°')
text = text.replace('&trade;', '')
text = text.replace('&plusmn;', '±')
return text
def request_user_dialogs(session, userid):
order = []
users_ids = []
group_ids = []
positive_group_ids = []
api = vk.API(session, v=VK_API_VERSION)
dialogs = api.messages.getDialogs(count=200)
for chat in dialogs[1:]:
if 'chat_id' in chat:
chat['title'] = replace_shields(chat['title'])
order.append({'title': chat['title'], 'id': 'group' + str(chat['chat_id'])})
elif chat['uid'] > 0:
order.append({'title': None, 'id': chat['uid']})
users_ids.append(chat['uid'])
elif chat['uid'] < 0:
order.append({'title': None, 'id': chat['uid']})
group_ids.append(chat['uid'])
for g in group_ids:
positive_group_ids.append(str(g)[1:])
if users_ids:
users = api.users.get(user_ids=users_ids, fields=['first_name', 'last_name', 'uid'])
else:
users = []
if positive_group_ids:
groups = api.groups.getById(group_ids=positive_group_ids, fields=[])
else:
groups = []
for output in order:
if output['title'] == ' ... ' or not output['title']:
if output['id'] > 0:
for x in users:
if x['uid'] == output['id']:
output['title'] = '{} {}'.format(x['first_name'], x['last_name'])
break
else:
for f in groups:
if str(f['gid']) == str(output['id'])[1:]:
output['title'] = '{}'.format(f['name'])
break
for button in range(len(order)):
order[button] = types.InlineKeyboardButton(order[button]['title'], callback_data=str(order[button]['id']))
rows = [order[x:x + 2] for x in range(0, len(order), 2)]
pages = [rows[x:x + 4] for x in range(0, len(rows), 4)]
vk_dialogs[str(userid)] = pages
def create_markup(message, user, page, edit=False):
markup = types.InlineKeyboardMarkup(row_width=2)
for i in vk_dialogs[str(user)][page]:
markup.row(*i)
get_pages_switcher(markup, page, vk_dialogs[str(user)])
if edit:
bot.edit_message_text(
'<b>Выберите Диалог:</b> <code>{}/{}</code> стр.'.format(page + 1, len(vk_dialogs[str(user)])),
message.chat.id, message.message_id,
parse_mode='HTML', reply_markup=markup).wait()
else:
bot.send_message(message.from_user.id,
'<b>Выберите Диалог:</b> <code>{}/{}</code> стр.'.format(page + 1, len(vk_dialogs[str(user)])),
parse_mode='HTML', reply_markup=markup).wait()
def search_users(message, text):
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
markup = types.InlineKeyboardMarkup(row_width=1)
result = api.messages.searchDialogs(q=text, limit=10, fields=[])
for chat in result:
if chat['type'] == 'profile':
markup.add(types.InlineKeyboardButton('{} {}'.format(chat['first_name'], chat['last_name']),
callback_data=str(chat['uid'])))
elif chat['type'] == 'chat':
markup.add(
types.InlineKeyboardButton(replace_shields(chat['title']),
callback_data='group' + str(chat['chat_id'])))
if markup.keyboard:
markup.add(types.InlineKeyboardButton('Поиск 🔍', callback_data='search'))
bot.send_message(message.from_user.id, '<b>Результат поиска по</b> <i>{}</i>'.format(text),
reply_markup=markup, parse_mode='HTML')
else:
markup.add(types.InlineKeyboardButton('Поиск 🔍', callback_data='search'))
bot.send_message(message.from_user.id, '<b>Ничего не найдено по запросу</b> <i>{}</i>'.format(text),
parse_mode='HTML', reply_markup=markup)
@bot.callback_query_handler(func=lambda call: True)
def callback_buttons(call):
if call.message:
if 'page' in call.data:
try:
create_markup(call.message, call.from_user.id, int(call.data.split('page')[1]), True)
except:
session = VkMessage(vk_tokens.get(str(call.from_user.id))).session
request_user_dialogs(session, call.from_user.id)
create_markup(call.message, call.from_user.id, int(call.data.split('page')[1]), True)
bot.answer_callback_query(call.id).wait()
elif 'search' in call.data:
markup = types.ForceReply(selective=False)
bot.answer_callback_query(call.id, 'Поиск беседы 🔍').wait()
bot.send_message(call.from_user.id, '<b>Поиск беседы</b> 🔍',
parse_mode='HTML', reply_markup=markup).wait()
elif 'group' in call.data:
session = VkMessage(vk_tokens.get(str(call.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
chat = api.messages.getChat(chat_id=call.data.split('group')[1], fields=[])
bot.answer_callback_query(call.id,
'Вы в беседе {}'.format(replace_shields(chat['title']))).wait()
bot.send_message(call.from_user.id,
'<i>Вы в беседе {}</i>'.format(chat['title']),
parse_mode='HTML').wait()
currentchat[str(call.from_user.id)] = {'title': chat['title'], 'id': 'group' + str(chat['chat_id'])}
elif call.data.lstrip('-').isdigit():
session = VkMessage(vk_tokens.get(str(call.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
if '-' in call.data:
user = api.groups.getById(group_id=call.data.lstrip('-'), fields=[])[0]
user = {'first_name': user['name'], 'last_name': ''}
else:
user = api.users.get(user_ids=call.data, fields=[])[0]
bot.answer_callback_query(call.id,
'Вы в чате с {} {}'.format(user['first_name'], user['last_name'])).wait()
bot.send_message(call.from_user.id,
'<i>Вы в чате с {} {}</i>'.format(user['first_name'], user['last_name']),
parse_mode='HTML').wait()
currentchat[str(call.from_user.id)] = {'title': user['first_name'] + ' ' + user['last_name'],
'id': call.data}
def create_thread(uid, vk_token):
a = VkPolling()
longpoller = VkMessage(vk_token)
t = threading.Thread(name='vk' + str(uid), target=a.run, args=(longpoller, bot, uid,))
t.setDaemon(True)
t.start()
vk_threads[str(uid)] = a
vk_tokens.set(str(uid), vk_token)
session = longpoller.session
api = vk.API(session, v=VK_API_VERSION)
api.account.setOffline()
def check_thread(uid):
for th in threading.enumerate():
if th.getName() == 'vk' + str(uid):
return False
return True
# Creating VkPolling threads and dialogs info after bot's reboot/exception using existing tokens
def thread_reviver(uid):
tries = 0
while check_thread(uid.decode("utf-8")):
if tries < 4:
try:
create_thread(uid.decode("utf-8"), vk_tokens.get(uid))
except:
time.sleep(10)
tries = tries + 1
else:
mark = types.InlineKeyboardMarkup()
login = types.InlineKeyboardButton('ВХОД', url=link)
mark.add(login)
bot.send_message(uid.decode("utf-8"), '<b>Непредвиденная ошибка, требуется повторный логин ВК!</b>',
parse_mode='HTML', reply_markup=mark).wait()
break
def thread_supervisor():
while True:
for uid in vk_tokens.scan_iter():
reviver_thread = threading.Thread(name='reviver' + str(uid.decode('utf-8')), target=thread_reviver,
args=(uid,))
reviver_thread.setDaemon(True)
reviver_thread.start()
time.sleep(60)
supervisor = threading.Thread(name='supervisor', target=thread_supervisor)
supervisor.setDaemon(True)
supervisor.start()
def stop_thread(message):
for th in threading.enumerate():
if th.getName() == 'vk' + str(message.from_user.id):
t = vk_threads[str(message.from_user.id)]
t.terminate()
th.join()
vk_tokens.delete(str(message.from_user.id))
vk_dialogs.pop(str(message.from_user.id), None)
currentchat.pop(str(message.from_user.id), None)
def extract_unique_code(text):
# Extracts the unique_code from the sent /start command.
try:
return text[45:].split('&')[0]
except:
return None
def verifycode(code):
session = vk.Session(access_token=code)
api = vk.API(session, v=VK_API_VERSION)
return dict(api.account.getProfileInfo(fields=[]))
def info_extractor(info):
info = info[-1].url[8:-1].split('.')
return info
@bot.message_handler(commands=['chat'])
def chat_command(message):
if logged(message):
if str(message.from_user.id) in currentchat:
if 'group' in currentchat[str(message.from_user.id)]['id']:
chat = currentchat[str(message.from_user.id)]
bot.send_message(message.from_user.id,
'<i>Вы в беседе {}</i>'.format(chat['title']),
parse_mode='HTML').wait()
else:
chat = currentchat[str(message.from_user.id)]
bot.send_message(message.from_user.id,
'<i>Вы в чате с {}</i>'.format(chat['title']),
parse_mode='HTML').wait()
else:
bot.send_message(message.from_user.id,
'<i>Вы не находитесь в чате</i>',
parse_mode='HTML').wait()
@bot.message_handler(commands=['leave'])
def leave_command(message):
if logged(message):
if str(message.from_user.id) in currentchat:
currentchat.pop(str(message.from_user.id), None)
bot.send_message(message.from_user.id,
'<i>Вы вышли из чата</i>',
parse_mode='HTML').wait()
else:
bot.send_message(message.from_user.id,
'<i>Вы не находитесь в чате</i>',
parse_mode='HTML').wait()
@bot.message_handler(commands=['dialogs'])
def dialogs_command(message):
if logged(message):
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
request_user_dialogs(session, message.from_user.id)
create_markup(message, message.from_user.id, 0)
@bot.message_handler(commands=['search'])
def search_command(message):
if logged(message):
markup = types.ForceReply(selective=False)
if telebot.util.extract_arguments(message.text):
search_users(message, telebot.util.extract_arguments(message.text))
else:
bot.send_message(message.from_user.id, '<b>Поиск беседы</b> 🔍',
parse_mode='HTML', reply_markup=markup).wait()
@bot.message_handler(commands=['stop'])
def stop_command(message):
if not check_thread(message.from_user.id):
stop_thread(message)
bot.send_message(message.from_user.id, 'Успешный выход!').wait()
else:
bot.send_message(message.from_user.id, 'Вход не был выполнен!').wait()
@bot.message_handler(commands=['start'])
def start_command(message):
if check_thread(message.from_user.id):
mark = types.InlineKeyboardMarkup()
login = types.InlineKeyboardButton('ВХОД', url=link)
mark.add(login)
bot.send_message(message.from_user.id,
'Привет, этот бот поможет тебе общаться ВКонтакте, войди по кнопке ниже'
' и отправь мне то, что получишь в адресной строке.',
reply_markup=mark).wait()
else:
bot.send_message(message.from_user.id, 'Вход уже выполнен!\n/stop для выхода.').wait()
def form_request(message, method, info):
if int(info[2]):
if message.text and message.text.startswith('!'):
if len(message.text) - 1:
message.text = message.text[1:]
if info[2] != 'None':
method(message, info[1], group=True, forward_messages=info[2])
else:
method(message, info[1], group=True)
elif message.caption and message.caption.startswith('!'):
if len(message.caption) - 1:
message.caption = message.caption[1:]
if info[2] != 'None':
method(message, info[1], group=True, forward_messages=info[2])
else:
method(message, info[1], group=True)
else:
if message.text and message.text.startswith('!'):
if len(message.text) - 1:
message.text = message.text[1:]
if info[1] != 'None':
method(message, info[0], group=False, forward_messages=info[1])
else:
method(message, info[0], group=False)
elif message.caption and message.caption.startswith('!'):
if len(message.caption) - 1:
message.caption = message.caption[1:]
if info[1] != 'None':
method(message, info[0], group=False, forward_messages=info[1])
else:
method(message, info[0], group=False)
else:
method(message, info[0], group=False)
def logged(message):
if vk_tokens.get(str(message.from_user.id)):
return True
else:
bot.send_message(message.from_user.id, 'Вход не выполнен! /start для входа').wait()
return False
def vk_sender(message, method):
if logged(message):
if message.reply_to_message:
info = info_extractor(message.reply_to_message.entities)
if info is not None:
form_request(message, method, info)
elif str(message.from_user.id) in currentchat:
info = []
if 'group' in currentchat[str(message.from_user.id)]['id']:
info.append('0')
info.append(currentchat[str(message.from_user.id)]['id'].split('group')[1])
info.append('1')
else:
info.append(currentchat[str(message.from_user.id)]['id'])
info.append('0')
info.append('0')
form_request(message, method, info)
def audio_title_creator(message, performer=None, title=None):
if not performer and not title:
return 'Аудио_{}'.format(str(message.date)[5:])
else:
return '{} - {}'.format(performer, title)
def send_text(message, userid, group, forward_messages=None):
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
if group:
api.messages.send(chat_id=userid, message=message.text, forward_messages=forward_messages)
else:
api.messages.send(user_id=userid, message=message.text, forward_messages=forward_messages)
def send_doc(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
if filetype == 'document' and 'video' not in message.document.mime_type:
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path))
openedfile = open(file, 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(api.docs.getUploadServer()['upload_url'],
files=files).text)
attachment = api.docs.save(file=fileonserver['file'],
title=getattr(message, filetype).file_name,
tags='')
openedfile.close()
os.remove(file)
elif filetype == 'voice':
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path))
openedfile = open(file, 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(
requests.post(api.docs.getUploadServer(type='audio_message')['upload_url'],
files=files).text)
attachment = api.docs.save(file=fileonserver['file'], title='Аудиосообщение',
tags='')
openedfile.close()
os.remove(file)
elif filetype == 'document' and 'video' in message.document.mime_type:
vk_sender(message, send_video)
return
else: # filetype == 'audio':
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path))
newfile = file.split('.')[0] + '.aac'
os.rename(file, newfile)
openedfile = open(newfile, 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(api.docs.getUploadServer()['upload_url'],
files=files).text)
attachment = api.docs.save(file=fileonserver['file'],
title=audio_title_creator(message, message.audio.performer,
message.audio.title), tags='')
openedfile.close()
os.remove(newfile)
if group:
if message.caption:
api.messages.send(chat_id=userid, message=message.caption,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
else:
api.messages.send(chat_id=userid,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
else:
if message.caption:
api.messages.send(user_id=userid, message=message.caption,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
else:
api.messages.send(user_id=userid,
attachment='doc{}_{}'.format(attachment[0]['owner_id'],
attachment[0]['did']),
forward_messages=forward_messages)
def send_photo(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype)[-1].file_id).wait().file_path))
openedfile = open(file, 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(api.photos.getMessagesUploadServer()['upload_url'],
files=files).text)
attachment = api.photos.saveMessagesPhoto(server=fileonserver['server'], photo=fileonserver['photo'],
hash=fileonserver['hash'])
if group:
if message.caption:
api.messages.send(chat_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
api.messages.send(chat_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
if message.caption:
api.messages.send(user_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
api.messages.send(user_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
openedfile.close()
os.remove(file)
def send_sticker(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path))
Image.open(file).save("{}.png".format(file))
openedfile = open('{}.png'.format(file), 'rb')
files = {'file': openedfile}
fileonserver = ujson.loads(requests.post(api.photos.getMessagesUploadServer()['upload_url'],
files=files).text)
attachment = api.photos.saveMessagesPhoto(server=fileonserver['server'], photo=fileonserver['photo'],
hash=fileonserver['hash'])
if group:
if message.caption:
api.messages.send(chat_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
api.messages.send(chat_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
if message.caption:
api.messages.send(user_id=userid, message=message.caption, attachment=attachment[0]['id'],
forward_messages=forward_messages)
else:
api.messages.send(user_id=userid, attachment=attachment[0]['id'],
forward_messages=forward_messages)
openedfile.close()
os.remove('{}.png'.format(file))
os.remove(file)
def send_video(message, userid, group, forward_messages=None):
filetype = message.content_type
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
file = wget.download(
FILE_URL.format(token, bot.get_file(getattr(message, filetype).file_id).wait().file_path))
openedfile = open(file, 'rb')
files = {'video_file': openedfile}
if group:
attachment = api.video.save(is_private=1)
fileonserver = ujson.loads(requests.post(attachment['upload_url'],
files=files).text)
video = 'video{}_{}'.format(attachment['owner_id'], attachment['owner_id']['video_id'])
if message.caption:
api.messages.send(chat_id=userid, message=message.caption, attachment=video,
forward_messages=forward_messages)
else:
api.messages.send(chat_id=userid, attachment=video, forward_messages=forward_messages)
else:
attachment = api.video.save(is_private=1)
fileonserver = ujson.loads(requests.post(attachment['upload_url'],
files=files).text)
video = 'video{}_{}'.format(attachment['owner_id'], attachment['vid'])
if message.caption:
api.messages.send(user_id=userid, message=message.caption, attachment=video,
forward_messages=forward_messages)
else:
api.messages.send(user_id=userid, attachment=video, forward_messages=forward_messages)
openedfile.close()
os.remove(file)
def send_contact(message, userid, group, forward_messages=None):
session = VkMessage(vk_tokens.get(str(message.from_user.id))).session
api = vk.API(session, v=VK_API_VERSION)
if message.contact.last_name:
text = 'Контакт: {} {}'.format(message.contact.first_name, message.contact.last_name)
else:
text = 'Контакт: {}'.format(message.contact.first_name)
if group:
api.messages.send(chat_id=userid, message=text, forward_messages=forward_messages)
api.messages.send(chat_id=userid, message=message.contact, forward_messages=forward_messages)
else:
api.messages.send(user_id=userid, message=text, forward_messages=forward_messages)
api.messages.send(chat_id=userid, message=message.contact, forward_messages=forward_messages)
@bot.message_handler(content_types=['document', 'voice', 'audio'])
def reply_document(message):
try:
vk_sender(message, send_doc)
except:
bot.reply_to(message, 'Файл слишком большой, максимально допустимый размер *20мб*!',
parse_mode='Markdown').wait()
@bot.message_handler(content_types=['sticker'])
def reply_sticker(message):
try:
vk_sender(message, send_sticker)
except Exception:
bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*',
parse_mode='Markdown').wait() # TODO?: Bugreport system
print('Error: {}'.format(traceback.format_exc()))
@bot.message_handler(content_types=['photo'])
def reply_photo(message):
try:
vk_sender(message, send_photo)
except:
bot.send_message(message.from_user.id, 'Фото слишком большое, максимально допустимый размер *20мб*!',
parse_mode='Markdown').wait()
@bot.message_handler(content_types=['video', 'video_note'])
def reply_video(message):
try:
vk_sender(message, send_video)
except:
bot.reply_to(message, 'Файл слишком большой, максимально допустимый размер *20мб*!',
parse_mode='Markdown').wait()
@bot.message_handler(content_types=['contact'])
def reply_contact(message):
try:
vk_sender(message, send_contact)
except Exception:
bot.reply_to(message, '*Произошла неизвестная ошибка при отправке*',
parse_mode='Markdown').wait()
print('Error: {}'.format(traceback.format_exc()))
@bot.message_handler(content_types=['text'])
def reply_text(message):
m = re.search('https://oauth\.vk\.com/blank\.html#access_token=[a-z0-9]*&expires_in=[0-9]*&user_id=[0-9]*',
message.text)
if m:
code = extract_unique_code(m.group(0))
if check_thread(message.from_user.id):
try:
user = verifycode(code)
create_thread(message.from_user.id, code)
bot.send_message(message.from_user.id,
'Вход выполнен в аккаунт {} {}!'.format(user['first_name'], user['last_name'])).wait()
bot.send_message(message.from_user.id, '[Использование](https://asergey.me/tgvkbot/usage/)',
parse_mode='Markdown').wait()
except:
bot.send_message(message.from_user.id, 'Неверная ссылка, попробуй ещё раз!').wait()
else:
bot.send_message(message.from_user.id, 'Вход уже выполнен!\n/stop для выхода.').wait()
elif message.reply_to_message and message.reply_to_message.text == 'Поиск беседы 🔍':
search_users(message, message.text)
else:
try:
vk_sender(message, send_text)
except Exception:
bot.reply_to(message, 'Произошла неизвестная ошибка при отправке',
parse_mode='Markdown').wait()
bot.polling(none_stop=True)
"""class WebhookServer(object):
# index равнозначно /, т.к. отсутствию части после ip-адреса (грубо говоря)
@cherrypy.expose
def index(self):
length = int(cherrypy.request.headers['content-length'])
json_string = cherrypy.request.body.read(length).decode("utf-8")
update = telebot.types.Update.de_json(json_string)
bot.process_new_updates([update])
return ''
if __name__ == '__main__':
logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log')
bot.remove_webhook()
bot.set_webhook('https://{}/{}/'.format(bot_url, token))
cherrypy.config.update(
{'server.socket_host': '127.0.0.1', 'server.socket_port': local_port, 'engine.autoreload.on': False,
'log.screen': False})
cherrypy.quickstart(WebhookServer(), '/', {'/': {}})"""

View File

@@ -1,3 +0,0 @@
import os
token = os.environ['TELEGRAM_TOKEN']
vk_app_id = os.environ['VK_APP']

77
installation/README.md Normal file
View File

@@ -0,0 +1,77 @@
# Создание и развёртывание бота.
В первую очередь, _почему же нужно создавать именно своего бота?_
- Ограничения <a href="https://core.telegram.org/bots/faq#broadcasting-to-users" target="_blank">Telegram</a>
- Ограничения <a href="https://vk.com/dev/api_requests?f=3.1.%20%D0%A7%D0%B0%D1%81%D1%82%D0%BE%D1%82%
D0%BD%D1%8B%D0%B5%20%D0%BE%D0%B3%D1%80%D0%B0%D0%BD%D0%B8%D1%87%D0%B5%D0%BD%D0%B8%D1%8F" target="_blank">VK</a>
- Гарантия сохранности переписки и полного контроля над ботом
Бот имеет полностью открытый исходный код, с которым можно ознакомиться перейдя по ссылке _View on GitHub_ в верхнем углу станицы.
# ⚠️ ВНИМАНИЕ
Гайд далее рассказывает об устаревшем методе установки бота на heroku. К сожалению, пришлось забросить такой вариант из-за модификаций бота и отключения старых VK API. Исходники старого бота лежат в ветке [heroku-old](https://github.com/Kylmakalle/tgvkbot/tree/heroku-old)
Для энтузиастов есть [инструкция](https://github.com/Kylmakalle/tgvkbot/blob/master/README.md) по установке бота на свой сервер.
Если вы боитесь командной строки, рекомендую воспользоваться готовым ботом от разработчика [@tgVKbot](https://t.me/tgVKbot)
## Heroku
Развёртывать бота мы будем на Heroku, поэтому там нужно завести аккаунт <a href="https://heroku.com" target="_blank">heroku.com</a>
Т.к мы будем использовать бесплатный тип хостинга, то на него накладываются некоторые <a href="https://devcenter.heroku.com/articles/free-dyno-hours#usage" target="_blank">ограничения</a>, дабы частично их смягчить можно <a href="https://dashboard.heroku.com/account/billing" target="_blank">привязать карту</a> (никаких плат не взимается), тогда бот сможет работать полный месяц без остановок (а не предусмотренные 550ч/мес изначально)
Подробнее можно ознакомиться <a href="https://devcenter.heroku.com/articles/free-dyno-hours" target="_blank">тут</a>
## VK
По <a href="https://vk.com/editapp?act=create" target="_blank">ссылке</a> нужно создать своё Standalone-приложение, затем во вкладке _Настройки_ перевести _Состояние_ в риложение включено и видно всем_, не забудьте сохранить изменения!
На этом этапе мы сохраняем себе куда-нибудь **ID приложения**
## Telegram
<a href="https://t.me/BotFather" target="_blank">Создаём бота</a>, в качестве имени удобно будет использовать _VK_, юзернейм роли не играет. Сохраняем **токен бота**, который мы получили от BotFather
_Опционально:_
Настройка команд бота
```
dialogs - Список диалогов
search - Поиск диалогов
chat - Текущий чат
leave - Покинуть текущий чат
start - Подключить ВК
stop - Отключить ВК
```
[Логотип VK](vklogo.jpg) для аватарки бота.
<h2><a name="heroku--vk--telegram"></a>Heroku + VK + Telegram</h2>
Получив ID приложения и токен бота, можно смело начинать развёртывать бота на Heroku.
Нажав на кнопку ниже вы попадёте на страницу развёртывания, где будут поля:
[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy?template=https://github.com/Kylmakalle/tgvkbot/tree/master)
- **Имя приложения** - можно оставить пустым, Heroku выберет за вас.
- **Регион развёртывания** - выбираем Европу, чтобы бот был пошустрее.
- **Telegram API Token** - токен бота полученный ранее.
- **VK APP ID** - ID приложения ВКонтакте полученный ранее.
После успешного развёртывания можно смело пользоваться ботом.
Если вы вдруг что-то напутали с токеном и/или ID, их всегда можно настроить перейдя в _Settings->Config Vars_ соответствующего приложения в своей панели управления <a href="https://dashboard.heroku.com/ " target="_blank">dashboard.heroku.com</a>
Если всё прошло гладко, то можно ознакомиться с [Использованием](/tgvkbot/usage/)
## Обновление
Обо всех **ВАЖНЫХ** обновлениях можно будет узнать в <a href="https://t.me/tg_vk" target="_blank">Telegram канале</a>
К сожалению простого механизма обновления бота нет и не предусмотрено, поэтому единственный способ - повторное <a href="#heroku--vk--telegram">развёртывание</a> бота на Heroku с уже имеющимися токеном бота и ID приложения из VK.
При обновлении **обязательно** удалить предыдущее приложение с ботом на Heroku. Делается это в _Settings_ соответствующего приложения, в самом низу страницы. После обновления не забудьте заново залогиниться ВК с помощью `/start`

BIN
installation/vklogo.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -1,6 +0,0 @@
pyTelegramBotAPI
vk
redis
Pillow
ujson
wget

View File

@@ -1 +0,0 @@
python-3.6.1

43
usage/README.md Normal file
View File

@@ -0,0 +1,43 @@
# Использование
Команды:
`/start` - Логин ВКонтакте.
`/dialogs` - Вывод меню со списком диалогов.
`/search Иван` - Поиск диалогов по запросу (в данном случае `Иван`), при вызове команды без запроса бот автоматически спросит что искать, следующим шагом можно будет ввести запрос.
Поддерживаются части слов, транслит, а так же абракадабра, которую вы ненароком напишете забыв сменить раскладку.
`/chat` - Бот сообщает о том. в каком чате вы сейчас находитесь, все дальнеёшие сообщения без _Reply_ будут отправляться именно в этот чат.
`/leave` - Вы покидаете текущий чат, дальнейшее общение происходит только с помощью _Reply_ (или при выборе чата из `/search`, `/dialogs`)
`/stop` - Выход из ВКонтакте, бот полностью стирает всю информацию, для дальнейшей работы требуется повторная инициализация `/start`
Бот отправляет личные сообщения в таком виде:
<p align="center"><img src ="/tgvkbot/assets/rsz_privatemessage.jpg" /></p>
Для сообщений из групповых чатов будет указываться чат после имени отправителя
<p align="center"><img src ="/tgvkbot/assets/rsz_groupmessage.jpg" /></p>
Ответ в чат откуда пришло сообщение (ЛС/Беседа) производится с помощью функции _Reply_ в самом _Telegram_
<p align="center"><img src ="/tgvkbot/assets/rsz_reply.jpg" /></p>
Однако, не нужно делать _Reply_ если вы находитесь в определённом чате (проверить можно командой `/chat`)
**Пример:** Если вы находитесь в чате А и вам пришло сообщение из чата Б, то сделав _Reply_ на сообщение из чата Б, вы отправите сообщение в чат Б и **сообщение отправится только в чат Б, без дублей в чат А!** При этом вы останетесь в чате А и сможете дальше продолжить общаться в чате А без использования _Reply_.
Тем самым **функция Reply имеет приоритет!**
Для "пересылки" сообшения написанного ВК в сам чат ВК, нужно написать `!` первым символом в сообщении (подписи к фото/документу) отправленного из Telegram.
<p align="center"><img src ="/tgvkbot/assets/rsz_forwardtg.jpg" /></p>
<p align="center"><img src ="/tgvkbot/assets/forwardvk.PNG" /></p>
По возможности бот будет отправлять вложения из ВК как документы, или давать ссылку с превью. Если же это невозможно, бот даст прямую ссылку на файл. <del>Исключение на получение <a href="https://vc.ru/n/vk-music-noapi" target="_blank">аудио</a>, для них будет даваться ссылка на раздел аудио VK.</del> Отправка музыкальных файлов из Telegram **поддерживается**, однако вся музыка конвертируется в расширение `.aac` GIF из Telegram отправляются как видео VK.
- [Канал в Telegram](https://t.me/tg_vk) - обновления, поддержа

View File

@@ -1,367 +0,0 @@
import logging
import os
import redis
import requests
import time
import ujson
import vk
import wget
VK_POLLING_VERSION = '3.0'
logging.basicConfig(format='%(levelname)-8s [%(asctime)s] %(message)s', level=logging.WARNING, filename='vk.log')
vk_tokens = redis.from_url(os.environ.get("REDIS_URL"))
class VkPolling:
def __init__(self):
self._running = True
def terminate(self):
self._running = False
def run(self, vk_user, bot, chat_id):
while self._running:
timeout = 30
try:
updates = vk_user.get_new_messages()
if updates:
handle_updates(vk_user, bot, chat_id, updates)
except requests.exceptions.ReadTimeout:
logging.warning('Retrying VK Polling.')
timeout = 0
for i in range(timeout):
if self._running:
time.sleep(0.1)
else:
break
def handle_messages(m, vk_user, bot, chat_id, mainmessage=None):
api = vk.API(vk_user.session, v=VK_POLLING_VERSION)
if m['uid'] > 0:
user = api.users.get(user_ids=m["uid"], fields=[])[0]
else:
group = api.groups.getById(group_ids=str(m['uid'])[1:])[0]
user = {'first_name': group['name'], 'last_name': None}
if 'body' in m and not 'attachment' in m and not 'geo' in m and not 'fwd_messages' in m:
data = add_user_info(m, user["first_name"], user["last_name"])[:-1] + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
if 'attachment' in m:
attachment_handler(m, user, bot, chat_id, mainmessage)
if 'geo' in m:
data = add_user_info(m, user["first_name"], user["last_name"]) + '<i>Местоположение</i>' + add_reply_info(m)
geo = bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
if 'place' in m['geo'] and 'city' in m['geo']['place'] and 'title' in m[geo]['place']:
bot.send_venue(chat_id, m['geo']['coordinates'].split(' ')[0], m['geo']['coordinates'].split(' ')[1],
m['geo']['place']['title'], m['geo']['place']['city'],
disable_notification=check_notification(m),
reply_to_message_id=geo.message_id).wait()
else:
bot.send_location(chat_id, m['geo']['coordinates'].split(' ')[0], m['geo']['coordinates'].split(' ')[1],
disable_notification=check_notification(m),
reply_to_message_id=geo.message_id).wait()
if 'fwd_messages' in m:
data = add_user_info(m, user["first_name"],
user["last_name"]) + '<i>Пересланные сообщения</i>' + add_reply_info(m)
reply = bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait().message_id
for forwared in m['fwd_messages']:
handle_messages(forwared, vk_user, bot, chat_id, reply)
def handle_updates(vk_user, bot, chat_id, updates):
for m in updates:
if not m['out']:
handle_messages(m, vk_user, bot, chat_id)
def attachment_handler(m, user, bot, chat_id, mainmessage=None):
for attach in m['attachments']:
if attach['type'] == 'photo':
try:
data = add_user_info(m, user['first_name'], user['last_name']) + '<a href="{}">Фото</a>'.format(
get_max_src(attach['photo'])) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
except:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['type'] == 'video':
try:
link = 'https://vk.com/video{}_{}'.format(attach['video']['owner_id'],
attach['video']['vid'])
data = add_user_info(m, user['first_name'], user['last_name']) + '<a href="{}">Видео</a>'.format(
link) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
except:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['type'] == 'audio':
headers = {'content-type': 'application/json'}
audio = requests.get('https://asergey.me/vkmusapi/',
json={'aid': attach['audio']['aid'], 'owner_id': attach['audio']['owner_id']},
headers=headers)
try:
if audio.status_code == 200 and audio.json()['ok']:
audio_dict = audio.json()
data = add_user_info(m, user["first_name"],
user["last_name"]) + '🎧 <i>Аудиозапись</i>' + add_reply_info(m)
audio_msg = bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
action = bot.send_chat_action(chat_id, 'upload_document')
bot.send_audio(chat_id, audio_dict['vk_response']['url'],
duration=audio_dict['vk_response']['duration'],
title=audio_dict['vk_response']['title'],
performer=audio_dict['vk_response']['artist'],
disable_notification=check_notification(m),
reply_to_message_id=audio_msg.message_id).wait()
action.wait()
else:
data = add_user_info(m, user['first_name'], user[
'last_name']) + '🎧 <a href="https://m.vk.com/audio?q={}%20-%20{}">{} - {}</a>'.format(
attach['audio']['artist'].replace(' ', '%20'),
attach['audio']['title'].replace(' ', '%20'), attach['audio']['artist'],
attach['audio']['title']) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
except Exception as e:
print(e)
data = add_user_info(m, user['first_name'], user[
'last_name']) + '🎧 <a href="https://m.vk.com/audio?q={}%20-%20{}">{} - {}</a>'.format(
attach['audio']['artist'].replace(' ', '%20'),
attach['audio']['title'].replace(' ', '%20'), attach['audio']['artist'],
attach['audio']['title']) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
elif attach['type'] == 'doc':
if attach['doc']['ext'] == 'gif':
try:
link = attach['doc']['url']
data = add_user_info(m, user["first_name"], user["last_name"]) + '<a href="{}">GIF</a>'.format(
link) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
except:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['doc']['ext'] == 'pdf' or attach['doc']['ext'] == 'zip':
try:
link = attach['doc']['url']
data = add_user_info(m, user["first_name"],
user["last_name"]) + '<a href="{}">Документ</a>'.format(
link) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
except:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['doc']['ext'] == 'jpg' or attach['doc']['ext'] == 'png':
try:
link = attach['doc']['url']
data = add_user_info(m, user["first_name"],
user["last_name"], ) + '<i>Документ</i>' + add_reply_info(m)
notification = bot.send_message(chat_id, data, parse_mode='HTML',
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
uploading = bot.send_chat_action(chat_id, 'upload_document')
bot.send_document(chat_id, link, reply_to_message_id=notification.message_id,
disable_notification=check_notification(m)).wait()
uploading.wait()
except:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['doc']['ext'] == 'ogg':
try:
link = attach['doc']['url']
data = add_user_info(m, user["first_name"], user["last_name"], ) + \
'<a href="{}">Аудио</a>'.format(link) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
except:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['doc']['ext'] == 'doc' or attach['doc']['ext'] == 'docx':
try:
data = add_user_info(m, user["first_name"],
user["last_name"], ) + '<i>Документ</i>' + add_reply_info(m)
notification = bot.send_message(chat_id, data, parse_mode='HTML',
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
uploading = bot.send_chat_action(chat_id, 'upload_document')
file = wget.download(requests.get(attach['doc']['url']).url)
openedfile = open(file, 'rb')
bot.send_document(chat_id, openedfile,
reply_to_message_id=notification.message_id,
disable_notification=check_notification(m)).wait()
uploading.wait()
openedfile.close()
os.remove(file)
except:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
else:
send_doc_link(attach, m, user, bot, chat_id, mainmessage)
elif attach['type'] == 'sticker':
link = attach['sticker']['photo_512']
data = add_user_info(m, user["first_name"], user["last_name"]) + '<a href="{}">Стикер</a>'.format(
link) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
elif attach['type'] == 'wall':
link = 'https://vk.com/wall{}_{}'.format(attach['wall']['from_id'], attach['wall']['id'])
data = add_user_info(m, user["first_name"], user["last_name"]) + '<a href="{}">Запись на стене</a>'.format(
link) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
elif attach['type'] == 'wall_reply':
data = add_user_info(m, user["first_name"],
user["last_name"]) + '<i>Комментарий на стене</i>' + add_reply_info(m)
comment = bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=mainmessage).wait()
try:
api = vk.API(get_session(vk_tokens.get(str(chat_id))), v=VK_POLLING_VERSION)
user = api.users.get(user_ids=attach['wall_reply']["uid"], fields=[])[0]
if attach['wall_reply']['text']:
data = add_user_info(m, user["first_name"], user["last_name"]) + \
attach['wall_reply']['text'].replace('<br>', '\n') + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=comment.message_id).wait()
if 'attachments' in attach['wall_reply']:
attachment_handler(attach['wall_reply'], user, bot, chat_id, mainmessage=comment.message_id)
except:
link = 'https://vk.com/wall{}_{}'.format(attach['wall']['owner_id'], attach['wall']['cid'])
data = add_user_info(m, user["first_name"],
user["last_name"]) + '<a href="{}">Комментарий</a>'.format(
link) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m),
reply_to_message_id=comment.message_id).wait()
def check_expansion(document):
if len(document['doc']['title'].split('.')) - 1:
return document['doc']['title']
else:
return document['doc']['title'] + '.' + document['doc']['ext']
def send_doc_link(doc, m, user, bot, chat_id, mainmessage=None):
link = doc['doc']['url']
data = add_user_info(m, user["first_name"], user["last_name"]) + \
'<i>Документ</i>\n<a href="{}">{}</a>'.format(link, check_expansion(doc)) + add_reply_info(m)
bot.send_message(chat_id, data, parse_mode='HTML', disable_web_page_preview=False,
disable_notification=check_notification(m), reply_to_message_id=mainmessage).wait()
def check_forward_id(msg):
if 'mid' in msg:
return msg['mid']
else:
return None
def add_reply_info(m):
if 'chat_id' in m:
return '<a href="x{}.{}.{}">&#8203;</a>'.format(m['uid'], m['chat_id'], check_forward_id(m))
else:
return '<a href="x{}.{}.00">&#8203;</a>'.format(m['uid'], check_forward_id(m))
def add_user_info(m, first_name, last_name):
if 'body' in m and m['body']:
if last_name:
if 'chat_id' in m:
return '<b>{} {} @ {}:</b>\n{}\n'.format(first_name, last_name, m['title'],
m['body'].replace('<br>', '\n'))
else:
return '<b>{} {}:</b>\n{}\n'.format(first_name, last_name, m['body'].replace('<br>', '\n'))
else:
if 'chat_id' in m:
return '<b>{} @ {}:</b>\n{}\n'.format(first_name, m['title'],
m['body'].replace('<br>', '\n'))
else:
return '<b>{}:</b>\n{}\n'.format(first_name, m['body'].replace('<br>', '\n'))
else:
if last_name:
if 'chat_id' in m:
return '<b>{} {} @ {}:</b>\n'.format(first_name, last_name, m['title'])
else:
return '<b>{} {}:</b>\n'.format(first_name, last_name)
else:
if 'chat_id' in m:
return '<b>{} @ {}:</b>\n'.format(first_name, m['title'])
else:
return '<b>{}:</b>\n'.format(first_name)
def check_notification(value):
if 'push_settings' in value:
return True
else:
return False
def get_max_src(attachment):
if 'src_xxbig' in attachment:
return attachment['src_xxbig']
if 'src_xbig' in attachment:
return attachment['src_xbig']
if 'src_big' in attachment:
return attachment['src_big']
if 'src' in attachment:
return attachment['src']
class VkMessage:
def __init__(self, token):
self.session = get_session(token)
self.ts, self.pts = get_tses(self.session)
def get_new_messages(self):
api = vk.API(self.session, v=VK_POLLING_VERSION)
try:
ts_pts = ujson.dumps({"ts": self.ts, "pts": self.pts})
new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts))
except vk.api.VkAPIError:
timeout = 3
logging.warning('Retrying getLongPollHistory in {} seconds'.format(timeout))
time.sleep(timeout)
self.ts, self.pts = get_tses(self.session)
ts_pts = ujson.dumps({"ts": self.ts, "pts": self.pts})
new = api.execute(code='return API.messages.getLongPollHistory({});'.format(ts_pts))
msgs = new['messages']
self.pts = new["new_pts"]
count = msgs[0]
res = []
if count == 0:
pass
else:
res = msgs[1:]
return res
def get_session(token):
return vk.Session(access_token=token)
def get_tses(session):
api = vk.API(session, v=VK_POLLING_VERSION)
ts = api.messages.getLongPollServer(need_pts=1)
return ts['ts'], ts['pts']