diff --git a/source/main/feeds.py b/source/main/feeds.py
index 5e7cdc0..0413475 100644
--- a/source/main/feeds.py
+++ b/source/main/feeds.py
@@ -21,4 +21,4 @@ class LatestMoviesFeed(Feed):
return message
def item_link(self, item):
- return reverse("movies", args=[item.pk])
+ return reverse("movie", args=[item.pk])
diff --git a/source/main/models.py b/source/main/models.py
index 70be90f..7ee9f1c 100644
--- a/source/main/models.py
+++ b/source/main/models.py
@@ -1,6 +1,8 @@
import random
import time
import re
+from pathlib import Path
+
import wikipediaapi
from bs4 import BeautifulSoup
from django.conf import settings
@@ -170,24 +172,34 @@ class MovieQuerySet(models.QuerySet):
movie["duration_formatted"] = self.format_duration(movie["duration"])
movie["count_formatted"] = self.format_count(movie["count"])
movie["stars_icons"] = self.format_stars(movie["stars"])
- movie["file_name"] = self.fix_path(movie["file_name"])
- movie["cartel"] = self.fix_path(movie["cartel"])
+ movie["file_name"] = self._fix_path_movie(movie["file_name"])
+ movie["cartel"] = self._fix_path_cartel(movie['cartel'])
if wikipedia:
movie["wiki"] = self.get_wiki(movie)
- def fix_path(self, el):
+ def _fix_path_movie(self, file_name):
"""
Enmienda ruta a medio.
-
- La ruta es distinta según se esté en producción o en desarrollo
- ('DEBUG'). La URL_DEBUB apunta a la dirección en nebula.
"""
- if settings.DEBUG:
- if str(Path(el).parent) == "." and len(el) > 0:
- el = f"{el[0]}/{el}"
- return settings.URL_DEBUG.format(el)
- else:
- return settings.MEDIA_ROOT / el
+ if not file_name:
+ return ''
+
+ letter = file_name[0].upper()
+ if letter.isdigit():
+ letter = '0'
+ url = f"{settings.URL_CDN}/{letter}/{file_name}"
+ return url
+
+ def _fix_path_cartel(self, file_name):
+ """ Si no existe el cartel regresa el default """
+ 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
+
def fix_summ(self, raw):
"""
diff --git a/source/mauflix/settings.py b/source/mauflix/settings.py
index 35160b8..b2a6cfc 100644
--- a/source/mauflix/settings.py
+++ b/source/mauflix/settings.py
@@ -21,6 +21,7 @@ from .conf import (
TOKEN_TELEGRAM,
CHAT_ID,
API_TOKEN,
+ URL_CDN,
URL_DEBUG,
)
@@ -144,5 +145,4 @@ DISALLOWED_USER_AGENTS = (
SESSION_EXPIRE_AT_BROWSER_CLOSE = True
SESSION_COOKIE_AGE = 3600
-URL_CDN = "https://mauflix.cuates.net/{}"
URL_MASTODON = "https://mstdn.mx/"
diff --git a/source/static/admin/css/dark_mode.css b/source/static/admin/css/dark_mode.css
new file mode 100644
index 0000000..547717c
--- /dev/null
+++ b/source/static/admin/css/dark_mode.css
@@ -0,0 +1,33 @@
+@media (prefers-color-scheme: dark) {
+ :root {
+ --primary: #264b5d;
+ --primary-fg: #f7f7f7;
+
+ --body-fg: #eeeeee;
+ --body-bg: #121212;
+ --body-quiet-color: #e0e0e0;
+ --body-loud-color: #ffffff;
+
+ --breadcrumbs-link-fg: #e0e0e0;
+ --breadcrumbs-bg: var(--primary);
+
+ --link-fg: #81d4fa;
+ --link-hover-color: #4ac1f7;
+ --link-selected-fg: #6f94c6;
+
+ --hairline-color: #272727;
+ --border-color: #353535;
+
+ --error-fg: #e35f5f;
+ --message-success-bg: #006b1b;
+ --message-warning-bg: #583305;
+ --message-error-bg: #570808;
+
+ --darkened-bg: #212121;
+ --selected-bg: #1b1b1b;
+ --selected-row: #00363a;
+
+ --close-button-bg: #333333;
+ --close-button-hover-bg: #666666;
+ }
+ }
diff --git a/source/static/admin/js/SelectFilter2.js b/source/static/admin/js/SelectFilter2.js
index 6c709a0..194c2db 100644
--- a/source/static/admin/js/SelectFilter2.js
+++ b/source/static/admin/js/SelectFilter2.js
@@ -153,24 +153,6 @@ Requires core.js and SelectBox.js.
// Move selected from_box options to to_box
SelectBox.move(field_id + '_from', field_id + '_to');
- if (!is_stacked) {
- // In horizontal mode, give the same height to the two boxes.
- const j_from_box = document.getElementById(field_id + '_from');
- const j_to_box = document.getElementById(field_id + '_to');
- let height = filter_p.offsetHeight + j_from_box.offsetHeight;
-
- const j_to_box_style = window.getComputedStyle(j_to_box);
- if (j_to_box_style.getPropertyValue('box-sizing') === 'border-box') {
- // Add the padding and border to the final height.
- height += parseInt(j_to_box_style.getPropertyValue('padding-top'), 10)
- + parseInt(j_to_box_style.getPropertyValue('padding-bottom'), 10)
- + parseInt(j_to_box_style.getPropertyValue('border-top-width'), 10)
- + parseInt(j_to_box_style.getPropertyValue('border-bottom-width'), 10);
- }
-
- j_to_box.style.height = height + 'px';
- }
-
// Initial icon refresh
SelectFilter.refresh_icons(field_id);
},
diff --git a/source/static/admin/js/filters.js b/source/static/admin/js/filters.js
new file mode 100644
index 0000000..ba691ac
--- /dev/null
+++ b/source/static/admin/js/filters.js
@@ -0,0 +1,30 @@
+/**
+ * Persist changelist filters state (collapsed/expanded).
+ */
+'use strict';
+{
+ // Init filters.
+ let filters = JSON.parse(sessionStorage.getItem('django.admin.filtersState'));
+
+ if (!filters) {
+ filters = {};
+ }
+
+ Object.entries(filters).forEach(([key, value]) => {
+ const detailElement = document.querySelector(`[data-filter-title='${key}']`);
+
+ // Check if the filter is present, it could be from other view.
+ if (detailElement) {
+ value ? detailElement.setAttribute('open', '') : detailElement.removeAttribute('open');
+ }
+ });
+
+ // Save filter state when clicks.
+ const details = document.querySelectorAll('details');
+ details.forEach(detail => {
+ detail.addEventListener('toggle', event => {
+ filters[`${event.target.dataset.filterTitle}`] = detail.open;
+ sessionStorage.setItem('django.admin.filtersState', JSON.stringify(filters));
+ });
+ });
+}
diff --git a/source/static/admin/js/inlines.js b/source/static/admin/js/inlines.js
index 82ec027..e9a1dfe 100644
--- a/source/static/admin/js/inlines.js
+++ b/source/static/admin/js/inlines.js
@@ -88,7 +88,12 @@
if (options.added) {
options.added(row);
}
- $(document).trigger('formset:added', [row, options.prefix]);
+ row.get(0).dispatchEvent(new CustomEvent("formset:added", {
+ bubbles: true,
+ detail: {
+ formsetName: options.prefix
+ }
+ }));
};
/**
@@ -130,7 +135,11 @@
if (options.removed) {
options.removed(row);
}
- $(document).trigger('formset:removed', [row, options.prefix]);
+ document.dispatchEvent(new CustomEvent("formset:removed", {
+ detail: {
+ formsetName: options.prefix
+ }
+ }));
// Update the TOTAL_FORMS form count.
const forms = $("." + options.formCssClass);
$("#id_" + options.prefix + "-TOTAL_FORMS").val(forms.length);
@@ -218,12 +227,10 @@
// instantiate a new SelectFilter instance for it.
if (typeof SelectFilter !== 'undefined') {
$('.selectfilter').each(function(index, value) {
- const namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], false);
+ SelectFilter.init(value.id, this.dataset.fieldName, false);
});
$('.selectfilterstacked').each(function(index, value) {
- const namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], true);
+ SelectFilter.init(value.id, this.dataset.fieldName, true);
});
}
};
@@ -283,12 +290,10 @@
// If any SelectFilter widgets were added, instantiate a new instance.
if (typeof SelectFilter !== "undefined") {
$(".selectfilter").each(function(index, value) {
- const namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], false);
+ SelectFilter.init(value.id, this.dataset.fieldName, false);
});
$(".selectfilterstacked").each(function(index, value) {
- const namearr = value.name.split('-');
- SelectFilter.init(value.id, namearr[namearr.length - 1], true);
+ SelectFilter.init(value.id, this.dataset.fieldName, true);
});
}
};
@@ -300,7 +305,13 @@
dependency_list = input.data('dependency_list') || [],
dependencies = [];
$.each(dependency_list, function(i, field_name) {
- dependencies.push('#' + row.find('.form-row .field-' + field_name).find('input, select, textarea').attr('id'));
+ // Dependency in a fieldset.
+ let field_element = row.find('.form-row .field-' + field_name);
+ // Dependency without a fieldset.
+ if (!field_element.length) {
+ field_element = row.find('.form-row.field-' + field_name);
+ }
+ dependencies.push('#' + field_element.find('input, select, textarea').attr('id'));
});
if (dependencies.length) {
input.prepopulate(dependencies, input.attr('maxlength'));
diff --git a/source/static/admin/js/nav_sidebar.js b/source/static/admin/js/nav_sidebar.js
index efaa721..261a9d4 100644
--- a/source/static/admin/js/nav_sidebar.js
+++ b/source/static/admin/js/nav_sidebar.js
@@ -13,6 +13,12 @@
navLink.tabIndex = 0;
}
}
+ function disableNavFilterTabbing() {
+ document.getElementById('nav-filter').tabIndex = -1;
+ }
+ function enableNavFilterTabbing() {
+ document.getElementById('nav-filter').tabIndex = 0;
+ }
const main = document.getElementById('main');
let navSidebarIsOpen = localStorage.getItem('django.admin.navSidebarIsOpen');
@@ -21,6 +27,7 @@
}
if (navSidebarIsOpen === 'false') {
disableNavLinkTabbing();
+ disableNavFilterTabbing();
}
main.classList.toggle('shifted', navSidebarIsOpen === 'true');
@@ -28,12 +35,68 @@
if (navSidebarIsOpen === 'true') {
navSidebarIsOpen = 'false';
disableNavLinkTabbing();
+ disableNavFilterTabbing();
} else {
navSidebarIsOpen = 'true';
enableNavLinkTabbing();
+ enableNavFilterTabbing();
}
localStorage.setItem('django.admin.navSidebarIsOpen', navSidebarIsOpen);
main.classList.toggle('shifted');
});
}
+
+ function initSidebarQuickFilter() {
+ const options = [];
+ const navSidebar = document.getElementById('nav-sidebar');
+ if (!navSidebar) {
+ return;
+ }
+ navSidebar.querySelectorAll('th[scope=row] a').forEach((container) => {
+ options.push({title: container.innerHTML, node: container});
+ });
+
+ function checkValue(event) {
+ let filterValue = event.target.value;
+ if (filterValue) {
+ filterValue = filterValue.toLowerCase();
+ }
+ if (event.key === 'Escape') {
+ filterValue = '';
+ event.target.value = ''; // clear input
+ }
+ let matches = false;
+ for (const o of options) {
+ let displayValue = '';
+ if (filterValue) {
+ if (o.title.toLowerCase().indexOf(filterValue) === -1) {
+ displayValue = 'none';
+ } else {
+ matches = true;
+ }
+ }
+ // show/hide parent
+ o.node.parentNode.parentNode.style.display = displayValue;
+ }
+ if (!filterValue || matches) {
+ event.target.classList.remove('no-results');
+ } else {
+ event.target.classList.add('no-results');
+ }
+ sessionStorage.setItem('django.admin.navSidebarFilterValue', filterValue);
+ }
+
+ const nav = document.getElementById('nav-filter');
+ nav.addEventListener('change', checkValue, false);
+ nav.addEventListener('input', checkValue, false);
+ nav.addEventListener('keyup', checkValue, false);
+
+ const storedValue = sessionStorage.getItem('django.admin.navSidebarFilterValue');
+ if (storedValue) {
+ nav.value = storedValue;
+ checkValue({target: nav, key: ''});
+ }
+ }
+ window.initSidebarQuickFilter = initSidebarQuickFilter;
+ initSidebarQuickFilter();
}
diff --git a/source/static/admin/js/prepopulate_init.js b/source/static/admin/js/prepopulate_init.js
index 72ebdcf..a58841f 100644
--- a/source/static/admin/js/prepopulate_init.js
+++ b/source/static/admin/js/prepopulate_init.js
@@ -3,7 +3,11 @@
const $ = django.jQuery;
const fields = $('#django-admin-prepopulated-fields-constants').data('prepopulatedFields');
$.each(fields, function(index, field) {
- $('.empty-form .form-row .field-' + field.name + ', .empty-form.form-row .field-' + field.name).addClass('prepopulated_field');
+ $(
+ '.empty-form .form-row .field-' + field.name +
+ ', .empty-form.form-row .field-' + field.name +
+ ', .empty-form .form-row.field-' + field.name
+ ).addClass('prepopulated_field');
$(field.id).data('dependency_list', field.dependency_list).prepopulate(
field.dependency_ids, field.maxLength, field.allowUnicode
);
diff --git a/source/static/admin/js/vendor/jquery/LICENSE.txt b/source/static/admin/js/vendor/jquery/LICENSE.txt
index e3dbacb..f642c3f 100644
--- a/source/static/admin/js/vendor/jquery/LICENSE.txt
+++ b/source/static/admin/js/vendor/jquery/LICENSE.txt
@@ -1,4 +1,4 @@
-Copyright JS Foundation and other contributors, https://js.foundation/
+Copyright OpenJS Foundation and other contributors, https://openjsf.org/
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
diff --git a/source/static/admin/js/vendor/jquery/jquery.js b/source/static/admin/js/vendor/jquery/jquery.js
index 5093733..fc6c299 100644
--- a/source/static/admin/js/vendor/jquery/jquery.js
+++ b/source/static/admin/js/vendor/jquery/jquery.js
@@ -1,15 +1,15 @@
/*!
- * jQuery JavaScript Library v3.5.1
+ * jQuery JavaScript Library v3.6.0
* https://jquery.com/
*
* Includes Sizzle.js
* https://sizzlejs.com/
*
- * Copyright JS Foundation and other contributors
+ * Copyright OpenJS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
- * Date: 2020-05-04T22:49Z
+ * Date: 2021-03-02T17:08Z
*/
( function( global, factory ) {
@@ -76,12 +76,16 @@ var support = {};
var isFunction = function isFunction( obj ) {
- // Support: Chrome <=57, Firefox <=52
- // In some browsers, typeof returns "function" for HTML