async def get_highlights( self, identifier: int | str = "", refresh: bool = True, limit: int = 100, offset: int = 0, hightlight_id: int | str = "", ) -> Union[list[create_highlight], list[create_story]]: result, status = await api_helper.default_data(self, refresh) if status: return result if not identifier: identifier = self.id if not hightlight_id: link = endpoint_links(identifier=identifier, global_limit=limit, global_offset=offset).list_highlights results = await self.get_session_manager().json_request(link) results = await api_helper.remove_errors(results) results = [create_highlight(x) for x in results] else: link = endpoint_links(identifier=hightlight_id, global_limit=limit, global_offset=offset).highlight results = await self.get_session_manager().json_request(link) results = [create_story(x) for x in results["stories"]] return results
async def get_chats( self, links: Optional[list] = None, limit=100, offset=0, refresh=True, inside_loop=False, ) -> list: api_type = "chats" if not self.active: return [] if not refresh: result = handle_refresh(self, api_type) if result: return result if links is None: links = [] api_count = self.chatMessagesCount if api_count and not links: link = endpoint_links(identifier=self.id, global_limit=limit, global_offset=offset).list_chats ceil = math.ceil(api_count / limit) numbers = list(range(ceil)) for num in numbers: num = num * limit link = link.replace(f"limit={limit}", f"limit={limit}") new_link = link.replace("offset=0", f"offset={num}") links.append(new_link) multiplier = getattr(self.session_manager.pool, "_processes") if links: link = links[-1] else: link = endpoint_links(identifier=self.id, global_limit=limit, global_offset=offset).list_chats links2 = api_helper.calculate_the_unpredictable( link, limit, multiplier) if not inside_loop: links += links2 else: links = links2 results = await self.session_manager.async_requests(links) has_more = results[-1]["hasMore"] final_results = [x["list"] for x in results] final_results = list(chain.from_iterable(final_results)) if has_more: results2 = await self.get_chats(links=[links[-1]], limit=limit, offset=limit + offset, inside_loop=True) final_results.extend(results2) final_results.sort(key=lambda x: x["withUser"]["id"], reverse=True) self.chats = final_results return final_results
async def get_message_by_id( self, user_id: Optional[int] = None, message_id: Optional[int] = None, refresh: bool = True, limit: int = 10, offset: int = 0, ): if not user_id: user_id = self.id link = endpoint_links( identifier=user_id, identifier2=message_id, global_limit=limit, global_offset=offset, ).message_by_id response = await self.get_session_manager().json_request(link) if isinstance(response, dict): temp_response: dict[str, Any] = response results: list[dict[str, Any]] = [ x for x in temp_response["list"] if x["id"] == message_id ] result = results[0] if results else {} final_result = message_model.create_message(result, self) return final_result return response
async def get_paid_content( self, check: bool = False, refresh: bool = True, limit: int = 10, offset: int = 0, inside_loop: bool = False, ) -> list[create_product] | ErrorDetails: result, status = await api_helper.default_data(self, refresh) if status: return result link = endpoint_links(global_limit=limit, global_offset=offset).paid_api final_results = await self.session_manager.json_request(link) if not isinstance(final_results, ErrorDetails): if len(final_results) >= limit and not check: results2 = await self.get_paid_content(limit=limit, offset=limit + offset, inside_loop=True) final_results.extend(results2) if not inside_loop: temp: list[create_product] = [] for final_result in final_results: user = create_user(final_result["author"], self) content = create_product(final_result, user) content.media = [content.media] temp.append(content) final_results = temp self.paid_content = final_results return final_results
async def get_archived_posts( self, links: Optional[list[str]] = None, refresh: bool = True, limit: int = 10, offset: int = 0, ): result, status = await api_helper.default_data(self, refresh) if status: return result if links is None: links = [] api_count = self.archivedPostsCount if api_count and not links: link = endpoint_links(identifier=self.id, global_limit=limit, global_offset=offset).archived_posts ceil = math.ceil(api_count / limit) numbers = list(range(ceil)) for num in numbers: num = num * limit link = link.replace(f"limit={limit}", f"limit={limit}") new_link = link.replace("offset=0", f"offset={num}") links.append(new_link) results = await api_helper.scrape_endpoint_links( links, self.get_session_manager()) final_results = self.finalize_content_set(results) self.temp_scraped.Archived.Posts = final_results return final_results
async def get_user( self, identifier: Union[str, int]) -> Union[create_user, ErrorDetails]: link = endpoint_links(identifier).users response = await self.session_manager.json_request(link) if not isinstance(response, ErrorDetails): response["session_manager"] = self.session_manager response = create_user(response, self) return response
async def favorite(self): link = endpoint_links( identifier=f"{self.responseType}s", identifier2=self.id, identifier3=self.author.id, ).favorite results = await self.user.session_manager.json_request(link, method="POST") self.isFavorite = True return results
async def get_messages( self, links: Optional[list[str]] = None, limit: int = 10, offset: int = 0, refresh: bool = True, inside_loop: bool = False, ): result, status = await api_helper.default_data(self, refresh) if status: return result if links is None: links = [] multiplier = self.get_session_manager().max_threads if links: link = links[-1] else: link = endpoint_links(identifier=self.id, global_limit=limit, global_offset=offset).message_api links.append(link) links2 = api_helper.calculate_the_unpredictable( link, limit, multiplier) if not inside_loop: links += links2 else: links = links2 results = await self.get_session_manager().async_requests(links) results = await api_helper.remove_errors(results) final_results = [] if isinstance(results, list): has_more = results[-1]["list"] if results else False final_results = [x["list"] for x in results if "list" in x] final_results = list(chain.from_iterable(final_results)) if has_more: results2 = await self.get_messages( links=[links[-1]], limit=limit, offset=limit + offset, inside_loop=True, ) final_results.extend(results2) print if not inside_loop: final_results = [ message_model.create_message(x, self) for x in final_results if x ] else: final_results.sort(key=lambda x: x["fromUser"]["id"], reverse=True) self.temp_scraped.Messages = final_results return final_results
async def get_archived_stories( self, refresh: bool = True, limit: int = 100, offset: int = 0 ): result, status = await api_helper.default_data(self, refresh) if status: return result link = endpoint_links(global_limit=limit, global_offset=offset).archived_stories results = await self.get_session_manager().json_request(link) results = await api_helper.remove_errors(results) results = [create_story(x) for x in results] return results
async def get_post( self, identifier: Optional[int | str] = None, limit: int = 10, offset: int = 0 ) -> Union[create_post, ErrorDetails]: if not identifier: identifier = self.id link = endpoint_links( identifier=identifier, global_limit=limit, global_offset=offset ).post_by_id result = await self.get_session_manager().json_request(link) if isinstance(result, dict): temp_result: dict[str, Any] = result final_result = post_model.create_post(temp_result, self) return final_result return result
async def get_authed(self): if not self.active: link = endpoint_links().customer response = await self.session_manager.json_request(link) if response: await self.resolve_auth_errors(response) if not self.errors: # merged = self.__dict__ | response # self = create_auth(merged,self.pool,self.session_manager.max_threads) self.active = True self.update(response) else: # 404'ed self.active = False return self
async def search_messages( self, identifier: int | str = "", text: str = "", refresh: bool = True, limit: int = 10, offset: int = 0, ): if identifier: identifier = parse.urljoin(str(identifier), "messages") text = parse.quote_plus(text) link = endpoint_links( identifier=identifier, text=text, global_limit=limit, global_offset=offset ).search_messages results = await self.get_session_manager().json_request(link) return results
async def buy_message(self): """ This function will buy a ppv message from a model. """ message_price = self.price x = { "amount": message_price, "messageId": self.id, "paymentType": "message", "token": "", "unavailablePaymentGates": [], } link = endpoint_links().pay result = await self.user.session_manager.json_request(link, method="POST", payload=x) return result
async def get_stories(self, refresh: bool = True, limit: int = 100, offset: int = 0) -> list[create_story]: result, status = await api_helper.default_data(self, refresh) if status: return result link = [ endpoint_links(identifier=self.id, global_limit=limit, global_offset=offset).stories_api ] results = await api_helper.scrape_endpoint_links( link, self.get_session_manager()) results = [create_story(x) for x in results] self.temp_scraped.Stories = results return results
async def search_chat( self, identifier: int | str = "", text: str = "", refresh: bool = True, limit: int = 10, offset: int = 0, ): # Onlyfans can't do a simple search, so this is broken. If you want it to "work", don't use commas, or basically any mysql injection characters (lol) if identifier: identifier = parse.urljoin(str(identifier), "messages") else: identifier = self.id link = endpoint_links( identifier=identifier, text=text, global_limit=limit, global_offset=offset ).search_chat results = await self.get_session_manager().json_request(link) return results
async def get_lists_users( self, identifier: int | str, check: bool = False, limit: int = 100, offset: int = 0, ): result, status = await api_helper.default_data(self, refresh=True) if status: return result link = endpoint_links(identifier, global_limit=limit, global_offset=offset).lists_users results = await self.session_manager.json_request(link) if len(results) >= limit and not check: results2 = await self.get_lists_users(identifier, limit=limit, offset=limit + offset) results.extend(results2) return results
async def get_posts( self, links: Optional[list[str]] = None, limit: int = 10, offset: int = 0, refresh: bool = True, ) -> Optional[list[create_post | create_product]]: result, status = await api_helper.default_data(self, refresh) if status: return result if links is None: links = [] if not links: epl = endpoint_links() link = epl.list_posts(self.id) links = epl.create_links(link, self.postsCount) results = await api_helper.scrape_endpoint_links( links, self.get_session_manager()) final_results = self.finalize_content_set(results) self.temp_scraped.Posts = final_results return final_results
async def buy_subscription(self): """ This function will subscribe to a model. If the model has a promotion available, it will use it. """ subscription_price = await self.subscription_price() x: dict[str, Any] = { "paymentType": "subscribe", "userId": self.id, "subscribeSource": "profile", "amount": subscription_price, "token": "", "unavailablePaymentGates": [], } if self.__authed.creditBalance >= subscription_price: link = endpoint_links().pay result = await self.get_session_manager().json_request( link, method="POST", payload=x) else: result = ErrorDetails({ "code": 2011, "message": "Insufficient Credit Balance" }) return result
async def get_mass_messages( self, resume: Optional[list[dict[str, Any]]] = None, refresh: bool = True, limit: int = 10, offset: int = 0, ) -> list[dict[str, Any]]: result, status = await api_helper.default_data(self, refresh) if status: return result link = endpoint_links(global_limit=limit, global_offset=offset).mass_messages_api results = await self.session_manager.json_request(link) items = results.get("list", []) if not items: return items if resume: for item in items: if any(x["id"] == item["id"] for x in resume): resume.sort(key=lambda x: x["id"], reverse=True) self.mass_messages = resume return resume else: resume.append(item) if results["hasMore"]: results2 = self.get_mass_messages(resume=resume, limit=limit, offset=limit + offset) items.extend(results2) if resume: items = resume items.sort(key=lambda x: x["id"], reverse=True) self.mass_messages = items return items
async def login(self, max_attempts: int = 10, guest: bool = False): auth_version = "(V1)" auth_items = self.auth_details if not auth_items: return self if guest and auth_items: auth_items.cookie.auth_id = "0" auth_items.user_agent = generate_user_agent() # type: ignore link = endpoint_links().customer user_agent = auth_items.user_agent # type: ignore auth_id = str(auth_items.cookie.auth_id) # expected string error is fixed by auth_id dynamic_rules = self.session_manager.dynamic_rules a: List[Any] = [dynamic_rules, auth_id, user_agent, link] self.session_manager.headers = create_headers(*a) if guest: print("Guest Authentication") return self count = 1 while count < max_attempts + 1: string = f"Auth {auth_version} Attempt {count}/{max_attempts}" print(string) await self.get_authed() count += 1 async def resolve_auth(auth: create_auth): if self.errors: error = self.errors[-1] print(error.message) if error.code == 101: if auth_items.support_2fa: link = f"https://onlyfans.com/api2/v2/users/otp/check" count = 1 max_count = 3 while count < max_count + 1: print("2FA Attempt " + str(count) + "/" + str(max_count)) code = input("Enter 2FA Code\n") data = {"code": code, "rememberMe": True} response = await self.session_manager.json_request( link, method="POST", payload=data) if isinstance(response, ErrorDetails): error.message = response.message count += 1 else: print("Success") auth.active = False auth.errors.remove(error) await self.get_authed() break await resolve_auth(self) if not self.active: if self.errors: error = self.errors[-1] error_message = error.message if "token" in error_message: pass if "Code wrong" in error_message: break if "Please refresh" in error_message: break else: print("Auth 404'ed") continue else: print( f"Welcome {' | '.join([x for x in [self.name, self.username] if x])}" ) self.create_directory_manager() break if not self.active: user = await self.get_user(auth_id) if isinstance(user, create_user): self.update(user.__dict__) return self
async def get_subscriptions( self, refresh: bool = True, identifiers: list[int | str] = [], extra_info: bool = True, limit: int = 20, ) -> list[create_user]: result, status = await api_helper.default_data(self, refresh) if status: return result # if self.subscribesCount > 900: # limit = 100 ceil = math.ceil(self.subscribesCount / limit) a = list(range(ceil)) offset_array: list[str] = [] for b in a: b = b * limit link = endpoint_links(global_limit=limit, global_offset=b).subscriptions offset_array.append(link) results: list[list[create_user]] = [] if not identifiers: async def multi(item: str): link = item subscriptions = await self.session_manager.json_request(link) valid_subscriptions: list[create_user] = [] extras = {} extras["auth_check"] = "" if isinstance(subscriptions, ErrorDetails): return subscriptions = [ subscription for subscription in subscriptions["list"] if "error" != subscription ] tasks: list[Task[create_user | ErrorDetails]] = [] for subscription in subscriptions: subscription["session_manager"] = self.session_manager if extra_info: task = asyncio.create_task( self.get_user(subscription["username"])) tasks.append(task) results2 = await asyncio.gather(*tasks) for result in results2: if isinstance(result, ErrorDetails): continue if not result: print subscription2: create_user = result for subscription in subscriptions: if subscription["id"] != subscription2.id: continue subscribedByData = {} new_date = datetime.utcnow().replace( tzinfo=timezone.utc) + relativedelta(years=1) temp = subscription.get("subscribedByExpireDate", new_date) if isinstance(temp, str): new_date = datetime.fromisoformat(temp) subscribedByData["expiredAt"] = new_date subscription2.subscribedByData = subscribedByData subscription["mediaCount"] = subscription2.mediasCount subscription = subscription | subscription2.__dict__ subscription = create_user(subscription, self) if subscription.isBlocked: continue valid_subscriptions.append(subscription) return valid_subscriptions # If user is a creator, add them to the subscription list if self.isPerformer: subscription = await self.convert_to_user() if isinstance(subscription, ErrorDetails): return result subscription.subscribedByData = {} new_date = datetime.now() + relativedelta(years=1) subscription.subscribedByData[ "expiredAt"] = new_date.isoformat() subscriptions = [subscription] results.append(subscriptions) pool = self.pool tasks = pool.starmap(multi, product(offset_array)) results2 = await asyncio.gather(*tasks) results2 = list(filter(None, results2)) results.extend(results2) else: for identifier in identifiers: if self.id == identifier or self.username == identifier: continue link = endpoint_links(identifier=identifier).users result = await self.session_manager.json_request(link) if isinstance(result, ErrorDetails) or not result["subscribedBy"]: continue subscription = create_user(result, self) if subscription.isBlocked: continue results.append([subscription]) print print final_results = [x for x in results if x is not None] final_results = list(chain(*final_results)) self.subscriptions = final_results return final_results
async def unlike(self, category: str, identifier: int): link = endpoint_links(identifier=category, identifier2=identifier).like results = await self.get_session_manager().json_request( link, method="DELETE") return results