An iOS app (or script perhaps better term) for e.g. iPhone that allow you to add links heard in podcasts into reminders.
Imagine that you just as I often do listening to a podcast such as PythonBytes (a fantastic one btw) using Pocket Casts while out walking and hear a talk about an interesting project or article you wish to read more about when time allow.
Thankfully the referenced links are added to the show notes of the talk, but it means you would usually need to look it up on the podcasts main page and add this into your own personal notes, and using the phone to copy-and-paste is found tedious.
Wouldn't it be nice if there was an easier way select which of those you found interesting and have them added to reminders on your phone while you'd still out walking without the need to lose too much of your focus on where you put your feets..?
... if you also see this as a problem and wished there were a better way, then this small app might be what you're searching for.
So currently the following podcasts are currently supported by the parsers that does the work of finding links and allow one to add to your reminders, but easily extended in the futurue ... see further down how ...
The initial Memocast <= 1.0.0 were relying on Google Podcast, but since the turndown πͺ¦ 2024 the future releases instead suppors same method but you share from Pocket Casts instead.
If you wish to listen or see discussion around this project you may in interessted visiting PythonBytes #338: Scripting iOS with Python (at 18:20) and Real Python - episode 160 (at 43:20)
Step 1) Install Pythonista 3 from app store
Step 2) Either download and run this install.py script within Pythonista on your iPhone/iPad or aim your camera at the below QR-code and open this link.
Step 3) Click Run in the upper right corner.
Step 4) Open up Pyhonista β‘ Script Library β‘ This Phone β‘ memocast-master β‘ app.py
Step 5) Click on the wrench π§ in the upper right β‘ Shortcuts β‘ Share Extension β‘ Click on + icon
Step 6) Change custom title to "MemoCast" β‘ click Add
All that is needed need to do is to create a new python file within the parsers package...
π¦ memocast-project
β£ π memocast
β β£ π ...
β β π parsers
β β£ π __init__.py
β β£ π baseclass.py
β β£ π pythonbytes.py
β β π otherpodcast.py β¨π
... let's pretend we wish to add a new one named otherpodcast.py
and within this we assure we create a new class and inherit from BasePodCastParser
that will allow the application to dynamically use this new one as a plugin.
# memocast/parsers/otherpodcast.py
from typing import Iterable
from bs4 import BeautifulSoup # Most likely to be used for parsing HTML
from memocast.logging_ import logger # Custom logging singleton class
from .. import io_ # Module with e.g. convinient download_html(episode_url)
from .. import protocols # Includes dataclass Url
from .baseclass import BasePodcastParser # Inherit from this baseclass
class OtherParser(BasePodcastParser):
# This is the URL of which this podcast has its links available
base_url = 'https://.....'
@staticmethod
def get_podcast_short_name() -> str:
return "OtherPodCast" # This is used as part of the links shown in Reminders
def get_current_episode_number(self) -> int:
# This should return the episode number from Google Podcasts URL
example_episode_number = 134
return example_episodr_number
def parse(self) -> Iterable[protocols.Url]:
# This is the main method to do the work
episode_source_html = io_.download('https://....') # Example
bs = BeautifulSoup(episode_source_html, 'html.parser')
static_example_urls = [
protocols.Url(url='http://foo.com', description='Project Foo', parser=self)
protocols.Url(url='http://bar.com', description='Project Bar', parser=self)
] # Obviously this should be dynamically created by your code
return static_example_urls # Return a list of URLs
By adding this module it will work as a plugin and will automatically be used by the app.
To manually test your parser you can also do that using your regular working environment (MacOS/Windows/Linux) by copying the URL to your clipboard since it use this as fallback. Currently the user interface and "Reminders" is only support by iOS the application will exit before then - but for most cases enough to test your parser.
As with good best practice you may consider creating unit tests (pytest) within the tests
folder.
My past experience developing apps for iOS using Python have been that it have added a lot of overhead using framework such as Kivy that have involved setting up certain tool chain including XCode and required one to compile such into an .ipa file that also required a complex procedure for signing and/or apply other strategy to allow other users to take advantage of your app that often came with a price (at least at that time). But such project were eventually made such as this one.
When I stumbled on Pythonista 3 it crossed me how easy it was to get an "app" running with minimal efforts and does expose the most relevant iOS API's such as accessing part of it you wouldn't easily do using other frameworks and it does have a rich set of packages included from start such as those found here which is quite astonishing. And have yet only started to scratch the surface. ππ
And all that is needed is to share your Python code that also could be done sharing as an URL (at least small scripts) that makes it relatively easy to share your project.
Pythonista 3 comes with a one-time price, but a fairly low one so I would not think it would frighten others
Also what I did discover and made the development experience so smooth is the fact that as long as you have a Mac with a silicon processor you are apple to install and run Pythonista as iOS app within MacOS and continue developing using your favorite IDE (such as PyCharm) and interchangable run within Pythonista on your computer as found needed (acting as an "emulator").
So what I did was to create project folder within the Pythonista created in the iCloud drive, and then I also assured I had this folder under version control using a git-repository and using the iOS app Working Copy as git client on the devices.
Now this iCloud folder that you can have kept synced with your MacOS is found available within
Library/Mobile Documents/iCloud~com~omz-software~Pythonista3/Documents
so that way you can access it either from your favorite IDE on your Mac or from Pythonista from you iOS devices.
For me at least this satisifed my main needs... π
Essentially in sequence the application does ..
- Get URL for the Pocket Casts
- The
BasePodCastParser
sequentially test all parsers- If multiple parsers matching give user a choice to select correct
- The list of all links (URLs) with descriptions displayed to user for selection
- Selected links stored to iOS Reminders
flowchart LR
subgraph get_url [Get Pockets Casts URL]
direction LR
ios_share -.-> get_html_source
clipboard -.-> get_html_source
end
subgraph process [Get podcast homepage and parse]
get_html_source --> get_links
get_links -- ".try_all()" --> PodCastParser(BasePodCastParser)
PodCastParser --Urls--> get_links
style PodCastParser fill:#bbf
end
subgraph podcast [External]
external_podcast_page -.-> PodCastParser
end
subgraph select [Display & Select links]
get_links -- Urls --> PythonistaPodView
style PythonistaPodView fill:#bbf
end
subgraph save [Save to Reminders]
PythonistaPodView -- Urls --> Reminders[(iOS Reminders)]
end
For further development this is the the only class of relevance to extend with additional parsers
classDiagram
BasePodcastParser <|-- PythonBytesParser
BasePodcastParser <|-- OtherParser
BasePodView <|-- PythonistaPodView
main ..> PythonistaPodView : depends
main ..> BasePodcastParser : depends
class BasePodcastParser {
<<abstract>>
+try_all()
}
class PythonBytesParser {
+ base_url
- get_podcast_short_name() : str
- get_current_episode_number() : int
+ parse() : List[Url]
}
class OtherParser {
+ base_url
- get_podcast_short_name() : str
- get_current_episode_number() : int
+ parse() : List[Url]
}
class BasePodView {
<<abstract>>
+show(urls: List[Url])
add_urls_to_reminder(urls: List[Url])
get_option(self, options: List[str], title='')
}
class PythonistaPodView {
...
}
class main {
...
}
This is a project in a very early stage and any contributions are more than welcome by submitting pull request for the repository https://github.com/engdan77/memocast since it may still have some rough edges. And new "parsers" (see above) is found valuable.
- Developers of Pythonista for such great app making life easiers
- Maintainers of Requests, Beautifulsoup4 making this app possible
- Hosts of PythonBytes (Michael Kennedy and Brian Okken), Talk Python To Me (Michael Kennedy) and RealPython (Christopher Bailey) for fantastic talks
- Jetbrains for remarkable PyCharm