diff --git a/README.md b/README.md
index 871a9a3..79116ff 100644
--- a/README.md
+++ b/README.md
@@ -25,7 +25,7 @@ XNXX API is an API for xnxx.com. It allows you to fetch information from videos
```python
-from xnxx_api import Client, Quality, threaded, default, FFMPEG
+from xnxx_api import Client
# Initialize a Client object
client = Client()
@@ -37,7 +37,7 @@ print(video_object.title)
print(video_object.likes)
# Download the video
-video_object.download(downloader=threaded, quality=Quality.BEST, path="your_output_path + filename")
+video_object.download(downloader="threaded", quality="best", path="your_output_path + filename")
# SEE DOCUMENTATION FOR MORE
```
@@ -48,6 +48,17 @@ video_object.download(downloader=threaded, quality=Quality.BEST, path="your_outp
# Changelog
See [Changelog](https://github.com/EchterAlsFake/xnxx_api/blob/master/README/Changelog.md) for more details.
+# Support (Donations)
+I am developing all my projects entirely for free. I do that because I have fun and I don't want
+to charge 30€ like other people do.
+
+However, if you find my work useful, please consider donating something. A tiny amount such as 1€
+means a lot to me.
+
+Paypal: https://paypal.me/EchterAlsFake
+
XMR (Monero): `46xL2reuanxZgFxXBBaoagiEJK9c7bL7aiwKNR15neyX2wUsX2QVzkeRMVG2Cro44qLUNYvsP1BQa12KPbNat2ML41nyEeq`
+
+
# Contribution
Do you see any issues or having some feature requests? Simply open an Issue or talk
in the discussions.
@@ -56,5 +67,4 @@ Pull requests are also welcome.
# License
Licensed under the LGPLv3 License
-
-Copyright (C) 2023–2024 Johannes Habel
+
Copyright (C) 2023–2025 Johannes Habel
diff --git a/README/Changelog.md b/README/Changelog.md
index 083cd8c..f403c48 100644
--- a/README/Changelog.md
+++ b/README/Changelog.md
@@ -19,4 +19,11 @@
- fixed an issue with video loading
# 1.4.1
-- added support for mode searching #2
\ No newline at end of file
+- added support for mode searching #2
+
+# 1.4.0
+- proxy support (See Documentation)
+- updated to eaf_base_api v2
+- written tests for search and user objects
+- removed headers, cuz they were broken
+- type hinting
\ No newline at end of file
diff --git a/setup.py b/setup.py
index e666e76..29923e7 100644
--- a/setup.py
+++ b/setup.py
@@ -2,7 +2,7 @@
setup(
name="xnxx_api",
- version="1.4.3",
+ version="1.5.0",
packages=find_packages(),
install_requires=[
"requests", "bs4", "lxml", "ffmpeg-progress-yield", "eaf_base_api"
diff --git a/xnxx_api/__init__.py b/xnxx_api/__init__.py
index e136bdc..3c664cd 100644
--- a/xnxx_api/__init__.py
+++ b/xnxx_api/__init__.py
@@ -1,10 +1,10 @@
# xnxx_api/__init__.py
__all__ = [
- "Client", "Core", "Quality", "Video", "Callback", "threaded", "default", "FFMPEG",
+ "Client", "BaseCore", "Video", "Callback",
"errors", "consts", "search_filters", "category"
]
# Public API from xnxx_api.py
-from xnxx_api.xnxx_api import Client, Core, Quality, Video, Callback, threaded, default, FFMPEG
+from xnxx_api.xnxx_api import Client, BaseCore, Video, Callback
from xnxx_api.modules import errors, consts, category, search_filters
\ No newline at end of file
diff --git a/xnxx_api/modules/consts.py b/xnxx_api/modules/consts.py
index 2ea8bfc..ce1ea27 100644
--- a/xnxx_api/modules/consts.py
+++ b/xnxx_api/modules/consts.py
@@ -3,23 +3,6 @@
# ROOT URLs
ROOT_URL = "https://www.xnxx.com/"
-HEADERS = {
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.0.0 Safari/537.36",
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
- "Accept-Language": "en-US,en;q=0.9",
- "Accept-Encoding": "gzip, deflate, br",
- "DNT": "1", # Do Not Track request header
- "Connection": "keep-alive",
- "Upgrade-Insecure-Requests": "1",
- "Sec-Fetch-Site": "none",
- "Sec-Fetch-Mode": "navigate",
- "Sec-Fetch-User": "?1",
- "Sec-Fetch-Dest": "document",
- "Host": "www.xnxx.com",
- "Referer": "https://www.xnxx.com"
-}
-
-
# REGEX
REGEX_VIDEO_CHECK = re.compile(r"xnxx.com/(.*?)")
REGEX_VIDEO_TITLE = re.compile(r"html5player\.setVideoTitle\('([^']*)'\);")
diff --git a/xnxx_api/tests/test_search.py b/xnxx_api/tests/test_search.py
new file mode 100644
index 0000000..44fa3bf
--- /dev/null
+++ b/xnxx_api/tests/test_search.py
@@ -0,0 +1,11 @@
+from ..xnxx_api import Client
+
+client = Client()
+search = client.search("fortnite")
+
+def test_search():
+ for idx, video in enumerate(search.videos):
+ assert isinstance(video.title, str)
+
+ if idx == 3:
+ break
\ No newline at end of file
diff --git a/xnxx_api/tests/test_user.py b/xnxx_api/tests/test_user.py
new file mode 100644
index 0000000..83b0920
--- /dev/null
+++ b/xnxx_api/tests/test_user.py
@@ -0,0 +1,19 @@
+from ..xnxx_api import Client
+
+client = Client()
+user = client.get_user("https://www.xnxx.com/pornstar/cory-chase")
+objects_video = ["title", "publish_date", "length", "author"]
+
+
+
+def test_video_views():
+ assert isinstance(user.total_video_views, str)
+ assert user.total_videos > 0
+
+def test_videos():
+ for idx, video in enumerate(user.videos):
+ if idx == 3:
+ break
+ for object in objects_video:
+ assert isinstance(getattr(video, object), str)
+
diff --git a/xnxx_api/tests/test_video.py b/xnxx_api/tests/test_video.py
index 912c6a6..9da7264 100644
--- a/xnxx_api/tests/test_video.py
+++ b/xnxx_api/tests/test_video.py
@@ -1,5 +1,4 @@
from ..xnxx_api import Video
-from base_api.modules.quality import Quality
url = "https://www.xnxx.com/video-1b9bufc9/die_zierliche_stieftochter_passt_kaum_in_den_mund_ihres_stiefvaters"
# This will be the URL for all tests
@@ -77,5 +76,8 @@ def test_content_url():
def test_get_segments():
- segments = list(video.get_segments(quality=Quality.BEST))
+ segments = list(video.get_segments(quality="best"))
assert len(segments) > 10
+
+def test_download_low():
+ assert video.download(quality="worst", downloader="threaded") is True
\ No newline at end of file
diff --git a/xnxx_api/xnxx_api.py b/xnxx_api/xnxx_api.py
index a29f8ac..71eb02c 100644
--- a/xnxx_api/xnxx_api.py
+++ b/xnxx_api/xnxx_api.py
@@ -8,23 +8,31 @@
from .modules.errors import *
from .modules.search_filters import *
-import json
+import os
import html
+import json
+import logging
import argparse
-import os
+import traceback
+from typing import Union, Generator
from bs4 import BeautifulSoup
from functools import cached_property
-from base_api import Core, Quality, threaded, default, FFMPEG, Callback, setup_api
+from base_api import BaseCore, Callback
+
+core = BaseCore()
+logging.basicConfig(format='%(name)s %(levelname)s %(asctime)s %(message)s', datefmt='%I:%M:%S %p')
+logger = logging.getLogger("XNXX API")
+logger.setLevel(logging.DEBUG)
-base_qualities = ["250p", "360p", "480p", "720p", "1080p", "1440p", "2160p"]
+def disable_logging() -> None:
+ logger.setLevel(logging.CRITICAL)
class Video:
def __init__(self, url):
self.url = url
self.available_m3u8_urls = None
- self.available_qualities = None
self.script_content = None
self.html_content = None
self.metadata_matches = None
@@ -39,8 +47,8 @@ def __init__(self, url):
self.get_metadata_matches()
self.extract_json_from_html()
- def get_base_html(self):
- self.html_content = Core().get_content(url=self.url, headers=None, cookies=None).decode("utf-8")
+ def get_base_html(self) -> None:
+ self.html_content = core.fetch(url=self.url)
@classmethod
def is_desired_script(cls, tag):
@@ -49,7 +57,7 @@ def is_desired_script(cls, tag):
script_contents = ['html5player', 'setVideoTitle', 'setVideoUrlLow']
return all(content in tag.text for content in script_contents)
- def get_metadata_matches(self):
+ def get_metadata_matches(self) -> None:
soup = BeautifulSoup(self.html_content, 'html.parser')
metadata_span = soup.find('span', class_='metadata')
metadata_text = metadata_span.get_text(separator=' ', strip=True)
@@ -57,7 +65,7 @@ def get_metadata_matches(self):
# Use a regex to extract the desired strings
self.metadata_matches = re.findall(r'(\d+min|\d+p|\d[\d.,]*\s*[views]*)', metadata_text)
- def get_script_content(self):
+ def get_script_content(self) -> None:
soup = BeautifulSoup(self.html_content, 'lxml')
target_script = soup.find(self.is_desired_script)
if target_script:
@@ -66,7 +74,7 @@ def get_script_content(self):
else:
raise InvalidResponse("Couldn't extract JSON from HTML")
- def extract_json_from_html(self):
+ def extract_json_from_html(self) -> None:
soup = BeautifulSoup(self.html_content, 'lxml')
# Find the