2023-04-06 12:48:12 -06:00
|
|
|
import requests
|
2022-11-17 17:51:43 -06:00
|
|
|
import random
|
|
|
|
import time
|
2023-01-20 16:01:45 -06:00
|
|
|
import re
|
2023-02-13 23:08:53 -06:00
|
|
|
from pathlib import Path
|
|
|
|
|
2022-11-17 17:51:43 -06:00
|
|
|
import wikipediaapi
|
|
|
|
from bs4 import BeautifulSoup
|
2020-12-05 19:38:14 -06:00
|
|
|
from django.conf import settings
|
|
|
|
from django.db import models
|
2023-01-20 16:01:45 -06:00
|
|
|
from unidecode import unidecode
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
|
|
|
|
class Gender(models.Model):
|
2021-08-10 21:46:07 -05:00
|
|
|
id = models.AutoField(primary_key=True)
|
2020-12-05 19:38:14 -06:00
|
|
|
name = models.CharField(max_length=250)
|
|
|
|
|
|
|
|
class Meta:
|
2022-11-17 17:51:43 -06:00
|
|
|
unique_together = ["name"]
|
|
|
|
ordering = ["name"]
|
|
|
|
verbose_name = "Género"
|
|
|
|
verbose_name_plural = "Generos"
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
|
|
class Country(models.Model):
|
2021-08-10 21:46:07 -05:00
|
|
|
id = models.AutoField(primary_key=True)
|
2022-11-17 17:51:43 -06:00
|
|
|
name = models.CharField(max_length=250, verbose_name="País")
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
class Meta:
|
2022-11-17 17:51:43 -06:00
|
|
|
unique_together = ["name"]
|
|
|
|
ordering = ["name"]
|
|
|
|
verbose_name = "País"
|
|
|
|
verbose_name_plural = "Paises"
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
|
|
class PersonQuerySet(models.QuerySet):
|
|
|
|
def directors(self):
|
2022-11-17 17:51:43 -06:00
|
|
|
rows = self.filter(is_director=True).values_list("name", flat=True)
|
2020-12-05 19:38:14 -06:00
|
|
|
return rows
|
|
|
|
|
|
|
|
def actors(self):
|
2022-11-17 17:51:43 -06:00
|
|
|
rows = self.filter(is_actor=True).values_list("name", flat=True)
|
2020-12-05 19:38:14 -06:00
|
|
|
return rows
|
|
|
|
|
|
|
|
|
|
|
|
class Person(models.Model):
|
2021-08-10 21:46:07 -05:00
|
|
|
id = models.AutoField(primary_key=True)
|
2022-11-17 17:51:43 -06:00
|
|
|
name = models.CharField("Nombre", max_length=500)
|
|
|
|
country = models.ForeignKey(
|
|
|
|
Country, related_name="country", on_delete=models.PROTECT
|
|
|
|
)
|
|
|
|
date_born = models.DateField("Fecha de nacimiento", null=True, blank=True)
|
|
|
|
is_actor = models.BooleanField("Es Actor", default=False)
|
|
|
|
is_director = models.BooleanField("Es Director", default=False)
|
|
|
|
is_woman = models.BooleanField("Es mujer", default=False)
|
|
|
|
photo = models.ImageField(
|
|
|
|
"Fotografía", upload_to="%Y/%m/%d/", null=True, blank=True
|
|
|
|
)
|
2020-12-05 19:38:14 -06:00
|
|
|
objects = PersonQuerySet.as_manager()
|
|
|
|
|
|
|
|
class Meta:
|
2022-11-17 17:51:43 -06:00
|
|
|
unique_together = ["name"]
|
|
|
|
ordering = ["name"]
|
|
|
|
verbose_name = "Persona"
|
|
|
|
verbose_name_plural = "Personas"
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|
|
|
|
|
|
|
|
|
|
|
|
class MovieQuerySet(models.QuerySet):
|
2023-07-06 17:20:02 -06:00
|
|
|
|
2023-01-20 16:01:45 -06:00
|
|
|
def random_pick(self, random_max=6, min_items=20, all=None, **kwargs):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Regresa películas de manera aleatoria.
|
|
|
|
|
|
|
|
Por defecto tiene que haber al menos 20 películas en la consulta.
|
|
|
|
Por defecto regresa un máximo de 6 películas.
|
|
|
|
"""
|
2023-01-20 16:01:45 -06:00
|
|
|
if all is None:
|
|
|
|
all = list(Movie.objects.filter(**kwargs).values())
|
2022-11-17 17:51:43 -06:00
|
|
|
if len(all) < min_items:
|
|
|
|
return None
|
2023-03-20 12:17:45 -06:00
|
|
|
elif len(all) <= random_max:
|
2022-11-17 17:51:43 -06:00
|
|
|
return all
|
2020-12-05 19:38:14 -06:00
|
|
|
else:
|
2022-11-17 17:51:43 -06:00
|
|
|
return random.sample(all, random_max)
|
|
|
|
|
|
|
|
def top_pick(self, key, top_max=6):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Regresa el top de películas.
|
|
|
|
|
|
|
|
El top corresponde al criterio de búsqueda en 'key'.
|
|
|
|
Por defecto regresa las primeras 6 películas como máximo.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
all = list(Movie.objects.order_by(f"-{key}").values())
|
2023-01-20 16:01:45 -06:00
|
|
|
return self.fix_all(all[:top_max])
|
2022-11-17 17:51:43 -06:00
|
|
|
|
|
|
|
def top_random_pick(self, key, top_max=6):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Regresa el top de películas de manera aleatorias.
|
|
|
|
|
|
|
|
El top corresponde al criterio de búsqueda en 'key'.
|
|
|
|
Por defecto regresa un máximo de 6 películas.
|
|
|
|
A diferencia de 'random_pick', de todo el top selecciona de manera
|
|
|
|
aleatoria según el 'top_max'.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
all = list(Movie.objects.order_by(f"-{key}").values())
|
|
|
|
top = []
|
|
|
|
for movie in all:
|
|
|
|
if movie[key] == all[0][key]:
|
|
|
|
top.append(movie)
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
if len(top) > top_max:
|
2023-01-20 16:01:45 -06:00
|
|
|
movies = random.sample(top, top_max)
|
2022-11-17 17:51:43 -06:00
|
|
|
else:
|
2023-01-20 16:01:45 -06:00
|
|
|
movies = top
|
|
|
|
return self.fix_all(movies)
|
2022-11-17 17:51:43 -06:00
|
|
|
|
|
|
|
def home_pick(self):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Regresa la selección de películas para el 'home'.
|
|
|
|
|
2022-12-21 21:46:45 -06:00
|
|
|
El 'home' es la página principal.
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
genders = list(Gender.objects.values_list("id", flat=True))
|
|
|
|
sections = self.home_sections()
|
|
|
|
for gender in genders:
|
|
|
|
key = Gender.objects.get(pk=gender).name
|
|
|
|
picked = self.random_pick(genders=gender)
|
|
|
|
if picked:
|
2023-01-09 19:41:36 -06:00
|
|
|
sections["genders"][key] = self.fix_all(picked)
|
2022-11-17 17:51:43 -06:00
|
|
|
return sections
|
|
|
|
|
|
|
|
def home_sections(self):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Regresa la selección de películas en secciones para el 'home'.
|
|
|
|
|
|
|
|
Las secciones son novedades, mejor valorados y más descargados.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
sections = {
|
2023-01-20 16:01:45 -06:00
|
|
|
"Novedades": self.top_pick("id"),
|
|
|
|
"Mejor valorados": self.top_random_pick("stars"),
|
|
|
|
"Más descargados": self.top_pick("count"),
|
2022-11-17 17:51:43 -06:00
|
|
|
}
|
|
|
|
sections["genders"] = {}
|
|
|
|
return sections
|
|
|
|
|
2023-01-09 19:41:36 -06:00
|
|
|
def fix_all(self, movies):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Enmienda los datos de las películas.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
for movie in movies:
|
|
|
|
self.fix_data(movie, wikipedia=False)
|
|
|
|
return movies
|
|
|
|
|
|
|
|
def fix_data(self, movie, wikipedia=True):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Enmienda los datos de una película.
|
|
|
|
|
|
|
|
Los enmiendos son formateos de unos valores (que se guardan en nuevas
|
|
|
|
llaves) y de rutas a medios.
|
|
|
|
"""
|
2023-01-20 16:01:45 -06:00
|
|
|
if len(movie["file_name"]) == 0 or len(movie["cartel"]) == 0:
|
|
|
|
print(f"WARN: película sin ruta de video o cartel:\n{movie}")
|
2022-11-17 17:51:43 -06:00
|
|
|
movie["duration_formatted"] = self.format_duration(movie["duration"])
|
|
|
|
movie["count_formatted"] = self.format_count(movie["count"])
|
|
|
|
movie["stars_icons"] = self.format_stars(movie["stars"])
|
2023-02-13 23:08:53 -06:00
|
|
|
movie["file_name"] = self._fix_path_movie(movie["file_name"])
|
2023-03-20 12:17:45 -06:00
|
|
|
movie["cartel"] = self._fix_path_cartel(movie["cartel"])
|
2022-11-17 17:51:43 -06:00
|
|
|
if wikipedia:
|
|
|
|
movie["wiki"] = self.get_wiki(movie)
|
|
|
|
|
2023-02-13 23:08:53 -06:00
|
|
|
def _fix_path_movie(self, file_name):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Enmienda ruta a medio.
|
|
|
|
"""
|
2023-02-12 23:37:38 -06:00
|
|
|
if not file_name:
|
2023-03-20 12:17:45 -06:00
|
|
|
return ""
|
2023-02-12 23:37:38 -06:00
|
|
|
|
2023-02-12 23:18:47 -06:00
|
|
|
letter = file_name[0].upper()
|
|
|
|
if letter.isdigit():
|
2023-03-20 12:17:45 -06:00
|
|
|
letter = "0"
|
2023-02-12 23:18:47 -06:00
|
|
|
url = f"{settings.URL_CDN}/{letter}/{file_name}"
|
|
|
|
return url
|
2022-11-17 17:51:43 -06:00
|
|
|
|
2023-02-13 23:08:53 -06:00
|
|
|
def _fix_path_cartel(self, file_name):
|
2023-03-20 12:17:45 -06:00
|
|
|
"""Si no existe el cartel regresa el default"""
|
2023-02-13 23:08:53 -06:00
|
|
|
url = f"{settings.MEDIA_URL}{file_name}"
|
|
|
|
|
|
|
|
path = Path(f"{settings.MEDIA_ROOT}{file_name}")
|
|
|
|
if not path.exists():
|
|
|
|
url = f"{settings.MEDIA_URL}default.png"
|
|
|
|
|
|
|
|
return url
|
|
|
|
|
2022-11-17 17:51:43 -06:00
|
|
|
def fix_summ(self, raw):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Enmienda sinopsis de Wikipedia.
|
|
|
|
|
|
|
|
Los sumarios de artículos a la Wikipedia vienen con notas al pie que no
|
2023-01-09 19:41:36 -06:00
|
|
|
son necesarias. Para la sinopsis estas notas son eliminadas y se
|
|
|
|
regresa el código HTML como una cadena de caracteres.
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
html = BeautifulSoup(raw, "lxml")
|
|
|
|
for ref in html.find_all("sup", "reference"):
|
|
|
|
ref.decompose()
|
2023-01-20 17:31:07 -06:00
|
|
|
for crossref in html.find_all("dl"):
|
|
|
|
crossref.decompose()
|
2022-11-17 17:51:43 -06:00
|
|
|
clean = list(map(lambda x: str(x), html.body.children))
|
|
|
|
return " ".join(clean)
|
|
|
|
|
|
|
|
def format_stars(self, num):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Da formato a la cantidad de estrellas.
|
|
|
|
|
|
|
|
Regresa la cantidad de estrellas en lugar del número de estas.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
stars = "★" * num
|
|
|
|
while len(stars) < 5:
|
|
|
|
stars += "☆"
|
|
|
|
return stars
|
|
|
|
|
|
|
|
def format_count(self, num):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Da formato a la cantidad de descargas.
|
|
|
|
|
|
|
|
Regresa la cantidad en una cifra separada por comas.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
return "{:,}".format(num)
|
|
|
|
|
|
|
|
def format_duration(self, num):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Da formato a duración.
|
|
|
|
|
2023-01-10 13:21:12 -06:00
|
|
|
Regresa la duración en 'Nh Nm'; p. ej.: 1h 22m, 2h, 15m.
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
secs = num * 60
|
2023-01-10 13:21:12 -06:00
|
|
|
hours = self.format_duration_num("%H", secs)
|
|
|
|
mins = self.format_duration_num("%M", secs)
|
|
|
|
if hours == "":
|
|
|
|
return mins
|
|
|
|
elif mins == "":
|
|
|
|
return hours
|
|
|
|
else:
|
|
|
|
return f"{hours} {mins}"
|
|
|
|
|
|
|
|
def format_duration_num(self, num_type, secs):
|
|
|
|
"""
|
|
|
|
Da formato a cada número de la duración.
|
|
|
|
|
|
|
|
Extrae hora o minuto de la duración, la pasa a int y si no es cero,
|
|
|
|
regresa Ns; p. ej.: 1h, 55m.
|
|
|
|
"""
|
|
|
|
num = int(time.strftime(num_type, time.gmtime(secs)))
|
|
|
|
sym = num_type[-1].lower()
|
|
|
|
if num == 0:
|
|
|
|
return ""
|
|
|
|
else:
|
|
|
|
return f"{num}{sym}"
|
2022-11-17 17:51:43 -06:00
|
|
|
|
2023-04-06 12:48:12 -06:00
|
|
|
def get_subs(self, id):
|
|
|
|
"""
|
|
|
|
Obtiene subtítulos de película por id.
|
|
|
|
|
|
|
|
TODO: en la restructuración de la DB no debería hacer requests.
|
|
|
|
"""
|
2023-04-09 21:43:36 -06:00
|
|
|
file_name = Movie.objects.get(pk=id).file_name
|
|
|
|
if not file_name:
|
|
|
|
return []
|
|
|
|
|
|
|
|
letter = file_name[0].upper()
|
|
|
|
if letter.isdigit():
|
|
|
|
letter = "0"
|
|
|
|
|
|
|
|
url_base = f"{settings.URL_CDN}/{letter}"
|
|
|
|
base_name = Path(file_name).stem
|
|
|
|
|
2023-04-06 12:48:12 -06:00
|
|
|
subs = []
|
2023-04-09 21:43:36 -06:00
|
|
|
for k, v in settings.LANG_SUBTITLES.items():
|
2023-07-06 16:40:55 -06:00
|
|
|
url_sub = f'{url_base}/{base_name}.{k}.vtt'
|
2023-04-09 21:43:36 -06:00
|
|
|
response = requests.get(url_sub)
|
|
|
|
if response.status_code==200:
|
2023-04-09 22:17:23 -06:00
|
|
|
v['path'] = url_sub
|
2023-04-09 21:43:36 -06:00
|
|
|
subs.append(v)
|
|
|
|
|
2023-04-06 12:48:12 -06:00
|
|
|
return subs
|
|
|
|
|
2022-11-17 17:51:43 -06:00
|
|
|
def get_wiki(self, movie, again=True):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Obtiene artículo de Wikipedia.
|
|
|
|
|
|
|
|
Primero intenta obtener el artículo por el nombre original. Si no tiene
|
|
|
|
éxito, intenta obtenerlo por el nombre en español. Regresa None si no
|
|
|
|
tuvo ningún éxito.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
wiki = self.get_wiki_page(movie["original_name"])
|
|
|
|
if not wiki:
|
|
|
|
wiki = self.get_wiki_page(movie["name"])
|
|
|
|
return wiki
|
|
|
|
|
|
|
|
def get_wiki_page(self, title):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Intenta obtener artículo de Wikipedia.
|
|
|
|
|
|
|
|
Si no tiene éxito, regresa 'None'.
|
|
|
|
"""
|
2022-11-17 17:51:43 -06:00
|
|
|
try:
|
|
|
|
lang = settings.LANGUAGE_CODE.split("-")[0]
|
|
|
|
wiki = wikipediaapi.Wikipedia(
|
|
|
|
lang, extract_format=wikipediaapi.ExtractFormat.HTML
|
|
|
|
)
|
|
|
|
page = wiki.page(title)
|
|
|
|
if page.exists():
|
|
|
|
return {
|
|
|
|
"title": page.title,
|
|
|
|
"url": page.fullurl,
|
|
|
|
"summary": self.fix_summ(page.summary),
|
|
|
|
}
|
|
|
|
else:
|
|
|
|
return None
|
2023-01-09 19:41:36 -06:00
|
|
|
except Exception:
|
2022-11-17 17:51:43 -06:00
|
|
|
return None
|
|
|
|
|
2023-01-20 16:01:45 -06:00
|
|
|
def get_related(self):
|
|
|
|
"""
|
|
|
|
Regresa los campos relacionados a las películas.
|
|
|
|
"""
|
|
|
|
return ["countries", "genders", "directors", "actors"]
|
|
|
|
|
2022-12-08 20:18:26 -06:00
|
|
|
def get_movie_by_id(self, id):
|
|
|
|
"""
|
|
|
|
Obtiene película por id.
|
|
|
|
|
|
|
|
Esta obtención también añade objetos relacionados.
|
|
|
|
"""
|
2023-01-20 16:01:45 -06:00
|
|
|
related = self.get_related()
|
2022-12-08 20:18:26 -06:00
|
|
|
movie = Movie.objects.prefetch_related(*related).get(pk=id).__dict__
|
2023-01-20 16:01:45 -06:00
|
|
|
for key, val in movie["_prefetched_objects_cache"].items():
|
|
|
|
movie[key] = list(map(lambda x: x["name"], val.values()))
|
2022-11-17 17:51:43 -06:00
|
|
|
movie.pop("_state")
|
2022-12-08 20:18:26 -06:00
|
|
|
movie.pop("_prefetched_objects_cache")
|
2022-11-17 17:51:43 -06:00
|
|
|
self.fix_data(movie)
|
|
|
|
return movie
|
2020-12-05 19:38:14 -06:00
|
|
|
|
2023-01-20 16:01:45 -06:00
|
|
|
def get_movies(self, query):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
Obtiene películas buscadas.
|
2023-01-20 16:01:45 -06:00
|
|
|
"""
|
|
|
|
movies = Movie.objects.prefetch_related(*self.get_related())
|
|
|
|
for q in self.get_queries(query):
|
|
|
|
selector = None
|
|
|
|
if re.match(r"^\w:", q) is not None:
|
|
|
|
selector = self.get_selector(re.sub(r"^(\w):.*", r"\1", q))
|
|
|
|
q = re.sub(r"^\w:(.*)", r"\1", q)
|
|
|
|
movies = self.get_movies_by_query(selector, q, movies)
|
|
|
|
if len(movies) != len(Movie.objects.all()):
|
|
|
|
if hasattr(movies, "values"):
|
|
|
|
movies = self.fix_all(list(movies.values()))
|
|
|
|
movies = self.random_pick(random_max=100, min_items=0, all=movies)
|
|
|
|
return movies
|
|
|
|
else:
|
|
|
|
return []
|
|
|
|
|
|
|
|
def get_movies_by_query(self, selector, query, movies):
|
|
|
|
"""
|
|
|
|
Obtiene película por query.
|
|
|
|
"""
|
|
|
|
if selector is None:
|
|
|
|
return self.get_movies_by_query_any(query, movies)
|
|
|
|
elif selector != "section":
|
|
|
|
return self.get_movies_by_query_selector(selector, query, movies)
|
|
|
|
else:
|
|
|
|
return self.get_movies_by_query_section(query, movies)
|
2022-12-08 20:18:26 -06:00
|
|
|
|
2023-01-20 16:01:45 -06:00
|
|
|
def get_movies_by_query_selector(self, selector, query, movies):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
2023-01-20 16:01:45 -06:00
|
|
|
Obtiene película por query que tiene selector 'w:'.
|
|
|
|
"""
|
|
|
|
if selector == "year":
|
|
|
|
selector = f"{selector}__iregex"
|
|
|
|
try:
|
|
|
|
query = int(query)
|
|
|
|
except Exception:
|
|
|
|
query = 0
|
|
|
|
else:
|
|
|
|
if selector == "name" or selector == "original_name":
|
|
|
|
selector = f"{selector}__unaccent__iregex"
|
|
|
|
else:
|
|
|
|
selector = f"{selector}__name__unaccent__iregex"
|
|
|
|
query = f"[[:<:]]{query}"
|
|
|
|
kwargs = {selector: query}
|
|
|
|
return movies.filter(**kwargs)
|
2022-12-08 20:18:26 -06:00
|
|
|
|
2023-01-20 16:01:45 -06:00
|
|
|
def get_movies_by_query_section(self, query, movies):
|
|
|
|
"""
|
|
|
|
Obtiene película por query que tiene selector 'w:' para sección.
|
|
|
|
"""
|
|
|
|
if query == "mejor valorados":
|
|
|
|
return self.top_random_pick("stars", top_max=100)
|
|
|
|
elif query == "novedades":
|
|
|
|
return self.top_pick("id", top_max=100)
|
|
|
|
elif query == "mas descargados":
|
|
|
|
return self.top_pick("count", top_max=100)
|
|
|
|
else:
|
|
|
|
return list(movies.values())
|
|
|
|
|
|
|
|
def get_movies_by_query_any(self, query, movies):
|
|
|
|
"""
|
|
|
|
Obtiene película por query que no tiene ningún selector.
|
|
|
|
"""
|
|
|
|
for field in ["name"] + self.get_related():
|
|
|
|
if field != "name":
|
|
|
|
field = f"{field}__name"
|
|
|
|
kwargs = {f"{field}__unaccent__iregex": f"[[:<:]]{query}"}
|
|
|
|
result = movies.filter(**kwargs)
|
|
|
|
if len(result) > 0:
|
|
|
|
movies = result
|
|
|
|
return movies
|
|
|
|
|
|
|
|
def get_queries(self, query):
|
|
|
|
"""
|
|
|
|
Devuelve un conjunto de queries sanitizado; p. ej.:
|
|
|
|
de: d:Bruno--Stagñaro y:1997 pizzá, birra, faso
|
|
|
|
a: ['d:bruno-stagnaro', 'y:1997', 'pizza', 'birra', 'faso']
|
|
|
|
"""
|
|
|
|
queries = re.sub(r"\s+", " ", unidecode(str(query)).lower()).split()
|
|
|
|
return list(map(lambda q: self.clean_query(q), queries))
|
|
|
|
|
|
|
|
def clean_query(self, word):
|
|
|
|
"""
|
|
|
|
Limpia query de caracteres 'W' al inicio y al final. También sustituye
|
|
|
|
'-' por un espacio.
|
|
|
|
"""
|
|
|
|
word = re.sub(r"^\W+", "", word)
|
|
|
|
word = re.sub(r"\W+$", "", word)
|
|
|
|
word = re.sub(r"-+", " ", word)
|
|
|
|
return word
|
|
|
|
|
|
|
|
def get_selector(self, prefix):
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
2022-12-21 21:46:45 -06:00
|
|
|
Obtiene el selector para filtrar la consulta de una búsqueda.
|
2022-12-08 20:18:26 -06:00
|
|
|
|
|
|
|
Esto permite restricciones en la búsqueda con esta sintaxis:
|
2023-01-20 16:01:45 -06:00
|
|
|
* t:Un-Título => Buscará las películas que tengan 'Un T…' en sus 'name'
|
2022-12-08 20:18:26 -06:00
|
|
|
* d:Nombre => Buscará las películas que tengan 'N…' en sus 'directors'
|
2023-01-20 16:01:45 -06:00
|
|
|
El guion (-) se usa como separador de palabras, puede contener acentos
|
|
|
|
o eñe, aunque va a ser decodificado.
|
2022-12-08 20:18:26 -06:00
|
|
|
"""
|
|
|
|
prefixes = {
|
2023-01-20 16:01:45 -06:00
|
|
|
"t": "name",
|
|
|
|
"o": "original_name",
|
|
|
|
"y": "year",
|
|
|
|
"c": "countries",
|
|
|
|
"p": "countries",
|
|
|
|
"d": "directors",
|
|
|
|
"a": "actors",
|
|
|
|
"g": "genders",
|
|
|
|
"s": "section",
|
2022-12-08 20:18:26 -06:00
|
|
|
}
|
|
|
|
if prefix in prefixes:
|
|
|
|
return prefixes[prefix]
|
|
|
|
else:
|
2023-01-20 16:01:45 -06:00
|
|
|
return None
|
2022-12-08 20:18:26 -06:00
|
|
|
|
2023-01-20 17:31:07 -06:00
|
|
|
def api(self, request):
|
|
|
|
"""
|
|
|
|
Obtiene resultados de la API.
|
|
|
|
"""
|
|
|
|
msg = f"Vista {request.get_host()}/help/#api para más información."
|
|
|
|
result = {"ERROR": msg}
|
|
|
|
try:
|
|
|
|
if request.GET.get("q"):
|
|
|
|
query = request.GET["q"]
|
|
|
|
result = {"movies": Movie.objects.get_movies(query)}
|
|
|
|
elif request.GET.get("id"):
|
|
|
|
query = request.GET["id"]
|
|
|
|
result = {"movie": Movie.objects.get_movie_by_id(query)}
|
|
|
|
else:
|
|
|
|
result["Exception"] = f"Invalid {request.GET}"
|
|
|
|
except Exception:
|
|
|
|
result["Exception"] = f"Invalid {request.GET}"
|
|
|
|
if request.user.is_authenticated:
|
|
|
|
return result
|
|
|
|
else:
|
|
|
|
return self.clean_api_response(result)
|
|
|
|
|
|
|
|
def clean_api_response(self, result):
|
|
|
|
"""
|
|
|
|
Elimina la URL de la película para usuarios no autenticados.
|
|
|
|
"""
|
|
|
|
url = "file_name"
|
|
|
|
if "movies" in result:
|
|
|
|
for movie in result["movies"]:
|
|
|
|
del movie[url]
|
|
|
|
elif "movie" in result:
|
|
|
|
del result["movie"][url]
|
|
|
|
return result
|
|
|
|
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
def upload_cartel(instance, filename):
|
|
|
|
first = filename[0].upper()
|
|
|
|
if first.isdigit():
|
2022-11-17 17:51:43 -06:00
|
|
|
first = "0"
|
|
|
|
return f"{first}/{filename}"
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
|
|
|
|
class Movie(models.Model):
|
2021-08-10 21:46:07 -05:00
|
|
|
id = models.AutoField(primary_key=True)
|
2022-11-17 17:51:43 -06:00
|
|
|
name = models.CharField("Nombre", max_length=1000)
|
|
|
|
original_name = models.CharField(
|
|
|
|
"Nombre original", max_length=1000, default="", blank=True
|
|
|
|
)
|
|
|
|
file_name = models.CharField(
|
|
|
|
"Nombre archivo", max_length=1000, default="", blank=True
|
|
|
|
)
|
|
|
|
year = models.PositiveSmallIntegerField("Año", default=1900)
|
|
|
|
duration = models.PositiveSmallIntegerField("Duración", default=0)
|
|
|
|
directors = models.ManyToManyField(
|
|
|
|
Person, verbose_name="Director", related_name="directors"
|
|
|
|
)
|
|
|
|
actors = models.ManyToManyField(Person, related_name="actors", blank=True)
|
|
|
|
countries = models.ManyToManyField(
|
|
|
|
Country, related_name="countries", verbose_name="País", blank=True
|
|
|
|
)
|
|
|
|
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
|
|
|
|
)
|
|
|
|
count = models.PositiveIntegerField("Descargas", default=0)
|
|
|
|
stars = models.PositiveSmallIntegerField("Estrellas", default=0)
|
|
|
|
published = models.BooleanField("¿Publicar?", default=True)
|
|
|
|
is_digital = models.BooleanField("Es digital", default=False)
|
2020-12-05 19:38:14 -06:00
|
|
|
objects = MovieQuerySet.as_manager()
|
|
|
|
|
|
|
|
class Meta:
|
2022-11-17 17:51:43 -06:00
|
|
|
unique_together = ["name", "original_name"]
|
|
|
|
ordering = ["name"]
|
|
|
|
verbose_name = "Película"
|
|
|
|
verbose_name_plural = "Películas"
|
2020-12-05 19:38:14 -06:00
|
|
|
|
|
|
|
def __str__(self):
|
|
|
|
return self.name
|