ghost
1 year ago
5 changed files with 309 additions and 1 deletions
@ -1,2 +1,129 @@
@@ -1,2 +1,129 @@
|
||||
# yggtracker-wanted-torrents-receiver |
||||
Crontab script that allows to receive wanted torrents from multiple YGGtracker nodes |
||||
|
||||
Crontab script that allows to receive wanted torrents from multiple [YGGtracker](https://github.com/YGGverse/YGGtracker) nodes |
||||
|
||||
#### Install |
||||
|
||||
Latest version of toolkit could be installed with single command: |
||||
|
||||
`git clone https://github.com/YGGverse/yggtracker-wanted-torrents-receiver.git` |
||||
|
||||
#### Config |
||||
|
||||
All configuration files placed at `/config` folder |
||||
|
||||
##### local.json |
||||
|
||||
``` |
||||
{ |
||||
"import": |
||||
{ |
||||
// Common rules for FTP connections |
||||
"ftp": |
||||
{ |
||||
// How many of seconds wait for each provider response |
||||
"timeout":5, |
||||
// Which of remote folders grab to |
||||
// array of target directories for each provider, eg. all, sensitive/no, locale/en, etc |
||||
"directories": |
||||
[ |
||||
"all" |
||||
] |
||||
}, |
||||
// Requirements filter before import something from providers |
||||
"require": |
||||
{ |
||||
// Require approved torrents import only (according to provide.approved option in remote.json for each provider) |
||||
"approved":true |
||||
}, |
||||
// Local storage settings for imported content |
||||
"storage": |
||||
{ |
||||
// Storage directory by default, feel free to change like `/home/qbittorrent-nox/import` |
||||
"directory":"storage", |
||||
|
||||
// Copy all torrents imported from providers folders to the storage/_common/{hash}.torrent |
||||
// This mode check files MD5 hash sum to prevent duplicates in single folder from different providers |
||||
// Useful when bittorrent client does not support support listening of multiple folders, recursive mode |
||||
"common":true |
||||
} |
||||
}, |
||||
"update": |
||||
{ |
||||
"config": |
||||
{ |
||||
// This option allows to auto-update remote.json file on the fly without updating codebase with git clone |
||||
"remote": |
||||
{ |
||||
// If disabled, local file will not be updated, but manually |
||||
"enabled": true, |
||||
|
||||
// Don't worry, just this repository |
||||
"repository":"https://raw.githubusercontent.com/YGGverse/yggtracker-wanted-torrents-receiver/main/config/remote.json", |
||||
|
||||
// How many seconds to wait before ask repository for remote.json updates (after last file write) |
||||
"cache":86400 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
``` |
||||
|
||||
##### remote.json |
||||
|
||||
The remote configuration contains available YGGtracker providers. |
||||
|
||||
File also could be auto-updated from this repository when owner enabled `update.config.remote.enabled` option in `local.json` |
||||
that makes registry actualization simpler for recipients and providers, as update details without `git pull`. |
||||
|
||||
``` |
||||
[ |
||||
{ |
||||
"description": |
||||
{ |
||||
"name":"YGGtracker", // Used as storage subfolder |
||||
"description":"YGGtracker official node", // Just provider description |
||||
"url":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]/yggtracker/" // Provider's website |
||||
}, |
||||
"ftp": |
||||
{ |
||||
"host":"201:23b4:991a:634d:8359:4521:5576:15b7", // Connection host |
||||
"port":21, // Connection port |
||||
"passive":true, // Recommended passive mode for better compatibility |
||||
"username":"anonymous", // YGGtracker instances usually provides public FTP access |
||||
"password":"anonymous", |
||||
"directory":"/yggtracker/torrents/wanted" // Directory where wanted torrent files placed |
||||
}, |
||||
"provide": |
||||
{ |
||||
"approved":true // Tells to receiver that node administrator check the torrents before send to API |
||||
} |
||||
} |
||||
], |
||||
... |
||||
``` |
||||
|
||||
#### Usage |
||||
|
||||
`php src/receiver.php` |
||||
|
||||
or add to crontab: |
||||
|
||||
`* * * * * /usr/bin/php src/receiver.php > /dev/null 2>&1` |
||||
|
||||
#### Bash, python? |
||||
|
||||
Feel free to contribute! |
||||
|
||||
#### Add new YGGtracker node |
||||
|
||||
Just send PR to nodes.json file |
||||
|
||||
#### Feedback |
||||
|
||||
Any questions and bug reports, please send to the [Issues](https://github.com/YGGverse/yggtracker-wanted-torrents-receiver/issues)! |
||||
|
||||
#### See also |
||||
|
||||
* [YGGtracker - BitTorrent Network for Yggdrasil](https://github.com/YGGverse/YGGtracker) |
||||
* [YGGtracker Search Plugin for qBittorrent](https://github.com/YGGverse/qbittorrent-yggtracker-search-plugin) |
@ -0,0 +1,34 @@
@@ -0,0 +1,34 @@
|
||||
{ |
||||
"import": |
||||
{ |
||||
"ftp": |
||||
{ |
||||
"timeout":5, |
||||
"directories": |
||||
[ |
||||
"all" |
||||
] |
||||
}, |
||||
"require": |
||||
{ |
||||
"approved":true |
||||
}, |
||||
"storage": |
||||
{ |
||||
"directory":"storage", |
||||
"common":true |
||||
} |
||||
}, |
||||
"update": |
||||
{ |
||||
"config": |
||||
{ |
||||
"remote": |
||||
{ |
||||
"enabled": true, |
||||
"repository":"https://raw.githubusercontent.com/YGGverse/yggtracker-wanted-torrents-receiver/main/config/remote.json", |
||||
"cache":86400 |
||||
} |
||||
} |
||||
} |
||||
} |
@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
|
||||
[ |
||||
{ |
||||
"description": |
||||
{ |
||||
"name":"YGGtracker", |
||||
"description":"YGGtracker official node", |
||||
"url":"http://[201:23b4:991a:634d:8359:4521:5576:15b7]/yggtracker/" |
||||
}, |
||||
"ftp": |
||||
{ |
||||
"host":"201:23b4:991a:634d:8359:4521:5576:15b7", |
||||
"port":21, |
||||
"passive":true, |
||||
"username":"anonymous", |
||||
"password":"anonymous", |
||||
"directory":"/yggtracker/torrents/wanted" |
||||
}, |
||||
"provide": |
||||
{ |
||||
"approved":true |
||||
} |
||||
} |
||||
] |
@ -0,0 +1,122 @@
@@ -0,0 +1,122 @@
|
||||
<?php |
||||
|
||||
// Init PHP |
||||
declare(strict_types=1); |
||||
|
||||
ini_set('display_errors', 1); |
||||
ini_set('display_startup_errors', 1); |
||||
error_reporting(E_ALL); |
||||
|
||||
// Prevent multi-thread execution |
||||
$semaphore = sem_get(crc32('yggtracker-wanted-torrents-receiver'), 1); |
||||
|
||||
if (false === sem_acquire($semaphore, true)) |
||||
{ |
||||
exit; |
||||
} |
||||
|
||||
// Init local config |
||||
$local = json_decode( |
||||
file_get_contents(__DIR__ . '/../config/local.json') |
||||
); |
||||
|
||||
// Init remote config |
||||
if ($local->update->config->remote->enabled) |
||||
{ |
||||
// Reset remote config cache |
||||
if ($local->update->config->remote->cache + (int) filectime(__DIR__ . '/../config/remote.json') < time()) |
||||
{ |
||||
// Cache results |
||||
if ($result = @file_get_contents($local->update->config->remote->repository)) |
||||
{ |
||||
file_put_contents( |
||||
__DIR__ . '/../config/remote.json', |
||||
$result |
||||
); |
||||
} |
||||
} |
||||
} |
||||
|
||||
// Sync remotes |
||||
foreach ( |
||||
json_decode( |
||||
file_get_contents(__DIR__ . '/../config/remote.json') |
||||
) as $remote) |
||||
{ |
||||
// Apply approved filters |
||||
if ($local->import->require->approved && !$remote->provide->approved) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Connect remote |
||||
if (!$connection = ftp_connect($remote->ftp->host, $remote->ftp->port, $local->import->ftp->timeout)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Login |
||||
if (!ftp_login($connection, $remote->ftp->username, $remote->ftp->password)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Apply passive mode if required |
||||
if (!ftp_pasv($connection, $remote->ftp->passive)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Navigate to wanted directory |
||||
if (!ftp_chdir($connection, $remote->ftp->directory)) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
// Scan directories |
||||
foreach ($local->import->ftp->directories as $directory) |
||||
{ |
||||
// Get torrents |
||||
foreach (ftp_nlist($connection, $directory) as $torrent) |
||||
{ |
||||
// Init provider directory |
||||
@mkdir( |
||||
$local->import->storage->directory . '/' . $remote->description->name . '/' . $directory, |
||||
0755, |
||||
true |
||||
); |
||||
|
||||
// Save torrents |
||||
ftp_get( |
||||
$connection, |
||||
$local->import->storage->directory . '/' . $remote->description->name . '/' . $torrent, |
||||
$torrent |
||||
); |
||||
|
||||
// Common storage mode enabled |
||||
if ($local->import->storage->common) |
||||
{ |
||||
// Init common folder |
||||
@mkdir( |
||||
$local->import->storage->directory . '/_common', |
||||
0755, |
||||
true |
||||
); |
||||
|
||||
// Prevent same file duplicates from different providers |
||||
$hash = md5_file( |
||||
$local->import->storage->directory . '/' . $remote->description->name . '/' . $torrent |
||||
); |
||||
|
||||
// Copy torrent file into the common directory if not exists yet |
||||
if (!file_exists($local->import->storage->directory . '/_common/' . $hash . '.torrent')) |
||||
{ |
||||
copy( |
||||
$local->import->storage->directory . '/' . $remote->description->name . '/' . $torrent, |
||||
$local->import->storage->directory . '/_common/' . $hash . '.torrent' |
||||
); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue