diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..13566b8
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/django-elastic-transcoder.iml b/.idea/django-elastic-transcoder.iml
new file mode 100644
index 0000000..7a6134d
--- /dev/null
+++ b/.idea/django-elastic-transcoder.iml
@@ -0,0 +1,14 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="PYTHON_MODULE" version="4">
+  <component name="NewModuleRootManager">
+    <content url="file://$MODULE_DIR$">
+      <excludeFolder url="file://$MODULE_DIR$/.venv" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+  <component name="PyDocumentationSettings">
+    <option name="format" value="PLAIN" />
+    <option name="myDocStringFormat" value="Plain" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..90c711d
--- /dev/null
+++ b/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,268 @@
+<component name="InspectionProjectProfileManager">
+  <profile version="1.0">
+    <option name="myName" value="Project Default" />
+    <inspection_tool class="Eslint" enabled="true" level="WARNING" enabled_by_default="true" />
+    <inspection_tool class="PyPackageRequirementsInspection" enabled="true" level="WARNING" enabled_by_default="true">
+      <option name="ignoredPackages">
+        <value>
+          <list size="254">
+            <item index="0" class="java.lang.String" itemvalue="psycopg2" />
+            <item index="1" class="java.lang.String" itemvalue="geocoder" />
+            <item index="2" class="java.lang.String" itemvalue="ndg-httpsclient" />
+            <item index="3" class="java.lang.String" itemvalue="markupsafe" />
+            <item index="4" class="java.lang.String" itemvalue="python-magic" />
+            <item index="5" class="java.lang.String" itemvalue="pywebpush" />
+            <item index="6" class="java.lang.String" itemvalue="pycryptodomex" />
+            <item index="7" class="java.lang.String" itemvalue="lxml" />
+            <item index="8" class="java.lang.String" itemvalue="django-extra-fields" />
+            <item index="9" class="java.lang.String" itemvalue="jsonschema" />
+            <item index="10" class="java.lang.String" itemvalue="PyLTI1p3" />
+            <item index="11" class="java.lang.String" itemvalue="xlrd" />
+            <item index="12" class="java.lang.String" itemvalue="tenant-schemas-celery" />
+            <item index="13" class="java.lang.String" itemvalue="proglog" />
+            <item index="14" class="java.lang.String" itemvalue="asgiref" />
+            <item index="15" class="java.lang.String" itemvalue="typing-extensions" />
+            <item index="16" class="java.lang.String" itemvalue="vobject" />
+            <item index="17" class="java.lang.String" itemvalue="automat" />
+            <item index="18" class="java.lang.String" itemvalue="gunicorn" />
+            <item index="19" class="java.lang.String" itemvalue="click" />
+            <item index="20" class="java.lang.String" itemvalue="hiredis" />
+            <item index="21" class="java.lang.String" itemvalue="prettytable" />
+            <item index="22" class="java.lang.String" itemvalue="pyyaml" />
+            <item index="23" class="java.lang.String" itemvalue="backports-abc" />
+            <item index="24" class="java.lang.String" itemvalue="boto3" />
+            <item index="25" class="java.lang.String" itemvalue="aioredis" />
+            <item index="26" class="java.lang.String" itemvalue="imageio" />
+            <item index="27" class="java.lang.String" itemvalue="haikunator" />
+            <item index="28" class="java.lang.String" itemvalue="twilio" />
+            <item index="29" class="java.lang.String" itemvalue="ua-parser" />
+            <item index="30" class="java.lang.String" itemvalue="idna" />
+            <item index="31" class="java.lang.String" itemvalue="shellescape" />
+            <item index="32" class="java.lang.String" itemvalue="rsa" />
+            <item index="33" class="java.lang.String" itemvalue="django-tenant-schemas" />
+            <item index="34" class="java.lang.String" itemvalue="django-environ" />
+            <item index="35" class="java.lang.String" itemvalue="pycurl" />
+            <item index="36" class="java.lang.String" itemvalue="django-image-cropping" />
+            <item index="37" class="java.lang.String" itemvalue="python-crontab" />
+            <item index="38" class="java.lang.String" itemvalue="cffi" />
+            <item index="39" class="java.lang.String" itemvalue="django-storages" />
+            <item index="40" class="java.lang.String" itemvalue="numpy" />
+            <item index="41" class="java.lang.String" itemvalue="jdcal" />
+            <item index="42" class="java.lang.String" itemvalue="segno" />
+            <item index="43" class="java.lang.String" itemvalue="celery" />
+            <item index="44" class="java.lang.String" itemvalue="selenium" />
+            <item index="45" class="java.lang.String" itemvalue="wikipedia" />
+            <item index="46" class="java.lang.String" itemvalue="websockets" />
+            <item index="47" class="java.lang.String" itemvalue="django-webpack-loader" />
+            <item index="48" class="java.lang.String" itemvalue="cssselect2" />
+            <item index="49" class="java.lang.String" itemvalue="rcssmin" />
+            <item index="50" class="java.lang.String" itemvalue="enum-compat" />
+            <item index="51" class="java.lang.String" itemvalue="django-feature-policy" />
+            <item index="52" class="java.lang.String" itemvalue="et-xmlfile" />
+            <item index="53" class="java.lang.String" itemvalue="django-debug-toolbar" />
+            <item index="54" class="java.lang.String" itemvalue="dicttoxml" />
+            <item index="55" class="java.lang.String" itemvalue="importlib-resources" />
+            <item index="56" class="java.lang.String" itemvalue="autobahn" />
+            <item index="57" class="java.lang.String" itemvalue="django-internationalflavor" />
+            <item index="58" class="java.lang.String" itemvalue="babel" />
+            <item index="59" class="java.lang.String" itemvalue="itypes" />
+            <item index="60" class="java.lang.String" itemvalue="pytz" />
+            <item index="61" class="java.lang.String" itemvalue="pyjwt" />
+            <item index="62" class="java.lang.String" itemvalue="django-jsonview" />
+            <item index="63" class="java.lang.String" itemvalue="pyexcel-handsontable" />
+            <item index="64" class="java.lang.String" itemvalue="h11" />
+            <item index="65" class="java.lang.String" itemvalue="tinycss2" />
+            <item index="66" class="java.lang.String" itemvalue="django-extensions" />
+            <item index="67" class="java.lang.String" itemvalue="markuppy" />
+            <item index="68" class="java.lang.String" itemvalue="docopt" />
+            <item index="69" class="java.lang.String" itemvalue="django-excel" />
+            <item index="70" class="java.lang.String" itemvalue="oauthlib" />
+            <item index="71" class="java.lang.String" itemvalue="stripe" />
+            <item index="72" class="java.lang.String" itemvalue="django-waffle" />
+            <item index="73" class="java.lang.String" itemvalue="pyparsing" />
+            <item index="74" class="java.lang.String" itemvalue="uvloop" />
+            <item index="75" class="java.lang.String" itemvalue="beautifulsoup4" />
+            <item index="76" class="java.lang.String" itemvalue="django-celery-beat" />
+            <item index="77" class="java.lang.String" itemvalue="hyperlink" />
+            <item index="78" class="java.lang.String" itemvalue="django-cookie-consent" />
+            <item index="79" class="java.lang.String" itemvalue="djangorestframework-jwt" />
+            <item index="80" class="java.lang.String" itemvalue="django-htmlmin" />
+            <item index="81" class="java.lang.String" itemvalue="cryptography" />
+            <item index="82" class="java.lang.String" itemvalue="whitenoise" />
+            <item index="83" class="java.lang.String" itemvalue="django-isbn-field" />
+            <item index="84" class="java.lang.String" itemvalue="easy-thumbnails" />
+            <item index="85" class="java.lang.String" itemvalue="jinja2" />
+            <item index="86" class="java.lang.String" itemvalue="odfpy" />
+            <item index="87" class="java.lang.String" itemvalue="channels" />
+            <item index="88" class="java.lang.String" itemvalue="django-csp" />
+            <item index="89" class="java.lang.String" itemvalue="pyexcel" />
+            <item index="90" class="java.lang.String" itemvalue="django-allauth" />
+            <item index="91" class="java.lang.String" itemvalue="pyexcel-xls" />
+            <item index="92" class="java.lang.String" itemvalue="pyexcel-xlsx" />
+            <item index="93" class="java.lang.String" itemvalue="django-ical" />
+            <item index="94" class="java.lang.String" itemvalue="django-ses" />
+            <item index="95" class="java.lang.String" itemvalue="netaddr" />
+            <item index="96" class="java.lang.String" itemvalue="txaio" />
+            <item index="97" class="java.lang.String" itemvalue="pyexcel-webio" />
+            <item index="98" class="java.lang.String" itemvalue="billiard" />
+            <item index="99" class="java.lang.String" itemvalue="django-dumpslow" />
+            <item index="100" class="java.lang.String" itemvalue="coverage" />
+            <item index="101" class="java.lang.String" itemvalue="six" />
+            <item index="102" class="java.lang.String" itemvalue="cairosvg" />
+            <item index="103" class="java.lang.String" itemvalue="asn1crypto" />
+            <item index="104" class="java.lang.String" itemvalue="ruamel.yaml" />
+            <item index="105" class="java.lang.String" itemvalue="weasyprint" />
+            <item index="106" class="java.lang.String" itemvalue="xlwt" />
+            <item index="107" class="java.lang.String" itemvalue="packaging" />
+            <item index="108" class="java.lang.String" itemvalue="ipwhois" />
+            <item index="109" class="java.lang.String" itemvalue="xlsxwriter" />
+            <item index="110" class="java.lang.String" itemvalue="chardet" />
+            <item index="111" class="java.lang.String" itemvalue="jmespath" />
+            <item index="112" class="java.lang.String" itemvalue="user-agents" />
+            <item index="113" class="java.lang.String" itemvalue="coreapi" />
+            <item index="114" class="java.lang.String" itemvalue="s3transfer" />
+            <item index="115" class="java.lang.String" itemvalue="django-cookies-samesite" />
+            <item index="116" class="java.lang.String" itemvalue="pypdf2" />
+            <item index="117" class="java.lang.String" itemvalue="collectfast" />
+            <item index="118" class="java.lang.String" itemvalue="paho-mqtt" />
+            <item index="119" class="java.lang.String" itemvalue="django-concurrency" />
+            <item index="120" class="java.lang.String" itemvalue="tabulate" />
+            <item index="121" class="java.lang.String" itemvalue="defusedxml" />
+            <item index="122" class="java.lang.String" itemvalue="lml" />
+            <item index="123" class="java.lang.String" itemvalue="pycparser" />
+            <item index="124" class="java.lang.String" itemvalue="redis" />
+            <item index="125" class="java.lang.String" itemvalue="coreschema" />
+            <item index="126" class="java.lang.String" itemvalue="django-positions" />
+            <item index="127" class="java.lang.String" itemvalue="django-widget-tweaks" />
+            <item index="128" class="java.lang.String" itemvalue="backports.ssl-match-hostname" />
+            <item index="129" class="java.lang.String" itemvalue="django-limits" />
+            <item index="130" class="java.lang.String" itemvalue="django-health-check" />
+            <item index="131" class="java.lang.String" itemvalue="moviepy" />
+            <item index="132" class="java.lang.String" itemvalue="django-user-agents" />
+            <item index="133" class="java.lang.String" itemvalue="docutils" />
+            <item index="134" class="java.lang.String" itemvalue="django-timedeltafield" />
+            <item index="135" class="java.lang.String" itemvalue="uvicorn" />
+            <item index="136" class="java.lang.String" itemvalue="django-oauth-toolkit" />
+            <item index="137" class="java.lang.String" itemvalue="py-moneyed" />
+            <item index="138" class="java.lang.String" itemvalue="reportlab" />
+            <item index="139" class="java.lang.String" itemvalue="python3-openid" />
+            <item index="140" class="java.lang.String" itemvalue="ratelim" />
+            <item index="141" class="java.lang.String" itemvalue="attrs" />
+            <item index="142" class="java.lang.String" itemvalue="psutil" />
+            <item index="143" class="java.lang.String" itemvalue="msgpack" />
+            <item index="144" class="java.lang.String" itemvalue="decorator" />
+            <item index="145" class="java.lang.String" itemvalue="django-npm" />
+            <item index="146" class="java.lang.String" itemvalue="pip-tools" />
+            <item index="147" class="java.lang.String" itemvalue="wget" />
+            <item index="148" class="java.lang.String" itemvalue="awscli" />
+            <item index="149" class="java.lang.String" itemvalue="pyasn1" />
+            <item index="150" class="java.lang.String" itemvalue="requests" />
+            <item index="151" class="java.lang.String" itemvalue="drf-yasg" />
+            <item index="152" class="java.lang.String" itemvalue="pyopenssl" />
+            <item index="153" class="java.lang.String" itemvalue="websocket-client" />
+            <item index="154" class="java.lang.String" itemvalue="pyrsistent" />
+            <item index="155" class="java.lang.String" itemvalue="ruamel.yaml.clib" />
+            <item index="156" class="java.lang.String" itemvalue="zipp" />
+            <item index="157" class="java.lang.String" itemvalue="cached-property" />
+            <item index="158" class="java.lang.String" itemvalue="django-lazysignup" />
+            <item index="159" class="java.lang.String" itemvalue="djangorestframework" />
+            <item index="160" class="java.lang.String" itemvalue="django-cors-headers" />
+            <item index="161" class="java.lang.String" itemvalue="uritemplate" />
+            <item index="162" class="java.lang.String" itemvalue="tornado" />
+            <item index="163" class="java.lang.String" itemvalue="botocore" />
+            <item index="164" class="java.lang.String" itemvalue="django-celery-results" />
+            <item index="165" class="java.lang.String" itemvalue="raven" />
+            <item index="166" class="java.lang.String" itemvalue="phonenumbers" />
+            <item index="167" class="java.lang.String" itemvalue="amqp" />
+            <item index="168" class="java.lang.String" itemvalue="django-adv-cache-tag" />
+            <item index="169" class="java.lang.String" itemvalue="django-mathfilters" />
+            <item index="170" class="java.lang.String" itemvalue="twisted" />
+            <item index="171" class="java.lang.String" itemvalue="django-select2" />
+            <item index="172" class="java.lang.String" itemvalue="django-compressor" />
+            <item index="173" class="java.lang.String" itemvalue="incremental" />
+            <item index="174" class="java.lang.String" itemvalue="pyhamcrest" />
+            <item index="175" class="java.lang.String" itemvalue="django-macaddress" />
+            <item index="176" class="java.lang.String" itemvalue="future" />
+            <item index="177" class="java.lang.String" itemvalue="django-redis" />
+            <item index="178" class="java.lang.String" itemvalue="pilkit" />
+            <item index="179" class="java.lang.String" itemvalue="pysocks" />
+            <item index="180" class="java.lang.String" itemvalue="geoip2" />
+            <item index="181" class="java.lang.String" itemvalue="django-referrer-policy" />
+            <item index="182" class="java.lang.String" itemvalue="first" />
+            <item index="183" class="java.lang.String" itemvalue="webencodings" />
+            <item index="184" class="java.lang.String" itemvalue="inflection" />
+            <item index="185" class="java.lang.String" itemvalue="html5lib" />
+            <item index="186" class="java.lang.String" itemvalue="django-el-pagination" />
+            <item index="187" class="java.lang.String" itemvalue="texttable" />
+            <item index="188" class="java.lang.String" itemvalue="python-dateutil" />
+            <item index="189" class="java.lang.String" itemvalue="kombu" />
+            <item index="190" class="java.lang.String" itemvalue="constantly" />
+            <item index="191" class="java.lang.String" itemvalue="naked" />
+            <item index="192" class="java.lang.String" itemvalue="httptools" />
+            <item index="193" class="java.lang.String" itemvalue="django-robots" />
+            <item index="194" class="java.lang.String" itemvalue="certifi" />
+            <item index="195" class="java.lang.String" itemvalue="daphne" />
+            <item index="196" class="java.lang.String" itemvalue="vine" />
+            <item index="197" class="java.lang.String" itemvalue="django-elastic-transcoder" />
+            <item index="198" class="java.lang.String" itemvalue="rjsmin" />
+            <item index="199" class="java.lang.String" itemvalue="cairocffi" />
+            <item index="200" class="java.lang.String" itemvalue="django-elevate" />
+            <item index="201" class="java.lang.String" itemvalue="tornadis" />
+            <item index="202" class="java.lang.String" itemvalue="boto" />
+            <item index="203" class="java.lang.String" itemvalue="tablib" />
+            <item index="204" class="java.lang.String" itemvalue="django-import-export" />
+            <item index="205" class="java.lang.String" itemvalue="webvtt-py" />
+            <item index="206" class="java.lang.String" itemvalue="zope.interface" />
+            <item index="207" class="java.lang.String" itemvalue="django-appconf" />
+            <item index="208" class="java.lang.String" itemvalue="crypto" />
+            <item index="209" class="java.lang.String" itemvalue="django-xmlrpc" />
+            <item index="210" class="java.lang.String" itemvalue="django-qr-code" />
+            <item index="211" class="java.lang.String" itemvalue="django-mptt" />
+            <item index="212" class="java.lang.String" itemvalue="django-filter" />
+            <item index="213" class="java.lang.String" itemvalue="sqlibrist" />
+            <item index="214" class="java.lang.String" itemvalue="django-ratelimit" />
+            <item index="215" class="java.lang.String" itemvalue="django-taggit" />
+            <item index="216" class="java.lang.String" itemvalue="django-watchman" />
+            <item index="217" class="java.lang.String" itemvalue="django-recurrence" />
+            <item index="218" class="java.lang.String" itemvalue="diff-match-patch" />
+            <item index="219" class="java.lang.String" itemvalue="async-timeout" />
+            <item index="220" class="java.lang.String" itemvalue="django-localflavor" />
+            <item index="221" class="java.lang.String" itemvalue="imageio-ffmpeg" />
+            <item index="222" class="java.lang.String" itemvalue="xhtml2pdf" />
+            <item index="223" class="java.lang.String" itemvalue="django-classy-tags" />
+            <item index="224" class="java.lang.String" itemvalue="sqlparse" />
+            <item index="225" class="java.lang.String" itemvalue="requests-oauthlib" />
+            <item index="226" class="java.lang.String" itemvalue="num2words" />
+            <item index="227" class="java.lang.String" itemvalue="pyphen" />
+            <item index="228" class="java.lang.String" itemvalue="icalendar" />
+            <item index="229" class="java.lang.String" itemvalue="django-weasyprint" />
+            <item index="230" class="java.lang.String" itemvalue="pyecharts" />
+            <item index="231" class="java.lang.String" itemvalue="xmltodict" />
+            <item index="232" class="java.lang.String" itemvalue="urllib3" />
+            <item index="233" class="java.lang.String" itemvalue="opengraph" />
+            <item index="234" class="java.lang.String" itemvalue="django-imagekit" />
+            <item index="235" class="java.lang.String" itemvalue="python-stdnum" />
+            <item index="236" class="java.lang.String" itemvalue="django-url-filter" />
+            <item index="237" class="java.lang.String" itemvalue="single-beat" />
+            <item index="238" class="java.lang.String" itemvalue="pinax-referrals" />
+            <item index="239" class="java.lang.String" itemvalue="django-resumable" />
+            <item index="240" class="java.lang.String" itemvalue="maxminddb" />
+            <item index="241" class="java.lang.String" itemvalue="pyexcel-io" />
+            <item index="242" class="java.lang.String" itemvalue="maxminddb-geolite2" />
+            <item index="243" class="java.lang.String" itemvalue="swagger-spec-validator" />
+            <item index="244" class="java.lang.String" itemvalue="channels-redis" />
+            <item index="245" class="java.lang.String" itemvalue="tqdm" />
+            <item index="246" class="java.lang.String" itemvalue="html2image" />
+            <item index="247" class="java.lang.String" itemvalue="django" />
+            <item index="248" class="java.lang.String" itemvalue="django-fsm" />
+            <item index="249" class="java.lang.String" itemvalue="colorama" />
+            <item index="250" class="java.lang.String" itemvalue="django-js-asset" />
+            <item index="251" class="java.lang.String" itemvalue="django-timezone-field" />
+            <item index="252" class="java.lang.String" itemvalue="pillow" />
+            <item index="253" class="java.lang.String" itemvalue="openpyxl" />
+          </list>
+        </value>
+      </option>
+    </inspection_tool>
+  </profile>
+</component>
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+<component name="InspectionProjectProfileManager">
+  <settings>
+    <option name="USE_PROJECT_PROFILE" value="false" />
+    <version value="1.0" />
+  </settings>
+</component>
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..45bf5f7
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="Black">
+    <option name="sdkName" value="Python 3.11 (django-elastic-transcoder)" />
+  </component>
+  <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.11 (django-elastic-transcoder)" project-jdk-type="Python SDK" />
+</project>
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..ee1916a
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/django-elastic-transcoder.iml" filepath="$PROJECT_DIR$/.idea/django-elastic-transcoder.iml" />
+    </modules>
+  </component>
+</project>
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>
\ No newline at end of file
diff --git a/.travis.yml b/.travis.yml
index 99f4106..9d31228 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,33 +2,40 @@ language: python
 
 python:
   - "2.7"
+  - "3.3"
+  - "3.4"
+  - "3.5"
+  - "3.6"
 
 env:
-  matrix:
-    - TOX_ENV=py27-dj14
-    - TOX_ENV=py27-dj15
-    - TOX_ENV=py27-dj16
-    - TOX_ENV=py27-dj17
-    - TOX_ENV=py27-dj18
-    - TOX_ENV=py33-dj15
-    - TOX_ENV=py33-dj16
-    - TOX_ENV=py33-dj17
-    - TOX_ENV=py33-dj18
-    - TOX_ENV=py34-dj15
-    - TOX_ENV=py34-dj16
-    - TOX_ENV=py34-dj17
-    - TOX_ENV=py34-dj18
-    - TOX_ENV=pypy-dj14
-    - TOX_ENV=pypy-dj15
-    - TOX_ENV=pypy-dj16
-    - TOX_ENV=pypy-dj17
-    - TOX_ENV=pypy-dj18
-    - TOX_ENV=py27-cov
+  - DJANGO=1.8
+  - DJANGO=1.10
+  - DJANGO=1.11
+  - DJANGO=cov
+
+matrix:
+  exclude:
+    - python: "3.3"
+      env: DJANGO=1.10
+    - python: "3.3"
+      env: DJANGO=1.11
+    - python: "3.3"
+      env: DJANGO=cov
+    - python: "3.4"
+      env: DJANGO=cov
+    - python: "3.5"
+      env: DJANGO=cov
+    - python: "3.6"
+      env: DJANGO=1.8
+    - python: "3.6"
+      env: DJANGO=1.10
+    - python: "3.6"
+      env: DJANGO=cov
 
 install:
-  - pip install tox
+  - pip install tox coveralls
 
 script:
-  - tox -e $TOX_ENV
+  - tox -e py${TRAVIS_PYTHON_VERSION//[.]/}-${DJANGO//[.]/}
 after_success:
   - coveralls
diff --git a/dj_elastictranscoder/admin.py b/dj_elastictranscoder/admin.py
index c7ad991..b9123b8 100644
--- a/dj_elastictranscoder/admin.py
+++ b/dj_elastictranscoder/admin.py
@@ -1,6 +1,7 @@
 from django.contrib import admin
 from .models import EncodeJob
 
+
 class EncodeJobAdmin(admin.ModelAdmin):
     list_display = ('id', 'state', 'message')
     list_filters = ('state',)
diff --git a/dj_elastictranscoder/migrations/0001_initial.py b/dj_elastictranscoder/migrations/0001_initial.py
index db0199f..bfa5ae9 100644
--- a/dj_elastictranscoder/migrations/0001_initial.py
+++ b/dj_elastictranscoder/migrations/0001_initial.py
@@ -2,7 +2,7 @@
 from __future__ import unicode_literals
 
 from django.db import models, migrations
-
+import django.db.models.deletion
 
 class Migration(migrations.Migration):
 
@@ -20,7 +20,7 @@ class Migration(migrations.Migration):
                 ('message', models.TextField()),
                 ('created_at', models.DateTimeField(auto_now_add=True)),
                 ('last_modified', models.DateTimeField(auto_now=True)),
-                ('content_type', models.ForeignKey(to='contenttypes.ContentType')),
+                ('content_type', models.ForeignKey(to='contenttypes.ContentType', on_delete=models.PROTECT)),
             ],
         ),
     ]
diff --git a/dj_elastictranscoder/models.py b/dj_elastictranscoder/models.py
index 8422e07..3d2d02a 100644
--- a/dj_elastictranscoder/models.py
+++ b/dj_elastictranscoder/models.py
@@ -1,10 +1,6 @@
 from django.db import models
 from django.contrib.contenttypes.models import ContentType
-import django
-if django.get_version() >= '1.8':
-    from django.contrib.contenttypes.fields import GenericForeignKey
-else:
-    from django.contrib.contenttypes.generic import GenericForeignKey
+from django.contrib.contenttypes.fields import GenericForeignKey
 
 
 class EncodeJob(models.Model):
@@ -16,10 +12,13 @@ class EncodeJob(models.Model):
         (4, 'Complete'),
     )
     id = models.CharField(max_length=100, primary_key=True)
-    content_type = models.ForeignKey(ContentType)
+    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
     object_id = models.PositiveIntegerField()
     state = models.PositiveIntegerField(choices=STATE_CHOICES, default=0, db_index=True)
     content_object = GenericForeignKey()
     message = models.TextField()
     created_at = models.DateTimeField(auto_now_add=True)
     last_modified = models.DateTimeField(auto_now=True)
+
+    def __str__(self):
+        return self.id
diff --git a/dj_elastictranscoder/signals.py b/dj_elastictranscoder/signals.py
index f5c52c8..9cff6b1 100644
--- a/dj_elastictranscoder/signals.py
+++ b/dj_elastictranscoder/signals.py
@@ -1,5 +1,8 @@
-from django.dispatch import Signal
+import django.dispatch
 
-transcode_onprogress = Signal(providing_args=["job", "message"])
-transcode_onerror = Signal(providing_args=["job", "message"])
-transcode_oncomplete = Signal(providing_args=["job", "message"])
+# (providing_args=["job", "message"]
+
+transcode_onprogress = django.dispatch.Signal()
+transcode_onerror = django.dispatch.Signal()
+transcode_oncomplete = django.dispatch.Signal()
+transcode_onwarning = django.dispatch.Signal()
diff --git a/dj_elastictranscoder/south_migrations/0001_initial.py b/dj_elastictranscoder/south_migrations/0001_initial.py
deleted file mode 100644
index 849422f..0000000
--- a/dj_elastictranscoder/south_migrations/0001_initial.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# -*- coding: utf-8 -*-
-from south.utils import datetime_utils as datetime
-from south.db import db
-from south.v2 import SchemaMigration
-from django.db import models
-
-
-class Migration(SchemaMigration):
-
-    def forwards(self, orm):
-        # Adding model 'EncodeJob'
-        db.create_table(u'dj_elastictranscoder_encodejob', (
-            ('id', self.gf('django.db.models.fields.CharField')(max_length=100, primary_key=True)),
-            ('content_type', self.gf('django.db.models.fields.related.ForeignKey')(to=orm['contenttypes.ContentType'])),
-            ('object_id', self.gf('django.db.models.fields.PositiveIntegerField')()),
-            ('state', self.gf('django.db.models.fields.PositiveIntegerField')(default=0, db_index=True)),
-            ('message', self.gf('django.db.models.fields.TextField')()),
-            ('created_at', self.gf('django.db.models.fields.DateTimeField')(auto_now_add=True, blank=True)),
-            ('last_modified', self.gf('django.db.models.fields.DateTimeField')(auto_now=True, blank=True)),
-        ))
-        db.send_create_signal(u'dj_elastictranscoder', ['EncodeJob'])
-
-
-    def backwards(self, orm):
-        # Deleting model 'EncodeJob'
-        db.delete_table(u'dj_elastictranscoder_encodejob')
-
-
-    models = {
-        u'contenttypes.contenttype': {
-            'Meta': {'ordering': "('name',)", 'unique_together': "(('app_label', 'model'),)", 'object_name': 'ContentType', 'db_table': "'django_content_type'"},
-            'app_label': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            u'id': ('django.db.models.fields.AutoField', [], {'primary_key': 'True'}),
-            'model': ('django.db.models.fields.CharField', [], {'max_length': '100'}),
-            'name': ('django.db.models.fields.CharField', [], {'max_length': '100'})
-        },
-        u'dj_elastictranscoder.encodejob': {
-            'Meta': {'object_name': 'EncodeJob'},
-            'content_type': ('django.db.models.fields.related.ForeignKey', [], {'to': u"orm['contenttypes.ContentType']"}),
-            'created_at': ('django.db.models.fields.DateTimeField', [], {'auto_now_add': 'True', 'blank': 'True'}),
-            'id': ('django.db.models.fields.CharField', [], {'max_length': '100', 'primary_key': 'True'}),
-            'last_modified': ('django.db.models.fields.DateTimeField', [], {'auto_now': 'True', 'blank': 'True'}),
-            'message': ('django.db.models.fields.TextField', [], {}),
-            'object_id': ('django.db.models.fields.PositiveIntegerField', [], {}),
-            'state': ('django.db.models.fields.PositiveIntegerField', [], {'default': '0', 'db_index': 'True'})
-        }
-    }
-
-    complete_apps = ['dj_elastictranscoder']
\ No newline at end of file
diff --git a/dj_elastictranscoder/south_migrations/__init__.py b/dj_elastictranscoder/south_migrations/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/dj_elastictranscoder/transcoder.py b/dj_elastictranscoder/transcoder.py
index 6d77f75..6d540bf 100644
--- a/dj_elastictranscoder/transcoder.py
+++ b/dj_elastictranscoder/transcoder.py
@@ -1,6 +1,5 @@
-from boto3.session import Session
+import boto3
 
-from django.conf import settings
 from django.contrib.contenttypes.models import ContentType
 
 from .models import EncodeJob
@@ -11,33 +10,8 @@ class Transcoder(object):
     def __init__(self, pipeline_id, region=None, access_key_id=None, secret_access_key=None):
         self.pipeline_id = pipeline_id
 
-        if not region:
-            region = getattr(settings, 'AWS_REGION', None)
-        self.aws_region = region
-
-        if not access_key_id:
-            access_key_id = getattr(settings, 'AWS_ACCESS_KEY_ID', None)
-        self.aws_access_key_id = access_key_id
-
-        if not secret_access_key:
-            secret_access_key = getattr(settings, 'AWS_SECRET_ACCESS_KEY', None)
-        self.aws_secret_access_key = secret_access_key
-
-        if self.aws_access_key_id is None:
-            assert False, 'Please provide AWS_ACCESS_KEY_ID'
-
-        if self.aws_secret_access_key is None:
-            assert False, 'Please provide AWS_SECRET_ACCESS_KEY'
-
-        if self.aws_region is None:
-            assert False, 'Please provide AWS_REGION'
-
-        boto_session = Session(
-            aws_access_key_id=self.aws_access_key_id,
-            aws_secret_access_key=self.aws_secret_access_key,
-            region_name=self.aws_region,
-        )
-        self.client = boto_session.client('elastictranscoder')
+        self.client = boto3.client('elastictranscoder', aws_access_key_id=access_key_id,
+                                   aws_secret_access_key=secret_access_key, region_name=region)
 
     def encode(self, input_name, outputs, **kwargs):
         self.message = self.client.create_job(
diff --git a/dj_elastictranscoder/urls.py b/dj_elastictranscoder/urls.py
index 3b6d4a3..007d431 100644
--- a/dj_elastictranscoder/urls.py
+++ b/dj_elastictranscoder/urls.py
@@ -1,8 +1,7 @@
-try:
-    from django.conf.urls import url, patterns
-except ImportError:
-    from django.conf.urls.defaults import url, patterns  # Support for Django < 1.4
+from django.conf.urls import url
 
-urlpatterns = patterns('dj_elastictranscoder.views',
-    url(r'^endpoint/$', 'endpoint'),
-)
+from .views import endpoint
+
+urlpatterns = [
+    url(r'^endpoint/$', endpoint, name='endpoint'),
+]
diff --git a/dj_elastictranscoder/views.py b/dj_elastictranscoder/views.py
index 9ff0f51..7e5db5a 100644
--- a/dj_elastictranscoder/views.py
+++ b/dj_elastictranscoder/views.py
@@ -8,9 +8,11 @@
 from .signals import (
     transcode_onprogress,
     transcode_onerror,
-    transcode_oncomplete
+    transcode_oncomplete,
+    transcode_onwarning
 )
 
+
 @csrf_exempt
 def endpoint(request):
     """
@@ -22,7 +24,6 @@ def endpoint(request):
     except ValueError:
         return HttpResponseBadRequest('Invalid JSON')
 
-
     # handle SNS subscription
     if data['Type'] == 'SubscriptionConfirmation':
         subscribe_url = data['SubscribeURL']
@@ -34,7 +35,6 @@ def endpoint(request):
         mail_admins('Please confirm SNS subscription', subscribe_body)
         return HttpResponse('OK')
 
-    
     #
     try:
         message = json.loads(data['Message'])
@@ -58,10 +58,17 @@ def endpoint(request):
         transcode_oncomplete.send(sender=None, job=job, message=message)
     elif message['state'] == 'ERROR':
         job = EncodeJob.objects.get(pk=message['jobId'])
-        job.message = message['messageDetails']
+        job.message = message.get('messageDetails', json.dumps(message))
         job.state = 2
         job.save()
 
         transcode_onerror.send(sender=None, job=job, message=message)
+    elif message['state'] == 'WARNING':
+        job = EncodeJob.objects.get(pk=message['jobId'])
+        job.message = json.dumps(message)
+        job.state = 3
+        job.save()
+
+        transcode_onwarning.send(sender=None, job=job, message=message)
 
     return HttpResponse('Done')
diff --git a/setup.py b/setup.py
index 13ecc92..cc0cde0 100644
--- a/setup.py
+++ b/setup.py
@@ -15,18 +15,15 @@
     include_package_data=True,
     zip_safe=False,
     install_requires=[
-        "django >= 1.3, < 1.9",
+        "django >= 1.8",
         "boto3 >= 1.1",
-        "South >= 0.8",
     ],
     classifiers=[
         "Intended Audience :: Developers",
         "Operating System :: OS Independent",
         "Programming Language :: Python",
-        "Programming Language :: Python :: 2",
-        'Programming Language :: Python :: 2.7',
-        'Programming Language :: Python :: 3',
-        'Programming Language :: Python :: 3.4',
+        'Programming Language :: Python :: 3.11',
+        'Programming Language :: Python :: 3.12',
         "Topic :: Software Development :: Libraries :: Python Modules",
         "Environment :: Web Environment",
         "Framework :: Django",
diff --git a/testsapp/models.py b/testsapp/models.py
index 6014fc4..381ce30 100644
--- a/testsapp/models.py
+++ b/testsapp/models.py
@@ -1,4 +1,5 @@
 from django.db import models
 
+
 class Item(models.Model):
     name = models.CharField(max_length=100)
diff --git a/testsapp/requirements.txt b/testsapp/requirements.txt
index 6513ae3..b37fdba 100644
--- a/testsapp/requirements.txt
+++ b/testsapp/requirements.txt
@@ -1,5 +1,4 @@
 pytest
 pytest-django
 pytest-cov
-boto
-south
\ No newline at end of file
+boto3
\ No newline at end of file
diff --git a/testsapp/test_job.py b/testsapp/test_job.py
index 13dc3b0..fa01121 100644
--- a/testsapp/test_job.py
+++ b/testsapp/test_job.py
@@ -3,20 +3,18 @@
 
 from django.test import TestCase
 from django.dispatch import receiver
-from django.db import models
 from django.contrib.contenttypes.models import ContentType
 
 from dj_elastictranscoder.models import EncodeJob
 from dj_elastictranscoder.signals import (
-    transcode_onprogress, 
-    transcode_onerror, 
+    transcode_onprogress,
+    transcode_onerror,
     transcode_oncomplete
 )
 
 from .models import Item
 
 
-
 PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
 FIXTURE_DIRS = os.path.join(PROJECT_ROOT, 'fixtures')
 
@@ -62,7 +60,6 @@ def setUp(self):
     def test_initial(self):
         job = EncodeJob.objects.get(id=self.job_id)
         self.assertEqual(job.state, 0)
-        
 
     def test_onprogress(self):
         with open(os.path.join(FIXTURE_DIRS, 'onprogress.json')) as f:
@@ -86,7 +83,6 @@ def test_onerror(self):
         job = EncodeJob.objects.get(id=self.job_id)
         self.assertEqual(job.state, 2)
 
-
     def test_oncomplete(self):
         with open(os.path.join(FIXTURE_DIRS, 'oncomplete.json')) as f:
             content = f.read()
@@ -134,7 +130,6 @@ def test_transcode_onprogress(self):
         self.assertEqual('Progress', job.message)
         self.assertEqual(1, job.state)
 
-
     def test_transcode_onerror(self):
         """
         test for transcode_onerror signal
diff --git a/testsapp/tests_settings.py b/testsapp/tests_settings.py
index 3eaaec3..7e246d1 100644
--- a/testsapp/tests_settings.py
+++ b/testsapp/tests_settings.py
@@ -15,5 +15,5 @@
 ]
 SITE_ID = 1
 DEBUG = False
-ROOT_URLCONF = ''
-SECRET_KEY='test'
\ No newline at end of file
+ROOT_URLCONF = 'testsapp.urls'
+SECRET_KEY = 'test'
diff --git a/testsapp/urls.py b/testsapp/urls.py
new file mode 100644
index 0000000..dfc56e4
--- /dev/null
+++ b/testsapp/urls.py
@@ -0,0 +1,5 @@
+from django.conf.urls import include, url
+
+urlpatterns = [
+    url(r'', include('dj_elastictranscoder.urls')),
+]
diff --git a/tox.ini b/tox.ini
index d77ba72..55a516e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,33 +1,23 @@
 [tox]
-# for py 3.x we are using only django 1.6.x as 1.5.x had only "experimental py3 support"
 envlist =
-    py{27,py}-dj{14,15,16,17,18},
-    py{33,34}-dj{15,16,17,18},
-    py27-cov
+    py{310,311}-dj{5}
 skipsdist = True
 usedevelop = True
 
 [testenv]
-commands = {posargs:py.test --create-db -vv}
+commands = {posargs:pytest --create-db -vv}
 basepython =
-    py27: python2.7
-    py33: python3.3
-    py34: python3.4
-    pypy: pypy
+    py310: python3.10
+    py311: python3.11
 deps =
     -rtestsapp/requirements.txt
-    dj14: django>=1.4,<1.4.999
-    dj15: django>=1.5,<1.5.999
-    dj16: django>=1.6,<1.6.999
-    dj17: django>=1.7,<1.7.999
-    dj18: django>=1.8,<1.8.999
-    dj19: https://github.com/django/django/archive/master.tar.gz#egg=django
+    dj5: django>=5.0,<5.1
 setenv =
     DJANGO_SETTINGS_MODULE = testsapp.tests_settings
     PYTHONPATH = {toxinidir}/testsapp:{toxinidir}
 
-[testenv:py27-cov]
-commands = py.test --cov=dj_elastictranscoder
+[testenv:py311-cov]
+commands = pytest --cov=dj_elastictranscoder
 deps =
     -rtestsapp/requirements.txt
-    django>=1.8,<1.8.999
+    django>=5.0,<5.1
