From 24157fa4af2d1a1260016d94f4531e09a40b6124 Mon Sep 17 00:00:00 2001 From: bstoilov Date: Tue, 8 Oct 2019 09:02:57 +0300 Subject: [PATCH 1/2] adding support for direct messages --- README.md | 3 + messages_example.py | 86 +++++++++++++++++++++++++++ py3pin/Pinterest.py | 124 ++++++++++++++++++++++++++++++++++++++- py3pin/RequestBuilder.py | 4 +- py3pin/__version__.py | 2 +- 5 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 messages_example.py diff --git a/README.md b/README.md index d028f6b..f27c7d1 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,9 @@ Current pinterest scopes are: pins, buyable_pins, my_pins, videos, users, boards ```pinterest.load_pin(pin_id='pin_id')``` +### Send perosnal message +```pinterest.send_message(conversation_id=conversation_id, pin_id="(pin_id)", message="hey")``` + diff --git a/messages_example.py b/messages_example.py new file mode 100644 index 0000000..024cef0 --- /dev/null +++ b/messages_example.py @@ -0,0 +1,86 @@ +from py3pin.Pinterest import Pinterest + +username = 'username' +password = 'password!' +email = 'email' +# cred_root is the place the user sessions and cookies will be stored you should specify this to avoid permission issues +cred_root = 'cred_root' + +pinterest = Pinterest(email=email, + password=password, + username=username, + cred_root=cred_root) + + +# get the user id by username +def get_user_id(username): + return pinterest.get_user_overview(username=username)['id'] + + +# Pinterest conversations are stored in a list of conversation object on their side. +# Each converastion has id and last message they use to display on the initial drop down once you click the message button +def get_all_conversations(): + return pinterest.get_conversations() + + +# Once you obtain a conversation id, only then you can see all the messages and participants in it. +def load_conversation(conversation_id): + return pinterest.load_conversation(conversation_id=conversation_id) + + +# in order to have conversation with some one, it needs to be initialized once with some initial message +# this is called once per user (or group of users) +# the method receives array of users, this way grop conversations are started +# calling this method multiple times for the same user does nothing +def initiate_conversation(username, message): + usernames = [username] + + # get the user id by username + user_ids = [] + for u in usernames: + user_ids.append(get_user_id(u)) + + pinterest.initiate_conversation(user_ids=user_ids, message=message) + + +# search for conversation with specific user +# NOTE: he might be part of multiple conversations (group conversations) +def find_conversation_by_username(username): + conversations = pinterest.get_conversations() + conversation_ids = [] + + # get all conversations in which username is found + for c in conversations: + conv_usernames = [] + for usr in c['users']: + conv_usernames.append(usr['username']) + if username in conv_usernames: + conversation_ids.append(c['id']) + + return conversation_ids + + +# send message to user +# if this is the first time new conversation will be created +def send_message(username, message): + conversations_ids = find_conversation_by_username(username) + + if len(conversations_ids) == 0: + initiate_conversation(username=username, message=message) + else: + # add logic to chose conversation if needed + conversation_id = conversations_ids[0] + + # you can send 3 types of messages + + # Only text message + pinterest.send_message(conversation_id=conversation_id, pin_id=None, message=message) + + # Send pin by id + # pinterest.send_message(conversation_id=conversation_id, pin_id="(pin_id)") + + # Message followed by pin + # pinterest.send_message(conversation_id=conversation_id, pin_id="(pin_id)", message="hey") + + +send_message(username='hknives', message='hi2') diff --git a/py3pin/Pinterest.py b/py3pin/Pinterest.py index 80a9a31..169bed3 100644 --- a/py3pin/Pinterest.py +++ b/py3pin/Pinterest.py @@ -45,6 +45,10 @@ GET_PIN_COMMENTS_RESOURCE = 'https://www.pinterest.com/_ngjs/resource/AggregatedCommentFeedResource/get' LOAD_PIN_URL_FORMAT = 'https://www.pinterest.com/pin/{}/' DELETE_COMMENT = 'https://www.pinterest.com/_ngjs/resource/AggregatedCommentResource/delete/' +CONVERSATION_RESOURCE = 'https://www.pinterest.com/resource/ConversationsResource/get/' +CONVERSATION_RESOURCE_CREATE = 'https://www.pinterest.com/resource/ConversationsResource/create/' +LOAD_CONVERSATION = 'https://www.pinterest.com/resource/ConversationMessagesResource/get/' +SEND_MESSAGE = 'https://www.pinterest.com/resource/ConversationMessagesResource/create/' class Pinterest: @@ -59,7 +63,7 @@ def __init__(self, password='', proxies=None, username='', email='', cred_root=' self.http = requests.session() self.proxies = proxies - self.data_path = os.path.join(cred_root,self.email) + os.sep + self.data_path = os.path.join(cred_root, self.email) + os.sep if not os.path.isdir(self.data_path): os.makedirs(self.data_path) self.registry = Registry('%sregistry.dat' % self.data_path) @@ -608,6 +612,124 @@ def board_feed(self, board_url='', board_id='', page_size=250): pins.append(pin_data) return pins + def initiate_conversation(self, user_ids=None, message='hi'): + headers = self._load_headers() + options = { + "user_ids": user_ids, + "text": message + } + + data_obj = { + 'options': options, + 'context': {} + } + + data = { + 'source_url': '/', + 'data': json.dumps(data_obj) + } + + return requests.post(CONVERSATION_RESOURCE_CREATE, headers=headers, data=data) + + def send_message(self, message='', conversation_id='', pin_id=''): + options = { + "conversation_id": conversation_id, + "text": message, + "pin": pin_id + } + + data_obj = { + 'options': options, + 'context': {} + } + + + data = { + 'source_url': '/', + 'data': json.dumps(data_obj) + } + + headers = self._load_headers() + return requests.post(url=SEND_MESSAGE, headers=headers, data=data) + + def _load_headers(self): + cookies = self.registry.get(Registry.Key.COOKIES) + csrftoken = '' + cookie_str = '' + for c in cookies: + if c.name == 'csrftoken': + csrftoken = c.value + cookie_str += c.name + '=' + c.value + '; ' + cookie_str = cookie_str.strip() + + headers = { + 'cookie': cookie_str, + 'x-csrftoken': csrftoken, + 'user-agent': AGENT_STRING + } + + return headers + + def load_conversation(self, conversation_id=''): + messages = [] + + message_batch = self._load_conversation_batch(conversation_id=conversation_id) + while len(message_batch) > 0: + messages += message_batch + message_batch = self._load_conversation_batch(conversation_id=conversation_id) + + return messages + + def _load_conversation_batch(self, conversation_id='', page_size=25): + next_bookmark = self.bookmark_manager.get_bookmark(primary='conversations', secondary=conversation_id) + + if next_bookmark == '-end-': + return [] + + options = { + "isPrefetch": False, + "page_size": page_size, + "conversation_id": conversation_id, + "bookmarks": [next_bookmark] + } + + url = self.req_builder.buildGet(url=LOAD_CONVERSATION, options=options) + response = self.get(url=url).json() + + bookmark = response['resource']['options']['bookmarks'][0] + self.bookmark_manager.add_bookmark(primary='conversations', secondary=conversation_id, bookmark=bookmark) + + return response['resource_response']['data'] + + def get_conversations(self): + conversations = [] + conv_batch = self._get_conversation_batch() + while len(conv_batch) > 0: + conversations += conv_batch + conv_batch = self._get_conversation_batch() + + return conversations + + def _get_conversation_batch(self): + next_bookmark = self.bookmark_manager.get_bookmark(primary='conversations') + + if next_bookmark == '-end-': + return [] + + options = { + "isPrefetch": False, + "field_set_key": "default", + "bookmarks": [next_bookmark] + } + + url = self.req_builder.buildGet(url=CONVERSATION_RESOURCE, options=options) + response = self.get(url=url).json() + + next_bookmark = response['resource']['options']['bookmarks'][0] + self.bookmark_manager.add_bookmark(primary='conversations', bookmark=next_bookmark) + + return response['resource_response']['data'] + def extract_pins(results): pins = [] diff --git a/py3pin/RequestBuilder.py b/py3pin/RequestBuilder.py index 6a17693..b170d4b 100644 --- a/py3pin/RequestBuilder.py +++ b/py3pin/RequestBuilder.py @@ -7,7 +7,7 @@ class RequestBuilder: def __init__(self): pass - def buildPost(self, options, source_url, context={}): + def buildPost(self, options, source_url="/", context={}): return self.url_encode({ 'source_url': source_url, 'data': json.dumps({ @@ -17,7 +17,7 @@ def buildPost(self, options, source_url, context={}): '_': '%s' % int(time.time() * 1000) }) - def buildGet(self, url, options, source_url, context={}): + def buildGet(self, url, options, source_url="/", context={}): data = self.url_encode({ 'source_url': source_url, 'data': json.dumps({ diff --git a/py3pin/__version__.py b/py3pin/__version__.py index d93b5b2..0404d81 100644 --- a/py3pin/__version__.py +++ b/py3pin/__version__.py @@ -1 +1 @@ -__version__ = '0.2.3' +__version__ = '0.3.0' From 299342a95c6dae357da09be74aef9063c8abb921 Mon Sep 17 00:00:00 2001 From: VeemPees Date: Wed, 9 Oct 2019 18:11:21 +0200 Subject: [PATCH 2/2] PEP8 and linting --- examples.py | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/examples.py b/examples.py index 5eab3e3..4657dd8 100644 --- a/examples.py +++ b/examples.py @@ -37,7 +37,8 @@ def get_board_pins(): feed_batch = pinterest.board_feed(board_id=board_id, board_url=board_url) while len(feed_batch) > 0: board_feed += feed_batch - feed_batch = pinterest.board_feed(board_id=board_id, board_url=board_url) + feed_batch = pinterest.board_feed( + board_id=board_id, board_url=board_url) return board_feed @@ -113,7 +114,8 @@ def get_board_pin_recommendations(): board_id = 'board_id' max_len = 100 rec_pins = [] - rec_batch = pinterest.board_recommendations(board_url=board_url, board_id=board_id) + rec_batch = pinterest.board_recommendations( + board_url=board_url, board_id=board_id) while len(rec_batch) > 0: rec_pins += rec_batch if len(rec_pins) > max_len: @@ -131,11 +133,6 @@ def pin(): return pinterest.pin(board_id=board_id, image_url=image_url, description=description, title=title, link=link) -def delete_pin(): - pin_id = 'some pin id' - return pinterest.delete_pin(pin_id=pin_id) - - def search(): # After change in pinterest API, you can no longer search for users # Instead you need to search for something else and extract the user data from there. @@ -182,7 +179,8 @@ def get_board_invites(): board_url = 'board_url' board_id = 'board_id' invites = [] - invites_batch = pinterest.get_board_invites(board_url=board_url, board_id=board_id) + invites_batch = pinterest.get_board_invites( + board_url=board_url, board_id=board_id) while len(invites_batch) > 0: invites += invites_batch return invites