Adición de ficha por peli

This commit is contained in:
perro tuerto 2022-11-15 18:17:04 -08:00
parent a468c37ba0
commit 098cb26fd6
14 changed files with 402 additions and 126 deletions

View File

@ -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

View File

@ -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):

View File

@ -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",

View File

@ -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)

View File

@ -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;
}

View File

@ -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');
});
});
});
}

View File

@ -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)

View File

@ -19,6 +19,7 @@ urlpatterns = [
path("", views.home, name="home"),
path("search/", views.search, name="search"),
# path('movies/<str:args>', views.movies, name='movies'),
path("movie/<int:id>", views.movie, name="movie"),
path("ultimas/rss/", LatestMoviesFeed()),
path("admin/", admin.site.urls),
# path('api/', include(v1_api.urls)),

View File

@ -17,63 +17,10 @@
<p>Otras plataformas tienen todas las películas, excepto las que nos gustan :)</p>
</div>
</section>
<nav class="navbar is-fixed-top" role="navigation" aria-label="main navigation">
<div class="navbar-brand">
<a class="navbar-item" href="{% url 'home' %}">
<img src="{% static 'img/logo-mauflix.png' %}" width="112" height="28">
</a>
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="menu">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="menu" class="navbar-menu">
<div class="navbar-start">
{% if request.get_full_path == "/" %}
<a class="navbar-item" href="{% url 'search' %}">Buscar</a>
{% else %}
<a class="navbar-item" href="{% url 'home' %}">Inicio</a>
{% endif %}
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Más</a>
<div class="navbar-dropdown">
<a class="navbar-item">Acerca</a>
<hr class="navbar-divider">
<a class="navbar-item">Reporta un problema</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">Ingresa</a>
</div>
</div>
</div>
</div>
</nav>
{% include 'nav.html' %}
<section id="main">
{% block content %}{% endblock %}
</section>
<footer class="footer">
<div class="content">
<p><b>BCH</b>:&nbsp;<code>qztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d</code></p>
<p><b>BTC</b>:&nbsp;<code>3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV</code></p>
<p><b>LTC</b>:&nbsp;<code>MBcgQ3LQJA4W2wsXknTdm2fxRSysLaBJHS</code></p>
<p><b>ETH</b>:&nbsp;<code>0x61a4f614a30ff686445751ed8328b82b77ecfc69</code></p>
</div>
<div class="content has-text-centered">
<p>Te recomendamos <a href="https://www.videolan.org/vlc/" target="_blank">VLC</a> para ver tus películas.</p>
</div>
<div class="content has-text-centered">
<p>
Sitio desarrollado con
<a href="https://python.org" target='_blank'>Python</a>,
<a href="https://djangoproject.com/" target='_blank'>Django</a> y
<a href="https://bulma.io/" target='_blank'>Bulma</a>.
</p>
</div>
</footer>
{% include 'footer.html' %}
</body>
</html>

View File

@ -0,0 +1,19 @@
<footer class="footer">
<div class="content">
<p><b>BCH</b>:&nbsp;<code>qztd3l00xle5tffdqvh2snvadkuau2ml0uqm4n875d</code></p>
<p><b>BTC</b>:&nbsp;<code>3FhiXcXmAesmQzrNEngjHFnvaJRhU1AGWV</code></p>
<p><b>LTC</b>:&nbsp;<code>MBcgQ3LQJA4W2wsXknTdm2fxRSysLaBJHS</code></p>
<p><b>ETH</b>:&nbsp;<code>0x61a4f614a30ff686445751ed8328b82b77ecfc69</code></p>
</div>
<div class="content has-text-centered">
<p>Te recomendamos <a href="https://www.videolan.org/vlc/" target="_blank">VLC</a> para ver tus películas.</p>
</div>
<div class="content has-text-centered">
<p>
Sitio desarrollado con
<a href="https://python.org" target='_blank'>Python</a>,
<a href="https://djangoproject.com/" target='_blank'>Django</a> y
<a href="https://bulma.io/" target='_blank'>Bulma</a>.
</p>
</div>
</footer>

View File

@ -0,0 +1,30 @@
<section class="hero {% if request.get_full_path == "/" %}is-fullheight{% else %}is-large{% endif%}">
<div class="hero-head movie-head">
<p class="title">{{ movie.name }}</p>
<p class="stats">
<span>{{ movie.duration }} min</span>
<span>{{ movie.count_formatted }} descargas</span>
<span class="stars">{{ movie.stars_icons }}</span>
</p>
</div>
<div class="hero-body movie-body">
<video controls>
<source src="{{ movie.file_name }}" type="video/mp4">
</video>
</div>
<div class="hero-foot">
<nav class="tabs is-boxed is-fullwidth">
<div class="container">
<ul>
<li><a href="{{ movie.file_name }}" target="_blank" download>Descargar</a></li>
{% if request.get_full_path == "/" %}
<li><a href="/movie/{{ movie.id }}">Detalles</a></li>
{% endif %}
</ul>
</div>
</nav>
</div>
</section>
{% if request.get_full_path != "/" %}
TODO: {{ movie }}
{% endif %}

View File

@ -0,0 +1,4 @@
{% extends "base.html" %}
{% block content %}
{% include 'info.html' with movie=movie %}
{% endblock %}

37
source/templates/nav.html Normal file
View File

@ -0,0 +1,37 @@
<nav id="nav" class="navbar" role="navigation" aria-label="main navigation">
{% load static %}
<div class="navbar-brand">
<a class="navbar-item" href="{% url 'home' %}">
<img src="{% static 'img/logo-mauflix.png' %}" width="112" height="28">
</a>
<a role="button" class="navbar-burger" aria-label="menu" aria-expanded="false" data-target="menu">
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
<span aria-hidden="true"></span>
</a>
</div>
<div id="menu" class="navbar-menu force-display">
<div class="navbar-start">
{% if request.get_full_path == "/" %}
<a class="navbar-item" href="{% url 'search' %}">Buscar</a>
{% else %}
<a class="navbar-item" href="{% url 'home' %}">Inicio</a>
{% endif %}
<div class="navbar-item has-dropdown is-hoverable">
<a class="navbar-link">Más</a>
<div class="navbar-dropdown">
<a class="navbar-item">Acerca</a>
<hr class="navbar-divider">
<a class="navbar-item">Reporta un problema</a>
</div>
</div>
</div>
<div class="navbar-end">
<div class="navbar-item">
<div class="buttons">
<a class="button is-primary">Ingresa</a>
</div>
</div>
</div>
</div>
</nav>

View File

@ -1,13 +1,19 @@
<section class="hero">
<div class="hero-body">
<p class="title">{{ section }}</p>
<div class="columns is-desktop">
<div class="hero-body hero-cartels">
<p class="title"><a href="movies/{{ section }}">{{ section }}<span class="arrows"/></a></p>
<div class="cartels">
{% for movie in content %}
<div class="column">
<figure class="image is-3by4">
<img src="../media/{{ movie.cartel }}">
<div class="cartel">
<input type="checkbox" class="toggle">
<label for="checkbox">×</label>
<div class="info-container">
<div class="info">
{% include 'info.html' with movie=movie %}
</div>
</div>
<figure class="image is-2by3">
<img src="{{ movie.cartel }}">
</figure>
{{ movie }}
</div>
{% endfor %}
</div>