diff --git a/source/main/admin.py b/source/main/admin.py index d431d47..85e25e3 100644 --- a/source/main/admin.py +++ b/source/main/admin.py @@ -87,7 +87,8 @@ class AdminMovie(admin.ModelAdmin): try: server = Mastodon( - access_token=settings.TOKEN_MASTODON, api_base_url=settings.URL_MASTODON + access_token=settings.TOKEN_MASTODON, + api_base_url=settings.URL_MASTODON, ) media = server.media_post(cartel.read(), media_type) @@ -99,7 +100,11 @@ class AdminMovie(admin.ModelAdmin): def _public_telegram(self, message, cartel): url = f"https://api.telegram.org/bot{settings.TOKEN_TELEGRAM}/sendPhoto" url_cartel = settings.URL_CDN.format(cartel) - data = {"chat_id": settings.CHAT_ID, "photo": url_cartel, "caption": message} + data = { + "chat_id": settings.CHAT_ID, + "photo": url_cartel, + "caption": message, + } result = httpx.post(url, data=data).json() return diff --git a/source/main/feeds.py b/source/main/feeds.py index da1005a..5e7cdc0 100644 --- a/source/main/feeds.py +++ b/source/main/feeds.py @@ -17,9 +17,7 @@ class LatestMoviesFeed(Feed): return item.name def item_description(self, item): - message = ( - f"{item.name}, Dirigida por: {item.directors.all()[0]}, Año: {item.year}" - ) + message = f"{item.name}, Dirigida por: {item.directors.all()[0]}, Año: {item.year}" return message def item_link(self, item): diff --git a/source/main/migrations/0001_initial.py b/source/main/migrations/0001_initial.py index 668cdf9..23749fa 100644 --- a/source/main/migrations/0001_initial.py +++ b/source/main/migrations/0001_initial.py @@ -65,11 +65,16 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("name", models.CharField(max_length=500, verbose_name="Nombre")), + ( + "name", + models.CharField(max_length=500, verbose_name="Nombre"), + ), ( "date_born", models.DateField( - blank=True, null=True, verbose_name="Fecha de nacimiento" + blank=True, + null=True, + verbose_name="Fecha de nacimiento", ), ), ( @@ -78,7 +83,9 @@ class Migration(migrations.Migration): ), ( "is_director", - models.BooleanField(default=False, verbose_name="Es Director"), + models.BooleanField( + default=False, verbose_name="Es Director" + ), ), ( "photo", @@ -117,7 +124,10 @@ class Migration(migrations.Migration): verbose_name="ID", ), ), - ("name", models.CharField(max_length=1000, verbose_name="Nombre")), + ( + "name", + models.CharField(max_length=1000, verbose_name="Nombre"), + ), ( "original_name", models.CharField( @@ -138,7 +148,9 @@ class Migration(migrations.Migration): ), ( "year", - models.PositiveSmallIntegerField(default=1900, verbose_name="Año"), + models.PositiveSmallIntegerField( + default=1900, verbose_name="Año" + ), ), ( "duration", @@ -157,7 +169,9 @@ class Migration(migrations.Migration): ), ( "count", - models.PositiveIntegerField(default=0, verbose_name="Descargas"), + models.PositiveIntegerField( + default=0, verbose_name="Descargas" + ), ), ( "stars", diff --git a/source/main/models.py b/source/main/models.py index 5f777d1..ecdf312 100644 --- a/source/main/models.py +++ b/source/main/models.py @@ -70,46 +70,24 @@ class Person(models.Model): class MovieQuerySet(models.QuerySet): - def _to_str(self, q): - return ",".join([r.name for r in q.all()]) - - def _to_link(self, file_name): - # ~ folder = file_name[0].upper() - # ~ if folder.isdigit(): - # ~ folder = '0' - url = settings.URL_CDN.format(file_name) - return url - - def _to_image(self, img, director=""): - if settings.DEBUG: - path = Path(settings.BASE_DIR + img.url) - remote = settings.URL_CDN.format(img.url) - remote = remote.replace("/media/", "") - if not path.exists(): - if not path.parent.exists(): - path.parent.mkdir() - res = requests.get(remote, stream=True) - if res.status_code == 200: - with open(path, "wb") as f: - shutil.copyfileobj(res.raw, f) - url = "" - if director: - url = "../../" - return url + img.url - - def random_pick(self, random_max=5, **kwargs): + def random_pick(self, random_max=6, min_items=20, **kwargs): all = list(Movie.objects.filter(**kwargs).values()) - if len(all) > random_max: - return random.sample(all, random_max) - else: + all = self.fix_all_data(all) + if len(all) < min_items: + return None + elif len(all) < random_max: return all + else: + return random.sample(all, random_max) - def top_pick(self, key, top_max=5): + def top_pick(self, key, top_max=6): all = list(Movie.objects.order_by(f"-{key}").values()) + all = self.fix_all_data(all) return all[:top_max] - def top_random_pick(self, key, top_max=5): + def top_random_pick(self, key, top_max=6): all = list(Movie.objects.order_by(f"-{key}").values()) + all = self.fix_all_data(all) top = [] for movie in all: if movie[key] == all[0][key]: @@ -123,24 +101,53 @@ class MovieQuerySet(models.QuerySet): def home_pick(self): genders = list(Gender.objects.values_list("id", flat=True)) - sections = { + sections = self.home_sections() + for gender in genders: + key = Gender.objects.get(pk=gender).name + picked = self.random_pick(genders=gender) + if picked: + sections["genders"][key] = picked + return sections + + def home_sections(self): + return { "Novedades": self.top_pick("id"), "Mejor valorados": self.top_random_pick("stars"), "Más descargados": self.top_pick("count"), "genders": {}, } - for gender in genders: - key = Gender.objects.get(pk=gender).name - sections["genders"][key] = self.random_pick(genders=gender) - return sections - def get_directors(self): - data = ( - self.distinct() - .values_list("directors__name", flat=True) - .order_by("directors") - ) - return data + def fix_all_data(self, movies): + for movie in movies: + self.fix_data(movie) + return movies + + def fix_data(self, movie): + movie["count_formatted"] = self.set_count(movie["count"]) + movie["stars_icons"] = self.set_stars(movie["stars"]) + movie["file_name"] = self.fix_path(movie["file_name"]) + movie["cartel"] = self.fix_path(movie["cartel"]) + + def fix_path(self, el): + if settings.DEBUG: + return settings.URL_CDN.format(el) + else: + return settings.MEDIA_ROOT / el + + def set_stars(self, num): + stars = "★" * num + while len(stars) < 5: + stars += "☆" + return stars + + def set_count(self, num): + return "{:,}".format(num) + + def get_movie(self, id): + movie = Movie.objects.get(pk=id).__dict__ + movie.pop("_state") + self.fix_data(movie) + return movie def upload_cartel(instance, filename): @@ -171,7 +178,9 @@ class Movie(models.Model): genders = models.ManyToManyField( Gender, related_name="genders", verbose_name="Género", blank=True ) - cartel = models.ImageField("Cartel", upload_to=upload_cartel, null=True, blank=True) + cartel = models.ImageField( + "Cartel", upload_to=upload_cartel, null=True, blank=True + ) count = models.PositiveIntegerField("Descargas", default=0) stars = models.PositiveSmallIntegerField("Estrellas", default=0) published = models.BooleanField("¿Publicar?", default=True) diff --git a/source/main/static/css/main.css b/source/main/static/css/main.css index e0610d4..0c88c01 100644 --- a/source/main/static/css/main.css +++ b/source/main/static/css/main.css @@ -1,4 +1,202 @@ -.navbar.is-fixed-top { +/* BASE */ + +:root { + --color-primary: #375a7f; + --color-background: #343c3d; +} + +#nav { + z-index: 101; +} + +#nav.is-fixed-top { position: sticky; top: -1px; } + +#menu.force-display { + display: flex !important; +} + +/* Cada flecha en los títulos de secciones */ +.arrows { + font-size: 1.5rem; +} + +.arrows:before { + content: " ❯❯"; +} + +/* HOME */ + +/* Cada sección de pelis */ + +.hero-cartels { + margin-bottom: 0; + padding-bottom: 0; +} + +.cartels { + clear: both; + width: calc(100% + 3rem); + margin-left: -1.5rem !important; + padding-left: 0; + display: grid; + align-items: center; + grid-template-columns: repeat(1, 1fr); +} + +@media screen and (min-width: 300px) { + .cartels { + grid-template-columns: repeat(2, 1fr); + } +} + +@media screen and (min-width: 450px) { + .cartels { + grid-template-columns: repeat(3, 1fr); + } +} + +@media screen and (min-width: 600px) { + .cartels { + grid-template-columns: repeat(4, 1fr); + } +} + +@media screen and (min-width: 750px) { + .cartels { + grid-template-columns: repeat(5, 1fr); + } +} + +@media screen and (min-width: 900px) { + .cartels { + grid-template-columns: repeat(6, 1fr); + } +} + +@media screen and (min-width: 1920px) { + .cartels { + width: auto; + margin: 0 !important; + grid-template-columns: repeat(6, 1fr); + } +} + +/* Cada peli */ + +.cartel { + position: relative; + float: left; + min-width: 150px; + min-height: 225px; + max-width: 300px; + max-height: 450px; +} + +.cartel img { + object-fit: cover; +} + +.cartel .info-container { + display: none; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100vh; + background-color: rgba(0,0,0,.5); + z-index: 102; +} + +/* HOME / MOVIE */ + +/* Cada ficha de peli */ + +.movie-head { + padding: 2rem 2rem 0 2rem !important; +} + +.movie-body { + padding: 2rem !important; +} + +.movie-body video { + width: 100%; + height: auto; +} + +.info { + position: fixed; + width: 90%; + height: 90vh; + background-color: var(--color-background); + z-index: 103; +} + +.info .is-fullheight { + height: 100%; + min-height: 100%; +} + +.stats span { + padding-right: 2rem; +} + +.stars { + font-size: 1.5rem; +} + +/* Despliegue de la ficha; Cfr: + * https://stackoverflow.com/questions/42177216/manipulate-css-class-without-javascript + * https://stackoverflow.com/questions/55858255/custom-checkbox-with-css-before-not-working-in-firefox-edge + */ + +.toggle:checked ~ .info-container { + display: flex; + align-items: center; + justify-content: center; +} + +.toggle { + position: absolute; + z-index: 100; + width: 100%; + height: 100%; + opacity: 0; + cursor: pointer; +} + +.toggle + label { + visibility: visible; + content: ""; + display: none; + color: white; + text-align: center; + font-size: 3rem; + background: var(--color-background); + cursor: pointer; +} + +.toggle:checked { + display: block; + visibility: 0; + z-index: 104; +} + +.toggle:checked ~ label { + z-index: 103; + display: flex; + align-items: center; + justify-content: center; +} + +.toggle:checked, +.toggle:checked ~ label { + position: fixed; + top: calc(5vh + 1rem); + right: calc(5vw + 1rem); + width: 2rem; + height: 2rem; +} diff --git a/source/main/static/js/main.js b/source/main/static/js/main.js index e7f351a..8417919 100644 --- a/source/main/static/js/main.js +++ b/source/main/static/js/main.js @@ -1,16 +1,19 @@ -// Para menú en móviles; cfr: https://bulma.io/documentation/components/navbar/#navbar-burger document.addEventListener('DOMContentLoaded', () => { - // Get all "navbar-burger" elements + modMenu(); +}); + +// Habilita el menú de hamburguesa y que esté fijo +function modMenu() { + document.getElementById('nav').classList.add('is-fixed-top'); + document.getElementById('menu').classList.remove('force-display'); + // Cfr: https://bulma.io/documentation/components/navbar/#navbar-burger const $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); - // Add a click event on each of them $navbarBurgers.forEach( el => { el.addEventListener('click', () => { - // Get the target from the "data-target" attribute const target = el.dataset.target; const $target = document.getElementById(target); - // Toggle the "is-active" class on both the "navbar-burger" and the "navbar-menu" el.classList.toggle('is-active'); $target.classList.toggle('is-active'); }); }); -}); +} diff --git a/source/main/views.py b/source/main/views.py index 84b5d25..90ac413 100644 --- a/source/main/views.py +++ b/source/main/views.py @@ -14,3 +14,8 @@ def home(request): def search(request): context = {} return render(request, "search.html", context) + + +def movie(request, id): + context = {"movie": Movie.objects.get_movie(id)} + return render(request, "movie.html", context) diff --git a/source/mauflix/urls.py b/source/mauflix/urls.py index ec8e466..552e4be 100644 --- a/source/mauflix/urls.py +++ b/source/mauflix/urls.py @@ -19,6 +19,7 @@ urlpatterns = [ path("", views.home, name="home"), path("search/", views.search, name="search"), # path('movies/', views.movies, name='movies'), + path("movie/", views.movie, name="movie"), path("ultimas/rss/", LatestMoviesFeed()), path("admin/", admin.site.urls), # path('api/', include(v1_api.urls)), diff --git a/source/templates/base.html b/source/templates/base.html index 11b9800..ed91739 100644 --- a/source/templates/base.html +++ b/source/templates/base.html @@ -17,63 +17,10 @@

Otras plataformas tienen todas las películas, excepto las que nos gustan :)

- + {% include 'nav.html' %}
{% block content %}{% endblock %}
-
-
-

BCHqztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d

-

BTC3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV

-

LTCMBcgQ3LQJA4W2wsXknTdm2fxRSysLaBJHS

-

ETH0x61a4f614a30ff686445751ed8328b82b77ecfc69

-
-
-

Te recomendamos VLC para ver tus películas.

-
-
-

- Sitio desarrollado con - Python, - Django y - Bulma. -

-
-
+ {% include 'footer.html' %} diff --git a/source/templates/footer.html b/source/templates/footer.html new file mode 100644 index 0000000..00e2acd --- /dev/null +++ b/source/templates/footer.html @@ -0,0 +1,19 @@ +
+
+

BCHqztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d

+

BTC3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV

+

LTCMBcgQ3LQJA4W2wsXknTdm2fxRSysLaBJHS

+

ETH0x61a4f614a30ff686445751ed8328b82b77ecfc69

+
+
+

Te recomendamos VLC para ver tus películas.

+
+
+

+ Sitio desarrollado con + Python, + Django y + Bulma. +

+
+
diff --git a/source/templates/info.html b/source/templates/info.html new file mode 100644 index 0000000..c31f76d --- /dev/null +++ b/source/templates/info.html @@ -0,0 +1,30 @@ +
+
+

{{ movie.name }}

+

+ {{ movie.duration }} min + {{ movie.count_formatted }} descargas + {{ movie.stars_icons }} +

+
+
+ +
+
+ +
+
+{% if request.get_full_path != "/" %} + TODO: {{ movie }} +{% endif %} diff --git a/source/templates/movie.html b/source/templates/movie.html new file mode 100644 index 0000000..1d71bc1 --- /dev/null +++ b/source/templates/movie.html @@ -0,0 +1,4 @@ +{% extends "base.html" %} +{% block content %} + {% include 'info.html' with movie=movie %} +{% endblock %} diff --git a/source/templates/nav.html b/source/templates/nav.html new file mode 100644 index 0000000..c69487b --- /dev/null +++ b/source/templates/nav.html @@ -0,0 +1,37 @@ + diff --git a/source/templates/section.html b/source/templates/section.html index 689403e..c71477c 100644 --- a/source/templates/section.html +++ b/source/templates/section.html @@ -1,13 +1,19 @@
-
-

{{ section }}

-
+
+

{{ section }}

+
{% for movie in content %} -
-
- +
+ + +
+
+ {% include 'info.html' with movie=movie %} +
+
+
+
- {{ movie }}
{% endfor %}