Skip to content

Commit ae7cdf5

Browse files
Re-apply old TR feedback
Co-authored-by: Bartosz <[email protected]>
1 parent a0fd072 commit ae7cdf5

File tree

8 files changed

+84
-95
lines changed

8 files changed

+84
-95
lines changed

python-selenium/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ To run the music player, install the package, then use the entry point command f
2828
You'll see a text-based user interface that allows you to interact with the music player:
2929

3030
```
31-
Type: play [<track_number>] | tracks | more | exit
31+
Type: play [<track_number>] | pause | tracks | more | exit
3232
>
3333
```
3434

python-selenium/pyproject.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,3 @@ dependencies = [
1616
]
1717
[project.scripts]
1818
bandcamp-player = "bandcamp.__main__:main"
19-
20-
[tool.setuptools.packages.find]
21-
where = ["src"]
Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
1-
from bandcamp.app.tui import TUI
1+
from bandcamp.app.tui import interact
22

33

44
def main():
5-
"""Provides the main entry point for the app."""
6-
tui = TUI()
7-
tui.interact()
5+
"""Provide the main entry point for the app."""
6+
interact()
87

98

10-
if __name__ == "__main__":
11-
main()
9+
main()

python-selenium/src/bandcamp/app/player.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
from bandcamp.web.element import TrackElement
55
from bandcamp.web.page import DiscoverPage
66

7-
BANDCAMP_DISCOVER = "https://bandcamp.com/discover/"
7+
BANDCAMP_DISCOVER_URL = "https://bandcamp.com/discover/"
88

99

1010
class Player:
11-
"""Plays tracks from Bandcamp's Discover page."""
11+
"""Play tracks from Bandcamp's Discover page."""
1212

1313
def __init__(self) -> None:
1414
self._driver = self._set_up_driver()
@@ -22,11 +22,11 @@ def __enter__(self):
2222
return self
2323

2424
def __exit__(self, exc_type, exc_value, exc_tb):
25-
"""Closes the headless browser."""
25+
"""Close the headless browser."""
2626
self._driver.quit()
2727

2828
def play(self, track_number=None):
29-
"""Plays the first track, or one of the available numbered tracks."""
29+
"""Play the first track, or one of the available numbered tracks."""
3030
if track_number:
3131
self._current_track = TrackElement(
3232
self.tracklist.available_tracks[track_number - 1],
@@ -35,13 +35,13 @@ def play(self, track_number=None):
3535
self._current_track.play()
3636

3737
def pause(self):
38-
"""Pauses the current track."""
38+
"""Pause the current track."""
3939
self._current_track.pause()
4040

4141
def _set_up_driver(self):
42-
"""Creates a headless browser pointing to Bandcamp."""
42+
"""Create a headless browser pointing to Bandcamp."""
4343
options = Options()
4444
options.add_argument("--headless")
4545
browser = Firefox(options=options)
46-
browser.get(BANDCAMP_DISCOVER)
46+
browser.get(BANDCAMP_DISCOVER_URL)
4747
return browser
Lines changed: 56 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -1,76 +1,70 @@
11
from bandcamp.app.player import Player
22

33

4-
class TUI:
5-
"""Provides a text-based user interface for a Bandcamp music player."""
4+
COLUMN_WIDTH = CW = 30
5+
MAX_TRACKS = 100 # Allows to load more tracks once.
66

7-
COLUMN_WIDTH = CW = 30
8-
MAX_TRACKS = 120 # Twice the number of tracks that fit in the viewport.
9-
10-
def interact(self):
11-
"""Controls the player through user interactions."""
12-
with Player() as player:
13-
while True:
14-
print(
15-
"\nType: [play <track number>], [pause], [tracks], [more], [exit]"
16-
)
17-
command = input("> ").strip().lower()
18-
19-
if command.startswith("play"):
7+
def interact():
8+
"""Control the player through user interactions."""
9+
with Player() as player:
10+
while True:
11+
print(
12+
"\nType: play [<track number>] | pause | tracks | more | exit"
13+
)
14+
match input("> ").strip().lower().split():
15+
case ["play"]:
16+
play(player)
17+
case ["play", track]:
2018
try:
21-
track_number = int(command.split()[1])
22-
self.play(player, track_number)
23-
except IndexError: # Play first track.
24-
self.play(player)
19+
track_number = int(track)
20+
play(player, track_number)
2521
except ValueError:
2622
print("Please provide a valid track number.")
27-
elif command == "pause":
28-
self.pause(player)
29-
elif command == "tracks":
30-
self.tracks(player)
31-
elif command == "more":
32-
# A higher number of tracks can't be clicked without scrolling.
33-
if len(player.tracklist.available_tracks) >= self.MAX_TRACKS:
34-
print("Can't load more tracks. Pick one from the track list.")
35-
else:
36-
player.tracklist.load_more()
37-
self.tracks(player)
38-
elif command == "exit":
23+
case ["pause"]:
24+
pause(player)
25+
case ["tracks"]:
26+
display_tracks(player)
27+
case ["more"] if len(player.tracklist.available_tracks) >= MAX_TRACKS:
28+
print("Can't load more tracks. Pick one from the track list.")
29+
case ["more"]:
30+
player.tracklist.load_more()
31+
display_tracks(player)
32+
case ["exit"]:
3933
print("Exiting the player...")
4034
break
41-
else:
35+
case _:
4236
print("Unknown command. Try again.")
4337

44-
def play(self, player, track_number=None):
45-
"""Plays a track and shows info about the track."""
46-
player.play(track_number)
47-
print(player._current_track._get_track_info())
4838

49-
def pause(self, player):
50-
"""Pauses the current track."""
51-
player.pause()
39+
def play(player, track_number=None):
40+
"""Play a track and shows info about the track."""
41+
player.play(track_number)
42+
print(player._current_track._get_track_info())
43+
44+
def pause(player):
45+
"""Pause the current track."""
46+
player.pause()
5247

53-
def tracks(self, player):
54-
"""Displays information about the currently playable tracks."""
55-
header = (
56-
f"{'#':<5} {'Album':<{self.CW}} {'Artist':<{self.CW}} {'Genre':<{self.CW}}"
57-
)
58-
print(header)
59-
print("-" * 100)
60-
for track_number, track in enumerate(
61-
player.tracklist.available_tracks, start=1
62-
):
63-
if track.text:
64-
album, artist, *genre = track.text.split("\n")
65-
album = self._truncate(album, self.CW)
66-
artist = self._truncate(artist, self.CW)
67-
genre = self._truncate(genre[0], self.CW) if genre else ""
68-
print(
69-
f"{track_number:<5} {album:<{self.CW}} "
70-
f"{artist:<{self.CW}} {genre:<{self.CW}}"
71-
)
48+
def display_tracks(player):
49+
"""Display information about the currently playable tracks."""
50+
header = (
51+
f"{'#':<5} {'Album':<{CW}} {'Artist':<{CW}} {'Genre':<{CW}}"
52+
)
53+
print(header)
54+
print("-" * 100)
55+
for track_number, track in enumerate(
56+
player.tracklist.available_tracks, start=1
57+
):
58+
if track.text:
59+
album, artist, *genre = track.text.split("\n")
60+
album = _truncate(album, CW)
61+
artist = _truncate(artist, CW)
62+
genre = _truncate(genre[0], CW) if genre else ""
63+
print(
64+
f"{track_number:<5} {album:<{CW}} "
65+
f"{artist:<{CW}} {genre:<{CW}}"
66+
)
7267

73-
@staticmethod
74-
def _truncate(text, width):
75-
"""Truncates track information."""
76-
return text[: width - 3] + "..." if len(text) > width else text
68+
def _truncate(text, width):
69+
"""Truncate track information."""
70+
return text[: width - 3] + "..." if len(text) > width else text

python-selenium/src/bandcamp/web/element.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,19 +4,19 @@
44
from selenium.webdriver.support import expected_conditions as EC
55

66
from bandcamp.web.base import Track, WebComponent
7-
from bandcamp.web.locators import DiscoverPageLocatorMixin, TrackLocatorMixin
7+
from bandcamp.web.locators import DiscoverPageLocator, TrackLocator
88

99

10-
class TrackElement(WebComponent, TrackLocatorMixin):
11-
"""Models a playable track in Bandcamp's Discover section."""
10+
class TrackElement(WebComponent, TrackLocator):
11+
"""Model a playable track in Bandcamp's Discover section."""
1212

1313
def play(self) -> None:
14-
"""Plays the track."""
14+
"""Play the track."""
1515
if not self.is_playing:
1616
self._get_play_button().click()
1717

1818
def pause(self) -> None:
19-
"""Pauses the track."""
19+
"""Pause the track."""
2020
if self.is_playing:
2121
self._get_play_button().click()
2222

@@ -25,7 +25,7 @@ def is_playing(self) -> bool:
2525
return "Pause" in self._get_play_button().get_attribute("aria-label")
2626

2727
def _get_track_info(self) -> Track:
28-
"""Creates a representation of the track's relevant information."""
28+
"""Create a representation of the track's relevant information."""
2929
full_url = self._parent.find_element(*self.URL).get_attribute("href")
3030
# Cut off the referrer query parameter
3131
clean_url = full_url.split("?")[0] if full_url else ""
@@ -45,23 +45,23 @@ def _get_play_button(self):
4545
return self._parent.find_element(*self.PLAY_BUTTON)
4646

4747

48-
class DiscoverTrackList(WebComponent, DiscoverPageLocatorMixin, TrackLocatorMixin):
49-
"""Models the track list in Bandcamp's Discover section."""
48+
class DiscoverTrackList(WebComponent, DiscoverPageLocator, TrackLocator):
49+
"""Model the track list in Bandcamp's Discover section."""
5050

5151
def __init__(self, parent: WebElement, driver: WebDriver = None) -> None:
5252
super().__init__(parent, driver)
5353
self.available_tracks = self._get_available_tracks()
5454

5555
def load_more(self) -> None:
56-
"""Loads additional tracks in the Discover section."""
56+
"""Load additional tracks in the Discover section."""
5757
view_more_button = self._driver.find_element(*self.PAGINATION_BUTTON)
5858
view_more_button.click()
5959
# The button is disabled until all new tracks are loaded.
6060
self._wait.until(EC.element_to_be_clickable(self.PAGINATION_BUTTON))
6161
self.available_tracks = self._get_available_tracks()
6262

6363
def _get_available_tracks(self) -> list:
64-
"""Finds all currently available tracks in the Discover section."""
64+
"""Find all currently available tracks in the Discover section."""
6565
self._wait.until(
6666
lambda driver: any(
6767
e.is_displayed() and e.text.strip()

python-selenium/src/bandcamp/web/locators.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from selenium.webdriver.common.by import By
22

33

4-
class DiscoverPageLocatorMixin:
4+
class DiscoverPageLocator:
55
DISCOVER_RESULTS = (By.CLASS_NAME, "results-grid")
66
ITEM = (By.CLASS_NAME, "results-grid-item")
77
PAGINATION_BUTTON = (By.ID, "view-more")
@@ -11,7 +11,7 @@ class DiscoverPageLocatorMixin:
1111
)
1212

1313

14-
class TrackLocatorMixin:
14+
class TrackLocator:
1515
PLAY_BUTTON = (By.CSS_SELECTOR, "button.play-pause-button")
1616
URL = (By.CSS_SELECTOR, "div.meta p a")
1717
ALBUM = (By.CSS_SELECTOR, "div.meta p a strong")

python-selenium/src/bandcamp/web/page.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
from bandcamp.web.base import WebPage
44
from bandcamp.web.element import DiscoverTrackList
5-
from bandcamp.web.locators import DiscoverPageLocatorMixin
5+
from bandcamp.web.locators import DiscoverPageLocator
66

77

8-
class DiscoverPage(WebPage, DiscoverPageLocatorMixin):
9-
"""Models the relevant parts of the Bandcamp Discover page."""
8+
class DiscoverPage(WebPage, DiscoverPageLocator):
9+
"""Model the relevant parts of the Bandcamp Discover page."""
1010

1111
def __init__(self, driver: WebDriver) -> None:
1212
super().__init__(driver)
@@ -16,5 +16,5 @@ def __init__(self, driver: WebDriver) -> None:
1616
)
1717

1818
def _accept_cookie_consent(self) -> None:
19-
"""Accepts the necessary cookie consent."""
19+
"""Accept the necessary cookie consent."""
2020
self._driver.find_element(*self.COOKIE_ACCEPT_NECESSARY).click()

0 commit comments

Comments
 (0)