diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6f84f36
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,6 @@
+# Audio files
+*.aax
+*.m4b
+
+# Config files
+settings.conf
\ No newline at end of file
diff --git a/audible-converter.sh b/audible-converter.sh
new file mode 100644
index 0000000..9e1bdec
--- /dev/null
+++ b/audible-converter.sh
@@ -0,0 +1,61 @@
+#!/usr/bin/env bash
+
+# getHash returns the hash of a given file.
+function getHash() {
+    echo $(xxd -p -l20 -s 653 ${1})
+}
+
+# getActivationBytes returns the bytes needed to decrypt a given hash. 
+function getActivationBytes() {
+    json=$(curl -A 'Christian Colglazier' https://aax.api.j-kit.me/api/v2/activation/${1})
+    echo $(echo $json | jq '.activationBytes' | tr -d '"')
+}
+
+# createConfig creates a config file.
+function createConfig() {
+    hash=$(getHash ${2})
+    bytes=$(getActivationBytes $hash)
+    echo "activationBytes=${bytes}" >> ${1}
+}
+
+# checkAudibleFile checks if a given file is valid and if not exits the program.
+function checkAudibleFile() {
+    if [ ! -f ${1} ]; then
+	echo "${1}" not found
+	exit 1
+    fi
+}
+
+function removeDRM() {
+    ffmpeg -activation_bytes ${2} -i ${1} -c copy "$(basename ${1} | cut -f 1 -d '.').m4b"
+}
+
+function getChapterJSON() {
+    echo $(ffprobe -i ${1} -print_format json -show_chapters -loglevel error -sexagesimal)
+}
+
+function getMetadataJSON() {
+    echo $(ffprobe -show_format -print_format json ${1} | jq '.format.tags')
+}
+
+function getTitle() {
+    echo $(echo ${1} | jq '.title')
+}
+
+settingsFile='./settings.conf'
+
+audibleFile=${1}
+checkAudibleFile $audibleFile
+
+# Check for config file
+if [ ! -f $settingsFile ]; then
+    echo 'No config file'
+    createConfig $settingsFile $audibleFile
+fi
+
+# Load settings
+. $settingsFile
+
+metadataJSON=$(getMetadataJSON $audibleFile)
+json=$(getMetadataJSON $audibleFile)
+removeDRM $audibleFile $activationBytes