Merge pull request #45 from hughrun/poetry

Version 3 alpha
This commit is contained in:
Hugh Rundle 2020-08-28 18:32:39 +10:00 committed by GitHub
commit 81db1f167f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 567 additions and 170 deletions

5
.gitignore vendored
View File

@ -1,3 +1,4 @@
config.py
config.yaml
_assets
_assets
pypi-readme.md
dist

View File

@ -1,8 +1,9 @@
# 🥳 ==> 🧼 ==> 😇
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
**ephemetoot** is a Python command line tool for deleting old toots.
## Documentation
* [Installation](./docs/install.md)
* [Options](./docs/options.md)
* [Upgrading and uninstalling](./docs/upgrade.md)
@ -13,29 +14,14 @@ The initial `ephemetoot` script was based on [this tweet-deleting script](https:
`ephemetoot` relies heavily on the Mastodon.py package by [@halcy](https://github.com/halcy)
## Usage
You can use `ephemetoot` to delete [Mastodon](https://github.com/tootsuite/mastodon) toots that are older than a certain number of days (default is 365). Toots can optionally be saved from deletion if:
* they are pinned; or
* they include certain hashtags; or
* they have certain visibility; or
* they are individually listed to be kept
## Rate limits
As of v2.7.2 the Mastodon API has a rate limit of 30 deletions per 30 minutes. `mastodon.py` automatically handles this. If you are running `ephemetoot` for the first time and/or have a lot of toots to delete, it may take a while as the script will pause when it hits a rate limit, until the required time has expired. You can use the `--pace` flag to slow down ephemetoot so that it never hits the limit - this is recommended on your first run. It will not speed up the process but will smooth it out.
Note that the rate limit is per access token, so using ephemetoot for multiple accounts on the same server shouldn't be a big problem, however one new user may delay action on subsequent accounts in the config file.
## ASCII / utf-8 errors
Prior to Python 3.7, running a Python script on some BSD and Linux systems may throw an error. This can be resolved by:
* setting a _locale_ that encodes utf-8, by using the environment setting `PYTHONIOENCODING=utf-8` when running the script, or
* upgrading your Python version to 3.7 or higher. See [Issue 11](https://github.com/hughrun/ephemetoot/issues/11) for more information.
## Contributing
For all bugs, suggestions, pull requests or other contributions, please check the [contributing guide](./contributing.md).
For all bugs, suggestions, pull requests or other contributions, please check the [contributing guide](./docs/contributing.md).
## License
This project and all contributions are [licensed](./LICENSE) under the GPL 3.0 or future version

1
docs/CNAME Normal file
View File

@ -0,0 +1 @@
ephemetoot.hugh.run

View File

@ -7,16 +7,16 @@ You can contribute in many ways - improving the documentation, reporting bugs, s
# Expectations
## Adhere to the Code of Conduct 🤗
All contributors must adhere to the [Code of Conduct](./CODE_OF_CONDUCT.md) for this project. If you do not wish to follow this Code of Conduct, feel free to direct your energies towards a different project.
All contributors must adhere to the [Code of Conduct](https://github.com/hughrun/ephemetoot/blob/poetry/CODE_OF_CONDUCT.md) for this project. If you do not wish to follow this Code of Conduct, feel free to direct your energies towards a different project.
## Do not log security problems as public issues
If you have identified a security flaw in **ephemetoot**, please email `ephemetoot AT ausglam DOT space` to discuss this confidentially.
If you have identified a security flaw in **ephemetoot**, please email `ephemetoot@hugh.run` to discuss this confidentially.
## Check existing issues 🧐
Your bug or enhancement might already be listed in the [issues](./issues). It's a good idea to check existing issues before you log your own. If you like someone else's enhancement suggestion, please "upvote" it with a 👍 reaction. If you have also experienced the same bug as someone else, you can add any useful additional context to the existing issue.
Your bug or enhancement might already be listed in the [issues](https://github.com/hughrun/ephemetoot/issues). It's a good idea to check existing issues before you log your own. If you like someone else's enhancement suggestion, please "upvote" it with a 👍 reaction. If you have also experienced the same bug as someone else, you can add any useful additional context to the existing issue.
## Always log an issue 📝
If you would like to contribute code or documentation changes that do not already have an issue listed, you should always [log an issue](./issues) first. Please **do not add pull requests without prior discussion**. Whilst pull requests are very welcome and encouraged, if you don't log an issue for discussion first, you may end up wasting your time if someone else is already working on the same feature, or maintainers decide it isn't a good fit. This also allows for your proposed feature to be scoped before you get too deep in the weeds coding it.
If you would like to contribute code or documentation changes that do not already have an issue listed, you should always [log an issue](https://github.com/hughrun/ephemetoot/issues) first. Please **do not add pull requests without prior discussion**. Whilst pull requests are very welcome and encouraged, if you don't log an issue for discussion first, you may end up wasting your time if someone else is already working on the same feature, or maintainers decide it isn't a good fit. This also allows for your proposed feature to be scoped before you get too deep in the weeds coding it.
Regardless of whether is is a bug report, feature request or code proposal, provide as much detail as possible in your issue, and give it a clear name.
@ -63,4 +63,10 @@ This is a pretty small project so there usually won't be a lot of issues waiting
# Help
You can get in touch with Hugh at [@hugh@ausglam.space](https://ausglam.space/@hugh) if you need help contributing or want to discuss something about **ephemetoot**.
You can get in touch with Hugh at [@hugh@ausglam.space](https://ausglam.space/@hugh) if you need help contributing or want to discuss something about **ephemetoot**.
---
* [Home](/)
* [Installation](./install.md)
* [Options](./options.md)
* [Upgrading and uninstalling](./upgrade.md)

38
docs/index.md Normal file
View File

@ -0,0 +1,38 @@
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=flat-square)](http://makeapullrequest.com)
**ephemetoot** is a Python command line tool for deleting old toots.
These docs apply to Version 3.
* [Installation](./install.md)
* [Options](./options.md)
* [Upgrading and uninstalling](./upgrade.md)
* [Contributing](./contributing.md)
## Prior work
The initial `ephemetoot` script was based on [this tweet-deleting script](https://gist.github.com/flesueur/bcb2d9185b64c5191915d860ad19f23f) by [@flesueur](https://github.com/flesueur)
`ephemetoot` relies heavily on the Mastodon.py package by [@halcy](https://github.com/halcy)
## Usage
You can use `ephemetoot` to delete [Mastodon](https://github.com/tootsuite/mastodon) toots that are older than a certain number of days (default is 365). Toots can optionally be saved from deletion if:
* they are pinned; or
* they include certain hashtags; or
* they have certain visibility; or
* they are individually listed to be kept
## Rate limits
As of Mastodon v2.7.2 the Mastodon API has a rate limit of 30 deletions per 30 minutes. `mastodon.py` automatically handles this. If you are running `ephemetoot` for the first time and/or have a lot of toots to delete, it may take a while as the script will pause when it hits a rate limit, until the required time has expired. You can use the `--pace` flag to slow down ephemetoot so that it never hits the limit - this is recommended on your first run. It will not speed up the process but will smooth it out.
Note that the rate limit is per access token, so using ephemetoot for multiple accounts on the same server shouldn't be a big problem, however one new user may delay action on subsequent accounts in the config file.
## ASCII / utf-8 errors
Prior to Python 3.7, running a Python script on some BSD and Linux systems may throw an error. This can be resolved by:
* setting a _locale_ that encodes utf-8, by using the environment setting `PYTHONIOENCODING=utf-8` when running the script, or
* upgrading your Python version to 3.7 or higher. See [Issue 11](https://github.com/hughrun/ephemetoot/issues/11) for more information.
## Contributing
For all bugs, suggestions, pull requests or other contributions, please check the [contributing guide](./docs/contributing.md).
## License
This project and all contributions are [licensed](https://github.com/hughrun/ephemetoot/blob/master/LICENSE) under the GPL 3.0 or future version

View File

@ -2,33 +2,20 @@
## Install Python 3 and pip
You need to [install Python 3](https://wiki.python.org/moin/BeginnersGuide/Download) to use `ephemetoot`. Python 2 is now end-of-life, however it continued to be installed as the default Python on MacOS and many Linux distributions until very recently, so you should check. You will also need to check that `pip` is installed and pointing to Python3 (not Python2). On some systems this will mean using the command `pip3`.
You need to [install Python 3](https://wiki.python.org/moin/BeginnersGuide/Download) to use `ephemetoot`. Python 2 is now end-of-life, however it continued to be installed as the default Python on MacOS and many Linux distributions until very recently, so you should check.
## Install ephemetoot
### Option 1 - get code with git
If you already have `git` installed on the machine where you're running ephemetoot, you can download the latest release with:
```shell
git clone https://github.com/hughrun/ephemetoot.git
cd ephemetoot
git checkout [tagname]
```
### Option 2 - get the code by downloading the zip file
If you don't have `git` or don't want to use it, you can download the zip file by clicking the green button above and selecting `Download ZIP`. You will then need to unzip the file into a new directory where you want to run it.
These instructions use the command `pip3` since it is very likely you will need to use that instead of `pip` (which usually points to Python 2). On some systems you may need to use `pip` instead, if `pip` is pointing to Python 3.
## Install ephemetoot from pypi
### Complete install with pip
From a command line, move into the main `ephemetoot` directory (i.e. where the README file is) and run:
```shell
pip install .
pip3 install ephemetoot
```
With some Python 3 installations (e.g on MacOS with Homebrew) you may need to use:
If you do not have permission to install python modules, you may need to use the `--user` flag. Generally this is not advisable, since you will need to run ephemetoot with the same user since it will only be installed for that user and not globally:
```shell
pip3 install .
pip3 install . --user
```
If you do not have permission to install python modules, you may need to use the `--user` flag:
```shell
pip install . --user
```
Note that you will need to run the script with the same user as ephemetoot will only be installed for that user and not globally.
## Obtain an access token
@ -51,13 +38,15 @@ Now you've installed `ephemetoot`, in order to actually use it you will need an
## Configuration file
As of version 2, you can use a single `ephemetoot` installation to delete toots from multiple accounts. Configuration for each user is set up in the `config.yaml` file. This uses [yaml syntax](https://yaml.org/spec/1.2/spec.html) and can be updated at any time without having to reload `ephemetoot`.
Configuration for each user is set up in the `config.yaml` file. This uses [yaml syntax](https://yaml.org/spec/1.2/spec.html) and can be updated at any time without having to reload `ephemetoot`.
You can create a config file by hand, but the easiest way to do it is with the `--init` flag:
Copy `example-config.yaml` to a new file called `config.yaml`:
```shell
cp example-config.yam config.yaml
ephemetoot --init
```
You can now enter the configuration details for each user:
This will ask you to fill in information for each part of the file:
| setting | description |
| ---: | :--- |
@ -80,9 +69,10 @@ hashtags_to_keep:
visibility_to_keep: [ ] # this empty list is also ok
```
If you want to use `ephemetoot` for multiple accounts, separate the config for each user with a single dash (`-`), as shown in the example file.
As of version 2, you can use a single `ephemetoot` installation to delete toots from multiple accounts. If you want to use `ephemetoot` for multiple accounts, separate the config for each user with a single dash (`-`), and add the additional details, as shown in [the example file](https://github.com/hughrun/ephemetoot/blob/master/example-config.yaml).
---
* [Home](/)
* [Options](./options.md)
* [Upgrading and uninstalling](./upgrade.md)
* [Upgrading and uninstalling](./upgrade.md)
* [Contributing](./contributing.md)

View File

@ -4,37 +4,52 @@ For a short description of all available options, run `ephemetoot --help` from t
It is **strongly recommended** that you do a test run before using `ephemetoot` live. There is no "undo"!
## Running in test mode (--test)
## Create your config file (--init)
Before you can use `ephemetoot` you need a `config.yaml` file. You can create this yourself, but `--init` will walk you through the values you need and save your `config.yaml` file in the directory from which you run the command:
```shell
ephemetoot --init
```
More information about the config file can be found on teh _[Installation](./install.md)_ page, and an [example file](https://github.com/hughrun/ephemetoot/blob/master/example-config.yaml) is available on GitHub.
## Run in test mode (--test)
To do a test-run without actually deleting anything, run the script with the `--test` flag:
```shell
ephemetoot --test
```
## Running in "live" mode
## Run in "live" mode
To call the script call ephemetoot with no arguments:
To call the script use the command `ephemetoot` without any other arguments:
```shell
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.
## Specifying the config location (--config)
## Specify the config location (--config)
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:
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. when using `cron`), you need to specify where your config file is:
```shell
ephemetoot --config '~/directory/subdirectory/config.yaml'
```
## Manage timing
## Slow down deletes to match API limit (--pace)
### Slow down deletes to match API limit (--pace)
With the `--pace` flag, delete actions are slowed so that the API limit is never reached, using [`Mastodon.py`'s 'pace' method](https://mastodonpy.readthedocs.io/en/stable/index.html?highlight=pace#mastodon.Mastodon.__init__). This is recommended for your first run, as unless you have tooted fewer than 30 times you are guaranteed to hit the API limit for deletions the first time you run `ephemetoot`. If you do not toot very often on most days, it is probably more efficient to use the default behaviour for daily runs after the first time, but you can use `--pace` every time if you prefer.
With the `--pace` flag, delete actions are slowed so that the API limit is never reached, essentially borrowing the 'pace' method from the [`Mastodon.py`](https://mastodonpy.readthedocs.io/en/stable/index.html?highlight=pace#mastodon.Mastodon.__init__) module. This is **recommended for your first run**, as unless you have tooted fewer than 30 times you are guaranteed to hit the API limit for deletions the first time you run `ephemetoot`. If you do not toot very often on most days, it is probably more efficient to use the default behaviour for daily runs after the first time, but you can use `--pace` every time if you prefer.
## Increase the time between retry attempts when encountering errors (--retry-mins)
### Increase the time between retry attempts when encountering errors (--retry-mins)
Use `--retry-mins` to increase the period between attempts to retry deletion after an error. The default value is one (1) minute, but you can make it anything you like. This is useful if your mastodon server is unreliable or frequently in "maintenance mode".
Use `--retry-mins` to increase the period between attempts to retry deletion after an error. The default value is one (1) minute, but you can make it anything you like. This is useful if your mastodon server is unreliable or frequently in "maintenance mode". `ephemetoot` will make four additional attempts if it encounters an error, so the following command, for example, would wait 20 minutes between each retry, allowing the script to continue if there is an outage of 79 minutes or fewer:
```shell
ephemetoot --retry-mins 20
```
## Do more
@ -66,11 +81,7 @@ ephemetoot --config 'directory/config.yaml' --test --hide-skipped
```
Use them in any order:
```shell
ephemetoot --pace --datestamp --config 'directory/config.yaml'
```
Instead of coming back to this page when you forget the flags, you can just use the help option:
```shell
ephemetoot --help
ephemetoot --pace --retry-mins 5 --datestamp --config 'directory/config.yaml'
```
## Scheduling
@ -85,7 +96,7 @@ To run automatically every day on a n*x server you could try using crontab:
2. enter a new line: `@daily /path/to/ephemetoot --config /path/to/ephemetoot/config.yaml`
3. exit with `:qw` (Vi/Vim) or `Ctrl + x` (nano)
### MacOS
### MacOS (--schedule)
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**.
@ -112,6 +123,7 @@ For example to run at 2.25pm every day:
ephemetoot --schedule --time 14 25
```
---
* [Home](/)
* [Installation](./install.md)
* [Upgrading and uninstalling](./upgrade.md)
* [Contributing](./contributing.md)

View File

@ -2,17 +2,33 @@
## Upgrading
### Note for users upgrading from Version 2 to Version 3
To upgrade from Version 2.x to Version 3.x you should be able to simply follow the _Upgrading with pypi_ instructions below. However the safest procedure is:
1. save a copy of your `config.yaml` file somewhere safe
2. run `pip uninstall ephemetoot`
3. run `pip install ephemetoot`
4. do a test run with `ephemetoot --test`
### Upgrading with pypi
To upgrade to a new version, the easiest way is to use pip to download the latest version from pypi (remembering that for your machine you may need to substitute `pip` for `pip3`):
```shell
pip3 install --upgrade ephemetoot
```
### Upgrading with git
To upgrade to a new version using git, run the following from inside the `ephemetoot` directory:
```shell
git fetch --tags
git checkout [tagname]
pip install .
git checkout [latest-tagname]
pip3 install .
```
### Upgrading with a ZIP file
To upgrade without using git:
To upgrade without using git or pypi:
* put your config file somewhere safe
* download and unzip the zip file into your `ephemetoot` directory over the top of your existing installation
@ -23,7 +39,7 @@ To upgrade without using git:
Uninstall using pip:
```shell
pip uninstall ephemetoot
pip3 uninstall ephemetoot
```
If you scheduled a `launchd` job on MacOS using `--schedule`, you will also need to unload and remove the scheduling file:
@ -32,6 +48,7 @@ launchctl unload ~/Library/LaunchAgents/ephemetoot.scheduler.plist
rm ~/Library/LaunchAgents/ephemetoot.scheduler.plist
```
---
* [Home](/)
* [Installation](./install.md)
* [Options](./options.md)
* [Options](./options.md)
* [Contributing](./contributing.md)

View File

@ -1,27 +0,0 @@
<?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>

View File

@ -1,8 +1,8 @@
#!/usr/bin/env python3
# #####################################################################
# Ephemetoot - A script to delete your old toots
# Copyright (C) 2018 Hugh Rundle, 2019-2020 Hugh Rundle & Mark Eaton
# Ephemetoot - A command line tool to delete your old toots
# Copyright (C) 2018 Hugh Rundle, 2019-2020 Hugh Rundle & others
# Initial work based on tweet-deleting script by @flesueur
# (https://gist.github.com/flesueur/bcb2d9185b64c5191915d860ad19f23f)
#
@ -19,8 +19,8 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# You can contact Hugh on Mastodon @hugh@ausglam.space
# or email hugh [at] hughrundle [dot] net
# You can contact Hugh on Mastodon: @hugh@ausglam.space
# or email: ephemetoot@hugh.run
# #####################################################################
# import
@ -32,10 +32,10 @@ from datetime import datetime, timezone
import os
import pkg_resources
# local files
from lib import ephemetoot
# import funtions
from ephemetoot import ephemetoot as func
# version number from setup.py
# version number from package info
vnum = pkg_resources.require("ephemetoot")[0].version
parser = ArgumentParser()
@ -51,6 +51,9 @@ parser.add_argument(
parser.add_argument(
"--hide-skipped", "--hide_skipped", action="store_true", help="Do not write to log when skipping saved toots"
)
parser.add_argument(
"--init", action="store_true", help="Initialise creation of a config file saved in the current directory."
)
parser.add_argument(
"--pace", action="store_true", help="Slow deletion actions to match API rate limit to avoid pausing"
)
@ -81,11 +84,13 @@ elif options.config[0] == '/':
else:
config_file = os.path.join( os.getcwd(), options.config )
if __name__ == "__main__":
if options.version:
ephemetoot.version(vnum)
def main():
if options.init:
func.init()
elif options.version:
func.version(vnum)
elif options.schedule:
ephemetoot.schedule(options)
func.schedule(options)
else:
if not options.quiet:
print('')
@ -98,4 +103,7 @@ 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)
func.checkToots(user, options)
if __name__ == '__main__':
main()

View File

@ -1,5 +1,12 @@
# standard library
from datetime import date, datetime, timedelta, timezone
import json
import os
import subprocess
import sys
import time
# third party
from mastodon import (
Mastodon,
MastodonError,
@ -7,12 +14,127 @@ from mastodon import (
MastodonNetworkError,
MastodonRatelimitError,
)
import os
import requests
import subprocess
import sys
import time
# local
from ephemetoot import plist
def init():
init_start = "\033[96m"
init_end = "\033[0m"
init_eg = "\033[2m"
conf_token = ""
while len(conf_token) < 1:
conf_token = input(init_start + "Access token: " + init_end)
conf_user = ""
while len(conf_user) < 1:
conf_user = input(
init_start
+ "Username"
+ init_eg
+ "(without the '@' - e.g. alice):"
+ init_end
)
conf_url = ""
while len(conf_url) < 1:
conf_url = input(
init_start
+ "Base URL"
+ init_eg
+ "(e.g. example.social):"
+ init_end
)
conf_days = ""
while conf_days.isdigit() == False:
conf_days = input(
init_start
+ "Days to keep"
+ init_eg
+ "(default 365):"
+ init_end
)
conf_keep_pinned = ""
while conf_keep_pinned not in ["y", "n"]:
conf_keep_pinned = input(
init_start
+ "Keep pinned toots?"
+ init_eg
+ "(y or n):"
+ init_end
)
conf_pinned = "true" if conf_keep_pinned == "y" else "false"
conf_keep_toots = input(
init_start
+ "Toots to keep"
+ init_eg
+ " (optional list of IDs separated by commas):"
+ init_end
)
conf_keep_hashtags = input(
init_start
+ "Hashtags to keep"
+ init_eg
+ " (optional list separated by commas):"
+ init_end
)
conf_keep_visibility = input(
init_start
+ "Visibility to keep"
+ init_eg
+ " (optional list separated by commas):"
+ init_end
)
conf_archive = input(
init_start
+ "Archive path"
+ init_eg
+ " (optional filepath for archive):"
+ init_end
)
# write out the config file
with open("config.yaml", "w") as configfile:
configfile.write("-")
configfile.write("\n access_token: " + conf_token)
configfile.write("\n username: " + conf_user)
configfile.write("\n base_url: " + conf_url)
configfile.write("\n days_to_keep: " + conf_days)
configfile.write("\n keep_pinned: " + conf_pinned)
if len(conf_keep_toots) > 0:
keep_list = conf_keep_toots.split(',')
configfile.write("\n toots_to_keep:")
for toot in keep_list:
configfile.write("\n - " + toot.strip())
if len(conf_keep_hashtags) > 0:
tag_list = conf_keep_hashtags.split(',')
configfile.write("\n hashtags_to_keep:")
for tag in tag_list:
configfile.write("\n - " + tag.strip())
if len(conf_keep_visibility) > 0:
viz_list = conf_keep_visibility.split(',')
configfile.write("\n visibility_to_keep:")
for mode in viz_list:
configfile.write("\n - " + mode.strip())
if len(conf_archive) > 0:
configfile.write("\n archive: " + conf_archive)
configfile.close()
def version(vnum):
try:
@ -21,61 +143,57 @@ def version(vnum):
)
res = latest.json()
latest_version = res["name"]
print("\nYou are using ephemetoot Version " + vnum)
print("The latest release is " + latest_version + "\n")
print("\nephemetoot ==> 🥳 ==> 🧼 ==> 😇")
print("-------------------------------")
print("Using: \033[92mVersion " + vnum + "\033[0m")
print("Latest: \033[92m" + latest_version + "\033[0m")
print("To upgrade to the most recent version run \033[92mpip3 install --update ephemetoot\033[0m")
except Exception as e:
print("Something went wrong:")
print(e)
def schedule(options):
try:
with open(options.schedule + "/ephemetoot.scheduler.plist", "r") as file:
lines = file.readlines()
if options.schedule == ".":
working_dir = os.getcwd()
if options.schedule == ".":
working_dir = os.getcwd()
else:
working_dir = options.schedule
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"
lines = plist.default_file.splitlines()
lines[7] = " <string>" + working_dir + "</string>"
lines[10] = " <string>" + sys.argv[0] + "</string>"
lines[12] = " <string>" + working_dir + "/config.yaml</string>"
lines[15] = " <string>" + working_dir + "/ephemetoot.log</string>"
lines[17] = " <string>" + working_dir + "/ephemetoot.error.log</string>"
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)
lines[21] = " <integer>" + options.time[0] + "</integer>"
lines[23] = " <integer>" + options.time[1] + "</integer>"
# write out file directly to ~/Library/LaunchAgents
f = open(os.path.expanduser("~/Library/LaunchAgents/") + "ephemetoot.scheduler.plist", mode="w")
for line in lines:
if line == lines[-1]:
f.write(line)
else:
f.write(line + "\n")
f.close()
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,
shell=True
)
# load the new file and suppress any errors
# load the new file
subprocess.run(
["launchctl load ~/Library/LaunchAgents/ephemetoot.scheduler.plist"],
shell=True,
shell=True
)
print("⏰ Scheduled!")
except Exception:
except Exception as e:
print("🙁 Scheduling failed.")

27
ephemetoot/plist.py Normal file
View File

@ -0,0 +1,27 @@
default_file = '''<?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>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>'''

206
poetry.lock generated Normal file
View File

@ -0,0 +1,206 @@
[[package]]
category = "main"
description = "Pure-Python implementation of the blurhash algorithm."
name = "blurhash"
optional = false
python-versions = "*"
version = "1.1.4"
[package.extras]
test = ["pillow", "numpy", "pytest"]
[[package]]
category = "main"
description = "Python package for providing Mozilla's CA Bundle."
name = "certifi"
optional = false
python-versions = "*"
version = "2020.6.20"
[[package]]
category = "main"
description = "Universal encoding detector for Python 2 and 3"
name = "chardet"
optional = false
python-versions = "*"
version = "3.0.4"
[[package]]
category = "main"
description = "Decorators for Humans"
name = "decorator"
optional = false
python-versions = ">=2.6, !=3.0.*, !=3.1.*"
version = "4.4.2"
[[package]]
category = "main"
description = "Internationalized Domain Names in Applications (IDNA)"
name = "idna"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
version = "2.10"
[[package]]
category = "main"
description = "Python wrapper for the Mastodon API"
name = "mastodon.py"
optional = false
python-versions = "*"
version = "1.5.1"
[package.dependencies]
blurhash = ">=1.1.4"
decorator = ">=4.0.0"
python-dateutil = "*"
python-magic = "*"
pytz = "*"
requests = ">=2.4.2"
six = "*"
[package.extras]
blurhash = ["blurhash (>=1.1.4)"]
test = ["blurhash (>=1.1.4)", "cryptography (>=1.6.0)", "http-ece (>=1.0.5)", "pytest", "pytest-cov", "pytest-mock", "pytest-runner", "pytest-vcr", "requests-mock", "vcrpy"]
webpush = ["cryptography (>=1.6.0)", "http-ece (>=1.0.5)"]
[[package]]
category = "main"
description = "Extensions to the standard Python datetime module"
name = "python-dateutil"
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
version = "2.8.1"
[package.dependencies]
six = ">=1.5"
[[package]]
category = "main"
description = "File type identification using libmagic"
name = "python-magic"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "0.4.18"
[[package]]
category = "main"
description = "World timezone definitions, modern and historical"
name = "pytz"
optional = false
python-versions = "*"
version = "2020.1"
[[package]]
category = "main"
description = "YAML parser and emitter for Python"
name = "pyyaml"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "5.3.1"
[[package]]
category = "main"
description = "Python HTTP for Humans."
name = "requests"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
version = "2.24.0"
[package.dependencies]
certifi = ">=2017.4.17"
chardet = ">=3.0.2,<4"
idna = ">=2.5,<3"
urllib3 = ">=1.21.1,<1.25.0 || >1.25.0,<1.25.1 || >1.25.1,<1.26"
[package.extras]
security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7)", "win-inet-pton"]
[[package]]
category = "main"
description = "Python 2 and 3 compatibility utilities"
name = "six"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
version = "1.15.0"
[[package]]
category = "main"
description = "HTTP library with thread-safe connection pooling, file post, and more."
name = "urllib3"
optional = false
python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4"
version = "1.25.10"
[package.extras]
brotli = ["brotlipy (>=0.6.0)"]
secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "pyOpenSSL (>=0.14)", "ipaddress"]
socks = ["PySocks (>=1.5.6,<1.5.7 || >1.5.7,<2.0)"]
[metadata]
content-hash = "35d07702bbbc789f7e6dc248539c816144f6b4a294d7f5e277ab4aed3c094584"
lock-version = "1.1"
python-versions = "^3.6"
[metadata.files]
blurhash = [
{file = "blurhash-1.1.4-py2.py3-none-any.whl", hash = "sha256:7611c1bc41383d2349b6129208587b5d61e8792ce953893cb49c38beeb400d1d"},
{file = "blurhash-1.1.4.tar.gz", hash = "sha256:da56b163e5a816e4ad07172f5639287698e09d7f3dc38d18d9726d9c1dbc4cee"},
]
certifi = [
{file = "certifi-2020.6.20-py2.py3-none-any.whl", hash = "sha256:8fc0819f1f30ba15bdb34cceffb9ef04d99f420f68eb75d901e9560b8749fc41"},
{file = "certifi-2020.6.20.tar.gz", hash = "sha256:5930595817496dd21bb8dc35dad090f1c2cd0adfaf21204bf6732ca5d8ee34d3"},
]
chardet = [
{file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"},
{file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"},
]
decorator = [
{file = "decorator-4.4.2-py2.py3-none-any.whl", hash = "sha256:41fa54c2a0cc4ba648be4fd43cff00aedf5b9465c9bf18d64325bc225f08f760"},
{file = "decorator-4.4.2.tar.gz", hash = "sha256:e3a62f0520172440ca0dcc823749319382e377f37f140a0b99ef45fecb84bfe7"},
]
idna = [
{file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"},
{file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"},
]
"mastodon.py" = [
{file = "Mastodon.py-1.5.1-py2.py3-none-any.whl", hash = "sha256:cc454cac0ed1ae4f105f7399ea53f5b31a1be5075d1882f47162d2e78a9e4064"},
{file = "Mastodon.py-1.5.1.tar.gz", hash = "sha256:2afddbad8b5d7326fcc8a8f8c62bfe956e34627f516b06c6694fc8c8fedc33ee"},
]
python-dateutil = [
{file = "python-dateutil-2.8.1.tar.gz", hash = "sha256:73ebfe9dbf22e832286dafa60473e4cd239f8592f699aa5adaf10050e6e1823c"},
{file = "python_dateutil-2.8.1-py2.py3-none-any.whl", hash = "sha256:75bb3f31ea686f1197762692a9ee6a7550b59fc6ca3a1f4b5d7e32fb98e2da2a"},
]
python-magic = [
{file = "python-magic-0.4.18.tar.gz", hash = "sha256:b757db2a5289ea3f1ced9e60f072965243ea43a2221430048fd8cacab17be0ce"},
{file = "python_magic-0.4.18-py2.py3-none-any.whl", hash = "sha256:356efa93c8899047d1eb7d3eb91e871ba2f5b1376edbaf4cc305e3c872207355"},
]
pytz = [
{file = "pytz-2020.1-py2.py3-none-any.whl", hash = "sha256:a494d53b6d39c3c6e44c3bec237336e14305e4f29bbf800b599253057fbb79ed"},
{file = "pytz-2020.1.tar.gz", hash = "sha256:c35965d010ce31b23eeb663ed3cc8c906275d6be1a34393a1d73a41febf4a048"},
]
pyyaml = [
{file = "PyYAML-5.3.1-cp27-cp27m-win32.whl", hash = "sha256:74809a57b329d6cc0fdccee6318f44b9b8649961fa73144a98735b0aaf029f1f"},
{file = "PyYAML-5.3.1-cp27-cp27m-win_amd64.whl", hash = "sha256:240097ff019d7c70a4922b6869d8a86407758333f02203e0fc6ff79c5dcede76"},
{file = "PyYAML-5.3.1-cp35-cp35m-win32.whl", hash = "sha256:4f4b913ca1a7319b33cfb1369e91e50354d6f07a135f3b901aca02aa95940bd2"},
{file = "PyYAML-5.3.1-cp35-cp35m-win_amd64.whl", hash = "sha256:cc8955cfbfc7a115fa81d85284ee61147059a753344bc51098f3ccd69b0d7e0c"},
{file = "PyYAML-5.3.1-cp36-cp36m-win32.whl", hash = "sha256:7739fc0fa8205b3ee8808aea45e968bc90082c10aef6ea95e855e10abf4a37b2"},
{file = "PyYAML-5.3.1-cp36-cp36m-win_amd64.whl", hash = "sha256:69f00dca373f240f842b2931fb2c7e14ddbacd1397d57157a9b005a6a9942648"},
{file = "PyYAML-5.3.1-cp37-cp37m-win32.whl", hash = "sha256:d13155f591e6fcc1ec3b30685d50bf0711574e2c0dfffd7644babf8b5102ca1a"},
{file = "PyYAML-5.3.1-cp37-cp37m-win_amd64.whl", hash = "sha256:73f099454b799e05e5ab51423c7bcf361c58d3206fa7b0d555426b1f4d9a3eaf"},
{file = "PyYAML-5.3.1-cp38-cp38-win32.whl", hash = "sha256:06a0d7ba600ce0b2d2fe2e78453a470b5a6e000a985dd4a4e54e436cc36b0e97"},
{file = "PyYAML-5.3.1-cp38-cp38-win_amd64.whl", hash = "sha256:95f71d2af0ff4227885f7a6605c37fd53d3a106fcab511b8860ecca9fcf400ee"},
{file = "PyYAML-5.3.1.tar.gz", hash = "sha256:b8eac752c5e14d3eca0e6dd9199cd627518cb5ec06add0de9d32baeee6fe645d"},
]
requests = [
{file = "requests-2.24.0-py2.py3-none-any.whl", hash = "sha256:fe75cc94a9443b9246fc7049224f75604b113c36acb93f87b80ed42c44cbb898"},
{file = "requests-2.24.0.tar.gz", hash = "sha256:b3559a131db72c33ee969480840fff4bb6dd111de7dd27c8ee1f820f4f00231b"},
]
six = [
{file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"},
{file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"},
]
urllib3 = [
{file = "urllib3-1.25.10-py2.py3-none-any.whl", hash = "sha256:e7983572181f5e1522d9c98453462384ee92a0be7fac5f1413a1e35c56cc0461"},
{file = "urllib3-1.25.10.tar.gz", hash = "sha256:91056c15fa70756691db97756772bb1eb9678fa585d9184f24534b100dc60f4a"},
]

34
pyproject.toml Normal file
View File

@ -0,0 +1,34 @@
[tool.poetry]
name = "ephemetoot"
version = "3.0.0-alpha.0"
description = "A command line tool to delete your old toots"
authors = ["Hugh Rundle <ephemetoot@hugh.run>"]
license = "GPL-3.0-or-later"
readme = "pypi-readme.md"
homepage = "https://ephemetoot.hugh.run"
repository = "https://github.com/hughrun/ephemetoot"
keywords = ["mastodon", "api", "microblogging"]
classifiers = [
"Environment :: Console",
"Operating System :: OS Independent",
"Topic :: Communications"
]
include = [
"LICENSE",
]
[tool.poetry.dependencies]
python = "^3.6"
requests = "^2.22.0"
"mastodon.py" = "^1.4.3"
pyyaml = "^5.0"
[tool.poetry.dev-dependencies]
# TODO - tests!
[tool.poetry.scripts]
ephemetoot = 'ephemetoot.console:main'
[build-system]
requires = ["poetry-core>=1.0.0a5"]
build-backend = "poetry.core.masonry.api"

View File

@ -1,20 +0,0 @@
from setuptools import setup, find_packages
setup(
name="ephemetoot",
version="2.6",
url="https://github.com/hughrun/ephemetoot",
license="GPL-3.0-or-later",
packages=find_packages(),
scripts=["bin/ephemetoot"],
install_requires=["Mastodon.py", "pyyaml", "requests"],
zip_safe=False,
author="Hugh Rundle",
author_email="hugh@hughrundle.net",
description="A command line tool for selectively deleting old toots from one or more Mastodon accounts.",
keywords="mastodon, mastodon api",
project_urls={
"Source Code": "https://github.com/hughrun/ephemetoot",
"Documentation": "https://github.com/hughrun/ephemetoot",
},
)