<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Michael Jay Lissner</title><link href="https://michaeljaylissner.com/" rel="alternate"></link><link href="https://michaeljaylissner.com/feeds/tag/sqlite3" rel="self"></link><id>https://michaeljaylissner.com/</id><updated>2009-10-14T00:30:12-07:00</updated><entry><title>Script to Clean Up F-Spot Database</title><link href="https://michaeljaylissner.com/posts/2009/10/14/script-to-cleanup-fspot-database/" rel="alternate"></link><updated>2009-10-14T00:30:12-07:00</updated><author><name>Mike Lissner</name></author><id>tag:michaeljaylissner.com,2009-10-14:posts/2009/10/14/script-to-cleanup-fspot-database/</id><summary type="html">&lt;p&gt;One of the more popular photo management applications for Linux is f-spot, 
but unfortunately it has a rather glaring bug. It uses a sqlite3 database 
internally to track which pictures you&amp;#8217;ve imported into it, 
what tags they have, etc. However, if you delete, move or rename any of the
files that f-spot is tracking, the next time you browse to that photo within f-spot, it will crash the program. It&amp;#8217;s annoying, and there&amp;#8217;s no particularly easy way to deal with it&amp;#8230;until&amp;nbsp;now.&lt;/p&gt;
&lt;p&gt;The script below simply iterates through all of the photos 
that are in f-spot&amp;#8217;s database, and checks to see if those photos exist on 
your hard drive. If you run it in demo-mode, it will show you which files 
look problematic, and if you run it in normal mode, 
it will delete those database entries so that your database is cleaned up 
(but not before backing up your database, just in&amp;nbsp;case).&lt;/p&gt;
&lt;p&gt;In my very limited testing, it works very well, any additional feedback or 
bug reporting is more than&amp;nbsp;welcome. &lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span class="c"&gt;#!/bin/bash&lt;/span&gt;

&lt;span class="c"&gt;# A script to find missing files in the f-spot database, and then delete them.&lt;/span&gt;
&lt;span class="c"&gt;# At present these files crash f-spot. It&amp;#39;s frustrating as all hell.&lt;/span&gt;

&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Welcome to the f-spot database cleaner. All the usual disclaimers apply, as you might imagine.&amp;quot;&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;What would you like to do: &amp;quot;&lt;/span&gt; 
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;  1) Run in demo-mode &amp;quot;&lt;/span&gt; 
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;  2) Clean up your f-spot database&amp;quot;&lt;/span&gt; 
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;  3) Quit&amp;quot;&lt;/span&gt; 
&lt;span class="nb"&gt;read&lt;/span&gt; -p &lt;span class="s2"&gt;&amp;quot;Your choice: &amp;quot;&lt;/span&gt; choice

&lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="nv"&gt;$choice&lt;/span&gt; in 
    1&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;demomode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;;;
    2&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;demomode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;;;
    3&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="nb"&gt;exit &lt;/span&gt;0;;
&lt;span class="k"&gt;esac&lt;/span&gt;

&lt;span class="c"&gt;# With that beginning stuff out of the way, let us do some functions&lt;/span&gt;
&lt;span class="c"&gt;# First, a function to gather the database contents and to print out the ones that are orphans&lt;/span&gt;

&lt;span class="k"&gt;function &lt;/span&gt;findAndFixOrphans &lt;span class="o"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;# find our db, and set a var. Checking for XDG path first, since it&amp;#39;s the more recent location of the db&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="nv"&gt;$XDG_CONFIG_DIR&lt;/span&gt;/f-spot/photos.db &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="c"&gt;#checks if the $XDG_CONFIG_DIR variable is in use&lt;/span&gt;
    &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;DBPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$XDG_CONFIG_DIR&lt;/span&gt;/f-spot/photos.db
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.config/f-spot/photos.db &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="c"&gt;#uses the default $XDG location, if that&amp;#39;s being used.&lt;/span&gt;
    &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;DBPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.config/f-spot/photos.db
    &lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; -f &lt;span class="nv"&gt;$HOME&lt;/span&gt;/.gnome2/f-spot/photos.db &lt;span class="o"&gt;]&lt;/span&gt; &lt;span class="c"&gt;#uses the old location of the DB, if the former aren&amp;#39;t in use.&lt;/span&gt;
    &lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;        &lt;/span&gt;&lt;span class="nv"&gt;DBPATH&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;/.gnome2/f-spot/photos.db
    &lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="k"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Error: Could not find database. Damn.&amp;quot;&lt;/span&gt; 
        &lt;span class="nb"&gt;exit &lt;/span&gt;1
    &lt;span class="k"&gt;fi&lt;/span&gt;

    &lt;span class="c"&gt;# Select the filenames, and put them in a variable.&lt;/span&gt;
    &lt;span class="nv"&gt;filenames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;sqlite3 &lt;span class="nv"&gt;$DBPATH&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;SELECT URI FROM PHOTOS&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;filenames_versions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;sqlite3 &lt;span class="nv"&gt;$DBPATH&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;SELECT URI FROM PHOTO_VERSIONS&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;# Chomp off the first instance of file://, and replace the rest with newlines.&lt;/span&gt;
    &lt;span class="nv"&gt;filenames&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$filenames&lt;/span&gt; | sed &lt;span class="s1"&gt;&amp;#39;s/file:\/\///&amp;#39;&lt;/span&gt; | sed &lt;span class="s1"&gt;&amp;#39;s/file:\/\//\n/g&amp;#39;&lt;/span&gt;  &lt;span class="k"&gt;)&lt;/span&gt;
    &lt;span class="nv"&gt;filenames_versions&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$filenames_versions&lt;/span&gt; | sed &lt;span class="s1"&gt;&amp;#39;s/file:\/\///&amp;#39;&lt;/span&gt; | sed &lt;span class="s1"&gt;&amp;#39;s/file:\/\//\n/g&amp;#39;&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$demomode&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
    &lt;span class="k"&gt;then            &lt;/span&gt;
&lt;span class="k"&gt;        while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r line
        &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="c"&gt;# Decode the filename&lt;/span&gt;
            &lt;span class="nv"&gt;decodedLine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;${line//\%/\\x}&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; ! -f  &lt;span class="s2"&gt;&amp;quot;$decodedLine&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt; 
            &lt;span class="k"&gt;then&lt;/span&gt;
                &lt;span class="c"&gt;# If the file doesn&amp;#39;t exist, we output the filename, if in demomode, or we fix it if we are not in demomode.&lt;/span&gt;
                &lt;span class="nb"&gt;echo&lt;/span&gt;  &lt;span class="s2"&gt;&amp;quot;Errant record found in the photos table: $decodedLine&amp;quot;&lt;/span&gt;
            &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;        done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$filenames&amp;quot;&lt;/span&gt;

        &lt;span class="c"&gt;# We do the same for the photo_versions table&lt;/span&gt;
        &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r line
        &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="c"&gt;# Decode filename&lt;/span&gt;
            &lt;span class="nv"&gt;decodedLine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;${line//\%/\\x}&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; ! -f &lt;span class="s2"&gt;&amp;quot;$decodedLine&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;then&lt;/span&gt;
                &lt;span class="c"&gt;# If the file doesn&amp;#39;t exist, we output the filename&lt;/span&gt;
                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Errant record found in the photo_versions table: $decodedLine&amp;quot;&lt;/span&gt;
            &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;        done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$filenames_versions&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;else&lt;/span&gt;
        &lt;span class="c"&gt;# We backup the database, and make the correction&lt;/span&gt;
        cp &lt;span class="nv"&gt;$DBPATH&lt;/span&gt; &lt;span class="nv"&gt;$DBPATH&lt;/span&gt;.&lt;span class="sb"&gt;`&lt;/span&gt;date -I&lt;span class="sb"&gt;`&lt;/span&gt;.bak
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="nv"&gt;$?&lt;/span&gt; -eq 0 &lt;span class="o"&gt;]&lt;/span&gt;
        &lt;span class="k"&gt;then&lt;/span&gt;
            &lt;span class="c"&gt;#The backup worked, tell the user.&lt;/span&gt;
            &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Your database has been backed up to $DBPATH.`date -I`.bak&amp;quot;&lt;/span&gt;
        &lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="k"&gt;            &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Error backing up your database.&amp;quot;&lt;/span&gt;
            &lt;span class="nb"&gt;exit &lt;/span&gt;3
        &lt;span class="k"&gt;fi&lt;/span&gt;

        &lt;span class="c"&gt;# First we do the photos table&lt;/span&gt;
        &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r line
        &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="c"&gt;# Decode the filename&lt;/span&gt;
            &lt;span class="nv"&gt;decodedLine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;${line//\%/\\x}&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; ! -f &lt;span class="s2"&gt;&amp;quot;$decodedLine&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;then&lt;/span&gt;
                &lt;span class="c"&gt;# Do some sql here.&lt;/span&gt;
                &lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file://${line}&amp;quot;&lt;/span&gt;
                &lt;span class="nb"&gt;echo&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;Deleting URI $line from the database table photos...&amp;quot;&lt;/span&gt;
                sqlite3 &lt;span class="nv"&gt;$DBPATH&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;DELETE FROM PHOTOS WHERE uri = &amp;#39;$foo&amp;#39;&amp;quot;&lt;/span&gt;
                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;done.&amp;quot;&lt;/span&gt;
            &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;        done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$filenames&amp;quot;&lt;/span&gt;

        &lt;span class="c"&gt;# Then we do the photo_versions table&lt;/span&gt;
        &lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="nb"&gt;read&lt;/span&gt; -r line
        &lt;span class="k"&gt;do&lt;/span&gt;
            &lt;span class="c"&gt;# Decode the filename&lt;/span&gt;
            &lt;span class="nv"&gt;decodedLine&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; -e &lt;span class="s2"&gt;&amp;quot;${line//\%/\\x}&amp;quot;&lt;/span&gt;&lt;span class="k"&gt;)&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; ! -f &lt;span class="s2"&gt;&amp;quot;$decodedLine&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
            &lt;span class="k"&gt;then&lt;/span&gt;
                &lt;span class="c"&gt;#Do some sql stuff&lt;/span&gt;
                &lt;span class="nv"&gt;foo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;file://${line}&amp;quot;&lt;/span&gt;
                &lt;span class="nb"&gt;echo&lt;/span&gt; -n &lt;span class="s2"&gt;&amp;quot;Deleting URI $line from the database table photo_versions...&amp;quot;&lt;/span&gt;
                sqlite3 &lt;span class="nv"&gt;$DBPATH&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;DELETE FROM PHOTO_VERSIONS WHERE uri = &amp;#39;$foo&amp;#39;&amp;quot;&lt;/span&gt;
                &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;done.&amp;quot;&lt;/span&gt;
            &lt;span class="k"&gt;fi&lt;/span&gt;
&lt;span class="k"&gt;        done&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$filenames_versions&amp;quot;&lt;/span&gt;

    &lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$demomode&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;true&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Great. Proceeding in demomode.&amp;quot;&lt;/span&gt;

    findAndFixOrphans

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Demomode successfully finished. Exiting.&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;0;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;$demomode&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;false&amp;quot;&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Great. Cleaning up your database.&amp;quot;&lt;/span&gt;

    findAndFixOrphans

    &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Database cleaned successfully.&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;0;
&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="k"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;quot;Something strange happened. See the script for details. Exiting.&amp;quot;&lt;/span&gt;
    &lt;span class="nb"&gt;exit &lt;/span&gt;2;
&lt;span class="k"&gt;fi&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;</summary><category term="sqlite3"></category><category term="f-spot"></category><category term="database"></category><category term="bash"></category></entry></feed>