Changed sendXFiles
to only needing file url / path
This commit is contained in:
160
fbchat/client.py
160
fbchat/client.py
@@ -1087,103 +1087,40 @@ class Client(object):
|
|||||||
data['specific_to_list[0]'] = "fbid:{}".format(thread_id)
|
data['specific_to_list[0]'] = "fbid:{}".format(thread_id)
|
||||||
return self._doSendRequest(data)
|
return self._doSendRequest(data)
|
||||||
|
|
||||||
def _upload(self, file_name, data, mimetype, type_="file"):
|
def _upload(self, files):
|
||||||
data = {
|
"""
|
||||||
'file': (
|
Uploads files to Facebook
|
||||||
file_name,
|
|
||||||
data,
|
|
||||||
mimetype
|
|
||||||
)
|
|
||||||
}
|
|
||||||
j = self._postFile(self.req_url.UPLOAD, data, fix_request=True, as_json=True)
|
|
||||||
|
|
||||||
return j['payload']['metadata'][0]['{}_id'.format(type_)]
|
`files` should be a list of files that requests can upload, see:
|
||||||
|
http://docs.python-requests.org/en/master/api/#requests.request
|
||||||
|
|
||||||
|
Returns a list of tuples with a file's ID and mimetype
|
||||||
|
"""
|
||||||
|
file_dict = {'upload_{}'.format(i): f for i, f in enumerate(files)}
|
||||||
|
j = self._postFile(self.req_url.UPLOAD, files=file_dict, fix_request=True, as_json=True)
|
||||||
|
|
||||||
|
if len(j['payload']['metadata']) != len(files):
|
||||||
|
raise FBchatException("Some files could not be uploaded: {}, {}".format(j, files))
|
||||||
|
|
||||||
|
return [(data[mimetype_to_key(data['filetype'])], data['filetype']) for data in j['payload']['metadata']]
|
||||||
|
|
||||||
def _sendFiles(self, files, message=None, thread_id=None, thread_type=ThreadType.USER):
|
def _sendFiles(self, files, message=None, thread_id=None, thread_type=ThreadType.USER):
|
||||||
|
"""
|
||||||
|
Sends files from file IDs to a thread
|
||||||
|
|
||||||
|
`files` should be a list of tuples, with a file's ID and mimetype
|
||||||
|
"""
|
||||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
||||||
data = self._getSendData(message=self._oldMessage(message), thread_id=thread_id, thread_type=thread_type)
|
data = self._getSendData(message=self._oldMessage(message), thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
data['action_type'] = 'ma-type:user-generated-message'
|
data['action_type'] = 'ma-type:user-generated-message'
|
||||||
data['has_attachment'] = True
|
data['has_attachment'] = True
|
||||||
|
|
||||||
for type_ in files:
|
for i, (file_id, mimetype) in enumerate(files):
|
||||||
for i, file_id in enumerate(files[type_]):
|
data['{}s[{}]'.format(mimetype_to_key(mimetype), i)] = file_id
|
||||||
data['{}_ids[{}]'.format(type_, i)] = file_id
|
|
||||||
|
|
||||||
return self._doSendRequest(data)
|
return self._doSendRequest(data)
|
||||||
|
|
||||||
def sendFiles(self, file_ids, message=None, thread_id=None, thread_type=ThreadType.USER):
|
|
||||||
"""
|
|
||||||
Sends files from file IDs to a thread
|
|
||||||
|
|
||||||
:param file_ids: ID of files to upload and send
|
|
||||||
:param message: Additional message
|
|
||||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
|
||||||
:param thread_type: See :ref:`intro_threads`
|
|
||||||
:type thread_type: models.ThreadType
|
|
||||||
:return: :ref:`Message ID <intro_message_ids>` of the sent files
|
|
||||||
:raises: FBchatException if request failed
|
|
||||||
"""
|
|
||||||
file_ids = require_list(file_ids)
|
|
||||||
return self._sendFiles(files={'file': file_ids}, message=None, thread_id=None, thread_type=ThreadType.USER)
|
|
||||||
|
|
||||||
def sendAudios(self, audio_ids, message=None, thread_id=None, thread_type=ThreadType.USER):
|
|
||||||
"""
|
|
||||||
Sends audios from audio IDs to a thread
|
|
||||||
|
|
||||||
:param audio_id: IDs of audios to upload and send
|
|
||||||
:param message: Additional message
|
|
||||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
|
||||||
:param thread_type: See :ref:`intro_threads`
|
|
||||||
:type thread_type: models.ThreadType
|
|
||||||
:return: :ref:`Message ID <intro_message_ids>` of the sent audios
|
|
||||||
:raises: FBchatException if request failed
|
|
||||||
"""
|
|
||||||
audio_ids = require_list(audio_ids)
|
|
||||||
return self._sendFiles(files={'audio': audio_ids}, message=None, thread_id=None, thread_type=ThreadType.USER)
|
|
||||||
|
|
||||||
def sendImages(self, image_ids, message=None, thread_id=None, thread_type=ThreadType.USER):
|
|
||||||
"""
|
|
||||||
Sends images from image IDs to a thread
|
|
||||||
|
|
||||||
:param image_ids: IDs of images to upload and send
|
|
||||||
:param message: Additional message
|
|
||||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
|
||||||
:param thread_type: See :ref:`intro_threads`
|
|
||||||
:type thread_type: models.ThreadType
|
|
||||||
:return: :ref:`Message ID <intro_message_ids>` of the sent images
|
|
||||||
:raises: FBchatException if request failed
|
|
||||||
"""
|
|
||||||
return self._sendFiles(files={'image': image_ids}, message=None, thread_id=None, thread_type=ThreadType.USER)
|
|
||||||
|
|
||||||
def sendGifs(self, gif_ids, message=None, thread_id=None, thread_type=ThreadType.USER):
|
|
||||||
"""
|
|
||||||
Sends gifs from gif IDs to a thread
|
|
||||||
|
|
||||||
:param gif_ids: IDs of gifs to upload and send
|
|
||||||
:param message: Additional message
|
|
||||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
|
||||||
:param thread_type: See :ref:`intro_threads`
|
|
||||||
:type thread_type: models.ThreadType
|
|
||||||
:return: :ref:`Message ID <intro_message_ids>` of the sent image
|
|
||||||
:raises: FBchatException if request failed
|
|
||||||
"""
|
|
||||||
return self._sendFiles(files={'gif': gif_ids}, message=None, thread_id=None, thread_type=ThreadType.USER)
|
|
||||||
|
|
||||||
def sendVideos(self, video_ids, message=None, thread_id=None, thread_type=ThreadType.USER):
|
|
||||||
"""
|
|
||||||
Sends videos from video IDs to a thread
|
|
||||||
|
|
||||||
:param video_ids: IDs of videos to upload and send
|
|
||||||
:param message: Additional message
|
|
||||||
:param thread_id: User/Group ID to send to. See :ref:`intro_threads`
|
|
||||||
:param thread_type: See :ref:`intro_threads`
|
|
||||||
:type thread_type: models.ThreadType
|
|
||||||
:return: :ref:`Message ID <intro_message_ids>` of the sent videos
|
|
||||||
:raises: FBchatException if request failed
|
|
||||||
"""
|
|
||||||
return self._sendFiles(files={'video': video_ids}, message=None, thread_id=None, thread_type=ThreadType.USER)
|
|
||||||
|
|
||||||
def sendRemoteFiles(self, file_urls, message=None, thread_id=None, thread_type=ThreadType.USER):
|
def sendRemoteFiles(self, file_urls, message=None, thread_id=None, thread_type=ThreadType.USER):
|
||||||
"""
|
"""
|
||||||
Sends files from URLs to a thread
|
Sends files from URLs to a thread
|
||||||
@@ -1197,17 +1134,7 @@ class Client(object):
|
|||||||
:raises: FBchatException if request failed
|
:raises: FBchatException if request failed
|
||||||
"""
|
"""
|
||||||
file_urls = require_list(file_urls)
|
file_urls = require_list(file_urls)
|
||||||
file_ids = list()
|
files = self._upload(get_files_from_urls(file_urls))
|
||||||
files = {'image':[], 'gif':[], 'video':[], 'audio':[], 'file':[]}
|
|
||||||
|
|
||||||
for file_url in file_urls:
|
|
||||||
mimetype = guess_type(file_url)[0]
|
|
||||||
type_ = mimetype.split('/')[0]
|
|
||||||
type_ = 'file' if files.get(type_) is None else 'gif' if mimetype == "image/gif" else type_
|
|
||||||
remote_file = requests.get(file_url).content
|
|
||||||
file_id = self._upload(file_url, remote_file, mimetype, type_=type_)
|
|
||||||
files[type_].append(file_id)
|
|
||||||
|
|
||||||
return self._sendFiles(files=files, message=message, thread_id=thread_id, thread_type=thread_type)
|
return self._sendFiles(files=files, message=message, thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
def sendLocalFiles(self, file_paths, message=None, thread_id=None, thread_type=ThreadType.USER):
|
def sendLocalFiles(self, file_paths, message=None, thread_id=None, thread_type=ThreadType.USER):
|
||||||
@@ -1223,16 +1150,8 @@ class Client(object):
|
|||||||
:raises: FBchatException if request failed
|
:raises: FBchatException if request failed
|
||||||
"""
|
"""
|
||||||
file_paths = require_list(file_paths)
|
file_paths = require_list(file_paths)
|
||||||
file_ids = list()
|
with get_files_from_paths(file_paths) as x:
|
||||||
files = {'image':[], 'gif':[], 'video':[], 'audio':[], 'file':[]}
|
files = self._upload(x)
|
||||||
|
|
||||||
for file_path in file_paths:
|
|
||||||
mimetype = guess_type(file_path)[0]
|
|
||||||
type_ = mimetype.split('/')[0]
|
|
||||||
type_ = 'file' if files.get(type_) is None else 'gif' if mimetype == "image/gif" else type_
|
|
||||||
file_id = self._upload(file_path, open(file_path, 'rb'), mimetype, type_=type_)
|
|
||||||
files[type_].append(file_id)
|
|
||||||
|
|
||||||
return self._sendFiles(files=files, message=message, thread_id=thread_id, thread_type=thread_type)
|
return self._sendFiles(files=files, message=message, thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
def sendImage(self, image_id, message=None, thread_id=None, thread_type=ThreadType.USER, is_gif=False):
|
def sendImage(self, image_id, message=None, thread_id=None, thread_type=ThreadType.USER, is_gif=False):
|
||||||
@@ -1240,21 +1159,21 @@ class Client(object):
|
|||||||
Deprecated. Use :func:`fbchat.Client.sendFiles` instead
|
Deprecated. Use :func:`fbchat.Client.sendFiles` instead
|
||||||
"""
|
"""
|
||||||
if is_gif:
|
if is_gif:
|
||||||
return self.sendGifs(image_ids=image_id, message=message, thread_id=thread_id, thread_type=thread_type)
|
return self._sendFiles(files=[(image_id, "image/png")], message=message, thread_id=thread_id, thread_type=thread_type)
|
||||||
else:
|
else:
|
||||||
return self.sendImages(image_ids=image_id, message=message, thread_id=thread_id, thread_type=thread_type)
|
return self._sendFiles(files=[(image_id, "image/gif")], message=message, thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
def sendRemoteImage(self, image_url, message=None, thread_id=None, thread_type=ThreadType.USER):
|
def sendRemoteImage(self, image_url, message=None, thread_id=None, thread_type=ThreadType.USER):
|
||||||
"""
|
"""
|
||||||
Deprecated. Use :func:`fbchat.Client.sendRemoteFiles` instead
|
Deprecated. Use :func:`fbchat.Client.sendRemoteFiles` instead
|
||||||
"""
|
"""
|
||||||
return self.sendRemoteFiles(file_urls=image_url, message=message, thread_id=thread_id, thread_type=thread_type)
|
return self.sendRemoteFiles(file_urls=[image_url], message=message, thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
def sendLocalImage(self, image_path, message=None, thread_id=None, thread_type=ThreadType.USER):
|
def sendLocalImage(self, image_path, message=None, thread_id=None, thread_type=ThreadType.USER):
|
||||||
"""
|
"""
|
||||||
Deprecated. Use :func:`fbchat.Client.sendLocalFiles` instead
|
Deprecated. Use :func:`fbchat.Client.sendLocalFiles` instead
|
||||||
"""
|
"""
|
||||||
return self.sendLocalFiles(file_paths=image_path, message=message, thread_id=thread_id, thread_type=thread_type)
|
return self.sendLocalFiles(file_paths=[image_path], message=message, thread_id=thread_id, thread_type=thread_type)
|
||||||
|
|
||||||
def createGroup(self, message, person_ids=None):
|
def createGroup(self, message, person_ids=None):
|
||||||
"""Creates a group with the given ids
|
"""Creates a group with the given ids
|
||||||
@@ -1439,15 +1358,8 @@ class Client(object):
|
|||||||
:raises: FBchatException if request failed
|
:raises: FBchatException if request failed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
with get_files_from_urls([image_url]) as files:
|
||||||
|
(image_id, mimetype), = self._upload(files)
|
||||||
if thread_type != ThreadType.GROUP:
|
|
||||||
raise FBchatUserError('Can only change the image of group threads')
|
|
||||||
|
|
||||||
mimetype = guess_type(image_url)[0]
|
|
||||||
is_gif = (mimetype == 'image/gif')
|
|
||||||
remote_image = requests.get(image_url).content
|
|
||||||
image_id = self._upload(image_url, remote_image, mimetype, type_="gif" if is_gif else "image")
|
|
||||||
|
|
||||||
self.changeThreadImage(image_id, thread_id, thread_type)
|
self.changeThreadImage(image_id, thread_id, thread_type)
|
||||||
|
|
||||||
@@ -1462,14 +1374,8 @@ class Client(object):
|
|||||||
:raises: FBchatException if request failed
|
:raises: FBchatException if request failed
|
||||||
"""
|
"""
|
||||||
|
|
||||||
thread_id, thread_type = self._getThread(thread_id, thread_type)
|
with get_files_from_paths([image_path]) as files:
|
||||||
|
(image_id, mimetype), = self._upload(files)
|
||||||
if thread_type != ThreadType.GROUP:
|
|
||||||
raise FBchatUserError('Can only change the image of group threads')
|
|
||||||
|
|
||||||
mimetype = guess_type(image_path)[0]
|
|
||||||
is_gif = (mimetype == 'image/gif')
|
|
||||||
image_id = self._upload(image_path, open(image_path, 'rb'), mimetype, type_="gif" if is_gif else "image")
|
|
||||||
|
|
||||||
self.changeThreadImage(image_id, thread_id, thread_type)
|
self.changeThreadImage(image_id, thread_id, thread_type)
|
||||||
|
|
||||||
|
@@ -5,8 +5,12 @@ import re
|
|||||||
import json
|
import json
|
||||||
from time import time
|
from time import time
|
||||||
from random import random
|
from random import random
|
||||||
|
from contextlib import contextmanager
|
||||||
|
from mimetypes import guess_type
|
||||||
|
from os.path import basename
|
||||||
import warnings
|
import warnings
|
||||||
import logging
|
import logging
|
||||||
|
import requests
|
||||||
from .models import *
|
from .models import *
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@@ -265,3 +269,41 @@ def require_list(list_):
|
|||||||
return set(list_)
|
return set(list_)
|
||||||
else:
|
else:
|
||||||
return set([list_])
|
return set([list_])
|
||||||
|
|
||||||
|
def mimetype_to_key(mimetype):
|
||||||
|
if not mimetype:
|
||||||
|
return "file_id"
|
||||||
|
if mimetype == "image/gif":
|
||||||
|
return "gif_id"
|
||||||
|
x = mimetype.split("/")
|
||||||
|
if x[0] in ["video", "image", "audio"]:
|
||||||
|
return "%s_id" % x[0]
|
||||||
|
return "file_id"
|
||||||
|
|
||||||
|
|
||||||
|
def get_files_from_urls(file_urls):
|
||||||
|
files = []
|
||||||
|
for file_url in file_urls:
|
||||||
|
r = requests.get(file_url)
|
||||||
|
# We could possibly use r.headers.get('Content-Disposition'), see
|
||||||
|
# https://stackoverflow.com/a/37060758
|
||||||
|
files.append((
|
||||||
|
basename(file_url),
|
||||||
|
r.content,
|
||||||
|
r.headers.get('Content-Type') or guess_type(file_url)[0],
|
||||||
|
))
|
||||||
|
return files
|
||||||
|
|
||||||
|
|
||||||
|
@contextmanager
|
||||||
|
def get_files_from_paths(filenames):
|
||||||
|
files = []
|
||||||
|
for filename in filenames:
|
||||||
|
files.append((
|
||||||
|
basename(filename),
|
||||||
|
open(filename, 'rb'),
|
||||||
|
guess_type(filename)[0],
|
||||||
|
))
|
||||||
|
yield files
|
||||||
|
for fn, fp, ft in files:
|
||||||
|
fp.close()
|
||||||
|
Reference in New Issue
Block a user