1
1
import os
2
2
import glob
3
+ from pathlib import Path
3
4
from django .conf import settings
4
5
from django .db .models .signals import pre_save , post_save , pre_delete , post_delete
5
6
from django .dispatch import receiver
14
15
download_media , rescan_media_server , download_source_images ,
15
16
save_all_media_for_source , rename_all_media_for_source ,
16
17
get_media_metadata_task )
17
- from .utils import delete_file
18
+ from .utils import delete_file , glob_quote
18
19
from .filtering import filter_media
19
20
20
21
@@ -208,19 +209,63 @@ def media_pre_delete(sender, instance, **kwargs):
208
209
if thumbnail_url :
209
210
delete_task_by_media ('sync.tasks.download_media_thumbnail' ,
210
211
(str (instance .pk ), thumbnail_url ))
211
- if instance .source .delete_files_on_disk and (instance .media_file or instance .thumb ):
212
- # Delete all media files if it contains filename
213
- filepath = instance .media_file .path if instance .media_file else instance .thumb .path
214
- barefilepath , fileext = os .path .splitext (filepath )
212
+
213
+
214
+ @receiver (post_delete , sender = Media )
215
+ def media_post_delete (sender , instance , ** kwargs ):
216
+ # Remove thumbnail file for deleted media
217
+ if instance .thumb :
218
+ instance .thumb .delete (save = False )
219
+ # Remove the video file, when configured to do so
220
+ if instance .source .delete_files_on_disk and instance .media_file :
221
+ video_path = Path (str (instance .media_file .path )).resolve ()
222
+ instance .media_file .delete (save = False )
223
+ # the other files we created have these known suffixes
224
+ for suffix in frozenset (('nfo' , 'jpg' , 'webp' , 'info.json' ,)):
225
+ other_path = video_path .with_suffix (f'.{ suffix } ' ).resolve ()
226
+ log .info (f'Deleting file for: { instance } path: { other_path !s} ' )
227
+ delete_file (other_path )
228
+ # Jellyfin creates .trickplay directories and posters
229
+ for suffix in frozenset (('.trickplay' , '-poster.jpg' , '-poster.webp' ,)):
230
+ # with_suffix insists on suffix beginning with '.' for no good reason
231
+ other_path = Path (str (video_path .with_suffix ('' )) + suffix ).resolve ()
232
+ if other_path .is_file ():
233
+ log .info (f'Deleting file for: { instance } path: { other_path !s} ' )
234
+ delete_file (other_path )
235
+ elif other_path .is_dir ():
236
+ # Delete the contents of the directory
237
+ paths = list (other_path .rglob ('*' ))
238
+ attempts = len (paths )
239
+ while paths and attempts > 0 :
240
+ attempts -= 1
241
+ # delete files first
242
+ for p in list (filter (lambda x : x .is_file (), paths )):
243
+ log .info (f'Deleting file for: { instance } path: { p !s} ' )
244
+ delete_file (p )
245
+ # refresh the list
246
+ paths = list (other_path .rglob ('*' ))
247
+ # delete directories
248
+ # a directory with a subdirectory will fail
249
+ # we loop to try removing each of them
250
+ # a/b/c: c then b then a, 3 times around the loop
251
+ for p in list (filter (lambda x : x .is_dir (), paths )):
252
+ try :
253
+ p .rmdir ()
254
+ log .info (f'Deleted directory for: { instance } path: { p !s} ' )
255
+ except OSError as e :
256
+ pass
257
+ # Delete the directory itself
258
+ try :
259
+ other_path .rmdir ()
260
+ log .info (f'Deleted directory for: { instance } path: { other_path !s} ' )
261
+ except OSError as e :
262
+ pass
215
263
# Get all files that start with the bare file path
216
- all_related_files = glob . glob (f'{ barefilepath } . *' )
264
+ all_related_files = video_path . parent . glob (f'{ glob_quote ( video_path . with_suffix ( "" ). name ) } *' )
217
265
for file in all_related_files :
218
266
log .info (f'Deleting file for: { instance } path: { file } ' )
219
267
delete_file (file )
220
268
221
-
222
- @receiver (post_delete , sender = Media )
223
- def media_post_delete (sender , instance , ** kwargs ):
224
269
# Schedule a task to update media servers
225
270
for mediaserver in MediaServer .objects .all ():
226
271
log .info (f'Scheduling media server updates' )
@@ -231,3 +276,4 @@ def media_post_delete(sender, instance, **kwargs):
231
276
verbose_name = verbose_name .format (mediaserver ),
232
277
remove_existing_tasks = True
233
278
)
279
+
0 commit comments