Skip to content
This repository was archived by the owner on Nov 1, 2019. It is now read-only.

Add getsettings, remove, removedata, and list API methods for sonarr support #7

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
FROM node:10.4.0-alpine

ADD putio_client /app

WORKDIR /app
RUN npm install

CMD node app.js
38 changes: 21 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,31 @@
# putio_client

This is a fork of OmgImAlexis' put.io utorrent proxy client node app. Wow that
was a mouthful...

I modified this to work with sonarr in particular, and have no idea if it'll
work with sickrage still (although I have no reason to believe it doesn't).
Also haven't tested with unraid... Honestly, Omg's repo was seemingly
abandoned, so I just made this work for myself.

I'd suggest you use Docker for this.

````
git clone https://github.com/OmgImAlexis/putio_client.git && cd putio_client
echo '{ "putio": { "token": "FAKE_TOKEN" }}' >> config.json
npm install
git clone https://github.com/cvockrodt/putio_client.git && cd putio_client
cp config.example.json config.json
docker build . -t putio_client
docker run -d -p 3000:3000 \
-v "$PWD":/app \
-w /app \
mhart/alpine-node node app.js
-v "config.json":/app/config.json \
putio_client
````

You'll need to open the config.json and replace `FAKE_TOKEN` with your Put.io API token you can get that [here](https://put.io/v2/oauth2/register).
Just fill in the details and copy the "Oauth Token" from the page after you submit the form.

If you're running this on UNRAID then SSH into the machine and run this instead of the Docker command.
Make sure the repo is cloned into `/mnt/user/appdata/putio_client/`.
````
/usr/local/emhttp/plugins/dynamix.docker.manager/scripts/docker run -d --name="putio" -w /app --net="bridge" -p 3000:3000/tcp -v "/mnt/user/appdata/putio_client/":"/app":rw mhart/alpine-node node app.js
````
You'll need to open the config.json and replace `MY_PUTIO_TOKEN` with your
Put.io API token you can get that [here](https://put.io/v2/oauth2/register).
Just fill in the details and copy the "Oauth Token" from the page after you
submit the form.

From here you should now be able to open Sickrage(/config/search/) and select uTorrent as the torrent downloader.
Make sure to use the IP for the machine running Docker. If you're using this on OSX run `docker-machine ip default` to get the Docker IP.
From here you should now be able to open Sonarr and select uTorrent as the
torrent downloader.
Make sure to use the IP for the machine running Docker. If you're using this
on OSX run `docker-machine ip default` to get the Docker IP.

![Sickrage](http://i.imgur.com/JXoeC5i.png)
2 changes: 1 addition & 1 deletion app.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,6 @@ app.use(methodOverride());

app.use('/', require('./app/routes/api'));

app.listen(config.get('web:port'), function() {
app.listen(config.get('web:port'), function () {
console.log('The server is running on port %s', config.get('web:port'));
});
179 changes: 167 additions & 12 deletions app/routes/api.js
100755 → 100644
Original file line number Diff line number Diff line change
@@ -1,23 +1,92 @@
const express = require('express');
const express = require('express');
const path = require('path');
const config = require('cz');
const readTorrent = require('read-torrent');
const PutIO = require('put.io-v2');
const multiparty = require('connect-multiparty');
const multipartMiddleware = multiparty();

config.load(path.normalize(__dirname + '/../../config.json'));
config.args();
config.store('disk');

module.exports = (function() {
function determine_status_value(status) {
if (status === 'DOWNLOADING') {
return 1; // Started
} else if (status === 'COMPLETING' || status === 'SAVING') {
return 130; // Loaded + Checking
} else if (status === 'COMPLETED') {
return 136; // Loaded + Checked
} else if (status === 'IN_QUEUE' || status === 'WAITING') {
return 64; // Queued
} else if (status === 'SEEDING' || status === 'PREPARING_SEED') {
return 136; // Loaded + Checked
} else {
return 16; // ERROR
}
}

function validate_eta(eta) {
if (eta === null) {
return 0;
}
return eta;
}

function validate_availability(availability, total) {
var MAX_INT32 = Math.pow(2, 31) - 1;
if (availability === null) {
if (total > MAX_INT32) {
return MAX_INT32;
}
return total;
} else if (availability > MAX_INT32) {
return MAX_INT32;
}
return availability;
}

function determine_remaining(size, downloaded, status) {
if (status === 'COMPLETED') {
return 0;
}
var remaining = size - downloaded;
var MAX_INT32 = Math.pow(2, 31) - 1;
if (remaining > MAX_INT32) {
return MAX_INT32
}
return remaining;
}

function validate_size(size) {
var MAX_INT32 = Math.pow(2, 31) - 1;
if (size > MAX_INT32) {
return MAX_INT32;
}
return size;
}

module.exports = (function () {
const app = express.Router();
const api = new PutIO(config.get('putio:token'));

app.get('/gui/token.html', function(req, res){
app.get('/gui/token.html', function (req, res) {
console.log('Authenticating...');
res.send('<div id="token" style="display:none;">' + config.get('apiKey') + '</div>');
});

app.get('*', function(req, res, next){
if(req.query.token === config.get('apiKey')){
app.get('*', function (req, res, next) {
if (req.query.token === config.get('apiKey')) {
next();
} else {
res.send({
error: 'Incorrect API key'
});
}
});

app.post('*', function (req, res, next) {
if (req.query.token === config.get('apiKey')) {
next();
} else {
res.send({
Expand All @@ -26,20 +95,106 @@ module.exports = (function() {
}
});

app.get('/gui/', function(req, res){
if(req.query.action === 'add-url'){
readTorrent(req.query.s, function(err, torrent) {
if(err){
app.post('/gui/', multipartMiddleware, function (req, res) {
if (req.query.action === 'add-file') {
readTorrent(req.files.torrent_file.path, function (err, torrent) {
if (err) {
console.log(err);
return res.status(500).end();
}
api.transfers.add(torrent.infoHash);
console.log('Adding ' + torrent.name);
api.transfers.add(torrent.infoHash, parent_id = config.get('putio:id'));
console.log('Added ' + torrent.name);
});
return res.end();
} else {
console.log('invalid endpoint: ' + req.query.action);
console.log('query parameters: ' + req.query);
return res.status(400).end();
}
});
app.get('/gui/', function (req, res) {
if (req.query.action === 'add-url') {
readTorrent(req.query.s, function (err, torrent) {
if (err) {
console.log(err);
return res.status(500).end();
}
console.log('Adding ' + torrent.name);
api.transfers.add(torrent.infoHash, parent_id = config.get('putio:id'));
console.log('Added ' + torrent.name);
});
return res.send({});
} else if (req.query.action === 'getsettings') {
console.log('Getting settings...');
return res.send({
"build": 44632, "settings": [
["install_modification_time", 0, "0", { "access": "Y" }]
]
});
} else if (req.query.action === 'remove') {
api.transfers.cancel(req.query.hash);
console.log('Canceled torrent ' + req.query.hash);
return res.status(200).end();
} else if (req.query.action === 'removedata') {
api.transfers.cancel(req.query.hash);
console.log('Canceled torrent ' + req.query.hash);
return res.status(200).end();
} else if (req.query.list === '1') {
api.transfers.list(function (data) {
ret_data = {
"build": 44994
, "torrents": []
, "label": [[config.get("putio:folder"), config.get('putio:id')]]
, "torrentc": "994925276"
, "rssfeeds": []
, "rssfilters": []
}
for (var transfer_index in data.transfers) {
var transfer = data.transfers[transfer_index];
var detail = [
transfer.id,
determine_status_value(transfer.status),
transfer.name,
validate_size(transfer.size),
transfer.percent_done * 10,
transfer.downloaded || 0,
transfer.uploaded || 0,
Math.round(transfer.current_ratio * 100),
transfer.up_speed || 0,
transfer.down_speed || 0,
validate_eta(transfer.estimated_time),
config.get("putio:folder"),
transfer.peers_connected || 0,
transfer.peers_getting_from_us + transfer.peers_sending_to_us,
transfer.peers_connected || 0,
transfer.peers_sending_to_us || 0,
validate_availability(transfer.availability, transfer.size),
transfer.id,
determine_remaining(transfer.size, transfer.downloaded, transfer.status),
"",
"",
transfer.status,
"1",
1550730519,
0,
"",
config.get('putio:download_dir'),
0,
"4767C3CE"
];
ret_data['torrents'].push(detail);
}
return res.json(ret_data);
});
} else {
console.log('invalid endpoint: ' + req.query.action);
console.log('query parameters: ' + req.query);
return res.send('{"status":"unknown"}');
}
return res.sendStatus(200);
});

app.get('*', function(req, res){
app.get('*', function (req, res) {
res.send({
error: 'Unknown Route'
});
Expand Down
12 changes: 12 additions & 0 deletions config.example.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
{
"web": {
"port": 3000
},
"apiKey": "MY_API_KEY",
"putio": {
"token": "MY_PUTIO_TOKEN",
"folder": "shows",
"download_dir": "/downloads/shows/",
"id": 123456789
}
}
14 changes: 8 additions & 6 deletions package.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@
"author": "X O <xo@wvvw.me> (https://wvvw.me)",
"license": "MIT",
"dependencies": {
"body-parser": "^1.15.0",
"cookie-parser": "^1.4.1",
"body-parser": "^1.19.0",
"cookie-parser": "^1.4.4",
"connect-multiparty": "^2.2.0",
"raw-body": "^2.4.1",
"crypto": "0.0.3",
"cz": "^1.3.1",
"express": "^4.13.4",
"cz": "1.5.0",
"express": "^4.17.1",
"method-override": "^2.3.5",
"put.io-v2": "0.0.2",
"read-torrent": "^1.3.0"
"read-torrent": "^1.3.1"
}
}
}