|
@@ -15,152 +15,56 @@
|
|
|
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
from __future__ import annotations
|
|
|
|
|
|
-from uuid import uuid4
|
|
|
-import json
|
|
|
import random
|
|
|
import time
|
|
|
|
|
|
-from ..types import FinishUploadResponse, MediaType, UploadPhotoResponse, UploadVideoResponse
|
|
|
+from yarl import URL
|
|
|
+
|
|
|
+from ..types import FacebookUploadResponse
|
|
|
from .base import BaseAndroidAPI
|
|
|
|
|
|
|
|
|
class UploadAPI(BaseAndroidAPI):
|
|
|
- async def upload_photo(
|
|
|
- self,
|
|
|
- data: bytes,
|
|
|
- mime: str,
|
|
|
- upload_id: str | None = None,
|
|
|
- width: int | None = None,
|
|
|
- height: int | None = None,
|
|
|
- ) -> UploadPhotoResponse:
|
|
|
- upload_id = upload_id or str(int(time.time() * 1000))
|
|
|
- name = f"{upload_id}_0_{random.randint(1000000000, 9999999999)}"
|
|
|
- params = {
|
|
|
- "retry_context": json.dumps(
|
|
|
- {
|
|
|
- "num_step_auto_retry": 0,
|
|
|
- "num_reupload": 0,
|
|
|
- "num_step_manual_retry": 0,
|
|
|
- }
|
|
|
- ),
|
|
|
- "media_type": str(MediaType.IMAGE.value),
|
|
|
- "upload_id": upload_id,
|
|
|
- "xsharing_user_ids": json.dumps([]),
|
|
|
- }
|
|
|
- if mime == "image/jpeg":
|
|
|
- params["image_compression"] = json.dumps(
|
|
|
- {"lib_name": "moz", "lib_version": "3.1.m", "quality": 80}
|
|
|
- )
|
|
|
- if width and height:
|
|
|
- params["original_width"] = str(width)
|
|
|
- params["original_height"] = str(height)
|
|
|
- headers = {
|
|
|
- "X_FB_PHOTO_WATERFALL_ID": str(uuid4()),
|
|
|
- "X-Entity-Type": mime,
|
|
|
- "Offset": "0",
|
|
|
- "X-Instagram-Rupload-Params": json.dumps(params),
|
|
|
- "X-Entity-Name": name,
|
|
|
- "X-Entity-Length": str(len(data)),
|
|
|
+ rupload_fb = URL("https://rupload.facebook.com")
|
|
|
+
|
|
|
+ def _make_rupload_headers(self, length: int, name: str, mime: str) -> dict[str, str]:
|
|
|
+ return {
|
|
|
+ **self._rupload_headers,
|
|
|
+ "x-entity-length": str(length),
|
|
|
+ "x-entity-name": name,
|
|
|
+ "x-entity-type": mime,
|
|
|
+ "offset": "0",
|
|
|
"Content-Type": "application/octet-stream",
|
|
|
"priority": "u=6, i",
|
|
|
}
|
|
|
- return await self.std_http_post(
|
|
|
- f"/rupload_igphoto/{name}",
|
|
|
- headers=headers,
|
|
|
- data=data,
|
|
|
- raw=True,
|
|
|
- response_type=UploadPhotoResponse,
|
|
|
- )
|
|
|
|
|
|
- async def upload_mp4(
|
|
|
+ async def upload(
|
|
|
self,
|
|
|
data: bytes,
|
|
|
+ mimetype: str,
|
|
|
upload_id: str | None = None,
|
|
|
- audio: bool = False,
|
|
|
- duration_ms: int | None = None,
|
|
|
- width: int | None = None,
|
|
|
- height: int | None = None,
|
|
|
- ) -> tuple[UploadVideoResponse, str]:
|
|
|
+ ) -> FacebookUploadResponse:
|
|
|
upload_id = upload_id or str(int(time.time() * 1000))
|
|
|
name = f"{upload_id}_0_{random.randint(1000000000, 9999999999)}"
|
|
|
- media_type = MediaType.AUDIO if audio else MediaType.VIDEO
|
|
|
- params: dict[str, str] = {
|
|
|
- "retry_context": json.dumps(
|
|
|
- {
|
|
|
- "num_step_auto_retry": 0,
|
|
|
- "num_reupload": 0,
|
|
|
- "num_step_manual_retry": 0,
|
|
|
- }
|
|
|
- ),
|
|
|
- "media_type": str(media_type.value),
|
|
|
- "upload_id": upload_id,
|
|
|
- "xsharing_user_ids": json.dumps([]),
|
|
|
- }
|
|
|
- if duration_ms:
|
|
|
- params["upload_media_duration_ms"] = str(duration_ms)
|
|
|
- if audio:
|
|
|
- params["is_direct_voice"] = "1"
|
|
|
+ headers = self._make_rupload_headers(len(data), name, mimetype)
|
|
|
+ if mimetype.startswith("image/"):
|
|
|
+ path_type = "messenger_gif" if mimetype == "image/gif" else "messenger_image"
|
|
|
+ headers["image_type"] = "FILE_ATTACHMENT"
|
|
|
+ elif mimetype.startswith("video/"):
|
|
|
+ path_type = "messenger_video"
|
|
|
+ headers["video_type"] = "FILE_ATTACHMENT"
|
|
|
+ elif mimetype.startswith("audio/"):
|
|
|
+ path_type = "messenger_audio"
|
|
|
+ headers["audio_type"] = "VOICE_MESSAGE"
|
|
|
else:
|
|
|
- params["direct_v2"] = "1"
|
|
|
- params["for_direct_story"] = "1"
|
|
|
- params["content_tags"] = "use_default_cover"
|
|
|
- params["extract_cover_frame"] = "1"
|
|
|
- if width and height:
|
|
|
- params["upload_media_width"] = str(width)
|
|
|
- params["upload_media_height"] = str(height)
|
|
|
- headers = {
|
|
|
- "X_FB_VIDEO_WATERFALL_ID": str(uuid4()),
|
|
|
- "X-Entity-Type": "audio/mp4" if audio else "video/mp4",
|
|
|
- "Offset": "0",
|
|
|
- "X-Instagram-Rupload-Params": json.dumps(params),
|
|
|
- "X-Entity-Name": name,
|
|
|
- "X-Entity-Length": str(len(data)),
|
|
|
- "Content-Type": "application/octet-stream",
|
|
|
- "priority": "u=6, i",
|
|
|
- }
|
|
|
- if not audio:
|
|
|
- headers["segment-type"] = "3"
|
|
|
- headers["segment-start-offset"] = "0"
|
|
|
- return (
|
|
|
- await self.std_http_post(
|
|
|
- f"/rupload_igvideo/{name}",
|
|
|
- headers=headers,
|
|
|
- data=data,
|
|
|
- raw=True,
|
|
|
- response_type=UploadVideoResponse,
|
|
|
- ),
|
|
|
- upload_id,
|
|
|
- )
|
|
|
-
|
|
|
- async def finish_upload(
|
|
|
- self, upload_id: str, source_type: str, video: bool = False
|
|
|
- ) -> FinishUploadResponse:
|
|
|
- headers = {
|
|
|
- "retry_context": json.dumps(
|
|
|
- {
|
|
|
- "num_step_auto_retry": 0,
|
|
|
- "num_reupload": 0,
|
|
|
- "num_step_manual_retry": 0,
|
|
|
- }
|
|
|
- ),
|
|
|
- }
|
|
|
- req = {
|
|
|
- "timezone_offset": self.state.device.timezone_offset,
|
|
|
- "_csrftoken": self.state.cookies.csrf_token,
|
|
|
- "source_type": source_type,
|
|
|
- "_uid": self.state.session.ds_user_id,
|
|
|
- "device_id": self.state.device.id,
|
|
|
- "_uuid": self.state.device.uuid,
|
|
|
- "upload_id": upload_id,
|
|
|
- "device": self.state.device.payload,
|
|
|
- }
|
|
|
- query = {}
|
|
|
- if video:
|
|
|
- query["video"] = "1"
|
|
|
+ path_type = "messenger_file"
|
|
|
+ headers["file_type"] = "FILE_ATTACHMENT"
|
|
|
return await self.std_http_post(
|
|
|
- "/api/v1/media/upload_finish/",
|
|
|
+ f"/{path_type}/{name}",
|
|
|
+ url_override=self.rupload_fb,
|
|
|
+ default_headers=False,
|
|
|
headers=headers,
|
|
|
- data=req,
|
|
|
- query=query,
|
|
|
- response_type=FinishUploadResponse,
|
|
|
+ data=data,
|
|
|
+ raw=True,
|
|
|
+ response_type=FacebookUploadResponse,
|
|
|
)
|