def select_option(self, options, find_arg=None): if self.serv_name: self.choices[self.state] = options[self.serv_path[self.state]] self._next_state() return print(f'Select your {self.state} from below choices:') if self.state == 'continent': choice = get_choice(options, find_arg, None) if choice == -1: print_quit() else: choice = get_choice(options, find_arg) if choice == -1: if self.state in self.choices: del self.choices[self.state] self._prev_state() if self.state in self.cache: self.select_option(**self.cache[self.state]) else: self.choices[self.state] = options[choice] self.serv_path[self.state] = choice name = options[choice].select_one(find_arg).text print(f"You have selected {name}.") self.cache[self.state] = {'options': options, 'find_arg': find_arg} self._next_state()
def get_serv_details(self): serv = self.choices.get('server') if not serv: print_quit('No server selected') if not self.serv_name: print("Details:") for item in serv.select('li.list-group-item'): print(item.text.strip()) else: print("Selected", self.serv_name) form = serv.form config_url = form.a['href'] config_name = config_url[config_url.rfind('/') + 1:] self.server = { 'name': config_name[:config_name.find('.com')].lower(), 'create_url': form['action'], 'id': form.find('input')['value'], 'config_url': config_url, 'config_name': config_name } self.serv_name = self.server['name'] self.save_serv_path() self.download_serv_config()
def state_loop(self): for _ in range(25): if self.state == 'END': break if self.state == 'continent': self._get_continent() elif self.state == 'country': self._get_country() elif self.state == 'protocol': self._get_protocol() elif self.state == 'server': self._get_server() else: print_quit("Too many choices")
def parse_lec_ranges(ranges: str, total_lecs: int) -> set: if not ranges: return set(range(1, total_lecs + 1)) lecture_ids = set() ranges = ranges.split(",") if ranges.find(",") else (ranges, ) for r in ranges: m = RANGE_PAT.match(r) if not m: print_quit(f'Invalid range "{r}"') start = int(m["l"] or 1) end = start + 1 if m["r"] is None else int(m["r"] or total_lecs + 1) if start >= end: print_quit(f'Invalid range "{r}"') lecture_ids.update(range(start, min(end, total_lecs + 1))) return lecture_ids
def login(username, password): payload = {"username": username, "password": password} try: response = requests.post(IMP_BASE_URL + IMP_LOGIN_URL, data=payload, timeout=3) except (requests.ConnectionError, requests.Timeout) as e: print_quit(f"Connection Error {e}") if response.status_code >= 500: print_quit("Impartus not responding properly") elif response.status_code == 400: print_quit("Invalid login request. Impartus changed something.") elif response.status_code == 401: print_quit("Invalid login credentials!") resp = response.json() if not resp["success"]: print_quit(f"Impartus: {resp.get('message', resp)}", 1) return resp["token"]
def login(username, password): payload = {"username": username, "password": password} try: response = requests.post(IMP_BASE_URL + IMP_LOGIN_URL, data=payload, timeout=3) except (requests.ConnectionError, requests.Timeout) as e: print_quit(f"Connection Error {e}") if response.status_code >= 500: print_quit("Impartus not responding properly", 1) resp = response.json() if not resp["success"]: print_quit("Impartus:" + resp["message"], 1) return resp["token"]
def main(): try: sp.check_call(["ffmpeg", "-version"], **dict(sp_args, stdout=sp.DEVNULL)) except FileNotFoundError: print_quit("ffmpeg not found. Ensure it is present in PATH.") config = read_json(CONFIG_FILE, verbose=True) data = read_json(DATA_FILE) or {"urls": {}} args = parse_args(config, data["urls"]) if not args.username or not args.password: print_quit("Email and password not provided.") if args.save_creds: config["creds"] = { "username": args.username, "password": args.password } store_json(config, CONFIG_FILE) course_lectures_url = get_course_url(args, data["urls"]) token = login(args.username, args.password) headers = {"Authorization": "Bearer " + token} response = requests.get(course_lectures_url, headers=headers) if not response.ok: print_quit("Error fetching course info. Is the url proper?") lectures = response.json() total_lecs = len(lectures) subject_name = "{subjectName} {sessionName}".format(**lectures[0]) working_dir: Path = args.dest / subject_name working_dir.mkdir(exist_ok=True, parents=True) print(f'Saving to "{working_dir}"') data["urls"][subject_name.upper()] = course_lectures_url store_json(data, DATA_FILE) lecture_ids = parse_lec_ranges(args.range, total_lecs) downloaded: dict = { int(file.stem[:2]): file for file in working_dir.glob("[0-9][0-9].*.mkv") if int(file.stem[:2]) in lecture_ids } if downloaded: if args.rename: rename_old(downloaded, lectures) if args.only_new: lecture_ids.difference_update(range(max(downloaded) + 1)) elif args.force: print("Force option enabled. Deleting old lectures:", *sorted(downloaded)) for file in downloaded.values(): file.unlink() else: print("Skipping already downloaded lectures:", *sorted(downloaded)) lecture_ids.difference_update(downloaded) if not lecture_ids: print_quit("No lectures to download. Exiting.", 0) no_class = [] task_args = [] for lecture in reversed(lectures): # Download lecture #1 first lec_no = lecture["seqNo"] if lec_no not in lecture_ids: continue file_name = make_filename(lecture) if not args.keep_no_class and "no class" in file_name.lower(): no_class.append(lec_no) continue stream_url = IMP_BASE_URL + IMP_STREAM_URL.format( lecture["ttid"], token) task_args.append(( token, stream_url, working_dir / file_name, args.quality, ANGLE_CHOICES.index(args.angle), )) if no_class: print("Skipping lectures with 'no class' in title:", *no_class) print("Downloading lecture numbers:", *sorted(lecture_ids.difference(no_class))) with DirServer(), ThreadPool(args.worker_processes) as pool: try: pool.starmap(download_stream, task_args) pool.close() pool.join() except KeyboardInterrupt: print_quit("Aborted.", 1) print("Finished!")