def send_photo(u_id, p_id, urls): try: attachments = [] from vk_api import VkUpload upload = VkUpload(vk_session) if isinstance(urls, list): for url in urls: image_url = url image = session.get(url=image_url, stream=True) photo = upload.photo_messages(photos=image.raw, peer_id=peer_id)[0] print(photo) attachments.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) else: image_url = urls image = session.get(url=image_url, stream=True) photo = upload.photo_messages(photos=image.raw, peer_id=peer_id)[0] print(photo) attachments.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) vk.messages.send(peer_id=p_id, user_id=u_id, attachment=','.join(attachments), message='Актуалочка', random_id=np.int64( random.randint(10000, 1000000000000))) except vk_api.ApiError as error: send_photo(u_id, p_id, urls) send_message(u_id, p_id, 'Произошла ошибка загрузки фото, ебучий сайт упал') print(error.raw) pass
def main(): session = requests.Session() # Авторизация пользователя: """ login, password = '******', 'mypassword' vk_session = vk_api.VkApi(login, password) try: vk_session.auth(token_only=True) except vk_api.AuthError as error_msg: print(error_msg) return """ # Авторизация группы (для групп рекомендуется использовать VkBotLongPoll): # при передаче token вызывать vk_session.auth не нужно """ vk_session = vk_api.VkApi(token='токен с доступом к сообщениям и фото') """ vk = vk_session.get_api() upload = VkUpload(vk_session) # Для загрузки изображений longpoll = VkLongPoll(vk_session) for event in longpoll.listen(): if event.type == VkEventType.MESSAGE_NEW and event.to_me and event.text: print('id{}: "{}"'.format(event.user_id, event.text), end=' ') response = session.get('http://api.duckduckgo.com/', params={ 'q': event.text, 'format': 'json' }).json() text = response.get('AbstractText') image_url = response.get('Image') if not text: vk.messages.send(user_id=event.user_id, random_id=get_random_id(), message='No results') print('no results') continue attachments = [] if image_url: image = session.get(image_url, stream=True) photo = upload.photo_messages(photos=image.raw)[0] attachments.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) vk.messages.send(user_id=event.user_id, attachment=','.join(attachments), random_id=get_random_id(), message=text) print('ok')
def mediaResponse(vk_session, mediaRel): upload = VkUpload(vk_session) media = upload.photo_messages(photos=mediaRel)[0] return 'photo{}_{}'.format(media['owner_id'], media['id'])
def work(self, peer_id: int, msg: str, event: bot_longpoll.VkBotEvent): limit = msg.split(maxsplit=1)[1] try: if limit is None or int(limit) <= 1: limit = 1 except ValueError: self.bot.send_message(peer_id, "Самый умный?") return if event.object["from_id"] not in self.bot.admins and int(limit) >= 3: limit = 5 r = requests.get( f"https://konachan.net/post.json?limit={limit}&tags=order%3Arandom" ) json_parsed = json.loads(r.text) attachments = [] self.bot.send_message(peer_id, "Начинаю выкачку...") for i, jsonx in enumerate(json_parsed): img_r = requests.get(jsonx["file_url"], stream=True) img_r.raw.decode_content = True img: Image = Image.open(img_r.raw) img.save(f"/tmp/foo{i}.png", "PNG") # logging.info(msg) upload = VkUpload(self.bot.vk) photo = upload.photo_messages(f"/tmp/foo{i}.png")[0] attachments.append(f"photo{photo['owner_id']}_{photo['id']},") attachment_str = "" for attachment in attachments: attachment_str += attachment self.bot.send_message(peer_id=peer_id, msg=None, attachment=attachment_str) return
def get_single_random_post(id): pic = '' session = requests.Session() upload = VkUpload(session_bot) try: posts_count = vk_me.wall.get(owner_id=id)['count'] offset = random.randint(0, posts_count - 1) while True: response = vk_me.wall.get(owner_id=id, offset=offset, count=1)['items'][0] print(response) if response['likes']['count'] < 50: print('Not enough likes, lets find another post') time.sleep(1) continue try: picture = response['attachments'][0]['photo']['sizes'][-1][ 'url'] image = session.get(picture, stream=True) photo = upload.photo_messages(photos=image.raw)[0] print(photo) pic = [f'photo{photo["owner_id"]}_{photo["id"]}'] except KeyError: print('No pictures') text = response['text'] return text, pic except KeyError: print('Error while fetching public wall posts count')
def send_photo_tochat(vk_session, chat_id, path_to_photo=None, attachment=None): """ :param chat_id: id чата(беседы) :param path_to_photo: путь к фото на пк :param attachment: медиавложения к личному сообщению, перечисленные через запятую. Каждое прикрепление представлено в формате: <type><owner_id>_<media_id> В случае, если прикрепляется объект, принадлежащий другому пользователю добавлять к вложению его access_key в формате <type><owner_id>_<media_id>_<access_key> :return: """ upload = VkUpload(vk_session) if path_to_photo: photo = upload.photo_messages(path_to_photo) attachment = "photo" + (str)(photo[0]['owner_id']) + "_" + (str)( photo[0]['id']) + "_" + (str)(photo[0]['access_key']) vk_session.method( "messages.send", { "chat_id": chat_id, "message": "", "attachment": attachment, "random_id": randint(0, 2048) })
def send_message(self, message, keyboard=None, image_url=None) -> None: """Отсылает сообщение опционально с клавиатурой и/или изображением Parameters ---------- message: str сообщение для пользователя keyboard: VkKeyboard клавиатура доступная пользователю image_url: str ссылка на изображение """ payload = { 'user_id': self._user_id, 'message': message, 'random_id': get_random_id() } if keyboard: payload['keyboard'] = keyboard if image_url: arr = BytesIO(req_get(image_url).content) arr.seek(0) upload = VkUpload(self._vk_session) photo = upload.photo_messages(arr) payload['attachment'] = "photo{}_{}".format(photo[0]["owner_id"], photo[0]["id"]) self._vk_session.method('messages.send', payload)
def sendmessage(event, text, pic=None, kboard=None): if text != None and text.replace(' ', '') != '': if pic != None: # это на случай, если возникнет ошибка с загрузкой картинки. да, они иногда возникают, но очень редко try: upload = VkUpload(vk_session) image_url = pic image = session.get(image_url, stream=True) photo = upload.photo_messages(photos=image.raw)[0] attach = 'photo{}_{}'.format(photo['owner_id'], photo['id']) if kboard != None: vk.messages.send(peer_id=event.obj.message['peer_id'], random_id=get_random_id(), attachment=attach, message=text, keyboard=kboard) else: vk.messages.send(peer_id=event.obj.message['peer_id'], random_id=get_random_id(), attachment=attach, message=text) except: print(pic) text = pic + ' ' + text pic = None if pic == None: if kboard != None: vk.messages.send(peer_id=event.obj.message['peer_id'], random_id=get_random_id(), message=text, keyboard=kboard) else: vk.messages.send(peer_id=event.obj.message['peer_id'], random_id=get_random_id(), message=text)
def sendMsgToChat(self, event, message, image=False, url='https://pbs.twimg.com/media/D4aTJ8yWAAE4GJu.jpg', video=False, videoref='video213946714_456239065'): try: upload = VkUpload(self.vk_session) attachments = [] if image: upload = VkUpload(self.vk_session) image_url = url image = self.session.get(image_url, stream=True) photo = upload.photo_messages(photos=image.raw)[0] attachments.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) if video: attachments.append('video-' + videoref) self.vk.messages.send(attachment=videoref if video else '', chat_id=event.chat_id, message=message, random_id=1) except Exception as e: print(e)
def uploadphoto(photto): upload = VkUpload(vk) photo = upload.photo_messages(photto) owner_id = photo[0]['owner_id'] photo_id = photo[0]['id'] access_key = photo[0]['access_key'] attachment = f'photo{owner_id}_{photo_id}_{access_key}' return attachment
def cmd(api, message, args, uploader: VkUpload): attach = message.get('attachments') reply = message.get('reply_message') if len(attach) == 0 and reply is None: api.messages.send( peer_id=message['peer_id'], random_id=0, message=f"{config.prefixes['error']} Необходимо ответить на сообщение с фотографией / стикером, либо прикрепить фотографию.", reply_to=message['id'] ) return try: if reply is not None: _type = reply['attachments'][0]['type'] if reply['attachments'][0].get('sticker') is not None: img = reply['attachments'][0]['sticker']['images'].pop()['url'] elif reply['attachments'][0].get('photo') is not None: img = reply['attachments'][0]['photo']['sizes'].pop()['url'] else: raise Exception() else: _type = "photo" img = attach[0]['photo']['sizes'].pop()['url'] except: api.messages.send( peer_id=message['peer_id'], random_id=0, message=f"{config.prefixes['error']} Необходимо ответить на сообщение с фотографией / стикером, либо прикрепить фотографию.", reply_to=message['id'] ) return filename = "files/" + os.path.basename(img).split('?')[0] if len(filename.split('.')) < 2: filename += ".png" r = requests.get(img) with open(filename, 'wb') as f: f.write(r.content) os.system(f"convert {filename} -negate {filename}") if _type == "sticker": uploaded = uploader.graffiti(filename, peer_id=message['peer_id'])['graffiti'] attach = f"graffiti{uploaded['owner_id']}_{uploaded['id']}" else: uploaded = uploader.photo_messages(filename, peer_id=message['peer_id'])[0] attach = f"photo{uploaded['owner_id']}_{uploaded['id']}" os.remove(filename) api.messages.send( peer_id=message['peer_id'], random_id=0, attachment=attach, reply_to=message['id'] ) return
def main(): vk_session = vk_api.VkApi(token=TOKEN) longpoll = VkBotLongPoll(vk_session, 195095163) upload = VkUpload(vk_session) vk = vk_session.get_api() for event in longpoll.listen(): if event.type == VkBotEventType.MESSAGE_NEW: vk.messages.send( user_id=event.obj.message['from_id'], random_id=get_random_id(), message="Введи название местности которую хочешь увидеть. Например Калуга" ) for event in longpoll.listen(): if event.type == VkBotEventType.MESSAGE_NEW: toponim = event.obj.message['text'] keyboard = VkKeyboard(one_time=True) keyboard.add_button( 'map (схема)', color=VkKeyboardColor.DEFAULT) keyboard.add_button( 'sat (спутник)', color=VkKeyboardColor.POSITIVE) keyboard.add_button( 'skl (гибрид)', color=VkKeyboardColor.NEGATIVE) keyboard.add_line() keyboard.add_location_button() vk.messages.send(user_id=event.obj.message['from_id'], message="Выберите тип карты на клавиатуре", keyboard=keyboard.get_keyboard(), random_id=get_random_id()) for event in longpoll.listen(): if event.type == VkBotEventType.MESSAGE_NEW: map_type = { 'map (схема)': 'map', 'sat (спутник)': 'sat', 'skl (гибрид)': 'skl'} im = get_image( toponim, map_type[event.obj.message['text']]) photo = upload.photo_messages(photos=im)[0] attachments = 'photo{}_{}'.format( photo['owner_id'], photo['id']) vk.messages.send( user_id=event.obj.message['from_id'], attachment=attachments, random_id=get_random_id(), message=f"Это {toponim}. Что вы еще хотите увидеть?" ) break else: print(event.type)
def send_photo(): attachments = [] session = requests.Session() upload = VkUpload(vk_session) image_url = photos[random.randint(0,len(photos)-1)] image = session.get(image_url, stream=True) photo = upload.photo_messages(photos=image.raw)[0] attachments.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) vk.messages.send(peer_id=id, attachment=','.join(attachments), random_id=0)
def upload_photo_for_message(vk, image_url): upload = VkUpload(vk) attachment = [] image_content = requests.get(image_url) image_content.raise_for_status() file_obj = BytesIO(image_content.content) photo = upload.photo_messages(file_obj)[0] attachment.append("photo{}_{}".format(photo["owner_id"], photo["id"])) return attachment
def uploadImg(self, path): """ :param self: класс бота или че там я хз :param path: путь к фалу :return: строку для аттачмента """ upload = VkUpload(self.bot.vk) photo = upload.photo_messages(path)[0] return f"photo{photo['owner_id']}_{photo['id']},"
def get_attachments(self, photos): """Создает и возврашает объект класса VkUpload с фотографиями photos.""" attachments = [] upload = VkUpload(self.session) for item in photos: image = requests.get(item['url'], stream=True) photo = upload.photo_messages(photos=image.raw)[0] attachments.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) return attachments
def UploadPhotoInMessage(self, vk_session, photo_url, attachments): upload = VkUpload(vk_session) image = self._SESSION.get(photo_url, stream=True) if not image: return attachments try: photo = upload.photo_messages(photos=image.raw)[0] except ApiError: return attachments attachments.append(f'photo{photo["owner_id"]}_{photo["id"]}') return attachments
def get(vk_session, session, image_url): attachments = [] from vk_api import VkUpload upload = VkUpload(vk_session) image = session.get(image_url, stream=True) photo = upload.photo_messages(photos=image.raw)[0] attachments.append( 'photo{}_{}'.format(photo['owner_id'], photo['id']) ) attachment = ','.join(attachments) return attachment
def send_photo(self, user_id, image): upload = VkUpload(self.vk) f = io.BytesIO() image.save(f, format='png') f.seek(0) photo = upload.photo_messages(photos=f)[0] attachment = "photo{}_{}".format(photo['owner_id'], photo['id']) self.vk_api.messages.send(user_id=user_id, attachment=attachment, v=5.50)
def cmd(api, message, args, uploader: VkUpload): attach = message.get('attachments') reply = message.get('reply_message') if (len(attach) == 0 and reply is None) or args[1] is None: api.messages.send( peer_id=message['peer_id'], random_id=0, message= f"{config.prefixes['error']} Необходимо прикрепить фотографию и написать текст: /text [text]", reply_to=message['id']) return try: if reply is not None: img = reply['attachments'][0]['photo']['sizes'].pop()['url'] else: img = attach[0]['photo']['sizes'].pop()['url'] except: api.messages.send( peer_id=message['peer_id'], random_id=0, message= f"{config.prefixes['error']} Необходимо прикрепить фотографию и написать текст: /text [text]", reply_to=message['id']) return filename = "files/" + os.path.basename(img).split('?')[0] if len(filename.split('.')) < 2: filename += ".png" r = requests.get(img) with open(filename, 'wb') as f: f.write(r.content) text = " ".join(args[1:]) os.system(f"convert {filename} \ -bordercolor black -border 3 -bordercolor white -border 2 \ \( -background black -fill white -pointsize 24 \ label:\"{text}\" -trim +repage \ -bordercolor black -border 20 \ \) -gravity South -append \ -bordercolor black -border 10 -gravity South -chop 0x10 \ {filename}") uploaded = uploader.photo_messages(filename, peer_id=message['peer_id'])[0] attach = f"photo{uploaded['owner_id']}_{uploaded['id']}" os.remove(filename) api.messages.send(peer_id=message['peer_id'], random_id=0, attachment=attach, reply_to=message['id']) return
def wth_now_photo(vk_sesh): api = '819012f85e3fd2b9d0da0e7916b318dc' msg = '' response = requests.get('http://api.openweathermap.org/data/2.5/weather', params={ 'id': 524901, 'units': 'metric', 'APPID': api }) info = response.json() image = requests.get('http://openweathermap.org/img/w/{}.png'.format( info['weather'][0]['icon'])) with open('{}.png'.format(info['weather'][0]['icon']), 'wb') as f: f.write(image.content) upload = VkUpload(vk_sesh) photo = upload.photo_messages( photos='{}.png'.format(info['weather'][0]['icon']))[0] return 'photo{}_{}'.format(photo['owner_id'], photo['id'])
def main(): vk_session = vk_api.VkApi( token= '0e536a53faa0b8dce9d3e463379aa4d9d5c49b04d5c469d6078c375790cb9bf7eb12d665b67ef349d3e88' ) vk = vk_session.get_api() upload = VkUpload(vk_session) attachments = [] image = requests.get('http://openweathermap.org/img/w/02d.png', stream=True) photo = upload.photo_messages(photos=image.raw)[0] attachments.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) print(attachments) # -181735299 456239056 longpol = VkLongPoll(vk_session) for event in longpol.listen(): if event.type == VkEventType.MESSAGE_NEW and event.to_me: send(event.user_id, vk, 'att', attachments)
def send_question(vk_session, vk, uid): q = random.randint(0, len(lands.keys())) a = [] for elem in lands.keys(): a.append(elem) # print(lands.keys()) # print(a) name = a[q - 1] # print(name) m = Maps() m.get_map(lands[name][0], lands[name][1]) upload = VkUpload(vk_session) photo = upload.photo_messages(photos='map.png')[0] vk.messages.send(user_id=uid, message='Какая это страна?', attachment='photo{}_{}'.format(photo['owner_id'], photo['id']), random_id=int(random.randint(2, 2**64))) w = d.get_state_2(uid) d.set_state_2(uid, w - 1)
def work(self, peer_id, msg: str, event: vk_api.bot_longpoll.VkBotEvent) -> None: url = "https://r34-json-api.herokuapp.com/posts" if len(msg.split()) <= 1: self.__send_message(peer_id, "Ашыпка. Вы забыли теги") return params = {"tags": "+".join(msg.split()[1:]), "limit": 200} try: r = requests.get(url, params=params).json() r = random.choice(r) file_url = r['file_url'] tags = ", ".join(r['tags']) file_name = downloadfile(file_url) upload = VkUpload(self.bot.vk) photo = upload.photo_messages(f"{file_name['name']}")[0] self.bot.send_message( peer_id, "вотъ", attachment=f"photo{photo['owner_id']}_{photo['id']},") except Exception as e: self.bot.send_message(peer_id, f"Ашыпка. {e}")
def wth_five_photo(vk_sesh): api = '819012f85e3fd2b9d0da0e7916b318dc' msg = '' attach = [] response = requests.get('http://api.openweathermap.org/data/2.5/forecast', params={ 'id': 524901, 'units': 'metric', 'APPID': api }) info = response.json() print(info) count = 0 for i in info['list']: if not (date_is_today(i['dt_txt'])): if count == 7: count = 0 image = requests.get( 'http://openweathermap.org/img/w/{}.png'.format( i['weather'][0]['icon']), stream=True) with open('{}.png'.format(i['weather'][0]['icon']), 'wb') as f: f.write(image.content) count += 1 img = Image.new('RGB', (200, 50)) x = 0 for file in os.listdir("D:\\Code\\Python\\VKBOT\\vk_sender"): if file.endswith(".png"): imga = Image.open( os.path.join("D:\\Code\\Python\\VKBOT\\vk_sender", file)) img.paste(imga, (x, 0)) x += 50 img.save('img.png') upload = VkUpload(vk_sesh) photo = upload.photo_messages( photos='D:\\Code\\Python\\VKBOT\\vk_sender\\img.png')[0] attach.append('photo{}_{}'.format(photo['owner_id'], photo['id'])) return attach
def get_response(event): global search_mode global buffer text = picture = '' session = requests.Session() upload = VkUpload(session_bot) event_message = get_shuffle_words(event.text) if event.text == 'АНЕК': text, _ = get_single_random_post(HUMORESKI) elif event.text == 'ПЁСА': _, picture = get_single_random_post(PESY) elif event.text == 'АНЕК + ПЁСА': text, _ = get_single_random_post(HUMORESKI) _, picture = get_single_random_post(PESY) elif event.text == 'НАЙТИ АНЕК': vk_bot.messages.send(user_id=event.user_id, message='чего искать будем?', random_id=0) return True elif event.text == 'ЕЩЁ': return True elif event.text == 'ХВАТИТ': buffer[event.user_id] = '' search_mode[event.user_id] = False pic = 'http://sun9-19.userapi.com/impg/BJj_7WZRVPT6utF1kZ8AbE10y9zCWBfzjxhuaw/Azcp4ZQDj3M.jpg?size=640x359&quality=96&sign=0cd3d1acde1362e3df3ee3864a2923e8&type=album' image = session.get(pic, stream=True) photo = upload.photo_messages(photos=image.raw)[0] picture = [f'photo{photo["owner_id"]}_{photo["id"]}'] else: text = event_message picture = '' vk_bot.messages.send(user_id=event.user_id, message=text, attachment=','.join(picture), keyboard=set_buttons(), random_id=0) return False
def bot_random_dog(random_id, token, vk_session): '''Обрабатывает принятые сообщения.''' for event in longpoll.listen(): if (event.type == VkEventType.MESSAGE_NEW and event.to_me and event.text): if event.text.lower() in greetings: random_id+=1 vk.messages.send( random_id=random_id, user_id=event.user_id, message=message ) elif event.text.lower() in dog_names: random_id+=1 upload = VkUpload(vk_session) image_url = get_image_url() with requests.Session() as session: image = session.get(image_url, stream=True) photo = upload.photo_messages(photos=image.raw)[0] vk.messages.send( random_id=random_id, user_id=event.user_id, attachment='photo{}_{}'.format(photo['owner_id'], photo['id']), message=answers[randint(0,len(answers)-1)] ) else: random_id+=1 vk.messages.send( random_id=random_id, user_id=event.user_id, message=helper_message )
def compress(this, peer_id, msg: str, event): helps = """ Жмыхалка фоток, хорошо ломает психику неподготовленным личностям. Жмыхает вашу прикрепленную фотку, так же можно передавать степень жмыхнутости, пример: /жмых 55 55 /жмых 59 80 /жмых 50 чем ниже значения, тем сильнее жмыханет максимум для одного из знчений - 100 а дефолт - 40 40 """ if len(event.obj["attachments"]) >= 1 \ and event.obj["attachments"][0]["type"] == "photo": url = event.obj["attachments"][0]["photo"]["sizes"][-1]["url"] elif event.obj.reply_message and len(event.obj.reply_message["attachments"]) >= 1 \ and event.obj.reply_message["attachments"][0]["type"] == "photo": url = event.obj["reply_message"]["attachments"][0]["photo"][ "sizes"][-1]["url"] else: self.bot.send_message(peer_id, helps) return img_r = requests.get(url, stream=True) img_r.raw.decode_content = True img: Image = Image.open(img_r.raw) img.save(f"{self.path}/жмых.png", "PNG") # Скачали фоточку... # ------------------------ # x, y = 50, 50 args = msg.split(" ") print(len(args)) if len(args) >= 3: try: x = int(args[1]) y = int(args[2]) except ValueError: self.bot.send_message(peer_id, helps) elif len(args) == 2: try: x = int(args[1]) y = int(args[1]) except ValueError: self.bot.send_message(peer_id, helps) if x > 100 or y > 100: self.bot.send_message(peer_id, helps) os.system( f"convert {self.path}/жмых.png -liquid-rescale {y}x{x}%\! {self.path}/жмых_бахнутый.png" ) os.remove(f"{self.path}/жмых.png") # # Загружаем фоточку в вк... # ------------------------ upload = VkUpload(self.bot.vk) photo = upload.photo_messages(f"{self.path}/жмых_бахнутый.png")[0] self.bot.send_message(peer_id, " Ж М Ы Х ", f"photo{photo['owner_id']}_{photo['id']}") return
class VkBot(CommonBot): def __init__(self): CommonBot.__init__(self, Platform.VK) self.token = env.str('VK_BOT_TOKEN') self.group_id = env.str('VK_BOT_GROUP_ID') vk_session = VkApi(token=self.token, api_version="5.131", config_filename="secrets/vk_bot_config.json") self.longpoll = MyVkBotLongPoll(vk_session, group_id=self.group_id) self.upload = VkUpload(vk_session) self.vk = vk_session.get_api() # MAIN ROUTING AND MESSAGING def listen(self): """ Получение новых событий и их обработка """ for raw_event in self.longpoll.listen(): vk_event = VkEvent(raw_event, self) threading.Thread(target=self.handle_event, args=(vk_event, )).start() def send_response_message(self, rm: ResponseMessage): """ Отправка ResponseMessage сообщения Вовзращает список результатов отправки в формате [{success:bool, response:Response, response_message_item:ResponseMessageItem}] """ results = [] for rmi in rm.messages: try: response = self.send_response_message_item(rmi) results.append({ "success": True, "response": response, "response_message_item": rmi }) except vk_api.exceptions.ApiError as e: if e.code not in [901, 917]: error_rm = ResponseMessage(self.ERROR_MSG, rmi.peer_id).messages[0] self.logger.error({ 'message': self.ERROR_MSG, 'error': str(e) }) response = self.send_response_message_item(error_rm) results.append({ "success": False, "response": response, "response_message_item": error_rm }) return results def send_response_message_item(self, rm: ResponseMessageItem): """ Отправка ResponseMessageItem сообщения Возвращает Response платформы """ text = str(rm.text) if len(text) > 4096: text = text[:4092] text += "\n..." attachments = [] for att in rm.attachments: if isinstance(att, str): attachments.append(att) elif att.url: attachments.append(att.url) elif att.public_download_url: attachments.append(att.public_download_url) return self.vk.messages.send( peer_id=rm.peer_id, message=text, access_token=self.token, random_id=get_random_id(), attachment=','.join(attachments), keyboard=json.dumps(rm.keyboard), ) # END MAIN ROUTING AND MESSAGING # ATTACHMENTS def upload_photos(self, images, max_count=10, peer_id=None): """ Загрузка фотографий на сервер ТГ. images: список изображений в любом формате (ссылки, байты, файлы) При невозможности загрузки одной из картинки просто пропускает её """ atts = super().upload_photos(images, max_count) parsed_atts = [] for pa in atts: try: url, public_download_url = self.upload_photo_and_urls(pa) pa.url = url.replace(VK_URL, '') pa.public_download_url = public_download_url parsed_atts.append(pa) except Exception: continue return parsed_atts def upload_photo_and_urls(self, image: PhotoAttachment): """ Загрузка изображения на сервер VK Возвращает vk_url и public_download_url """ vk_photo = self.upload.photo_messages(image.get_bytes_io_content())[0] vk_url = f"{VK_URL}photo{vk_photo['owner_id']}_{vk_photo['id']}" vk_max_photo_url = sorted(vk_photo['sizes'], key=lambda x: x['height'])[-1]['url'] return vk_url, vk_max_photo_url def upload_document(self, document, peer_id=None, title='Документ', filename=None): """ Загрузка документа на сервер ВК. """ da = super().upload_document(document, peer_id, title, filename) content = da.download_content() vk_doc = self.upload.document_message(content, title=title, peer_id=peer_id)['doc'] return f"doc{vk_doc['owner_id']}_{vk_doc['id']}" # END ATTACHMENTS # USERS GROUPS BOTS def get_profile_by_user(self, user: User, is_new=False, _defaults: dict = None) -> Profile: """ Возвращает пользователя по его id Регистрирует если пользователя нет в БД """ if not user.profile: vk_user = self.get_user_info(int(user.user_id)) profile = Profile() profile.name = vk_user['first_name'] profile.surname = vk_user['last_name'] profile.platform = self.platform.name profile.set_avatar(vk_user['photo_max']) if 'sex' in vk_user: profile.gender = vk_user['sex'] if 'city' in vk_user: from apps.service.models import City city_name = vk_user['city']['title'] city = City.objects.filter(name__icontains=city_name) if len(city) > 0: city = city.first() else: try: city = add_city_to_db(city_name) except Exception: city = None profile.city = city else: profile.city = None if 'screen_name' in vk_user: user.nickname = vk_user['screen_name'] with self.lock: profile.save() user.profile = profile user.save() return super().get_profile_by_user(user, is_new=True) return super().get_profile_by_user(user) def get_user_info(self, user_id: int): """ Получение информации о пользователе """ return self.vk.users.get( user_id=user_id, lang='ru', fields='sex, bdate, city, screen_name, photo_max')[0] def update_profile_avatar(self, profile: Profile, user_id): """ Обновление аватара пользователя """ user_info = self.get_user_info(user_id) profile.set_avatar(user_info['photo_max']) def get_bot_by_id(self, bot_id: int) -> BotModel: """ Получение информации о боте """ try: bot = self.bot_model.get(bot_id=bot_id) except BotModel.DoesNotExist: bot = super().get_bot_by_id(bot_id) vk_bot = self.get_bot_info(bot_id) bot.name = vk_bot['name'] bot.set_avatar(vk_bot['photo_200']) bot.save() return bot def get_bot_info(self, bot_id): """ Получение информации о боте """ return self.vk.groups.getById(group_id=bot_id)[0] def update_bot_avatar(self, bot_id): """ Обновление аватара бота """ bot = self.get_bot_by_id(bot_id) bot_info = self.get_bot_info(bot_id) bot.name = bot_info['name'] bot.set_avatar(bot_info['photo_200']) # END USERS GROUPS BOTS # EXTRA def set_activity(self, peer_id, activity: ActivitiesEnum): """ Метод позволяет указать пользователю, что бот набирает сообщение или записывает голосовое Используется при длительном выполнении команд, чтобы был фидбек пользователю, что его запрос принят """ tg_activity = VK_ACTIVITIES.get(activity) if tg_activity: self.vk.messages.setActivity(type=tg_activity, peer_id=peer_id, group_id=self.group_id) @staticmethod def _get_keyboard_buttons(buttons): """ Определение структуры кнопок """ return [{ 'action': { 'type': 'text', 'label': button_item['button_text'], "payload": json.dumps( { "command": button_item['command'], "args": button_item.get('args'), }, ensure_ascii=False) }, 'color': 'primary', } for button_item in buttons] def get_inline_keyboard(self, buttons: list, cols=1): """ param buttons: ToDo: Получение инлайн-клавиатуры с кнопками В основном используется для команд, где нужно запускать много команд и лень набирать заново """ keyboard = super().get_inline_keyboard(buttons) return {'inline': True, 'buttons': keyboard} def get_mention(self, profile: Profile, name=None): """ Получение меншона пользователя """ user = profile.get_user_by_platform(self.platform) name = name or str(user) return f"[id{user.user_id}|{name}]" def remove_self_from_chat(self, chat_id): """ Удаление бота (себя) из чата """ self.vk.messages.removeChatUser(chat_id=chat_id, member_id=f"-{self.group_id}") def get_conversation_messages(self, peer_id, conversation_message_id): """ Получение полного сообщения """ response = self.vk.messages.getByConversationMessageId( peer_id=peer_id, conversation_message_ids=[conversation_message_id]) return response['items'][0]
class VkBot(CommonBot, Thread): def __init__(self): Thread.__init__(self) CommonBot.__init__(self, Platform.VK) self.token = env.str('VK_BOT_TOKEN') self.group_id = env.str('VK_BOT_GROUP_ID') vk_session = VkApi(token=self.token, api_version="5.107", config_filename="secrets/vk_bot_config.json") self.longpoll = MyVkBotLongPoll(vk_session, group_id=self.group_id) self.upload = VkUpload(vk_session) self.vk = vk_session.get_api() self.vk_user = VkUser() self.test_chat = Chat.objects.get(chat_id=env.str("VK_TEST_CHAT_ID")) def set_activity(self, peer_id, activity='typing'): if activity not in ['typing', 'audiomessage']: raise PWarning("Не знаю такого типа активности") self.vk.messages.setActivity(type=activity, peer_id=peer_id, group_id=self.group_id) def get_user_by_id(self, user_id): vk_user = self.user_model.filter(user_id=user_id) if len(vk_user) > 0: vk_user = vk_user.first() else: # Прозрачная регистрация user = self.vk.users.get(user_id=user_id, lang='ru', fields='sex, bdate, city, screen_name')[0] vk_user = Users() vk_user.user_id = user_id vk_user.name = user['first_name'] vk_user.surname = user['last_name'] vk_user.platform = self.platform.name if 'sex' in user: vk_user.gender = user['sex'] if 'bdate' in user: vk_user.birthday = self.parse_date(user['bdate']) if 'city' in user: from apps.service.models import City city_name = user['city']['title'] city = City.objects.filter(name=city_name) if len(city) > 0: city = city.first() else: try: city = add_city_to_db(city_name) except Exception: city = None vk_user.city = city else: vk_user.city = None if 'screen_name' in user: vk_user.nickname = user['screen_name'] vk_user.save() group_user = Group.objects.get(name=Role.USER.name) vk_user.groups.add(group_user) vk_user.save() return vk_user def get_chat_by_id(self, chat_id): vk_chat = self.chat_model.filter(chat_id=chat_id) if len(vk_chat) > 0: vk_chat = vk_chat.first() else: vk_chat = Chat(chat_id=chat_id, platform=self.platform.name) vk_chat.save() return vk_chat @staticmethod def add_extra_group_to_user(user, chat): group = ScheduleGroup.objects.filter(conference=chat).first() if group: groups = user.groups group_student = Group.objects.get(name=Role.STUDENT.name) if group_student not in groups.all(): user.groups.add(group_student) user.save() def get_bot_by_id(self, bot_id): if bot_id > 0: bot_id = -bot_id bot = self.bot_model.filter(bot_id=bot_id) if len(bot) > 0: bot = bot.first() else: # Прозрачная регистрация vk_bot = self.vk.groups.getById(group_id=bot_id)[0] bot = Bot() bot.bot_id = bot_id bot.name = vk_bot['name'] bot.platform = self.platform.name bot.save() return bot def send_message(self, peer_id, msg="ᅠ", attachments=None, keyboard=None, dont_parse_links=False, **kwargs): if attachments is None: attachments = [] if isinstance(attachments, str): attachments = [attachments] if attachments and msg == "ᅠ": msg = "" if keyboard: keyboard = json.dumps(keyboard) msg = str(msg) if len(msg) > 4096: msg = msg[:4092] msg += "\n..." try: self.vk.messages.send(peer_id=peer_id, message=msg, access_token=self.token, random_id=get_random_id(), attachment=','.join(attachments), keyboard=keyboard, dont_parse_links=dont_parse_links ) except vk_api.exceptions.ApiError as e: if e.code == 901: pass else: print("Ошибка отправки сообщения\n" f"{e}") def _setup_event(self, event): vk_event = { 'platform': self.platform, 'from_user': event.from_user, 'chat_id': event.chat_id, 'user_id': event.message.from_id, 'peer_id': event.message.peer_id, 'message': { # 'id': event.message.id, 'text': event.message.text, 'payload': event.message.payload, 'attachments': event.message.attachments, 'action': event.message.action }, 'fwd': None } if (vk_event['message'].get('action', None) and vk_event['message']['action']['type'] in ['chat_invite_user', 'chat_invite_user_by_link']): vk_event['message']['action']['member_ids'] = [vk_event['message']['action'].pop('member_id')] return vk_event def listen(self): for event in self.longpoll.listen(): try: # Если пришло новое сообщение if event.type == VkBotEventType.MESSAGE_NEW: vk_event = self._setup_event(event) if self.DEVELOP_DEBUG: from_test_chat = vk_event['chat_id'] == self.test_chat.id from_me = str(vk_event['user_id']) == env.str('VK_ADMIN_ID') if not from_test_chat or not from_me: continue # Сообщение либо мне в лс, либо упоминание меня, либо есть аудиосообщение, либо есть экшн if not self.need_a_response(vk_event): continue # Обработка вложенных сообщений в event['fwd']. reply и fwd для вк это разные вещи. if event.message.reply_message: vk_event['fwd'] = [event.message.reply_message] elif len(event.message.fwd_messages) != 0: vk_event['fwd'] = event.message.fwd_messages # Узнаём пользователя if vk_event['user_id'] > 0: vk_event['sender'] = self.get_user_by_id(vk_event['user_id']) else: self.send_message(vk_event['peer_id'], "Боты не могут общаться с Петровичем :(") continue # Узнаём конфу if vk_event['chat_id']: vk_event['chat'] = self.get_chat_by_id(int(vk_event['peer_id'])) if vk_event['sender'] and vk_event['chat']: self.add_chat_to_user(vk_event['sender'], vk_event['chat']) self.add_extra_group_to_user(vk_event['sender'], vk_event['chat']) else: vk_event['chat'] = None vk_event_object = VkEvent(vk_event) thread = threading.Thread(target=self.menu, args=(vk_event_object,)) thread.start() except Exception as e: print(str(e)) tb = traceback.format_exc() print(tb) @staticmethod def _prepare_obj_to_upload(file_like_object, allowed_exts_url=None): # bytes array if isinstance(file_like_object, bytes): obj = io.BytesIO(file_like_object) obj.seek(0) # bytesIO elif isinstance(file_like_object, io.BytesIO): obj = file_like_object obj.seek(0) # url elif urlparse(file_like_object).hostname: if allowed_exts_url: extension = file_like_object.split('.')[-1].lower() is_default_extension = extension not in allowed_exts_url is_vk_image = any(extension.startswith(x) for x in allowed_exts_url) if is_default_extension and not is_vk_image: raise PWarning(f"Загрузка по URL доступна только для {' '.join(allowed_exts_url)}") try: response = requests.get(file_like_object, stream=True, timeout=3) except SSLError: raise PWarning("SSLError") except requests.exceptions.ConnectionError: raise PWarning("ConnectionError") obj = response.raw # path else: obj = file_like_object return obj def _get_attachment_by_id(self, _type, group_id, _id): if group_id is None: group_id = f'-{self.group_id}' return f"{_type}{group_id}_{_id}" def upload_photos(self, images, max_count=10): if not isinstance(images, list): images = [images] attachments = [] images_to_load = [] for image in images: try: image = self._prepare_obj_to_upload(image, ['jpg', 'jpeg', 'png']) except PWarning: continue except ReadTimeout: continue except ConnectTimeout: continue # Если Content-Length > 50mb bytes_count = None if isinstance(image, io.BytesIO): bytes_count = image.getbuffer().nbytes elif isinstance(image, urllib3.response.HTTPResponse) or isinstance(image, requests.packages.urllib3.response.HTTPResponse): bytes_count = image.headers.get('Content-Length') elif os.path.exists(image): bytes_count = os.path.getsize(image) else: print("ШТО ТЫ ТАКОЕ", type(image)) if not bytes_count: continue if int(bytes_count) / 1024 / 1024 > 50: continue images_to_load.append(image) if len(images_to_load) >= max_count: break try: vk_photos = self.upload.photo_messages(images_to_load) for vk_photo in vk_photos: attachments.append(self._get_attachment_by_id('photo', vk_photo['owner_id'], vk_photo['id'])) except vk_api.exceptions.ApiError as e: print(e) return attachments def upload_document(self, document, peer_id=None, title='Документ'): document = self._prepare_obj_to_upload(document) vk_document = self.upload.document_message(document, title=title, peer_id=peer_id)['doc'] return self._get_attachment_by_id('doc', vk_document['owner_id'], vk_document['id']) def upload_audio(self, audio, artist, title): audio = self._prepare_obj_to_upload(audio) try: vk_audio = self.vk_user.upload.audio(audio, artist=artist, title=title) except vk_api.exceptions.ApiError as e: if e.code == 270: raise PWarning("Аудиозапись была удалена по просьбе правообладателя") raise PError("Ошибка загрузки аудиозаписи") return self.get_attachment_by_id('audio', vk_audio['owner_id'], vk_audio['id']) @staticmethod def get_inline_keyboard(command_text, button_text="Ещё", args=None): if args is None: args = {} return { 'inline': True, 'buttons': [[ { 'action': { 'type': 'text', 'label': button_text, "payload": json.dumps({"command": command_text, "args": args}, ensure_ascii=False) }, 'color': 'primary', } ]]} @staticmethod def get_group_id(_id): return 2000000000 + int(_id) @staticmethod def get_mention(user, name=None): name = name or str(user) return f"[id{user.user_id}|{name}]" def upload_video_by_link(self, link, name): values = { 'name': name, 'is_private': False, 'link': link, } response = self.vk_user.vk.video.save(**values) requests.post(response['upload_url']) return f"video{response['owner_id']}_{response['video_id']}" def get_attachment_by_id(self, _type, group_id, _id): if group_id is None: group_id = f'-{self.group_id}' return f"{_type}{group_id}_{_id}" def get_video(self, owner_id, _id): return self.vk_user.vk.video.get(videos=f'{owner_id}_{_id}') def set_chat_title(self, chat_id, title): self.vk.messages.editChat(chat_id=chat_id, title=title) def set_chat_title_if_not_equals(self, chat_id, title): if title != self.vk.messages.getConversationsById(peer_ids=chat_id)['items'][0]['chat_settings']['title']: self.set_chat_title(int(chat_id) - 2000000000, title) return True return False def get_conference_users(self, peer_id): try: return self.vk.messages.getConversationMembers(peer_id=peer_id, group_id=self.group_id, lang='ru')[ 'profiles'] except: raise PWarning("У бота нет админских прав для получения списка пользователей в конференции")
def main(): session = requests.Session() # Авторизация пользователя: """ login, password = '******', 'mypassword' vk_session = vk_api.VkApi(login, password) try: vk_session.auth(token_only=True) except vk_api.AuthError as error_msg: print(error_msg) return """ # Авторизация группы (для групп рекомендуется использовать VkBotLongPoll): # при передаче token вызывать vk_session.auth не нужно """ vk_session = vk_api.VkApi(token='токен с доступом к сообщениям и фото') """ vk = vk_session.get_api() upload = VkUpload(vk_session) # Для загрузки изображений longpoll = VkLongPoll(vk_session) for event in longpoll.listen(): if event.type == VkEventType.MESSAGE_NEW and event.to_me and event.text: print('id{}: "{}"'.format(event.user_id, event.text), end=' ') response = session.get( 'http://api.duckduckgo.com/', params={ 'q': event.text, 'format': 'json' } ).json() text = response.get('AbstractText') image_url = response.get('Image') if not text: vk.messages.send( user_id=event.user_id, random_id=get_random_id(), message='No results' ) print('no results') continue attachments = [] if image_url: image = session.get(image_url, stream=True) photo = upload.photo_messages(photos=image.raw)[0] attachments.append( 'photo{}_{}'.format(photo['owner_id'], photo['id']) ) vk.messages.send( user_id=event.user_id, attachment=','.join(attachments), random_id=get_random_id(), message=text ) print('ok')