diff --git a/README.md b/README.md index 24e9fcf..5c3ace7 100644 --- a/README.md +++ b/README.md @@ -8,14 +8,14 @@ [tippin_svg]: https://img.shields.io/badge/donate-BuyMeACoffee-ffdd00?logo=buymeacoffee&style=flat [tippin_url]: https://www.buymeacoffee.com/bemble -> Torrent -> Real Debrid -> Downloader +> Torrent & magnet -> Debrider -> Downloader ## Running ### Docker ```bash -docker run -v "/local/data:/app/data" -p8781:8781 ghcr.io/bemble/holerr:latest +docker run -v "/local/data:/app/data" -p8765:8765 ghcr.io/bemble/holerr:latest ``` ### Docker compose @@ -26,46 +26,66 @@ holerr: container_name: holerr restart: unless-stopped ports: - - ${PORT_HOLERR}:8781 + - ${PORT_HOLERR}:8765 volumes: - "${PWD}/holerr/data:/app/data" - /usr/share/zoneinfo:/usr/share/zoneinfo:ro - /etc/localtime:/etc/localtime:ro ``` +## Supported debriders & downloaders + +**Debriders:** + +- Real-Debrid + +**Downloaders:** + +- Synology Download Station + +## Migrate from v1 + +The main file to migrate is the configuration, but holerr will migrate your configuration file from v1 to v2 after its first starts. +:warning: Also note that default port has changed, it's now `8765` + ## Configuration -Create a `config.json` file in the data directory. - -```typescript -type Configuration = { - // Set holerr in debug (default: false) - debug: boolean; - // If necessary, the base_path to fetch the front [optional, default: ""] example: "/holerr" - base_path: string; - // Debriders, providers that will download the torrent - debriders: { - // Real-Debrid - real_debrid: { - // Real-Debrid private API token: https://real-debrid.com/apitoken - api_key: string; - }; - }; - // Downloaders, providers that will download the files downloaded by the debrider - downloaders: { - // Synology - synology_download_station: { - // Your Synology endpoint (example: "http://192.168.1.1:5000") - endpoint: string; - // DSM username (this user must not have 2FA) - username: string; - // DSM password - password: string; - }; - }; - // Presets, see in Data structure - presets: Preset[]; -}; +Create a `config.yaml` file in the data directory. + +```yaml +# Select the logger to set in debug +debug: # optional, string[] + - holerr.* +# If necessary, project base path (root path), when run behind a proxy fo example +base_path: /holerr # optional, string +# Debrider configuration +debrider: + real_debrid: + # Real-Debrid private API token: https://real-debrid.com/apitoken + api_key: your key # string +# Downloader configuration +downloader: + # Synology + synology_download_station: + # Your Synology endpoint (example: "http://192.168.1.1:5000") + endpoint: synology endpoint # string + # DSM username (this user must not have 2FA) + username: dsm user # string + # DSM password + password: use password # string +# Presets list +presets: + - name: Downloads # string + # Directory that holerr will watch + watch_dir: holes/downloads # string + # Downloader output directory + output_dir: Downloads # string + # Whether the file should be downloaded in a subdoctory or not + create_sub_dir: false # optional, boolean + # Restrict the extensions to download, default no-restriction + file_extensions: # optional, string[] + # Restrict the size of the files to download, default no restriction + min_file_size: # human readbale string, example: 3.0B, 12KB, 432.2MB, 4.5GB, 1TB ``` ### Synology specifics @@ -90,276 +110,33 @@ Before being able to start a download in Download Station you **must**: - Add a configuration file - :warning: while developing, you should not use a `base_path` -### Running the front and the server - -Open VS Code, start the dev container. There's 2 tasks: - -- Run front -- Run server - -**Note:** if you set an API key in your configuration, you must set it when running front: `REACT_APP_API_KEY= npm run start` - -## API documentation - -### Websocket - -A websocket connection will push events when concerned. +### Prepare environment -- **Endpoint:** `/api/ws` -- **Protocol:** `ws` +#### Front -Example: `ws://192.168.1.1:8781/api/ws` - -#### Messages +```bash +cd front +npm i +``` -Messages are JSON objects stringified, with the following shape: +#### Server -```typescript -type WebsocketInputMessage = { - // Action to perform - action: string; - // Payload, if concerned - payload?: any; -}; -``` +Create a virtual environment: -##### Actions - -- **`downloads/new`:** new download found, payload is the new download - ```typescript - type WebsocketDownloadsNewInputMessage = { - action: "downloads/new"; - payload: Download; - }; - ``` -- **`downloads/update`:** download has been updated, payload is the updated download - ```typescript - type WebsocketDownloadsUpdateInputMessage = { - action: "downloads/update"; - payload: Download; - }; - ``` -- **`downloads/delete`:** download has been deleted, payload is the deleted download (also send - on `/api/downloads/clean_up`) - ```typescript - type WebsocketDownloadsUpdateInputMessage = { - action: "downloads/delete"; - payload: Download; - }; - ``` - -### HTTP - -#### Configuration - -- **List:** `[GET] /api/configuration` get the configuration (passwords and API keys are obfuscated) -- **Update:** `[PATCH] /api/configuration` update configuration parts - -#### Status - -- **Get:** `[GET] /api/status` get the status and other information - -#### Constants - -- **List:** `[GET] /api/constants` get the list of used constants - -#### Presets - -- **List:** `[GET] /api/presets` get the list of presets -- **Add:** `[POST] /api/presets` add the given preset, replies with the preset added -- **Update:** `[PATCH] /api/presets/:name` update the preset given by its name, replies with the updated preset -- **Delete:** `[DELETE] /api/presets/:name` delete the preset given by its name - -#### Downloads - -- **List:** `[GET] /api/downloads` get the list of downloads -- **Add:** `[POST] /api/downloads` add a new torrent to holerr - - Data are sent using FormData. - - _Body structure:_ - - ```typescript - type PostTorrentBody = { - // Preset name - preset: string; - // Torrent file - torrent_file: File; - }; - ``` - - _Example:_ - - ```javascript - const body = new FormData(); - body.append("preset", "Film"); - body.append("torrent_file", fileInput.files[0], "myFile.torrent"); - - fetch("/api/downloads", { method: "POST", body }) - .then((response) => response.text()) - .then((result) => console.log(result)) - .catch((error) => console.log("error", error)); - ``` - -- **Delete:** `[DELETE] /api/downloads/:id` abort the current download (torrent on debrider and download task on - downloader will be deleted) and delete download from database -- **Clean:** `[POST] /api/downloads/clean_up` remove downloads sent to downloader or in error from database - -## Data structure - -### Configuration - -```typescript -type Configuration = { - // API key used to communicate with the server [default: ""] - api_key: string; - // Set holerr in debug (default: false) - debug: boolean; - // If necessary, the base_path to fetch the front [optional, default: "/"] example: "/holerr" - base_path: string; - // Debriders, providers that will download the torrent - debriders?: Debriders; - // Downloaders, providers that will download the files downloaded by the debrider - downloaders?: Downloaders; - // Download presets - presets?: Preset[]; -}; - -type Debriders = { - // Real-Debrid - real_debrid: RealDebrid; -}; - -type RealDebrid = { - // Real-Debrid private API token: https://real-debrid.com/apitoken - api_key: string; -}; - -type Downloaders = { - // Synology - synology_download_station: SynologyDownloadStation; -}; - -type SynologyDownloadStation = { - // Your Synology endpoint (example: "http://192.168.1.1:5000") - endpoint: string; - // DSM username (this user must not have 2FA) - username: string; - // DSM password - password: string; -}; -``` +- In VSCode, open command palette (`Shift+CMD+P`) > `Python: Create Environment...` +- Select `Venv` +- Select `server` workspace +- Check `requirements.txt` -### Status +### Running the front and the server -```typescript -type Status = { - // Is connected to debrider - debrider_connected: bool; - // Is connected to downloader - downloader_connected: bool; -}; -``` +Open VS Code, start the dev container. There's 2 tasks: -### Constants +- Run front +- Run server -```typescript -type Constants = { - // Global download task status - download_status: Record; - // Torrent status from debrider - torrent_status: Record; -}; -``` +Database migrations will be run before the server starts. -### Presets - -```typescript -type Preset = { - // Human readable name - name: string; - // Where holerr will watch torrents, relative to data dir - watch_dir: string; - // Downloader output directory [optional] (in Synology, must start with a shared folder) - output_dir: string; - // If true, create a sub directory, into output_dir, per download task and download files in it [optional, default: false] - create_sub_dir: bool; - // Accepted file extensions [optional] - file_extensions: string[] | null; - // Minimum file size to download [optional, default: 0] - min_file_size: number; - // Whether downloader should download in subdir - create_sub_dir?: boolean; -}; -``` +## API documentation -### Downloads - -```typescript -type Download = { - // Internal download id - id: string; - // Download title (computed from torrent file name) - title: string; - // Name of the preset used - preset: string; - // Global downlaod task status - status: DownloadStatus; - // Human readable status - status_details: string; - // Debrider torrent info (might have more data, according to the debrider used) - torrent_info: TorrentInfo | null; - // Downloader downloads info - download_info: DownloadInfo | null; - // Download task creation date - created_at: string; - // Download task last update date - updated_at: string; -}; - -type TorrentInfo = { - // Debrider torrent ID - id: string; - // Torrent filename - filename: string; - // Size of selected files only - bytes: int; - // Download progress [0...100] - progress: int; - // Current status of the torrent - status: string; - // List of file available in the torrent - files: DownloadFile[]; - // When torrent is downloaded, list of files - links: string[] | null; -}; - -type DownloadFile = { - // Debrider file ID - id: int; - // Path to the file inside the torrent, starting with "/" - path: string; - // Size of the file - bytes: int; - // Whether the file is selected for download or not [0,1] - selected: int; -}; - -type DownloadInfo = { - // Download progress [0...100] - progress: number; - // Total files size - bytes: number; - // Key are links - tasks: Record; -}; - -type DownloadInfoTask = { - // Downloader ID - id: string; - // Tasks status - status: number; - // Downloaded - bytes_downloaded: number; -}; -``` +Simply navigate to http://localhost:8765/docs or http://localhost:8765/redoc.