Add station selection feature to SetupWizard and scrape function

Co-authored-by: nmemmert <67961292+nmemmert@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot]andnmemmert committed 2025-11-28 16:29:29 +00:00
1 parent d5da0f710e
commit 013edb952f
2 files changed
+114 -69

No files matched your search

+36 -1
View File
@@ -59,6 +59,9 @@ class Config:
def save_config(self, config): def save_config(self, config):
"""Save config to QSettings""" """Save config to QSettings"""
for key, value in config.items(): for key, value in config.items():
# Handle list values (convert to comma-separated string)
if isinstance(value, list):
value = ','.join(value)
self.set(key, value) self.set(key, value)
class SetupWizard(QDialog): class SetupWizard(QDialog):
@@ -109,6 +112,22 @@ class SetupWizard(QDialog):
form_group.setLayout(form_layout) form_group.setLayout(form_layout)
layout.addWidget(form_group) layout.addWidget(form_group)
# Station Selection
station_group = QGroupBox("Station Selection")
station_layout = QVBoxLayout()
station_layout.addWidget(QLabel("Select which stations to monitor:"))
self.journey_fm_checkbox = QCheckBox("Journey FM (myjourneyfm.com)")
self.journey_fm_checkbox.setChecked(True)
station_layout.addWidget(self.journey_fm_checkbox)
self.spirit_fm_checkbox = QCheckBox("Spirit FM (spiritfm.com)")
self.spirit_fm_checkbox.setChecked(True)
station_layout.addWidget(self.spirit_fm_checkbox)
station_group.setLayout(station_layout)
layout.addWidget(station_group)
# Scheduling options # Scheduling options
sched_group = QGroupBox("Scheduling") sched_group = QGroupBox("Scheduling")
sched_layout = QVBoxLayout() sched_layout = QVBoxLayout()
@@ -147,14 +166,30 @@ class SetupWizard(QDialog):
self.server_input.setText(config.get('SERVER_IP', '')) self.server_input.setText(config.get('SERVER_IP', ''))
self.playlist_input.setText(config.get('PLAYLIST_NAME', 'Journey FM Recently Played')) self.playlist_input.setText(config.get('PLAYLIST_NAME', 'Journey FM Recently Played'))
# Load station selections
selected_stations = config.get('SELECTED_STATIONS', 'journey_fm,spirit_fm')
if isinstance(selected_stations, str):
selected_stations = selected_stations.split(',')
else:
selected_stations = ['journey_fm', 'spirit_fm']
self.journey_fm_checkbox.setChecked('journey_fm' in selected_stations)
self.spirit_fm_checkbox.setChecked('spirit_fm' in selected_stations)
def get_config(self): def get_config(self):
selected_stations = []
if self.journey_fm_checkbox.isChecked():
selected_stations.append('journey_fm')
if self.spirit_fm_checkbox.isChecked():
selected_stations.append('spirit_fm')
return { return {
'PLEX_TOKEN': self.token_input.text().strip(), 'PLEX_TOKEN': self.token_input.text().strip(),
'SERVER_IP': self.server_input.text().strip(), 'SERVER_IP': self.server_input.text().strip(),
'PLAYLIST_NAME': self.playlist_input.text().strip(), 'PLAYLIST_NAME': self.playlist_input.text().strip(),
'AUTO_UPDATE': self.auto_update.isChecked(), 'AUTO_UPDATE': self.auto_update.isChecked(),
'UPDATE_INTERVAL': self.interval_spin.value(), 'UPDATE_INTERVAL': self.interval_spin.value(),
'UPDATE_UNIT': self.interval_unit.currentText() 'UPDATE_UNIT': self.interval_unit.currentText(),
'SELECTED_STATIONS': ','.join(selected_stations)
} }
class LogViewer(QWidget): class LogViewer(QWidget):
+78 -68
View File
@@ -32,8 +32,11 @@ PLEX_TOKEN = 'pU-m3HWYUZU6iXJFhJyA' # Your Plex.tv token
SERVER_IP = '172.16.16.106' # Your local server IP SERVER_IP = '172.16.16.106' # Your local server IP
PLAYLIST_NAME = 'Journey FM Recently Played' PLAYLIST_NAME = 'Journey FM Recently Played'
def scrape_recently_played(): def scrape_recently_played(selected_stations=None):
"""Scrape recently played songs from Journey FM and Spirit FM""" """Scrape recently played songs from Journey FM and Spirit FM"""
if selected_stations is None:
selected_stations = ['journey_fm', 'spirit_fm']
options = Options() options = Options()
options.add_argument("--headless=new") options.add_argument("--headless=new")
options.add_argument("--no-sandbox") options.add_argument("--no-sandbox")
@@ -58,80 +61,82 @@ def scrape_recently_played():
seen = set() seen = set()
# Journey FM - uses <strong> for title, normal text for artist # Journey FM - uses <strong> for title, normal text for artist
try: if 'journey_fm' in selected_stations:
print("Scraping Journey FM...")
driver.get('https://www.myjourneyfm.com/recently-played/')
time.sleep(5)
# Click "View More" button if exists
try: try:
more_button = driver.find_element(By.ID, "moreSongs") print("Scraping Journey FM...")
more_button.click() driver.get('https://www.myjourneyfm.com/recently-played/')
time.sleep(5) time.sleep(5)
except:
pass # Click "View More" button if exists
soup = BeautifulSoup(driver.page_source, 'html.parser')
# Find all song items using the proper class structure
song_items = soup.find_all('div', class_='rp-item')
for item in song_items:
try: try:
title_elem = item.find('h5', class_='song-title') more_button = driver.find_element(By.ID, "moreSongs")
artist_elem = item.find('p', class_='song-artist') more_button.click()
time.sleep(5)
if title_elem and artist_elem: except:
title = title_elem.get_text().strip() pass
artist = artist_elem.get_text().strip()
soup = BeautifulSoup(driver.page_source, 'html.parser')
# Find all song items using the proper class structure
song_items = soup.find_all('div', class_='rp-item')
for item in song_items:
try:
title_elem = item.find('h5', class_='song-title')
artist_elem = item.find('p', class_='song-artist')
if title_elem and artist_elem:
title = title_elem.get_text().strip()
artist = artist_elem.get_text().strip()
if title and artist:
key = (title.lower(), artist.lower())
if key not in seen:
all_songs.append({'title': title, 'artist': artist, 'source': 'Journey FM'})
seen.add(key)
print(f" Found: {title} by {artist}")
except Exception as e:
continue
except Exception as e:
print(f"Error scraping Journey FM: {e}")
# Spirit FM - loads songs from iframe text file
if 'spirit_fm' in selected_stations:
try:
print("Scraping Spirit FM...")
driver.get('https://spiritfm.com/ajax/now_playing_history.txt')
time.sleep(3)
# Parse the plain text format: "Mon 01:45PM Artist - Title"
soup = BeautifulSoup(driver.page_source, 'html.parser')
text_content = soup.get_text()
# Split into lines and parse each
for line in text_content.split('\n'):
line = line.strip()
if not line:
continue
# Match pattern: Day HH:MM(AM/PM) Artist - Title
match = re.match(r'^\w+\s+\d+:\d+[AP]M\s+(.+?)\s+-\s+(.+)$', line)
if match:
artist = match.group(1).strip()
title = match.group(2).strip()
# Clean up HTML entities
artist = artist.replace('&amp;', '&')
title = title.replace('&amp;', '&')
if title and artist: if title and artist:
key = (title.lower(), artist.lower()) key = (title.lower(), artist.lower())
if key not in seen: if key not in seen:
all_songs.append({'title': title, 'artist': artist, 'source': 'Journey FM'}) all_songs.append({'title': title, 'artist': artist, 'source': 'Spirit FM'})
seen.add(key) seen.add(key)
print(f" Found: {title} by {artist}") print(f" Found: {title} by {artist}")
except Exception as e:
continue except Exception as e:
print(f"Error scraping Spirit FM: {e}")
except Exception as e:
print(f"Error scraping Journey FM: {e}")
# Spirit FM - loads songs from iframe text file
try:
print("Scraping Spirit FM...")
driver.get('https://spiritfm.com/ajax/now_playing_history.txt')
time.sleep(3)
# Parse the plain text format: "Mon 01:45PM Artist - Title"
soup = BeautifulSoup(driver.page_source, 'html.parser')
text_content = soup.get_text()
# Split into lines and parse each
for line in text_content.split('\n'):
line = line.strip()
if not line:
continue
# Match pattern: Day HH:MM(AM/PM) Artist - Title
match = re.match(r'^\w+\s+\d+:\d+[AP]M\s+(.+?)\s+-\s+(.+)$', line)
if match:
artist = match.group(1).strip()
title = match.group(2).strip()
# Clean up HTML entities
artist = artist.replace('&amp;', '&')
title = title.replace('&amp;', '&')
if title and artist:
key = (title.lower(), artist.lower())
if key not in seen:
all_songs.append({'title': title, 'artist': artist, 'source': 'Spirit FM'})
seen.add(key)
print(f" Found: {title} by {artist}")
except Exception as e:
print(f"Error scraping Spirit FM: {e}")
driver.quit() driver.quit()
@@ -312,12 +317,17 @@ def setup_scheduler(params):
def main(): def main():
global PLEX_TOKEN, SERVER_IP, PLAYLIST_NAME global PLEX_TOKEN, SERVER_IP, PLAYLIST_NAME
# Load or prompt for config # Load or prompt for config
selected_stations = ['journey_fm', 'spirit_fm'] # default
if os.path.exists('config.json'): if os.path.exists('config.json'):
with open('config.json', 'r') as f: with open('config.json', 'r') as f:
config = json.load(f) config = json.load(f)
PLEX_TOKEN = config.get('PLEX_TOKEN', PLEX_TOKEN) PLEX_TOKEN = config.get('PLEX_TOKEN', PLEX_TOKEN)
SERVER_IP = config.get('SERVER_IP', SERVER_IP) SERVER_IP = config.get('SERVER_IP', SERVER_IP)
PLAYLIST_NAME = config.get('PLAYLIST_NAME', PLAYLIST_NAME) PLAYLIST_NAME = config.get('PLAYLIST_NAME', PLAYLIST_NAME)
# Load selected stations
selected_stations_str = config.get('SELECTED_STATIONS', 'journey_fm,spirit_fm')
if isinstance(selected_stations_str, str):
selected_stations = selected_stations_str.split(',')
else: else:
# If no config file, use defaults (GUI should handle this) # If no config file, use defaults (GUI should handle this)
pass pass
@@ -328,8 +338,8 @@ def main():
# Initialize history database # Initialize history database
init_history_db() init_history_db()
# Scrape songs # Scrape songs with selected stations
songs = scrape_recently_played() songs = scrape_recently_played(selected_stations)
# Connect to Plex via MyPlexAccount # Connect to Plex via MyPlexAccount
account = MyPlexAccount(token=PLEX_TOKEN) account = MyPlexAccount(token=PLEX_TOKEN)