Skip to content

Commit

Permalink
Merge pull request #17 from jeremiah-k/crossplatform-refactor
Browse files Browse the repository at this point in the history
Crossplatform refactor
  • Loading branch information
jeremiah-k authored Nov 19, 2024
2 parents b5d2930 + 8eb6e24 commit e7923d4
Show file tree
Hide file tree
Showing 9 changed files with 582 additions and 150 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@
topic.txt
fetchtastic.log
.aider*
app/__pycache__/
fetchtastic.egg-info/
2 changes: 1 addition & 1 deletion .trunk/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@
plugins
user_trunk.yaml
user.yaml
tmp
tmp
110 changes: 98 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,90 @@
# Fetchtastic Termux Setup
# Fetchtastic

Fetchtastic is a utility for downloading and managing the latest Meshtastic Android app and Firmware releases on your phone using Termux. It also provides optional notifications via NTFY.
Fetchtastic is a utility for downloading and managing the latest Meshtastic Android app and Firmware releases. It also provides optional notifications via NTFY.

## Prerequisites
## Table of Contents

### Install Termux and Add-ons
- [Installation](#installation)
- [Termux Installation (Android)](#termux-installation-android)
- [Windows/Mac/Linux Installation](#windowsmaclinux-installation)
- [Usage](#usage)
- [Setup Process](#setup-process)
- [Command List](#command-list)
- [Files and Directories](#files-and-directories)
- [Scheduling with Cron](#scheduling-with-cron)
- [Notifications via NTFY](#notifications-via-ntfy)
- [Contributing](#contributing)

## Installation

### Termux Installation (Android)

Fetchtastic can be installed on your Android device using Termux.

#### Prerequisites

1. **Install Termux**: Download and install [Termux](https://f-droid.org/en/packages/com.termux/) from F-Droid.
2. **Install Termux Boot**: Download and install [Termux Boot](https://f-droid.org/en/packages/com.termux.boot/) from F-Droid.
3. **Install Termux API**: Download and install [Termux API](https://f-droid.org/en/packages/com.termux.api/) from F-Droid.
4. _(Optional)_ **Install ntfy**: Download and install [ntfy](https://f-droid.org/en/packages/io.heckel.ntfy/) from F-Droid.

## Installation
#### Install Dependencies

### Step 1: Install Dependencies
Open Termux and run:

```bash
pkg install python python-pip openssl -y
```

### Step 2: Install Fetchtastic
#### Install Fetchtastic

```bash
pip install fetchtastic
```

### Windows/Mac/Linux Installation

Fetchtastic can also be installed on Windows, macOS, or Linux systems.

#### Install with pipx (Recommended)

It's recommended to use `pipx` to install Fetchtastic in an isolated environment.

1. **Install pipx**:

- **On macOS/Linux**:

```bash
python3 -m pip install --user pipx
python3 -m pipx ensurepath
```

- **On Windows**:

```powershell
python -m pip install --user pipx
python -m pipx ensurepath
```

Restart your terminal or command prompt after installing pipx.

2. **Install Fetchtastic with pipx**:

```bash
pipx install fetchtastic
```

#### Install with pip

Alternatively, you can install Fetchtastic using pip:

```bash
pip install fetchtastic
```

## Usage

### Run the Setup Process
### Setup Process

Run the setup command and follow the prompts to configure Fetchtastic:

Expand All @@ -39,18 +96,22 @@ During setup, you will be able to:

- Choose whether to download APKs, firmware, or both.
- Select specific assets to download.
- Set the number of versions to keep.
- Set the number of versions to keep (default is 2 on Termux, 3 on desktop platforms).
- Configure automatic extraction of firmware files. (Optional)
- Set up notifications via NTFY. (Optional)
- Choose to receive notifications only when new files are downloaded. (Optional)
- Add a cron job to run Fetchtastic regularly. (Optional)
- On Termux, Fetchtastic can be scheduled to run daily at 3 AM using Termux's cron.
- On Windows/Mac/Linux, Fetchtastic can be scheduled using the system's cron scheduler.

### Command list
### Command List

- **setup**: Run the setup process.
- **download**: Download firmware and APKs.
- **topic**: Display the current NTFY topic.
- **clean**: Remove configuration, downloads, and cron jobs.
- **--help**: Show help and usage instructions.
- **version**: Display Fetchtastic version.
- **help**: Show help and usage instructions.

### Files and Directories

Expand All @@ -67,6 +128,28 @@ You can manually edit the configuration file to change the settings.

During setup, you have the option to add a cron job that runs Fetchtastic daily at 3 AM.

#### Termux

The setup process will configure the cron job using Termux's cron implementation.
To modify the cron job, you can run:
```bash
crontab -e
```
#### Windows
You can schedule Fetchtastic to run automatically using the Task Scheduler.
1. Open **Task Scheduler**.
2. Create a new **Basic Task**.
3. Set the action to **Start a program** and enter `fetchtastic download`.
#### macOS/Linux
The setup process will configure the cron job using the system's cron scheduler.

To modify the cron job, you can run:

```bash
Expand All @@ -77,6 +160,9 @@ crontab -e

If you choose to set up notifications, Fetchtastic will send updates to your specified NTFY topic.

### Contributing
- You can subscribe to the topic using the ntfy app or by visiting the topic URL in a browser.
- You can choose to receive notifications **only when new files are downloaded**.

## Contributing

Contributions are welcome! Feel free to open issues or submit pull requests.
156 changes: 128 additions & 28 deletions app/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import os
import shutil
import subprocess
import platform
import sys

from . import downloader, setup_config

Expand All @@ -28,6 +30,12 @@ def main():
"clean", help="Remove Fetchtastic configuration, downloads, and cron jobs"
)

# Command to display version
subparsers.add_parser("version", help="Display Fetchtastic version")

# Command to display help
subparsers.add_parser("help", help="Display help information")

args = parser.parse_args()

if args.command == "setup":
Expand All @@ -50,39 +58,106 @@ def main():
full_url = f"{ntfy_server}/{ntfy_topic}"
print(f"Current NTFY topic URL: {full_url}")
print(f"Topic name: {ntfy_topic}")

if setup_config.is_termux():
copy_prompt_text = "Do you want to copy the topic name to the clipboard? [y/n] (default: yes): "
text_to_copy = ntfy_topic
else:
copy_prompt_text = "Do you want to copy the topic URL to the clipboard? [y/n] (default: yes): "
text_to_copy = full_url

copy_to_clipboard = (
input(
"Do you want to copy the topic name to the clipboard? [y/n] (default: yes): "
)
input(copy_prompt_text)
.strip()
.lower()
or "y"
)
if copy_to_clipboard == "y":
copy_to_clipboard_termux(ntfy_topic)
print("Topic name copied to clipboard.")
success = copy_to_clipboard_func(text_to_copy)
if success:
if setup_config.is_termux():
print("Topic name copied to clipboard.")
else:
print("Topic URL copied to clipboard.")
else:
print("Failed to copy to clipboard.")
else:
print("You can copy the topic name from above.")
print("You can copy the topic information from above.")
else:
print(
"Notifications are not set up. Run 'fetchtastic setup' to configure notifications."
)
elif args.command == "clean":
# Run the clean process
run_clean()
elif args.command == "version":
print(f"Fetchtastic version {get_fetchtastic_version()}")
elif args.command == "help":
parser.print_help()
elif args.command is None:
# No command provided
print("No command provided.")
print("For help and available commands, run 'fetchtastic --help'.")
parser.print_help()
else:
parser.print_help()


def copy_to_clipboard_termux(text):
try:
subprocess.run(["termux-clipboard-set"], input=text.encode("utf-8"), check=True)
except Exception as e:
print(f"An error occurred while copying to clipboard: {e}")
def copy_to_clipboard_func(text):
if setup_config.is_termux():
# Termux environment
try:
subprocess.run(["termux-clipboard-set"], input=text.encode("utf-8"), check=True)
return True
except Exception as e:
print(f"An error occurred while copying to clipboard: {e}")
return False
else:
# Other platforms
system = platform.system()
try:
if system == "Darwin":
# macOS
subprocess.run("pbcopy", text=True, input=text, check=True)
return True
elif system == "Linux":
# Linux
if shutil.which("xclip"):
subprocess.run(
["xclip", "-selection", "clipboard"],
input=text.encode("utf-8"),
check=True,
)
return True
elif shutil.which("xsel"):
subprocess.run(
["xsel", "--clipboard", "--input"],
input=text.encode("utf-8"),
check=True,
)
return True
else:
print(
"xclip or xsel not found. Install xclip or xsel to use clipboard functionality."
)
return False
elif system == "Windows":
# Windows
try:
import win32clipboard

win32clipboard.OpenClipboard()
win32clipboard.EmptyClipboard()
win32clipboard.SetClipboardText(text)
win32clipboard.CloseClipboard()
return True
except Exception as e:
print(f"An error occurred while copying to clipboard: {e}")
return False
else:
print("Clipboard functionality is not supported on this platform.")
return False
except Exception as e:
print(f"An error occurred while copying to clipboard: {e}")
return False


def run_clean():
Expand All @@ -103,11 +178,21 @@ def run_clean():
os.remove(config_file)
print(f"Removed configuration file: {config_file}")

# Remove download directory
# Remove contents of download directory
download_dir = setup_config.DEFAULT_CONFIG_DIR
if os.path.exists(download_dir):
shutil.rmtree(download_dir)
print(f"Removed download directory: {download_dir}")
for item in os.listdir(download_dir):
item_path = os.path.join(download_dir, item)
try:
if os.path.isfile(item_path) or os.path.islink(item_path):
os.remove(item_path)
print(f"Removed file: {item_path}")
elif os.path.isdir(item_path):
shutil.rmtree(item_path)
print(f"Removed directory: {item_path}")
except Exception as e:
print(f"Failed to delete {item_path}. Reason: {e}")
print(f"Cleaned contents of download directory: {download_dir}")

# Remove cron job entries
try:
Expand All @@ -116,15 +201,21 @@ def run_clean():
["crontab", "-l"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True
)
if result.returncode == 0:
existing_cron = result.stdout
existing_cron = result.stdout.strip()
# Remove existing fetchtastic cron jobs
new_cron = "\n".join(
[
line
for line in existing_cron.split("\n")
if "fetchtastic download" not in line
]
)
cron_lines = [
line for line in existing_cron.splitlines() if line.strip()
]
cron_lines = [
line
for line in cron_lines
if "# fetchtastic" not in line and "fetchtastic download" not in line
]
# Join cron lines
new_cron = "\n".join(cron_lines)
# Ensure new_cron ends with a newline
if not new_cron.endswith("\n"):
new_cron += "\n"
# Update crontab
process = subprocess.Popen(
["crontab", "-"], stdin=subprocess.PIPE, text=True
Expand All @@ -140,10 +231,19 @@ def run_clean():
os.remove(boot_script)
print(f"Removed boot script: {boot_script}")

print("Fetchtastic has been cleaned from your system.")
print(
"If you installed Fetchtastic via pip and wish to uninstall it, run 'pip uninstall fetchtastic'."
)
print("The downloaded files and Fetchtastic configuration have been removed from your system.")


def get_fetchtastic_version():
try:
from importlib.metadata import version
except ImportError:
# For Python < 3.8
from importlib_metadata import version
try:
return version("fetchtastic")
except Exception:
return "unknown"


if __name__ == "__main__":
Expand Down
Loading

0 comments on commit e7923d4

Please sign in to comment.