zenporn.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. import base64
  2. import binascii
  3. from .common import InfoExtractor
  4. from ..utils import ExtractorError, determine_ext, unified_strdate, url_or_none
  5. from ..utils.traversal import traverse_obj
  6. class ZenPornIE(InfoExtractor):
  7. _VALID_URL = r'https?://(?:www\.)?zenporn\.com/video/(?P<id>\d+)'
  8. _TESTS = [{
  9. 'url': 'https://zenporn.com/video/15627016/desi-bhabi-ki-chudai',
  10. 'md5': '07bd576b5920714d74975c054ca28dee',
  11. 'info_dict': {
  12. 'id': '9563799',
  13. 'display_id': '15627016',
  14. 'ext': 'mp4',
  15. 'title': 'md5:669eafd3bbc688aa29770553b738ada2',
  16. 'description': '',
  17. 'thumbnail': 'md5:2fc044a19bab450fef8f1931e7920a18',
  18. 'upload_date': '20230925',
  19. 'uploader': 'md5:9fae59847f1f58d1da8f2772016c12f3',
  20. 'age_limit': 18,
  21. },
  22. }, {
  23. 'url': 'https://zenporn.com/video/15570701',
  24. 'md5': 'acba0d080d692664fcc8c4e5502b1a67',
  25. 'info_dict': {
  26. 'id': '2297875',
  27. 'display_id': '15570701',
  28. 'ext': 'mp4',
  29. 'title': 'md5:47aebdf87644ec91e8b1a844bc832451',
  30. 'description': '',
  31. 'thumbnail': 'https://mstn.nv7s.com/contents/videos_screenshots/2297000/2297875/480x270/1.jpg',
  32. 'upload_date': '20230921',
  33. 'uploader': 'Lois Clarke',
  34. 'age_limit': 18,
  35. },
  36. }, {
  37. 'url': 'https://zenporn.com/video/8531117/amateur-students-having-a-fuck-fest-at-club/',
  38. 'md5': '67411256aa9451449e4d29f3be525541',
  39. 'info_dict': {
  40. 'id': '12791908',
  41. 'display_id': '8531117',
  42. 'ext': 'mp4',
  43. 'title': 'Amateur students having a fuck fest at club',
  44. 'description': '',
  45. 'thumbnail': 'https://tn.txxx.tube/contents/videos_screenshots/12791000/12791908/288x162/1.jpg',
  46. 'upload_date': '20191005',
  47. 'uploader': 'Jackopenass',
  48. 'age_limit': 18,
  49. },
  50. }, {
  51. 'url': 'https://zenporn.com/video/15872038/glad-you-came/',
  52. 'md5': '296ccab437f5bac6099433768449d8e1',
  53. 'info_dict': {
  54. 'id': '111585',
  55. 'display_id': '15872038',
  56. 'ext': 'mp4',
  57. 'title': 'Glad You Came',
  58. 'description': '',
  59. 'thumbnail': 'https://vpim.m3pd.com/contents/videos_screenshots/111000/111585/480x270/1.jpg',
  60. 'upload_date': '20231024',
  61. 'uploader': 'Martin Rudenko',
  62. 'age_limit': 18,
  63. },
  64. }]
  65. def _gen_info_url(self, ext_domain, extr_id, lifetime=86400):
  66. """ This function is a reverse engineering from the website javascript """
  67. result = '/'.join(str(int(extr_id) // i * i) for i in (1_000_000, 1_000, 1))
  68. return f'https://{ext_domain}/api/json/video/{lifetime}/{result}.json'
  69. @staticmethod
  70. def _decode_video_url(encoded_url):
  71. """ This function is a reverse engineering from the website javascript """
  72. # Replace lookalike characters and standardize map
  73. translation = str.maketrans('АВСЕМ.,~', 'ABCEM+/=')
  74. try:
  75. return base64.b64decode(encoded_url.translate(translation), validate=True).decode()
  76. except (binascii.Error, ValueError):
  77. return None
  78. def _real_extract(self, url):
  79. display_id = self._match_id(url)
  80. webpage = self._download_webpage(url, display_id)
  81. ext_domain, video_id = self._search_regex(
  82. r'https://(?P<ext_domain>[\w.-]+\.\w{3})/embed/(?P<extr_id>\d+)/',
  83. webpage, 'embed info', group=('ext_domain', 'extr_id'))
  84. info_json = self._download_json(
  85. self._gen_info_url(ext_domain, video_id), video_id, fatal=False)
  86. video_json = self._download_json(
  87. f'https://{ext_domain}/api/videofile.php', video_id, query={
  88. 'video_id': video_id,
  89. 'lifetime': 8640000,
  90. }, note='Downloading video file JSON', errnote='Failed to download video file JSON')
  91. decoded_url = self._decode_video_url(video_json[0]['video_url'])
  92. if not decoded_url:
  93. raise ExtractorError('Unable to decode the video url')
  94. return {
  95. 'id': video_id,
  96. 'display_id': display_id,
  97. 'ext': traverse_obj(video_json, (0, 'format', {determine_ext})),
  98. 'url': f'https://{ext_domain}{decoded_url}',
  99. 'age_limit': 18,
  100. **traverse_obj(info_json, ('video', {
  101. 'title': ('title', {str}),
  102. 'description': ('description', {str}),
  103. 'thumbnail': ('thumb', {url_or_none}),
  104. 'upload_date': ('post_date', {unified_strdate}),
  105. 'uploader': ('user', 'username', {str}),
  106. })),
  107. }