Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save EdwardHinkle/d05eb67bb1081940c30e0e0be17e6604 to your computer and use it in GitHub Desktop.
Save EdwardHinkle/d05eb67bb1081940c30e0e0be17e6604 to your computer and use it in GitHub Desktop.
Fetch recently played episodes from Overcast.fm. WIP.
'''
You'll need to pip install some dependencies:
* python-dateutil
* requests
Also, populate your EMAIL and PASSWORD below.
'''
from xml.etree import ElementTree
from datetime import datetime
from dateutil.tz import UTC
from dateutil.parser import parse as parse_dt
import re
import sys
import requests
import pickle
import os.path
# configuration
EMAIL = 'EMAIL HERE'
PASSWORD = 'PASSWORD HERE'
# load stored session, or re-authenticate
if os.path.exists('session.saved'):
print('Found saved session. Restoring!')
session = pickle.loads(open('session.saved', 'rb').read())
else:
print('No saved session. Authenticating!')
session = requests.Session()
response = session.post('https://overcast.fm/login', data={
'email': EMAIL,
'password': PASSWORD
})
if response.status_code != 200:
print('Authentication failed')
sys.exit(0)
print('Authenticated successfully. Saving session.')
with open('session.saved', 'wb') as saved_session:
saved_session.write(pickle.dumps(session))
# fetch the latest detailed OPML export from Overcast
print('Fetching latest OPML export from Overcast')
response = session.get('https://overcast.fm/account/export_opml/extended')
if response.status_code != 200:
print('Failed to fetch OPML. Exiting.')
print(response.text)
sys.exit(0)
# parse the OPML
tree = ElementTree.fromstring(response.text)
# find all podcasts and their episodes
podcasts = tree.findall(".//*[@type='rss']")
# look for recently played episodes
now = datetime.utcnow().astimezone(UTC)
for podcast in podcasts:
pod_title = podcast.attrib['title']
for episode in podcast.getchildren():
# skip unplayed episodes
played = episode.attrib.get('played', '0') == '1'
if not played:
continue
# skip episodes played over one day ago
user_activity_date = parse_dt(episode.attrib.get('userUpdatedDate'))
recency = now - user_activity_date
if recency.days > 1:
continue
# parse out the remaining details we care about
title = episode.attrib['title']
published = parse_dt(episode.attrib['pubDate'])
url = episode.attrib['url']
overcast_url = episode.attrib['overcastUrl']
overcast_id = episode.attrib['overcastId']
progress = episode.attrib.get('progress')
# fetch the epside artwork
response = session.get(overcast_url)
results = re.findall('img class="art fullart" src="(.*)"', response.text)
artwork_url = ''
if len(results) == 1:
artwork_url = results[0]
print('Played episode of ', pod_title)
print(' ->', title)
print(' ->', artwork_url)
print(' ->', url)
print(' ->', overcast_url)
print(' ->', user_activity_date)
@pandaissad
Copy link

Hi I'm very new to python and script running, but I'm getting "ImportError: cannot import name UTC" - I've installed the dependencies, but I don't know if that is the dateutil is the issue?

Python 2.7.10

@EdwardHinkle
Copy link
Author

To be honest, I'm not great with Python either. I ended up using the logic as the foundation for a Node.js version. I forked this code from here: https://gist.github.com/cleverdevil/a8215850420493c1ee06364161e281c0 I would recommend asking there.

@rknightuk
Copy link

I know this is kinda old but did you ever release the node version of this at all?

@EdwardHinkle
Copy link
Author

EdwardHinkle commented Jan 17, 2023

@rknightuk I built it in a private repo where I had my username and password as strings. Which I shouldn't have done.

But I just copied and pasted that into a Gist over here: https://gist.github.com/EdwardHinkle/80c1f012bdb5681961f834d1a2ada596

@rknightuk
Copy link

Thank you so much!

@EdwardHinkle
Copy link
Author

My pleasure! Have fun 😁

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment