├── logo.ico ├── .deepsource.toml ├── .github ├── dependabot.yml └── FUNDING.yml ├── pyproject.toml ├── LICENSE ├── .gitignore ├── setup.py ├── README.rst ├── freshpaper.py └── poetry.lock /logo.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/guptarohit/freshpaper/HEAD/logo.ico -------------------------------------------------------------------------------- /.deepsource.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [[analyzers]] 4 | name = "python" 5 | enabled = true 6 | runtime_version = "3.x.x" 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "pip" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [guptarohit] 4 | patreon: rohitgupta 5 | ko_fi: rohitgupta 6 | custom: ["https://www.buymeacoffee.com/rohitgupta"] 7 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [tool.poetry] 2 | name = "freshpaper" 3 | version = "1.2.2" 4 | description = "Program to automatically set Bing's `Photo of the day` as your Desktop's wallpaper." 5 | authors = ["Rohit Gupta "] 6 | license = "BSD-3-Clause" 7 | readme = "README.rst" 8 | homepage = "https://github.com/guptarohit/freshpaper" 9 | repository = "https://github.com/guptarohit/freshpaper" 10 | keywords = ["wallpaper changer", "wallpaper", "bing", "bing wallpaper", "nasa-apod"] 11 | 12 | classifiers = [ 13 | "Development Status :: 5 - Production/Stable", 14 | "Topic :: Utilities", 15 | "Operating System :: MacOS", 16 | "Operating System :: POSIX :: Linux", 17 | "Operating System :: Microsoft :: Windows", 18 | ] 19 | include = [ 20 | "LICENSE", 21 | ] 22 | 23 | [tool.poetry.dependencies] 24 | python = "^3.6" 25 | pillow = "^7.0" 26 | click = "*" 27 | 28 | [tool.poetry.dev-dependencies] 29 | black = "^20.8b1" 30 | 31 | [tool.poetry.scripts] 32 | freshpaper = "freshpaper:main" 33 | 34 | [build-system] 35 | requires = ["poetry>=0.12"] 36 | build-backend = "poetry.masonry.api" 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 3-Clause License 2 | 3 | Copyright (c) 2019, Rohit Gupta 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | * Neither the name of the copyright holder nor the names of its 17 | contributors may be used to endorse or promote products derived from 18 | this software without specific prior written permission. 19 | 20 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 23 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 24 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 26 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 27 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 28 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | temp/ 7 | temp/* 8 | 9 | .idea/ 10 | .idea/* 11 | 12 | # C extensions 13 | *.so 14 | 15 | # Distribution / packaging 16 | .Python 17 | env/ 18 | build/ 19 | develop-eggs/ 20 | dist/ 21 | downloads/ 22 | eggs/ 23 | .eggs/ 24 | lib/ 25 | lib64/ 26 | parts/ 27 | sdist/ 28 | var/ 29 | wheels/ 30 | *.egg-info/ 31 | .installed.cfg 32 | *.egg 33 | 34 | # PyInstaller 35 | # Usually these files are written by a python script from a template 36 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 37 | *.manifest 38 | *.spec 39 | 40 | # Installer logs 41 | pip-log.txt 42 | pip-delete-this-directory.txt 43 | 44 | # Unit test / coverage reports 45 | htmlcov/ 46 | .tox/ 47 | .coverage 48 | .coverage.* 49 | .cache 50 | nosetests.xml 51 | coverage.xml 52 | *.cover 53 | .hypothesis/ 54 | 55 | # Translations 56 | *.mo 57 | *.pot 58 | 59 | # Django stuff: 60 | *.log 61 | local_settings.py 62 | 63 | # Flask stuff: 64 | instance/ 65 | .webassets-cache 66 | 67 | # Scrapy stuff: 68 | .scrapy 69 | 70 | # Sphinx documentation 71 | docs/_build/ 72 | 73 | # PyBuilder 74 | target/ 75 | 76 | # Jupyter Notebook 77 | .ipynb_checkpoints 78 | 79 | # pyenv 80 | .python-version 81 | 82 | # celery beat schedule file 83 | celerybeat-schedule 84 | 85 | # SageMath parsed files 86 | *.sage.py 87 | 88 | # dotenv 89 | .env 90 | 91 | # virtualenv 92 | .venv 93 | venv/ 94 | ENV/ 95 | 96 | # Spyder project settings 97 | .spyderproject 98 | .spyproject 99 | 100 | # Rope project settings 101 | .ropeproject 102 | 103 | # mkdocs documentation 104 | /site 105 | 106 | # mypy 107 | .mypy_cache/ 108 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # !/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import io 5 | import os 6 | import sys 7 | from shutil import rmtree 8 | from setuptools import setup, Command 9 | 10 | # Package meta-data. 11 | NAME = "freshpaper" 12 | DESCRIPTION = "Program to automatically set Bing's `Photo of the day` as your Desktop's wallpaper." 13 | URL = "https://github.com/guptarohit/freshpaper" 14 | AUTHOR = "Rohit Gupta" 15 | VERSION = "1.2.2" 16 | 17 | # Packages are required for this module 18 | REQUIRED = ["click", "Pillow"] 19 | 20 | here = os.path.abspath(os.path.dirname(__file__)) 21 | 22 | with io.open(os.path.join(here, "README.rst"), encoding="utf-8") as f: 23 | long_description = "\n" + f.read() 24 | 25 | 26 | class UploadCommand(Command): 27 | """Support setup.py upload.""" 28 | 29 | description = "Build and publish the package." 30 | user_options = [] 31 | 32 | @staticmethod 33 | def status(s): 34 | """Prints things in bold.""" 35 | print("\033[1m{0}\033[0m".format(s)) 36 | 37 | def initialize_options(self): 38 | pass 39 | 40 | def finalize_options(self): 41 | pass 42 | 43 | def run(self): 44 | try: 45 | self.status("Removing previous builds...") 46 | rmtree(os.path.join(here, "dist")) 47 | except OSError: 48 | pass 49 | 50 | self.status("Building Source and Wheel (universal) distribution...") 51 | os.system("{0} setup.py sdist bdist_wheel --universal".format(sys.executable)) 52 | 53 | self.status("Uploading the package to PyPi via Twine...") 54 | os.system("twine upload dist/*") 55 | 56 | sys.exit() 57 | 58 | 59 | setup( 60 | name=NAME, 61 | version=VERSION, 62 | description=DESCRIPTION, 63 | long_description=long_description, 64 | author=AUTHOR, 65 | url=URL, 66 | py_modules=["freshpaper"], 67 | entry_points={"console_scripts": ["freshpaper=freshpaper:main"]}, 68 | install_requires=REQUIRED, 69 | include_package_data=True, 70 | license="BSD", 71 | classifiers=[ 72 | "Development Status :: 5 - Production/Stable", 73 | "Topic :: Utilities", 74 | "Programming Language :: Python", 75 | "Programming Language :: Python :: 3", 76 | "Programming Language :: Python :: 3.6", 77 | "Programming Language :: Python :: 3.7", 78 | "Programming Language :: Python :: 3.8", 79 | "Programming Language :: Python :: 3.9", 80 | "Operating System :: MacOS", 81 | "Operating System :: POSIX :: Linux", 82 | "Operating System :: Microsoft :: Windows", 83 | "License :: OSI Approved :: BSD License", 84 | ], 85 | # $ setup.py publish support. 86 | cmdclass={"upload": UploadCommand}, 87 | ) 88 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | .. -*-restructuredtext-*- 2 | 3 | freshpaper 4 | ========== 5 | 6 | .. image:: https://img.shields.io/pypi/v/freshpaper.svg 7 | :target: https://pypi.python.org/pypi/freshpaper 8 | :alt: PyPi version 9 | 10 | .. image:: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fguptarohit%2Ffreshpaper.svg?type=shield 11 | :target: https://app.fossa.io/projects/git%2Bgithub.com%2Fguptarohit%2Ffreshpaper?ref=badge_shield 12 | :alt: FOSSA Status 13 | 14 | .. image:: https://img.shields.io/pypi/l/freshpaper.svg 15 | :target: https://github.com/guptarohit/freshpaper/blob/master/LICENSE 16 | :alt: License 17 | 18 | .. image:: https://pepy.tech/badge/freshpaper 19 | :target: https://pepy.tech/project/freshpaper 20 | :alt: Downloads 21 | 22 | .. image:: https://img.shields.io/badge/code%20style-black-000000.svg 23 | :target: https://github.com/ambv/black 24 | :alt: Code style: black 25 | 26 | freshpaper automatically sets `Bing `_ photo of the day or `NASA-APOD `_ or `Random Unsplash photo `_ or `Nat Geo - Photo of the Day `_ as your desktop's wallpaper. Available for Windows, macOS & Linux. 27 | 28 | 29 | Installation 30 | ------------ 31 | 32 | :: 33 | 34 | $ pip install freshpaper 35 | 36 | Update to latest release: 37 | 38 | :: 39 | 40 | $ pip install -U freshpaper 41 | 42 | 43 | Usage 44 | ------ 45 | 46 | To update the wallpaper simply run: 47 | 48 | :: 49 | 50 | $ freshpaper 51 | 52 | The default source of wallpaper is ``bing``. Available sources: ``bing``, ``nasa``, ``unsplash_random``, ``nat_geo``. 53 | 54 | To change the source of the wallpaper, run: 55 | 56 | :: 57 | 58 | $ freshpaper --source 59 | 60 | Help command of cli utility: 61 | 62 | :: 63 | 64 | $ freshpaper --help 65 | Usage: freshpaper [OPTIONS] COMMAND [ARGS]... 66 | 67 | Options: 68 | --source [bing|nasa|unsplash_random|nat_geo] Source for setting the wallpaper. 69 | --help Show this message and exit. 70 | 71 | Contributing 72 | ------------ 73 | 74 | Feel free to make a pull request! :octocat: 75 | 76 | If you found this useful, I'd appreciate your consideration in the below. ✨🍰 77 | 78 | .. image:: https://user-images.githubusercontent.com/7895001/52529389-e2da5280-2d16-11e9-924c-4fe3f309c780.png 79 | :target: https://www.buymeacoffee.com/rohitgupta 80 | :alt: Buy Me A Coffee 81 | 82 | .. image:: https://user-images.githubusercontent.com/7895001/52529390-e8379d00-2d16-11e9-913b-4d09db90403f.png 83 | :target: https://www.patreon.com/bePatron?u=14009502 84 | :alt: Become a Patron! 85 | 86 | 87 | License 88 | ------- 89 | 90 | .. image:: https://app.fossa.io/api/projects/git%2Bgithub.com%2Fguptarohit%2Ffreshpaper.svg?type=large 91 | :target: https://app.fossa.io/projects/git%2Bgithub.com%2Fguptarohit%2Ffreshpaper?ref=badge_large 92 | :alt: FOSSA Status 93 | -------------------------------------------------------------------------------- /freshpaper.py: -------------------------------------------------------------------------------- 1 | import os 2 | import re 3 | import sys 4 | import click 5 | import json 6 | import logging 7 | from random import choice 8 | from datetime import datetime 9 | from subprocess import check_call, CalledProcessError 10 | from PIL import Image 11 | 12 | try: 13 | # for python3 14 | from urllib.request import urlopen, urlretrieve, HTTPError, URLError 15 | except ImportError: 16 | # for python2 17 | from urllib import urlretrieve 18 | from urllib2 import urlopen, HTTPError, URLError 19 | 20 | if sys.platform.startswith("win32"): 21 | import win32api 22 | import win32con 23 | import win32gui 24 | 25 | logging.basicConfig(level=logging.INFO, format="%(message)s") 26 | 27 | log = logging.getLogger(__name__) 28 | 29 | 30 | def set_wallpaper(image_path): 31 | if image_path is None: 32 | return 33 | """ Given a path to an image, set it as the wallpaper """ 34 | if not os.path.exists(image_path): 35 | log.error("Image does not exist.") 36 | sys.exit(1) 37 | 38 | log.info("Updating wallpaper..") 39 | log.info( 40 | "Name of wallpaper: {}".format( 41 | re.sub("([a-z])([A-Z])", r"\1 \2", image_path.split("/")[-1].split("_")[0]) 42 | ) 43 | ) 44 | 45 | if sys.platform.startswith("win32"): 46 | 47 | bmp_image = Image.open(image_path) 48 | bmp_img_path = os.path.splitext(image_path)[0] + ".bmp" 49 | bmp_image.save(bmp_img_path, "BMP") 50 | key = win32api.RegOpenKeyEx( 51 | win32con.HKEY_CURRENT_USER, 52 | "Control Panel\\Desktop", 53 | 0, 54 | win32con.KEY_SET_VALUE, 55 | ) 56 | win32api.RegSetValueEx(key, "WallpaperStyle", 0, win32con.REG_SZ, "0") 57 | win32api.RegSetValueEx(key, "TileWallpaper", 0, win32con.REG_SZ, "0") 58 | win32gui.SystemParametersInfo( 59 | win32con.SPI_SETDESKWALLPAPER, bmp_img_path, 1 + 2 60 | ) 61 | os.remove(bmp_img_path) 62 | elif sys.platform.startswith("darwin"): 63 | try: 64 | command = """ 65 | osascript -e 'tell application "System Events" 66 | set desktopCount to count of desktops 67 | repeat with desktopNumber from 1 to desktopCount 68 | tell desktop desktopNumber 69 | set picture to "{image_path}" 70 | end tell 71 | end repeat 72 | end tell' 73 | """.format( 74 | image_path=image_path 75 | ) 76 | 77 | check_call([command], shell=True) 78 | except (CalledProcessError, FileNotFoundError): 79 | log.error("Setting wallpaper failed.") 80 | sys.exit(1) 81 | elif sys.platform.startswith("linux"): 82 | check_call( 83 | [ 84 | "gsettings", 85 | "set", 86 | "org.gnome.desktop.background", 87 | "picture-uri", 88 | "file://{}".format(image_path), 89 | ] 90 | ) 91 | 92 | log.info("Wallpaper successfully updated. :)") 93 | 94 | 95 | def get_saved_wallpaper(wall_dir): 96 | """ returns random saved wallpaper's path """ 97 | 98 | files = os.listdir(wall_dir) 99 | if files: 100 | log.info("\nRandomly picking from saved wallpapers.") 101 | image_name = choice(files) 102 | image_path = os.path.join(os.sep, wall_dir, image_name) 103 | return image_path 104 | else: 105 | log.error("There is no wallpaper available offline.") 106 | sys.exit(1) 107 | 108 | 109 | def get_wallpaper_directory(): 110 | """ check if `default` wallpaper download directory exists or not, create if doesn't exist """ 111 | pictures_dir = "" 112 | wall_dir_name = "freshpaper" 113 | os.path.join(os.sep, os.path.expanduser("~"), "a", "freshpaper") 114 | if sys.platform.startswith("win32"): 115 | pictures_dir = "My Pictures" 116 | elif sys.platform.startswith("darwin"): 117 | pictures_dir = "Pictures" 118 | elif sys.platform.startswith("linux"): 119 | pictures_dir = "Pictures" 120 | wall_dir = os.path.join( 121 | os.sep, os.path.expanduser("~"), pictures_dir, wall_dir_name 122 | ) 123 | 124 | if not os.path.isdir(wall_dir): 125 | log.error("wallpaper directory does not exist.") 126 | os.makedirs(wall_dir) 127 | log.info("created wallpaper directory at: {}".format(wall_dir)) 128 | 129 | return wall_dir 130 | 131 | 132 | def download_image_bing(download_dir, image_extension="jpg"): 133 | """ 134 | Download & save the image 135 | :param download_dir: directory where to download the image 136 | :param image_extension: directory where to download the image 137 | :return: downloaded image path 138 | """ 139 | # mkt(s) HIN, EN-IN 140 | 141 | url = "http://www.bing.com/HPImageArchive.aspx?format=js&idx=0&n=1&mkt=EN-IN" 142 | 143 | try: 144 | image_data = json.loads(urlopen(url).read().decode("utf-8")) 145 | 146 | image_url = "http://www.bing.com" + image_data["images"][0]["url"] 147 | 148 | image_name = re.search(r"OHR\.(.*?)_", image_url).group(1) 149 | 150 | image_url_hd = "http://www.bing.com/hpwp/" + image_data["images"][0]["hsh"] 151 | date_time = datetime.now().strftime("%d_%m_%Y") 152 | image_file_name = "{image_name}_{date_stamp}.{extention}".format( 153 | image_name=image_name, date_stamp=date_time, extention=image_extension 154 | ) 155 | 156 | image_path = os.path.join(os.sep, download_dir, image_file_name) 157 | log.debug("download_dir: {}".format(download_dir)) 158 | log.debug("image_file_name: {}".format(image_file_name)) 159 | log.debug("image_path: {}".format(image_path)) 160 | 161 | if os.path.isfile(image_path): 162 | log.info("No new wallpaper yet..updating to latest one.\n") 163 | return image_path 164 | 165 | try: 166 | log.info("Downloading..") 167 | urlretrieve(image_url_hd, filename=image_path) 168 | except HTTPError: 169 | log.info("Downloading...") 170 | urlretrieve(image_url, filename=image_path) 171 | return image_path 172 | except URLError: 173 | log.error("Something went wrong..\nMaybe Internet is not working...") 174 | raise ConnectionError 175 | 176 | 177 | def download_image_nasa(download_dir, image_extension="jpg"): 178 | """ 179 | Download & save the image 180 | :param download_dir: directory where to download the image 181 | :param image_extension: directory where to download the image 182 | :return: downloaded image path 183 | """ 184 | 185 | url = "https://api.nasa.gov/planetary/apod?api_key=DEMO_KEY" 186 | 187 | try: 188 | image_data = json.loads(urlopen(url).read().decode("utf-8")) 189 | if image_data.get("media_type") != "image": 190 | log.info("No NASA image of the day available. It can be a video.\n") 191 | return None 192 | image_url = image_data.get("url") 193 | 194 | image_name = image_data.get("title").split(" ")[0] 195 | 196 | image_url_hd = image_data.get("hdurl") 197 | date_time = datetime.now().strftime("%d_%m_%Y") 198 | image_file_name = "{image_name}_{date_stamp}.{extention}".format( 199 | image_name=image_name, date_stamp=date_time, extention=image_extension 200 | ) 201 | 202 | image_path = os.path.join(os.sep, download_dir, image_file_name) 203 | log.debug("download_dir: {}".format(download_dir)) 204 | log.debug("image_file_name: {}".format(image_file_name)) 205 | log.debug("image_path: {}".format(image_path)) 206 | 207 | if os.path.isfile(image_path): 208 | log.info("No new wallpaper yet..updating to latest one.\n") 209 | return image_path 210 | 211 | try: 212 | log.info("Downloading..") 213 | urlretrieve(image_url_hd, filename=image_path) 214 | except HTTPError: 215 | log.info("Downloading...") 216 | urlretrieve(image_url, filename=image_path) 217 | return image_path 218 | except URLError: 219 | log.error("Something went wrong..\nMaybe Internet is not working...") 220 | raise ConnectionError 221 | 222 | 223 | def download_image_unsplash_random(download_dir, image_extension="jpg"): 224 | """ 225 | Download & save the image 226 | :param download_dir: directory where to download the image 227 | :param image_extension: directory where to download the image 228 | :return: downloaded image path 229 | """ 230 | 231 | url = "https://source.unsplash.com/random/1920x1080" 232 | 233 | try: 234 | image_url = url 235 | 236 | image_name = "unsplash_random" 237 | 238 | date_time = datetime.now().strftime("%d_%m_%Y_%H_%M_%S") 239 | image_file_name = "{image_name}_{date_stamp}.{extention}".format( 240 | image_name=image_name, date_stamp=date_time, extention=image_extension 241 | ) 242 | 243 | image_path = os.path.join(os.sep, download_dir, image_file_name) 244 | log.debug("download_dir: {}".format(download_dir)) 245 | log.debug("image_file_name: {}".format(image_file_name)) 246 | log.debug("image_path: {}".format(image_path)) 247 | 248 | if os.path.isfile(image_path): 249 | log.info("No new wallpaper yet..updating to latest one.\n") 250 | return image_path 251 | 252 | log.info("Downloading...") 253 | urlretrieve(image_url, filename=image_path) 254 | return image_path 255 | except URLError: 256 | log.error("Something went wrong..\nMaybe Internet is not working...") 257 | raise ConnectionError 258 | 259 | 260 | def download_image_nat_geo(download_dir, image_extension="jpg"): 261 | """ 262 | Download & save the image 263 | :param download_dir: directory where to download the image 264 | :param image_extension: directory where to download the image 265 | :return: downloaded image path 266 | """ 267 | url = "https://www.nationalgeographic.com/photography/photo-of-the-day/" 268 | 269 | try: 270 | request = urlopen(url) 271 | except URLError: 272 | log.error("Something went wrong..\nMaybe Internet is not working...") 273 | raise ConnectionError 274 | 275 | html = request.read().decode("utf-8") 276 | url_regex = r"twitter:image:src\" content=\"(.*?)\"" 277 | image_url = re.findall(url_regex, html)[0] 278 | 279 | if not image_url: 280 | log.info("No National Geographic image of the day available.\n") 281 | return None 282 | 283 | image_name_regex = r"(.*?)" 284 | image_name = re.findall(image_name_regex, html)[0] 285 | 286 | try: 287 | if not image_name: 288 | image_name = "nat_geo" 289 | 290 | date_time = datetime.now().strftime("%d_%m_%Y") 291 | image_file_name = "{image_name}_{date_stamp}.{extention}".format( 292 | image_name=image_name, date_stamp=date_time, extention=image_extension 293 | ) 294 | 295 | image_path = os.path.join(os.sep, download_dir, image_file_name) 296 | log.debug("download_dir: {}".format(download_dir)) 297 | log.debug("image_file_name: {}".format(image_file_name)) 298 | log.debug("image_path: {}".format(image_path)) 299 | 300 | if os.path.isfile(image_path): 301 | log.info("No new wallpaper yet..updating to latest one.\n") 302 | return image_path 303 | 304 | log.info("Downloading...") 305 | urlretrieve(image_url, filename=image_path) 306 | return image_path 307 | 308 | except URLError: 309 | log.error("Something went wrong..\nMaybe Internet is not working...") 310 | raise ConnectionError 311 | 312 | 313 | freshpaper_sources = { 314 | "bing": {"download": download_image_bing, "description": "Bing photo of the day"}, 315 | "nasa": {"download": download_image_nasa, "description": "NASA photo of the day"}, 316 | "unsplash_random": { 317 | "download": download_image_unsplash_random, 318 | "description": "Unsplash random photo", 319 | }, 320 | "nat_geo": { 321 | "download": download_image_nat_geo, 322 | "description": "National Geographic photo of the day", 323 | }, 324 | } 325 | 326 | 327 | @click.group(invoke_without_command=True) 328 | @click.pass_context 329 | @click.option( 330 | "--source", 331 | default="bing", 332 | type=click.Choice(freshpaper_sources.keys()), 333 | help="Source for setting the wallpaper.", 334 | ) 335 | def main(ctx, source): 336 | if ctx.invoked_subcommand is None: 337 | dir_name = get_wallpaper_directory() # Wallpaper directory name 338 | 339 | try: 340 | download_image = freshpaper_sources.get(source)["download"] 341 | image_path = download_image(dir_name) 342 | set_wallpaper(image_path) 343 | except ConnectionError: 344 | image_path = get_saved_wallpaper(dir_name) 345 | set_wallpaper(image_path) 346 | except Exception as e: 347 | log.error(e) 348 | 349 | 350 | if __name__ == "__main__": 351 | main() 352 | -------------------------------------------------------------------------------- /poetry.lock: -------------------------------------------------------------------------------- 1 | [[package]] 2 | category = "dev" 3 | description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." 4 | name = "appdirs" 5 | optional = false 6 | python-versions = "*" 7 | version = "1.4.4" 8 | 9 | [[package]] 10 | category = "dev" 11 | description = "The uncompromising code formatter." 12 | name = "black" 13 | optional = false 14 | python-versions = ">=3.6" 15 | version = "20.8b1" 16 | 17 | [package.dependencies] 18 | appdirs = "*" 19 | click = ">=7.1.2" 20 | mypy-extensions = ">=0.4.3" 21 | pathspec = ">=0.6,<1" 22 | regex = ">=2020.1.8" 23 | toml = ">=0.10.1" 24 | typed-ast = ">=1.4.0" 25 | typing-extensions = ">=3.7.4" 26 | 27 | [package.dependencies.dataclasses] 28 | python = "<3.7" 29 | version = ">=0.6" 30 | 31 | [package.extras] 32 | colorama = ["colorama (>=0.4.3)"] 33 | d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] 34 | 35 | [[package]] 36 | category = "main" 37 | description = "Composable command line interface toolkit" 38 | name = "click" 39 | optional = false 40 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 41 | version = "7.1.2" 42 | 43 | [[package]] 44 | category = "dev" 45 | description = "A backport of the dataclasses module for Python 3.6" 46 | marker = "python_version < \"3.7\"" 47 | name = "dataclasses" 48 | optional = false 49 | python-versions = "*" 50 | version = "0.6" 51 | 52 | [[package]] 53 | category = "dev" 54 | description = "Experimental type system extensions for programs checked with the mypy typechecker." 55 | name = "mypy-extensions" 56 | optional = false 57 | python-versions = "*" 58 | version = "0.4.3" 59 | 60 | [[package]] 61 | category = "dev" 62 | description = "Utility library for gitignore style pattern matching of file paths." 63 | name = "pathspec" 64 | optional = false 65 | python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" 66 | version = "0.8.0" 67 | 68 | [[package]] 69 | category = "main" 70 | description = "Python Imaging Library (Fork)" 71 | name = "pillow" 72 | optional = false 73 | python-versions = ">=3.5" 74 | version = "7.2.0" 75 | 76 | [[package]] 77 | category = "dev" 78 | description = "Alternative regular expression module, to replace re." 79 | name = "regex" 80 | optional = false 81 | python-versions = "*" 82 | version = "2020.9.27" 83 | 84 | [[package]] 85 | category = "dev" 86 | description = "Python Library for Tom's Obvious, Minimal Language" 87 | name = "toml" 88 | optional = false 89 | python-versions = "*" 90 | version = "0.10.1" 91 | 92 | [[package]] 93 | category = "dev" 94 | description = "a fork of Python 2 and 3 ast modules with type comment support" 95 | name = "typed-ast" 96 | optional = false 97 | python-versions = "*" 98 | version = "1.4.1" 99 | 100 | [[package]] 101 | category = "dev" 102 | description = "Backported and Experimental Type Hints for Python 3.5+" 103 | name = "typing-extensions" 104 | optional = false 105 | python-versions = "*" 106 | version = "3.7.4.3" 107 | 108 | [metadata] 109 | content-hash = "119df1b8965670d870f4f94e245cf7c0838f97745dafb31f79a3279f98e1fd4c" 110 | lock-version = "1.0" 111 | python-versions = "^3.6" 112 | 113 | [metadata.files] 114 | appdirs = [ 115 | {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, 116 | {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, 117 | ] 118 | black = [ 119 | {file = "black-20.8b1.tar.gz", hash = "sha256:1c02557aa099101b9d21496f8a914e9ed2222ef70336404eeeac8edba836fbea"}, 120 | ] 121 | click = [ 122 | {file = "click-7.1.2-py2.py3-none-any.whl", hash = "sha256:dacca89f4bfadd5de3d7489b7c8a566eee0d3676333fbb50030263894c38c0dc"}, 123 | {file = "click-7.1.2.tar.gz", hash = "sha256:d2b5255c7c6349bc1bd1e59e08cd12acbbd63ce649f2588755783aa94dfb6b1a"}, 124 | ] 125 | dataclasses = [ 126 | {file = "dataclasses-0.6-py3-none-any.whl", hash = "sha256:454a69d788c7fda44efd71e259be79577822f5e3f53f029a22d08004e951dc9f"}, 127 | {file = "dataclasses-0.6.tar.gz", hash = "sha256:6988bd2b895eef432d562370bb707d540f32f7360ab13da45340101bc2307d84"}, 128 | ] 129 | mypy-extensions = [ 130 | {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, 131 | {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, 132 | ] 133 | pathspec = [ 134 | {file = "pathspec-0.8.0-py2.py3-none-any.whl", hash = "sha256:7d91249d21749788d07a2d0f94147accd8f845507400749ea19c1ec9054a12b0"}, 135 | {file = "pathspec-0.8.0.tar.gz", hash = "sha256:da45173eb3a6f2a5a487efba21f050af2b41948be6ab52b6a1e3ff22bb8b7061"}, 136 | ] 137 | pillow = [ 138 | {file = "Pillow-7.2.0-cp35-cp35m-macosx_10_10_intel.whl", hash = "sha256:1ca594126d3c4def54babee699c055a913efb01e106c309fa6b04405d474d5ae"}, 139 | {file = "Pillow-7.2.0-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c92302a33138409e8f1ad16731568c55c9053eee71bb05b6b744067e1b62380f"}, 140 | {file = "Pillow-7.2.0-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:8dad18b69f710bf3a001d2bf3afab7c432785d94fcf819c16b5207b1cfd17d38"}, 141 | {file = "Pillow-7.2.0-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:431b15cffbf949e89df2f7b48528be18b78bfa5177cb3036284a5508159492b5"}, 142 | {file = "Pillow-7.2.0-cp35-cp35m-win32.whl", hash = "sha256:09d7f9e64289cb40c2c8d7ad674b2ed6105f55dc3b09aa8e4918e20a0311e7ad"}, 143 | {file = "Pillow-7.2.0-cp35-cp35m-win_amd64.whl", hash = "sha256:0295442429645fa16d05bd567ef5cff178482439c9aad0411d3f0ce9b88b3a6f"}, 144 | {file = "Pillow-7.2.0-cp36-cp36m-macosx_10_10_x86_64.whl", hash = "sha256:ec29604081f10f16a7aea809ad42e27764188fc258b02259a03a8ff7ded3808d"}, 145 | {file = "Pillow-7.2.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:612cfda94e9c8346f239bf1a4b082fdd5c8143cf82d685ba2dba76e7adeeb233"}, 146 | {file = "Pillow-7.2.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0a80dd307a5d8440b0a08bd7b81617e04d870e40a3e46a32d9c246e54705e86f"}, 147 | {file = "Pillow-7.2.0-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:06aba4169e78c439d528fdeb34762c3b61a70813527a2c57f0540541e9f433a8"}, 148 | {file = "Pillow-7.2.0-cp36-cp36m-win32.whl", hash = "sha256:f7e30c27477dffc3e85c2463b3e649f751789e0f6c8456099eea7ddd53be4a8a"}, 149 | {file = "Pillow-7.2.0-cp36-cp36m-win_amd64.whl", hash = "sha256:ffe538682dc19cc542ae7c3e504fdf54ca7f86fb8a135e59dd6bc8627eae6cce"}, 150 | {file = "Pillow-7.2.0-cp37-cp37m-macosx_10_10_x86_64.whl", hash = "sha256:94cf49723928eb6070a892cb39d6c156f7b5a2db4e8971cb958f7b6b104fb4c4"}, 151 | {file = "Pillow-7.2.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6edb5446f44d901e8683ffb25ebdfc26988ee813da3bf91e12252b57ac163727"}, 152 | {file = "Pillow-7.2.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:52125833b070791fcb5710fabc640fc1df07d087fc0c0f02d3661f76c23c5b8b"}, 153 | {file = "Pillow-7.2.0-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:9ad7f865eebde135d526bb3163d0b23ffff365cf87e767c649550964ad72785d"}, 154 | {file = "Pillow-7.2.0-cp37-cp37m-win32.whl", hash = "sha256:c79f9c5fb846285f943aafeafda3358992d64f0ef58566e23484132ecd8d7d63"}, 155 | {file = "Pillow-7.2.0-cp37-cp37m-win_amd64.whl", hash = "sha256:d350f0f2c2421e65fbc62690f26b59b0bcda1b614beb318c81e38647e0f673a1"}, 156 | {file = "Pillow-7.2.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:6d7741e65835716ceea0fd13a7d0192961212fd59e741a46bbed7a473c634ed6"}, 157 | {file = "Pillow-7.2.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:edf31f1150778abd4322444c393ab9c7bd2af271dd4dafb4208fb613b1f3cdc9"}, 158 | {file = "Pillow-7.2.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:d08b23fdb388c0715990cbc06866db554e1822c4bdcf6d4166cf30ac82df8c41"}, 159 | {file = "Pillow-7.2.0-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:5e51ee2b8114def244384eda1c82b10e307ad9778dac5c83fb0943775a653cd8"}, 160 | {file = "Pillow-7.2.0-cp38-cp38-win32.whl", hash = "sha256:725aa6cfc66ce2857d585f06e9519a1cc0ef6d13f186ff3447ab6dff0a09bc7f"}, 161 | {file = "Pillow-7.2.0-cp38-cp38-win_amd64.whl", hash = "sha256:a060cf8aa332052df2158e5a119303965be92c3da6f2d93b6878f0ebca80b2f6"}, 162 | {file = "Pillow-7.2.0-pp36-pypy36_pp73-macosx_10_10_x86_64.whl", hash = "sha256:9c87ef410a58dd54b92424ffd7e28fd2ec65d2f7fc02b76f5e9b2067e355ebf6"}, 163 | {file = "Pillow-7.2.0-pp36-pypy36_pp73-manylinux2010_x86_64.whl", hash = "sha256:e901964262a56d9ea3c2693df68bc9860b8bdda2b04768821e4c44ae797de117"}, 164 | {file = "Pillow-7.2.0-pp36-pypy36_pp73-win32.whl", hash = "sha256:25930fadde8019f374400f7986e8404c8b781ce519da27792cbe46eabec00c4d"}, 165 | {file = "Pillow-7.2.0.tar.gz", hash = "sha256:97f9e7953a77d5a70f49b9a48da7776dc51e9b738151b22dacf101641594a626"}, 166 | ] 167 | regex = [ 168 | {file = "regex-2020.9.27-cp27-cp27m-win32.whl", hash = "sha256:d23a18037313714fb3bb5a94434d3151ee4300bae631894b1ac08111abeaa4a3"}, 169 | {file = "regex-2020.9.27-cp27-cp27m-win_amd64.whl", hash = "sha256:84e9407db1b2eb368b7ecc283121b5e592c9aaedbe8c78b1a2f1102eb2e21d19"}, 170 | {file = "regex-2020.9.27-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5f18875ac23d9aa2f060838e8b79093e8bb2313dbaaa9f54c6d8e52a5df097be"}, 171 | {file = "regex-2020.9.27-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ae91972f8ac958039920ef6e8769277c084971a142ce2b660691793ae44aae6b"}, 172 | {file = "regex-2020.9.27-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:9a02d0ae31d35e1ec12a4ea4d4cca990800f66a917d0fb997b20fbc13f5321fc"}, 173 | {file = "regex-2020.9.27-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:ebbe29186a3d9b0c591e71b7393f1ae08c83cb2d8e517d2a822b8f7ec99dfd8b"}, 174 | {file = "regex-2020.9.27-cp36-cp36m-win32.whl", hash = "sha256:4707f3695b34335afdfb09be3802c87fa0bc27030471dbc082f815f23688bc63"}, 175 | {file = "regex-2020.9.27-cp36-cp36m-win_amd64.whl", hash = "sha256:9bc13e0d20b97ffb07821aa3e113f9998e84994fe4d159ffa3d3a9d1b805043b"}, 176 | {file = "regex-2020.9.27-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:f1b3afc574a3db3b25c89161059d857bd4909a1269b0b3cb3c904677c8c4a3f7"}, 177 | {file = "regex-2020.9.27-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5533a959a1748a5c042a6da71fe9267a908e21eded7a4f373efd23a2cbdb0ecc"}, 178 | {file = "regex-2020.9.27-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:1fe0a41437bbd06063aa184c34804efa886bcc128222e9916310c92cd54c3b4c"}, 179 | {file = "regex-2020.9.27-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:c570f6fa14b9c4c8a4924aaad354652366577b4f98213cf76305067144f7b100"}, 180 | {file = "regex-2020.9.27-cp37-cp37m-win32.whl", hash = "sha256:eda4771e0ace7f67f58bc5b560e27fb20f32a148cbc993b0c3835970935c2707"}, 181 | {file = "regex-2020.9.27-cp37-cp37m-win_amd64.whl", hash = "sha256:60b0e9e6dc45683e569ec37c55ac20c582973841927a85f2d8a7d20ee80216ab"}, 182 | {file = "regex-2020.9.27-cp38-cp38-manylinux1_i686.whl", hash = "sha256:088afc8c63e7bd187a3c70a94b9e50ab3f17e1d3f52a32750b5b77dbe99ef5ef"}, 183 | {file = "regex-2020.9.27-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:eaf548d117b6737df379fdd53bdde4f08870e66d7ea653e230477f071f861121"}, 184 | {file = "regex-2020.9.27-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:41bb65f54bba392643557e617316d0d899ed5b4946dccee1cb6696152b29844b"}, 185 | {file = "regex-2020.9.27-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:8d69cef61fa50c8133382e61fd97439de1ae623fe943578e477e76a9d9471637"}, 186 | {file = "regex-2020.9.27-cp38-cp38-win32.whl", hash = "sha256:f2388013e68e750eaa16ccbea62d4130180c26abb1d8e5d584b9baf69672b30f"}, 187 | {file = "regex-2020.9.27-cp38-cp38-win_amd64.whl", hash = "sha256:4318d56bccfe7d43e5addb272406ade7a2274da4b70eb15922a071c58ab0108c"}, 188 | {file = "regex-2020.9.27.tar.gz", hash = "sha256:a6f32aea4260dfe0e55dc9733ea162ea38f0ea86aa7d0f77b15beac5bf7b369d"}, 189 | ] 190 | toml = [ 191 | {file = "toml-0.10.1-py2.py3-none-any.whl", hash = "sha256:bda89d5935c2eac546d648028b9901107a595863cb36bae0c73ac804a9b4ce88"}, 192 | {file = "toml-0.10.1.tar.gz", hash = "sha256:926b612be1e5ce0634a2ca03470f95169cf16f939018233a670519cb4ac58b0f"}, 193 | ] 194 | typed-ast = [ 195 | {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:73d785a950fc82dd2a25897d525d003f6378d1cb23ab305578394694202a58c3"}, 196 | {file = "typed_ast-1.4.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:aaee9905aee35ba5905cfb3c62f3e83b3bec7b39413f0a7f19be4e547ea01ebb"}, 197 | {file = "typed_ast-1.4.1-cp35-cp35m-win32.whl", hash = "sha256:0c2c07682d61a629b68433afb159376e24e5b2fd4641d35424e462169c0a7919"}, 198 | {file = "typed_ast-1.4.1-cp35-cp35m-win_amd64.whl", hash = "sha256:4083861b0aa07990b619bd7ddc365eb7fa4b817e99cf5f8d9cf21a42780f6e01"}, 199 | {file = "typed_ast-1.4.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:269151951236b0f9a6f04015a9004084a5ab0d5f19b57de779f908621e7d8b75"}, 200 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:24995c843eb0ad11a4527b026b4dde3da70e1f2d8806c99b7b4a7cf491612652"}, 201 | {file = "typed_ast-1.4.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:fe460b922ec15dd205595c9b5b99e2f056fd98ae8f9f56b888e7a17dc2b757e7"}, 202 | {file = "typed_ast-1.4.1-cp36-cp36m-win32.whl", hash = "sha256:4e3e5da80ccbebfff202a67bf900d081906c358ccc3d5e3c8aea42fdfdfd51c1"}, 203 | {file = "typed_ast-1.4.1-cp36-cp36m-win_amd64.whl", hash = "sha256:249862707802d40f7f29f6e1aad8d84b5aa9e44552d2cc17384b209f091276aa"}, 204 | {file = "typed_ast-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:8ce678dbaf790dbdb3eba24056d5364fb45944f33553dd5869b7580cdbb83614"}, 205 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:c9e348e02e4d2b4a8b2eedb48210430658df6951fa484e59de33ff773fbd4b41"}, 206 | {file = "typed_ast-1.4.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:bcd3b13b56ea479b3650b82cabd6b5343a625b0ced5429e4ccad28a8973f301b"}, 207 | {file = "typed_ast-1.4.1-cp37-cp37m-win32.whl", hash = "sha256:d5d33e9e7af3b34a40dc05f498939f0ebf187f07c385fd58d591c533ad8562fe"}, 208 | {file = "typed_ast-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:0666aa36131496aed8f7be0410ff974562ab7eeac11ef351def9ea6fa28f6355"}, 209 | {file = "typed_ast-1.4.1-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:d205b1b46085271b4e15f670058ce182bd1199e56b317bf2ec004b6a44f911f6"}, 210 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:6daac9731f172c2a22ade6ed0c00197ee7cc1221aa84cfdf9c31defeb059a907"}, 211 | {file = "typed_ast-1.4.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:498b0f36cc7054c1fead3d7fc59d2150f4d5c6c56ba7fb150c013fbc683a8d2d"}, 212 | {file = "typed_ast-1.4.1-cp38-cp38-win32.whl", hash = "sha256:715ff2f2df46121071622063fc7543d9b1fd19ebfc4f5c8895af64a77a8c852c"}, 213 | {file = "typed_ast-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:fc0fea399acb12edbf8a628ba8d2312f583bdbdb3335635db062fa98cf71fca4"}, 214 | {file = "typed_ast-1.4.1-cp39-cp39-macosx_10_15_x86_64.whl", hash = "sha256:d43943ef777f9a1c42bf4e552ba23ac77a6351de620aa9acf64ad54933ad4d34"}, 215 | {file = "typed_ast-1.4.1.tar.gz", hash = "sha256:8c8aaad94455178e3187ab22c8b01a3837f8ee50e09cf31f1ba129eb293ec30b"}, 216 | ] 217 | typing-extensions = [ 218 | {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, 219 | {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, 220 | {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, 221 | ] 222 | --------------------------------------------------------------------------------