Feeds:
Innlegg
Kommentarar

Archive for mars 2012

Frå Safari til Google Reader

Summary in English at the bottom of the blogpost. The script extracts RSS feeds from the Safari bookmarks export (limited to feeds in the Bookmarks Bar and subfolders) and saves them in an opml file.

* * * * * * *

Eg har Safari som nettlesar i det daglege, og i Safari har eg også ein del RSS-bokmerke. Men når eg er på reisefot med iPad, bruker eg ein app som kommuniserer med Google Reader, det var visst litt praktisk. Eg kunne sjølvsagt konstant ha brukt berre Google Reader når eg sit ved datamaskina, men slik har det no ikkje vorte. Mellom anna fordi Google Reader ikkje tillèt mappe i mappe, og det er også meir tungvint å redigere bokmerka der. Men kven veit korleis eg les RSS i framtida.

I alle fall, til poenget: Eg var for lat til å leggje alle RSS-lenkjene mine frå Safari manuelt inn i Google Reader. I staden laga eg eit skript som trekkjer ut RSS-bokmerke frå bokmerkeeksporten i Safari 5.1 for Mac, og lagrar dei i ei opml-fil, som så kan importerast i Google Reader eller andre RSS-lesarar.

Fyrst, ha i bakhovudet at Safari viser talet på ulesne RSS-artiklar i ein parentes, men at dette gjeld berre for RSS-bokmerke som ligg i bokmerkelina. RSS-lenkjer som ligg i bokmerkemenyen, oppdaterer seg ikkje. Derfor hentar skriptet ut RSS-lenkjer berre frå bokmerkelina med undermapper.

Skjermbilete: Safari med RSS-bokmerke

Då eg tok skjermbiletet, hadde eg 220 + 3 ulesne artiklar. Som vi ser på biletet, er bokmerka mine til dels – men ikkje fullstendig – sorterte i mapper.

Det vi kan kalle 1. nivå, er sjølve bokmerkelina, som i seg sjølv er ei mappe (det ser du om du ser etter i bokmerkemenyen). Alt innhald som ligg direkte på bokmerkelina, er på 2. nivå. Der på 2. nivå ligg det eitt RSS-bokmerke i min Safari, det heiter «feed», og har 3 ulesne artiklar på biletet. Her på 2. nivå ligg også mappa «Nyhende» med 220 ulesne artiklar. Inne i den mappa har vi både lenkjer (den eine har 1 ulesen artikkel) og nye mapper. La oss kalle dette 3. nivå. Og den eine mappa på 3. nivå inneheld mapper på 4. nivå, desse mappene har namn etter årstal, og inni der finst fleire bokmerke igjen.

Det er heilt i orden å behalde denne strukturen i opml-fila, og vanlege RSS-lesarar taklar det. Heilt mot slutten av skriptet kan ein velje korleis ein vil gjere dette, om ein vil behalde heile mappestrukturen eller ikkje. Som standard er det stilt inn til ikkje å behalde heile strukturen, dette til ære for Google Reader.

For Google Reader liker altså ikkje mapper inne i mapper. Så sjølv om bokmerka overlever, må skriptet gjere noko med mappestrukturen som dei ligg i. Skriptet tek då vare berre på mappenamna på nivå 3. Dette tyder at når opml-fila vert importert i Google Reader, så er alt innhaldet frå mappene «2006», «2008», «2009», «2010» og «2011» samla i den mappa som desse årstala var grupperte under i Safari, men sjølve årstalssorteringa er borte. Bokmerka som ligg direkte på bokmerkelina (altså «feed») og bokmerke som ligg rett under «Nyhende», vil lande utanfor mappestrukturen i Google Reader.

Men skriptet kan altså også redigerast slik at fullstendig mappestruktur vert teken vare på. Det er berre å la vere å køyre tekststrengene gjennom «mappeslettingsubrutine». For å slette mapper på andre måtar er det elles denne subrutinen som må redigerast.

Og her er skriptet

(This is the Norwegian version. See below for the English version.)

#!/bin/sh
# Jardar Eggesbø Abrahamsen 19.8.2011, 15.10.2011, 1.3.2012
# https://jardar.wordpress.com/2012/03/10/fra-safari-til-google-reader/
# Skriptet tek føre seg av bokmerkeeksport frå Safari 5.1,
# og plukkar ut rss-lenkjene frå bokmerkelina og undermappene, ikkje 
# frå andre stader, og lagar ei opml-fil.
#
# LISENS
# Du har lov til å modifisere skriptet. Du har lov til å distribuere 
# modifikasjonen din, så sant han inneheld informasjon om kven som laga 
# det opphavlege skriptet, og så sant du ikkje krev betalt for det. Om 
# du ynskjer å distribuere skriptet eller ein modifisert versjon av det 
# under andre vilkår, eller inkorporere det i andre produkt, må du be 
# meg om løyve.
# Kontakt: abjaeg krullalfa gmail punktum com (eg les ikkje denne adressa kvar dag)

if [ "$1" = "" ] ; then
  echo
  echo "   safariopml filnamn.html"
  echo "   Det vil verte laga ei fil som heiter filnamn.opml"
  echo
  exit
fi

filnamn="$1"
nytt_filnamn=`echo "$filnamn" | sed 's/\.html$/.opml/'`

# Sile bort andre linkar enn feed-URL-ar, og ta vare på overliggjande mapper,
# fjerne hermeteikn frå mappenamn, skifte ut mappenamna med opml-taggar.
bokmerka=`cat "$filnamn" \
| grep -v 'HREF="[^f][^e][^e][^d]' \
| sed 's/<DT>//' \
| awk '/<H3 FOLDED>/ { gsub ("\"", "") ; print } ; !/<H3 FOLDED>/ { print }' \
| grep -e '^	*<H3 FOLDED' -e '^	*<A HREF' -e '</DL><p>' \
| sed 's/<H3 FOLDED>/<outline text="/
       s/<\/H3>/">/
       s/<\/DL><p>/<\/outline>/

# sed: gjere URL og linknamn om til to felt med TAB mellom
# awk: fjerne eventuelle hermeteikn i linknamna (Google Reader liker dei ikkje)
# sed: få på plass resten av taggane
       s/<A HREF="[^>]*>/&	/
       s/">	/	/
       s/<A HREF="//' \
| awk '/	feed:/ { gsub ("\"", "") ; print } ; !/	feed:/ { print }' \
| sed 's/	feed:/	<outline type="rss" text="" xmlUrl="feed:/
       s/<outline type="rss"[^	]*/&" title="/
       s/title="	/title="/
       s/<\/A>$/" \/>/'`

# ta vare berre på bokmerkeline-delen av bokmerka
hit=`echo "$bokmerka" \
| grep -n . \
| grep "^[0-9]*:	<outline" \
| head -2 | tail -1 \
| sed 's/:.*//'`
hit=$(($hit-1))

bokmerka=`echo "$bokmerka" | head -"$hit"`

# Fjerne tome mapper:
# Opnar med å slå saman liner.
# Så kjem sjølve fjerninga, og denne kjem så lenge der er noko å fjerne.
# Fjerninga må skje rekursivt pga mapper i mapper.

bokmerka=`echo "$bokmerka" \
| tr -d '\n'`
testdingseboms=`echo "$bokmerka" | grep "	*<outline text=\"[^\"][^>]*>	*<\/outline>"`
while [ "$testdingseboms" != "" ] ; do
  bokmerka=`echo "$bokmerka" \
            | sed 's/	*<outline text=\"[^\"][^>]*>	*<\/outline>//g'`
  testdingseboms=`echo "$bokmerka" | grep "	*<outline text=\"[^\"][^>]*>	*<\/outline>"`
done
# Det som vert fjerna, er <outline text="mappenamn"> og </outline>.
# Sjølve lenkjene er <outline type="rss"...

# Vi deler opp til liner igjen etter avslutta tagg, og fiksar &:
bokmerka=`echo "$bokmerka" \
| tr '>' '\n' \
| grep -v '^$' \
| sed 's/$/>/
       s/&/\&amp;/g'`

#####
# Google Reader taklar ikkje mappe i mappe.
# Denne subrutinen må køyrast dersom opml-fila skal inn i Google Reader.
#####
mappeslettingsubrutine()
{
# Slette mappeetikett på 1. nivå (1 TAB, "Bokmerkelinje") og på 2. nivå 
# (2 TAB, menyar/mapper i bokmerkelina).
# Merk at på dette stadiet er det berre mapper som har sekvensen "<outline text"
# Og berre mapper har ein eigen avsluttande tagg.
sed -E 's/^		?<outline text.*//
        s/^		?<\/outline>//

# slette mappeetikettar på 4. nivå og oppover (4 TAB og meir), tek 
# altså vare berre på hovudmappene i menyane
       s/^					*<outline text.*//
       s/^					*<\/outline>//' \
| grep -v "^$"
}

sistefiks()
{
# Ein siste fiks som gjer title- og text-attributtane identiske,
# slik det er i opml-eksportane frå Google Reader,
# og fordi eg las det her: http://www.therssweblog.com/?guid=20051003145153
sed 's/text="" //
     s/text="/title="/
     s/title="[^"]*"/& text="&"/
     s/"title=//
     s/""/"/'
}

{
cat << EOF
<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
	<head>
		<title>Safari OPML Export</title>
	</head>
	<body>
EOF

# For Google Reader, slett dei fleste mappenivåa:
echo "$bokmerka" | mappeslettingsubrutine | sistefiks

# Alternativt: ta vare på alle mappenivåa:
# echo "$bokmerka" | sistefiks

cat << EOF
	</body>
</opml>
EOF
} > "$nytt_filnamn"
  1. Eksporter bokmerka frå Safari (Arkiv > Eksporter bokmerker…), slik at du har fila «Safari-bokmerker.html».
  2. Kopier skriptet frå boksen over, lim det inn i eit tekstdokument som du lagrar som rein tekst og med filnamnet safariopml der du vil, typisk i ~/bin om det finst.
  3. I Terminal: chmod +x safariopml
  4. Rediger skriptet dersom det trengst. Som standard fjernar det mesteparten av mappestrukturen til ære for Google Reader, som nemnt over, men dette kan ein endre. Sjå kommentarar mot slutten av skriptet og ved «mappeslettingsubrutine».
  5. Køyr det slik: safariopml Safari-bokmerker.html
  6. No har du ei fil «Safari-bokmerker.opml» som kan importerast i ein RSS-lesar.

Eg reknar med at dei som har lese så langt som dette, også veit korleis dei skal chmod-e (punkt 3) og forhalde seg til skriptet elles, t.d. modifisere det etter eigne behov, så eg skriv ikkje noka meir utførleg rettleiing. Ekte datafolk vil same kva sjå at dette er eit amatørskript frå ein som har lært slikt på eiga hand, og som også har arbeidt med det i fleire omgangar.

Summary in English

  1. In Safari, export the bookmarks (File > Export Bookmarks…) to the file “Safari Bookmarks.html”.
  2. Copy the script from the box below, paste it in a text document that you save as plain text and with the name safariopml wherever you want, typically in ~/bin if it exists.
  3. In Terminal: chmod +x safariopml
  4. Edit the script as you need. By default it will remove the folder structure apart from any folders at the top level inside a folder that is found in the Bookmarks Bar. For reference, this means that although the RSS feeds are kept, the folders «2006», «2008» etc. in the screendump above will be removed, and all their contents will be found in a flat structure in the folder where all those subfolders were previously grouped. This is the default behaviour because Google Reader does not permit nested folders. The behaviour can be altered to keep the full folder structure, see comments near the bottom of the script and at the «folderdeletionsubroutine». Edit that subroutine to delete folders in other ways than described here.
  5. Run the script like this: safariopml Safari\ Bookmarks.html
  6. You now have a file “Safari Bookmarks.opml” that can be imported into an RSS reader.

The script has been tested with exports from Safari 5.1 for Mac. It extracts only RSS feeds found in the Bookmarks Bar and any subfolders of it. I’m just an amateur, so don’t expect to find a very sophisticated piece of code.

#!/bin/sh
# Jardar Eggesbø Abrahamsen 2011-08-19, 2011-10-15, 2012-03-01
# https://jardar.wordpress.com/2012/03/10/fra-safari-til-google-reader/
# The script uses a bookmarks file from Safari 5.1, extracts the rss 
# feeds from the Bookmarks Bar and its subfolders, and makes an opml file.
#
# LICENSE
# You are allowed to modify the script. You are allowed to distribute 
# your modification, provided that the modified version contains 
# information about the original author, and provided that you do not 
# make charges for it. If you wish to distribute the script or a 
# modified version of it under other conditions, or incorporate it into 
# other products, you must ask permission from the original author.
# Contact: abjaeg at gmail dot com (I don't read this address every day)

if [ "$1" = "" ] ; then
  echo
  echo "   safariopml filename.html"
  echo "   A file called filname.opml will be created."
  echo
  exit
fi

filename="$1"
new_filename=`echo "$filename" | sed 's/\.html$/.opml/'`

# Remove any other URLs than RSS feeds, keep the folder structure,
# remove quotes from foldernames, turn folder names into opml tags
bookmarks=`cat "$filename" \
| grep -v 'HREF="[^f][^e][^e][^d]' \
| sed 's/<DT>//' \
| awk '/<H3 FOLDED>/ { gsub ("\"", "") ; print } ; !/<H3 FOLDED>/ { print }' \
| grep -e '^	*<H3 FOLDED' -e '^	*<A HREF' -e '</DL><p>' \
| sed 's/<H3 FOLDED>/<outline text="/
       s/<\/H3>/">/
       s/<\/DL><p>/<\/outline>/

# sed: convert URL and linkname to 2 fields separated by TAB
# awk: remove quotes from linknames
# sed: the rest of the tags
       s/<A HREF="[^>]*>/&	/
       s/">	/	/
       s/<A HREF="//' \
| awk '/	feed:/ { gsub ("\"", "") ; print } ; !/	feed:/ { print }' \
| sed 's/	feed:/	<outline type="rss" text="" xmlUrl="feed:/
       s/<outline type="rss"[^	]*/&" title="/
       s/title="	/title="/
       s/<\/A>$/" \/>/'`

# keep only bookmarks that are found in the bookmarks bar
hitherto=`echo "$bookmarks" \
| grep -n . \
| grep "^[0-9]*:	<outline" \
| head -2 | tail -1 \
| sed 's/:.*//'`
hitherto=$(($hitherto-1))

bookmarks=`echo "$bookmarks" | head -"$hitherto"`

# Remove empty folders:
# 1) Merge lines.
# 2) Remove folders as long as there is something to remove.
#    The removal is recursive due to nested folders.

bookmarks=`echo "$bookmarks" \
| tr -d '\n'`
testthingy=`echo "$bookmarks" | grep "	*<outline text=\"[^\"][^>]*>	*<\/outline>"`
while [ "$testthingy" != "" ] ; do
  bookmarks=`echo "$bookmarks" \
            | sed 's/	*<outline text=\"[^\"][^>]*>	*<\/outline>//g'`
  testthingy=`echo "$bookmarks" | grep "	*<outline text=\"[^\"][^>]*>	*<\/outline>"`
done
# What is removed is <outline text="foldername"> and </outline>.
# The links themselves are <outline type="rss"...

# Reinsert newlines right after closed tags, and fix &:
bookmarks=`echo "$bookmarks" \
| tr '>' '\n' \
| grep -v '^$' \
| sed 's/$/>/
       s/&/\&amp;/g'`

#####
# Google Reader does not like nested folders.
# This subroutine must be run if the opml file is meant for Google Reader.
#####
folderdeletionsubroutine()
{
# Remove folder from level 1 (1 TAB, "Bookmarks bar") and level 2 (2 
# TAB, folders in the bookmarks bar).
# Note that at this stage the sequence "<outline text" uniquely identifies folders.
# And only folders have a separate closing tag.
sed -E 's/^		?<outline text.*//
        s/^		?<\/outline>//

# Remove folders from level 4+ (4+ TAB). In other words, keep only the names
# of the folders that are on the top level inside any folder placed in
# the bookmarks bar.
       s/^					*<outline text.*//
       s/^					*<\/outline>//' \
| grep -v "^$"
}

lastfixsubroutine()
{
# A last fix so the title and text attributes are identical,
# just like in the opml exports from Google Reader,
# and because I read it here: http://www.therssweblog.com/?guid=20051003145153
sed 's/text="" //
     s/text="/title="/
     s/title="[^"]*"/& text="&"/
     s/"title=//
     s/""/"/'
}

{
cat << EOF
<?xml version="1.0" encoding="UTF-8"?>
<opml version="1.0">
	<head>
		<title>Safari OPML Export</title>
	</head>
	<body>
EOF

# For Google Reader, delete most folder levels:
echo "$bookmarks" | folderdeletionsubroutine | lastfixsubroutine

# Alternatively, keep all folder levels:
# echo "$bookmarks" | lastfixsubroutine

cat << EOF
	</body>
</opml>
EOF
} > "$new_filename"

Read Full Post »