From aedfc743c67296cc6e2403bec597cb09044c0672 Mon Sep 17 00:00:00 2001 From: "Timothy J. Warren" Date: Thu, 11 Jun 2015 16:44:52 -0400 Subject: [PATCH] Refactor EVERYTHING, for better, more configurable code --- app/base/BaseApiModel.php | 57 ++++++++++++++++ app/base/BaseController.php | 16 ++++- app/base/BaseDBModel.php | 28 ++++++++ app/base/BaseModel.php | 40 +++-------- app/base/Router.php | 60 ++++++++++++---- app/base/autoloader.php | 17 ----- app/base/functions.php | 47 +++++++++++++ app/config/config.php | 22 +++++- app/config/routes.php | 67 +++++++++++------- app/controllers/AnimeController.php | 68 ++++++++++++++----- app/controllers/MangaController.php | 60 +++++++++------- app/models/AnimeCollectionModel.php | 23 ++++--- app/models/AnimeModel.php | 13 ++-- app/models/MangaModel.php | 13 ++-- app/views/404.php | 1 - .../collection.php} | 13 ++-- app/views/{anime_edit.php => anime/edit.php} | 2 +- app/views/anime/list.php | 34 ++++++++++ app/views/anime/nav.php | 7 ++ app/views/anime_list.php | 33 --------- app/views/anime_nav.php | 11 --- app/views/{manga_list.php => manga/list.php} | 21 ++---- app/views/manga/nav.php | 7 ++ app/views/manga_nav.php | 10 --- index.php | 47 ++++++++++--- public/css/base.css | 68 +++++++++++++------ public/css/manga.css | 29 -------- 27 files changed, 529 insertions(+), 285 deletions(-) create mode 100644 app/base/BaseApiModel.php create mode 100644 app/base/BaseDBModel.php delete mode 100644 app/base/autoloader.php create mode 100644 app/base/functions.php rename app/views/{anime_collection.php => anime/collection.php} (75%) rename app/views/{anime_edit.php => anime/edit.php} (73%) create mode 100644 app/views/anime/list.php create mode 100644 app/views/anime/nav.php delete mode 100644 app/views/anime_list.php delete mode 100644 app/views/anime_nav.php rename app/views/{manga_list.php => manga/list.php} (66%) create mode 100644 app/views/manga/nav.php delete mode 100644 app/views/manga_nav.php delete mode 100644 public/css/manga.css diff --git a/app/base/BaseApiModel.php b/app/base/BaseApiModel.php new file mode 100644 index 00000000..38934cfa --- /dev/null +++ b/app/base/BaseApiModel.php @@ -0,0 +1,57 @@ +cookieJar = new CookieJar(); + $this->client = new Client([ + 'base_url' => $this->base_url, + 'defaults' => [ + 'cookies' => $this->cookieJar, + 'headers' => [ + 'User-Agent' => $_SERVER['HTTP_USER_AGENT'], + 'Accept-Encoding' => 'application/json' + ], + 'timeout' => 5, + 'connect_timeout' => 5 + ] + ]); + } + + /** + * Get the full url path, since the base_url in Guzzle doesn't work correctly + * + * @param string $path + * @return string + */ + protected function _url($path) + { + return "{$this->base_url}{$path}"; + } + +} +// End of BaseApiModel.php \ No newline at end of file diff --git a/app/base/BaseController.php b/app/base/BaseController.php index a3aa14e5..88ea13a8 100644 --- a/app/base/BaseController.php +++ b/app/base/BaseController.php @@ -1,9 +1,19 @@ get_route(); $data['route_path'] = ($route) ? $router->get_route()->path : ""; - $path = realpath(__DIR__ . "/../views/{$template}.php"); + $path = _dir(APP_DIR, 'views', "{$template}.php"); if ( ! is_file($path)) { @@ -32,6 +42,7 @@ class BaseController { ob_start(); extract($data); + include _dir(APP_DIR, 'views', 'header.php'); include $path; $buffer = ob_get_contents(); ob_end_clean(); @@ -57,4 +68,5 @@ class BaseController { header("Content-type: application/json"); echo $data; } -} \ No newline at end of file +} +// End of BaseController.php \ No newline at end of file diff --git a/app/base/BaseDBModel.php b/app/base/BaseDBModel.php new file mode 100644 index 00000000..a4480090 --- /dev/null +++ b/app/base/BaseDBModel.php @@ -0,0 +1,28 @@ +db_config = $this->config->database; + } +} +// End of BaseDBModel.php \ No newline at end of file diff --git a/app/base/BaseModel.php b/app/base/BaseModel.php index a0de0e86..6e9812d6 100644 --- a/app/base/BaseModel.php +++ b/app/base/BaseModel.php @@ -1,43 +1,23 @@ config = $config; - $this->cookieJar = new CookieJar(); - $this->client = new Client([ - 'base_url' => $this->base_url, - 'defaults' => [ - 'cookies' => $this->cookieJar, - 'headers' => [ - 'User-Agent' => $_SERVER['HTTP_USER_AGENT'], - 'Accept-Encoding' => 'application/json' - ], - 'timeout' => 5, - 'connect_timeout' => 5 - ] - ]); - } - - /** - * Get the full url path, since the base_url in Guzzle doesn't work correctly - * - * @param string $path - * @return string - */ - protected function _url($path) - { - return "{$this->base_url}{$path}"; } /** diff --git a/app/base/Router.php b/app/base/Router.php index 47981172..a1c41940 100644 --- a/app/base/Router.php +++ b/app/base/Router.php @@ -2,10 +2,31 @@ use Aura\Router\RouterFactory; +/** + * Basic routing/ dispatch + */ class Router { + /** + * The route-matching object + * @var object $router + */ + protected $router; + + /** + * The global configuration object + * @var object $config + */ + protected $config; + + /** + * Constructor + */ public function __construct() { + global $config; + $this->config = $config; + $router_factory = new RouterFactory(); $router = $router_factory->newInstance(); $this->router = $router_factory->newInstance(); @@ -20,8 +41,17 @@ class Router { */ public function get_route() { - //$path = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); - $route = $this->router->match($_SERVER['REQUEST_URI'], $_SERVER); + global $defaultHandler; + + $raw_route = $_SERVER['REQUEST_URI']; + $route_path = str_replace([$this->config->anime_path, $this->config->manga_path], '', $raw_route); + $route_path = "/" . trim($route_path, '/'); + + $defaultHandler->addDataTable('Route Info', [ + 'route_path' => $route_path + ]); + + $route = $this->router->match($route_path, $_SERVER); return $route; } @@ -54,7 +84,6 @@ class Router { 'title' => 'Page Not Found' ] ]; - } else { @@ -69,22 +98,25 @@ class Router { call_user_func_array([$controller, $action_method], $params); } + /** + * Select controller based on the current url, and apply its relevent routes + * + * @return void + */ private function _setup_routes() { - $host = $_SERVER['HTTP_HOST']; - $route_type = ""; - switch($host) - { - case "anime.timshomepage.net": - $route_type = "anime"; - break; + $route_type = "anime"; - case "manga.timshomepage.net": - $route_type = "manga"; - break; + if ($this->config->manga_host !== "" && strpos($_SERVER['HTTP_HOST'], $this->config->manga_host) !== FALSE) + { + $route_type = "manga"; + } + else if ($this->config->manga_path !== "" && strpos($_SERVER['REQUEST_URI'], $this->config->manga_path) !== FALSE) + { + $route_type = "manga"; } - $routes = require __DIR__ . '/../config/routes.php'; + $routes = $this->config->routes; // Add routes by the configuration file foreach($routes[$route_type] as $name => $route) diff --git a/app/base/autoloader.php b/app/base/autoloader.php deleted file mode 100644 index 7cc5dba0..00000000 --- a/app/base/autoloader.php +++ /dev/null @@ -1,17 +0,0 @@ -{"{$type}_path"}; + $config_host = $config->{"{$type}_host"}; + + // Remove beginning/trailing slashes + $config_path = trim($config_path, '/'); + $path = trim($path, '/'); + + $host = ($config_host !== '') ? $config_host : $_SERVER['HTTP_HOST']; + + if ($config_path !== '') + { + $path = "{$config_path}/{$path}"; + } + + return "//{$host}/{$path}"; +} + +// End of functions.php \ No newline at end of file diff --git a/app/config/config.php b/app/config/config.php index 1982bc8f..748300d6 100644 --- a/app/config/config.php +++ b/app/config/config.php @@ -2,8 +2,24 @@ return (object)[ // Username for feeds 'hummingbird_username' => 'timw4mail', - + + // ---------------------------------------------------------------------------- + // Routing + // + // Route by path, or route by domain. To route by path, set the _host suffixed + // options to an empty string. To route by host, set the _path suffixed options + // to an empty string + // ---------------------------------------------------------------------------- + 'anime_host' => 'anime.timshomepage.net', + 'manga_host' => 'manga.timshomepage.net', + 'anime_path' => '', + 'manga_path' => '', + // Cache paths - 'data_cache_path' => __DIR__ . '/../cache', - 'img_cache_path' => __DIR__ .'/../../public/images' + 'data_cache_path' => _dir(APP_DIR, 'cache'), + 'img_cache_path' => _dir(ROOT_DIR, 'public/images'), + + // Included config files + 'routes' => require _dir(CONF_DIR, 'routes.php'), + 'database' => require _dir(CONF_DIR, 'database.php'), ]; \ No newline at end of file diff --git a/app/config/routes.php b/app/config/routes.php index 1718f5b0..f2d9916b 100644 --- a/app/config/routes.php +++ b/app/config/routes.php @@ -2,21 +2,31 @@ return [ 'anime' => [ - 'index' => [ - 'path' => '/', - 'controller' => 'AnimeController' - ], 'all' => [ 'path' => '/all', 'controller' => 'AnimeController', - 'action' => 'all' + 'action' => 'anime_list', + 'params' => [ + 'type' => 'all', + 'title' => WHOSE . " Anime List · All" + ] + ], + 'index' => [ + 'path' => '/', + 'controller' => 'AnimeController', + 'action' => 'anime_list', + 'params' => [ + 'type' => 'currently-watching', + 'title' => WHOSE . " Anime List · Watching" + ] ], 'plan_to_watch' => [ 'path' => '/plan_to_watch', 'controller' => 'AnimeController', 'action' => 'anime_list', 'params' => [ - 'type' => 'plan-to-watch' + 'type' => 'plan-to-watch', + 'title' => WHOSE . " Anime List · Plan to Watch" ] ], 'on_hold' => [ @@ -24,7 +34,8 @@ return [ 'controller' => 'AnimeController', 'action' => 'anime_list', 'params' => [ - 'type' => 'on-hold' + 'type' => 'on-hold', + 'title' => WHOSE . " Anime List · On Hold" ] ], 'dropped' => [ @@ -32,7 +43,8 @@ return [ 'controller' => 'AnimeController', 'action' => 'anime_list', 'params' => [ - 'type' => 'dropped' + 'type' => 'dropped', + 'title' => WHOSE . " Anime List · Dropped" ] ], 'completed' => [ @@ -40,7 +52,8 @@ return [ 'controller' => 'AnimeController', 'action' => 'anime_list', 'params' => [ - 'type' => 'completed' + 'type' => 'completed', + 'title' => WHOSE . " Anime List · Completed" ] ], 'collection' => [ @@ -48,29 +61,34 @@ return [ 'controller' => 'AnimeController', 'action' => 'collection', 'params' => [] - ], - 'anime_login' => [ - 'path' => '/login', - 'controller' => 'AnimeController', - 'action' => 'login' ] ], 'manga' => [ - 'index' => [ - 'path' => '/', - 'controller' => 'MangaController' - ], 'all' => [ 'path' => '/all', 'controller' => 'MangaController', - 'action' => 'all' + 'action' => 'manga_list', + 'params' => [ + 'type' => 'all', + 'title' => WHOSE . " Manga List · All" + ] + ], + 'index' => [ + 'path' => '/', + 'controller' => 'MangaController', + 'action' => 'manga_list', + 'params' => [ + 'type' => 'Reading', + 'title' => WHOSE . " Manga List · Reading" + ] ], 'plan_to_read' => [ 'path' => '/plan_to_read', 'controller' => 'MangaController', 'action' => 'manga_list', 'params' => [ - 'type' => 'Plan to Read' + 'type' => 'Plan to Read', + 'title' => WHOSE . " Manga List · Plan to Read" ] ], 'on_hold' => [ @@ -78,7 +96,8 @@ return [ 'controller' => 'MangaController', 'action' => 'manga_list', 'params' => [ - 'type' => 'On Hold' + 'type' => 'On Hold', + 'title' => WHOSE . " Manga List · On Hold" ] ], 'dropped' => [ @@ -86,7 +105,8 @@ return [ 'controller' => 'MangaController', 'action' => 'manga_list', 'params' => [ - 'type' => 'Dropped' + 'type' => 'Dropped', + 'title' => WHOSE . " Manga List · Dropped" ] ], 'completed' => [ @@ -94,7 +114,8 @@ return [ 'controller' => 'MangaController', 'action' => 'manga_list', 'params' => [ - 'type' => 'Completed' + 'type' => 'Completed', + 'title' => WHOSE . " Manga List · Completed" ] ], ] diff --git a/app/controllers/AnimeController.php b/app/controllers/AnimeController.php index 1cd15d84..334d9238 100644 --- a/app/controllers/AnimeController.php +++ b/app/controllers/AnimeController.php @@ -1,10 +1,39 @@ '/', + 'Plan to Watch' => '/plan_to_watch', + 'On Hold' => '/on_hold', + 'Dropped' => '/dropped', + 'Completed' => '/completed', + 'Collection' => '/collection', + 'All' => '/all' + ]; + + /** + * Constructor + */ public function __construct() { parent::__construct(); @@ -12,35 +41,38 @@ class AnimeController extends BaseController { $this->collection_model = new AnimeCollectionModel(); } - public function index() + /** + * Show a portion, or all of the anime list + * + * @param string $type - The section of the list + * @param string $title - The title of the page + * @return void + */ + public function anime_list($type, $title) { - $this->anime_list('currently-watching'); - } + $data = ($type != 'all') + ? $this->model->get_list($type) + : $this->model->get_all_lists(); - public function all() - { - $data = $this->model->get_all_lists(); - $this->outputHTML('anime_list', [ - 'title' => "Tim's Anime List · All", - 'sections' => $data - ]); - } - - public function anime_list($type, $title="Tim's Anime List") - { - $data = $this->model->get_list($type); - $this->outputHTML('anime_list', [ + $this->outputHTML('anime/list', [ 'title' => $title, + 'nav_routes' => $this->nav_routes, 'sections' => $data ]); } + /** + * Show the anime collection page + * + * @return void + */ public function collection() { $data = $this->collection_model->get_collection(); - $this->outputHTML('anime_collection', [ - 'title' => "Tim's Anime Collection", + $this->outputHTML('anime/collection', [ + 'title' => WHOSE . " Anime Collection", + 'nav_routes' => $this->nav_routes, 'sections' => $data ]); } diff --git a/app/controllers/MangaController.php b/app/controllers/MangaController.php index 1b28eb8b..991936f2 100644 --- a/app/controllers/MangaController.php +++ b/app/controllers/MangaController.php @@ -1,42 +1,56 @@ '/', + 'Plan to Read' => '/plan_to_read', + 'On Hold' => '/on_hold', + 'Dropped' => '/dropped', + 'Completed' => '/completed', + 'All' => '/all' + ]; + + /** + * Constructor + */ public function __construct() { parent::__construct(); $this->model = new MangaModel(); } - public function index() + /** + * Get a section of the manga list + * + * @param string $status + * @param string $title + * @return void + */ + public function manga_list($status, $title) { - $this->manga_list('Reading'); - } + $data = ($status !== 'all') + ? [$status => $this->model->get_list($status)] + : $this->model->get_all_lists(); - public function all() - { - $data = $this->model->get_all_lists(); - $this->outputHTML('manga_list', [ - 'title' => "Tim's Manga List · All", + $this->outputHTML('manga/list', [ + 'title' => $title, + 'nav_routes' => $this->nav_routes, 'sections' => $data ]); } - - public function manga_list($type, $title="Tim's Manga List") - { - $data = $this->model->get_list($type); - $this->outputHTML('manga_list', [ - 'title' => $title, - 'sections' => [$type => $data] - ]); - } - - public function login() - { - $data = $this->model->authenticate(); - //print_r($data); - } } // End of MangaController.php \ No newline at end of file diff --git a/app/models/AnimeCollectionModel.php b/app/models/AnimeCollectionModel.php index fb8853e7..2627044b 100644 --- a/app/models/AnimeCollectionModel.php +++ b/app/models/AnimeCollectionModel.php @@ -3,21 +3,24 @@ /** * Model for getting anime collection data */ -class AnimeCollectionModel extends BaseModel { - protected $base_url = ""; - private $db; - private $anime_model; - private $db_config; +class AnimeCollectionModel extends BaseDBModel { + /** + * Anime API Model + * @var object $anime_model + */ + private $anime_model; + + /** + * Constructor + */ public function __construct() { - $this->db_config = require_once(__DIR__ . '/../config/database.php'); - $this->db = Query($this->db_config['collection']); - - $this->anime_model = new AnimeModel(); - parent::__construct(); + $this->db = Query($this->db_config['collection']); + $this->anime_model = new AnimeModel(); + // Do an import if an import file exists $this->json_import(); } diff --git a/app/models/AnimeModel.php b/app/models/AnimeModel.php index 7eda6267..895638e8 100644 --- a/app/models/AnimeModel.php +++ b/app/models/AnimeModel.php @@ -3,11 +3,16 @@ /** * Model for handling requests dealing with the anime list */ -class AnimeModel extends BaseModel { - protected $client; - protected $cookieJar; +class AnimeModel extends BaseApiModel { + /** + * The base url for api requests + * @var string $base_url + */ protected $base_url = "https://hummingbird.me/api/v1"; + /** + * Constructor + */ public function __construct() { parent::__construct(); @@ -134,7 +139,7 @@ class AnimeModel extends BaseModel { $output = $response->json(); $output_json = json_encode($output); - if (file_get_contents($cache_file) !== $output_json) + if (( ! file_exists($cache_file)) || file_get_contents($cache_file) !== $output_json) { // Cache the call in case of downtime file_put_contents($cache_file, json_encode($output)); diff --git a/app/models/MangaModel.php b/app/models/MangaModel.php index e2f1b068..15d86e1a 100644 --- a/app/models/MangaModel.php +++ b/app/models/MangaModel.php @@ -1,14 +1,17 @@ config->data_cache_path, 'manga.json'); $config = [ 'query' => [ diff --git a/app/views/404.php b/app/views/404.php index b0b7359a..8237ad29 100644 --- a/app/views/404.php +++ b/app/views/404.php @@ -1,4 +1,3 @@ -

404

diff --git a/app/views/anime_collection.php b/app/views/anime/collection.php similarity index 75% rename from app/views/anime_collection.php rename to app/views/anime/collection.php index 422e1b53..9e9cf143 100644 --- a/app/views/anime_collection.php +++ b/app/views/anime/collection.php @@ -1,19 +1,19 @@ - - -

Tim's Anime List [Manga List]

- + +

Anime Collection [Manga List]

+
$items): ?>

+ +
diff --git a/app/views/anime_edit.php b/app/views/anime/edit.php similarity index 73% rename from app/views/anime_edit.php rename to app/views/anime/edit.php index c90e3aee..fe128b54 100644 --- a/app/views/anime_edit.php +++ b/app/views/anime/edit.php @@ -1,5 +1,5 @@ - +
diff --git a/app/views/anime/list.php b/app/views/anime/list.php new file mode 100644 index 00000000..4dbdf483 --- /dev/null +++ b/app/views/anime/list.php @@ -0,0 +1,34 @@ + +

Anime List [Manga List]

+ +
+ $items): ?> +
+

+
+ + +
+ +
+ + ({$item['anime']['alternate_title']})" : ""; ?> +
+ + +
+
+ +
+
+ +
+ + \ No newline at end of file diff --git a/app/views/anime/nav.php b/app/views/anime/nav.php new file mode 100644 index 00000000..983bbd9e --- /dev/null +++ b/app/views/anime/nav.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/app/views/anime_list.php b/app/views/anime_list.php deleted file mode 100644 index a03d2cbd..00000000 --- a/app/views/anime_list.php +++ /dev/null @@ -1,33 +0,0 @@ - - -

Tim's Anime List [Manga List]

- -
- $items): ?> -
-

-
- - - -
-
- -
- - \ No newline at end of file diff --git a/app/views/anime_nav.php b/app/views/anime_nav.php deleted file mode 100644 index 8b1f433d..00000000 --- a/app/views/anime_nav.php +++ /dev/null @@ -1,11 +0,0 @@ - \ No newline at end of file diff --git a/app/views/manga_list.php b/app/views/manga/list.php similarity index 66% rename from app/views/manga_list.php rename to app/views/manga/list.php index cea9fb74..47d3c9e3 100644 --- a/app/views/manga_list.php +++ b/app/views/manga/list.php @@ -1,28 +1,20 @@ - - - - <?= $title ?> - - - - - -

Tim's Manga List [Anime List]

- + +

Manga List [">Anime List]

+
$items): ?>

+ +
diff --git a/app/views/manga/nav.php b/app/views/manga/nav.php new file mode 100644 index 00000000..fb6d3fcf --- /dev/null +++ b/app/views/manga/nav.php @@ -0,0 +1,7 @@ + \ No newline at end of file diff --git a/app/views/manga_nav.php b/app/views/manga_nav.php deleted file mode 100644 index 30e9a89c..00000000 --- a/app/views/manga_nav.php +++ /dev/null @@ -1,10 +0,0 @@ - \ No newline at end of file diff --git a/index.php b/index.php index 0ce959eb..ad693c2e 100644 --- a/index.php +++ b/index.php @@ -1,20 +1,47 @@ register(); // ----------------------------------------------------------------------------- $router = new Router(); -//$defaultHandler->addDataTable('route', (array)$router->get_route()); +$defaultHandler->addDataTable('route', (array)$router->get_route()); $router->dispatch(); // End of index.php \ No newline at end of file diff --git a/public/css/base.css b/public/css/base.css index de067b09..541693f2 100644 --- a/public/css/base.css +++ b/public/css/base.css @@ -2,6 +2,22 @@ body { margin: 0.5em; } +.round_all { + border-radius:0.5em; +} + +.round_top { + border-radius: 0; + border-top-right-radius:0.5em; + border-top-left-radius:0.5em; +} + +.round_bottom { + border-radius: 0; + border-bottom-right-radius:0.5em; + border-bottom-left-radius:0.5em; +} + .media-wrap { text-align:center; margin:0 auto; @@ -16,9 +32,6 @@ body { height:319px; margin:0.25em; } - .media > img { - border-radius:0.5em; - } .name, .media_type, .airing_status, .user_rating, .completion, .age_rating { text-shadow: 1px 2px 1px rgba(0, 0, 0, 0.85); @@ -27,7 +40,7 @@ body { padding:0.25em; text-align:right; } - + .media_type, .age_rating { text-align:left; } @@ -37,34 +50,22 @@ body { bottom:0; right:0; } - + .media > .medium_metadata { position:absolute; bottom: 0; left:0; } - .media > .media_metadata > .airing_status, - .media > .medium_metadata > .media_type - { - border-top-left-radius: 0.5em; - border-top-right-radius: 0.5em; - } - - .media > .media_metadata > .completion, - .media > .medium_metadata > .age_rating - { - border-bottom-left-radius: 0.5em; - border-bottom-right-radius: 0.5em; - } - .media > .name { - border-radius:0.5em; position:absolute; top: 0; } - .media > .name:hover { + .media:hover > .name, + .media:hover > .media_metadata > div, + .media:hover > .medium_metadata > div + { background:rgba(0,0,0,0.9); } @@ -78,3 +79,28 @@ body { .user_rating::before { content: "Rating: "; } + +/* ----------------------------------------------------------------------------- + Manga-list-specific styles +------------------------------------------------------------------------------*/ + +.manga .media > .name { + padding:0.5em; + margin:1em; +} + +.manga .media { + border:1px solid #ddd; + width:200px; + height:290px; + margin:0.25em; +} + +.manga .completion::before { + content: ""; +} + +.manga .media_metadata { + padding: 0.25em; + margin: 0.75em; +} diff --git a/public/css/manga.css b/public/css/manga.css deleted file mode 100644 index 4c0cdfac..00000000 --- a/public/css/manga.css +++ /dev/null @@ -1,29 +0,0 @@ -.media, -.media > .name, -.media > img, -.media > .media_metadata > .user_rating, -.media > .media_metadata > .completion -{ - border-radius: 0; -} - -.media > .name { - padding:0.5em; - margin:1em; -} - -.media { - border:1px solid #ddd; - width:200px; - height:290px; - margin:0.25em; -} - -.completion::before { - content: ""; -} - -.media_metadata { - padding: 0.25em; - margin: 0.75em; -} \ No newline at end of file