custom filenames with media templates, resolves #5

This commit is contained in:
meeb 2020-12-18 15:59:01 +11:00
parent 25a1a82de4
commit 08c1a82c30
9 changed files with 450 additions and 26 deletions

View File

@ -0,0 +1,97 @@
<h2>Available media name variables</h2>
<table class="striped">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
<th>Output example</th>
</tr>
</thead>
<tbody>
<tr>
<td>{yyyymmdd}</td>
<td>Media publish date in YYYYMMDD</td>
<td>20210101</td>
</tr>
<tr>
<td>{yyyy_mm_dd}</td>
<td>Media publish date in YYYY-MM-DD</td>
<td>2021-01-01</td>
</tr>
<tr>
<td>{yyyy}</td>
<td>Media publish year in YYYY</td>
<td>2021</td>
</tr>
<tr>
<td>{source}</td>
<td>Lower case source name, max 80 chars</td>
<td>my-source</td>
</tr>
<tr>
<td>{source_full}</td>
<td>Full source name</td>
<td>My Source</td>
</tr>
<tr>
<td>{title}</td>
<td>Lower case media title, max 80 chars</td>
<td>my-video</td>
</tr>
<tr>
<td>{title_full}</td>
<td>Full media title</td>
<td>My Video</td>
</tr>
<tr>
<td>{key}</td>
<td>Media unique key or video ID</td>
<td>SoMeUnIqUeId</td>
</tr>
<tr>
<td>{format}</td>
<td>Media format string</td>
<td>720p-avc1-mp4a</td>
</tr>
<tr>
<td>{ext}</td>
<td>File extension</td>
<td>mkv</td>
</tr>
<tr>
<td>{resolution}</td>
<td>Resolution</td>
<td>720p</td>
</tr>
<tr>
<td>{height}</td>
<td>Media height in pixels</td>
<td>720</td>
</tr>
<tr>
<td>{width}</td>
<td>Media width in pixels</td>
<td>1280</td>
</tr>
<tr>
<td>{vcodec}</td>
<td>Media video codec</td>
<td>avc1</td>
</tr>
<tr>
<td>{acodec}</td>
<td>Media audio codec</td>
<td>opus</td>
</tr>
<tr>
<td>{fps}</td>
<td>Media fps</td>
<td>60fps</td>
</tr>
<tr>
<td>{flag_hdr}</td>
<td>Media has HDR flag</td>
<td>hdr</td>
</tr>
</tbody>
</table>

View File

@ -7,6 +7,7 @@ from django.conf import settings
from django.db import models from django.db import models
from django.core.files.storage import FileSystemStorage from django.core.files.storage import FileSystemStorage
from django.utils.text import slugify from django.utils.text import slugify
from django.utils import timezone
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from common.errors import NoFormatException from common.errors import NoFormatException
from .youtube import (get_media_info as get_youtube_media_info, from .youtube import (get_media_info as get_youtube_media_info,
@ -262,6 +263,11 @@ class Source(models.Model):
def icon(self): def icon(self):
return self.ICONS.get(self.source_type) return self.ICONS.get(self.source_type)
@property
def slugname(self):
replaced = self.name.replace('_', '-').replace('&', 'and').replace('+', 'and')
return slugify(replaced)[:80]
@property @property
def is_audio(self): def is_audio(self):
return self.source_resolution == self.SOURCE_RESOLUTION_AUDIO return self.source_resolution == self.SOURCE_RESOLUTION_AUDIO
@ -336,6 +342,49 @@ class Source(models.Model):
def can_fallback(self): def can_fallback(self):
return self.fallback != self.FALLBACK_FAIL return self.fallback != self.FALLBACK_FAIL
@property
def example_media_format_dict(self):
'''
Populates a dict with real-ish and some placeholder data for media name
format strings. Used for example filenames and media_format validation.
'''
fmt = []
if self.source_resolution:
fmt.append(self.source_resolution)
if self.source_vcodec:
fmt.append(self.source_vcodec.lower())
if self.source_acodec:
fmt.append(self.source_acodec.lower())
if self.prefer_60fps:
fmt.append('60fps')
if self.prefer_hdr:
fmt.append('hdr')
return {
'yyyymmdd': timezone.now().strftime('%Y%m%d'),
'yyyy_mm_dd': timezone.now().strftime('%Y-%m-%d'),
'yyyy': timezone.now().strftime('%Y'),
'source': self.slugname,
'source_full': self.name,
'title': 'some-media-title-name',
'title_full': 'Some Media Title Name',
'key': 'SoMeUnIqUiD',
'format': '-'.join(fmt),
'ext': self.extension,
'resolution': self.source_resolution if self.source_resolution else '',
'height': '720' if self.source_resolution else '',
'width': '1280' if self.source_resolution else '',
'vcodec': self.source_vcodec.lower() if self.source_vcodec else '',
'acodec': self.source_acodec.lower(),
'fps': '24' if self.source_resolution else '',
'hdr': 'hdr' if self.source_resolution else ''
}
def get_example_media_format(self):
try:
return self.media_format.format(**self.example_media_format_dict)
except Exception:
return ''
def index_media(self): def index_media(self):
''' '''
Index the media source returning a list of media metadata as dicts. Index the media source returning a list of media metadata as dicts.
@ -645,16 +694,39 @@ class Media(models.Model):
('720p', 'avc1', 'mp4a', '60fps', 'hdr') ('720p', 'avc1', 'mp4a', '60fps', 'hdr')
''' '''
fmt = [] fmt = []
resolution = ''
vcodec = ''
acodec = ''
height = '0'
width = '0'
fps = ''
hdr = ''
# If the download has completed use existing values # If the download has completed use existing values
if self.downloaded: if self.downloaded:
resolution = f'{self.downloaded_height}p'
if self.downloaded_format != 'audio': if self.downloaded_format != 'audio':
fmt.append(self.downloaded_video_codec.lower()) vcodec = self.downloaded_video_codec.lower()
fmt.append(self.downloaded_audio_codec.lower()) fmt.append(vcodec)
acodec = self.downloaded_audio_codec.lower()
fmt.append(acodec)
if self.downloaded_format != 'audio': if self.downloaded_format != 'audio':
fmt.append(str(self.downloaded_fps)) fps = str(self.downloaded_fps)
fmt.append(f'{fps}fps')
if self.downloaded_hdr: if self.downloaded_hdr:
fmt.append('hdr') hdr = 'hdr'
return fmt fmt.append(hdr)
height = str(self.downloaded_height)
width = str(self.downloaded_width)
return {
'resolution': resolution,
'height': height,
'width': width,
'vcodec': vcodec,
'acodec': acodec,
'fps': fps,
'hdr': hdr,
'format': tuple(fmt),
}
# Otherwise, calculate from matched format codes # Otherwise, calculate from matched format codes
vformat = None vformat = None
aformat = None aformat = None
@ -671,15 +743,31 @@ class Media(models.Model):
# Combined # Combined
vformat = cformat vformat = cformat
if vformat: if vformat:
fmt.append(vformat['format'].lower()) resolution = vformat['format'].lower()
fmt.append(vformat['vcodec'].lower()) fmt.append(resolution)
fmt.append(aformat['acodec'].lower()) vcodec = vformat['vcodec'].lower()
fmt.append(vcodec)
acodec = aformat['acodec'].lower()
fmt.append(acodec)
if vformat: if vformat:
if vformat['is_60fps']: if vformat['is_60fps']:
fmt.append('60fps') fps = '60fps'
fmt.append(fps)
if vformat['is_hdr']: if vformat['is_hdr']:
fmt.append('hdr') hdr = 'hdr'
return tuple(fmt) fmt.append(hdr)
height = str(vformat['height'])
width = str(vformat['width'])
return {
'resolution': resolution,
'height': height,
'width': width,
'vcodec': vcodec,
'acodec': acodec,
'fps': fps,
'hdr': hdr,
'format': tuple(fmt),
}
def get_format_by_code(self, format_code): def get_format_by_code(self, format_code):
''' '''
@ -690,6 +778,35 @@ class Media(models.Model):
return fmt return fmt
return False return False
@property
def format_dict(self):
'''
Returns a dict matching the media_format key requirements for this item
of media.
'''
format_str = self.get_format_str()
display_format = self.get_display_format(format_str)
dateobj = self.upload_date if self.upload_date else self.created
return {
'yyyymmdd': dateobj.strftime('%Y%m%d'),
'yyyy_mm_dd': dateobj.strftime('%Y-%m-%d'),
'yyyy': dateobj.strftime('%Y'),
'source': self.source.slugname,
'source_full': self.source.name,
'title': self.slugtitle,
'title_full': self.title,
'key': self.key,
'format': '-'.join(display_format['format']),
'ext': self.source.extension,
'resolution': display_format['resolution'],
'height': display_format['height'],
'width': display_format['width'],
'vcodec': display_format['vcodec'],
'acodec': display_format['acodec'],
'fps': display_format['fps'],
'hdr': display_format['hdr'],
}
@property @property
def loaded_metadata(self): def loaded_metadata(self):
try: try:
@ -712,6 +829,11 @@ class Media(models.Model):
field = self.get_metadata_field('title') field = self.get_metadata_field('title')
return self.loaded_metadata.get(field, '').strip() return self.loaded_metadata.get(field, '').strip()
@property
def slugtitle(self):
replaced = self.title.replace('_', '-').replace('&', 'and').replace('+', 'and')
return slugify(replaced)[:80]
@property @property
def thumbnail(self): def thumbnail(self):
field = self.get_metadata_field('thumbnail') field = self.get_metadata_field('thumbnail')
@ -750,20 +872,24 @@ class Media(models.Model):
@property @property
def filename(self): def filename(self):
# If a media_file has been downloaded use its existing name
if self.media_file: if self.media_file:
return os.path.basename(self.media_file.name) return os.path.basename(self.media_file.name)
upload_date = self.upload_date # Otherwise, create a suitable filename from the source media_format
dateobj = upload_date if upload_date else self.created media_format = str(self.source.media_format)
datestr = dateobj.strftime('%Y-%m-%d') media_details = self.format_dict
source_name = slugify(self.source.name).replace('_', '-') return media_format.format(**media_details)
name = slugify(self.name.replace('&', 'and').replace('+', 'and'))
name = name.replace('_', '-')[:80] @property
key = self.key.strip().replace('_', '-')[:20] def directory_path(self):
format_str = self.get_format_str() # If a media_file has been downloaded use its existing directory
format_tuple = self.get_display_format(format_str) if self.media_file:
fmt = '-'.join(format_tuple) return os.path.dirname(self.media_file.name)
ext = self.source.extension # Otherwise, create a suitable filename from the source media_format
return f'{datestr}_{source_name}_{name}_{key}_{fmt}.{ext}' media_format = str(self.source.media_format)
media_details = self.format_dict
dirname = self.source.directory_path / media_format.format(**media_details)
return os.path.dirname(str(dirname))
@property @property
def filepath(self): def filepath(self):

View File

@ -1,3 +1,4 @@
import os
from django.conf import settings from django.conf import settings
from django.db.models.signals import pre_save, post_save, pre_delete, post_delete from django.db.models.signals import pre_save, post_save, pre_delete, post_delete
from django.dispatch import receiver from django.dispatch import receiver
@ -152,11 +153,11 @@ def media_pre_delete(sender, instance, **kwargs):
if instance.media_file: if instance.media_file:
filepath = instance.media_file.path filepath = instance.media_file.path
log.info(f'Deleting media for: {instance} path: {filepath}') log.info(f'Deleting media for: {instance} path: {filepath}')
delete_file(instance.media_file.path) delete_file(filepath)
# Delete thumbnail copy if it exists # Delete thumbnail copy if it exists
barefilepath, fileext = os.path.splitext(filepath) barefilepath, fileext = os.path.splitext(filepath)
thumbpath = f'{barefilepath}.jpg' thumbpath = f'{barefilepath}.jpg'
log.info(f'Copying thumbnail: {instance} path: {thumbpath}') log.info(f'Deleting thumbnail for: {instance} path: {thumbpath}')
delete_file(thumbpath) delete_file(thumbpath)

View File

@ -80,6 +80,10 @@
<td class="hide-on-small-only">Filename</td> <td class="hide-on-small-only">Filename</td>
<td><span class="hide-on-med-and-up">Filename<br></span><strong>{{ media.filename }}</strong></td> <td><span class="hide-on-med-and-up">Filename<br></span><strong>{{ media.filename }}</strong></td>
</tr> </tr>
<tr title="The filename the media will be downloaded as">
<td class="hide-on-small-only">Directory</td>
<td><span class="hide-on-med-and-up">Directory<br></span><strong>{{ media.directory_path }}</strong></td>
</tr>
<tr title="Size of the file on disk"> <tr title="Size of the file on disk">
<td class="hide-on-small-only">File size</td> <td class="hide-on-small-only">File size</td>
<td><span class="hide-on-med-and-up">File size<br></span><strong>{{ media.downloaded_filesize|filesizeformat }}</strong></td> <td><span class="hide-on-med-and-up">File size<br></span><strong>{{ media.downloaded_filesize|filesizeformat }}</strong></td>

View File

@ -23,4 +23,9 @@
</div> </div>
</form> </form>
</div> </div>
<div class="row">
<div class="col s12">
{% include 'mediaformatvars.html' %}
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -25,4 +25,9 @@
</div> </div>
</form> </form>
</div> </div>
<div class="row">
<div class="col s12">
{% include 'mediaformatvars.html' %}
</div>
</div>
{% endblock %} {% endblock %}

View File

@ -47,6 +47,10 @@
<td class="hide-on-small-only">Media format</td> <td class="hide-on-small-only">Media format</td>
<td><span class="hide-on-med-and-up">Media format<br></span><strong>{{ source.media_format }}</strong></td> <td><span class="hide-on-med-and-up">Media format<br></span><strong>{{ source.media_format }}</strong></td>
</tr> </tr>
<tr title="Example file name for media format">
<td class="hide-on-small-only">Example filename</td>
<td><span class="hide-on-med-and-up">Example filename<br></span><strong>{{ source.get_example_media_format }}</strong></td>
</tr>
<tr title="Schedule of how often to index the source for new media"> <tr title="Schedule of how often to index the source for new media">
<td class="hide-on-small-only">Index schedule</td> <td class="hide-on-small-only">Index schedule</td>
<td><span class="hide-on-med-and-up">Index schedule<br></span><strong>{{ source.get_index_schedule_display }}</strong></td> <td><span class="hide-on-med-and-up">Index schedule<br></span><strong>{{ source.get_index_schedule_display }}</strong></td>

View File

@ -134,6 +134,7 @@ class FrontEndTestCase(TestCase):
'key': 'testkey', 'key': 'testkey',
'name': 'testname', 'name': 'testname',
'directory': 'testdirectory', 'directory': 'testdirectory',
'media_format': settings.MEDIA_FORMATSTR_DEFAULT,
'index_schedule': 3600, 'index_schedule': 3600,
'delete_old_media': False, 'delete_old_media': False,
'days_to_keep': 14, 'days_to_keep': 14,
@ -173,6 +174,7 @@ class FrontEndTestCase(TestCase):
'key': 'updatedkey', # changed 'key': 'updatedkey', # changed
'name': 'testname', 'name': 'testname',
'directory': 'testdirectory', 'directory': 'testdirectory',
'media_format': settings.MEDIA_FORMATSTR_DEFAULT,
'index_schedule': Source.IndexSchedule.EVERY_HOUR, 'index_schedule': Source.IndexSchedule.EVERY_HOUR,
'delete_old_media': False, 'delete_old_media': False,
'days_to_keep': 14, 'days_to_keep': 14,
@ -200,6 +202,7 @@ class FrontEndTestCase(TestCase):
'key': 'updatedkey', 'key': 'updatedkey',
'name': 'testname', 'name': 'testname',
'directory': 'testdirectory', 'directory': 'testdirectory',
'media_format': settings.MEDIA_FORMATSTR_DEFAULT,
'index_schedule': Source.IndexSchedule.EVERY_2_HOURS, # changed 'index_schedule': Source.IndexSchedule.EVERY_2_HOURS, # changed
'delete_old_media': False, 'delete_old_media': False,
'days_to_keep': 14, 'days_to_keep': 14,
@ -425,6 +428,137 @@ all_test_metadata = {
} }
class FilepathTestCase(TestCase):
def setUp(self):
# Disable general logging for test case
logging.disable(logging.CRITICAL)
# Add a test source
self.source = Source.objects.create(
source_type=Source.SOURCE_TYPE_YOUTUBE_CHANNEL,
key='testkey',
name='testname',
directory='testdirectory',
media_format=settings.MEDIA_FORMATSTR_DEFAULT,
index_schedule=3600,
delete_old_media=False,
days_to_keep=14,
source_resolution=Source.SOURCE_RESOLUTION_1080P,
source_vcodec=Source.SOURCE_VCODEC_VP9,
source_acodec=Source.SOURCE_ACODEC_OPUS,
prefer_60fps=False,
prefer_hdr=False,
fallback=Source.FALLBACK_FAIL
)
# Add some test media
self.media = Media.objects.create(
key='mediakey',
source=self.source,
metadata=metadata,
)
def test_source_dirname(self):
# Check media format validation is working
# Empty
self.source.media_format = ''
self.assertEqual(self.source.get_example_media_format(), '')
# Invalid, bad key
self.source.media_format = '{test}'
self.assertEqual(self.source.get_example_media_format(), '')
# Invalid, extra brackets
self.source.media_format = '{key}}'
self.assertEqual(self.source.get_example_media_format(), '')
# Invalid, not a string
self.source.media_format = 1
self.assertEqual(self.source.get_example_media_format(), '')
# Check all expected keys validate
self.source.media_format = 'test-{yyyymmdd}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + timezone.now().strftime('%Y%m%d'))
self.source.media_format = 'test-{yyyy_mm_dd}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + timezone.now().strftime('%Y-%m-%d'))
self.source.media_format = 'test-{yyyy}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + timezone.now().strftime('%Y'))
self.source.media_format = 'test-{source}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + self.source.slugname)
self.source.media_format = 'test-{source_full}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + self.source.name)
self.source.media_format = 'test-{title}'
self.assertEqual(self.source.get_example_media_format(),
'test-some-media-title-name')
self.source.media_format = 'test-{title_full}'
self.assertEqual(self.source.get_example_media_format(),
'test-Some Media Title Name')
self.source.media_format = 'test-{key}'
self.assertEqual(self.source.get_example_media_format(),
'test-SoMeUnIqUiD')
self.source.media_format = 'test-{format}'
self.assertEqual(self.source.get_example_media_format(),
'test-1080p-vp9-opus')
self.source.media_format = 'test-{ext}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + self.source.extension)
self.source.media_format = 'test-{resolution}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + self.source.source_resolution)
self.source.media_format = 'test-{height}'
self.assertEqual(self.source.get_example_media_format(),
'test-720')
self.source.media_format = 'test-{width}'
self.assertEqual(self.source.get_example_media_format(),
'test-1280')
self.source.media_format = 'test-{vcodec}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + self.source.source_vcodec.lower())
self.source.media_format = 'test-{acodec}'
self.assertEqual(self.source.get_example_media_format(),
'test-' + self.source.source_acodec.lower())
self.source.media_format = 'test-{fps}'
self.assertEqual(self.source.get_example_media_format(),
'test-24')
self.source.media_format = 'test-{hdr}'
self.assertEqual(self.source.get_example_media_format(),
'test-hdr')
def test_media_filename(self):
# Check child directories work
self.source.media_format = '{yyyy}/{key}.{ext}'
self.assertEqual(self.media.directory_path,
str(self.source.directory_path / '2017'))
self.assertEqual(self.media.filename, '2017/mediakey.mkv')
self.source.media_format = '{yyyy}/{yyyy_mm_dd}/{key}.{ext}'
self.assertEqual(self.media.directory_path,
str(self.source.directory_path / '2017/20179-11'))
self.assertEqual(self.media.filename, '2017/20179-11/mediakey.mkv')
# Check media specific media format keys work
test_media = Media.objects.create(
key='test',
source=self.source,
metadata=metadata,
downloaded=True,
download_date=timezone.now(),
downloaded_format='720p',
downloaded_height=720,
downloaded_width=1280,
downloaded_audio_codec='opus',
downloaded_video_codec='vp9',
downloaded_container='mkv',
downloaded_fps=30,
downloaded_hdr=True,
downloaded_filesize=12345
)
# Bypass media-file-exists on-save signal
test_media.downloaded = True
self.source.media_format = ('{title}_{key}_{resolution}-{height}x{width}-'
'{acodec}-{vcodec}-{fps}fps-{hdr}.{ext}')
self.assertEqual(test_media.filename,
'no-fancy-stuff_test_720p-720x1280-opus-vp9-30fps-hdr.mkv')
class FormatMatchingTestCase(TestCase): class FormatMatchingTestCase(TestCase):
def setUp(self): def setUp(self):

View File

@ -256,6 +256,11 @@ class AddSourceView(CreateView):
'index_schedule', 'delete_old_media', 'days_to_keep', 'index_schedule', 'delete_old_media', 'days_to_keep',
'source_resolution', 'source_vcodec', 'source_acodec', 'prefer_60fps', 'source_resolution', 'source_vcodec', 'source_acodec', 'prefer_60fps',
'prefer_hdr', 'fallback', 'copy_thumbnails') 'prefer_hdr', 'fallback', 'copy_thumbnails')
errors = {
'invalid_media_format': _('Invalid media format, the media format contains '
'errors or is empty. Check the table at the end of '
'this page for valid media name variables'),
}
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self.prepopulated_data = {} self.prepopulated_data = {}
@ -282,6 +287,20 @@ class AddSourceView(CreateView):
initial[k] = v initial[k] = v
return initial return initial
def form_valid(self, form):
# Perform extra validation to make sure the media_format is valid
obj = form.save(commit=False)
source_type = form.cleaned_data['media_format']
example_media_file = obj.get_example_media_format()
if example_media_file == '':
form.add_error(
'media_format',
ValidationError(self.errors['invalid_media_format'])
)
if form.errors:
return super().form_invalid(form)
return super().form_valid(form)
def get_success_url(self): def get_success_url(self):
url = reverse_lazy('sync:source', kwargs={'pk': self.object.pk}) url = reverse_lazy('sync:source', kwargs={'pk': self.object.pk})
return append_uri_params(url, {'message': 'source-created'}) return append_uri_params(url, {'message': 'source-created'})
@ -328,6 +347,25 @@ class UpdateSourceView(UpdateView):
'index_schedule', 'delete_old_media', 'days_to_keep', 'index_schedule', 'delete_old_media', 'days_to_keep',
'source_resolution', 'source_vcodec', 'source_acodec', 'prefer_60fps', 'source_resolution', 'source_vcodec', 'source_acodec', 'prefer_60fps',
'prefer_hdr', 'fallback', 'copy_thumbnails') 'prefer_hdr', 'fallback', 'copy_thumbnails')
errors = {
'invalid_media_format': _('Invalid media format, the media format contains '
'errors or is empty. Check the table at the end of '
'this page for valid media name variables'),
}
def form_valid(self, form):
# Perform extra validation to make sure the media_format is valid
obj = form.save(commit=False)
source_type = form.cleaned_data['media_format']
example_media_file = obj.get_example_media_format()
if example_media_file == '':
form.add_error(
'media_format',
ValidationError(self.errors['invalid_media_format'])
)
if form.errors:
return super().form_invalid(form)
return super().form_valid(form)
def get_success_url(self): def get_success_url(self):
url = reverse_lazy('sync:source', kwargs={'pk': self.object.pk}) url = reverse_lazy('sync:source', kwargs={'pk': self.object.pk})
@ -497,8 +535,13 @@ class MediaRedownloadView(FormView, SingleObjectMixin):
self.object.thumb = None self.object.thumb = None
# If the media file exists on disk, delete it # If the media file exists on disk, delete it
if self.object.media_file_exists: if self.object.media_file_exists:
delete_file(self.object.media_file.path) filepath = self.object.media_file.path
delete_file(filepath)
self.object.media_file = None self.object.media_file = None
# If the media has an associated thumbnail copied, also delete it
barefilepath, fileext = os.path.splitext(filepath)
thumbpath = f'{barefilepath}.jpg'
delete_file(thumbpath)
# Reset all download data # Reset all download data
self.object.downloaded = False self.object.downloaded = False
self.object.downloaded_audio_codec = None self.object.downloaded_audio_codec = None
@ -538,8 +581,13 @@ class MediaSkipView(FormView, SingleObjectMixin):
delete_task_by_media('sync.tasks.download_media', (str(self.object.pk),)) delete_task_by_media('sync.tasks.download_media', (str(self.object.pk),))
# If the media file exists on disk, delete it # If the media file exists on disk, delete it
if self.object.media_file_exists: if self.object.media_file_exists:
filepath = self.object.media_file.path
delete_file(self.object.media_file.path) delete_file(self.object.media_file.path)
self.object.media_file = None self.object.media_file = None
# If the media has an associated thumbnail copied, also delete it
barefilepath, fileext = os.path.splitext(filepath)
thumbpath = f'{barefilepath}.jpg'
delete_file(thumbpath)
# Reset all download data # Reset all download data
self.object.downloaded = False self.object.downloaded = False
self.object.downloaded_audio_codec = None self.object.downloaded_audio_codec = None