Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

50 cleanup temp files #51

Merged
merged 12 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ cython_debug/
/lastfm_cache.db
/lastfm_cache.db-journal
/test.flac
/test.opus
/test.mp3

# macOS General
.DS_Store
Expand Down
Empty file added src/__init__.py
Empty file.
459 changes: 286 additions & 173 deletions src/azuracast/main.py

Large diffs are not rendered by default.

14 changes: 11 additions & 3 deletions src/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,21 @@
from croniter import croniter
from time import sleep

# Set the global logging level to INFO
logging.basicConfig(level=logging.INFO, format='%(levelname)s:%(name)s:%(message)s')
# Get the logging level from the environment, default to 'INFO' if not set or invalid
log_level = os.getenv('M3U_LOGGING_LEVEL', 'INFO').upper()
numeric_level = getattr(logging, log_level, None)
if not isinstance(numeric_level, int):
raise ValueError(f'Invalid log level: {log_level}')

# Configure the basic logging settings with the specified log level
logging.basicConfig(level=numeric_level, format='%(levelname)s:%(name)s:%(message)s')

# Get a logger
logger = logging.getLogger(__name__)

VERSION = "__VERSION__" # <-- This will be replaced during the release process

BATCH_SIZE = 3
BATCH_SIZE = os.getenv('M3U_BATCH_SIZE', 1)

def generate_playlists() -> None:
"""Main function to generate m3u playlists for genres, artists, albums, and years."""
Expand Down
133 changes: 66 additions & 67 deletions src/radioplaylist/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,75 +129,74 @@ def generate_playlist(self, genres: List[str], min_duration: int, playlist_name:
"""Generates a radio playlist based on input genres, minimum duration, and playlist name.

Args:
genres (list): List of genres to include in the playlist.
min_duration (int): Minimum duration of the playlist in seconds.
playlist_name (str): Name of the playlist.
genres: List of genres to include in the playlist.
min_duration: Minimum duration of the playlist in seconds.
playlist_name: Name of the playlist.

Returns:
list: Generated playlist.
Generated playlist.
"""
def track_already_added(track_id: str) -> bool:
return track_id in [track['Id'] for track in playlist]

def is_track_rejected(track: Dict[str, Any]) -> bool:
return self._is_rejected(track, playlist_name)

def select_random_genre(genres: List[str], ignored_genres: set) -> Optional[str]:
available_genres = [genre for genre in genres if genre not in ignored_genres]
return random.choice(available_genres) if available_genres else None

def add_track_to_playlist(track: Dict[str, Any], playlist: List[Dict[str, Any]]) -> None:
playlist.append(track)
seen_tracks.add(track['Id'])
update_playlist_duration(track['RunTimeTicks'] // 10000000) # Convert ticks to seconds

def update_playlist_duration(duration: int) -> None:
nonlocal playlist_duration
playlist_duration += duration

def refresh_genres(genres: List[str]) -> List[str]:
return self._remove_year_decade_filters(genres)

playlist = []
playlist_duration = 0
seen_tracks = set()
genre_rejects = set()
max_failures = 20
failure_count = 0

with tqdm(total=min_duration, desc=f"Generating playlist '{playlist_name}'", unit="second") as pbar:
while playlist_duration < min_duration:
if len(genres) == len(genre_rejects):
genres = self._remove_year_decade_filters(genres)
genre_rejects.clear()
if not genres:
logger.warning(f"Could not generate full playlist '{playlist_name}'. Insufficient tracks.")
break

genre = random.choice([g for g in genres if g not in genre_rejects])
seed_track = self._get_random_track_by_genre(genre)

if not seed_track or seed_track['Id'] in seen_tracks:
genre_rejects.add(genre)
failure_count += 1
if failure_count >= max_failures:
logger.warning(f"Max failures reached. Unable to complete playlist '{playlist_name}'.")
break
continue

if self._is_rejected(seed_track, playlist_name):
genre_rejects.add(genre)
failure_count += 1
if failure_count >= max_failures:
logger.warning(f"Max failures reached. Unable to complete playlist '{playlist_name}'.")
break
continue

failure_count = 0 # Reset failure count on successful addition
playlist.append(seed_track)
duration = seed_track['RunTimeTicks'] // 10000000 # Convert ticks to seconds
playlist_duration += duration
seen_tracks.add(seed_track['Id'])
pbar.update(duration)

# Loop for fetching similar tracks
similar_tracks = self._get_similar_tracks(seed_track)
for similar_track in similar_tracks:
if not isinstance(similar_track, dict) or 'artist' not in similar_track or 'title' not in similar_track:
continue

track_artist = similar_track['artist']
track_title = similar_track['title']
track = self.playlist_manager.get_track_by_title_and_artist(track_title, track_artist)

if track and track['Id'] not in seen_tracks and not self._is_rejected(track, playlist_name):
playlist.append(track)
duration = track['RunTimeTicks'] // 10000000 # Convert ticks to seconds
playlist_duration += duration
seen_tracks.add(track['Id'])
pbar.update(duration)

if random.random() < 0.3:
break

# We do not update failure_count here to avoid counting every similar tracks loop as a failure

return playlist
ignored_genres = set()
retry_limit = 20
retry_count = 0

while playlist_duration < min_duration:
if retry_count >= retry_limit:
break

genre = select_random_genre(genres, ignored_genres)
if not genre:
genres = refresh_genres(genres)
if not genres:
logger.warning(f"Cannot generate full playlist '{playlist_name}': insufficient tracks.")
break
ignored_genres.clear()
continue

initial_track = self._get_random_track_by_genre(genre)
if not initial_track or track_already_added(initial_track['Id']) or is_track_rejected(initial_track):
ignored_genres.add(genre)
retry_count += 1
continue

retry_count = 0 # Reset retry count on successful track addition
add_track_to_playlist(initial_track, playlist)

candidate_tracks = self._get_similar_tracks(initial_track)
for candidate in candidate_tracks:
if random.random() < 0.3:
break

similar_track = self.playlist_manager.get_track_by_title_and_artist(candidate['title'], candidate['artist'])
if similar_track and not track_already_added(similar_track['Id']) and not is_track_rejected(similar_track):
add_track_to_playlist(similar_track, playlist)

if not candidate_tracks:
genres = refresh_genres(genres)

return playlist
Loading