CinemaPress/routes/website.js

757 lines
21 KiB
JavaScript

'use strict';
/**
* Module dependencies.
*/
var CP_cache = require('../lib/CP_cache');
var CP_decode = require('../lib/CP_decode');
var CP_translit = require('../lib/CP_translit');
var CP_regexp = require('../lib/CP_regexp');
/**
* Configuration dependencies.
*/
var config = require('../config/production/config');
Object.keys(config).length === 0 &&
(config = require('../config/production/config.backup'));
var config_md5 = require('md5')(JSON.stringify(config));
var modules = require('../config/production/modules');
Object.keys(modules).length === 0 &&
(modules = require('../config/production/modules.backup'));
var modules_md5 = require('md5')(JSON.stringify(modules));
setInterval(function() {
if (
config_md5 &&
process.env['CP_CONFIG_MD5'] &&
config_md5 !== process.env['CP_CONFIG_MD5']
) {
config = require('../config/production/config');
Object.keys(config).length === 0 &&
(config = require('../config/production/config.backup'));
config_md5 = process.env['CP_CONFIG_MD5'];
}
if (
modules_md5 &&
process.env['CP_MODULES_MD5'] &&
modules_md5 !== process.env['CP_MODULES_MD5']
) {
modules = require('../config/production/modules');
Object.keys(modules).length === 0 &&
(modules = require('../config/production/modules.backup'));
modules_md5 = process.env['CP_MODULES_MD5'];
}
}, 3333);
/**
* Node dependencies.
*/
var fs = require('fs');
var md5 = require('md5');
var url_parse = require('url');
var path = require('path');
var _eval = require('eval');
var express = require('express');
var router = express.Router();
/**
* Route dependencies.
*/
var index = require('./paths/index');
var movie = require('./paths/movie');
var category = require('./paths/category');
var sitemap = require('./paths/sitemap');
/**
* Route CP modules dependencies.
*/
var content = require('./paths/content');
/**
* Callback.
*
* @callback Callback
* @param {Object} err
* @param {Object} [render]
*/
router.get('/:level1?/:level2?/:level3?/:level4?', function(req, res, next) {
var levels = [
config.urls.movie,
config.urls.year,
config.urls.genre,
config.urls.country,
config.urls.actor,
config.urls.director,
config.urls.type,
config.urls.search,
modules.content.data.url
];
if (config.urls.noindex) {
levels.push(config.urls.noindex);
}
var levels_first = new RegExp('^(' + levels.join('|') + ')-(.*)$', 'i');
if (req.params && req.params.level1 && levels_first.test(req.params.level1)) {
var l = req.params.level1.match(levels_first);
req.params.level1 = l[1];
if (req.params.level2) {
req.params.level3 = req.params.level2;
req.params.level2 = l[2];
} else {
req.params.level2 = l[2];
}
}
var options = {};
options.query = {};
options.userinfo = req.userinfo;
options.protocol = req.userinfo.protocol || config.protocol;
options.domain = req.userinfo.domain || config.subdomain + '' + config.domain;
options.origin =
req.userinfo.origin || options.protocol + '' + options.domain;
options.port = req.userinfo.port;
options.subscribe = req.cookies.CP_subscribe || '';
options.debug =
process.env.NODE_ENV !== 'production'
? {
url: parseUrl(),
duration: {
current: new Date(),
all: req.start_request || new Date()
},
detail: [
{
type: 'website',
mem:
Math.round(
(process.memoryUsage().heapUsed / 1024 / 1024) * 100
) / 100,
duration: new Date() - (req.start_request || new Date()) + 'ms'
}
]
}
: null;
options.comments = {
page: req.query.page ? CP_regexp.str(req.query.page) : null,
sorting: req.query.sorting ? CP_regexp.str(req.query.sorting) : null,
num: req.query.num ? CP_regexp.str(req.query.num) : null
};
var url = parseUrl();
var urlHash = md5(
JSON.stringify(options) + url.toLowerCase() + process.env['CP_VER']
);
var level1 = CP_regexp.str(req.params.level1) || null;
var level2 =
CP_regexp.str(req.query.q) ||
CP_regexp.str(CP_translit.text(req.params.level2 || '', true, level1)) ||
null;
var level3 = CP_regexp.str(req.params.level3 || '') || null;
var sorting =
CP_regexp.str(req.query.sorting) ||
(level1 === modules.content.data.url || level1 === config.urls.search
? level1 === config.urls.search
? config.default.sorting_search
: ''
: config.default.sorting);
var tag = CP_regexp.str(req.query.tag) || null;
var id = level2 ? movie.id(level2) : '';
var filename = level2
? id
? id
: level1 === config.urls.sitemap && level3
? decodeURIComponent(
CP_translit.text(level2 + '-' + level3, undefined, '')
).replace(/^-/, '')
: decodeURIComponent(
CP_translit.text(level2 || '', undefined, '')
).replace(/^-/, '')
: 'index';
var custom_template = path.join(
__dirname,
'..',
'themes',
config.theme,
'views',
req.userinfo.device === 'desktop' ? '' : req.userinfo.device,
level1 || 'custom',
filename + '.ejs'
);
var custom_data = path.join(
__dirname,
'..',
'themes',
config.theme,
'views',
req.userinfo.device === 'desktop' ? '' : req.userinfo.device,
level1 || 'custom',
filename + '.json'
);
[
'type',
'year',
'genre',
'country',
'actor',
'director',
'kp_rating',
'imdb_rating'
].forEach(function(t) {
if (req.query[t] && level1 !== config.urls[t]) {
if (t === 'year' || t === 'kp_rating' || t === 'imdb_rating') {
options.query[t] = CP_regexp.str(req.query[t]);
} else {
options.query[t] = CP_regexp.str(
CP_translit.text(req.query[t], true, config.urls[t])
);
}
if (!level2) {
level2 = 'X';
}
}
});
Object.keys(req.query).forEach(function(t) {
if (/^custom\./i.test(t)) {
options.query[t] = CP_regexp.str(req.query[t]);
if (!level2) {
level2 = 'X';
}
}
});
var template = setTemplate();
getRender(function(err, render) {
switch (template) {
case 'content':
template = 'category';
break;
case 'contents':
template = 'categories';
break;
}
renderData(err, render);
});
function getRender(callback) {
if (typeof req.query.random !== 'undefined' && modules.random.status) {
getSphinx(function(err, render) {
return callback(err, render);
});
} else {
getCache(function(err, render) {
return callback(err, render);
});
}
}
function getCache(callback) {
CP_cache.get(urlHash, function(err, render) {
return render
? callback(null, render)
: getSphinx(function(err, render) {
return err ? callback(err) : callback(null, render);
});
});
}
function getSphinx(callback) {
switch (template) {
case 'movie':
movie.data(id, 'movie', options, function(err, render) {
if (err) {
callback(err);
} else if (url === render.page.url) {
callback(null, render);
} else {
return res.redirect(301, render.page.url);
}
});
break;
case 'online':
movie.data(id, 'online', options, function(err, render) {
if (err) {
callback(err);
} else if (url === render.page.url) {
callback(null, render);
} else {
return res.redirect(301, render.page.url);
}
});
break;
case 'download':
movie.data(id, 'download', options, function(err, render) {
if (err) {
callback(err);
} else if (url === render.page.url) {
callback(null, render);
} else {
return res.redirect(301, render.page.url);
}
});
break;
case 'trailer':
movie.data(id, 'trailer', options, function(err, render) {
if (err) {
callback(err);
} else if (url === render.page.url) {
callback(null, render);
} else {
return res.redirect(301, render.page.url);
}
});
break;
case 'picture':
movie.data(id, 'picture', options, function(err, render) {
if (err) {
callback(err);
} else if (url === render.page.url) {
callback(null, render);
} else {
return res.redirect(301, render.page.url);
}
});
break;
case 'episode':
movie.data(id, level3, options, function(err, render) {
if (err) {
callback(err);
} else if (url === render.page.url) {
callback(null, render);
} else {
return res.redirect(301, render.page.url);
}
});
break;
case 'category':
if (typeof req.query.random !== 'undefined' && modules.random.status) {
category.random(level1, level2, options, function(err, url) {
if (err) {
callback(err);
} else if (!url) {
callback(config.l.notFound);
} else {
return res.redirect(302, url);
}
});
} else {
category.one(
level1,
level2,
parseInt(level3),
sorting,
options,
function(err, render) {
var levels_category = new RegExp(
'/' + level1 + config.urls.slash,
'i'
);
if (err) {
callback(err);
} else if (
level1 === config.urls.search ||
levels_category.test(url)
) {
callback(null, render);
} else {
return res.redirect(301, render.page.url);
}
}
);
}
break;
case 'categories':
category.all(level1, options, function(err, render) {
callback(err, render);
});
break;
case 'content':
if (typeof req.query.random !== 'undefined' && modules.random.status) {
content.random(req.params.level2, options, function(err, url) {
if (err) {
callback(err);
} else if (!url) {
callback(config.l.notFound);
} else {
return res.redirect(302, url);
}
});
} else {
content.one(
req.params.level2,
parseInt(level3),
sorting,
options,
function(err, render) {
if (err || !render) {
return callback(err);
}
var levels_content = new RegExp(
'/' +
modules.content.data.url +
config.urls.slash +
render.content.slug,
''
);
if (levels_content.test(url)) {
callback(null, render);
} else {
return res.redirect(
301,
'/' +
modules.content.data.url +
config.urls.slash +
render.content.slug
);
}
}
);
}
break;
case 'contents':
content.all(tag, options, function(err, render) {
callback(err, render);
});
break;
case 'sitemap':
if (level2) {
sitemap.one(level2, level3, options, function(err, render) {
callback(err, render);
});
} else {
sitemap.all(options, function(err, render) {
callback(err, render);
});
}
break;
case 'index':
if (
typeof req.query.random !== 'undefined' &&
modules.random.status &&
modules.random.data.menu
) {
content.random(modules.random.data.menu, options, function(err, red) {
if (err) {
callback(err);
} else if (!red) {
callback(config.l.notFound);
} else {
return res.redirect(302, red);
}
});
} else {
index.data(options, function(err, render) {
callback(err, render);
});
}
break;
default:
callback(config.l.notFound);
}
}
function parseUrl() {
var parts = req.originalUrl.split('?');
var url =
options.protocol +
options.domain +
parts[0].replace(/\/tv-version|\/mobile-version/, '');
if (parts[1]) {
if (req.query.sorting && config.sorting[req.query.sorting]) {
url +=
(url.indexOf('?') + 1 ? '&' : '?') + 'sorting=' + req.query.sorting;
}
if (req.query.q) {
url +=
(url.indexOf('?') + 1 ? '&' : '?') +
'q=' +
CP_regexp.str(req.query.q);
}
if (req.query.tag) {
url +=
(url.indexOf('?') + 1 ? '&' : '?') +
'tag=' +
CP_regexp.str(req.query.tag);
}
[
'type',
'year',
'genre',
'country',
'actor',
'director',
'kp_rating',
'imdb_rating'
].forEach(function(t) {
if (req.query[t]) {
url += (url.indexOf('?') + 1 ? '&' : '?') + t + '=' + req.query[t];
}
});
if (typeof req.query.json !== 'undefined') {
url += (url.indexOf('?') + 1 ? '&' : '?') + 'json=1';
}
if (typeof req.query.random !== 'undefined') {
url += (url.indexOf('?') + 1 ? '&' : '?') + 'random=1';
}
}
return CP_decode.text(url);
}
function setTemplate() {
switch (level1) {
case config.urls.noindex:
if (!config.urls.noindex) return 'error';
return id ? movie.type(level3) : 'error';
case config.urls.movie:
return id ? movie.type(level3) : 'error';
case config.urls.year:
return level2 ? 'category' : 'categories';
case config.urls.genre:
return level2 ? 'category' : 'categories';
case config.urls.country:
return level2 ? 'category' : 'categories';
case config.urls.actor:
return level2 ? 'category' : 'categories';
case config.urls.director:
return level2 ? 'category' : 'categories';
case config.urls.type:
return level2 ? 'category' : 'error';
case config.urls.search:
return level2 && !/^-/.test(level2) ? 'category' : 'error';
case config.urls.sitemap:
return 'sitemap';
case modules.content.data.url:
if (!modules.content.status) return 'error';
return level2 ? 'content' : 'contents';
case null:
return 'index';
default:
return 'error';
}
}
function renderData(err, render) {
if (err) {
console.log('[routes/website.js]', url);
return next({
status: 404,
message: err
});
}
if (options.userinfo.bot.all) {
if (
config.publish.indexing &&
config.publish.indexing.condition &&
/(movie|online|download|trailer|picture|episode)/i.test(template)
) {
var condition = _eval(
'module.exports=function(movie){return !!(' +
config.publish.indexing.condition.toString() +
');}'
);
if (condition(render.movie)) {
console.log('[Indexing is forbidden in condition]', url);
return next({
status: 404,
message: err
});
}
}
}
if (template === 'sitemap') {
if (!config.user_bot) {
if (!req.userinfo.bot.main) {
return next({
status: 404,
message: 'The sitemap is available only to search bots.'
});
}
var host = req.get('host');
var host_domain = url_parse.parse(config.protocol + '://' + host)
.hostname;
if (
(config.bomain || config.ru.bomain) &&
(host_domain === config.subdomain + config.domain ||
host_domain === config.ru.subdomain + config.ru.domain ||
config.mirrors.indexOf(host_domain) + 1)
) {
return next({
status: 404,
message: 'The sitemap is available only to search bots.'
});
}
}
}
if (req.userinfo.bot.main) {
res.header('X-Robots-Tag', 'noarchive');
}
if (
req.userinfo.bot.main &&
(level1 === config.urls.year ||
level1 === config.urls.genre ||
level1 === config.urls.country ||
level1 === config.urls.actor ||
level1 === config.urls.director ||
level1 === config.urls.type) &&
(!render.movies || render.movies.length <= 0)
) {
return next({
status: 404,
message: config.l.notFound
});
}
if (typeof render === 'object') {
if (
config.theme === 'default' ||
(req.query.json && level1 === config.urls.search)
) {
if (level1 === config.urls.search) {
res.json({ movies: render.movies });
} else {
res.json(render);
}
if (options.debug) {
options.debug.duration =
new Date() - options.debug.duration.all + 'ms';
console.log(options.debug);
}
} else {
if (template === 'sitemap') {
res.header('Content-Type', 'application/xml');
template = 'desktop' + '/' + template;
} else {
template =
req.userinfo.device === 'desktop' || req.userinfo.device === 'app'
? template
: req.userinfo.device + '/' + template;
}
if (typeof render.page !== 'object') render.page = {};
if (typeof render.page.custom !== 'object') render.page.custom = {};
fs.access(custom_data, function(err) {
if (!err) {
try {
render.page.custom = require(custom_data);
} catch (e) {
console.error(e);
}
}
fs.access(custom_template, function(err) {
if (err) custom_template = template;
res.render(custom_template, render, function(err, html) {
if (options.debug) {
options.debug.detail.push({
type: 'render',
mem:
Math.round(
(process.memoryUsage().heapUsed / 1024 / 1024) * 100
) / 100,
duration: new Date() - options.debug.duration.current + 'ms'
});
options.debug.duration.current = new Date();
}
if (err) console.log('[renderData] Render Error:', err);
var link_header = '';
if (options.userinfo.alt && render.page && render.page.pathname) {
link_header +=
(link_header ? ', ' : '') +
'<' +
options.userinfo.alt +
render.page.pathname.replace(/\/$/, '') +
'>; rel="alternate"; hreflang="x-default"';
}
if (options.userinfo.ru && render.page && render.page.pathname) {
link_header +=
(link_header ? ', ' : '') +
'<' +
options.userinfo.ru +
render.page.pathname.replace(/\/$/, '') +
'>; rel="alternate"; hreflang="ru"';
}
if (link_header) {
res.header('Link', link_header);
}
res
.status(
render.page && render.page.status_code
? render.page.status_code
: 200
)
.send(html);
if (
config.cache.time &&
render &&
!render.cache &&
!req.userinfo.bot.all
) {
render.cache = true;
CP_cache.set(urlHash, render, function(err) {});
}
if (options.debug) {
options.debug.duration =
new Date() - options.debug.duration.all + 'ms';
console.log(options.debug);
}
});
});
});
}
} else {
if (options.debug) {
options.debug.detail.push({
type: 'cache',
mem:
Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) /
100,
duration: new Date() - options.debug.duration.current + 'ms'
});
options.debug.duration.current = new Date();
}
if (template === 'sitemap') {
res.header('Content-Type', 'application/xml');
res.send(render);
} else {
res.send(render);
}
if (options.debug) {
options.debug.duration = new Date() - options.debug.duration.all + 'ms';
console.log(options.debug);
}
}
}
});
module.exports = router;