Skip to content

Instantly share code, notes, and snippets.

@yinan-c
Last active September 20, 2023 22:09
Show Gist options
  • Save yinan-c/7a7db29eb3869b9fc493ef74d175b60d to your computer and use it in GitHub Desktop.
Save yinan-c/7a7db29eb3869b9fc493ef74d175b60d to your computer and use it in GitHub Desktop.
Export Reeder 5 starred items to csv and bookmark.HTML
# %%
import pandas as pd
import numpy as np
df = pd.read_csv('Item.csv')
df.columns
df.head()
# %%
starred = df[df['starred'] == "1"]
starred
# %%
starred_df = starred[['title', 'link', 'feed']]
starred_df.head()
# %%
starred_df.to_csv('starred.csv', index=False)
with open('starred_bookmarks_nofolder.html', 'w') as file:
file.write('<!DOCTYPE NETSCAPE-Bookmark-file-1>\n')
file.write('<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">\n')
file.write('<TITLE>Bookmarks</TITLE>\n')
file.write('<H1>Bookmarks</H1>\n')
file.write('<DL><p>\n')
for index, row in starred_df.iterrows():
file.write(f'<DT><A HREF="{row["link"]}">{row["title"]}</A>\n')
file.write('</DL><p>\n')
# %%
folder_df = pd.read_csv('Folder.csv')
folder_df.head()
# %%
import re
# Handling Feed column in starred_df
starred_df['feed'] = starred_df['feed'].apply(lambda x: re.findall(r'\d+', x)[0] if pd.notnull(x) else None)
# Create a mapping of feed to folder
feed_to_folder = {}
for idx, row in folder_df.iterrows():
feeds_in_folder = re.findall(r'\d+', row['feeds'])
for feed in feeds_in_folder:
feed_to_folder[feed] = row['extId']
# Map each item in starred_df to a folder
starred_df['folder'] = starred_df['feed'].map(feed_to_folder)
# Now generate the bookmark HTML with folders
with open('starred_bookmarks.html', 'w') as file:
file.write('<!DOCTYPE NETSCAPE-Bookmark-file-1>\n')
file.write('<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">\n')
file.write('<TITLE>Bookmarks</TITLE>\n')
file.write('<H1>Bookmarks</H1>\n')
# For each unique folder
for folder in starred_df['folder'].unique():
if folder is not None:
file.write('<DT><H3>{}</H3>\n'.format(folder))
file.write('<DL><p>\n')
# For each item in the folder
for idx, row in starred_df[starred_df['folder'] == folder].iterrows():
file.write('<DT><A HREF="{}" ADD_DATE="{}">{}</A>\n'.format(row['link'], pd.Timestamp.now().strftime("%Y%m%d%H%M%S"), row['title']))
file.write('</DL><p>\n')
# For items not in any folder
no_folder_items = starred_df[pd.isnull(starred_df['folder'])]
if not no_folder_items.empty:
file.write('<DT><H3>No Folder</H3>\n')
file.write('<DL><p>\n')
# For each item without a folder
for idx, row in no_folder_items.iterrows():
file.write('<DT><A HREF="{}" ADD_DATE="{}">{}</A>\n'.format(row['link'], pd.Timestamp.now().strftime("%Y%m%d%H%M%S"), row['title']))
file.write('</DL><p>\n')
@yinan-c
Copy link
Author

yinan-c commented Sep 20, 2023

Reeder 5 stores its database to RealmDB, the file is at this location:

~/Library/Containers/com.reederapp.5.macOS/Data/Library/Application Support/default.realm

You can use https://github.com/aromajoin/realm-to-csv to convert the data to a csv file for each class

After that, you can use this script to generate a csv for starred items and 2 HTML files which can be directly imported to your Browser (with or without folder structures).

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