phub 4.8.6__tar.gz → 4.8.8__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. phub-4.8.8/PKG-INFO +23 -0
  2. {phub-4.8.6 → phub-4.8.8}/pyproject.toml +17 -9
  3. {phub-4.8.6 → phub-4.8.8}/src/phub/consts.py +4 -2
  4. {phub-4.8.6 → phub-4.8.8}/src/phub/core.py +5 -0
  5. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/video.py +22 -8
  6. {phub-4.8.6 → phub-4.8.8}/src/phub/utils.py +4 -0
  7. phub-4.8.6/PKG-INFO +0 -705
  8. phub-4.8.6/README.md +0 -89
  9. phub-4.8.6/pypi.md +0 -11
  10. phub-4.8.6/setup.cfg +0 -4
  11. phub-4.8.6/setup.py +0 -4
  12. phub-4.8.6/src/phub.egg-info/PKG-INFO +0 -705
  13. phub-4.8.6/src/phub.egg-info/SOURCES.txt +0 -37
  14. phub-4.8.6/src/phub.egg-info/dependency_links.txt +0 -1
  15. phub-4.8.6/src/phub.egg-info/entry_points.txt +0 -2
  16. phub-4.8.6/src/phub.egg-info/requires.txt +0 -3
  17. phub-4.8.6/src/phub.egg-info/top_level.txt +0 -1
  18. {phub-4.8.6 → phub-4.8.8}/LICENSE +0 -0
  19. {phub-4.8.6 → phub-4.8.8}/src/phub/__init__.py +0 -0
  20. {phub-4.8.6 → phub-4.8.8}/src/phub/__main__.py +0 -0
  21. {phub-4.8.6 → phub-4.8.8}/src/phub/errors.py +0 -0
  22. {phub-4.8.6 → phub-4.8.8}/src/phub/literals.py +0 -0
  23. {phub-4.8.6 → phub-4.8.8}/src/phub/modules/__init__.py +0 -0
  24. {phub-4.8.6 → phub-4.8.8}/src/phub/modules/display.py +0 -0
  25. {phub-4.8.6 → phub-4.8.8}/src/phub/modules/parser.py +0 -0
  26. {phub-4.8.6 → phub-4.8.8}/src/phub/modules/rss.py +0 -0
  27. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/__init__.py +0 -0
  28. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/account.py +0 -0
  29. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/data.py +0 -0
  30. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/feed.py +0 -0
  31. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/image.py +0 -0
  32. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/playlist.py +0 -0
  33. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/query.py +0 -0
  34. {phub-4.8.6 → phub-4.8.8}/src/phub/objects/user.py +0 -0
  35. {phub-4.8.6 → phub-4.8.8}/src/phub/tests/__init__.py +0 -0
  36. {phub-4.8.6 → phub-4.8.8}/src/phub/tests/test_auth.py +0 -0
  37. {phub-4.8.6 → phub-4.8.8}/src/phub/tests/test_model.py +0 -0
  38. {phub-4.8.6 → phub-4.8.8}/src/phub/tests/test_playlist.py +0 -0
  39. {phub-4.8.6 → phub-4.8.8}/src/phub/tests/test_search.py +0 -0
  40. {phub-4.8.6 → phub-4.8.8}/src/phub/tests/test_video.py +0 -0
phub-4.8.8/PKG-INFO ADDED
@@ -0,0 +1,23 @@
1
+ Metadata-Version: 2.4
2
+ Name: phub
3
+ Version: 4.8.8
4
+ Summary: An API for Pornhub
5
+ Keywords: pornhub,phub,porn,api,web scrapper,api wrapper
6
+ Author: Egsagon, EchterAlsFake
7
+ Author-email: Egsagon <egsagon.git@gmail.com>, EchterAlsFake <EchterAlsFake@proton.me>
8
+ License-Expression: LGPL-3.0-only
9
+ License-File: LICENSE
10
+ Classifier: Development Status :: 4 - Beta
11
+ Classifier: Programming Language :: Python
12
+ Requires-Dist: eaf-base-api
13
+ Requires-Dist: m3u8
14
+ Requires-Dist: lxml
15
+ Requires-Dist: av ; python_full_version >= '3.10' and extra == 'av'
16
+ Requires-Dist: httpx[http2] ; extra == 'full'
17
+ Requires-Dist: httpx[socks] ; extra == 'full'
18
+ Requires-Python: >=3.9
19
+ Project-URL: Documentation, https://phub.readthedocs.io
20
+ Project-URL: Documentation_Updated, https://github.com/EchterAlsFake/API_Docs/blob/master/Porn_APIs/PHUB.md
21
+ Project-URL: Repository, https://github.com/EchterAlsFake/PHUB
22
+ Provides-Extra: av
23
+ Provides-Extra: full
@@ -1,21 +1,33 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.9.18,<0.10.0"]
3
+ build-backend = "uv_build"
4
+
1
5
  [project]
2
6
  name = "phub"
3
- version = "4.8.6"
7
+ version = "4.8.8"
4
8
  description = "An API for Pornhub"
5
9
  authors = [
6
10
  {name = 'Egsagon', email = "egsagon.git@gmail.com"},
7
11
  {name = "EchterAlsFake", email = "EchterAlsFake@proton.me"}
8
12
  ]
9
- license = {file = "LICENSE"}
10
- readme = {file = "pypi.md", content-type = "text/markdown"}
13
+ requires-python = ">=3.9"
14
+ license = "LGPL-3.0-only"
15
+ license-files = ["LICENSE"]
11
16
  keywords = ["pornhub", "phub", "porn", "api", "web scrapper", "api wrapper"]
12
17
  classifiers = [
13
18
  "Development Status :: 4 - Beta",
14
19
  "Programming Language :: Python"
15
20
  ]
16
- dependencies = ["httpx[brotli,socks]", "eaf_base_api", "h2"]
17
- requires-python = ">=3.9"
21
+ dependencies = [
22
+ "eaf_base_api",
23
+ "m3u8",
24
+ "lxml"
18
25
 
26
+ ]
27
+
28
+ [project.optional-dependencies]
29
+ av = ["av; python_version >= '3.10'"]
30
+ full = ["httpx[http2]", "httpx[socks]"] # H2 for HTTP 2.0 support, LXML for faster parsing speed, though optional :)
19
31
 
20
32
  [project.scripts]
21
33
  phub = "phub.__main__:main"
@@ -25,9 +37,5 @@ Documentation = "https://phub.readthedocs.io"
25
37
  Documentation_Updated = "https://github.com/EchterAlsFake/API_Docs/blob/master/Porn_APIs/PHUB.md"
26
38
  Repository = "https://github.com/EchterAlsFake/PHUB"
27
39
 
28
- [build-system]
29
- requires = ["setuptools", "wheel"]
30
- build-backend = "setuptools.build_meta"
31
-
32
40
  [tool.setuptools.packages.find]
33
41
  where = ["src"]
@@ -19,7 +19,9 @@ HEADERS = {
19
19
  'Accept': '*/*',
20
20
  'Accept-Language': 'en,en-US',
21
21
  'Connection': 'keep-alive',
22
- 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0'
22
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/114.0',
23
+ 'Referer': 'https://www.pornhub.com/',
24
+ 'Origin': 'https://www.pornhub.com',
23
25
  }
24
26
 
25
27
  COOKIES = {
@@ -227,7 +229,7 @@ class re:
227
229
  container = find( engine.DOTALL, r'class=\"container(.*)' ) # Get the page container
228
230
  document = find( engine.DOTALL, r'.*' ) # Match a whole document
229
231
  get_playlist_unavailable = find( engine.DOTALL, r': (\d+)</h5' ) # Get playlist unavailable videos amount
230
- get_playlist_size = find( engine.DOTALL, r'var itemsCount = (.*?) ||' ) # Get playlist video amount
232
+ get_playlist_size = find( engine.DOTALL, r'var itemsCount = (.*?) ||' ) # Get playlist video amount
231
233
  get_playlist_likes = find( engine.DOTALL, r'<span class="votesUp">(.*?)</span>' ) # Get playlist likes
232
234
  get_playlist_dislikes = find( engine.DOTALL, r'<span class="votesDown">(.*?)</span>' ) # Get playlist dislikes
233
235
  get_playlist_ratings = find( engine.DOTALL, r'<span class="percent">(.*?)%</span>' ) # Get paylist like/dislike ratio
@@ -5,6 +5,8 @@ import re
5
5
  import time
6
6
  import logging
7
7
  import random
8
+ import traceback
9
+
8
10
  import httpx
9
11
 
10
12
  from functools import cached_property
@@ -117,6 +119,7 @@ class Client:
117
119
  headers: dict = None,
118
120
  throw: bool = True,
119
121
  silent: bool = False,
122
+ params: dict = None,
120
123
  get_response = True) -> httpx.Response:
121
124
  '''
122
125
  Used internally to send a request or an API call.
@@ -156,6 +159,7 @@ class Client:
156
159
  method = method,
157
160
  url = url,
158
161
  data = data,
162
+ params = params,
159
163
  get_response=get_response)
160
164
 
161
165
  # Silent 429 errors
@@ -175,6 +179,7 @@ class Client:
175
179
  break
176
180
 
177
181
  except Exception as err:
182
+ print(traceback.format_exc())
178
183
  self.logger.log(logging.DEBUG if silent else logging.WARNING,
179
184
  f'Call failed: {repr(err)}. Retrying (attempt {i + 1}/{self.core.config.max_retries})')
180
185
  continue
@@ -4,11 +4,16 @@ import html
4
4
  import os
5
5
  import random
6
6
  import logging
7
+ import traceback
7
8
  from functools import cached_property
9
+
10
+ import httpx
8
11
  from base_api.base import setup_logger
9
12
  from datetime import datetime, timedelta
10
13
  from typing import TYPE_CHECKING, Iterator, Literal, Callable, Any, Union
11
14
 
15
+ from httpx import request
16
+
12
17
  from . import Tag, Like, User, Image
13
18
  from .. import utils
14
19
  from .. import errors
@@ -262,7 +267,8 @@ class Video:
262
267
  remux=remux, callback_remux=display_remux)
263
268
 
264
269
  except Exception as e:
265
- self.logger.error(f"An error occurred while downloading video {e}")
270
+ error = traceback.format_exc()
271
+ self.logger.error(f"An error occurred while downloading video {error}")
266
272
 
267
273
  return path
268
274
 
@@ -383,7 +389,7 @@ class Video:
383
389
 
384
390
  self._assert_internal_success(res.json())
385
391
 
386
- def watch_later(self, toggle: bool = True) -> None:
392
+ def watch_later(self, toggle: bool = True) -> bool:
387
393
  '''
388
394
  Add or remove the video to the watch later playlist.
389
395
 
@@ -391,14 +397,22 @@ class Video:
391
397
  toggle (bool): The toggle value.
392
398
  '''
393
399
 
394
- mod = 'add' if toggle else 'remove'
400
+ if toggle:
401
+ res = self.client.call(f'api/v1/playlist/video_add_watchlater', 'POST', dict(
402
+ vid=self.id,
403
+ token=self.client._granted_token
404
+ ))
405
+ return res.is_success
395
406
 
396
- res = self.client.call(f'playlist/video_{mod}_watchlater', 'POST', dict(
397
- vid=self.id,
398
- token=self.client._granted_token
399
- ))
407
+ else:
408
+ res = self.client.call(
409
+ "api/v1/playlist/video_remove_watchlater",
410
+ method="DELETE",
411
+ params={"vid": str(self.id), "token": str(self.client._granted_token)},
412
+ headers={"Accept": "application/json"},
413
+ )
414
+ return res.is_success
400
415
 
401
- self._assert_internal_success(res.json())
402
416
 
403
417
  # === Data properties === #
404
418
 
@@ -254,4 +254,8 @@ def fix_url(url: str):
254
254
  url = url.replace(language, "www", 1)
255
255
  return url
256
256
 
257
+
258
+ if "#" in url: # Some URLs have a # at the end and some number, idk why but yeah, fixing that here...
259
+ url = url.split("#")[0]
260
+
257
261
  return url # Sometimes URL doesn't need to be changed. In this case, just return it.