simple uploader script for deluge, assign this script to be called on torrent complete and it will walk a directory and upload it to your google drive
install dependencies:
npm install googleapis async winston lodash mime twilio| { | |
| "TWILIO_SID": "", | |
| "TWILIO_TOKEN": "", | |
| "NOTIFY_FROM_NUMBER": "", | |
| "NOTIFY_TO_NUMBER": "", | |
| "GOOGLE_API_CLIENT_ID": "", | |
| "GOOGLE_API_CLIENT_SECRET": "", | |
| "GOOGLE_API_REFRESH_TOKEN": "", | |
| "upload_concurrency": 5, | |
| "root_folder": "deluge-completed" | |
| } |
| #!/media/sdr1/home/exko/.nvm/versions/node/v4.0.0/bin/node | |
| 'use strict' | |
| var config = require('./config') | |
| const FOLDER = 'application/vnd.google-apps.folder' | |
| const DEST_FOLDER = config.root_folder | |
| var fs = require('fs') | |
| var twilio = require('twilio')(config.TWILIO_SID, config.TWILIO_TOKEN) | |
| var google = require('googleapis') | |
| var async = require('async') | |
| var winston = require('winston') | |
| var _ = require('lodash') | |
| var mime = require('mime') | |
| var tid = process.argv[2] | |
| var tname = process.argv[3] | |
| var tpath = process.argv[4] | |
| if (tpath.charAt(tpath.length - 1) !== '/') { | |
| tpath += '/' | |
| } | |
| var logger = new (winston.Logger)({ | |
| transports: [ | |
| new (winston.transports.Console)(), | |
| new (winston.transports.File)({ filename: './log' }) | |
| ] | |
| }) | |
| logger.info('starting upload!') | |
| logger.info(`${tid} / ${tname} / ${tpath}`) | |
| var auth = new google.auth.OAuth2( | |
| config.GOOGLE_API_CLIENT_ID, | |
| config.GOOGLE_API_CLIENT_SECRET | |
| ) | |
| auth.credentials.refresh_token = config.GOOGLE_API_REFRESH_TOKEN | |
| auth.refreshAccessToken(function (err, tokens) { | |
| if (err) { | |
| logger.error(`error retrieving access tokens ${err.error} - '${err.error_description}'`) | |
| process.exit(1) | |
| return | |
| } | |
| var rootFolder | |
| var drive = google.drive({ | |
| version: 'v2', | |
| auth: auth | |
| }) | |
| var uploadQueue = async.queue(function (task, done) { | |
| var filename = getLastPart(task.path) | |
| logger.info('start uploading: %s', filename) | |
| var insertOp = { | |
| resource: { | |
| title: filename, | |
| mimeType: task.type, | |
| parents: [ | |
| { id: task.in } | |
| ] | |
| } | |
| } | |
| if (task.type !== FOLDER) { | |
| insertOp.media = { | |
| mimeType: task.type, | |
| body: fs.createReadStream(task.path) | |
| } | |
| } | |
| drive.files.insert(insertOp, function (err, uploadedFile) { | |
| logger.info('finished uploading: %s', filename) | |
| done(err, uploadedFile) | |
| }) | |
| }, config.upload_concurrency) | |
| function upload (folder, _in, depth, done) { | |
| var uploadedFolder | |
| if (depth > 25) { | |
| logger.warning('maximum depth reached!!!') | |
| done(null) | |
| } | |
| if (fs.statSync(folder).isFile()) { | |
| logger.info('torrent is just a single file: %s', folder) | |
| uploadQueue.push({ | |
| path: folder, | |
| type: mime.lookup(folder), | |
| in: _in | |
| }, done) | |
| } else { | |
| logger.info('uploading folder: %s', folder) | |
| async.waterfall([ | |
| function (cb) { | |
| uploadQueue.push({ | |
| path: folder, | |
| type: FOLDER, | |
| in: _in | |
| }, cb) | |
| }, | |
| function (newFolder, cb) { | |
| uploadedFolder = newFolder | |
| fs.readdir(folder, cb) | |
| }, | |
| function (fileList, cb) { | |
| var folders = _.filter(fileList, function (f) { | |
| return fs.statSync(`${folder}/${f}`).isDirectory() | |
| }) | |
| var files = _.filter(fileList, function (f) { | |
| return fs.statSync(`${folder}/${f}`).isFile() | |
| }) | |
| async.map(files, function (file, cb) { | |
| uploadQueue.push({ | |
| path: `${folder}/${file}`, | |
| type: mime.lookup(file), | |
| in: uploadedFolder.id | |
| }, cb) | |
| }, function (err) { | |
| if (err) return cb(err) | |
| async.each(folders, function (subFolder, cb) { | |
| upload(`${folder}/${subFolder}`, uploadedFolder.id, (depth + 1), cb) | |
| }, cb) | |
| }) | |
| } | |
| ], done) | |
| } | |
| } | |
| async.series([ | |
| function findOrCreateFolder (cb) { | |
| // find folder to put stuff in | |
| logger.info('finding a folder to put stuff in') | |
| /* | |
| +----------------------+ | |
| | find folder with | | |
| | "title=DEST_FOLDER" | | |
| +----------------------+ | |
| | | |
| +-(found one)--+-(didn't find one)-+ | |
| | | | |
| v v | |
| +------------------+ +------------------+ | |
| | is it in the | |create new folder | | |
| | trash? |---+ | in root |--+ | |
| +------------------+ | +------------------+ | | |
| | | | | |
| +--(yes)-+ +------(no)--------+ | | |
| | | | | |
| v v | | |
| +------------------+ +------------------+ | | |
| | remove it from | |return destination| | | |
| | trash |-->| folder |<----+ | |
| +------------------+ +------------------+ | |
| */ | |
| drive.children.list({ | |
| folderId: 'root', | |
| q: `title="${DEST_FOLDER}"` | |
| }, function (err, childList) { | |
| if (err) return cb(err) | |
| if (childList.items.length > 0) { | |
| var rootFolderId = childList.items[0].id | |
| drive.files.get({ | |
| fileId: rootFolderId, | |
| updateViewedDate: true | |
| }, function (err, _root_folder) { | |
| if (err) { | |
| return cb(err) | |
| } | |
| rootFolder = _root_folder | |
| if (rootFolder.labels.trashed) { | |
| logger.info(`target folder was in the trash! untrashing...`) | |
| drive.files.untrash({ | |
| fileId: rootFolder.id | |
| }, function (err) { | |
| if (err) { | |
| return cb(err) | |
| } | |
| logger.info('cool! target folder out of the trash. moving on...') | |
| cb(null) | |
| }) | |
| return | |
| } | |
| logger.info(`found one! ${rootFolder.id}`) | |
| cb(null) | |
| }) | |
| return | |
| } | |
| logger.info('did not find one, creating one now...') | |
| drive.files.insert({ | |
| resource: { | |
| title: DEST_FOLDER, | |
| mimeType: FOLDER | |
| } | |
| }, function (err, _new_folder) { | |
| if (err) return cb(err) | |
| rootFolder = _new_folder | |
| cb(null) | |
| }) | |
| }) | |
| }, | |
| function uploadStuff (cb) { | |
| upload(`${tpath}${tname}`, rootFolder.id, 0, cb) | |
| } | |
| ], function (err) { | |
| if (err) { | |
| logger.error('ERROR') | |
| logger.error(err) | |
| return | |
| } | |
| twilio.sendMessage({ | |
| to: config.NOTIFY_TO_NUMBER, | |
| from: config.NOTIFY_FROM_NUMBER, | |
| body: `so let it be said, so let it be done! '${tname}' finished downloading!` | |
| }, function (err) { | |
| if (err) { | |
| logger.error('ERROR SENDING NOTIFICATION', err) | |
| return | |
| } | |
| logger.info('sent notification') | |
| }) | |
| logger.info('successfully finished uploading shit') | |
| }) | |
| }) | |
| function getLastPart (path) { | |
| if (path.charAt(path.length - 1) === '/') { | |
| path = path.slice(0, -1) | |
| } | |
| return path.split('/').pop() | |
| } |