Skip to content
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
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,18 @@

> This is the backend API for the Kapture server

# Getting started

# Quickstart with Docker

To get the entire system up and running, the quickest way is to use the docker build:

```bash
docker-compose up
```

This will get you a fully working kapture server installation (with dependent services) in docker that you can access via [localhost:9000](localhost:9000). See the [API documentation](http://kapture.docs.stoplight.io) on how to properly use it.

# Local Development

Easiest way to get up and running here is to start up a local server:

Expand All @@ -19,7 +30,7 @@ Then connect to http://localhost:9000



# API Spec
# API

[The entire API spec is well documented here](https://kapture.docs.stoplight.io)

Expand Down
28 changes: 28 additions & 0 deletions app/components/dest.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const _ = require('lodash');
const config = require('../config');
const path = require('path');

const WHERES = {
music: 'downloadPaths.music',
photo: 'downloadPaths.photos',
photos: 'downloadPaths.photos',
tvshows: 'downloadPaths.shows',
tvshow: 'downloadPaths.shows',
series: 'downloadPaths.shows',
movie: 'downloadPaths.movies',
movies: 'downloadPaths.movies',
other: 'downloadPaths.default',
default: 'downloadPaths.default',
auto: 'downloadPaths.default'
};

exports.determineDest = function(where) {
if(!_.includes(Object.keys(WHERES), where)) {
throw new Error(`key ${where} not valid target location`);
}

let subpath = config.get(WHERES[where]);
let fullbase = path.join(config.get('downloadPaths.root'), subpath);

return path.resolve(fullbase);
}
3 changes: 3 additions & 0 deletions app/components/plugin_handler/plugins.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ const PLUGIN_REQUIREMENTS = {
},
series: { // ie showrss
functions: ['enableId', 'disableId', 'getEnabledSeries']
},
uploader: {
functions: ['uploadFile']
}
}

Expand Down
109 changes: 109 additions & 0 deletions app/components/plugins/upload/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
const crypto = require('crypto');
const path = require('path');
const prettyBytes = require('pretty-bytes');

const Dest = require('../../dest');
const Plugin = require('../../plugin_handler/base');

// standard plugin metadata, and some additional flexget properties
class UploadHandler extends Plugin {
constructor() {
const metadata = {
pluginId: 'com_kapturebox_uploader', // Unique ID of plugin
pluginName: 'Uploader', // Display name of plugin
pluginTypes: ['downloader', 'uploader'], // 'source', 'downloader', 'player'
link: 'http://kapturebox.com', // Link to provider site
description: 'Uploader plugin' // Description of plugin provider
};

const defaultSettings = {
enabled: true,
};

super(metadata, defaultSettings);
}

// we keep this around so that we can add the uploads to the
// 'download' holistic list of all files in system
status() {
// handle ID if passed in optionally
if(arguments[0]) {
return this.getState(arguments[0]);
} else {
return this.getState();
}
}

uploadFile(file, where) {
const self = this;

return new Promise((resolve, reject) => {
const fname = file.name;
const basepath = Dest.determineDest(where);
const fullpath = path.join(basepath, fname);
const id = crypto.createHash('sha1')
.update(`${fullpath}`)
.digest('hex');

const saveObj = {
id: id,
fullPath: fullpath,
title: fname,
where: where,
contentType: file.mimetype,
size: prettyBytes(file.data.byteLength),
sourceId: self.metadata.sourceId,
sourceName: self.metadata.sourceName
};

file.mv(path.resolve(fullpath), function(err) {
if (err)
return reject(err);

self.setState(id, saveObj);

return resolve(saveObj);
});
});
}

removeDownloadId(id, fromDisk) {
const self = this;

return new Promise((resolve,reject) => {
let canonical = self.getState(id);

if(!canonical) {
let err = new Error(`not found ${id}`);
err.statusCode(404);
throw err;
}

self.removeState(id);

if(fromDisk) {
fs.unlink(canonical.fullPath, (err) => {
if(err) {
return reject(err);
}
resolve(canonical);
});
} else {
resolve(canonical);
}
});
}



downloadSlug(slug, where) {
return Promise.reject(new Error('KaptureUploadPlugin.downloadSlug not yet implemented'));
}


removeSlug(slug) {
return Promise.reject(new Error('KaptureUploadPlugin.removeSlug not yet implemented'));
}
}

module.exports = UploadHandler;
16 changes: 7 additions & 9 deletions app/components/plugins/url/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,17 @@ const path = require('path');
const sanitize = require('sanitize-filename');
const Promise = require('bluebird');
const Url = require('url');

const Plugin = require('../../plugin_handler/base');
const Dest = require('../../dest');


class KaptureURLHandler extends Plugin {
constructor() {
const metadata = {
pluginId: 'com_kapture_url', // Unique ID of plugin
pluginId: 'com_kapturebox_url', // Unique ID of plugin
pluginName: 'Kapture URL Handler', // Display name of plugin
pluginTypes: ['downloader'], // 'source', 'downloader', 'player'
pluginTypes: ['downloader'], // 'source', 'downloader', 'player'
sourceTypes: 'adhoc', // 'adhoc', 'continuous'
link: 'http://kapturebox.com', // Link to provider site
downloadProviders: 'url', // if plugin can also download, what
Expand Down Expand Up @@ -223,13 +225,9 @@ class KaptureURLHandler extends Plugin {


getDestPath(url, dest) {
return path.resolve(
path.join(
this.config.getUserSetting('downloadPaths.root'),
this.config.getUserSetting('downloadPaths.' + (dest || 'default')),
this.getFilename(url)
)
);
let cleanDest = Dest.determineDest(dest);

return path.join(cleanDest, this.getFilename(url));
}

getFilename(url) {
Expand Down
10 changes: 8 additions & 2 deletions app/endpoints/getuploads.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,13 @@
* GET: /api/v1/uploads
*
*/
const plugins = require('../components/plugin_handler');

exports.handler = function getuploads(req, res, next) {
res.send('getuploads')
next()
const uploader = plugins.getPlugin('com_kapturebox_uploader');

uploader
.status()
.then((results) => res.status(200).json(results))
.catch(next);
}
27 changes: 23 additions & 4 deletions app/endpoints/newupload.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,33 @@
/**
* Uploads a new file
*
* POST: /api/v1/uploads
* POST: /api/v1/uploads?where={where}
*
* formData:
* file {file} Binary upload data.
* type {string} Type of the media being uploaded.
* where {string} destination where file should be placed
*
*/
const plugins = require('../components/plugin_handler');

// TODO: This upload module needs tests

exports.handler = function newupload(req, res, next) {
res.send('newupload')
next()
const where = req.query.where || 'default';

if (!req.files) {
let err = new Error('no files were uploaded');
err.statusCode = 400;
return next(err);
}

const uploader = plugins.getPlugin('com_kapturebox_uploader');

const uplPromises = Object.keys(req.files)
.map((k) => uploader.uploadFile(req.files[k], where));

Promise
.all(uplPromises)
.then((results) => res.status(202).send(results))
.catch(next)
}
5 changes: 2 additions & 3 deletions app/express.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,11 @@



const express = require('express');
const compression = require('compression');
const bodyParser = require('body-parser');
const methodOverride = require('method-override');
const errorHandler = require('errorhandler');
const path = require('path');
const winstonExpress = require('express-winston');
const uploader = require('express-fileupload');
const cors = require('cors')

const config = require('./config');
Expand All @@ -22,6 +20,7 @@ module.exports = function( app ) {
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.use(methodOverride());
app.use(uploader());
app.set('x-powered-by', false);
app.set('json spaces', 2);
app.use(
Expand Down
Loading