Refactor more, fix and design 404
This commit is contained in:
parent
7de374e00b
commit
8521baa6d9
11 changed files with 223 additions and 138 deletions
23
app.js
23
app.js
|
@ -16,33 +16,14 @@ import share from './routes/share';
|
||||||
import itunesProxy from './routes/itunes-proxy';
|
import itunesProxy from './routes/itunes-proxy';
|
||||||
import { routes } from './views/app';
|
import { routes } from './views/app';
|
||||||
import createHandler from './lib/react-handler';
|
import createHandler from './lib/react-handler';
|
||||||
|
import errorHandler from './lib/error-handler';
|
||||||
|
|
||||||
import debuglog from 'debug';
|
import debuglog from 'debug';
|
||||||
const debug = debuglog('match.audio');
|
const debug = debuglog('match.audio');
|
||||||
|
|
||||||
const app = koa();
|
const app = koa();
|
||||||
|
|
||||||
app.use(function* (next) {
|
app.use(errorHandler(routes));
|
||||||
this.set('Server', 'Nintendo 64');
|
|
||||||
try {
|
|
||||||
yield next;
|
|
||||||
} catch (err) {
|
|
||||||
if (!err.status) {
|
|
||||||
debug('Error: %o', err);
|
|
||||||
throw err;
|
|
||||||
} else if (err.status === 404) {
|
|
||||||
let Handler = yield createHandler(routes, this.request.url);
|
|
||||||
|
|
||||||
let App = React.createFactory(Handler);
|
|
||||||
let content = React.renderToString(new App());
|
|
||||||
|
|
||||||
this.body = '<!doctype html>\n' + content;
|
|
||||||
} else {
|
|
||||||
debug('Error: %o', err);
|
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
app.use(bodyparser());
|
app.use(bodyparser());
|
||||||
app.use(compress({flush: zlib.Z_SYNC_FLUSH }));
|
app.use(compress({flush: zlib.Z_SYNC_FLUSH }));
|
||||||
|
|
48
lib/error-handler.js
Normal file
48
lib/error-handler.js
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
import React from 'react';
|
||||||
|
import createHandler from './react-handler';
|
||||||
|
|
||||||
|
import debuglog from 'debug';
|
||||||
|
const debug = debuglog('match.audio');
|
||||||
|
|
||||||
|
export default function (routes) {
|
||||||
|
return function* (next) {
|
||||||
|
this.set('Server', 'Nintendo 64');
|
||||||
|
try {
|
||||||
|
yield next;
|
||||||
|
} catch (err) {
|
||||||
|
if (err.status === 404) {
|
||||||
|
let Handler = yield createHandler(routes, this.request.url);
|
||||||
|
|
||||||
|
let App = React.createFactory(Handler);
|
||||||
|
let content = React.renderToString(new App());
|
||||||
|
|
||||||
|
this.body = '<!doctype html>\n' + content;
|
||||||
|
} else {
|
||||||
|
debug('Error: %o', err);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (404 != this.status) return;
|
||||||
|
|
||||||
|
switch (this.accepts('html', 'json')) {
|
||||||
|
case 'html':
|
||||||
|
this.type = 'html';
|
||||||
|
let Handler = yield createHandler(routes, this.request.url);
|
||||||
|
|
||||||
|
let App = React.createFactory(Handler);
|
||||||
|
let content = React.renderToString(new App());
|
||||||
|
|
||||||
|
this.body = '<!doctype html>\n' + content;
|
||||||
|
break;
|
||||||
|
case 'json':
|
||||||
|
this.body = {
|
||||||
|
message: 'Page Not Found'
|
||||||
|
};
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
this.type = 'text';
|
||||||
|
this.body = 'Page Not Found';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,10 +4,13 @@ import request from 'superagent';
|
||||||
import 'superagent-bluebird-promise';
|
import 'superagent-bluebird-promise';
|
||||||
import { match as urlMatch } from './url';
|
import { match as urlMatch } from './url';
|
||||||
|
|
||||||
export let id = "xbox";
|
import debuglog from 'debug';
|
||||||
|
const debug = debuglog('match.audio:xbox');
|
||||||
|
|
||||||
|
export let id = 'xbox';
|
||||||
|
|
||||||
if (!process.env.XBOX_CLIENT_ID || !process.env.XBOX_CLIENT_SECRET) {
|
if (!process.env.XBOX_CLIENT_ID || !process.env.XBOX_CLIENT_SECRET) {
|
||||||
console.warn("XBOX_CLIENT_ID and XBOX_CLIENT_SECRET environment variables not found, deactivating Xbox Music.");
|
console.warn('XBOX_CLIENT_ID and XBOX_CLIENT_SECRET environment variables not found, deactivating Xbox Music.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const credentials = {
|
const credentials = {
|
||||||
|
@ -15,12 +18,12 @@ const credentials = {
|
||||||
clientSecret: process.env.XBOX_CLIENT_SECRET
|
clientSecret: process.env.XBOX_CLIENT_SECRET
|
||||||
};
|
};
|
||||||
|
|
||||||
const apiRoot = "https://music.xboxlive.com/1/content";
|
const apiRoot = 'https://music.xboxlive.com/1/content';
|
||||||
|
|
||||||
function* getAccessToken() {
|
function* getAccessToken() {
|
||||||
const authUrl = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13";
|
const authUrl = 'https://datamarket.accesscontrol.windows.net/v2/OAuth2-13';
|
||||||
const scope = "http://music.xboxlive.com";
|
const scope = 'http://music.xboxlive.com';
|
||||||
const grantType = "client_credentials";
|
const grantType = 'client_credentials';
|
||||||
|
|
||||||
const data = {
|
const data = {
|
||||||
client_id: credentials.clientId,
|
client_id: credentials.clientId,
|
||||||
|
@ -28,7 +31,7 @@ function* getAccessToken() {
|
||||||
scope: scope,
|
scope: scope,
|
||||||
grant_type: grantType
|
grant_type: grantType
|
||||||
};
|
};
|
||||||
const result = yield request.post(authUrl).send(data).set('Content-type', 'application/x-www-form-urlencoded').promise();
|
const result = yield request.post(authUrl).timeout(10000).send(data).set('Content-type', 'application/x-www-form-urlencoded').promise();
|
||||||
return result.body.access_token;
|
return result.body.access_token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,16 +42,16 @@ function formatResponse(res) {
|
||||||
} else {
|
} else {
|
||||||
result = res.body.Albums.Items[0];
|
result = res.body.Albums.Items[0];
|
||||||
}
|
}
|
||||||
let item = {
|
const item = {
|
||||||
service: "xbox",
|
service: 'xbox',
|
||||||
type: res.body.Tracks ? "track" : "album",
|
type: res.body.Tracks ? 'track' : 'album',
|
||||||
id: result.Id,
|
id: result.Id,
|
||||||
name: result.Name,
|
name: result.Name,
|
||||||
streamUrl: result.Link,
|
streamUrl: result.Link,
|
||||||
purchaseUrl: null,
|
purchaseUrl: null,
|
||||||
artwork: {
|
artwork: {
|
||||||
small: result.ImageUrl.replace("http://", "https://") + "&w=250&h=250",
|
small: result.ImageUrl.replace('http://', 'https://') + '&w=250&h=250',
|
||||||
large: result.ImageUrl.replace("http://", "https://") + "&w=500&h=250"
|
large: result.ImageUrl.replace('http://', 'https://') + '&w=500&h=250'
|
||||||
},
|
},
|
||||||
artist: {
|
artist: {
|
||||||
name: result.Artists[0].Artist.Name
|
name: result.Artists[0].Artist.Name
|
||||||
|
@ -60,43 +63,60 @@ function formatResponse(res) {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function* apiCall(path) {
|
||||||
|
const access_token = yield getAccessToken();
|
||||||
|
return request.get(apiRoot + path).timeout(10000).set('Authorization', 'Bearer ' + access_token).promise();
|
||||||
|
}
|
||||||
|
|
||||||
export const match = urlMatch;
|
export const match = urlMatch;
|
||||||
|
|
||||||
export function* parseUrl(url) {
|
export function* parseUrl(url) {
|
||||||
const parsed = parse(url);
|
const parsed = parse(url);
|
||||||
const parts = parsed.path.split("/");
|
const parts = parsed.path.split('/');
|
||||||
const type = parts[1];
|
const type = parts[1];
|
||||||
const idMatches = parts[4].match(/[\w\-]+/);
|
const idMatches = parts[4].match(/[\w\-]+/);
|
||||||
const id = idMatches[0];
|
const id = idMatches[0];
|
||||||
if (!id) {
|
if (!id) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return yield lookupId("music." + id, type);
|
return yield lookupId('music.' + id, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function* lookupId(id, type) {
|
export function* lookupId(id, type) {
|
||||||
const access_token = yield getAccessToken();
|
const path = '/' + id + '/lookup';
|
||||||
const path = "/" + id + "/lookup";
|
try {
|
||||||
const result = yield request.get(apiRoot + path).set("Authorization", "Bearer " + access_token).promise();
|
const result = yield apiCall(path);
|
||||||
return result ? formatResponse(result) : {service: "xbox"};
|
return formatResponse(result);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.status !== 404) {
|
||||||
|
debug(e.body);
|
||||||
|
}
|
||||||
|
return {service: 'xbox'};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export function* search(data) {
|
export function* search(data) {
|
||||||
var cleanParam = function(str) {
|
var cleanParam = function(str) {
|
||||||
return str.replace(/[\:\?\&]+/, "");
|
return str.replace(/[\:\?\&\(\)\[\]]+/g, '');
|
||||||
}
|
}
|
||||||
let query, album;
|
let query, album;
|
||||||
const type = data.type;
|
const type = data.type;
|
||||||
|
|
||||||
if (type == "album") {
|
if (type == 'album') {
|
||||||
query = cleanParam(data.artist.name.substring(0, data.artist.name.indexOf('&'))) + " " + cleanParam(data.name);
|
query = cleanParam(data.artist.name.substring(0, data.artist.name.indexOf('&'))) + ' ' + cleanParam(data.name);
|
||||||
album = data.name;
|
album = data.name;
|
||||||
} else if (type == "track") {
|
} else if (type == 'track') {
|
||||||
query = cleanParam(data.artist.name.substring(0, data.artist.name.indexOf('&'))) + " " + cleanParam(data.name);
|
query = cleanParam(data.artist.name.substring(0, data.artist.name.indexOf('&'))) + ' ' + cleanParam(data.name);
|
||||||
album = data.album.name
|
album = data.album.name
|
||||||
}
|
}
|
||||||
const access_token = yield getAccessToken();
|
const path = '/music/search?q=' + encodeURIComponent(query) + '&filters=' + type + 's';
|
||||||
const path = "/music/search?q=" + encodeURIComponent(query) + "&filters=" + type + "s";
|
try {
|
||||||
const result = yield request.get(apiRoot + path).set("Authorization", "Bearer " + access_token).promise()
|
const result = yield apiCall(path);
|
||||||
return result ? formatResponse(result) : {service: "xbox"};
|
return formatResponse(result);
|
||||||
|
} catch (e) {
|
||||||
|
if (e.status !== 404) {
|
||||||
|
debug(e.body);
|
||||||
|
}
|
||||||
|
return {service: 'xbox'};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,6 +6,6 @@ export function* match(url, type) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const parts = parsed.path.split("/");
|
const parts = parsed.path.split('/');
|
||||||
return (parts[1] == "album" || parts[1] == "track") && parts[4];
|
return (parts[1] == 'album' || parts[1] == 'track') && parts[4];
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,9 +7,9 @@ const credentials = {
|
||||||
key: process.env.YOUTUBE_KEY,
|
key: process.env.YOUTUBE_KEY,
|
||||||
};
|
};
|
||||||
|
|
||||||
const apiRoot = "https://www.googleapis.com/freebase/v1/topic";
|
const apiRoot = 'https://www.googleapis.com/freebase/v1/topic';
|
||||||
|
|
||||||
export function* get(topic) {
|
export function* get(topic) {
|
||||||
const result = yield request.get(apiRoot + topic + "?key=" + credentials.key).promise();
|
const result = yield request.get(apiRoot + topic + '?key=' + credentials.key).promise();
|
||||||
return result.body;
|
return result.body;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ import 'superagent-bluebird-promise';
|
||||||
import { match as urlMatch } from './url';
|
import { match as urlMatch } from './url';
|
||||||
import freebase from './freebase';
|
import freebase from './freebase';
|
||||||
|
|
||||||
|
import debuglog from 'debug';
|
||||||
|
const debug = debuglog('match.audio:youtube');
|
||||||
|
|
||||||
module.exports.id = 'youtube';
|
module.exports.id = 'youtube';
|
||||||
|
|
||||||
if (!process.env.YOUTUBE_KEY) {
|
if (!process.env.YOUTUBE_KEY) {
|
||||||
|
@ -37,55 +40,58 @@ export function parseUrl(url) {
|
||||||
export function* lookupId(id, type) {
|
export function* lookupId(id, type) {
|
||||||
|
|
||||||
const path = '/videos?part=snippet%2CtopicDetails%2CcontentDetails&id=' + id + '&key=' + credentials.key;
|
const path = '/videos?part=snippet%2CtopicDetails%2CcontentDetails&id=' + id + '&key=' + credentials.key;
|
||||||
|
try {
|
||||||
const result = yield request.get(apiRoot + path).promise();
|
const result = yield request.get(apiRoot + path).promise();
|
||||||
const item = res.body.items[0];
|
const item = result.body.items[0];
|
||||||
if (!item.topicDetails.topicIds) {
|
if (!item.topicDetails.topicIds) {
|
||||||
return {service: 'youtube'};
|
return {service: 'youtube'};
|
||||||
}
|
|
||||||
|
|
||||||
const promises = [];
|
|
||||||
const match = {
|
|
||||||
id: id,
|
|
||||||
service: 'youtube',
|
|
||||||
name: item.snippet.title,
|
|
||||||
type: 'track',
|
|
||||||
album: {name: ''},
|
|
||||||
streamUrl: 'https://youtu.be/' + id,
|
|
||||||
purchaseUrl: null,
|
|
||||||
artwork: {
|
|
||||||
small: item.snippet.thumbnails.medium.url,
|
|
||||||
large: item.snippet.thumbnails.high.url,
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
for (let topic of yield freebase.get(topicId)) {
|
const match = {
|
||||||
const musicalArtist = topic.property['/type/object/type'].values.some((value) => {
|
id: id,
|
||||||
return value.text == 'Musical Artist';
|
service: 'youtube',
|
||||||
});
|
name: item.snippet.title,
|
||||||
|
type: 'track',
|
||||||
const musicalRecording = topic.property['/type/object/type'].values.some(function(value) {
|
album: {name: ''},
|
||||||
return value.text == 'Musical Recording';
|
streamUrl: 'https://youtu.be/' + id,
|
||||||
});
|
purchaseUrl: null,
|
||||||
|
artwork: {
|
||||||
const musicalAlbum = topic.property['/type/object/type'].values.some(function(value) {
|
small: item.snippet.thumbnails.medium.url,
|
||||||
return value.text == 'Musical Album';
|
large: item.snippet.thumbnails.high.url,
|
||||||
})
|
}
|
||||||
|
};
|
||||||
if (musicalArtist) {
|
|
||||||
match.artist = {name: topic.property['/type/object/name'].values[0].text};
|
for (let topic of yield freebase.get(topicId)) {
|
||||||
} else if (musicalRecording) {
|
const musicalArtist = topic.property['/type/object/type'].values.some((value) => {
|
||||||
match.name = topic.property['/type/object/name'].values[0].text;
|
return value.text == 'Musical Artist';
|
||||||
if (topic.property['/music/recording/releases']) {
|
});
|
||||||
match.type = 'album';
|
|
||||||
match.album.name = topic.property['/music/recording/releases'].values[0].text;
|
const musicalRecording = topic.property['/type/object/type'].values.some(function(value) {
|
||||||
|
return value.text == 'Musical Recording';
|
||||||
|
});
|
||||||
|
|
||||||
|
const musicalAlbum = topic.property['/type/object/type'].values.some(function(value) {
|
||||||
|
return value.text == 'Musical Album';
|
||||||
|
})
|
||||||
|
|
||||||
|
if (musicalArtist) {
|
||||||
|
match.artist = {name: topic.property['/type/object/name'].values[0].text};
|
||||||
|
} else if (musicalRecording) {
|
||||||
|
match.name = topic.property['/type/object/name'].values[0].text;
|
||||||
|
if (topic.property['/music/recording/releases']) {
|
||||||
|
match.type = 'album';
|
||||||
|
match.album.name = topic.property['/music/recording/releases'].values[0].text;
|
||||||
|
}
|
||||||
|
} else if (musicalAlbum) {
|
||||||
|
match.name = topic.property['/type/object/name'].values[0].text;
|
||||||
|
match.type = 'album';
|
||||||
}
|
}
|
||||||
} else if (musicalAlbum) {
|
|
||||||
match.name = topic.property['/type/object/name'].values[0].text;
|
|
||||||
match.type = 'album';
|
|
||||||
}
|
}
|
||||||
|
return match;
|
||||||
|
} catch (e) {
|
||||||
|
debug(e.body);
|
||||||
|
return {'service': 'youtube'};
|
||||||
}
|
}
|
||||||
return match;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function* search(data) {
|
export function* search(data) {
|
||||||
|
@ -101,7 +107,6 @@ export function* search(data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const path = '/search?part=snippet&q=' + encodeURIComponent(query) + '&type=video&videoCaption=any&videoCategoryId=10&key=' + credentials.key;
|
const path = '/search?part=snippet&q=' + encodeURIComponent(query) + '&type=video&videoCaption=any&videoCategoryId=10&key=' + credentials.key;
|
||||||
|
|
||||||
const result = yield request.get(apiRoot + path).promise();
|
const result = yield request.get(apiRoot + path).promise();
|
||||||
const item = result.body.items[0];
|
const item = result.body.items[0];
|
||||||
|
|
||||||
|
|
|
@ -214,38 +214,36 @@ h3 {
|
||||||
margin-bottom: 7px;
|
margin-bottom: 7px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.js-video {
|
.error {
|
||||||
height: 0;
|
background: #FE4365;
|
||||||
padding-top: 25px;
|
color: #febdc9;
|
||||||
padding-bottom: 67.5%;
|
|
||||||
margin-bottom: 10px;
|
|
||||||
position: relative;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-video.widescreen {
|
|
||||||
padding-bottom: 57.25%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.js-video embed, .js-video iframe, .js-video object, .js-video video {
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
position: absolute;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.error h1, .error h2 {
|
.error h1, .error h2 {
|
||||||
font-weight: 300;
|
font-weight: 100;
|
||||||
text-align: center;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.error .main h1 {
|
.error .main h1 {
|
||||||
font-size: 2em;
|
font-size: 2em;
|
||||||
margin-bottom: 50px;
|
margin-bottom: 20px;
|
||||||
|
color: #fff;
|
||||||
}
|
}
|
||||||
|
|
||||||
.error h2 {
|
.error h2 {
|
||||||
|
color: #ff7c94;
|
||||||
font-size: 4em;
|
font-size: 4em;
|
||||||
margin-top: 50px;
|
margin-top: 0px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error a {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vertical-center {
|
||||||
|
min-height: 100%; /* Fallback for browsers do NOT support vh unit */
|
||||||
|
min-height: 100vh; /* These two lines are counted as one :-) */
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,9 @@ import co from 'co';
|
||||||
import lookup from '../lib/lookup';
|
import lookup from '../lib/lookup';
|
||||||
import services from '../lib/services';
|
import services from '../lib/services';
|
||||||
|
|
||||||
|
import debuglog from 'debug';
|
||||||
|
const debug = debuglog('match.audio:search');
|
||||||
|
|
||||||
module.exports = function* () {
|
module.exports = function* () {
|
||||||
const url = parse(this.request.body.url);
|
const url = parse(this.request.body.url);
|
||||||
this.assert(url.host, 400, {error: {message: 'You need to submit a url.'}});
|
this.assert(url.host, 400, {error: {message: 'You need to submit a url.'}});
|
||||||
|
@ -26,17 +29,21 @@ module.exports = function* () {
|
||||||
yield this.db.matches.save({_id: item.service + '$$' + item.id, 'created_at': new Date(), services: matches});
|
yield this.db.matches.save({_id: item.service + '$$' + item.id, 'created_at': new Date(), services: matches});
|
||||||
this.body = item;
|
this.body = item;
|
||||||
|
|
||||||
process.nextTick(co.wrap(function* (){
|
process.nextTick(() => {
|
||||||
for (let service of services) {
|
for (let service of services) {
|
||||||
if (service.id === item.service) {
|
if (service.id === item.service) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
matches[service.id] = {service: service.id};
|
matches[service.id] = {service: service.id};
|
||||||
const match = yield service.search(item);
|
co(function* (){
|
||||||
match.matched_at = new Date(); // eslint-disable-line camelcase
|
const match = yield service.search(item);
|
||||||
const update = {};
|
match.matched_at = new Date(); // eslint-disable-line camelcase
|
||||||
update['services.' + match.service] = match;
|
const update = {};
|
||||||
yield this.db.matches.updateOne({_id: item.service + '$$' + item.id}, {'$set': update});
|
update['services.' + match.service] = match;
|
||||||
|
yield this.db.matches.updateOne({_id: item.service + '$$' + item.id}, {'$set': update});
|
||||||
|
}.bind(this)).catch((err) => {
|
||||||
|
debug(err);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}.bind(this)));
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -31,15 +31,13 @@ export default function* (serviceId, type, itemId, format, next) {
|
||||||
const shares = formatAndSort(doc.services, serviceId);
|
const shares = formatAndSort(doc.services, serviceId);
|
||||||
|
|
||||||
if (format === 'json') {
|
if (format === 'json') {
|
||||||
this.body = {shares: shares};
|
return this.body = {shares: shares};
|
||||||
} else {
|
|
||||||
const Handler = yield createHandler(routes, this.request.url);
|
|
||||||
|
|
||||||
const App = React.createFactory(Handler);
|
|
||||||
let content = React.renderToString(new App({shares: shares}));
|
|
||||||
|
|
||||||
content = content.replace('</body></html>', '<script>var shares = ' + JSON.stringify(shares) + '</script></body></html>');
|
|
||||||
|
|
||||||
this.body = '<!doctype html>\n' + content;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const Handler = yield createHandler(routes, this.request.url);
|
||||||
|
const App = React.createFactory(Handler);
|
||||||
|
let content = React.renderToString(new App({shares: shares}));
|
||||||
|
content = content.replace('</body></html>', '<script>var shares = ' + JSON.stringify(shares) + '</script></body></html>');
|
||||||
|
|
||||||
|
this.body = '<!doctype html>\n' + content;
|
||||||
};
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@ import Home from './home';
|
||||||
import Share from './share';
|
import Share from './share';
|
||||||
import Head from './head';
|
import Head from './head';
|
||||||
import ErrorView from './error';
|
import ErrorView from './error';
|
||||||
|
import NotFound from './notfound';
|
||||||
|
|
||||||
const App = React.createClass({
|
const App = React.createClass({
|
||||||
render: function () {
|
render: function () {
|
||||||
|
@ -27,7 +28,7 @@ const routes = (
|
||||||
<Route name='home' handler={App} path='/'>
|
<Route name='home' handler={App} path='/'>
|
||||||
<DefaultRoute handler={Home} />
|
<DefaultRoute handler={Home} />
|
||||||
<Route name='share' path=':service/:type/:id' handler={Share}/>
|
<Route name='share' path=':service/:type/:id' handler={Share}/>
|
||||||
<NotFoundRoute handler={ErrorView}/>
|
<NotFoundRoute handler={NotFound}/>
|
||||||
</Route>
|
</Route>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
27
views/notfound.js
Normal file
27
views/notfound.js
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
import React from 'react';
|
||||||
|
import Head from './head';
|
||||||
|
import Foot from './foot';
|
||||||
|
|
||||||
|
export default React.createClass({
|
||||||
|
|
||||||
|
render: function() {
|
||||||
|
return (
|
||||||
|
<html>
|
||||||
|
<Head {...this.props} />
|
||||||
|
<body>
|
||||||
|
<div className='error vertical-center'>
|
||||||
|
<div className='container main'>
|
||||||
|
<div className='row'>
|
||||||
|
<div className='col-md-12'>
|
||||||
|
<h2>404</h2>
|
||||||
|
<h1>Sorry, it looks like the page you asked for is gone.</h1>
|
||||||
|
<a href='/'>Take Me Home</a> or <a href='https://www.youtube.com/watch?v=gnnIrTLlLyA' target='_blank'>Show Me the Wubs</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
Loading…
Add table
Add a link
Reference in a new issue