|
24 | 24 |
|
25 | 25 | rich_traceback_install() |
26 | 26 |
|
27 | | -VERSION = "v2.3.3" |
| 27 | +VERSION = "v2.3.4" |
28 | 28 |
|
29 | 29 |
|
30 | 30 | log_file_path = "duce.log" |
@@ -248,7 +248,7 @@ def append_to_list(self, title: str, link: str): |
248 | 248 | target.append(course) |
249 | 249 |
|
250 | 250 | def fetch_page(self, url: str, headers: dict = None) -> requests.Response: |
251 | | - return requests.get(url, headers=headers, timeout=(10, 30)) |
| 251 | + return requests.get(url, headers=headers, timeout=(30, 30)) |
252 | 252 |
|
253 | 253 | def parse_html(self, content: str): |
254 | 254 | return bs(content, "lxml") |
@@ -627,18 +627,41 @@ def en(self): |
627 | 627 | def cj(self): |
628 | 628 | try: |
629 | 629 | self.set_attr("length", 4) |
| 630 | + |
| 631 | + headers = { |
| 632 | + "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:137.0) Gecko/20100101 Firefox/137.0", |
| 633 | + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8", |
| 634 | + "Accept-Language": "en-US,en;q=0.5", |
| 635 | + # 'Accept-Encoding': 'gzip, deflate, br, zstd', |
| 636 | + "DNT": "1", |
| 637 | + "Sec-GPC": "1", |
| 638 | + "Alt-Used": "www.coursejoiner.com", |
| 639 | + "Connection": "keep-alive", |
| 640 | + # 'Cookie': 'ezosuibasgeneris-1=f7de3a73-8edf-4957-6bd7-c03d6192a105; cf_clearance=Vo1nMPpI9BOvaSvzT1RuuxxHQDU.SjH0Gvy_1Q5A8eA-1745306395-1.2.1.1-a7L2AgL7rcy4jHX.whQY0bjrjQwiz78KBWIOzX6_b8wBevOqdlK5yNLXDzSk1KJao2pu7ogq5pFL.TfdYmOQY3hz5c3Zk8BvRZVu0fyENuYVk1PNX.Q.UswXoe.LOSzsPpOBzySIOo5frr2Wv.ez2dE9GvPfPKG_a3WgmI.da5J94k2bQrs2w5tGdPlZgBNNuXlln_g9hIWQf8FNPXNjYQajWhZMZRJEqrwN6J8axTX8InJ_Fpt4wJaP6AvwcE28Lw6sgnWHLjVlrSdW9u.ZmTXvB7rDVVF5fKTSydwn5v0iI_4ch8TQPx6gFD_JHdnhTuVyzp64J.cKe1Uh53n_.DbRv8sCkUP9lfl_I2VGlog; ezoictest=stable; ezopvc_664594=1; ezoab_664594=mod24-c; active_template::664594=pub_site.1745306394; ezoadgid_664594=-1; wssplashchk=c03df4b443bf0a1a0365c55282e792b435f0599b.1745309995.1', |
| 641 | + "Upgrade-Insecure-Requests": "1", |
| 642 | + "Sec-Fetch-Dest": "document", |
| 643 | + "Sec-Fetch-Mode": "navigate", |
| 644 | + "Sec-Fetch-Site": "cross-site", |
| 645 | + "Priority": "u=4", |
| 646 | + "Pragma": "no-cache", |
| 647 | + "Cache-Control": "no-cache", |
| 648 | + # Requests doesn't support trailers |
| 649 | + # 'TE': 'trailers', |
| 650 | + } |
630 | 651 | with concurrent.futures.ThreadPoolExecutor(max_workers=4) as executor: |
631 | 652 | future_page = [ |
632 | 653 | executor.submit( |
633 | 654 | self.fetch_page, |
634 | 655 | f"https://www.coursejoiner.com/wp-json/wp/v2/posts?categories=74&per_page=100&page={page}", |
| 656 | + headers=headers |
635 | 657 | ) |
636 | 658 | for page in range(1, 5) |
637 | 659 | ] |
638 | 660 | for i, future in enumerate( |
639 | 661 | concurrent.futures.as_completed(future_page) |
640 | 662 | ): |
641 | | - content = future.result().json() |
| 663 | + content = future.result() |
| 664 | + content = content.json() |
642 | 665 | if not content: |
643 | 666 | logger.debug("No more coupons") |
644 | 667 | break |
@@ -972,8 +995,7 @@ def get_session_info(self): |
972 | 995 | headers=headers, |
973 | 996 | ) |
974 | 997 | r = r.json() |
975 | | - if self.debug: |
976 | | - logger.info(r) |
| 998 | + logger.debug(r) |
977 | 999 | if not r["header"]["isLoggedIn"]: |
978 | 1000 | raise LoginException("Login Failed") |
979 | 1001 |
|
@@ -1147,20 +1169,20 @@ def check_course(self): |
1147 | 1169 | url = f"https://www.udemy.com/api-2.0/course-landing-components/{self.course.course_id}/me/?components=purchase" |
1148 | 1170 | if self.course.coupon_code: |
1149 | 1171 | url += f",redeem_coupon&couponCode={self.course.coupon_code}" |
1150 | | - try: |
1151 | | - r = None |
1152 | | - r = self.client.get(url).json() |
1153 | | - except Exception as e: |
1154 | | - logger.error(f"Error fetching course data: {e}") |
1155 | | - logger.error(f"Course ID: {self.course.course_id}") |
1156 | | - logger.error(f"Coupon Code: {self.course.coupon_code}") |
1157 | | - logger.error(f"URL: {url}") |
1158 | | - logger.error("Response:" + str(r)) |
1159 | | - logger.exception("Exception occurred") |
1160 | | - if self.debug: |
1161 | | - os.makedirs("test/", exist_ok=True) |
1162 | | - with open("test/check_course.json", "w") as f: |
1163 | | - json.dump(r, f, indent=4) |
| 1172 | + |
| 1173 | + for _ in range(3): |
| 1174 | + try: |
| 1175 | + r = self.client.get(url) |
| 1176 | + r = r.json() |
| 1177 | + break |
| 1178 | + except requests.exceptions.ConnectionError: |
| 1179 | + r = None |
| 1180 | + except Exception as e: |
| 1181 | + logger.error(f"Error fetching course data: {e}") |
| 1182 | + logger.error(f"Course ID: {self.course.course_id}") |
| 1183 | + logger.error(f"Coupon Code: {self.course.coupon_code}") |
| 1184 | + logger.error(f"URL: {url}") |
| 1185 | + r = None |
1164 | 1186 | amount = ( |
1165 | 1187 | r.get("purchase", {}) |
1166 | 1188 | .get("data", {}) |
@@ -1261,7 +1283,7 @@ def start_new_enroll( |
1261 | 1283 | self.valid_courses.append(self.course) |
1262 | 1284 | logger.info("Added for enrollment") |
1263 | 1285 |
|
1264 | | - if len(self.valid_courses) >= 30: |
| 1286 | + if len(self.valid_courses) >= 20: |
1265 | 1287 | self.bulk_checkout() |
1266 | 1288 | self.valid_courses.clear() |
1267 | 1289 | self.update_progress() |
@@ -1308,11 +1330,11 @@ def bulk_checkout(self): |
1308 | 1330 | # "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:119.0) Gecko/20100101 Firefox/119.0", |
1309 | 1331 | "Accept": "application/json, text/plain, */*", |
1310 | 1332 | "Accept-Language": "en-US", |
1311 | | - # "Referer": f"https://www.udemy.com/payment/checkout/express/course/{self.course.course_id}/?discountCode={self.course.coupon_code}", |
1312 | | - "Referer": "https://www.udemy.com/payment/checkout/express/", |
| 1333 | + "Referer": f"https://www.udemy.com/payment/checkout/express/course/{self.course.course_id}/?discountCode={self.course.coupon_code}", |
| 1334 | + # "Referer": "https://www.udemy.com/payment/checkout/express/", |
1313 | 1335 | "Content-Type": "application/json", |
1314 | 1336 | "X-Requested-With": "XMLHttpRequest", |
1315 | | - "x-checkout-is-mobile-app": "true", |
| 1337 | + "x-checkout-is-mobile-app": "false", |
1316 | 1338 | # "Origin": "https://www.udemy.com", |
1317 | 1339 | "Host": "www.udemy.com", |
1318 | 1340 | "DNT": "1", |
|
0 commit comments