api compelete
This commit is contained in:
parent
221a3f2748
commit
eaafdbe577
@ -1,19 +0,0 @@
|
|||||||
import {Context, DefaultState, DefaultContext, Middleware, Next} from 'koa';
|
|
||||||
import Router from 'koa-router';
|
|
||||||
/**
|
|
||||||
* content file or directory referrer
|
|
||||||
*/
|
|
||||||
export interface ContentReferrer{
|
|
||||||
getHash():Promise<string>;
|
|
||||||
path: string;
|
|
||||||
desc: object|undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContentContext{
|
|
||||||
content:ContentReferrer
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ContentManager{
|
|
||||||
getRouter():Router<ContentContext & DefaultState, DefaultContext>
|
|
||||||
createContent(path:string,option?:any):Promise<ContentReferrer>
|
|
||||||
}
|
|
@ -1,98 +1,8 @@
|
|||||||
|
import {ContentReferrer} from './referrer';
|
||||||
import {Context, DefaultContext, DefaultState, Next} from 'koa';
|
import {createDefaultClass,registerContentReferrer} from './referrer';
|
||||||
import StreamZip, { ZipEntry } from 'node-stream-zip';
|
export class MangaReferrer extends createDefaultClass("manga"){
|
||||||
import {orderBy} from 'natural-orderby';
|
|
||||||
import {since_last_modified} from './util';
|
|
||||||
import {ContentReferrer, ContentManager, ContentContext} from './manager'
|
|
||||||
import Router from 'koa-router';
|
|
||||||
|
|
||||||
export async function readZip(path : string):Promise<StreamZip>{
|
|
||||||
return new Promise((resolve,reject)=>{
|
|
||||||
let zip = new StreamZip({
|
|
||||||
file:path,
|
|
||||||
storeEntries: true
|
|
||||||
});
|
|
||||||
zip.on('error',(err)=>{
|
|
||||||
console.error(`read zip file ${path}`);
|
|
||||||
reject(err);
|
|
||||||
});
|
|
||||||
zip.on('ready',()=>{
|
|
||||||
resolve(zip);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
export function entriesByNaturalOrder(zip: StreamZip){
|
|
||||||
const entries = zip.entries();
|
|
||||||
const ret = orderBy(Object.values(entries),v=>v.name);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
export async function createReadStreamFromZip(zip:StreamZip,entry: ZipEntry):Promise<NodeJS.ReadableStream>{
|
|
||||||
return new Promise((resolve,reject)=>{
|
|
||||||
zip.stream(entry,(err, stream)=>{
|
|
||||||
if(stream !== undefined){
|
|
||||||
resolve(stream);
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
reject(err);
|
|
||||||
}
|
|
||||||
});}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function renderZipImage(ctx: Context,path : string, page:number){
|
|
||||||
const image_ext = ['gif', 'png', 'jpeg', 'bmp', 'webp', 'jpg'];
|
|
||||||
let zip = await readZip(path);
|
|
||||||
const entries = entriesByNaturalOrder(zip).filter(x=>{
|
|
||||||
const ext = x.name.split('.').pop();
|
|
||||||
return ext !== undefined && image_ext.includes(ext);
|
|
||||||
});
|
|
||||||
if(0 <= page && page < entries.length){
|
|
||||||
const entry = entries[page];
|
|
||||||
const last_modified = new Date(entry.time);
|
|
||||||
if(since_last_modified(ctx,last_modified)){
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const read_stream = (await createReadStreamFromZip(zip,entry));
|
|
||||||
read_stream.on('close',()=>zip.close());
|
|
||||||
ctx.body = read_stream;
|
|
||||||
ctx.response.length = entry.size;
|
|
||||||
//console.log(`${entry.name}'s ${page}:${entry.size}`);
|
|
||||||
ctx.response.type = entry.name.split(".").pop() as string;
|
|
||||||
ctx.status = 200;
|
|
||||||
ctx.set('Date', new Date().toUTCString());
|
|
||||||
ctx.set("Last-Modified",last_modified.toUTCString());
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
ctx.status = 404;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MangaReferrer implements ContentReferrer{
|
|
||||||
readonly path: string;
|
|
||||||
desc: object|undefined;
|
|
||||||
constructor(path:string){
|
constructor(path:string){
|
||||||
this.path = path;
|
super(path);
|
||||||
this.desc = undefined;
|
|
||||||
}
|
|
||||||
async getHash():Promise<string>{
|
|
||||||
return "a";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class MangaManager implements ContentManager{
|
|
||||||
async createContent(path:string):Promise<MangaReferrer>{
|
|
||||||
return new MangaReferrer(path);
|
|
||||||
}
|
|
||||||
getRouter(){
|
|
||||||
const router = new Router<DefaultState&ContentContext,DefaultContext>();
|
|
||||||
router.get("/",async (ctx,next)=>{
|
|
||||||
await renderZipImage(ctx,ctx.state.content.path,0);
|
|
||||||
})
|
|
||||||
router.get("/:page(\\d+)",async (ctx,next)=>{
|
|
||||||
const page = Number.parseInt(ctx.params['page']);
|
|
||||||
await renderZipImage(ctx,ctx.state.content.path,page);
|
|
||||||
});
|
|
||||||
return router;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
registerContentReferrer(MangaReferrer);
|
44
src/content/referrer.ts
Normal file
44
src/content/referrer.ts
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
import {Context, DefaultState, DefaultContext, Middleware, Next} from 'koa';
|
||||||
|
import Router from 'koa-router';
|
||||||
|
import {createHash} from 'crypto';
|
||||||
|
import {promises} from 'fs'
|
||||||
|
/**
|
||||||
|
* content file or directory referrer
|
||||||
|
*/
|
||||||
|
export interface ContentReferrer{
|
||||||
|
getHash():Promise<string>;
|
||||||
|
readonly path: string;
|
||||||
|
readonly type: string;
|
||||||
|
desc: object|undefined;
|
||||||
|
}
|
||||||
|
type ContentReferrerConstructor = (new (path:string,desc?:object) => ContentReferrer)&{content_type:string};
|
||||||
|
export const createDefaultClass = (type:string):ContentReferrerConstructor=>{
|
||||||
|
let cons = class implements ContentReferrer{
|
||||||
|
readonly path: string;
|
||||||
|
type = type;
|
||||||
|
static content_type = type;
|
||||||
|
|
||||||
|
desc: object|undefined;
|
||||||
|
constructor(path:string,desc?:object){
|
||||||
|
this.path = path;
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
async getHash():Promise<string>{
|
||||||
|
const stat = await promises.stat(this.path);
|
||||||
|
const hash = createHash("sha512");
|
||||||
|
hash.update(stat.mode.toString());
|
||||||
|
//if(this.desc !== undefined)
|
||||||
|
// hash.update(JSON.stringify(this.desc));
|
||||||
|
hash.update(stat.size.toString());
|
||||||
|
return hash.digest("base64");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return cons;
|
||||||
|
}
|
||||||
|
let ContstructorTable:{[k:string]:ContentReferrerConstructor} = {};
|
||||||
|
export function registerContentReferrer(s: ContentReferrerConstructor){
|
||||||
|
ContstructorTable[s.content_type] = s;
|
||||||
|
}
|
||||||
|
export function createContentReferrer(type:string,path:string,desc?:object){
|
||||||
|
return new ContstructorTable[type](path,desc);
|
||||||
|
}
|
@ -1,79 +1,9 @@
|
|||||||
import {Context, DefaultContext, DefaultState} from 'koa';
|
import {ContentReferrer, registerContentReferrer} from './referrer';
|
||||||
import {promises, createReadStream} from "fs";
|
import {createDefaultClass} from './referrer';
|
||||||
import { ContentContext, ContentManager, ContentReferrer } from './manager';
|
|
||||||
import Router from 'koa-router';
|
|
||||||
|
|
||||||
export async function renderVideo(ctx: Context,path : string){
|
export class VideoReferrer extends createDefaultClass("video"){
|
||||||
const ext = path.trim().split('.').pop();
|
|
||||||
if(ext === undefined) {
|
|
||||||
//ctx.status = 404;
|
|
||||||
console.error(`${path}:${ext}`)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.response.type = ext;
|
|
||||||
const range_text = ctx.request.get("range");
|
|
||||||
const stat = await promises.stat(path);
|
|
||||||
let start = 0;
|
|
||||||
let end = 0;
|
|
||||||
ctx.set('Last-Modified',(new Date(stat.mtime).toUTCString()));
|
|
||||||
ctx.set('Date', new Date().toUTCString());
|
|
||||||
ctx.set("Accept-Ranges", "bytes");
|
|
||||||
if(range_text === ''){
|
|
||||||
end = 1024*512;
|
|
||||||
end = Math.min(end,stat.size-1);
|
|
||||||
if(start > end){
|
|
||||||
ctx.status = 416;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.status = 200;
|
|
||||||
ctx.length = stat.size;
|
|
||||||
let stream = createReadStream(path);
|
|
||||||
ctx.body = stream;
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
const m = range_text.match(/^bytes=(\d+)-(\d*)/);
|
|
||||||
if(m === null){
|
|
||||||
ctx.status = 416;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
start = parseInt(m[1]);
|
|
||||||
end = m[2].length > 0 ? parseInt(m[2]) : start + 1024*1024;
|
|
||||||
end = Math.min(end,stat.size-1);
|
|
||||||
if(start > end){
|
|
||||||
ctx.status = 416;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
ctx.status = 206;
|
|
||||||
ctx.length = end - start + 1;
|
|
||||||
ctx.response.set("Content-Range",`bytes ${start}-${end}/${stat.size}`);
|
|
||||||
ctx.body = createReadStream(path,{
|
|
||||||
start:start,
|
|
||||||
end:end
|
|
||||||
});//inclusive range.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class VideoReferrer implements ContentReferrer{
|
|
||||||
readonly path: string;
|
|
||||||
desc: object|undefined;
|
|
||||||
constructor(path:string,desc?:object){
|
constructor(path:string,desc?:object){
|
||||||
this.path = path;
|
super(path,desc);
|
||||||
this.desc = desc;
|
|
||||||
}
|
|
||||||
async getHash():Promise<string>{
|
|
||||||
return "a";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class VideoManager implements ContentManager{
|
|
||||||
async createContent(path:string):Promise<VideoReferrer>{
|
|
||||||
return new VideoReferrer(path);
|
|
||||||
}
|
|
||||||
getRouter(){
|
|
||||||
const router = new Router<DefaultState&ContentContext,DefaultContext>();
|
|
||||||
router.get("/",async (ctx,next)=>{
|
|
||||||
await renderVideo(ctx,ctx.state.content.path);
|
|
||||||
});
|
|
||||||
return router;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
registerContentReferrer(VideoReferrer);
|
58
src/route/all.ts
Normal file
58
src/route/all.ts
Normal file
@ -0,0 +1,58 @@
|
|||||||
|
import { DefaultContext, Middleware, Next, ParameterizedContext } from 'koa';
|
||||||
|
import compose from 'koa-compose';
|
||||||
|
import Router, { IParamMiddleware } from 'koa-router';
|
||||||
|
import { ContentContext } from './context';
|
||||||
|
import MangaRouter from './manga';
|
||||||
|
import VideoRouter from './video';
|
||||||
|
|
||||||
|
const table:{[s:string]:Router|undefined} = {
|
||||||
|
"manga": new MangaRouter,
|
||||||
|
"video": new VideoRouter
|
||||||
|
}
|
||||||
|
const all_middleware = (cont: string|undefined, restarg: string|undefined)=>async (ctx:ParameterizedContext<ContentContext,DefaultContext>,next:Next)=>{
|
||||||
|
if(cont == undefined){
|
||||||
|
ctx.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(ctx.state.content.type != cont){
|
||||||
|
ctx.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const router = table[cont];
|
||||||
|
if(router == undefined){
|
||||||
|
ctx.status = 404;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const rest = "/"+(restarg as string|undefined || "");
|
||||||
|
|
||||||
|
const result = router.match(rest,"GET");
|
||||||
|
console.log(`s : ${result.pathAndMethod}`);
|
||||||
|
if(!result.route){
|
||||||
|
return await next();
|
||||||
|
}
|
||||||
|
const chain = result.pathAndMethod.reduce((combination : Middleware<any& DefaultContext,any>[],cur)=>{
|
||||||
|
combination.push(async (ctx,next)=>{
|
||||||
|
const captures = cur.captures(rest);
|
||||||
|
ctx.params = cur.params(rest,captures);
|
||||||
|
ctx.request.params = ctx.params;
|
||||||
|
ctx.routerPath = cur.path;
|
||||||
|
return await next();
|
||||||
|
});
|
||||||
|
return combination.concat(cur.stack);
|
||||||
|
},[]);
|
||||||
|
return await compose(chain)(ctx,next);
|
||||||
|
};
|
||||||
|
export class AllContentRouter extends Router<ContentContext>{
|
||||||
|
constructor(){
|
||||||
|
super();
|
||||||
|
this.get('/:content_type',async (ctx,next)=>{
|
||||||
|
console.log("no x");
|
||||||
|
return await (all_middleware(ctx.params["content_type"],undefined))(ctx,next);
|
||||||
|
});
|
||||||
|
this.get('/:content_type/:rest(.*)', async (ctx,next) => {
|
||||||
|
console.log("yes x");
|
||||||
|
const cont = ctx.params["content_type"] as string;
|
||||||
|
return await (all_middleware(cont,ctx.params["rest"]))(ctx,next);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
@ -4,6 +4,9 @@ import {ContentAccessor, isContentContent} from './../model/contents';
|
|||||||
import {QueryListOption} from './../model/contents';
|
import {QueryListOption} from './../model/contents';
|
||||||
import {ParseQueryNumber, ParseQueryArray, ParseQueryBoolean} from './util'
|
import {ParseQueryNumber, ParseQueryArray, ParseQueryBoolean} from './util'
|
||||||
import {sendError} from './error_handler';
|
import {sendError} from './error_handler';
|
||||||
|
import { createContentReferrer } from '../content/referrer';
|
||||||
|
import { join } from 'path';
|
||||||
|
import {AllContentRouter} from './all';
|
||||||
|
|
||||||
const ContentIDHandler = (controller: ContentAccessor) => async (ctx: Context,next: Next)=>{
|
const ContentIDHandler = (controller: ContentAccessor) => async (ctx: Context,next: Next)=>{
|
||||||
const num = Number.parseInt(ctx.params['num']);
|
const num = Number.parseInt(ctx.params['num']);
|
||||||
@ -102,6 +105,18 @@ const DeleteContentHandler = (controller : ContentAccessor) => async (ctx: Conte
|
|||||||
ctx.body = {"ret":r};
|
ctx.body = {"ret":r};
|
||||||
ctx.type = 'json';
|
ctx.type = 'json';
|
||||||
};
|
};
|
||||||
|
const ContentHandler = (controller : ContentAccessor) => async (ctx:Context, next:Next) => {
|
||||||
|
const num = Number.parseInt(ctx.params['num']);
|
||||||
|
let content = await controller.findById(num,true);
|
||||||
|
if (content == undefined){
|
||||||
|
sendError(404,"content does not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const path = join(content.basepath,content.filename);
|
||||||
|
ctx.state['content'] = createContentReferrer(content.content_type,path,content.additional);
|
||||||
|
await next();
|
||||||
|
};
|
||||||
|
|
||||||
export const getContentRouter = (controller: ContentAccessor)=>{
|
export const getContentRouter = (controller: ContentAccessor)=>{
|
||||||
const ret = new Router();
|
const ret = new Router();
|
||||||
ret.get("/search",ContentQueryHandler(controller));
|
ret.get("/search",ContentQueryHandler(controller));
|
||||||
@ -112,7 +127,8 @@ export const getContentRouter = (controller: ContentAccessor)=>{
|
|||||||
ret.post("/:num(\\d+)/tags/:tag",AddTagHandler(controller));
|
ret.post("/:num(\\d+)/tags/:tag",AddTagHandler(controller));
|
||||||
ret.del("/:num(\\d+)/tags/:tag",DelTagHandler(controller));
|
ret.del("/:num(\\d+)/tags/:tag",DelTagHandler(controller));
|
||||||
ret.del("/:num(\\d+)",DeleteContentHandler(controller));
|
ret.del("/:num(\\d+)",DeleteContentHandler(controller));
|
||||||
//ret.get("/");
|
ret.all("/:num(\\d+)/(.*)",ContentHandler(controller));
|
||||||
|
ret.use("/:num",(new AllContentRouter).routes());
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
5
src/route/context.ts
Normal file
5
src/route/context.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import {ContentReferrer} from '../content/referrer';
|
||||||
|
|
||||||
|
export interface ContentContext{
|
||||||
|
content:ContentReferrer
|
||||||
|
}
|
84
src/route/manga.ts
Normal file
84
src/route/manga.ts
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
|
||||||
|
import {Context, DefaultContext, DefaultState, Next} from 'koa';
|
||||||
|
import StreamZip, { ZipEntry } from 'node-stream-zip';
|
||||||
|
import {orderBy} from 'natural-orderby';
|
||||||
|
import {since_last_modified} from '../content/util';
|
||||||
|
import {ContentContext} from './context';
|
||||||
|
import Router from 'koa-router';
|
||||||
|
|
||||||
|
export async function readZip(path : string):Promise<StreamZip>{
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
let zip = new StreamZip({
|
||||||
|
file:path,
|
||||||
|
storeEntries: true
|
||||||
|
});
|
||||||
|
zip.on('error',(err)=>{
|
||||||
|
console.error(`read zip file ${path}`);
|
||||||
|
reject(err);
|
||||||
|
});
|
||||||
|
zip.on('ready',()=>{
|
||||||
|
resolve(zip);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
export function entriesByNaturalOrder(zip: StreamZip){
|
||||||
|
const entries = zip.entries();
|
||||||
|
const ret = orderBy(Object.values(entries),v=>v.name);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
export async function createReadStreamFromZip(zip:StreamZip,entry: ZipEntry):Promise<NodeJS.ReadableStream>{
|
||||||
|
return new Promise((resolve,reject)=>{
|
||||||
|
zip.stream(entry,(err, stream)=>{
|
||||||
|
if(stream !== undefined){
|
||||||
|
resolve(stream);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
reject(err);
|
||||||
|
}
|
||||||
|
});}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function renderZipImage(ctx: Context,path : string, page:number){
|
||||||
|
const image_ext = ['gif', 'png', 'jpeg', 'bmp', 'webp', 'jpg'];
|
||||||
|
let zip = await readZip(path);
|
||||||
|
const entries = entriesByNaturalOrder(zip).filter(x=>{
|
||||||
|
const ext = x.name.split('.').pop();
|
||||||
|
return ext !== undefined && image_ext.includes(ext);
|
||||||
|
});
|
||||||
|
if(0 <= page && page < entries.length){
|
||||||
|
const entry = entries[page];
|
||||||
|
const last_modified = new Date(entry.time);
|
||||||
|
if(since_last_modified(ctx,last_modified)){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const read_stream = (await createReadStreamFromZip(zip,entry));
|
||||||
|
read_stream.on('close',()=>zip.close());
|
||||||
|
ctx.body = read_stream;
|
||||||
|
ctx.response.length = entry.size;
|
||||||
|
//console.log(`${entry.name}'s ${page}:${entry.size}`);
|
||||||
|
ctx.response.type = entry.name.split(".").pop() as string;
|
||||||
|
ctx.status = 200;
|
||||||
|
ctx.set('Date', new Date().toUTCString());
|
||||||
|
ctx.set("Last-Modified",last_modified.toUTCString());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
ctx.status = 404;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MangaRouter extends Router<ContentContext>{
|
||||||
|
constructor(){
|
||||||
|
super();
|
||||||
|
this.get("/",async (ctx,next)=>{
|
||||||
|
await renderZipImage(ctx,ctx.state.content.path,0);
|
||||||
|
});
|
||||||
|
this.get("/:page(\\d+)",async (ctx,next)=>{
|
||||||
|
const page = Number.parseInt(ctx.params['page']);
|
||||||
|
await renderZipImage(ctx,ctx.state.content.path,page);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default MangaRouter;
|
65
src/route/video.ts
Normal file
65
src/route/video.ts
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import {Context } from 'koa';
|
||||||
|
import {promises, createReadStream} from "fs";
|
||||||
|
import {ContentContext} from './context';
|
||||||
|
import Router from 'koa-router';
|
||||||
|
|
||||||
|
export async function renderVideo(ctx: Context,path : string){
|
||||||
|
const ext = path.trim().split('.').pop();
|
||||||
|
if(ext === undefined) {
|
||||||
|
//ctx.status = 404;
|
||||||
|
console.error(`${path}:${ext}`)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.response.type = ext;
|
||||||
|
const range_text = ctx.request.get("range");
|
||||||
|
const stat = await promises.stat(path);
|
||||||
|
let start = 0;
|
||||||
|
let end = 0;
|
||||||
|
ctx.set('Last-Modified',(new Date(stat.mtime).toUTCString()));
|
||||||
|
ctx.set('Date', new Date().toUTCString());
|
||||||
|
ctx.set("Accept-Ranges", "bytes");
|
||||||
|
if(range_text === ''){
|
||||||
|
end = 1024*512;
|
||||||
|
end = Math.min(end,stat.size-1);
|
||||||
|
if(start > end){
|
||||||
|
ctx.status = 416;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.status = 200;
|
||||||
|
ctx.length = stat.size;
|
||||||
|
let stream = createReadStream(path);
|
||||||
|
ctx.body = stream;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
const m = range_text.match(/^bytes=(\d+)-(\d*)/);
|
||||||
|
if(m === null){
|
||||||
|
ctx.status = 416;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
start = parseInt(m[1]);
|
||||||
|
end = m[2].length > 0 ? parseInt(m[2]) : start + 1024*1024;
|
||||||
|
end = Math.min(end,stat.size-1);
|
||||||
|
if(start > end){
|
||||||
|
ctx.status = 416;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ctx.status = 206;
|
||||||
|
ctx.length = end - start + 1;
|
||||||
|
ctx.response.set("Content-Range",`bytes ${start}-${end}/${stat.size}`);
|
||||||
|
ctx.body = createReadStream(path,{
|
||||||
|
start:start,
|
||||||
|
end:end
|
||||||
|
});//inclusive range.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class VideoRouter extends Router<ContentContext>{
|
||||||
|
constructor(){
|
||||||
|
super();
|
||||||
|
this.get("/", async (ctx,next)=>{
|
||||||
|
await renderVideo(ctx,ctx.state.content.path);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default VideoRouter;
|
@ -10,11 +10,11 @@ import getContentRouter from './route/contents';
|
|||||||
import { createKnexContentsAccessor } from './db/contents';
|
import { createKnexContentsAccessor } from './db/contents';
|
||||||
import bodyparser from 'koa-bodyparser';
|
import bodyparser from 'koa-bodyparser';
|
||||||
import {error_handler} from './route/error_handler';
|
import {error_handler} from './route/error_handler';
|
||||||
|
import {MangaReferrer} from './content/manga';
|
||||||
|
import {VideoReferrer} from './content/video';
|
||||||
|
|
||||||
import {MangaManager,MangaReferrer} from './content/manga'
|
import { ContentContext } from './route/context';
|
||||||
import { ContentContext } from './content/manager';
|
import { AllContentRouter } from './route/all';
|
||||||
import { Context } from 'vm';
|
|
||||||
import { VideoManager } from './content/video';
|
|
||||||
|
|
||||||
//let Koa = require("koa");
|
//let Koa = require("koa");
|
||||||
async function main(){
|
async function main(){
|
||||||
@ -51,23 +51,17 @@ async function main(){
|
|||||||
let content_router = getContentRouter(createKnexContentsAccessor(db));
|
let content_router = getContentRouter(createKnexContentsAccessor(db));
|
||||||
router.use('/content',content_router.routes());
|
router.use('/content',content_router.routes());
|
||||||
router.use('/content',content_router.allowedMethods());
|
router.use('/content',content_router.allowedMethods());
|
||||||
let manga_manager = new MangaManager();
|
let ctnrouter = new AllContentRouter();
|
||||||
let video_manager = new VideoManager();
|
router.all('/image/(.*)', async (ctx,next)=>{
|
||||||
router.use('/image', async (ctx,next)=>{
|
ctx.state['content'] = new MangaReferrer("testdata/test_zip.zip");
|
||||||
ctx.state['content'] = await manga_manager.createContent("testdata/test_zip.zip");
|
|
||||||
await next();
|
await next();
|
||||||
});
|
});
|
||||||
let rr = manga_manager.getRouter();
|
router.use('/image',ctnrouter.routes());
|
||||||
rr.prefix("/image");
|
router.all('/ss/(.*)', async (ctx,next)=>{
|
||||||
router.use('/image',(ctx,next)=>{
|
ctx.state['content'] = new VideoReferrer("testdata/video_test.mp4");
|
||||||
console.log("asdf");
|
|
||||||
rr.routes()(ctx,next);
|
|
||||||
});
|
|
||||||
router.use('/ss.mp4', async (ctx,next)=>{
|
|
||||||
ctx.state['content'] = await video_manager.createContent("testdata/video_test.mp4");
|
|
||||||
await next();
|
await next();
|
||||||
});
|
});
|
||||||
router.use('/ss.mp4',video_manager.getRouter().routes());
|
router.use('/ss',ctnrouter.routes());
|
||||||
let mm_count=0;
|
let mm_count=0;
|
||||||
app.use(async (ctx,next)=>{
|
app.use(async (ctx,next)=>{
|
||||||
console.log(`==========================${mm_count++}`);
|
console.log(`==========================${mm_count++}`);
|
||||||
|
Loading…
Reference in New Issue
Block a user