|
...
|
...
|
@@ -128,6 +128,22 @@ class PostParam(Enum): |
|
|
|
EVENT_INVITE_ONLY = 599950423437029
|
|
|
|
|
|
|
|
|
|
|
|
class RequestSource():
|
|
|
|
const = {
|
|
|
|
1: 'requests_page_pymk',
|
|
|
|
2: 'profile_button',
|
|
|
|
3: 'profile_friends',
|
|
|
|
4: 'group_member_list',
|
|
|
|
5: 'hovercard',
|
|
|
|
}
|
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def get(cls, channel):
|
|
|
|
if isinstance(channel, str):
|
|
|
|
channel = int(channel)
|
|
|
|
return cls.const.get(channel, 'people_you_may_know')
|
|
|
|
|
|
|
|
|
|
|
|
class FacebookClient(Client):
|
|
|
|
def __init__(self,
|
|
|
|
user_obj,
|
|
...
|
...
|
@@ -195,16 +211,21 @@ class FacebookClient(Client): |
|
|
|
res = self._payload_post('/ajax/messenger/context_banner/?profile_id=%s' % fbid, {'__user': self.uid})
|
|
|
|
return res
|
|
|
|
|
|
|
|
def addFriend(self, friend_id):
|
|
|
|
data = {"to_friend": friend_id,
|
|
|
|
"action": "add_friend",
|
|
|
|
"how_found": "profile_button",
|
|
|
|
# "link_data[gt][profile_owner]": friend_id,
|
|
|
|
# "link_data[gt][ref]": "timeline:timeline",
|
|
|
|
# "no_flyout_on_click": "true",
|
|
|
|
# "floc": "profile_box"
|
|
|
|
}
|
|
|
|
res = self._payload_post("/ajax/add_friend/action.php", data)
|
|
|
|
def addFriend(self, fbid, channel=1):
|
|
|
|
how_found = RequestSource.get(channel)
|
|
|
|
data = {
|
|
|
|
"to_friend": fbid,
|
|
|
|
"action": "add_friend",
|
|
|
|
"how_found": how_found,
|
|
|
|
}
|
|
|
|
|
|
|
|
if how_found == 'profile_friends':
|
|
|
|
data['ref_param'] = 'friends_tab'
|
|
|
|
|
|
|
|
if channel == 2:
|
|
|
|
res = self._payload_post("/ajax/add_friend/action.php", data)
|
|
|
|
else:
|
|
|
|
res = self._payload_post("/ajax/add_friend/action?" + self._to_url_params(data), {})
|
|
|
|
return res
|
|
|
|
|
|
|
|
def previewName(self, primary_first, primary_middle, primary_last):
|
|
...
|
...
|
@@ -241,12 +262,12 @@ class FacebookClient(Client): |
|
|
|
except:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def setAvatar(self, fbid):
|
|
|
|
def setAvatar(self, photo_id):
|
|
|
|
'''
|
|
|
|
设置头像
|
|
|
|
'''
|
|
|
|
data = {'x': '0', 'y': '0', 'width': '1', 'height': '1',
|
|
|
|
'photo_id': fbid, 'profile_id': self.uid,
|
|
|
|
'photo_id': photo_id, 'profile_id': self.uid,
|
|
|
|
'source': 'timeline'} # 'source': 'unknown', 'method': 'upload'
|
|
|
|
|
|
|
|
res = self._payload_post('/profile/picture/crop_profile_pic/?' + self._to_url_params(data), {})
|
|
...
|
...
|
@@ -318,7 +339,31 @@ class FacebookClient(Client): |
|
|
|
data = {'sex': sex, 'sex_preferred_pronouns': '1',
|
|
|
|
'privacy[237760973066217]': PostParam.ONLY_ME.value}
|
|
|
|
res = self._post('/profile/edit/infotab/save/gender/', data)
|
|
|
|
return res
|
|
|
|
|
|
|
|
html = parse_html.get_domops_3(res)
|
|
|
|
if 'Gender' in html:
|
|
|
|
return {"success": True}
|
|
|
|
else:
|
|
|
|
raise BaseException("未知错误:", html)
|
|
|
|
|
|
|
|
def setSexualOrientation(self, sex: int):
|
|
|
|
'''
|
|
|
|
设置性取向 1女性 2男性 3双性
|
|
|
|
'''
|
|
|
|
|
|
|
|
data = {
|
|
|
|
'privacy[8787590733]': PostParam.EVERYONE.value
|
|
|
|
}
|
|
|
|
if sex == 1 or sex == 3:
|
|
|
|
data['meeting_sex1'] = 'on'
|
|
|
|
if sex == 2 or sex == 3:
|
|
|
|
data['meeting_sex2'] = 'on'
|
|
|
|
res = self._post('/profile/edit/infotab/save/interested_in/', data)
|
|
|
|
html = parse_html.get_domops_3(res)
|
|
|
|
if 'interested_in' in html:
|
|
|
|
return {"success": True}
|
|
|
|
else:
|
|
|
|
raise BaseException("未知错误:", html)
|
|
|
|
|
|
|
|
def sendSticker(self, sticker_id, thread_id, thread_type=ThreadType.USER):
|
|
|
|
return self.send(
|
|
...
|
...
|
@@ -364,16 +409,25 @@ class FacebookClient(Client): |
|
|
|
sub = (ids.pop(0), names.pop(0))
|
|
|
|
yield sub
|
|
|
|
|
|
|
|
def _friendRequest(self, url=None):
|
|
|
|
def _friendRequest(self, url=None, require_gender=True):
|
|
|
|
if url:
|
|
|
|
j = self._post(url, params={})
|
|
|
|
else:
|
|
|
|
data = {'log_impressions': 'true', 'reloadcontent': 'false'}
|
|
|
|
j = self._post('/ajax/requests/loader/', data)
|
|
|
|
result, next_url = parse_html.friend_unit(j)
|
|
|
|
|
|
|
|
return parse_html.friend_unit(j)
|
|
|
|
if require_gender and result:
|
|
|
|
ids = [x['fbid'] for x in result]
|
|
|
|
users = self.fetchUserInfo(*ids)
|
|
|
|
for r in result:
|
|
|
|
gender = users.get(r['fbid']).gender
|
|
|
|
r['gender'] = 'boy' if 'male_singular' == gender else \
|
|
|
|
('girl' if 'female_singular' == gender else 'unknown')
|
|
|
|
|
|
|
|
def rejectRequest(self, fbid):
|
|
|
|
return result, next_url
|
|
|
|
|
|
|
|
def deleteRequest(self, fbid):
|
|
|
|
data = {'confirm': fbid,
|
|
|
|
'type': 'friend_connect',
|
|
|
|
'request_id': fbid,
|
|
...
|
...
|
@@ -383,10 +437,13 @@ class FacebookClient(Client): |
|
|
|
'ref': 'jewel',
|
|
|
|
'ego_log': '',
|
|
|
|
'actions[reject]': '1',
|
|
|
|
'nctr[_mod]': 'pagelet_bluebar'
|
|
|
|
# 'nctr[_mod]': 'pagelet_bluebar'
|
|
|
|
}
|
|
|
|
res = self._post('/ajax/reqs.php', data)
|
|
|
|
return res
|
|
|
|
detail = res['domops'][0]
|
|
|
|
if detail[0] == 'setContent' and detail[2]:
|
|
|
|
return {"success": True}
|
|
|
|
raise BaseException("未知错误:" + json.dumps(detail))
|
|
|
|
|
|
|
|
def pymkRequest(self) -> tuple:
|
|
|
|
'''
|
|
...
|
...
|
@@ -406,26 +463,39 @@ class FacebookClient(Client): |
|
|
|
yield sub
|
|
|
|
|
|
|
|
def _pymk_request(self, total_ids: list):
|
|
|
|
data = {
|
|
|
|
'''data = {
|
|
|
|
'how_found': 'people_you_may_know',
|
|
|
|
'page': 'pymk_jewel',
|
|
|
|
'instance_name': 'jewel',
|
|
|
|
'show_more': 'true'
|
|
|
|
}
|
|
|
|
'''
|
|
|
|
data = {
|
|
|
|
'how_found': 'requests_page_pymk',
|
|
|
|
'page': 'friends_center',
|
|
|
|
'instance_name': 'friend-browser',
|
|
|
|
'big_pics': 1,
|
|
|
|
'social_context': 1,
|
|
|
|
'network_context': 1,
|
|
|
|
'show_more': True
|
|
|
|
}
|
|
|
|
|
|
|
|
for index, id in enumerate(total_ids):
|
|
|
|
data['friend_browser_id[%d]' % index] = id
|
|
|
|
|
|
|
|
path = "/ajax/growth/friend_browser/checkbox.php" # 直接调用翻页接口
|
|
|
|
j = self._post(path, data)
|
|
|
|
ids, names, _ = parse_html.friend_unit(j)
|
|
|
|
gender = []
|
|
|
|
j = self._post("/ajax/growth/friend_browser/checkbox.php", data)
|
|
|
|
result, _ = parse_html.friend_unit(j)
|
|
|
|
|
|
|
|
if ids:
|
|
|
|
if result:
|
|
|
|
ids = [x['fbid'] for x in result]
|
|
|
|
users = self.fetchUserInfo(*ids)
|
|
|
|
for id in ids:
|
|
|
|
gender.append(users.get(id).gender)
|
|
|
|
for r in result:
|
|
|
|
id = r['fbid']
|
|
|
|
gender = users.get(id).gender
|
|
|
|
r['gender'] = 'boy' if 'male_singular' == gender else \
|
|
|
|
('girl' if 'female_singular' == gender else 'unknown')
|
|
|
|
|
|
|
|
return ids, names, gender
|
|
|
|
return result
|
|
|
|
|
|
|
|
def pymkRemove(self, fbid):
|
|
|
|
'''
|
|
...
|
...
|
@@ -437,7 +507,9 @@ class FacebookClient(Client): |
|
|
|
'how_found': 'people_you_may_know',
|
|
|
|
'nctr[_mod]': 'pagelet_bluebar'}
|
|
|
|
res = self._post('/friends/pymk/xout/', data)
|
|
|
|
return res
|
|
|
|
if res['payload'] == None:
|
|
|
|
return {"success": True}
|
|
|
|
raise BaseException("未知错误:" + json.dumps(res))
|
|
|
|
|
|
|
|
def _to_url_params(self, data: dict):
|
|
|
|
return '&'.join(["{}={}".format(k, v) for k, v in data.items()])
|
|
...
|
...
|
@@ -474,7 +546,7 @@ class FacebookClient(Client): |
|
|
|
sub = (ids.pop(0), names.pop(0))
|
|
|
|
yield sub
|
|
|
|
|
|
|
|
def _outgoingRequest(self, url=None):
|
|
|
|
def _outgoingRequest(self, url=None, require_gender=True):
|
|
|
|
if url:
|
|
|
|
j = self._get(url, {})
|
|
|
|
else:
|
|
...
|
...
|
@@ -482,7 +554,31 @@ class FacebookClient(Client): |
|
|
|
'pager_id': 'outgoing_reqs_pager_5e3a685eb1075' + os.urandom(5).hex()}
|
|
|
|
j = self._get("/friends/requests/outgoing/more/", data)
|
|
|
|
|
|
|
|
return parse_html.friend_unit(j)
|
|
|
|
result, next_url = parse_html.friend_unit(j)
|
|
|
|
|
|
|
|
if require_gender and result:
|
|
|
|
ids = [x['fbid'] for x in result]
|
|
|
|
users = self.fetchUserInfo(*ids)
|
|
|
|
for r in result:
|
|
|
|
gender = users.get(r['fbid']).gender
|
|
|
|
r['gender'] = 'boy' if 'male_singular' == gender else \
|
|
|
|
('girl' if 'female_singular' == gender else 'unknown')
|
|
|
|
return result, next_url
|
|
|
|
|
|
|
|
def cancelRequest(self, fbid):
|
|
|
|
'''
|
|
|
|
取消好友申请
|
|
|
|
:return
|
|
|
|
'''
|
|
|
|
data = {
|
|
|
|
'friend': fbid,
|
|
|
|
'cancel_ref': 'outgoing_requests',
|
|
|
|
}
|
|
|
|
res = self._post('/ajax/friends/requests/cancel.php', data)
|
|
|
|
detail = res['jsmods']['require'][0]
|
|
|
|
if 'FriendRequest/cancel' in json.dumps(detail[3]):
|
|
|
|
return {'success': True}
|
|
|
|
raise BaseException("未知错误:" + json.dumps(detail))
|
|
|
|
|
|
|
|
def searchForCity(self, city):
|
|
|
|
query = {
|
|
...
|
...
|
@@ -573,21 +669,26 @@ class FacebookClient(Client): |
|
|
|
}
|
|
|
|
data = {'target_id': self.uid, 'profile_id': self.uid, 'source': '10'}
|
|
|
|
res = self._post('https://upload.facebook.com/ajax/timeline/cover/upload/', data, files=files)
|
|
|
|
text = json.dumps(res)
|
|
|
|
try:
|
|
|
|
return re.findall(r'data-fbid=\\"(\d+)\\"', text)[0]
|
|
|
|
except:
|
|
|
|
return None
|
|
|
|
|
|
|
|
def setCover(self, fbid):
|
|
|
|
result = res['jsmods']['require'][0]
|
|
|
|
status = result[1]
|
|
|
|
detail = result[3]
|
|
|
|
if isinstance(detail[0], int):
|
|
|
|
return str(detail[0])
|
|
|
|
raise BaseException(status + ' ' + ':'.join(detail[3]))
|
|
|
|
|
|
|
|
def setCover(self, photo_id):
|
|
|
|
'''设置封面图片'''
|
|
|
|
data = {
|
|
|
|
'photo_id': fbid, 'profile_id': self.uid, 'photo_offset_y': '',
|
|
|
|
'photo_id': photo_id, 'profile_id': self.uid, 'photo_offset_y': '',
|
|
|
|
'photo_offset_x': '', 'save': '1',
|
|
|
|
'nctr[_mod]': 'pagelet_timeline_main_column'
|
|
|
|
}
|
|
|
|
res = self._post("/ajax/timeline/cover_photo_select.php?av=%s" % self.uid, data)
|
|
|
|
return res
|
|
|
|
html = parse_html.get_domops_3(res)
|
|
|
|
m = re.search(r'src="(.*?)"', html)
|
|
|
|
if m:
|
|
|
|
return {'src': m.group(1).replace('&', '&')}
|
|
|
|
raise BaseException("设置封面未知错误:" + json.dumps(res['jsmods']['require'][0]))
|
|
|
|
|
|
|
|
def info(self):
|
|
|
|
data = {
|
|
...
|
...
|
@@ -596,4 +697,23 @@ class FacebookClient(Client): |
|
|
|
'page_url': self._state.page_url,
|
|
|
|
'imageurl': self._state.imageurl
|
|
|
|
}
|
|
|
|
return data |
|
|
\ No newline at end of file |
|
|
|
return data
|
|
|
|
|
|
|
|
def followProfile(self, fbid, status=True):
|
|
|
|
'''关注个人主页'''
|
|
|
|
data = {
|
|
|
|
'profile_id': fbid,
|
|
|
|
'location': 1,
|
|
|
|
}
|
|
|
|
if status:
|
|
|
|
url_ = '/ajax/follow/follow_profile.php'
|
|
|
|
else:
|
|
|
|
url_ = '/ajax/follow/unfollow_profile.php'
|
|
|
|
res = self._post(url_, data)
|
|
|
|
if 'onload' not in res:
|
|
|
|
raise BaseException("未知错误:" + res)
|
|
|
|
|
|
|
|
onloads = json.dumps(res['onload'])
|
|
|
|
if 'Arbiter.inform' in onloads:
|
|
|
|
return {"success": True}
|
|
|
|
raise BaseException("未知错误:" + onloads) |
...
|
...
|
|