diff --git a/CMakeLists.txt b/CMakeLists.txt
index 38cd3ffe79c323de24a832129cee5ff952786661..b6e38ba02f942a891a338dd7a3b40a5455c195c8 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -9,6 +9,6 @@ find_package(Wt REQUIRED)
 find_package(Groove REQUIRED)
 
 add_executable(arbitrateor src/main.cpp src/WebInterface.cpp src/GroovePlayer.cpp src/ui/LoginInterface.cpp src/ui/PlayerInterface.cpp)
-target_link_libraries(arbitrateor ${Wt_LIBRARIES} ${GROOVE_LIBRARY} pthread stdc++fs) #TODO get threading links based on platform. Remove gcc experimental fs when official c++17 exists.
+target_link_libraries(arbitrateor ${Wt_LIBRARIES} ${GROOVE_LIBRARY} ${GROOVE_FINGERPRINT_LIBRARY} pthread stdc++fs) #TODO get threading links based on platform. Remove gcc experimental fs when official c++17 exists.
 
 install(TARGETS arbitrateor RUNTIME DESTINATION bin)
diff --git a/cmake/FindGroove.cmake b/cmake/FindGroove.cmake
index 144c77e209d10062bd691806c1e8682a3fc75594..21f15c337314ecc646018cd63d207448b6129afd 100644
--- a/cmake/FindGroove.cmake
+++ b/cmake/FindGroove.cmake
@@ -5,12 +5,14 @@
 # GROOVE_FOUND
 # GROOVE_INCLUDE_DIR
 # GROOVE_LIBRARY
+# GROOVE_FINGERPRINT_LIBRARY
 
 find_path(GROOVE_INCLUDE_DIR NAMES groove/groove.h)
 
 find_library(GROOVE_LIBRARY NAMES groove)
+find_library(GROOVE_FINGERPRINT_LIBRARY NAMES groovefingerprinter)
 
 include(FindPackageHandleStandardArgs)
-find_package_handle_standard_args(GROOVE DEFAULT_MSG GROOVE_LIBRARY GROOVE_INCLUDE_DIR)
+find_package_handle_standard_args(GROOVE DEFAULT_MSG GROOVE_LIBRARY GROOVE_FINGERPRINT_LIBRARY GROOVE_INCLUDE_DIR)
 
-mark_as_advanced(GROOVE_INCLUDE_DIR GROOVE_LIBRARY)
+mark_as_advanced(GROOVE_INCLUDE_DIR GROOVE_LIBRARY GROOVE_FINGERPRINT_LIBRARY)
diff --git a/src/GroovePlayer.cpp b/src/GroovePlayer.cpp
index 5783cac9e7e448b23686534008edbff3dbf6d527..6cef18d2ecfd40924b3b68968ac3a5eab49bdea9 100644
--- a/src/GroovePlayer.cpp
+++ b/src/GroovePlayer.cpp
@@ -25,6 +25,8 @@
 #include "WebInterface.h"
 #include <locale>
 #include <Wt/WLogger>
+#include <Wt/Dbo/Transaction>
+#include <groovefingerprinter/fingerprinter.h>
 
 std::filesystem::path GroovePlayer::musicScanDir = "";
 
@@ -42,6 +44,8 @@ GroovePlayer::GroovePlayer(std::string dbFile) : sqliteConnection(dbFile)
         Wt::log("info") << "Using Existing DB.";
     }
     
+    groove_init();
+    
     grooveAudioScanner = new std::thread(grooveAudioScannerLoop);
     grooveEvents = new std::thread(grooveEventLoop);
 }
@@ -59,11 +63,85 @@ void GroovePlayer::grooveEventLoop()
 bool GroovePlayer::addFileToTrackDBIfTagged(std::filesystem::path file)
 {
     //Now check if tags exist and put into DB.
+    struct GrooveFile* gfile = groove_file_open(file.c_str());
+    struct GrooveTag* artist_tag = groove_file_metadata_get(gfile, "artist", nullptr, 0);
+    struct GrooveTag* album_tag = groove_file_metadata_get(gfile, "album", nullptr, 0);
+    struct GrooveTag* name_tag = groove_file_metadata_get(gfile, "title", nullptr, 0);
+    struct GrooveTag* genre_tag = groove_file_metadata_get(gfile, "genre", nullptr, 0);
+    if(artist_tag == nullptr || album_tag == nullptr || name_tag == nullptr || genre_tag == nullptr)
+    {
+        //Only accept song with all metadata for DB.
+        groove_file_close(gfile);
+        return false;
+    }
+    
+    //Take fingerprint and compare to DB.
+    struct GrooveFingerprinter* fingerprinter = groove_fingerprinter_create();
+    struct GrooveFingerprinterInfo info;
+    struct GroovePlaylist* playlist = groove_playlist_create();
+    groove_playlist_insert(playlist,gfile,1.0,1.0,nullptr);
+    groove_fingerprinter_attach(fingerprinter, playlist);
+    groove_fingerprinter_info_get(fingerprinter, &info, 1);
+    double trackLen = info.duration;
+    char* encodedFP;
+    groove_fingerprinter_encode(info.fingerprint,info.fingerprint_size,&encodedFP);
+    std::string fingerprint = std::string(encodedFP);
+    groove_fingerprinter_dealloc(encodedFP);
+    groove_fingerprinter_free_info(&info);
+    groove_fingerprinter_detach(fingerprinter);
+    groove_fingerprinter_destroy(fingerprinter);
+    groove_playlist_destroy(playlist);
+    
+    Wt::Dbo::Transaction transaction(getInstance()->sqlSession);
+    int existing = getInstance()->sqlSession.query<int>("select count(fingerprint) from tracks").where("fingerprint = ?").bind(fingerprint);
+    if(existing >0)
+    {
+        //This track has a duplicate already.
+        groove_file_close(gfile);
+        return false;
+    }
+    
+    //Add to DB.
+    AudioTrack* newTrack = new AudioTrack();
+    newTrack->trackName = groove_tag_value(name_tag);
+    newTrack->trackAlbumName = groove_tag_value(album_tag);
+    newTrack->trackArtistName = groove_tag_value(artist_tag);
+    newTrack->trackGenre = groove_tag_value(genre_tag);
+    newTrack->trackLengthSeconds = trackLen;
+    newTrack->trackFingerprint = fingerprint;
+    newTrack->trackPath = file.string();
+    getInstance()->sqlSession.add(newTrack);
+    groove_file_close(gfile);
+    return true;
 }
 
+void GroovePlayer::removeOrphanedTracks()
+{
+    Wt::Dbo::Transaction transaction(getInstance()->sqlSession);
+    Wt::Dbo::collection<Wt::Dbo::ptr<AudioTrack>> tracks = getInstance()->sqlSession.find<AudioTrack>();
+    for(Wt::Dbo::collection<Wt::Dbo::ptr<AudioTrack>>::const_iterator i = tracks.begin(); i != tracks.end(); ++i)
+    {
+        if(!std::filesystem::exists(std::filesystem::path((*i)->trackPath)))
+        {
+            Wt::Dbo::ptr<AudioTrack> item = getInstance()->sqlSession.find<AudioTrack>().where("fingerprint = ?").bind((*i)->trackFingerprint);
+            Wt::log("info") << (*i)->trackPath + " not found in filesystem. Removed from DB.";
+            item.remove();
+        }
+    }
+}
+
+
 
 void GroovePlayer::grooveAudioScannerLoop()
 {
+    if(!std::filesystem::exists(musicScanDir))
+    {
+        std::filesystem::create_directory(musicScanDir);
+        Wt::log("info") << "Directory "+std::filesystem::canonical(musicScanDir).string()+" didn't exist, so created.";
+    } else 
+    {
+        Wt::log("info") << "Directory "+std::filesystem::canonical(musicScanDir).string()+" exists.";
+    }
     for(std::filesystem::directory_entry p: std::filesystem::directory_iterator(musicScanDir))
     {
         std::string extensionLowered;
@@ -71,14 +149,20 @@ void GroovePlayer::grooveAudioScannerLoop()
         {
             extensionLowered.push_back(std::tolower(elem));
         }
-        if(extensionLowered == "mp3") //TODO:think about supporting more than mp3s.
+        if(extensionLowered == ".mp3") //TODO:think about supporting more than mp3s.
         {
             if(addFileToTrackDBIfTagged(p.path()))
             {
                 Wt::log("info") << p.path().string() << " was added to DB";
             }
         }
+        else
+        {
+            Wt::log("info") << p.path().string() + " was not an accepted audio file.";
+        }
     }
+    //Now check for tracks in DB without a file.
+    removeOrphanedTracks();
 }
 
 
diff --git a/src/GroovePlayer.h b/src/GroovePlayer.h
index 85493e53545f79959493ed9943b26d5447a71059..ac66b5f85bbdbf01c3d11d22c667ea334ff58a48 100644
--- a/src/GroovePlayer.h
+++ b/src/GroovePlayer.h
@@ -26,6 +26,7 @@
 #include <thread>
 #include "db/User.h"
 #include "db/AudioTrack.h"
+#include <groove/groove.h>
 #include <experimental/filesystem> //TODO:Change to non-gcc way when officially using c++17
 namespace std {
     namespace filesystem =  experimental::filesystem;
@@ -37,7 +38,7 @@ public:
     static std::filesystem::path musicScanDir;
     static GroovePlayer* getInstance() {
         static GroovePlayer instance("music.db");
-        musicScanDir = std::filesystem::current_path().string()+"/music";
+        musicScanDir = std::filesystem::path("music");
         return &instance;
     };
     GroovePlayer(GroovePlayer const&) = delete;
@@ -54,6 +55,7 @@ private:
     std::thread* grooveAudioScanner;
     static void grooveAudioScannerLoop();
     static bool addFileToTrackDBIfTagged(std::filesystem::path file);
+    static void removeOrphanedTracks();
     
 };
 
diff --git a/src/db/AudioTrack.h b/src/db/AudioTrack.h
index 8d4599022e21e9f7457e994274cae84248b8d083..4a10aad11d21bf1322c4a542a9449afd5f8c6446 100644
--- a/src/db/AudioTrack.h
+++ b/src/db/AudioTrack.h
@@ -29,6 +29,8 @@ public:
     std::string trackArtistName;
     std::string trackAlbumName;
     std::string trackGenre;
+    double trackLengthSeconds;
+    std::string trackFingerprint;
     std::string trackPath;
     
     template<class Action>
@@ -37,6 +39,8 @@ public:
         Wt::Dbo::field(a, trackName, "name");    
         Wt::Dbo::field(a, trackArtistName, "artist");
         Wt::Dbo::field(a, trackAlbumName, "album");
+        Wt::Dbo::field(a, trackLengthSeconds, "length");
+        Wt::Dbo::field(a, trackFingerprint, "fingerprint");
         Wt::Dbo::field(a, trackGenre, "genre");
         Wt::Dbo::field(a, trackPath, "path");
     }
diff --git a/src/db/UserAction.h b/src/db/UserAction.h
index e720e86bde09a51e6701dd10a86618a54bbbd09d..3ff381eac401b6521727f3c20f7b36f350988a98 100644
--- a/src/db/UserAction.h
+++ b/src/db/UserAction.h
@@ -39,9 +39,9 @@ public:
     template<class Action>
     void persist(Action& a)
     {
-        Wt::Dbo::belongsTo(a, user, "user");
+        Wt::Dbo::belongsTo(a, user, "user", Wt::Dbo::OnDeleteCascade);
         Wt::Dbo::field(a, action, "action");
-        Wt::Dbo::belongsTo(a, trackInvolved, "track");
+        Wt::Dbo::belongsTo(a, trackInvolved, "track", Wt::Dbo::OnDeleteCascade);
         Wt::Dbo::field(a, datetime, "datetime");
     }