rule34video.py 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import re
  2. from .common import InfoExtractor
  3. from ..utils import (
  4. clean_html,
  5. extract_attributes,
  6. get_element_by_attribute,
  7. get_element_by_class,
  8. get_element_html_by_class,
  9. get_elements_by_class,
  10. int_or_none,
  11. parse_count,
  12. parse_duration,
  13. unescapeHTML,
  14. )
  15. from ..utils.traversal import traverse_obj
  16. class Rule34VideoIE(InfoExtractor):
  17. _VALID_URL = r'https?://(?:www\.)?rule34video\.com/videos?/(?P<id>\d+)'
  18. _TESTS = [
  19. {
  20. 'url': 'https://rule34video.com/video/3065157/shot-it-mmd-hmv/',
  21. 'md5': 'ffccac2c23799dabbd192621ae4d04f3',
  22. 'info_dict': {
  23. 'id': '3065157',
  24. 'ext': 'mp4',
  25. 'title': 'Shot It-(mmd hmv)',
  26. 'thumbnail': 'https://rule34video.com/contents/videos_screenshots/3065000/3065157/preview.jpg',
  27. 'duration': 347.0,
  28. 'age_limit': 18,
  29. 'view_count': int,
  30. 'like_count': int,
  31. 'comment_count': int,
  32. 'timestamp': 1639872000,
  33. 'description': 'https://discord.gg/aBqPrHSHvv',
  34. 'upload_date': '20211219',
  35. 'uploader': 'Sweet HMV',
  36. 'uploader_url': 'https://rule34video.com/members/22119/',
  37. 'categories': ['3D', 'MMD', 'iwara'],
  38. 'tags': 'mincount:10',
  39. },
  40. },
  41. {
  42. 'url': 'https://rule34video.com/videos/3065296/lara-in-trouble-ep-7-wildeerstudio/',
  43. 'md5': '6bb5169f9f6b38cd70882bf2e64f6b86',
  44. 'info_dict': {
  45. 'id': '3065296',
  46. 'ext': 'mp4',
  47. 'title': 'Lara in Trouble Ep. 7 [WildeerStudio]',
  48. 'thumbnail': 'https://rule34video.com/contents/videos_screenshots/3065000/3065296/preview.jpg',
  49. 'duration': 938.0,
  50. 'age_limit': 18,
  51. 'view_count': int,
  52. 'like_count': int,
  53. 'comment_count': int,
  54. 'timestamp': 1640131200,
  55. 'description': '',
  56. 'creators': ['WildeerStudio'],
  57. 'upload_date': '20211222',
  58. 'uploader': 'CerZule',
  59. 'uploader_url': 'https://rule34video.com/members/36281/',
  60. 'categories': ['3D', 'Tomb Raider'],
  61. 'tags': 'mincount:40',
  62. },
  63. },
  64. ]
  65. def _real_extract(self, url):
  66. video_id = self._match_id(url)
  67. webpage = self._download_webpage(url, video_id)
  68. formats = []
  69. for mobj in re.finditer(r'<a[^>]+href="(?P<video_url>[^"]+download=true[^"]+)".*>(?P<ext>[^\s]+) (?P<quality>[^<]+)p</a>', webpage):
  70. url, ext, quality = mobj.groups()
  71. formats.append({
  72. 'url': url,
  73. 'ext': ext.lower(),
  74. 'quality': quality,
  75. })
  76. categories, creators, uploader, uploader_url = [None] * 4
  77. for col in get_elements_by_class('col', webpage):
  78. label = clean_html(get_element_by_class('label', col))
  79. if label == 'Categories:':
  80. categories = list(map(clean_html, get_elements_by_class('item', col)))
  81. elif label == 'Artist:':
  82. creators = list(map(clean_html, get_elements_by_class('item', col)))
  83. elif label == 'Uploaded By:':
  84. uploader = clean_html(get_element_by_class('name', col))
  85. uploader_url = extract_attributes(get_element_html_by_class('name', col) or '').get('href')
  86. return {
  87. **traverse_obj(self._search_json_ld(webpage, video_id, default={}), ({
  88. 'title': 'title',
  89. 'view_count': 'view_count',
  90. 'like_count': 'like_count',
  91. 'duration': 'duration',
  92. 'timestamp': 'timestamp',
  93. 'description': 'description',
  94. 'thumbnail': ('thumbnails', 0, 'url'),
  95. })),
  96. 'id': video_id,
  97. 'formats': formats,
  98. 'title': self._html_extract_title(webpage),
  99. 'thumbnail': self._html_search_regex(
  100. r'preview_url:\s+\'([^\']+)\'', webpage, 'thumbnail', default=None),
  101. 'duration': parse_duration(self._html_search_regex(
  102. r'"icon-clock"></i>\s+<span>((?:\d+:?)+)', webpage, 'duration', default=None)),
  103. 'view_count': int_or_none(self._html_search_regex(
  104. r'"icon-eye"></i>\s+<span>([ \d]+)', webpage, 'views', default='').replace(' ', '')),
  105. 'like_count': parse_count(get_element_by_class('voters count', webpage)),
  106. 'comment_count': int_or_none(self._search_regex(
  107. r'[^(]+\((\d+)\)', get_element_by_attribute('href', '#tab_comments', webpage), 'comment count', fatal=False)),
  108. 'age_limit': 18,
  109. 'creators': creators,
  110. 'uploader': uploader,
  111. 'uploader_url': uploader_url,
  112. 'categories': categories,
  113. 'tags': list(map(unescapeHTML, re.findall(
  114. r'<a class="tag_item"[^>]+\bhref="https://rule34video\.com/tags/\d+/"[^>]*>(?P<tag>[^>]*)</a>', webpage))),
  115. }