184 lines
6.2 KiB
Python
184 lines
6.2 KiB
Python
"""@file
|
|
@brief All constants of the Musical Time Machine, defined once.
|
|
"""
|
|
|
|
from typing import Final
|
|
|
|
## @name Chart source
|
|
## @{
|
|
|
|
## @brief Base URL of the Bakeboard Hot 100 clone; the chart date and a slash are appended.
|
|
BASE_URL: Final[str] = "https://appbrewery.github.io/bakeboard-hot-100/"
|
|
|
|
## @brief strptime/strftime format of the chart date the user enters.
|
|
DATE_FORMAT: Final[str] = "%Y-%m-%d"
|
|
|
|
## @brief Number of entries on one Hot 100 chart.
|
|
CHART_SIZE: Final[int] = 100
|
|
## @}
|
|
|
|
## @name HTTP request
|
|
## @{
|
|
|
|
## @brief Headers sent with every chart request.
|
|
REQUEST_HEADERS: Final[dict[str, str]] = {
|
|
"User-Agent": (
|
|
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 "
|
|
"(KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36"
|
|
),
|
|
}
|
|
|
|
## @brief Seconds to wait for the chart page before giving up.
|
|
REQUEST_TIMEOUT_SECONDS: Final[int] = 10
|
|
## @}
|
|
|
|
## @name CSS selectors of the Bakeboard chart markup
|
|
## @{
|
|
|
|
## @brief One chart row.
|
|
SELECTOR_ROW: Final[str] = "div.chart-entry"
|
|
|
|
## @brief Song title inside a row.
|
|
SELECTOR_TITLE: Final[str] = "h3.chart-entry__title"
|
|
|
|
## @brief Artist inside a row.
|
|
SELECTOR_ARTIST: Final[str] = "span.chart-entry__artist"
|
|
## @}
|
|
|
|
## @name Command line
|
|
## @{
|
|
|
|
## @brief Prompt asking for the chart date.
|
|
DATE_PROMPT: Final[str] = (
|
|
"Which year do you want to travel to? Type the date in this format YYYY-MM-DD: "
|
|
)
|
|
|
|
## @brief Message for a date that is not YYYY-MM-DD; format with the entered text.
|
|
INVALID_DATE_MESSAGE: Final[str] = "'{text}' is not a valid date; use the format YYYY-MM-DD."
|
|
|
|
## @brief Message when the chart page cannot be fetched; format with the cause.
|
|
CHART_UNAVAILABLE_MESSAGE: Final[str] = "The chart could not be fetched: {reason}"
|
|
|
|
## @brief Message when the page holds no songs; format with the chart date.
|
|
CHART_PARSE_MESSAGE: Final[str] = "No songs were found on the chart page for {date}."
|
|
|
|
## @brief Line format of the printed song list.
|
|
SONG_LINE_TEMPLATE: Final[str] = "{position}. {title} - {artist}"
|
|
|
|
## @brief Process exit code on success.
|
|
EXIT_OK: Final[int] = 0
|
|
|
|
## @brief Process exit code when a domain error stopped the run.
|
|
EXIT_FAILURE: Final[int] = 1
|
|
## @}
|
|
|
|
## @name YouTube Music
|
|
## @{
|
|
|
|
## @brief Playlist title; format with the chart date.
|
|
PLAYLIST_NAME_TEMPLATE: Final[str] = "{date} Billboard 100"
|
|
|
|
## @brief Playlist description; format with the chart date.
|
|
PLAYLIST_DESCRIPTION_TEMPLATE: Final[str] = (
|
|
"Billboard Hot 100 of {date}, made by Musical Time Machine."
|
|
)
|
|
|
|
## @brief File holding the ytmusicapi browser authentication headers (git-ignored).
|
|
BROWSER_FILE_NAME: Final[str] = "browser.json"
|
|
|
|
## @brief ytmusicapi search filter, so only songs are matched.
|
|
SEARCH_FILTER: Final[str] = "songs"
|
|
|
|
## @brief Privacy status of the created playlist.
|
|
PLAYLIST_PRIVACY: Final[str] = "PRIVATE"
|
|
## @}
|
|
|
|
## @name Login check
|
|
## @{
|
|
|
|
## @brief Message with the number of library playlists; format with the count.
|
|
PLAYLIST_COUNT_MESSAGE: Final[str] = "Found {count} playlists in your library."
|
|
|
|
## @brief Message when browser.json is missing or rejected; format with reason and file.
|
|
BROWSER_RENEWAL_MESSAGE: Final[str] = (
|
|
"YouTube Music login failed: {reason}\n"
|
|
"To create or renew {file}:\n"
|
|
" 1. Open Firefox and go to https://music.youtube.com while logged in.\n"
|
|
" 2. Open the developer tools (F12) and select the Network tab.\n"
|
|
" 3. Filter the requests by 'browse' and select one POST request.\n"
|
|
" 4. Right-click it and choose Copy Request Headers.\n"
|
|
" 5. Run 'ytmusicapi browser' and paste the headers "
|
|
"(macOS: pbpaste | ytmusicapi browser)."
|
|
)
|
|
|
|
## @brief Reason when the browser file does not exist; format with the file.
|
|
BROWSER_FILE_MISSING_REASON: Final[str] = "{file} was not found."
|
|
|
|
## @brief Command line flag that checks the YouTube Music login.
|
|
CHECK_LOGIN_FLAG: Final[str] = "--check-login"
|
|
|
|
## @brief Help text of the check-login flag.
|
|
CHECK_LOGIN_HELP: Final[str] = "Log in to YouTube Music and print the number of library playlists."
|
|
|
|
## @brief Command line flag that names the browser file.
|
|
BROWSER_FILE_FLAG: Final[str] = "--browser-file"
|
|
|
|
## @brief Help text of the browser-file flag.
|
|
BROWSER_FILE_HELP: Final[str] = "Path of the ytmusicapi browser headers file."
|
|
## @}
|
|
|
|
## @name Create playlist
|
|
## @{
|
|
|
|
## @brief Command line flag that creates the dated playlist.
|
|
CREATE_PLAYLIST_FLAG: Final[str] = "--create-playlist"
|
|
|
|
## @brief Help text of the create-playlist flag.
|
|
CREATE_PLAYLIST_HELP: Final[str] = (
|
|
"Create the private playlist '<date> Billboard 100' in YouTube Music."
|
|
)
|
|
|
|
## @brief Message after a playlist was created; format with the title.
|
|
PLAYLIST_CREATED_MESSAGE: Final[str] = 'Created playlist "{title}".'
|
|
|
|
## @brief Message when the playlist already exists; format with the title.
|
|
PLAYLIST_EXISTS_MESSAGE: Final[str] = 'Playlist "{title}" already exists; nothing was created.'
|
|
|
|
## @brief Message when YouTube Music returned no playlist id; format with the answer.
|
|
PLAYLIST_CREATION_FAILED_MESSAGE: Final[str] = "The playlist could not be created: {reason}"
|
|
## @}
|
|
|
|
## @name Add songs
|
|
## @{
|
|
|
|
## @brief Seconds to wait between two songs, to stay gentle with YouTube Music.
|
|
ADD_PAUSE_SECONDS: Final[float] = 0.2
|
|
|
|
## @brief Number of search results to ask for; only the first is used.
|
|
SEARCH_LIMIT: Final[int] = 1
|
|
|
|
## @brief Status text ytmusicapi reports when songs were added.
|
|
STATUS_SUCCEEDED: Final[str] = "STATUS_SUCCEEDED"
|
|
|
|
## @brief HTTP status codes that mean the login was rejected.
|
|
AUTH_HTTP_CODES: Final[tuple[str, ...]] = ("HTTP 401", "HTTP 403")
|
|
|
|
## @brief Message when a search fails; format with the reason.
|
|
SONG_SEARCH_FAILED_MESSAGE: Final[str] = "The song search failed: {reason}"
|
|
|
|
## @brief Message when a song is not added; format with the answer.
|
|
SONG_ADD_FAILED_MESSAGE: Final[str] = "The song could not be added: {reason}"
|
|
|
|
## @brief Command line flag that only prints the chart songs.
|
|
LIST_ONLY_FLAG: Final[str] = "--list-only"
|
|
|
|
## @brief Help text of the list-only flag.
|
|
LIST_ONLY_HELP: Final[str] = "Only print the numbered chart songs; no YouTube Music login."
|
|
|
|
## @brief Summary line; format with added, total, title and skipped.
|
|
SUMMARY_MESSAGE: Final[str] = 'Added {added} of {total} songs to "{title}"; skipped {skipped}.'
|
|
|
|
## @brief One line per skipped song; format with title and artist.
|
|
SKIPPED_SONG_MESSAGE: Final[str] = "Skipped: {title} - {artist}"
|
|
## @}
|