diff --git a/README.md b/README.md
index 4e505315b8f0e494fadf2df316349f072b875ef0..cc5b3aa40b9a5c27555a87f4b3f945fc210baf34 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,7 @@ WordPress plugin.
 ## Supported Sources
 
 - [Ecwid](https://support.ecwid.com/hc/en-us/articles/207099979-Import-Export)
+- [DPSounds](https://dpsounds.com) custom CSV format
 
 ## Usage
 `wooify.py adapter input_file`
diff --git a/wooify/adapters/adapter.py b/wooify/adapters/adapter.py
index b5c44a7cc8f57a2a7136ba66ddfc747bd49d2d0d..fab88d2a354ae39cca85b1739f90a4be86027b0d 100644
--- a/wooify/adapters/adapter.py
+++ b/wooify/adapters/adapter.py
@@ -27,6 +27,8 @@ class Adapter(object):
 
     def _clean_html(self, html_string):
         """Remove all attributes from HTML string."""
+        if not html_string:
+            return ''
         cleaner = lxml.html.clean.Cleaner(
             allow_tags=ALLOWED_HTML_TAGS, remove_unknown_tags=False,
             page_structure=False, safe_attrs_only=True, safe_attrs=frozenset())
diff --git a/wooify/adapters/dpsounds.py b/wooify/adapters/dpsounds.py
new file mode 100644
index 0000000000000000000000000000000000000000..62cab61a91873f598f7fe71371dbe50ddb9a2cb0
--- /dev/null
+++ b/wooify/adapters/dpsounds.py
@@ -0,0 +1,73 @@
+import csv
+import json
+import hashlib
+from .adapter import Adapter as BaseAdapter
+from ..constants import (ALLOWED_HTML_TAGS, HTML_FIELDS,
+                         WOO_IMP_EXP_PRODUCT_FIELDS)
+
+DP_TRACK_URL_BASE = 'https://ant.sr/dpsounds-audio'
+DP_TRACK_CATEGORIES = json.dumps([{'name': 'Music', 'slug': 'music'}])
+DP_TRACK_ATTRIBUTES = ['Time', 'Origin']
+DP_TRACK_PRICE = 1
+
+
+class DpsoundsAdapter(BaseAdapter):
+    """Input handler for spreadsheets received from my dad
+    for dpsounds.com.
+    Headers:
+     "Source Part","Source Track","Track",
+     "Title","Time","Origin","Tags",
+     "Alternative Takes","Compilation".
+    """
+
+    def parse(self, filename):
+        """Parse a CSV file for DPSounds.com."""
+        def parse_row(r):
+            """Parse a row of Dad's CSV file and rearrange the fields for
+            WooCommerce."""
+            name = "Track {}".format(r['Track'])
+            if r['Title']:
+                name += " - {}".format(r['Title'])
+            tags = ','.join([t.strip() for t in r['Tags'].split(',')])
+            file_url = "{url_base}/{part}-{track:02d}.mp3".format(
+                url_base=DP_TRACK_URL_BASE,
+                part=r['Source Part'],
+                track=int(r['Source Track']))
+            filehash = hashlib.md5(file_url.encode('utf-8')).hexdigest()
+            files = json.dumps({
+                filehash: {'name': name, 'file': file_url}})
+            # TODO: alternative takes
+            # TODO: compilation (album)
+            # TODO: Description text to include attributes.
+            attributes = [{
+                    'name': attr,
+                    'value': r[attr],
+                    'position': idx,
+                    'is_visible': '1',
+                    'is_variation': '0',
+                    'is_taxonomy': '0'
+                } for idx, attr in enumerate(DP_TRACK_ATTRIBUTES)]
+            product = dict(WOO_IMP_EXP_PRODUCT_FIELDS)
+            product.update({
+                "Product Name": name,
+                "Tags": tags,
+                "Categories": DP_TRACK_CATEGORIES,
+                "Downloadable": 'yes',
+                "Virtual": 'yes',
+                "Sold Individually": 'yes',
+                "Downloadable Files": files,
+                "Download Type": "music",
+                "Price": DP_TRACK_PRICE,
+                "Regular Price": DP_TRACK_PRICE,
+                "Attributes": json.dumps(attributes)
+            })
+            return product
+
+        with open(filename) as csv_in:
+            csv_reader = csv.DictReader(csv_in)
+            raw_category_names = []
+            for row in csv_reader:
+                product = parse_row(row)
+                self.products.append(product)
+
+adapter_cls = DpsoundsAdapter
diff --git a/wooify/adapters/ecwid.py b/wooify/adapters/ecwid.py
index 06d1de239f07e08d2b3429c7c14767b2ba2e496c..411bf79e42ec2fb55930da9dd0df810644b1146d 100644
--- a/wooify/adapters/ecwid.py
+++ b/wooify/adapters/ecwid.py
@@ -57,10 +57,10 @@ class EcwidAdapter(BaseAdapter):
             categories = self._expand_categories(raw_category_names)
             for product in self.products:
                 if 'Categories' in product and product['Categories']:
-                    product['Categories'] = [{
+                    product['Categories'] = json.dumps([{
                         'name': categories[c]['Name'],
                         'slug': categories[c]['Slug']}
-                        for c in product['Categories']]
+                        for c in product['Categories']])
             self.categories = categories.values()
 
     def _expand_categories(self, raw_category_names):