brunner56's picture
implement app
0bfe2e3
import express, { Request, Response } from 'express';
import {
userApi,
healthApi,
statusApi,
formatApi,
catalogApi,
} from './routes/api';
import {
configure,
manifest,
stream,
catalog,
meta,
subtitle,
addonCatalog,
alias,
} from './routes/stremio';
import {
ipMiddleware,
loggerMiddleware,
userDataMiddleware,
errorMiddleware,
corsMiddleware,
staticRateLimiter,
} from './middlewares';
import { constants, createLogger, Env } from '@aiostreams/core';
import { StremioTransformer } from '@aiostreams/core';
import { createResponse } from './utils/responses';
import path from 'path';
const app = express();
const logger = createLogger('server');
export const frontendRoot = path.join(__dirname, '../../frontend/out');
app.use(ipMiddleware);
app.use(loggerMiddleware);
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
// Allow all origins in development for easier testing
if (Env.NODE_ENV === 'development') {
logger.info('CORS enabled for all origins in development');
app.use(corsMiddleware);
}
// API Routes
const apiRouter = express.Router();
apiRouter.use('/user', userApi);
apiRouter.use('/health', healthApi);
apiRouter.use('/status', statusApi);
apiRouter.use('/format', formatApi);
apiRouter.use('/catalogs', catalogApi);
app.use(`/api/v${constants.API_VERSION}`, apiRouter);
// Stremio Routes
const stremioRouter = express.Router({ mergeParams: true });
stremioRouter.use(corsMiddleware);
// Public routes - no auth needed
stremioRouter.use('/manifest.json', manifest);
stremioRouter.use('/stream', stream);
stremioRouter.use('/configure', configure);
stremioRouter.use('/configure.txt', (req, res) => {
res.sendFile(path.join(frontendRoot, 'index.txt'));
});
stremioRouter.use('/u', alias);
// Protected routes with authentication
const stremioAuthRouter = express.Router({ mergeParams: true });
stremioAuthRouter.use(corsMiddleware);
stremioAuthRouter.use(userDataMiddleware);
stremioAuthRouter.use('/manifest.json', manifest);
stremioAuthRouter.use('/stream', stream);
stremioAuthRouter.use('/configure', configure);
stremioAuthRouter.use('/configure.txt', staticRateLimiter, (req, res) => {
res.sendFile(path.join(frontendRoot, 'index.txt'));
});
stremioAuthRouter.use('/meta', meta);
stremioAuthRouter.use('/catalog', catalog);
stremioAuthRouter.use('/subtitles', subtitle);
stremioAuthRouter.use('/addon_catalog', addonCatalog);
app.use('/stremio', stremioRouter); // For public routes
app.use('/stremio/:uuid/:encryptedPassword', stremioAuthRouter); // For authenticated routes
app.get(
['/_next/*', '/assets/*', '/favicon.ico', '/logo.png'],
staticRateLimiter,
(req, res, next) => {
const filePath = path.resolve(frontendRoot, req.path.replace(/^\//, ''));
if (filePath.startsWith(frontendRoot)) {
res.sendFile(filePath);
return;
}
next();
}
);
app.get('/', (req, res) => {
res.redirect('/stremio/configure');
});
// legacy route handlers
app.get('/:config?/stream/:type/:id.json', (req, res) => {
const baseUrl =
Env.BASE_URL ||
`${req.protocol}://${req.hostname}${
req.hostname === 'localhost' ? `:${Env.PORT}` : ''
}`;
res.json({
streams: [
StremioTransformer.createErrorStream({
errorDescription:
'AIOStreams v2 requires you to reconfigure. Please click this stream to reconfigure.',
errorUrl: `${baseUrl}/stremio/configure`,
}),
],
});
});
app.get('/:config?/configure', (req, res) => {
res.redirect('/stremio/configure');
});
// 404 handler
app.use((req, res) => {
res.status(404).json(
createResponse({
success: false,
detail: 'Not Found',
})
);
});
// Error handling middleware should be last
app.use(errorMiddleware);
export default app;