Add scraping from Spirit FM recently played list, combine with Journey FM and deduplicate songs
This commit is contained in:
1 parent
7e7754f533
commit
32d87cf0c2
1 file changed
+78
-67
@@ -31,77 +31,88 @@ 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():
|
||||||
"""Scrape recently played songs from myjourneyfm.com using Selenium"""
|
"""Scrape recently played songs from multiple stations using Selenium"""
|
||||||
options = Options()
|
urls = [
|
||||||
options.add_argument("--headless")
|
'https://www.myjourneyfm.com/recently-played/',
|
||||||
options.add_argument("--no-sandbox")
|
'https://spiritfm.com/spiritfm-recently-played/'
|
||||||
options.add_argument("--disable-dev-shm-usage")
|
]
|
||||||
options.add_argument("--disable-gpu")
|
|
||||||
options.add_argument("--remote-debugging-port=9222")
|
|
||||||
options.add_argument("--user-data-dir=/tmp/chromium")
|
|
||||||
options.add_argument("--no-first-run")
|
|
||||||
options.add_argument("--disable-extensions")
|
|
||||||
options.binary_location = "/usr/bin/chromium-browser"
|
|
||||||
service = Service()
|
|
||||||
driver = webdriver.Chrome(service=service, options=options)
|
|
||||||
|
|
||||||
url = 'https://www.myjourneyfm.com/recently-played/'
|
all_songs = []
|
||||||
driver.get(url)
|
seen = set() # To avoid duplicates
|
||||||
|
|
||||||
# Wait for initial load
|
for url in urls:
|
||||||
time.sleep(5)
|
options = Options()
|
||||||
|
options.add_argument("--headless")
|
||||||
# Click "View More" button if exists
|
options.add_argument("--no-sandbox")
|
||||||
try:
|
options.add_argument("--disable-dev-shm-usage")
|
||||||
more_button = driver.find_element(By.ID, "moreSongs")
|
options.add_argument("--disable-gpu")
|
||||||
more_button.click()
|
options.add_argument("--remote-debugging-port=9222")
|
||||||
time.sleep(5) # Wait for more songs to load
|
options.add_argument("--user-data-dir=/tmp/chromium")
|
||||||
except:
|
options.add_argument("--no-first-run")
|
||||||
pass # Button not found or already loaded
|
options.add_argument("--disable-extensions")
|
||||||
|
options.binary_location = "/usr/bin/chromium-browser"
|
||||||
html = driver.page_source
|
service = Service()
|
||||||
driver.quit()
|
driver = webdriver.Chrome(service=service, options=options)
|
||||||
|
|
||||||
# Optional: save HTML to file for debugging (comment out if not needed)
|
driver.get(url)
|
||||||
# with open('page.html', 'w', encoding='utf-8') as f:
|
|
||||||
# f.write(html)
|
# Wait for initial load
|
||||||
|
time.sleep(5)
|
||||||
soup = BeautifulSoup(html, 'html.parser')
|
|
||||||
|
# Click "View More" button if exists
|
||||||
songs = []
|
try:
|
||||||
# Find elements (div, li) that contain time in their text
|
more_button = driver.find_element(By.ID, "moreSongs")
|
||||||
song_elements = soup.find_all(lambda tag: tag.name in ['div', 'li', 'p'] and re.search(r'\d+:\d+ [AP]M', tag.get_text()))
|
more_button.click()
|
||||||
for element in song_elements:
|
time.sleep(5) # Wait for more songs to load
|
||||||
spans = element.find_all('span')
|
except:
|
||||||
if len(spans) >= 3:
|
pass # Button not found or already loaded
|
||||||
title = spans[0].get_text().strip()
|
|
||||||
artist = spans[1].get_text().strip()
|
html = driver.page_source
|
||||||
# Ignore time
|
driver.quit()
|
||||||
songs.append({'artist': artist, 'title': title})
|
|
||||||
else:
|
soup = BeautifulSoup(html, 'html.parser')
|
||||||
# Fallback to text parsing
|
|
||||||
full_text = element.get_text().strip()
|
songs = []
|
||||||
match = re.search(r'(\d+:\d+ [AP]M)', full_text)
|
# Find elements (div, li) that contain time in their text
|
||||||
if match:
|
song_elements = soup.find_all(lambda tag: tag.name in ['div', 'li', 'p'] and re.search(r'\d+:\d+ [AP]M', tag.get_text()))
|
||||||
play_time = match.group(1)
|
for element in song_elements:
|
||||||
before = full_text.split(play_time)[0].strip()
|
spans = element.find_all('span')
|
||||||
if ' by ' in before:
|
if len(spans) >= 3:
|
||||||
title, artist = before.split(' by ', 1)
|
title = spans[0].get_text().strip()
|
||||||
title = title.strip()
|
artist = spans[1].get_text().strip()
|
||||||
artist = artist.strip()
|
# Ignore time
|
||||||
else:
|
songs.append({'artist': artist, 'title': title})
|
||||||
# Split on capital letters
|
else:
|
||||||
parts = re.findall(r'[A-Z][^A-Z]*', before)
|
# Fallback to text parsing
|
||||||
if len(parts) == 4:
|
full_text = element.get_text().strip()
|
||||||
title = ' '.join(parts[:2])
|
match = re.search(r'(\d+:\d+ [AP]M)', full_text)
|
||||||
artist = ' '.join(parts[2:])
|
if match:
|
||||||
|
play_time = match.group(1)
|
||||||
|
before = full_text.split(play_time)[0].strip()
|
||||||
|
if ' by ' in before:
|
||||||
|
title, artist = before.split(' by ', 1)
|
||||||
|
title = title.strip()
|
||||||
|
artist = artist.strip()
|
||||||
else:
|
else:
|
||||||
title = ' '.join(parts[:3])
|
# Split on capital letters
|
||||||
artist = ' '.join(parts[3:])
|
parts = re.findall(r'[A-Z][^A-Z]*', before)
|
||||||
if title and artist:
|
if len(parts) == 4:
|
||||||
songs.append({'artist': artist, 'title': title})
|
title = ' '.join(parts[:2])
|
||||||
|
artist = ' '.join(parts[2:])
|
||||||
|
else:
|
||||||
|
title = ' '.join(parts[:3])
|
||||||
|
artist = ' '.join(parts[3:])
|
||||||
|
if title and artist:
|
||||||
|
songs.append({'artist': artist, 'title': title})
|
||||||
|
|
||||||
|
# Add to all_songs, avoiding duplicates
|
||||||
|
for song in songs:
|
||||||
|
key = (song['title'].lower(), song['artist'].lower())
|
||||||
|
if key not in seen:
|
||||||
|
all_songs.append(song)
|
||||||
|
seen.add(key)
|
||||||
|
|
||||||
return songs
|
return all_songs
|
||||||
|
|
||||||
def normalize_string(s):
|
def normalize_string(s):
|
||||||
"""Normalize string for comparison"""
|
"""Normalize string for comparison"""
|
||||||
|
|||||||
Reference in new issue
Block a user