diff --git a/src/.gitignore b/src/.gitignore
index e82f5252fbc4cff21c449fefd6dd7fa66d85dabe..507578d051bd656ecc56db7206943a29b3bc8392 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -125,3 +125,6 @@ nb-configuration.xml
 /results/
 /phpunit*.xml
 /.phpunit.*.cache
+
+# Media files
+public/media/*
diff --git a/src/app/Config/Routes.php b/src/app/Config/Routes.php
index a2a9654bc5267cb7f71b685e9248419101988a5c..4ceab4912111074978a2786ef302e75abd9e9ce5 100644
--- a/src/app/Config/Routes.php
+++ b/src/app/Config/Routes.php
@@ -5,9 +5,8 @@ $routes = Services::routes();
 
 // Load the system's routing file first, so that the app and ENVIRONMENT
 // can override as needed.
-if (file_exists(SYSTEMPATH . 'Config/Routes.php'))
-{
-	require SYSTEMPATH . 'Config/Routes.php';
+if (file_exists(SYSTEMPATH . 'Config/Routes.php')) {
+    require SYSTEMPATH . 'Config/Routes.php';
 }
 
 /**
@@ -20,7 +19,8 @@ $routes->setDefaultController('Home');
 $routes->setDefaultMethod('index');
 $routes->setTranslateURIDashes(false);
 $routes->set404Override();
-$routes->setAutoRoute(true);
+$routes->setAutoRoute(false);
+$routes->addPlaceholder('podcastName', '^@[a-z0-9\_]{1,191}$');
 
 /**
  * --------------------------------------------------------------------
@@ -31,6 +31,8 @@ $routes->setAutoRoute(true);
 // We get a performance increase by specifying the default
 // route since we don't have to scan directories.
 $routes->get('/', 'Home::index');
+$routes->add('/podcasts/create', 'Podcasts::create');
+$routes->add('/(:podcastName)', 'Podcasts::podcastByHandle/$1');
 
 /**
  * --------------------------------------------------------------------
@@ -45,7 +47,6 @@ $routes->get('/', 'Home::index');
  * You will have access to the $routes object within that file without
  * needing to reload it.
  */
-if (file_exists(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php'))
-{
-	require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
+if (file_exists(APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php')) {
+    require APPPATH . 'Config/' . ENVIRONMENT . '/Routes.php';
 }
diff --git a/src/app/Controllers/Podcast.php b/src/app/Controllers/Podcasts.php
similarity index 73%
rename from src/app/Controllers/Podcast.php
rename to src/app/Controllers/Podcasts.php
index 117c98d094a3cf778c3bb7753eddd1ce5d6ea603..161d6f95b0a3445d433eec64e2f9f040ea87b158 100644
--- a/src/app/Controllers/Podcast.php
+++ b/src/app/Controllers/Podcasts.php
@@ -5,7 +5,7 @@ use App\Models\LanguageModel;
 use App\Models\PodcastModel;
 use RuntimeException;
 
-class Podcast extends BaseController
+class Podcasts extends BaseController
 {
     public function index()
     {
@@ -15,10 +15,11 @@ class Podcast extends BaseController
     public function create()
     {
         $model = new PodcastModel();
+        helper(['form', 'url']);
 
         if (!$this->validate([
             'title' => 'required',
-            'name' => 'required|alpha_dash',
+            'name' => 'required|regex_match[^[a-z0-9\_]{1,191}$]',
             'description' => 'required|max_length[4000]',
             'image' => 'uploaded[image]|is_image[image]|ext_in[image,jpg,png]|max_dims[image,3000,3000]',
             'owner_email' => 'required|valid_email|permit_empty',
@@ -38,20 +39,23 @@ class Podcast extends BaseController
                 'browser_lang' => $browser_lang,
             ];
 
-            echo view('podcast/create', $data);
+            echo view('podcasts/create', $data);
         } else {
             $image = $this->request->getFile('image');
             if (!$image->isValid()) {
                 throw new RuntimeException($image->getErrorString() . '(' . $image->getError() . ')');
             }
-            $image_path = $image->store();
+            $podcast_name = $this->request->getVar('name');
+            $image_name = 'cover.' . $image->getExtension();
+            $image_storage_folder = 'media/' . $podcast_name . '/';
+            $image->move($image_storage_folder, $image_name);
 
             $model->save([
                 'title' => $this->request->getVar('title'),
-                'name' => $this->request->getVar('name'),
+                'name' => $podcast_name,
                 'description' => $this->request->getVar('description'),
                 'episode_description_footer' => $this->request->getVar('episode_description_footer'),
-                'image' => $image_path,
+                'image' => $image_storage_folder . $image_name,
                 'language' => $this->request->getVar('language'),
                 'category' => $this->request->getVar('category'),
                 'explicit' => $this->request->getVar('explicit') or false,
@@ -65,7 +69,18 @@ class Podcast extends BaseController
                 'custom_html_head' => $this->request->getVar('custom_html_head'),
             ]);
 
-            echo view('podcast/success');
+            return redirect()->to(base_url('/@' . $podcast_name));
         }
     }
+
+    public function podcastByHandle($handle)
+    {
+        $model = new PodcastModel();
+
+        $podcast_name = substr($handle, 1);
+
+        $data['podcast'] = $model->where('name', $podcast_name)->first();
+
+        return view('podcasts/view.php', $data);
+    }
 }
diff --git a/src/app/Views/podcast/index.php b/src/app/Views/podcast/index.php
deleted file mode 100644
index fbd3ed0450797b649b48496384daa8cd9c943375..0000000000000000000000000000000000000000
--- a/src/app/Views/podcast/index.php
+++ /dev/null
@@ -1,5 +0,0 @@
-<?=$this->extend('layouts/default')?>
-
-<?=$this->section('content')?>
-    <h1 class="text-xl">Podcast Page!</h1>
-<?=$this->endSection()?>
\ No newline at end of file
diff --git a/src/app/Views/podcast/success.php b/src/app/Views/podcast/success.php
deleted file mode 100644
index f985b46aff02b2ec96fac19c214629e5a3dc7468..0000000000000000000000000000000000000000
--- a/src/app/Views/podcast/success.php
+++ /dev/null
@@ -1 +0,0 @@
-Success!
diff --git a/src/app/Views/podcast/create.php b/src/app/Views/podcasts/create.php
similarity index 98%
rename from src/app/Views/podcast/create.php
rename to src/app/Views/podcasts/create.php
index 597b21620ce2875a18f42a3f1507a5728011fc39..cba980b438cc4bbe4d04dc394ebb719137f922d9 100644
--- a/src/app/Views/podcast/create.php
+++ b/src/app/Views/podcasts/create.php
@@ -1,4 +1,3 @@
-<?=helper('form')?>
 <?=$this->extend('layouts/default')?>
 
 <?=$this->section('content')?>
@@ -9,7 +8,7 @@
     <?=\Config\Services::validation()->listErrors()?>
 </div>
 
-<?=form_open_multipart('/podcast/create', ["method" => "post", "class" => "flex flex-col max-w-md"])?>
+<?=form_open_multipart('podcasts/create', ["method" => "post", "class" => "flex flex-col max-w-md"])?>
     <?=csrf_field()?>
 
     <div class="flex flex-col mb-4">
diff --git a/src/app/Views/podcasts/view.php b/src/app/Views/podcasts/view.php
new file mode 100644
index 0000000000000000000000000000000000000000..c2ed590eb0a7c3595464872c20378a6b4cc68a99
--- /dev/null
+++ b/src/app/Views/podcasts/view.php
@@ -0,0 +1,7 @@
+<?=$this->extend('layouts/default')?>
+
+<?=$this->section('content')?>
+    <h1 class="text-xl"><?=$podcast->title?></h1>
+    <img src="<?=base_url($podcast->image)?>" alt="Podcast cover"/>
+
+<?=$this->endSection()?>
\ No newline at end of file