def print_playlist(self): if not self.playlist: raise RuntimeError("No playlist. Read a playlist first!") width_artist = max(len(row["artist"]) for row in self.playlist) width_title = max(len(row["song"]) for row in self.playlist) heading = "{:<{width_artist}s} {:<{width_title}s} {:9s} {:9s} {:9s}".format( "ARTIST", "SONG", "TIME", "PLAYTIME", "STARTTIME", width_artist=width_artist + 2, width_title=width_title, ) print_bold(heading) print_color("".join(["-"] * len(heading))) for row in self.playlist: print("{:<{width_artist}s} - {:<{width_title}s} {} {} {}". format( row["artist"], row["song"], Color.yellow + str(row["time"]).split(", ")[-1], Color.green + str(row["playtime"]).split(", ")[-1], Color.blue + row["starttime"].strftime("%H:%M:%S"), width_artist=width_artist, width_title=width_title, ) + colorama.Style.RESET_ALL) print_color("".join(["-"] * len(heading)) + "\n")
def set_genre_filter(self): print_bold("Use default genres (y/n)?") ans = input() if ans.lower() in ("n", "no", "0"): print_bold("Choose genres:") print_color("hiphop, house, r&b, latin, pop, reggae, other", Color.cyan) genres = [ i.strip().lower() for i in input().split(",") if i.strip().lower() in self.genres ] if not genres: print("No genres specified, using all...") return else: genres = ("hiphop", "house", "r&b", "pop", "other") print(f"Genres: {get_color(', '.join(genres), Color.yellow)}") self.filter = "&f=ddfilter" for genre in genres: genre_id = self.genre_map[genre.lower()] self.filter += f"&{genre_id}=on" self.current_url = ( f"https://www.djcity.com/uk/digital/records.aspx?p={self.current_num}" ) self.current_url += self.filter self.driver.get(self.current_url)
def download_page(self, number=0) -> int: # overridden to directly download files without using 'get_tracks' if not self.check_free_disk_space(): raise OSError("Disk is full!") downloads = self.driver.find_elements_by_class_name("downloads") if not downloads: raise RuntimeError("No downloads found") print_color("downloading files...", Color.yellow) tracks = downloads[0].find_elements_by_class_name("download-title") # TODO: get download links using async tasks instead of sequentially to speedup download for song in tqdm(tracks): # wait for Bandcamp to prepare download button = WebDriverWait(song, 600).until( EC.element_to_be_clickable((By.CLASS_NAME, "item-button")) ) url = button.get_attribute("href") self.download(url) # wait a bit for downloads to finish time.sleep(2) num_tracks = len(tracks) self.total_files_downloaded += num_tracks return num_tracks
def print_stats(self): print("--------------------") print_color(self.name, Color.cyan) free_space, _ = self.free_disk_space() total_size = self.free_space_at_start - free_space msg = f"Total files downloaded: {self.total_files_downloaded} / {total_size:.1f} MB" logging.info(msg) print(msg, end="\n\n")
def __init__(self, name, folder_name): self.current_num = None self.current_url = None self.driver = None self.folder = folder_name self.name = name self.system = platform.system().lower() self.total_files_downloaded = 0 self.url = "" logging.basicConfig( filename=f"{self.name}.log", filemode="w", level=logging.INFO, format="%(asctime)s [%(levelname)s] %(message)s", datefmt="%Y.%m.%d %H:%M:%S", ) user_path = os.path.expanduser("~") if self.windows(): download_root = os.path.join("D:\\", "Dropbox", "DJ MUSIC SORT") chrome_profile = os.path.join( user_path, "AppData\\Local\\Google\\Chrome\\User Data") self.chrome_driver = "D:\\Dropbox\\CODE\\webdriver\\chromedriver.exe" elif self.mac_os(): download_root = os.path.join(user_path, "Dropbox", "DJ MUSIC SORT") chrome_profile = os.path.join( user_path, r"Library/Application Support/Google/Chrome") self.chrome_driver = "/usr/local/bin/chromedriver" else: print_color(f"Unsupported OS: '{platform.system()}'", Color.red) sys.exit() self.download_path = os.path.join(download_root, self.folder) if not os.path.exists(self.download_path): os.makedirs(self.download_path, exist_ok=True) self.free_space_at_start, _ = self.free_disk_space() self.chrome_options = webdriver.ChromeOptions() self.chrome_options.add_argument("user-data-dir=" + chrome_profile) self.chrome_options.add_argument("profile-directory=Default") self.chrome_options.add_argument("disable-infobars") self.chrome_options.add_experimental_option( "prefs", { "download.default_directory": self.download_path, "download.prompt_for_download": False, "download.directory_upgrade": True, "safebrowsing.enabled": True, }, )
def play_one_move(self, board: Board) -> None: """Play one round as this player.""" print(f"Turn: {str(self._disk)}") moves = board.possible_moves(self._disk) if moves: self._can_play = True if self._human and self._show_helpers: board.print_moves(moves) chosen_move = self._get_human_move( moves) if self._human else self._get_computer_move(moves) board.place_disk(chosen_move) board.print_score() self._rounds_played += 1 else: self._can_play = False print_color(" No moves available...", Color.yellow)
def start_driver(self): """Open chromedriver and prepare pool for downloading.""" try: self.driver = webdriver.Chrome(executable_path=self.chrome_driver, options=self.chrome_options) self.driver.implicitly_wait(0.5) self.driver.get(self.url) self.current_url = self.driver.current_url except InvalidArgumentException: print_color( "\nError: Chrome already running. Close Chrome and try again...", Color.red, ) sys.exit() print(f"\nDownloader initialized for:\n{repr(self)}") self.prepare_pool()
def print_moves(self, moves: List[Move]): """Print available move coordinates and resulting points gained.""" print_color(f" Possible moves ({len(moves)}):", Color.yellow) # convert board from Disk enums to strings board = [[disk.board_char() for disk in row] for row in self._board] for move in moves: print(f" {move}") x, y = move.square # add move value to matching position on board board[y][x] = get_color(move.value, Color.yellow) # print board with move positions print(f" {' '.join(get_color(str(x), bold=True) for x in range(self._size))}") for index, row in enumerate(board): text = get_color(f" {index} ", bold=True) text += " ".join(disk for disk in row) print(text)
def multi_page_loop(self, pages=1): self.pool.update_current_page() last_page = self.pool.current_num + pages - 1 for _ in range(1, pages + 1): print_bold(f"--- Page: {self.pool.current_num} / {last_page} ---") self.single_page_download() if not self.pool.next_page(): print_color("No more pages!", Color.red) return print_bold("Continue for pages?") self.play_notification_sound() try: num = int(input()) if num > 0: self.multi_page_loop(num) except ValueError: return
def export_playlist(self, event): filename, _ = QFileDialog.getSaveFileName( self, "Save playlist", self.defaultPath + os.sep + self.playlist_name_edit.text(), ) if filename: if filename.endswith(".csv"): self.formatter.export_csv(filename) elif filename.endswith(".txt"): print_color("txt export not implemented yet!", Color.red) return elif filename.endswith(".xlsx"): print_color("Excel export not implemented yet!", Color.red) return else: self.formatter.export_csv(filename) self.statusbar.showMessage(f"Saved playlist as: {filename}", 5000)
def single_page_loop(self): self.pool.update_current_page() while True: print_bold(f"--- Page: {self.pool.current_num} ---") try: number = int( input( "Give number of tracks to download from current page, 0 = all\n" ) ) number = max(0, number) except ValueError: number = 0 self.single_page_download(number) if not self.pool.next_page(): print_color("No more pages!", Color.red) break self.play_notification_sound() if not input("Continue?\n").lower() in ("y", "1"): break
def download_page(self, number=0) -> int: """Download all main files on current page, or optionally only the "number" first tracks.""" if not self.check_free_disk_space(): raise OSError("Disk is full!") print_color("Getting download links...", Color.yellow) tracks = self.get_tracks(number) if not tracks: print_color("No files to download!\n", Color.red) return 0 print_color("downloading files...", Color.yellow) for track in tqdm(tracks): self.download(track) # wait a bit for downloads to finish time.sleep(2) num_tracks = len(tracks) self.total_files_downloaded += num_tracks return num_tracks
def fill_basso(self, show, start_index=0): """Fill radioshow playlist to Bassoradio database using Selenium.""" print_bold("Uploading playlist to dj.basso.fi...", Color.red) start_time = timer() if len(self.playlist) <= start_index: print("Index not valid.") return self.open_basso_driver(show) print("\nFilling playlist for show:") print_color(show, Color.cyan) # input song data print_color("\nAdding songs...", Color.magenta) for index, row in enumerate(self.playlist[start_index:]): input_index = 0 print(" {:d}: {:s} - {:s}".format(index + 1, row["artist"], row["song"])) while True: # increase index so we don't send the first letter multiple times when trying again input_index += 1 try: time.sleep(0.5) find_track = WebDriverWait(self.driver, 10).until( EC.presence_of_element_located( (By.ID, "find-track-textfield"))) find_track.send_keys(row["artist"][:input_index]) WebDriverWait(self.driver, 10).until( EC.presence_of_element_located( (By.ID, "new-track-entry-form"))) artist = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable( (By.CSS_SELECTOR, "[ng-model*='newTrack.artist']"))) time.sleep(0.5) artist.send_keys(row["artist"][input_index:]) song = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable( (By.CSS_SELECTOR, "[ng-model*='newTrack.title']"))) song.send_keys(row["song"]) mins = row["playtime"].seconds // 60 minutes = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable( (By.CSS_SELECTOR, "[ng-model*='newTrack.minutes']"))) minutes.send_keys(mins) secs = row["playtime"].seconds % 60 seconds = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable( (By.CSS_SELECTOR, "[ng-model*='newTrack.seconds']"))) seconds.send_keys(secs) save = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable(( By.XPATH, "//input[@type='button' and @value='Tallenna uusi biisi']", ))) save.click() submit_button = WebDriverWait(self.driver, 10).until( EC.element_to_be_clickable(( By.XPATH, "//input[@type='submit' and @value='Lisää biisilistaan']", ))) submit_button.click() except Exception as e: print_color(str(e), Color.red) continue else: break print_color(f"Done in {timer() - start_time:.2f} seconds!", Color.green)
ans = input() if options.get(ans): site = options[ans].lower() else: print_error("Give a valid option...") try: site = Site[site.upper()] except KeyError: print_error(f"Unsupported record pool: {site}!") sys.exit() try: downloader = RecordPoolDownloader(site) if site == Site.BANDCAMP: downloader.pool.download_page() downloader.pool.open_page("chrome://downloads/") input("Wait until downloads have finished and press a button...\n") else: downloader.run_loop() except KeyboardInterrupt: print_bold("\nAborting...") sys.exit() except Exception: logging.exception("Exception raised!") error_type, error_value, trace = sys.exc_info() print_error(error_type) if error_value: print_color(error_value, Color.red) for line in traceback.format_tb(trace): print_color(line, Color.yellow)
from PlaylistGui import PlaylistGui from colorprint import print_bold, print_color, Color if __name__ == "__main__": if len(sys.argv) > 1: # arguments given, run on command line print_bold("\n///// PLAYLIST FORMATTER /////\n", Color.red) filename = sys.argv[1] outfile = sys.argv[2] if len(sys.argv) == 2 else filename formatter = PlaylistFormatter() formatter.read_playlist(filename) formatter.print_playlist() print("exporting formatted playlist to:") print_color(outfile, Color.yellow) formatter.export_csv(outfile) print_bold("\n/////////// DONE ////////////\n", Color.green) else: # open GUI app = QApplication(sys.argv) app.setStyle("Fusion") # colors palette = QPalette() palette.setColor(QPalette.Window, QColor(205, 0, 0)) palette.setColor(QPalette.WindowText, Qt.white) palette.setColor(QPalette.Base, QColor(15, 15, 15)) palette.setColor(QPalette.AlternateBase, QColor(53, 53, 53)) palette.setColor(QPalette.ToolTipBase, Qt.white)