Python client for Dudesnude to allow messaging and image/video download.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. #!/usr/bin/env python3
  2. # -*- coding: utf-8 -*-
  3. # Standard library imports
  4. import argparse
  5. import errno
  6. import logging
  7. import os
  8. import re
  9. import threading
  10. # Related third party imports (If you used pip/apt/yum to install)
  11. import arrow
  12. from bs4 import BeautifulSoup as bs
  13. from expand_path import expand_path
  14. import requests
  15. from requests.auth import AuthBase
  16. from shm_dict import SHMDict
  17. __author__ = "Nate Bohman"
  18. __license__ = "GPL-3"
  19. __version__ = "1.1.0"
  20. __maintainer__ = "Nate Bohman"
  21. __email__ = "natrinicle@gmail.com"
  22. logger = logging.getLogger(__name__)
  23. try:
  24. unichr
  25. except NameError:
  26. unichr = chr
  27. try:
  28. unicode
  29. except NameError:
  30. unicode = str
  31. DEFAULT_CFGDIR_BASE = expand_path("~/.config/dudesnude")
  32. LOGIN_URL = {"default": "https://dudesnude.com/login.php",
  33. "guest": "http://dudesnude.com/warning.php"}
  34. LOGIN_INPUT_RGX = re.compile(r'<input.*name="(?P<name>[^"]+)".*value="(?P<value>[^"]+)"', re.I)
  35. class DudesNudeCookieAuth(AuthBase):
  36. def __init__(self, email, password="", cookie_dir=DEFAULT_CFGDIR_BASE):
  37. self.cookie_dict = None
  38. self._cookie_dir = ""
  39. self.cookie_dir = cookie_dir
  40. self._email = ""
  41. self.email = email
  42. self.password = password
  43. self.session = requests.Session()
  44. @property
  45. def email(self):
  46. return self._email
  47. @email.setter
  48. def email(self, value):
  49. if self._email != value:
  50. self._email = value
  51. self.cookie_dict = SHMDict(name=self.cookie_file,
  52. size=8192, is_file=True)
  53. @property
  54. def cookie_dir(self):
  55. return self._cookie_dir
  56. @cookie_dir.setter
  57. def cookie_dir(self, value):
  58. value = expand_path(value)
  59. self._cookie_dir = value
  60. try:
  61. os.makedirs(value, mode=0o750)
  62. except OSError as e:
  63. if e.errno != errno.EEXIST:
  64. raise
  65. @property
  66. def cookie_file(self):
  67. return "{}/{}_cookies".format(self.cookie_dir,
  68. self.email)
  69. @property
  70. def login_form_fields(self):
  71. r = self.session.get(LOGIN_URL.get("default"))
  72. self.cookie_dict['cookies'] = self.session.cookies
  73. login_form_fields = {}
  74. if LOGIN_INPUT_RGX.search(r.text):
  75. for login_input in LOGIN_INPUT_RGX.finditer(r.text):
  76. login_input = login_input.groupdict()
  77. login_form_fields[login_input.get("name")] = login_input.get("value")
  78. return login_form_fields
  79. @property
  80. def login_data(self):
  81. if self.email == "guest":
  82. return {'go': '1', 'iagree': '1', 'token': '', 'win_x': '1080', 'win_y': '720'}
  83. else:
  84. login_form_fields = self.login_form_fields
  85. assert login_form_fields.get('s_token') is not None
  86. assert self.cookie_dict['cookies'].get('PHPSESSID') is not None
  87. login_data = {
  88. 'PHPSESSID': self.cookie_dict['cookies'].get('PHPSESSID'),
  89. 's_token': login_form_fields.get('s_token'),
  90. 'email': self.email,
  91. 'pass': self.password,
  92. 'logon': '1',
  93. 'seeking': '0', # 0 -, 1 chat only, 2 hookups
  94. 'tz': 0, # Force GMT
  95. 'win_x': '1080', # Force desktop
  96. 'win_y': '720', # Force desktop
  97. }
  98. return login_data
  99. def login(self):
  100. with self.cookie_dict.exclusive_lock():
  101. if self.cookie_dict.get('last_refresh') is None:
  102. log_message = "Creating cookie {}".format(self.cookie_file)
  103. else:
  104. log_message = "Updating cookie that was last refreshed {}".format(
  105. self.cookie_dict.get('last_refresh').humanize())
  106. logger.info(log_message)
  107. r = self.session.post(LOGIN_URL.get(self.email, LOGIN_URL.get("default")),
  108. data=self.login_data)
  109. # Check for HTTP error codes
  110. r.raise_for_status()
  111. # Check for bad URL
  112. if self.email == "guest" and r.url != 'http://dudesnude.com/search_menu.php':
  113. raise Exception('Failure to log in')
  114. if self.email != "guest" and r.url == 'http://dudesnude.com/login.php':
  115. raise Exception('Failure to log in')
  116. self.cookie_dict['cookies'] = self.session.cookies
  117. self.cookie_dict['last_refresh'] = arrow.utcnow()
  118. def handle_relogin(self, r, **kwargs):
  119. """Handle logging back in if response URL indicates not logged in."""
  120. if not r.url == 'http://dudesnude.com/enable_cookies.php':
  121. return r
  122. self.login()
  123. def __call__(self, req):
  124. """Handle every call through requests to webpage."""
  125. # Login if cookies dict doesn't exist
  126. if self.cookie_dict.get('last_refresh') is None:
  127. self.login()
  128. # Clean up, since we can't generate new cookies otherwise
  129. if 'Cookie' in req.headers:
  130. del req.headers['Cookie']
  131. # Add saved cookies to request
  132. req.prepare_cookies(self.cookie_dict.get('cookies'))
  133. # Register a method that is called after every request
  134. # to ensure that we don't have to login.
  135. req.register_hook('response', self.handle_relogin)
  136. return req
  137. class DudesNudeClient(object):
  138. def __init__(self, email, password, config_dir=DEFAULT_CFGDIR_BASE):
  139. self._config_dir = ""
  140. self.config_dir = config_dir
  141. #self.guest_session = requests.Session()
  142. #self.guest_session.auth = DudesNudeCookieAuth(email="guest")
  143. self.session = requests.Session()
  144. self.session.auth = DudesNudeCookieAuth(email=email, password=password)