def set_icon(self, icon): def set_from_theme_icon(name): if self.indicator: logger.info(lambda: "Showing indicator icon %s from GTK theme" % name) self.indicator.set_icon(name) if self.status_icon: logger.info(lambda: "Showing status icon %s from GTK theme" % name) self.status_icon.set_from_icon_name(name) if icon == "Light": if Gtk.IconTheme.get_default().has_icon(THEME_ICON_NAME): set_from_theme_icon(THEME_ICON_NAME) return else: icon_path = varietyconfig.get_data_file("media", "variety-indicator.png") elif icon == "Dark": if Gtk.IconTheme.get_default().has_icon(THEME_ICON_NAME_DARK): set_from_theme_icon(THEME_ICON_NAME_DARK) return else: icon_path = varietyconfig.get_data_file("media", "variety-indicator-dark.png") elif icon and os.access(icon, os.R_OK) and Util.is_image(icon): icon_path = icon else: icon_path = varietyconfig.get_data_file("media", "variety-indicator.png") if self.indicator: logger.info(lambda: "Showing indicator icon image: " + icon_path) self.indicator.set_icon(icon_path) if self.status_icon: logger.info(lambda: "Showing status icon image: " + icon_path) self.status_icon.set_from_file(icon_path)
def is_valid_content(x): return (x is not None and "url" in x.attrib and (Util.is_image(x.attrib["url"]) or ("medium" in x.attrib and x.attrib["medium"].lower() == "image") or ("type" in x.attrib and x.attrib["type"].lower().startswith("image/"))))
def is_valid_content(x): return ( x is not None and "url" in x.attrib and ( Util.is_image(x.attrib["url"]) or ("medium" in x.attrib and x.attrib["medium"].lower() == "image") or ("type" in x.attrib and x.attrib["type"].lower().startswith("image/")) ) )
def test_legacy_fallback_download_one(self): source = WallhavenSource() mock = MagicMock() mock.options.wallhaven_api_key = "" source.set_variety(mock) with tempfile.TemporaryDirectory() as tmpdir: dl = source.create_downloader( "https://wallhaven.cc/user/lewdpatriot/favorites/935888") dl.update_download_folder(tmpdir) for _ in range(5): f = dl.download_one() if f and os.path.isfile(f) and Util.is_image( f, check_contents=True): return self.fail("Tried download_one 5 times, all failed")
def test_is_image(self): self.assertTrue(Util.is_image("test.jpg")) self.assertTrue(Util.is_image("test.jpg", check_contents=True)) self.assertTrue(Util.is_image("fake_image.jpg")) self.assertFalse(Util.is_image("fake_image.jpg", check_contents=True))
def save_locally( self, origin_url, image_url, source_type=None, source_location=None, source_name=None, force_download=False, extra_metadata=None, local_filename=None, request_headers=None, request_kwargs=None, ): source_type = source_type or self.get_source_type() source_name = source_name or self.get_source_name() source_location = source_location or self.get_source_location( ) or self.get_description() if not force_download and self.is_in_banned(origin_url): logger.info( lambda: "URL " + origin_url + " is banned, skip downloading") return None try: os.makedirs(self.target_folder) except Exception: pass if origin_url.startswith("//"): origin_url = "https:" + origin_url if image_url.startswith("//"): image_url = origin_url.split("//")[0] + image_url # we will download the contents to a ".partial" file, then rename it to the proper name if not local_filename: local_filename = self.get_local_filename(url=image_url) local_filepath = self._local_filepath(local_filename=local_filename) local_filepath_partial = local_filepath + ".partial" logger.info(lambda: "Origin URL: " + origin_url) logger.info(lambda: "Image URL: " + image_url) logger.info(lambda: "Local path: " + local_filepath) if not force_download and os.path.exists(local_filepath): logger.info(lambda: "File already exists, skip downloading") return None is_unsafe, blacklisted = self.is_unsafe(extra_metadata or {}) if is_unsafe: logger.info( lambda: "Skipping non-safe download %s due to blacklisted keywords (%s). " "Is the source %s:%s suitable for Safe mode?" % (origin_url, str(blacklisted), source_type, source_location)) return None try: r = Util.request(image_url, stream=True, headers=request_headers, **(request_kwargs or {})) with open(local_filepath_partial, "wb") as f: Util.request_write_to(r, f) except Exception as e: logger.info( lambda: "Download failed from image URL: %s (source location: %s) " % (image_url, source_location)) Util.safe_unlink(local_filepath_partial) raise e if not Util.is_image(local_filepath_partial, check_contents=True): logger.info( lambda: "Downloaded data was not an image, image URL might be outdated" ) Util.safe_unlink(local_filepath_partial) return None metadata = { "sourceType": source_type, "sourceName": source_name, "sourceLocation": source_location, "sourceURL": origin_url, "imageURL": image_url, } metadata.update(extra_metadata or {}) Util.write_metadata(local_filepath_partial, metadata) # file rename is an atomic operation, so we should never end up with partial downloads os.rename(local_filepath_partial, local_filepath) logger.info(lambda: "Download complete") return local_filepath
class Downloader(object): def __init__(self, parent, source_type, name, location, is_refresher=False): self.parent = parent self.source_type = source_type self.name = name self.location = location self.is_refresher = is_refresher def update_download_folder(self): filename = self.convert_to_filename(self.location) l = len(self.parent.real_download_folder) if len(filename) + l > 160: filename = filename[:(150 - l)] + Util.md5(filename)[:10] self.target_folder = os.path.join(self.parent.real_download_folder, filename) def convert_to_filename(self, url): url = re.sub(r"http://", "", url) url = re.sub(r"https://", "", url) valid_chars = "_%s%s" % (string.ascii_letters, string.digits) return ''.join(c if c in valid_chars else '_' for c in url) def get_local_filename(self, url): return os.path.join(self.target_folder, Util.get_local_name(url)) def is_in_downloaded(self, url): return os.path.exists(self.get_local_filename(url)) def is_in_favorites(self, url): return self.parent and os.path.exists( os.path.join(self.parent.options.favorites_folder, Util.get_local_name(url))) def save_locally(self, origin_url, image_url, source_type=None, source_location=None, source_name=None, force_download=False, extra_metadata={}, local_filename=None): if not source_type: source_type = self.source_type if not source_name: source_name = self.name if not source_location: source_location = self.location if not force_download and self.parent and origin_url in self.parent.banned: logger.info( lambda: "URL " + origin_url + " is banned, skip downloading") return None try: os.makedirs(self.target_folder) except Exception: pass if origin_url.startswith('//'): origin_url = 'https:' + origin_url if image_url.startswith('//'): image_url = origin_url.split('//')[0] + image_url if not local_filename: local_filename = self.get_local_filename(image_url) logger.info(lambda: "Origin URL: " + origin_url) logger.info(lambda: "Image URL: " + image_url) logger.info(lambda: "Local name: " + local_filename) if not force_download and os.path.exists(local_filename): logger.info(lambda: "File already exists, skip downloading") return None if self.parent and self.parent.options.safe_mode: sfw_rating = Smart.get_sfw_rating(origin_url) if sfw_rating is not None and sfw_rating < 100: logger.info( lambda: "Skipping non-safe download %s. Is the source %s:%s " "suitable for Safe mode?" % (origin_url, source_type, self.location)) return None if self.parent and self.parent.options.safe_mode and 'keywords' in extra_metadata: blacklisted = set(k.lower() for k in extra_metadata['keywords'] ) & Smart.get_safe_mode_keyword_blacklist() if len(blacklisted) > 0: logger.info( lambda: "Skipping non-safe download %s due to blacklisted keywords (%s). " "Is the source %s:%s suitable for Safe mode?" % (origin_url, str(blacklisted), source_type, self.location)) return None try: r = Util.request(image_url, stream=True) with open(local_filename, 'wb') as f: Util.request_write_to(r, f) except Exception, e: logger.info( lambda: "Download failed from image URL: %s (source location: %s) " % (image_url, self.location)) raise e if not Util.is_image(local_filename, check_contents=True): logger.info( lambda: "Downloaded data was not an image, image URL might be outdated" ) os.unlink(local_filename) return None metadata = { "sourceType": source_type, "sourceName": source_name, "sourceLocation": source_location, "sourceURL": origin_url, "imageURL": image_url } metadata.update(extra_metadata) Util.write_metadata(local_filename, metadata) logger.info(lambda: "Download complete") return local_filename
def read(self): self.set_defaults() try: config = self.read_config() needs_writing = self.fix_outdated(config) try: self.change_enabled = config["change_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.change_on_start = config["change_on_start"].lower( ) in TRUTH_VALUES except Exception: pass try: self.change_interval = int(config["change_interval"]) if self.change_interval < 5: self.change_interval = 5 except Exception: pass try: self.safe_mode = config["safe_mode"].lower() in TRUTH_VALUES except Exception: pass try: self.download_folder = os.path.expanduser( config["download_folder"]) except Exception: pass try: self.download_preference_ratio = max( 0, min(1, float(config["download_preference_ratio"]))) except Exception: pass try: self.quota_enabled = config["quota_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.quota_size = max(50, int(config["quota_size"])) except Exception: pass try: self.favorites_folder = os.path.expanduser( config["favorites_folder"]) except Exception: pass try: favorites_ops_text = config["favorites_operations"] self.favorites_operations = list([ x.strip().split(":") for x in favorites_ops_text.split(";") if x ]) except Exception: pass try: self.fetched_folder = os.path.expanduser( config["fetched_folder"]) except Exception: pass try: self.clipboard_enabled = config["clipboard_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.clipboard_use_whitelist = ( config["clipboard_use_whitelist"].lower() in TRUTH_VALUES) except Exception: pass try: self.clipboard_hosts = config["clipboard_hosts"].lower().split( ",") except Exception: pass try: icon = config["icon"] if icon in [ "Light", "Dark", "Current", "1", "2", "3", "4", "None" ] or (os.access(icon, os.R_OK) and Util.is_image(icon)): self.icon = icon except Exception: pass try: self.desired_color_enabled = config[ "desired_color_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.desired_color = list( map(int, config["desired_color"].split())) for i, x in enumerate(self.desired_color): self.desired_color[i] = max(0, min(255, x)) except Exception: self.desired_color = None try: self.min_size_enabled = config["min_size_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.min_size = int(config["min_size"]) self.min_size = max(0, min(100, self.min_size)) except Exception: pass try: self.use_landscape_enabled = config[ "use_landscape_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.lightness_enabled = config["lightness_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.lightness_mode = int(config["lightness_mode"]) self.lightness_mode = max(0, min(1, self.lightness_mode)) except Exception: pass try: self.min_rating_enabled = config["min_rating_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.min_rating = int(config["min_rating"]) self.min_rating = max(1, min(5, self.min_rating)) except Exception: pass try: self.smart_notice_shown = config["smart_notice_shown"].lower( ) in TRUTH_VALUES except Exception: pass try: self.smart_register_shown = config[ "smart_register_shown"].lower() in TRUTH_VALUES except Exception: pass try: self.stats_notice_shown = config["stats_notice_shown"].lower( ) in TRUTH_VALUES except Exception: pass try: self.smart_enabled = config["smart_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.sync_enabled = config["sync_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.stats_enabled = config["stats_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.copyto_enabled = config["copyto_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.copyto_folder = os.path.expanduser( config["copyto_folder"]) except Exception: pass try: self.clock_enabled = config["clock_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.clock_filter = config["clock_filter"].strip() except Exception: pass try: self.clock_font = config["clock_font"] except Exception: pass try: self.clock_date_font = config["clock_date_font"] except Exception: pass try: self.quotes_enabled = config["quotes_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.quotes_font = config["quotes_font"] except Exception: pass try: self.quotes_text_color = list( map(int, config["quotes_text_color"].split())) for i, x in enumerate(self.quotes_text_color): self.quotes_text_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_bg_color = list( map(int, config["quotes_bg_color"].split())) for i, x in enumerate(self.quotes_bg_color): self.quotes_bg_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_bg_opacity = int(float( config["quotes_bg_opacity"])) self.quotes_bg_opacity = max(0, min(100, self.quotes_bg_opacity)) except Exception: pass try: self.quotes_text_shadow = config["quotes_text_shadow"].lower( ) in TRUTH_VALUES except Exception: pass try: self.quotes_text_color = list( map(int, config["quotes_text_color"].split())) for i, x in enumerate(self.quotes_text_color): self.quotes_text_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_disabled_sources = config[ "quotes_disabled_sources"].strip().split("|") except Exception: pass try: self.quotes_tags = config["quotes_tags"] except Exception: pass try: self.quotes_authors = config["quotes_authors"] except Exception: pass try: self.quotes_change_enabled = config[ "quotes_change_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.quotes_change_interval = int( config["quotes_change_interval"]) if self.quotes_change_interval < 10: self.quotes_change_interval = 10 except Exception: pass try: self.quotes_width = int(float(config["quotes_width"])) self.quotes_width = max(0, min(100, self.quotes_width)) except Exception: pass try: self.quotes_hpos = int(float(config["quotes_hpos"])) self.quotes_hpos = max(0, min(100, self.quotes_hpos)) except Exception: pass try: self.quotes_vpos = int(float(config["quotes_vpos"])) self.quotes_vpos = max(0, min(100, self.quotes_vpos)) except Exception: pass try: self.quotes_max_length = int(config["quotes_max_length"]) self.quotes_max_length = max(0, self.quotes_max_length) except Exception: pass try: self.quotes_favorites_file = os.path.expanduser( config["quotes_favorites_file"]) except Exception: pass try: self.slideshow_sources_enabled = ( config["slideshow_sources_enabled"].lower() in TRUTH_VALUES) except Exception: pass try: self.slideshow_favorites_enabled = ( config["slideshow_favorites_enabled"].lower() in TRUTH_VALUES) except Exception: pass try: self.slideshow_downloads_enabled = ( config["slideshow_downloads_enabled"].lower() in TRUTH_VALUES) except Exception: pass try: self.slideshow_custom_enabled = ( config["slideshow_custom_enabled"].lower() in TRUTH_VALUES) except Exception: pass try: custom_path = config["slideshow_custom_folder"] if custom_path in ( "None", "Default") or not os.path.isdir(custom_path): self.slideshow_custom_folder = Util.get_xdg_pictures_folder( ) else: self.slideshow_custom_folder = custom_path except Exception: pass try: slideshow_sort_order = config["slideshow_sort_order"] if slideshow_sort_order in [ "Random", "Name, asc", "Name, desc", "Date, asc", "Date, desc", ]: self.slideshow_sort_order = slideshow_sort_order except Exception: pass try: self.slideshow_monitor = config["slideshow_monitor"] except Exception: pass try: slideshow_mode = config["slideshow_mode"] if slideshow_mode in [ "Fullscreen", "Desktop", "Maximized", "Window" ]: self.slideshow_mode = slideshow_mode except Exception: pass try: self.slideshow_seconds = float(config["slideshow_seconds"]) self.slideshow_seconds = max(0.5, self.slideshow_seconds) except Exception: pass try: self.slideshow_fade = float(config["slideshow_fade"]) self.slideshow_fade = max(0, min(1, self.slideshow_fade)) except Exception: pass try: self.slideshow_zoom = float(config["slideshow_zoom"]) self.slideshow_zoom = max(0, min(1, self.slideshow_zoom)) except Exception: pass try: self.slideshow_pan = float(config["slideshow_pan"]) self.slideshow_pan = max(0, min(0.20, self.slideshow_pan)) except Exception: pass self.sources = [] if "sources" in config: sources = config["sources"] for v in sources.values(): try: self.sources.append(Options.parse_source(v)) except Exception: logger.debug(lambda: "Cannot parse source: " + v, exc_info=True) logger.info("Ignoring no longer supported source %s", v) # automatically append sources for all simple downloaders we have source_types = set(s[1] for s in self.sources) for downloader in sorted(self.SIMPLE_DOWNLOADERS, key=lambda dl: dl.get_source_type()): if downloader.get_source_type() not in source_types: self.sources.append([ True, downloader.get_source_type(), downloader.get_description() ]) self.parse_autosources() if "filters" in config: self.filters = [] filters = config["filters"] for v in filters.values(): try: self.filters.append(Options.parse_filter(v)) except Exception: logger.exception( lambda: "Cannot parse filter: " + str(v)) self.parse_autofilters() if needs_writing: logger.info( lambda: "Some outdated settings were updated, writing the changes") self.write() except Exception: logger.exception(lambda: "Could not read configuration:")
def read(self): self.set_defaults() try: config = self.read_config() needs_writing = self.fix_outdated(config) try: self.change_enabled = config["change_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.change_on_start = config["change_on_start"].lower() in TRUTH_VALUES except Exception: pass try: self.change_interval = int(config["change_interval"]) if self.change_interval < 5: self.change_interval = 5 except Exception: pass try: self.safe_mode = config["safe_mode"].lower() in TRUTH_VALUES except Exception: pass try: self.download_enabled = config["download_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.download_interval = int(config["download_interval"]) if self.download_interval < 60: self.download_interval = 60 except Exception: pass try: self.download_folder = os.path.expanduser(config["download_folder"]) except Exception: pass try: self.quota_enabled = config["quota_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.quota_size = int(config["quota_size"]) if self.quota_size < 50: self.quota_size = 50 except Exception: pass try: self.favorites_folder = os.path.expanduser(config["favorites_folder"]) except Exception: pass try: favorites_ops_text = config["favorites_operations"] self.favorites_operations = list([x.strip().split(':') for x in favorites_ops_text.split(';') if x]) except Exception: pass try: self.fetched_folder = os.path.expanduser(config["fetched_folder"]) except Exception: pass try: self.clipboard_enabled = config["clipboard_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.clipboard_use_whitelist = config["clipboard_use_whitelist"].lower() in TRUTH_VALUES except Exception: pass try: self.clipboard_hosts = config["clipboard_hosts"].lower().split(',') except Exception: pass try: icon = config["icon"] if icon in ["Light", "Dark", "Current", "None"] or (os.access(icon, os.R_OK) and Util.is_image(icon)): self.icon = icon except Exception: pass try: self.desired_color_enabled = config["desired_color_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.desired_color = map(int, config["desired_color"].split()) for i, x in enumerate(self.desired_color): self.desired_color[i] = max(0, min(255, x)) except Exception: self.desired_color = None try: self.min_size_enabled = config["min_size_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.min_size = int(config["min_size"]) self.min_size = max(0, min(100, self.min_size)) except Exception: pass try: self.use_landscape_enabled = config["use_landscape_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.lightness_enabled = config["lightness_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.lightness_mode = int(config["lightness_mode"]) self.lightness_mode = max(0, min(1, self.lightness_mode)) except Exception: pass try: self.min_rating_enabled = config["min_rating_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.min_rating = int(config["min_rating"]) self.min_rating = max(1, min(5, self.min_rating)) except Exception: pass try: self.smart_notice_shown = config["smart_notice_shown"].lower() in TRUTH_VALUES except Exception: pass try: self.smart_register_shown = config["smart_register_shown"].lower() in TRUTH_VALUES except Exception: pass try: self.stats_notice_shown = config["stats_notice_shown"].lower() in TRUTH_VALUES except Exception: pass try: self.smart_enabled = config["smart_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.sync_enabled = config["sync_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.stats_enabled = config["stats_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.facebook_show_dialog = config["facebook_show_dialog"].lower() in TRUTH_VALUES except Exception: pass try: self.facebook_message = config["facebook_message"].strip() except Exception: pass try: self.copyto_enabled = config["copyto_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.copyto_folder = os.path.expanduser(config["copyto_folder"]) except Exception: pass try: self.clock_enabled = config["clock_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.clock_filter = config["clock_filter"].strip() except Exception: pass try: self.clock_font = config["clock_font"] except Exception: pass try: self.clock_date_font = config["clock_date_font"] except Exception: pass try: self.quotes_enabled = config["quotes_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.quotes_font = config["quotes_font"] except Exception: pass try: self.quotes_text_color = map(int, config["quotes_text_color"].split()) for i, x in enumerate(self.quotes_text_color): self.quotes_text_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_bg_color = map(int, config["quotes_bg_color"].split()) for i, x in enumerate(self.quotes_bg_color): self.quotes_bg_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_bg_opacity = int(float(config["quotes_bg_opacity"])) self.quotes_bg_opacity = max(0, min(100, self.quotes_bg_opacity)) except Exception: pass try: self.quotes_text_shadow = config["quotes_text_shadow"].lower() in TRUTH_VALUES except Exception: pass try: self.quotes_text_color = map(int, config["quotes_text_color"].split()) for i, x in enumerate(self.quotes_text_color): self.quotes_text_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_disabled_sources = config["quotes_disabled_sources"].strip().split('|') except Exception: pass try: self.quotes_tags = config["quotes_tags"] except Exception: pass try: self.quotes_authors = config["quotes_authors"] except Exception: pass try: self.quotes_change_enabled = config["quotes_change_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.quotes_change_interval = int(config["quotes_change_interval"]) if self.quotes_change_interval < 10: self.quotes_change_interval = 10 except Exception: pass try: self.quotes_width = int(float(config["quotes_width"])) self.quotes_width = max(0, min(100, self.quotes_width)) except Exception: pass try: self.quotes_hpos = int(float(config["quotes_hpos"])) self.quotes_hpos = max(0, min(100, self.quotes_hpos)) except Exception: pass try: self.quotes_vpos = int(float(config["quotes_vpos"])) self.quotes_vpos = max(0, min(100, self.quotes_vpos)) except Exception: pass try: self.quotes_favorites_file = os.path.expanduser(config["quotes_favorites_file"]) except Exception: pass try: self.slideshow_sources_enabled = config["slideshow_sources_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.slideshow_favorites_enabled = config["slideshow_favorites_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.slideshow_downloads_enabled = config["slideshow_downloads_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.slideshow_custom_enabled = config["slideshow_custom_enabled"].lower() in TRUTH_VALUES except Exception: pass try: custom_path = config["slideshow_custom_folder"] if custom_path in ('None', 'Default') or not os.path.isdir(): self.slideshow_custom_folder = Util.get_xdg_pictures_folder() else: self.slideshow_custom_folder = custom_path except Exception: pass try: slideshow_sort_order = config["slideshow_sort_order"] if slideshow_sort_order in ["Random", "Name, asc", "Name, desc", "Date, asc", "Date, desc"]: self.slideshow_sort_order = slideshow_sort_order except Exception: pass try: self.slideshow_monitor = config["slideshow_monitor"] except Exception: pass try: slideshow_mode = config["slideshow_mode"] if slideshow_mode in ["Fullscreen", "Desktop", "Maximized", "Window"]: self.slideshow_mode = slideshow_mode except Exception: pass try: self.slideshow_seconds = float(config["slideshow_seconds"]) self.slideshow_seconds = max(0.5, self.slideshow_seconds) except Exception: pass try: self.slideshow_fade = float(config["slideshow_fade"]) self.slideshow_fade = max(0, min(1, self.slideshow_fade)) except Exception: pass try: self.slideshow_zoom = float(config["slideshow_zoom"]) self.slideshow_zoom = max(0, min(1, self.slideshow_zoom)) except Exception: pass try: self.slideshow_pan = float(config["slideshow_pan"]) self.slideshow_pan = max(0, min(0.20, self.slideshow_pan)) except Exception: pass if "sources" in config: self.sources = [] sources = config["sources"] for v in sources.values(): try: self.sources.append(Options.parse_source(v)) except Exception: logger.exception(lambda: "Cannot parse source: " + v) self.parse_autosources() for s in self.sources: if s[1] in (Options.SourceType.RECOMMENDED,) and not self.smart_enabled: s[0] = False if "filters" in config: self.filters = [] filters = config["filters"] for v in filters.values(): try: self.filters.append(Options.parse_filter(v)) except Exception: logger.exception(lambda: "Cannot parse filter: " + str(v)) self.parse_autofilters() if needs_writing: logger.info(lambda: "Some outdated settings were updated, writing the changes") self.write() except Exception: logger.exception(lambda: "Could not read configuration:")
def save_locally(self, origin_url, image_url, source_type=None, source_location=None, source_name=None, force_download=False, extra_metadata={}, local_filename=None): if not source_type: source_type = self.source_type if not source_name: source_name = self.name if not source_location: source_location = self.location if not force_download and self.parent and origin_url in self.parent.banned: logger.info( lambda: "URL " + origin_url + " is banned, skip downloading") return None try: os.makedirs(self.target_folder) except Exception: pass if origin_url.startswith('//'): origin_url = 'https:' + origin_url if image_url.startswith('//'): image_url = origin_url.split('//')[0] + image_url if not local_filename: local_filename = self.get_local_filename(image_url) logger.info(lambda: "Origin URL: " + origin_url) logger.info(lambda: "Image URL: " + image_url) logger.info(lambda: "Local name: " + local_filename) if not force_download and os.path.exists(local_filename): logger.info(lambda: "File already exists, skip downloading") return None if self.parent and self.parent.options.safe_mode and 'keywords' in extra_metadata: blacklisted = set( k.lower() for k in extra_metadata['keywords']) & SAFE_MODE_BLACKLIST if len(blacklisted) > 0: logger.info( lambda: "Skipping non-safe download %s due to blacklisted keywords (%s). " "Is the source %s:%s suitable for Safe mode?" % (origin_url, str(blacklisted), source_type, self.location)) return None try: r = Util.request(image_url, stream=True) with open(local_filename, 'wb') as f: Util.request_write_to(r, f) except Exception as e: logger.info( lambda: "Download failed from image URL: %s (source location: %s) " % (image_url, self.location)) raise e if not Util.is_image(local_filename, check_contents=True): logger.info( lambda: "Downloaded data was not an image, image URL might be outdated" ) os.unlink(local_filename) return None metadata = { "sourceType": source_type, "sourceName": source_name, "sourceLocation": source_location, "sourceURL": origin_url, "imageURL": image_url } metadata.update(extra_metadata) Util.write_metadata(local_filename, metadata) logger.info(lambda: "Download complete") return local_filename
def test_is_image(self): self.assertTrue(Util.is_image('test.jpg')) self.assertTrue(Util.is_image('test.jpg', check_contents=True)) self.assertTrue(Util.is_image('fake_image.jpg')) self.assertFalse(Util.is_image('fake_image.jpg', check_contents=True))
def read(self): self.set_defaults() try: config = self.read_config() needs_writing = self.fix_outdated(config) try: self.change_enabled = config["change_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.change_on_start = config["change_on_start"].lower( ) in TRUTH_VALUES except Exception: pass try: self.change_interval = int(config["change_interval"]) if self.change_interval < 5: self.change_interval = 5 except Exception: pass try: self.safe_mode = config["safe_mode"].lower() in TRUTH_VALUES except Exception: pass try: self.download_enabled = config["download_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.download_interval = int(config["download_interval"]) if self.download_interval < 60: self.download_interval = 60 except Exception: pass try: self.download_folder = os.path.expanduser( config["download_folder"]) except Exception: pass try: self.quota_enabled = config["quota_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.quota_size = int(config["quota_size"]) if self.quota_size < 50: self.quota_size = 50 except Exception: pass try: self.favorites_folder = os.path.expanduser( config["favorites_folder"]) except Exception: pass try: favorites_ops_text = config["favorites_operations"] self.favorites_operations = list([ x.strip().split(':') for x in favorites_ops_text.split(';') if x ]) except Exception: pass try: self.fetched_folder = os.path.expanduser( config["fetched_folder"]) except Exception: pass try: self.clipboard_enabled = config["clipboard_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.clipboard_use_whitelist = config[ "clipboard_use_whitelist"].lower() in TRUTH_VALUES except Exception: pass try: self.clipboard_hosts = config["clipboard_hosts"].lower().split( ',') except Exception: pass try: icon = config["icon"] if icon in [ "Light", "Dark", "Current", "None" ] or (os.access(icon, os.R_OK) and Util.is_image(icon)): self.icon = icon except Exception: pass try: self.desired_color_enabled = config[ "desired_color_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.desired_color = map(int, config["desired_color"].split()) for i, x in enumerate(self.desired_color): self.desired_color[i] = max(0, min(255, x)) except Exception: self.desired_color = None try: self.min_size_enabled = config["min_size_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.min_size = int(config["min_size"]) self.min_size = max(0, min(100, self.min_size)) except Exception: pass try: self.use_landscape_enabled = config[ "use_landscape_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.lightness_enabled = config["lightness_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.lightness_mode = int(config["lightness_mode"]) self.lightness_mode = max(0, min(1, self.lightness_mode)) except Exception: pass try: self.min_rating_enabled = config["min_rating_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.min_rating = int(config["min_rating"]) self.min_rating = max(1, min(5, self.min_rating)) except Exception: pass try: self.smart_notice_shown = config["smart_notice_shown"].lower( ) in TRUTH_VALUES except Exception: pass try: self.smart_register_shown = config[ "smart_register_shown"].lower() in TRUTH_VALUES except Exception: pass try: self.stats_notice_shown = config["stats_notice_shown"].lower( ) in TRUTH_VALUES except Exception: pass try: self.smart_enabled = config["smart_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.sync_enabled = config["sync_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.stats_enabled = config["stats_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.facebook_show_dialog = config[ "facebook_show_dialog"].lower() in TRUTH_VALUES except Exception: pass try: self.facebook_message = config["facebook_message"].strip() except Exception: pass try: self.copyto_enabled = config["copyto_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.copyto_folder = os.path.expanduser( config["copyto_folder"]) except Exception: pass try: self.clock_enabled = config["clock_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.clock_filter = config["clock_filter"].strip() except Exception: pass try: self.clock_font = config["clock_font"] except Exception: pass try: self.clock_date_font = config["clock_date_font"] except Exception: pass try: self.quotes_enabled = config["quotes_enabled"].lower( ) in TRUTH_VALUES except Exception: pass try: self.quotes_font = config["quotes_font"] except Exception: pass try: self.quotes_text_color = map( int, config["quotes_text_color"].split()) for i, x in enumerate(self.quotes_text_color): self.quotes_text_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_bg_color = map(int, config["quotes_bg_color"].split()) for i, x in enumerate(self.quotes_bg_color): self.quotes_bg_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_bg_opacity = int(float( config["quotes_bg_opacity"])) self.quotes_bg_opacity = max(0, min(100, self.quotes_bg_opacity)) except Exception: pass try: self.quotes_text_shadow = config["quotes_text_shadow"].lower( ) in TRUTH_VALUES except Exception: pass try: self.quotes_text_color = map( int, config["quotes_text_color"].split()) for i, x in enumerate(self.quotes_text_color): self.quotes_text_color[i] = max(0, min(255, x)) except Exception: pass try: self.quotes_disabled_sources = config[ "quotes_disabled_sources"].strip().split('|') except Exception: pass try: self.quotes_tags = config["quotes_tags"] except Exception: pass try: self.quotes_authors = config["quotes_authors"] except Exception: pass try: self.quotes_change_enabled = config[ "quotes_change_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.quotes_change_interval = int( config["quotes_change_interval"]) if self.quotes_change_interval < 10: self.quotes_change_interval = 10 except Exception: pass try: self.quotes_width = int(float(config["quotes_width"])) self.quotes_width = max(0, min(100, self.quotes_width)) except Exception: pass try: self.quotes_hpos = int(float(config["quotes_hpos"])) self.quotes_hpos = max(0, min(100, self.quotes_hpos)) except Exception: pass try: self.quotes_vpos = int(float(config["quotes_vpos"])) self.quotes_vpos = max(0, min(100, self.quotes_vpos)) except Exception: pass try: self.quotes_favorites_file = os.path.expanduser( config["quotes_favorites_file"]) except Exception: pass try: self.slideshow_sources_enabled = config[ "slideshow_sources_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.slideshow_favorites_enabled = config[ "slideshow_favorites_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.slideshow_downloads_enabled = config[ "slideshow_downloads_enabled"].lower() in TRUTH_VALUES except Exception: pass try: self.slideshow_custom_enabled = config[ "slideshow_custom_enabled"].lower() in TRUTH_VALUES except Exception: pass try: custom_path = config["slideshow_custom_folder"] if custom_path in ('None', 'Default') or not os.path.isdir(): self.slideshow_custom_folder = Util.get_xdg_pictures_folder( ) else: self.slideshow_custom_folder = custom_path except Exception: pass try: slideshow_sort_order = config["slideshow_sort_order"] if slideshow_sort_order in [ "Random", "Name, asc", "Name, desc", "Date, asc", "Date, desc" ]: self.slideshow_sort_order = slideshow_sort_order except Exception: pass try: self.slideshow_monitor = config["slideshow_monitor"] except Exception: pass try: slideshow_mode = config["slideshow_mode"] if slideshow_mode in [ "Fullscreen", "Desktop", "Maximized", "Window" ]: self.slideshow_mode = slideshow_mode except Exception: pass try: self.slideshow_seconds = float(config["slideshow_seconds"]) self.slideshow_seconds = max(0.5, self.slideshow_seconds) except Exception: pass try: self.slideshow_fade = float(config["slideshow_fade"]) self.slideshow_fade = max(0, min(1, self.slideshow_fade)) except Exception: pass try: self.slideshow_zoom = float(config["slideshow_zoom"]) self.slideshow_zoom = max(0, min(1, self.slideshow_zoom)) except Exception: pass try: self.slideshow_pan = float(config["slideshow_pan"]) self.slideshow_pan = max(0, min(0.20, self.slideshow_pan)) except Exception: pass if "sources" in config: self.sources = [] sources = config["sources"] for v in sources.values(): try: self.sources.append(Options.parse_source(v)) except Exception: logger.exception(lambda: "Cannot parse source: " + v) self.parse_autosources() for s in self.sources: if s[1] in (Options.SourceType.RECOMMENDED, ) and not self.smart_enabled: s[0] = False if "filters" in config: self.filters = [] filters = config["filters"] for v in filters.values(): try: self.filters.append(Options.parse_filter(v)) except Exception: logger.exception( lambda: "Cannot parse filter: " + str(v)) self.parse_autofilters() if needs_writing: logger.info( lambda: "Some outdated settings were updated, writing the changes") self.write() except Exception: logger.exception(lambda: "Could not read configuration:")