def __init__( self): log('Creating gPodderLib()', sender=self) if gpodder.interface == gpodder.MAEMO: gpodder_dir='/media/mmc2/gpodder/' self.osso_c=osso.Context('gpodder_osso_sender', '1.0', False) else: gpodder_dir=os.path.expanduser('~/.config/gpodder/') util.make_directory( gpodder_dir) self.tempdir=gpodder_dir self.feed_cache_file=os.path.join(gpodder_dir, 'feedcache.pickle.db') self.channel_settings_file=os.path.join(gpodder_dir, 'channelsettings.pickle.db') self.episode_metainfo_file=os.path.join(gpodder_dir, 'episodemetainfo.pickle.db') self.channel_opml_file=os.path.join(gpodder_dir, 'channels.opml') self.channel_xml_file=os.path.join(gpodder_dir, 'channels.xml') if os.path.exists(self.channel_xml_file) and not os.path.exists(self.channel_opml_file): log('Trying to migrate channel list (channels.xml => channels.opml)', sender=self) self.migrate_channels_xml() self.config=config.Config( os.path.join( gpodder_dir, 'gpodder.conf')) util.make_directory(self.config.bittorrent_dir) # We need to make a seamless upgrade, so by default the video player is not specified # so the first time this application is run it will detect this and set it to the same # as the audio player. This keeps gPodder functionality identical to that prior to the # upgrade. The user can then set a specific video player if they so wish. if self.config.videoplayer == 'unspecified': self.config.videoplayer=self.config.player self.__download_history=HistoryStore( os.path.join( gpodder_dir, 'download-history.txt')) self.__playback_history=HistoryStore( os.path.join( gpodder_dir, 'playback-history.txt')) self.__locked_history=HistoryStore( os.path.join( gpodder_dir, 'lock-history.txt'))
def __init__(self): """Create a new gPodder API instance Connects to the database and loads the configuration. """ util.make_directory(gpodder.home) gpodder.load_plugins() self._db = dbsqlite.Database(gpodder.database_file) self._config = config.Config(gpodder.config_file)
def __init__(self, config_class=config.Config, database_class=storage.Database, model_class=model.Model, prefix=None, verbose=True, progname='gpodder'): self._set_socket_timeout() self.prefix = prefix if not self.prefix: # XXX self.prefix = os.path.abspath('.') home = os.path.expanduser('~') xdg_data_home = os.environ.get('XDG_DATA_HOME', os.path.join(home, '.local', 'share')) xdg_config_home = os.environ.get('XDG_CONFIG_HOME', os.path.join(home, '.config')) xdg_cache_home = os.environ.get('XDG_CACHE_HOME', os.path.join(home, '.cache')) self.data_home = os.path.join(xdg_data_home, progname) self.config_home = os.path.join(xdg_config_home, progname) self.cache_home = os.path.join(xdg_cache_home, progname) # Use $GPODDER_HOME to set a fixed config and data folder if 'GPODDER_HOME' in os.environ: home = os.environ['GPODDER_HOME'] self.data_home = self.config_home = self.cache_home = home # Setup logging log.setup(self.cache_home, verbose) self.logger = logging.getLogger(__name__) config_file = os.path.join(self.config_home, 'Settings.json') database_file = os.path.join(self.data_home, 'Database') # Downloads go to <data_home> or $GPODDER_DOWNLOAD_DIR self.downloads = os.environ.get('GPODDER_DOWNLOAD_DIR', os.path.join(self.data_home)) # Initialize the gPodder home directories util.make_directory(self.data_home) util.make_directory(self.config_home) # Open the database and configuration file self.db = database_class(database_file) self.model = model_class(self) self.config = config_class(config_file) # Load installed/configured plugins self._load_plugins() self.cover_downloader = coverart.CoverDownloader(self)
def __init__(self, config_class=config.Config, database_class=storage.Database, model_class=model.Model, verbose=True, progname='gpodder', stdout=False): self._set_socket_timeout() home = os.path.expanduser('~') xdg_data_home = os.environ.get('XDG_DATA_HOME', os.path.join(home, '.local', 'share')) xdg_config_home = os.environ.get('XDG_CONFIG_HOME', os.path.join(home, '.config')) xdg_cache_home = os.environ.get('XDG_CACHE_HOME', os.path.join(home, '.cache')) self.data_home = os.path.join(xdg_data_home, progname) self.config_home = os.path.join(xdg_config_home, progname) self.cache_home = os.path.join(xdg_cache_home, progname) # Use $GPODDER_HOME to set a fixed config and data folder if 'GPODDER_HOME' in os.environ: home = os.environ['GPODDER_HOME'] self.data_home = self.config_home = self.cache_home = home # Setup logging log.setup(self.cache_home, verbose, stdout) self.logger = logging.getLogger(__name__) config_file = os.path.join(self.config_home, 'Settings.json') database_file = os.path.join(self.data_home, 'Database') # Downloads go to <data_home> or $GPODDER_DOWNLOAD_DIR self.downloads = os.environ.get('GPODDER_DOWNLOAD_DIR', os.path.join(self.data_home)) # Initialize the gPodder home directories util.make_directory(self.data_home) util.make_directory(self.config_home) # Open the database and configuration file self.db = database_class(database_file, verbose) self.model = model_class(self) self.config = config_class(config_file) # Load installed/configured plugins self._load_plugins() self.cover_downloader = coverart.CoverDownloader(self)
def add_track(self, task, reporthook=None): episode = task.episode self.notify('status', _('Adding %s') % episode.title) # get the folder on the device folder = self.get_episode_folder_on_device(episode) filename = episode.local_filename(create=False) # The file has to exist, if we ought to transfer it, and therefore, # local_filename(create=False) must never return None as filename assert filename is not None from_file = filename # verify free space needed = util.calculate_size(from_file) free = self.get_free_space() if free == -1: logger.warn('Cannot determine free disk space on device') elif needed > free: d = {'path': self.destination, 'free': util.format_filesize(free), 'need': util.format_filesize(needed)} message = _('Not enough space in %(path)s: %(free)s available, but need at least %(need)s') raise SyncFailedException(message % d) # get the filename that will be used on the device to_file = self.get_episode_file_on_device(episode) to_file = folder.get_child(to_file) util.make_directory(folder) if not to_file.query_exists(): logger.info('Copying %s => %s', os.path.basename(from_file), to_file.get_uri()) from_file = Gio.File.new_for_path(from_file) try: def hookconvert(current_bytes, total_bytes, user_data): return reporthook(current_bytes, 1, total_bytes) from_file.copy(to_file, Gio.FileCopyFlags.OVERWRITE, task.cancellable, hookconvert, None) except GLib.Error as err: if err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED): raise SyncCancelledException() logger.error('Error copying %s to %s: %s', from_file.get_uri(), to_file.get_uri(), err.message) d = {'from_file': from_file.get_uri(), 'to_file': to_file.get_uri(), 'message': err.message} self.errors.append(_('Error copying %(from_file)s to %(to_file)s: %(message)s') % d) return False return True
def write_m3u(self): """ write the list into the playlist on the device """ log('Writing playlist file: %s', self.playlist_file, sender=self) playlist_folder = os.path.split(self.playlist_file)[0] if not util.make_directory(playlist_folder): self.show_message( _('Folder %s could not be created.') % playlist_folder, _('Error writing playlist')) else: try: fp = open(self.playlist_file, 'w') fp.write('#EXTM3U%s' % self.linebreak) for icon, checked, filename in self.playlist: fp.write(self.build_extinf(filename)) if not checked: fp.write('#') fp.write(filename) fp.write(self.linebreak) fp.close() self.show_message( _('The playlist on your MP3 player has been updated.'), _('Update successful')) except IOError, ioe: self.show_message(str(ioe), _('Error writing playlist file'))
def write_m3u(self, episodes): """ write the list into the playlist on the device """ logger.info('Writing playlist file: %s', self.playlist_file) if not util.make_directory(self.playlist_folder): raise IOError( _('Folder %s could not be created.') % self.playlist_folder, _('Error writing playlist')) else: fp = open(os.path.join(self.playlist_folder, self.playlist_file), 'w') fp.write('#EXTM3U%s' % self.linebreak) for current_episode in episodes: filename_base = util.sanitize_filename( current_episode.sync_filename( self._config.device_sync.custom_sync_name_enabled, self._config.device_sync.custom_sync_name), self._config.device_sync.max_filename_length) filename = filename_base + os.path.splitext( current_episode.local_filename(create=False))[1].lower() filename = self.get_filename_for_playlist(current_episode) fp.write(self.build_extinf(filename)) filename = self.get_absolute_filename_for_playlist( current_episode) fp.write(filename) fp.write(self.linebreak) fp.close()
def get_save_dir(self, force_new=False): if self.download_folder is None or force_new: # we must change the folder name, because it has not been set manually fn_template = util.sanitize_filename(self.title, self.MAX_FOLDERNAME_LENGTH) if not fn_template: fn_template = util.sanitize_filename(self.url, self.MAX_FOLDERNAME_LENGTH) # Find a unique folder name for this podcast download_folder = self.find_unique_folder_name(fn_template) # Try renaming the download folder if it has been created previously if self.download_folder is not None: old_folder = os.path.join(self.model.core.downloads, self.download_folder) new_folder = os.path.join(self.model.core.downloads, download_folder) try: os.rename(old_folder, new_folder) except Exception as ex: logger.info('Cannot rename old download folder: %s', old_folder, exc_info=True) logger.info('Updating download_folder of %s to %s', self.url, download_folder) self.download_folder = download_folder self.save() save_dir = os.path.join(self.model.core.downloads, self.download_folder) # Create save_dir if it does not yet exist if not util.make_directory(save_dir): logger.error('Could not create save_dir: %s', save_dir) return save_dir
def get_save_dir(self, force_new=False): if self.download_folder is None or force_new: # we must change the folder name, because it has not been set manually fn_template = util.sanitize_filename(self.title, self.MAX_FOLDERNAME_LENGTH) if not fn_template: fn_template = util.sanitize_filename(self.url, self.MAX_FOLDERNAME_LENGTH) # Find a unique folder name for this podcast download_folder = self.find_unique_folder_name(fn_template) # Try removing the download folder if it has been created previously if self.download_folder is not None: folder = os.path.join(gpodder.downloads, self.download_folder) try: os.rmdir(folder) except OSError: logger.info('Old download folder is kept for %s', self.url) logger.info('Updating download_folder of %s to %s', self.url, download_folder) self.download_folder = download_folder self.save() save_dir = os.path.join(gpodder.downloads, self.download_folder) # Create save_dir if it does not yet exist if not util.make_directory(save_dir): logger.error('Could not create save_dir: %s', save_dir) return save_dir
def write_m3u(self, episodes): """ write the list into the playlist on the device """ logger.info('Writing playlist file: %s', self.playlist_file) if not util.make_directory(self.playlist_folder): raise IOError(_('Folder %s could not be created.') % self.playlist_folder, _('Error writing playlist')) else: # work around libmtp devices potentially having limited capabilities for partial writes is_mtp = self.playlist_folder.get_uri().startswith("mtp://") tempfile = None if is_mtp: tempfile = Gio.File.new_tmp() fs = tempfile[1].get_output_stream() else: fs = self.playlist_absolute_filename.replace(None, False, Gio.FileCreateFlags.NONE) os = Gio.DataOutputStream.new(fs) os.put_string('#EXTM3U%s' % self.linebreak) for current_episode in episodes: filename = self.get_filename_for_playlist(current_episode) os.put_string(self.build_extinf(filename)) filename = self.get_absolute_filename_for_playlist(current_episode) os.put_string(filename) os.put_string(self.linebreak) os.close() if is_mtp: try: tempfile[0].copy(self.playlist_absolute_filename, Gio.FileCopyFlags.OVERWRITE) except GLib.Error as err: logger.error('copying playlist to mtp device file %s failed: %s', self.playlist_absolute_filename.get_uri(), err.message) tempfile[0].delete()
def get_save_dir(self, force_new=False): if self.download_folder is None or force_new: # we must change the folder name, because it has not been set manually fn_template = util.sanitize_filename(self.title, self.MAX_FOLDERNAME_LENGTH) if not fn_template: fn_template = util.sanitize_filename(self.url, self.MAX_FOLDERNAME_LENGTH) # Find a unique folder name for this podcast download_folder = self.find_unique_folder_name(fn_template) # Try removing the download folder if it has been created previously if self.download_folder is not None: folder = os.path.join(gpodder.downloads, self.download_folder) try: os.rmdir(folder) except OSError: logger.info("Old download folder is kept for %s", self.url) logger.info("Updating download_folder of %s to %s", self.url, download_folder) self.download_folder = download_folder self.save() save_dir = os.path.join(gpodder.downloads, self.download_folder) # Avoid encoding errors for OS-specific functions (bug 1570) save_dir = util.sanitize_encoding(save_dir) # Create save_dir if it does not yet exist if not util.make_directory(save_dir): logger.error("Could not create save_dir: %s", save_dir) return save_dir
def get_save_dir(self): save_dir=os.path.join(gl.downloaddir, self.filename, '') # Create save_dir if it does not yet exist if not util.make_directory( save_dir): log( 'Could not create save_dir: %s', save_dir, sender=self) return save_dir
def __init__(self, config_class=config.Config, database_class=dbsqlite.Database, model_class=model.Model): # Initialize the gPodder home directory util.make_directory(gpodder.home) # Open the database and configuration file self.db = database_class(gpodder.database_file) self.model = model_class(self.db) self.config = config_class(gpodder.config_file) # Load extension modules and install the extension manager gpodder.user_extensions = extensions.ExtensionManager(self) # Load installed/configured plugins gpodder.load_plugins() # Update the current device in the configuration self.config.mygpo.device.type = util.detect_device_type()
def __init__(self, config_class=config.Config, database_class=dbsqlite.Database, model_class=model.Model): # Initialize the gPodder home directory util.make_directory(gpodder.home) # Load hook modules and install the hook manager gpodder.user_hooks = hooks.HookManager() # Load installed/configured plugins gpodder.load_plugins() # Open the database and configuration file self.db = database_class(gpodder.database_file) self.model = model_class(self.db) self.config = config_class(gpodder.config_file) # Update the current device in the configuration self.config.mygpo_device_type = util.detect_device_type()
def get_save_dir(self): urldigest = hashlib.md5(self.url).hexdigest() sanitizedurl = util.sanitize_filename(self.url, self.MAX_FOLDERNAME_LENGTH) if self.foldername is None or (self.auto_foldername and (self.foldername == urldigest or self.foldername.startswith(sanitizedurl))): # we must change the folder name, because it has not been set manually fn_template = util.sanitize_filename(self.title, self.MAX_FOLDERNAME_LENGTH) # if this is an empty string, try the basename if len(fn_template) == 0: log('That is one ugly feed you have here! (Report this to bugs.gpodder.org: %s)', self.url, sender=self) fn_template = util.sanitize_filename(os.path.basename(self.url), self.MAX_FOLDERNAME_LENGTH) # If the basename is also empty, use the first 6 md5 hexdigest chars of the URL if len(fn_template) == 0: log('That is one REALLY ugly feed you have here! (Report this to bugs.gpodder.org: %s)', self.url, sender=self) fn_template = urldigest # no need for sanitize_filename here # Find a unique folder name for this podcast wanted_foldername = self.find_unique_folder_name(fn_template) # if the foldername has not been set, check if the (old) md5 filename exists if self.foldername is None and os.path.exists(os.path.join(self.download_dir, urldigest)): log('Found pre-0.15.0 download folder for %s: %s', self.title, urldigest, sender=self) self.foldername = urldigest # we have a valid, new folder name in "current_try" -> use that! if self.foldername is not None and wanted_foldername != self.foldername: # there might be an old download folder crawling around - move it! new_folder_name = os.path.join(self.download_dir, wanted_foldername) old_folder_name = os.path.join(self.download_dir, self.foldername) if os.path.exists(old_folder_name): if not os.path.exists(new_folder_name): # Old folder exists, new folder does not -> simply rename log('Renaming %s => %s', old_folder_name, new_folder_name, sender=self) os.rename(old_folder_name, new_folder_name) else: # Both folders exist -> move files and delete old folder log('Moving files from %s to %s', old_folder_name, new_folder_name, sender=self) for file in glob.glob(os.path.join(old_folder_name, '*')): shutil.move(file, new_folder_name) log('Removing %s', old_folder_name, sender=self) shutil.rmtree(old_folder_name, ignore_errors=True) log('Updating foldername of %s to "%s".', self.url, wanted_foldername, sender=self) self.foldername = wanted_foldername self.save() save_dir = os.path.join(self.download_dir, self.foldername) # Create save_dir if it does not yet exist if not util.make_directory( save_dir): log( 'Could not create save_dir: %s', save_dir, sender = self) return save_dir
def __init__(self, config_class=config.Config, database_class=dbsqlite.Database, model_class=model.Model): # Initialize the gPodder home directory util.make_directory(gpodder.home) # Open the database and configuration file self.db = database_class(gpodder.database_file) self.model = model_class(self.db) self.config = config_class(gpodder.config_file) # Load extension modules and install the extension manager gpodder.user_extensions = extensions.ExtensionManager(self) # Load installed/configured plugins gpodder.load_plugins() # Update the current device in the configuration self.config.mygpo.device.type = util.detect_device_type() # Initialize Flattr integration self.flattr = flattr.Flattr(self.config.flattr)
def write_m3u(self, episodes): """ write the list into the playlist on the device """ logger.info('Writing playlist file: %s', self.playlist_file) if not util.make_directory(self.playlist_folder): raise IOError(_('Folder %s could not be created.') % self.playlist_folder, _('Error writing playlist')) else: fp = open(os.path.join(self.playlist_folder, self.playlist_file), 'w') fp.write('#EXTM3U%s' % self.linebreak) for current_episode in episodes: filename = self.get_filename_for_playlist(current_episode) fp.write(self.build_extinf(filename)) filename = self.get_absolute_filename_for_playlist(current_episode) fp.write(filename) fp.write(self.linebreak) fp.close()
def write_m3u(self, episodes): """ write the list into the playlist on the device """ logger.info('Writing playlist file: %s', self.playlist_file) if not util.make_directory(self.playlist_folder): raise IOError( _('Folder %s could not be created.') % self.playlist_folder, _('Error writing playlist')) else: fp = open(os.path.join(self.playlist_folder, self.playlist_file), 'w') fp.write('#EXTM3U%s' % self.linebreak) for current_episode in episodes: filename = self.get_filename_for_playlist(current_episode) fp.write(self.build_extinf(filename)) filename = self.get_absolute_filename_for_playlist( current_episode) fp.write(filename) fp.write(self.linebreak) fp.close()
def write_m3u(self): """ write the list into the playlist on the device """ log('Writing playlist file: %s', self.playlist_file, sender=self) playlist_folder = os.path.split(self.playlist_file)[0] if not util.make_directory(playlist_folder): self.show_message(_('Folder %s could not be created.') % playlist_folder, _('Error writing playlist')) else: try: fp = open(self.playlist_file, 'w') fp.write('#EXTM3U%s' % self.linebreak) for icon, checked, filename in self.playlist: fp.write(self.build_extinf(filename)) if not checked: fp.write('#') fp.write(filename) fp.write(self.linebreak) fp.close() self.show_message(_('The playlist on your MP3 player has been updated.'), _('Update successful')) except IOError, ioe: self.show_message(str(ioe), _('Error writing playlist file'))
def write_m3u(self, episodes): """ write the list into the playlist on the device """ logger.info('Writing playlist file: %s', self.playlist_file) if not util.make_directory(self.playlist_folder): raise IOError(_('Folder %s could not be created.') % self.playlist_folder, _('Error writing playlist')) else: fp = open(os.path.join(self.playlist_folder, self.playlist_file), 'w') fp.write('#EXTM3U%s' % self.linebreak) for current_episode in episodes: filename_base = util.sanitize_filename(current_episode.sync_filename( self._config.device_sync.custom_sync_name_enabled, self._config.device_sync.custom_sync_name), self._config.device_sync.max_filename_length) filename = filename_base + os.path.splitext(current_episode.local_filename(create=False))[1].lower() filename = self.get_filename_for_playlist(current_episode) fp.write(self.build_extinf(filename)) filename = self.get_absolute_filename_for_playlist(current_episode) fp.write(filename) fp.write(self.linebreak) fp.close()
def get_download_dir( self): util.make_directory( self.config.download_dir) return self.config.download_dir
def check_download_folder(self): """Check the download folder for externally-downloaded files This will try to assign downloaded files with episodes in the database and (failing that) will move downloaded files into the "Unknown" subfolder in the download directory, so that the user knows that gPodder doesn't know to which episode the file belongs (the "Unknown" folder may be used by external tools or future gPodder versions for better import support). This will also cause missing files to be marked as deleted. """ known_files = set() for episode in self.get_downloaded_episodes(): if episode.was_downloaded(): filename = episode.local_filename(create=False) if not os.path.exists(filename): # File has been deleted by the user - simulate a # delete event (also marks the episode as deleted) logger.debug('Episode deleted: %s', filename) episode.delete_from_disk() continue known_files.add(filename) existing_files = set(filename for filename in \ glob.glob(os.path.join(self.save_dir, '*')) \ if not filename.endswith('.partial')) external_files = existing_files.difference(list(known_files) + \ [os.path.join(self.save_dir, x) \ for x in ('folder.jpg', 'Unknown')]) if not external_files: return all_episodes = self.get_all_episodes() for filename in external_files: found = False basename = os.path.basename(filename) existing = [e for e in all_episodes if e.download_filename == basename] if existing: existing = existing[0] logger.info('Importing external download: %s', filename) existing.on_downloaded(filename) continue for episode in all_episodes: wanted_filename = episode.local_filename(create=True, \ return_wanted_filename=True) if basename == wanted_filename: logger.info('Importing external download: %s', filename) episode.download_filename = basename episode.on_downloaded(filename) found = True break wanted_base, wanted_ext = os.path.splitext(wanted_filename) target_base, target_ext = os.path.splitext(basename) if wanted_base == target_base: # Filenames only differ by the extension wanted_type = util.file_type_by_extension(wanted_ext) target_type = util.file_type_by_extension(target_ext) # If wanted type is None, assume that we don't know # the right extension before the download (e.g. YouTube) # if the wanted type is the same as the target type, # assume that it's the correct file if wanted_type is None or wanted_type == target_type: logger.info('Importing external download: %s', filename) episode.download_filename = basename episode.on_downloaded(filename) found = True break if not found: logger.warn('Unknown external file: %s', filename) target_dir = os.path.join(self.save_dir, 'Unknown') if util.make_directory(target_dir): target_file = os.path.join(target_dir, basename) logger.info('Moving %s => %s', filename, target_file) try: shutil.move(filename, target_file) except Exception, e: logger.error('Could not move file: %s', e, exc_info=True)