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")
Beispiel #2
0
    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)
Beispiel #3
0
    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
Beispiel #4
0
 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")
Beispiel #5
0
    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,
            },
        )
Beispiel #6
0
    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)
Beispiel #7
0
    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()
Beispiel #8
0
    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
Beispiel #10
0
    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
Beispiel #12
0
    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)
Beispiel #15
0
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)