add launchd scheduling
adds --schedule and --time flags improves CLI feedback resolves #5
This commit is contained in:
parent
3f6562b423
commit
abc7e07677
43
README.md
43
README.md
|
@ -88,6 +88,10 @@ ephemetoot
|
|||
|
||||
Depending on how many toots you have and how long you want to keep them, it may take a minute or two before you see any results.
|
||||
|
||||
## --schedule
|
||||
|
||||
For setting up scheduling on MacOS - see [Scheduling](#scheduling).
|
||||
|
||||
## Specifying the config location
|
||||
|
||||
By default ephemetoot expects there to be a config file called `config.yaml` in the directory from where you run the `ephemetoot` command. If you want to call it from elsewhere (e.g. with `cron`), you need to specify where your config file is:
|
||||
|
@ -126,12 +130,39 @@ As of v2.7.2 the Mastodon API has a rate limit of 30 deletions per 30 minutes. `
|
|||
|
||||
Deleting old toots daily is the best approach to keeping your timeline clean and avoiding problems wiht the API rate limit.
|
||||
|
||||
### Linux and FreeBSD/Unix
|
||||
|
||||
To run automatically every day on a n*x server you could try using crontab:
|
||||
|
||||
1. `crontab -e`
|
||||
2. `@daily ephemetoot`
|
||||
2. enter a new line: `@daily ephemetoot --config /path/to/ephemetoot/config.yaml`
|
||||
3. exit with `:qw` (Vi/Vim) or `Ctrl + x` (nano)
|
||||
|
||||
Alternatively on MacOS you could use [launchd](https://www.launchd.info/). Some further work on an example setup for launchd is coming soonish.
|
||||
### MacOS
|
||||
|
||||
On **MacOS** you can use the `--schedule` flag to schedule a daily job with [launchd](https://www.launchd.info/). Note that this feature has not been widely tested so **please log an issue if you notice anything go wrong**.
|
||||
|
||||
Run from within your `ephemetoot` directory:
|
||||
```shell
|
||||
ephemetoot --schedule
|
||||
```
|
||||
or from anywhere else run:
|
||||
```shell
|
||||
ephemetoot --schedule directory
|
||||
```
|
||||
where `directory` is where you installed `ephemetoot`. For example if `ephemetoot` is saved to `/User/hugh/python/ephemetoot`:
|
||||
```shell
|
||||
ephemetoot --schedule /User/hugh/python/ephemetoot
|
||||
```
|
||||
|
||||
By default, `ephemetoot` will run at 9am every day (as long as your machine is logged in and connected to the internet). You can change the time it is scheduled to run, using the `--time` flag with `--schedule`:
|
||||
```shell
|
||||
ephemetoot --schedule [directory] --time hour minute
|
||||
```
|
||||
For example to run at 2.25pm every day:
|
||||
```shell
|
||||
ephemetoot --schedule --time 14 25
|
||||
```
|
||||
|
||||
# ASCII / utf-8 errors
|
||||
|
||||
|
@ -142,10 +173,16 @@ Prior to Python 3.7, running a Python script on some BSD and Linux systems may t
|
|||
# Uninstalling
|
||||
|
||||
Uninstall using pip;
|
||||
```
|
||||
```shell
|
||||
pip uninstall ephemetoot
|
||||
```
|
||||
|
||||
If you scheduled a `launchd` job on MacOS using `--schedule`, you will also need to unload and remove the scheduling file:
|
||||
```shell
|
||||
launchctl unload ~/Library/LaunchAgents/ephemetoot.scheduler.plist
|
||||
rm ~/Library/LaunchAgents/ephemetoot.scheduler.plist
|
||||
```
|
||||
|
||||
# Bugs and suggestions
|
||||
|
||||
Please check existing [issues](https://github.com/hughrun/ephemetoot/issues) and if your issue is not already listed, create a new one with as much detail as possible (but don't include your access token!).
|
||||
|
|
|
@ -28,6 +28,7 @@ import yaml
|
|||
|
||||
# from standard library
|
||||
from argparse import ArgumentParser
|
||||
from datetime import datetime
|
||||
import os
|
||||
|
||||
# local files
|
||||
|
@ -40,6 +41,12 @@ parser.add_argument(
|
|||
parser.add_argument(
|
||||
"--test", action="store_true", help="do a test run without deleting any toots"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--schedule", action="store", metavar="'filepath'", nargs="?", const=".", help="save and load plist file on MacOS"
|
||||
)
|
||||
parser.add_argument(
|
||||
"--time", action="store", metavar="'hours minutes'", nargs="*", help="hour and minute to schedule: e.g. 9 30 for 9.30am"
|
||||
)
|
||||
|
||||
options = parser.parse_args()
|
||||
if options.config[0] == '~':
|
||||
|
@ -50,7 +57,15 @@ else:
|
|||
config_file = os.path.join( os.getcwd(), options.config )
|
||||
|
||||
if __name__ == "__main__":
|
||||
with open(config_file) as config:
|
||||
for accounts in yaml.safe_load_all(config):
|
||||
for user in accounts:
|
||||
ephemetoot.checkToots(user, options)
|
||||
if options.schedule:
|
||||
ephemetoot.schedule(options)
|
||||
else:
|
||||
print('')
|
||||
print('=========== EPHEMETOOT ================')
|
||||
print('Running at ' + str(datetime.now() ))
|
||||
print('=======================================')
|
||||
print('')
|
||||
with open(config_file) as config:
|
||||
for accounts in yaml.safe_load_all(config):
|
||||
for user in accounts:
|
||||
ephemetoot.checkToots(user, options)
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>Label</key>
|
||||
<string>ephemetoot.scheduler</string>
|
||||
<key>WorkingDirectory</key>
|
||||
<string>/FILEPATH/ephemetoot</string>
|
||||
<key>ProgramArguments</key>
|
||||
<array>
|
||||
<string>/usr/local/bin/ephemetoot</string>
|
||||
<string>--config</string>
|
||||
<string>/FILEPATH/config.yaml</string>
|
||||
</array>
|
||||
<key>StandardOutPath</key>
|
||||
<string>ephemetoot.log</string>
|
||||
<key>StandardErrorPath</key>
|
||||
<string>ephemetoot.error.log</string>
|
||||
<key>StartCalendarInterval</key>
|
||||
<dict>
|
||||
<key>Hour</key>
|
||||
<integer>9</integer>
|
||||
<key>Minute</key>
|
||||
<integer>00</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
</plist>
|
|
@ -1,10 +1,52 @@
|
|||
from datetime import datetime, timedelta, timezone
|
||||
import json
|
||||
from mastodon import Mastodon, MastodonError, MastodonAPIError, MastodonNetworkError
|
||||
from datetime import datetime, timedelta, timezone
|
||||
import time
|
||||
import os
|
||||
import requests
|
||||
import subprocess
|
||||
import sys
|
||||
import time
|
||||
|
||||
def checkToots(config, options, deleted_count=0):
|
||||
def schedule(options):
|
||||
try:
|
||||
with open(options.schedule + '/ephemetoot.scheduler.plist', 'r') as file:
|
||||
lines = file.readlines()
|
||||
if options.schedule == ".":
|
||||
working_dir = os.getcwd()
|
||||
else:
|
||||
working_dir = options.schedule
|
||||
lines[7] = " <string>" + working_dir + "</string>\n"
|
||||
lines[10] = " <string>" + sys.argv[0] + "</string>\n"
|
||||
lines[12] = " <string>" + working_dir + "/config.yaml</string>\n"
|
||||
if options.time:
|
||||
lines[21] = " <integer>" + options.time[0] + "</integer>\n"
|
||||
lines[23] = " <integer>" + options.time[1] + "</integer>\n"
|
||||
with open('ephemetoot.scheduler.plist', 'w') as file:
|
||||
file.writelines(lines)
|
||||
|
||||
sys.tracebacklimit = 0 # suppress Tracebacks
|
||||
# save the plist file into ~/Library/LaunchAgents
|
||||
subprocess.run(
|
||||
["cp " + options.schedule + "/ephemetoot.scheduler.plist" + " ~/Library/LaunchAgents/"],
|
||||
shell=True
|
||||
)
|
||||
# unload any existing file (i.e. if this is an update to the file) and suppress any errors
|
||||
subprocess.run(
|
||||
["launchctl unload ~/Library/LaunchAgents/ephemetoot.scheduler.plist"],
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL,
|
||||
shell=True
|
||||
)
|
||||
# load the new file and suppress any errors
|
||||
subprocess.run(
|
||||
["launchctl load ~/Library/LaunchAgents/ephemetoot.scheduler.plist"],
|
||||
shell=True
|
||||
)
|
||||
print('⏰ Scheduled!')
|
||||
except Exception:
|
||||
print('🙁 Scheduling failed.')
|
||||
|
||||
def checkToots(config, options, deleted_count=0, retry_count=0):
|
||||
if options.test:
|
||||
print("This is a test run...")
|
||||
print("Fetching account details for @" + config['username'] + "@" + config['base_url'] + "...")
|
||||
|
@ -108,6 +150,12 @@ def checkToots(config, options, deleted_count=0):
|
|||
)
|
||||
else:
|
||||
print("Removed " + str(deleted_count) + " toots.")
|
||||
|
||||
print('')
|
||||
print('---------------------------------------')
|
||||
print('🥳 ==> 🧼 ==> 😇 User cleanup complete!')
|
||||
print('---------------------------------------')
|
||||
|
||||
except IndexError:
|
||||
print("No toots found!")
|
||||
|
||||
|
@ -115,6 +163,11 @@ def checkToots(config, options, deleted_count=0):
|
|||
print('User and/or access token does not exist or has been deleted')
|
||||
except MastodonNetworkError:
|
||||
print('ephemetoot cannot connect to the server - are you online?')
|
||||
finally:
|
||||
print('🥳 ==> 🧼 ==> 😇 User cleanup complete!')
|
||||
print('---------------------------------------')
|
||||
if retry_count < 4:
|
||||
print('Waiting 1 minute before trying again')
|
||||
time.sleep(60)
|
||||
retry_count += 1
|
||||
print( 'Attempt ' + str(retry_count + 1) )
|
||||
checkToots(config, options, 0, retry_count)
|
||||
else:
|
||||
print('Gave up waiting for network')
|
4
setup.py
4
setup.py
|
@ -1,12 +1,12 @@
|
|||
from setuptools import setup, find_packages
|
||||
|
||||
setup(name='ephemetoot',
|
||||
version='2.0.0',
|
||||
version='2.1.0',
|
||||
url='https://github.com/hughrun/ephemetoot',
|
||||
license='GPL-3.0-or-later',
|
||||
packages=find_packages(),
|
||||
scripts=['bin/ephemetoot'],
|
||||
install_requires=['Mastodon.py', 'pyyaml'],
|
||||
install_requires=['Mastodon.py', 'pyyaml', 'requests'],
|
||||
zip_safe=False,
|
||||
author='Hugh Rundle',
|
||||
author_email='hugh@hughrundle.net',
|
||||
|
|
Loading…
Reference in New Issue