Skip to content

Commit

Permalink
A few major fixes and improvements:
Browse files Browse the repository at this point in the history
- Perform feed matching by feed URL instead of fuzzy matching which
  seems to have 100% success rate, old method wasn't working at all for me.
- Ignore uninitialized PA feeds
- Add support for transferring in-progress episodes
- Fix bug in episode URL match fallback logic where it wasn't doing
  anything when a match was found, and add log message when URL match is successful
- Fix error from referencing SimpleChapters.type column which doesn't
  exist in AP 3.6.1
- Remove some unnecessary repeated calls to print function where \n
  literal could be used instead.
  • Loading branch information
fadookie committed Jan 15, 2025
1 parent 31f19c0 commit 9e9ad59
Showing 1 changed file with 46 additions and 43 deletions.
89 changes: 46 additions & 43 deletions pa_to_ap.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ class Feed:
description: str
author: str
keep_updated: int
feed_url: str
folder_name: str = ''


Expand Down Expand Up @@ -77,43 +78,29 @@ def transfer(podcast_addict_cur: Cursor, antenna_pod_cur: Cursor):
# first find match for all feeds in pa
pa_feeds = [Feed(*a) for a in podcast_addict_cur.execute(
'select _id, name, description, author, '
'automaticRefresh, folderName from podcasts '
'where subscribed_status = 1 and is_virtual = 0')]
'automaticRefresh, feed_url, folderName from podcasts '
'where subscribed_status = 1 and is_virtual = 0 and initialized_status = 1')]

print("# Podcast addict feeds:")
for feed in pa_feeds:
print(feed.name)
print()
print()

ap_feeds = [Feed(*a) for a in antenna_pod_cur.execute(
'select id, title, description, author, keep_updated from Feeds '
'where downloaded = 1')]

feed_attr_to_weight = { #
(lambda f: f.name): 0.85, #
(lambda f: f.author): 0.15, #
}
matcher = ObjectListMatcher(feed_attr_to_weight)
print("\n\n")

# should never be larger than the largest weight (otherwise is
# slightly unpredictable, as not every weight will be evaluated)
# value in range [0, 1]
matcher.minimum_similarity = 0.78
ap_feeds = {a[5]: Feed(*a) for a in antenna_pod_cur.execute(
'select id, title, description, author, keep_updated, download_url from Feeds '
)}

pa_to_ap = []

ap_indices = matcher.get_indices(pa_feeds, ap_feeds)
for n, pa in enumerate(pa_feeds):
ap_idx = ap_indices[n]

ap_name = '!!! NO MATCH !!!'
if ap_idx >= 0:
ap = ap_feeds[ap_idx]
pa_name = pa.name if pa.name else pa.feed_url
if pa.feed_url in ap_feeds:
ap = ap_feeds[pa.feed_url]
ap_name = ap.name
pa_to_ap.append((pa, ap))

print(pa.name, ap_name, sep=" -> ")
print(pa_name, ap_name, sep=" -> ")
print()

if not confirmed("Is this correct? Can we continue?"):
Expand Down Expand Up @@ -154,24 +141,22 @@ def transfer_from_feed_to_feed(podcast_addict_cur: Cursor, #
pa_episodes = list(podcast_addict_cur.execute( #
# 0 1 n2 n3 n4
'select _id, name, seen_status, favorite, local_file_name, '
# n5 n6 n7 n8
'playbackDate, duration_ms, chapters_extracted, download_url '
# n5 n6 n7 n8 n9
'playbackDate, duration_ms, chapters_extracted, download_url, position_to_resume '
'from episodes where podcast_id = ? and '
'(seen_status = 1 or '
'(seen_status = 1 or position_to_resume < 0 or '
'(local_file_name != "" and local_file_name IS NOT NULL))',
(pa.id,)))

ap_episodes = list(antenna_pod_cur.execute( #
'select fi.id, fi.title, fm.download_url '
'from FeedItems fi '
'LEFT JOIN FeedMedia fm ON fi.id = fm.feeditem '
'where fi.feed = ? and fi.read = 0 ', (ap.id,)))
'where fi.feed = ? and fi.read = 0 '
, (ap.id,)))

print()
combinations = len(pa_episodes) * len(ap_episodes)
print(f"Rough estimate: {combinations / 4000:.2f} seconds")
print()
print()
print(f"\nRough estimate: {combinations / 4000:.2f} seconds\n\n")
pa_indices = ITEM_MATCHER.get_indices(ap_episodes, pa_episodes)
seen_match_count = 0

Expand All @@ -185,13 +170,15 @@ def transfer_from_feed_to_feed(podcast_addict_cur: Cursor, #
if MATCH_ON_EPISODE_URL_IF_COULD_NOT_FIND_A_MATCH_OTHERWISE and ap_url is not None:
ap_url = ap_url.strip()
if len(ap_url) > 9:
for pa_idx, pa_ep in enumerate(pa_episodes):
for pa_idx_urlmatch, pa_ep in enumerate(pa_episodes):
if not pa_ep[8]:
continue

pa_url = pa_ep[8].strip()
if pa_url and pa_url == ap_url:
print(f"! Fallback to URL match for: {ap_ep[1]}")
found = True
pa_idx = pa_idx_urlmatch
break

if not found:
Expand All @@ -203,6 +190,10 @@ def transfer_from_feed_to_feed(podcast_addict_cur: Cursor, #
if pa_ep[2]:
transfer_from_seen_ep_to_ep(antenna_pod_cur, podcast_addict_cur, #
pa_ep, ap_ep)
else:
transfer_progress_ep_to_ep(antenna_pod_cur, podcast_addict_cur, #
pa_ep, ap_ep)


if pa_ep[3]:
antenna_pod_cur.execute(
Expand All @@ -227,18 +218,17 @@ def transfer_chapters(antenna_pod_cur: Cursor, #
for title, start in podcast_addict_cur.execute( #
"select name, start from chapters "
"where podcastId = ? and episodeId = ?", (pa_feed_id, pa_ep[0])):
# we use chapter type 2 (id3) simply because it seems most likely
antenna_pod_cur.execute("INSERT INTO SimpleChapters "
"(title, start, feeditem, type) VALUES "
"(?, ?, ?, 2)", (title, start, ap_ep[0],))
"(title, start, feeditem) VALUES "
"(?, ?, ?)", (title, start, ap_ep[0]))


def transfer_from_dld_ep_to_ep(antenna_pod_cur: Cursor, #
podcast_addict_cur: Cursor, #
pa_ep: tuple, #
ap_ep: tuple, #
pa_folder_name: str):
pa_ep_id, _, _, _, pa_local_file_name, _, _, _, _ = pa_ep
pa_ep_id, _, _, _, pa_local_file_name, _, _, _, _, _ = pa_ep

dir_path = EPISODES_DIR_PATH.rstrip("/") + "/" + pa_folder_name
file_path = dir_path + "/" + pa_local_file_name
Expand All @@ -253,8 +243,8 @@ def transfer_from_seen_ep_to_ep(antenna_pod_cur: Cursor, #
podcast_addict_cur: Cursor, #
pa_ep: tuple, #
ap_ep: tuple):
print(ap_ep[1], " <<matched to>> ", pa_ep[1])
pa_ep_id, _, _, _, _, pa_playbackDate, pa_duration_ms, _, _ = pa_ep
print(ap_ep[1], " <<matched to seen>> ", pa_ep[1])
pa_ep_id, _, _, _, _, pa_playbackDate, pa_duration_ms, _, _, _ = pa_ep
antenna_pod_cur.execute("UPDATE FeedItems SET read = 1 WHERE id = ?",
(ap_ep[0],))

Expand All @@ -266,13 +256,26 @@ def transfer_from_seen_ep_to_ep(antenna_pod_cur: Cursor, #
(pa_playbackDate, pa_playbackDate, pa_duration_ms,
ap_ep[0],))

def transfer_progress_ep_to_ep(antenna_pod_cur: Cursor,
podcast_addict_cur: Cursor,
pa_ep: tuple,
ap_ep: tuple):
print(ap_ep[1], " <<matched to in-progress>> ", pa_ep[1])
pa_ep_id, _, _, _, _, pa_playbackDate, pa_duration_ms, _, _, pa_position = pa_ep

antenna_pod_cur.execute("UPDATE FeedMedia "
"SET last_played_time = ?, "
"position = ?, "
"played_duration = ? "
"WHERE feeditem = ?",
(pa_playbackDate, pa_position, pa_position,
ap_ep[0],))


ap_db, pa_db = get_antenna_pod_and_podcast_addict_backup_path()
print()
print("AntennaPod .db file found:", ap_db)
print("\nAntennaPod .db file found:", ap_db)
print("Podcast Addict .db file found:", pa_db)
print()
print()
print("\n")

podcast_addict_con = None
antenna_pod_con = None
Expand Down

0 comments on commit 9e9ad59

Please sign in to comment.