Skip to content

Commit

Permalink
[feature] support read config from env
Browse files Browse the repository at this point in the history
  • Loading branch information
littleneko committed Jan 6, 2023
1 parent 7d6a13a commit 1678840
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 130 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,6 @@ dmypy.json

.DS_Store
.idea/
bing/
database/
download/
storage/
log/
53 changes: 49 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,57 @@
# bing_wallpaper
A scripy to download bing daliy wallpaper

A scripy to download bing daily wallpaper

## Usage

```
usage: app.py [-h] [--storage-dir STORAGE_DIR] [--download-dir DOWNLOAD_DIR] [--download-timeout DOWNLOAD_TIMEOUT] [--filelog] [--log-dir LOG_DIR]
[--scan-interval SCAN_INTERVAL] [--notify-mail NOTIFY_MAIL] [--my-notify-mail MY_NOTIFY_MAIL] [--my-notify-pass MY_NOTIFY_PASS]
[--my-notify-name MY_NOTIFY_NAME] [--server-chan-key SERVER_CHAN_KEY]
A tool to download bing daily wallpaper.
options:
-h, --help show this help message and exit
General Options:
--storage-dir STORAGE_DIR
directory to store database file, env: BING_STORAGE_DIR (default: storage)
--download-dir DOWNLOAD_DIR
directory to store image file, env: BING_DOWNLOAD_DIR (default: download)
--download-timeout DOWNLOAD_TIMEOUT
download timeout ms, env: BING_DOWNLOAD_TIMEOUT (default: 5000)
--filelog write log to file, otherwise to stdout (default: False)
--log-dir LOG_DIR directory to store log file if filelog is true, env: BING_LOG_DIR (default: log)
--scan-interval SCAN_INTERVAL
every scan-interval seconds to get bing wallpaper, 0 means run once, env: BING_SCAN_INTERVAL (default: 0)
Notify Options:
--notify-mail NOTIFY_MAIL
email to notify when success or failed download, env: BING_NOTIFY_MAIL (default: None)
--my-notify-mail MY_NOTIFY_MAIL
email to send notify email, env: BING_MY_NOTIFY_MAIL (default: None)
--my-notify-pass MY_NOTIFY_PASS
my-email password or token, env: BING_MY_NOTIFY_PASS (default: None)
--my-notify-name MY_NOTIFY_NAME
user name to send notify email, env: BING_MY_NOTIFY_NAME (default: Robot)
--server-chan-key SERVER_CHAN_KEY
server-chan token to notify, env: BING_SERVER_CHAN_KEY (default: None)
```

All args can be read from environment variables, the environment variables with prefix `BING_`.

## Docker Usage

```shell
docker run -d \
-v /path/to/config/folder:/bing/config \
-v /path/to/database/folder:/bing/database \
-v /path/to/download/folder:/bing/wallpaper \
-e BING_SCAN_INTERVAL=3600 \
-e [email protected] \
-e [email protected] \
-e BING_MY_NOTIFY_PASS=password \
-e BING_SERVER_CHAN_KEY=xxx \
-v /path/to/storage/folder:/bing/storage \
-v /path/to/download/folder:/bing/download \
littleneko/bing-dl:latest
```
13 changes: 0 additions & 13 deletions config/bing.ini

This file was deleted.

72 changes: 52 additions & 20 deletions src/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,42 +7,74 @@
import time

from log import init_logging
from config import get_config
from bing import BingDownloader
from notify import Notification
from env import env_default

parser = argparse.ArgumentParser(description='bing-dl')
parser.add_argument('--config', '-c', default="config/bing.ini", help='config file name')
parser.add_argument('--clean-db', action='store_true', help='clean the bing wallpaper database')

def get_args():
parser = argparse.ArgumentParser(
description='A tool to download bing daily wallpaper.',
formatter_class=argparse.ArgumentDefaultsHelpFormatter)

group1 = parser.add_argument_group('General Options')
group1.add_argument('--storage-dir', default='storage', action=env_default('BING_STORAGE_DIR'),
help='directory to store database file, env: BING_STORAGE_DIR')
group1.add_argument('--download-dir', default="download", action=env_default('BING_DOWNLOAD_DIR'),
help='directory to store image file, env: BING_DOWNLOAD_DIR')
group1.add_argument('--download-timeout', default=5000, type=int, action=env_default('BING_DOWNLOAD_TIMEOUT'),
help='download timeout ms, env: BING_DOWNLOAD_TIMEOUT')
group1.add_argument('--filelog', action="store_true", help='write log to file, otherwise to stdout')
group1.add_argument('--log-dir', default="log", action=env_default('BING_LOG_DIR'),
help='directory to store log file if filelog is true, env: BING_LOG_DIR')
group1.add_argument('--scan-interval', default=0, type=int, action=env_default('BING_SCAN_INTERVAL'),
help='every scan-interval seconds to get bing wallpaper, 0 means run once, '
'env: BING_SCAN_INTERVAL')

group2 = parser.add_argument_group('Notify Options')
group2.add_argument('--notify-mail', action=env_default('BING_NOTIFY_MAIL'),
help='email to notify when success or failed download, env: BING_NOTIFY_MAIL')
group2.add_argument('--my-notify-mail', action=env_default('BING_MY_NOTIFY_MAIL'),
help='email to send notify email, env: BING_MY_NOTIFY_MAIL')
group2.add_argument('--my-notify-pass', action=env_default('BING_MY_NOTIFY_PASS'),
help='my-email password or token, env: BING_MY_NOTIFY_PASS')
group2.add_argument('--my-notify-name', default='Robot', action=env_default('BING_MY_NOTIFY_NAME'),
help='user name to send notify email, env: BING_MY_NOTIFY_NAME')
group2.add_argument('--server-chan-key', action=env_default('BING_SERVER_CHAN_KEY'),
help='server-chan token to notify, env: BING_SERVER_CHAN_KEY')

def run():
args = parser.parse_args()
return args

conf = get_config(args.config)
init_logging(conf.file_log, conf.log_dir)

notify = None
if conf.notify_mail is not None:
notify = Notification(conf.my_mail, conf.my_pass, conf.notify_mail, conf.server_chan_key)
def run():
args = get_args()

init_logging(args.filelog, args.log_dir)

if not os.path.exists(conf.database_dir):
os.makedirs(conf.database_dir)
db_file = os.path.join(conf.database_dir, "bing.db")
notify = None
if args.notify_mail:
if not args.my_notify_mail or not args.my_notify_pass:
logging.error("args error, must specify my_notify_mail and my_notify_pass if you specified notify_mail")
return
notify = Notification(my_mail=args.my_notify_mail, my_password=args.my_notify_pass, to_mail=args.notify_mail,
server_chan_key=args.server_chan_key)

bing_downloader = BingDownloader(db_file, conf.download_dir, notify=notify)
if args.clean_db:
bing_downloader.clean_db()
if not os.path.exists(args.storage_dir):
os.makedirs(args.storage_dir)
db_file = os.path.join(args.storage_dir, "bing.db")

bing_downloader = BingDownloader(db_file, args.download_dir, notify=notify,
download_timeout_ms=args.download_timeout)
bing_downloader.init_db()
while True:
bing_downloader.download()
if conf.scan_interval_sec <= 0:
if args.scan_interval <= 0:
break
logging.info("wait for next round after %d second", conf.scan_interval_sec)
logging.info("wait for next round after %d second", args.scan_interval)
try:
time.sleep(conf.scan_interval_sec)
except KeyboardInterrupt:
time.sleep(args.scan_interval)
except InterruptedError:
break


Expand Down
42 changes: 0 additions & 42 deletions src/config.py

This file was deleted.

33 changes: 33 additions & 0 deletions src/env.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
"""Provides a utility to inject environment variables into argparse definitions.
Currently requires explicit naming of env vars to check for"""

# https://gist.github.com/orls/51525c86ee77a56ad396

import argparse
import os


# Courtesy of http://stackoverflow.com/a/10551190 with env-var retrieval fixed
class EnvDefault(argparse.Action):
"""An argparse action class that auto-sets missing default values from env
vars. Defaults to requiring the argument."""

def __init__(self, env_var, required=False, default=None, **kwargs):
if env_var and env_var in os.environ:
var = os.environ[env_var]
if len(var) > 0:
default = var
if required and default:
required = False
super(EnvDefault, self).__init__(default=default, required=required, **kwargs)

def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, values)


# functional sugar for the above
def env_default(env_var):
def wrapper(**kwargs):
return EnvDefault(env_var, **kwargs)

return wrapper
2 changes: 1 addition & 1 deletion src/log.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ def init_logging(filelog: bool, path: str):


if __name__ == '__main__':
init_logging(".")
init_logging(True, ".")
logging.error("[logger] error")
logging.warning("[logger] waring")
logging.info("[logger] info")
41 changes: 25 additions & 16 deletions src/notify.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,38 @@
import requests
from requests import RequestException

from send_mail import mail
from send_mail import send_mail


class Notification(object):
SERVER_CHAN_URI = "https://sc.ftqq.com/"

def __init__(self,
my_mail: str,
my_password: str,
server_chan_key: str,
to_mail: str):
my_mail: str = None,
my_password: str = None,
my_name: str = 'Robot',
to_mail: str = None,
server_chan_key: str = None):
self._my_mail = my_mail
self._my_pass = my_password
self._server_chan_key = server_chan_key
self._my_name = my_name
self._to_mail = to_mail
self._server_chan_key = server_chan_key

def notify(self, title: str, content: str):
if self._to_mail:
try:
send_mail(self._my_mail, self._my_name, self._my_pass, self._to_mail, title, content)
except Exception as e:
logging.error("[Notify] failed to send mail, %s", e)

def notify(self, title: str, content: str) -> bool:
if not mail(self._my_mail, self._my_mail, self._my_pass, self._to_mail, title, content):
logging.error("[Notify] failed to send mail")
try:
r = requests.get(Notification.SERVER_CHAN_URI + self._server_chan_key + ".send", params={"text": title})
if r.status_code != 200:
logging.error("[Notify] failed to notify, status_code=%d, msg=%s" % (r.status_code, r.text))
except RequestException as e:
logging.error("[Notify] failed to notify", e)
return True
if self._server_chan_key:
try:
logging.info("FUCK")
r = requests.get(Notification.SERVER_CHAN_URI + self._server_chan_key + ".send", params={"text": title},
timeout=5)
if r.status_code != 200:
logging.error("[Notify] failed to notify server chan, status_code=%d, msg=%s", r.status_code,
r.text)
except RequestException as e:
logging.error("[Notify] failed to notify server-chan, %s", e)
Loading

0 comments on commit 1678840

Please sign in to comment.