1 # -*- coding: utf-8 -*-
3 # gPodder - A media aggregator and podcast client
4 # Copyright (c) 2005-2018 The gPodder Team
6 # gPodder is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 3 of the License, or
9 # (at your option) any later version.
11 # gPodder is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 # GNU General Public License for more details.
16 # You should have received a copy of the GNU General Public License
17 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 # gpodder.common - Common helper functions for all UIs
21 # Thomas Perl <thp@gpodder.org>; 2012-08-16
29 from gpodder
import util
31 logger
= logging
.getLogger(__name__
)
34 def clean_up_downloads(delete_partial
=False):
35 """Clean up temporary files left behind by old gPodder versions
37 delete_partial - If True, also delete in-progress downloads
39 temporary_files
= glob
.glob('%s/*/.tmp-*' % gpodder
.downloads
)
42 temporary_files
+= glob
.glob('%s/*/*.partial' % gpodder
.downloads
)
43 # youtube-dl creates .partial.* files for adaptive formats
44 temporary_files
+= glob
.glob('%s/*/*.partial.*' % gpodder
.downloads
)
46 for tempfile
in temporary_files
:
47 util
.delete_file(tempfile
)
50 def find_partial_downloads(channels
, start_progress_callback
, progress_callback
, finish_progress_callback
):
51 """Find partial downloads and match them with episodes
53 channels - A list of all model.PodcastChannel objects
54 start_progress_callback - A callback(count) when partial files are searched
55 progress_callback - A callback(title, progress) when an episode was found
56 finish_progress_callback - A callback(resumable_episodes) when finished
58 # Look for partial file downloads, ignoring .partial.* files created by youtube-dl
59 partial_files
= glob
.glob(os
.path
.join(gpodder
.downloads
, '*', '*.partial'))
60 count
= len(partial_files
)
61 resumable_episodes
= []
62 start_progress_callback(count
)
64 candidates
= [f
[:-len('.partial')] for f
in partial_files
]
67 for channel
in channels
:
68 for episode
in channel
.get_all_episodes():
69 filename
= episode
.local_filename(create
=False, check_only
=True)
70 if filename
in candidates
:
72 progress_callback(episode
.title
, found
/ count
)
73 candidates
.remove(filename
)
74 partial_files
.remove(filename
+ '.partial')
76 if os
.path
.exists(filename
):
77 # The file has already been downloaded;
78 # remove the leftover partial file
79 util
.delete_file(filename
+ '.partial')
81 resumable_episodes
.append(episode
)
89 for f
in partial_files
:
90 logger
.warning('Partial file without episode: %s', f
)
93 # never delete partial: either we can't clean them up because we offer to
94 # resume download or there are none to delete in the first place.
95 clean_up_downloads(delete_partial
=False)
96 finish_progress_callback(resumable_episodes
)
99 def get_expired_episodes(channels
, config
):
100 for channel
in channels
:
101 for index
, episode
in enumerate(channel
.get_episodes(gpodder
.STATE_DOWNLOADED
)):
102 # Never consider archived episodes as old
106 # Download strategy "Only keep latest"
107 if (channel
.download_strategy
== channel
.STRATEGY_LATEST
109 logger
.info('Removing episode (only keep latest strategy): %s',
114 # Only expire episodes if the age in days is positive
115 if config
.auto
.cleanup
.days
< 1:
118 # Never consider fresh episodes as old
119 if episode
.age_in_days() < config
.auto
.cleanup
.days
:
122 # Do not delete played episodes (except if configured)
123 if not episode
.is_new
:
124 if not config
.auto
.cleanup
.played
:
127 # Do not delete unfinished episodes (except if configured)
128 if not episode
.is_finished():
129 if not config
.auto
.cleanup
.unfinished
:
132 # Do not delete unplayed episodes (except if configured)
134 if not config
.auto
.cleanup
.unplayed
: