2019-06-03 18:37:28 +00:00
|
|
|
'''
|
|
|
|
Various utlity functions that are independant of any Django app or
|
|
|
|
model.
|
|
|
|
'''
|
|
|
|
|
|
|
|
from nturl2path import pathname2url as ntpathname2url
|
|
|
|
from nturl2path import url2pathname as url2ntpathname
|
2018-01-05 20:18:12 +00:00
|
|
|
import re
|
2017-12-27 21:11:20 +00:00
|
|
|
import string
|
2018-01-05 20:18:12 +00:00
|
|
|
from unicodedata import normalize
|
2019-06-03 18:37:28 +00:00
|
|
|
from urllib.parse import urljoin, urlparse
|
|
|
|
from urllib.request import pathname2url, url2pathname
|
2017-12-27 21:11:20 +00:00
|
|
|
|
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
2019-06-03 18:37:28 +00:00
|
|
|
from django.utils.encoding import iri_to_uri, uri_to_iri
|
2017-12-27 21:11:20 +00:00
|
|
|
|
2019-06-10 11:37:22 +00:00
|
|
|
|
|
|
|
GROUP_NT_UNC = r'file://[A-Za-z0-9!@#$%^&\'\)\(\.\-_{}~]+/'
|
|
|
|
|
|
|
|
GROUP_NT_DRIVE_LETTER = r'file:///[A-Za-z](?:\:|\|)/'
|
|
|
|
|
|
|
|
GROUP_NON_AUTH = r'file:///[A-Za-z0-9!@#$%^&\'\)\(\.\-_{}~]+'
|
|
|
|
|
|
|
|
FILE_IRI_PATTERN = (
|
|
|
|
r'^(?P<unc>' +
|
|
|
|
GROUP_NT_UNC +
|
|
|
|
r')|(?P<driveletter>' +
|
|
|
|
GROUP_NT_DRIVE_LETTER +
|
|
|
|
r')|(?P<nonauth>' +
|
|
|
|
GROUP_NON_AUTH +
|
|
|
|
r')'
|
|
|
|
)
|
2017-12-27 21:11:20 +00:00
|
|
|
|
|
|
|
|
2018-01-06 17:57:10 +00:00
|
|
|
def naturalize(text):
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-01-05 20:18:12 +00:00
|
|
|
Return a normalized unicode string, with removed starting articles, for use
|
|
|
|
in natural sorting.
|
|
|
|
|
|
|
|
Code was inspired by 'django-naturalsortfield' from Nathan Reynolds:
|
|
|
|
https://github.com/nathforge/django-naturalsortfield
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-01-05 20:18:12 +00:00
|
|
|
def naturalize_int_match(match):
|
2018-01-06 18:11:51 +00:00
|
|
|
return '{:08d}'.format(int(match.group(0)))
|
2018-01-05 20:18:12 +00:00
|
|
|
|
2018-01-06 17:57:10 +00:00
|
|
|
text = normalize('NFKD', text).encode('ascii', 'ignore').decode('ascii')
|
|
|
|
text = text.lower()
|
|
|
|
punc = re.compile('[{}]'.format(re.escape(string.punctuation)))
|
|
|
|
text = re.sub(punc, ' ', text)
|
|
|
|
text = text.strip()
|
|
|
|
text = re.sub(r'^(a|an|the)\s+', '', text)
|
|
|
|
text = re.sub(r'\d+', naturalize_int_match, text)
|
2018-01-05 20:18:12 +00:00
|
|
|
|
2018-01-06 17:57:10 +00:00
|
|
|
return text
|
2018-01-14 20:21:04 +00:00
|
|
|
|
|
|
|
|
2018-01-14 23:38:14 +00:00
|
|
|
def quantify(quantity, model):
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-01-14 23:38:14 +00:00
|
|
|
A message based on the quantity and singular/plural name of the model.
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-01-14 20:21:04 +00:00
|
|
|
if quantity == 1:
|
2018-01-14 23:38:14 +00:00
|
|
|
message = '1 {}'.format(model._meta.verbose_name)
|
2018-01-14 20:21:04 +00:00
|
|
|
else:
|
2018-01-14 23:38:14 +00:00
|
|
|
message = '{} {}'.format(str(quantity),
|
|
|
|
model._meta.verbose_name_plural)
|
2018-01-14 20:21:04 +00:00
|
|
|
return message
|
2018-01-14 23:38:14 +00:00
|
|
|
|
|
|
|
|
|
|
|
def create_success_message(parent_model, parent_quantity, child_model,
|
|
|
|
child_quantity, remove=False):
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-01-14 23:38:14 +00:00
|
|
|
Creates a message for displaying the success of model modification.
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-01-14 23:38:14 +00:00
|
|
|
p_message = quantify(parent_quantity, parent_model)
|
|
|
|
c_message = quantify(child_quantity, child_model)
|
|
|
|
if remove:
|
|
|
|
return '{} successfully removed from {}'.format(c_message, p_message)
|
2019-06-03 18:37:28 +00:00
|
|
|
return '{} successfully added to {}.'.format(c_message, p_message)
|
2018-03-26 19:28:38 +00:00
|
|
|
|
|
|
|
|
|
|
|
def get_pretty_time(seconds):
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-03-26 19:28:38 +00:00
|
|
|
Displays a human-readable representation of time.
|
2019-06-03 18:37:28 +00:00
|
|
|
'''
|
2018-03-26 19:28:38 +00:00
|
|
|
if seconds > 0:
|
|
|
|
periods = [
|
|
|
|
('year', 60*60*24*365.25),
|
|
|
|
('day', 60*60*24),
|
|
|
|
('hour', 60*60),
|
|
|
|
('minute', 60),
|
|
|
|
('second', 1)
|
|
|
|
]
|
|
|
|
strings = []
|
|
|
|
for period_name, period_seconds in periods:
|
|
|
|
if seconds >= period_seconds:
|
|
|
|
period_value, seconds = divmod(seconds, period_seconds)
|
|
|
|
strings.append('{} {}{}'.format(period_value,
|
|
|
|
period_name,
|
|
|
|
('s', '')[period_value == 1]))
|
|
|
|
return ', '.join(strings)
|
2019-06-03 18:37:28 +00:00
|
|
|
return 'Now'
|
|
|
|
|
|
|
|
|
|
|
|
def path_to_iri(path):
|
|
|
|
'''
|
|
|
|
OS-independant attempt at converting any OS absolute path to an
|
|
|
|
RFC3987-defined IRI along with the file scheme from RFC8089.
|
|
|
|
'''
|
|
|
|
# Looking to see if the path starts with a drive letter or UNC path
|
|
|
|
# (eg. 'D:\' or '\\')
|
|
|
|
windows = re.match(r'^(?:[A-Za-z]:|\\)\\', path)
|
|
|
|
if windows:
|
|
|
|
return uri_to_iri(urljoin('file:', ntpathname2url(path)))
|
|
|
|
return uri_to_iri(urljoin('file:', pathname2url(path)))
|
|
|
|
|
|
|
|
|
|
|
|
def iri_to_path(iri):
|
|
|
|
'''
|
|
|
|
OS-independant attempt at converting an RFC3987-defined IRI with a file
|
|
|
|
scheme from RFC8089 to an OS-specific absolute path.
|
|
|
|
'''
|
|
|
|
# Drive letter IRI will have three slashes followed by the drive letter
|
|
|
|
# UNC path IRI will have two slashes followed by the UNC path
|
|
|
|
uri = iri_to_uri(iri)
|
2019-06-06 19:45:25 +00:00
|
|
|
patt = r'^(?:' + GROUP_NT_DRIVE_LETTER + r'|' + GROUP_NT_UNC + r')'
|
2019-06-03 18:37:28 +00:00
|
|
|
windows = re.match(patt, uri)
|
|
|
|
if windows:
|
|
|
|
parse = urlparse(uri)
|
|
|
|
# UNC path URIs put the server name in the 'netloc' parameter.
|
|
|
|
if parse.netloc:
|
|
|
|
return '\\' + url2ntpathname('/' + parse.netloc + parse.path)
|
|
|
|
return url2ntpathname(parse.path)
|
|
|
|
return url2pathname(urlparse(uri).path)
|
2020-02-08 05:07:04 +00:00
|
|
|
|
|
|
|
|
|
|
|
def clean_quotes(unclean_string):
|
|
|
|
'''
|
|
|
|
Escapes quotes for use in the Liquidsoap parser.
|
|
|
|
'''
|
|
|
|
return unclean_string.replace('"', '\\"')
|
|
|
|
|
|
|
|
|
|
|
|
def beautify_artists(artists):
|
|
|
|
'''
|
|
|
|
Turns a list of one or more artists into a proper English listing.
|
|
|
|
'''
|
|
|
|
output = ', '
|
|
|
|
if len(artists) == 2:
|
|
|
|
output = ' & '
|
|
|
|
return clean_quotes(output.join(artists))
|