Repository: learningequality/kolibri

Issue:
Videos are not working on Safari 11.0.3
### Observed behavior
I can't play videos on Safari 11.0.3

![screen shot 2019-02-20 at 5 28 16 pm](https://user-images.githubusercontent.com/8663934/53081352-a63c0180-3535-11e9-8b58-8c5aad3d67a6.png)


### Errors and logs

```
[Error] VIDEOJS: (4)
"ERROR:"
"(CODE:4 MEDIA_ERR_SRC_NOT_SUPPORTED)"
"The media could not be loaded, either because the server or network failed or because the format is not supported."
MediaError
	(anonymous function) (media_player_module-0.12.0b7.js:1:209326)
	error (media_player_module-0.12.0b7.js:1:435778)
	handleTechError_ (media_player_module-0.12.0b7.js:1:423419)
	dispatcher (media_player_module-0.12.0b7.js:1:222733)
[Error] Unhandled Promise Rejection: [object DOMError]
```

### Context

Tell us about your environment, including:
 * Kolibri version: 0.12-beta7
 * Operating system: macOS 11.13.3
 * Browser: Safari 11.0.3





Discussion:
Also on Windows 10 chrome version 72.0.3636.109(official build)(64-bit), the videos are not working.
![video not working on chrome](https://user-images.githubusercontent.com/38421180/53083912-bd312280-353a-11e9-9298-18f1ce85e179.png)

does this happen with all videos or just some?
might relate to cherrypy config
> does this happen with all videos or just some?

On Safari all videos can't play.
I also tested those videos on Firefox and it play properly with no console errors. 

Resolving patch:
diff --git a/kolibri/utils/server.py b/kolibri/utils/server.py
--- a/kolibri/utils/server.py
+++ b/kolibri/utils/server.py
@@ -195,16 +195,30 @@ def run_server(port):
 
     cherrypy.config.update({
         "environment": "production",
-        "tools.gzip.on": True,
-        "tools.gzip.mime_types": ["text/*", "application/javascript"],
-        "tools.caching.on": True,
-        "tools.caching.maxobj_size": 2000000,
-        "tools.caching.maxsize": 50000000,
+        "tools.expires.on": True,
+        "tools.expires.secs": 31536000,
     })
 
-    serve_static_dir(settings.STATIC_ROOT, settings.STATIC_URL)
-    serve_static_dir(paths.get_content_dir_path(),
-                     paths.get_content_url(conf.OPTIONS['Deployment']['URL_PATH_PREFIX']))
+    # Mount static files
+    static_files_handler = cherrypy.tools.staticdir.handler(
+        section="/",
+        dir=settings.STATIC_ROOT)
+    cherrypy.tree.mount(static_files_handler, settings.STATIC_URL, config={
+        "/": {
+            "tools.gzip.on": True,
+            "tools.gzip.mime_types": ["text/*", "application/javascript"],
+            "tools.caching.on": True,
+            "tools.caching.maxobj_size": 2000000,
+            "tools.caching.maxsize": 50000000,
+        }
+    })
+
+    # Mount content files
+    content_files_handler = cherrypy.tools.staticdir.handler(
+        section="/",
+        dir=paths.get_content_dir_path())
+    cherrypy.tree.mount(content_files_handler,
+                        paths.get_content_url(conf.OPTIONS['Deployment']['URL_PATH_PREFIX']))
 
     # Unsubscribe the default server
     cherrypy.server.unsubscribe()
@@ -239,15 +253,6 @@ def unlock_after_vacuum():
             pass  # lock file was deleted by other process
 
 
-def serve_static_dir(root, url):
-
-    static_handler = cherrypy.tools.staticdir.handler(
-        section="/",
-        dir=os.path.split(root)[1],
-        root=os.path.abspath(os.path.split(root)[0]))
-    cherrypy.tree.mount(static_handler, url)
-
-
 def _read_pid_file(filename):
     """
     Reads a pid file and returns the contents. PID files have 1 or 2 lines;


Test patch: