Short urls 2 #93

Merged
bones7242 merged 8 commits from short-urls-2 into master 2017-07-20 08:16:30 +02:00
12 changed files with 376 additions and 433 deletions
Showing only changes of commit 2bda35968f - Show all commits

View file

@ -3,152 +3,10 @@ const db = require('../models');
const logger = require('winston'); const logger = require('winston');
const getAllFreePublicClaims = require('../helpers/functions/getAllFreePublicClaims.js'); const getAllFreePublicClaims = require('../helpers/functions/getAllFreePublicClaims.js');
const isFreePublicClaim = require('../helpers/functions/isFreePublicClaim.js'); const isFreePublicClaim = require('../helpers/functions/isFreePublicClaim.js');
const { getShortUrlByClaimId, getClaimIdByShortUrl } = require('../helpers/libraries/serveHelpers.js'); const serveHelpers = require('../helpers/libraries/serveHelpers.js');
function updateFileIfNeeded (uri, localOutpoint, localHeight) {
logger.debug(`Initiating resolve to check outpoint for ${uri}`);
// 1. resolve claim
lbryApi
.resolveUri(uri)
.then(result => {
// check to make sure the result is a claim
if (!result.claim) {
logger.debug('resolve did not return a claim');
return;
}
// logger.debug('resolved result:', result);
const resolvedOutpoint = `${result.claim.txid}:${result.claim.nout}`;
const resolvedHeight = result.claim.height;
const resolvedAddress = result.claim.address;
logger.debug('database outpoint:', localOutpoint);
logger.debug('resolved outpoint:', resolvedOutpoint);
// 2. if the outpoint's match, no further work needed
if (localOutpoint === resolvedOutpoint) {
logger.debug('local outpoint matched');
// 2. if the outpoints don't match, check the height
} else if (localHeight > resolvedHeight) {
logger.debug('local height was greater than resolved height');
// 2. get the resolved claim
} else {
logger.debug(`local outpoint did not match for ${uri}. Initiating update.`);
getClaimAndUpdate(uri, resolvedAddress, resolvedHeight);
}
})
.catch(error => {
logger.error(error);
});
}
function getClaimAndUpdate (uri, address, height) {
// 1. get the claim
lbryApi
.getClaim(uri)
.then(({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) => {
logger.debug(' Get returned outpoint: ', outpoint);
// 2. update the entry in db
db.File
.update({
outpoint,
height, // note: height is coming from the 'resolve', not 'get'.
address, // note: address is coming from the 'resolve', not 'get'.
fileName: file_name,
filePath: download_path,
fileType: mime_type,
nsfw : metadata.stream.metadata.nsfw,
}, {
where: {
name,
claimId: claim_id,
},
})
.then(result => {
logger.debug('successfully updated mysql record', result);
})
.catch(error => {
logger.error('sequelize error', error);
});
})
.catch(error => {
logger.error(`error while getting claim for ${uri} >> `, error);
});
}
function getClaimAndHandleResponse (uri, address, height, resolve, reject) {
lbryApi
.getClaim(uri)
.then(({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) => {
// create entry in the db
logger.silly(`creating "${name}" record in File db`);
db.File
.create({
name,
claimId : claim_id,
address, // note: comes from parent 'resolve,' not this 'get' call
outpoint,
height, // note: comes from parent 'resolve,' not this 'get' call
fileName: file_name,
filePath: download_path,
fileType: mime_type,
nsfw : metadata.stream.metadata.nsfw,
})
.then(result => {
logger.debug('successfully created mysql record');
})
.catch(error => {
logger.error('sequelize create error', error);
});
// resolve the request
resolve({
name,
claimId : claim_id,
fileName: file_name,
filePath: download_path,
fileType: mime_type,
});
})
.catch(error => {
reject(error);
});
}
function getClaimAndReturnResponse (uri, address, height) {
const deferred = new Promise((resolve, reject) => {
lbryApi
.getClaim(uri)
.then(({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) => {
// create entry in the db
logger.silly(`Creating new File record`);
db.File
.create({
name,
claimId : claim_id,
address, // note: passed as an arguent, not from this 'get' call
outpoint,
height, // note: passed as an arguent, not from this 'get' call
fileName: file_name,
filePath: download_path,
fileType: mime_type,
nsfw : metadata.stream.metadata.nsfw,
})
.then(result => {
logger.debug('Successfully created File record');
resolve(result); // note: result.dataValues ?
})
.catch(error => {
logger.debug('db.File.create error');
reject(error);
});
})
.catch(error => {
logger.debug('lbryApi.getClaim error');
reject(error);
});
});
return deferred;
}
module.exports = { module.exports = {
getClaimByName (claimName) { serveClaimByName (claimName) {
const deferred = new Promise((resolve, reject) => { const deferred = new Promise((resolve, reject) => {
// 1. get the top free, public claims // 1. get the top free, public claims
getAllFreePublicClaims(claimName) getAllFreePublicClaims(claimName)
@ -172,11 +30,11 @@ module.exports = {
// serve the file // serve the file
resolve(claim.dataValues); resolve(claim.dataValues);
// trigger update if needed // trigger update if needed
updateFileIfNeeded(uri, claim.dataValues.outpoint, claim.dataValues.height); serveHelpers.updateFileIfNeeded(uri, claim.dataValues.outpoint, claim.dataValues.height);
// 3. otherwise use daemon to retrieve it // 3. otherwise use daemon to retrieve it
} else { } else {
// get the claim and serve it // get the claim and serve it
getClaimAndHandleResponse(uri, address, height, resolve, reject); serveHelpers.getClaimAndHandleResponse(uri, address, height, resolve, reject);
} }
}) })
.catch(error => { .catch(error => {
@ -189,8 +47,8 @@ module.exports = {
}); });
return deferred; return deferred;
}, },
getClaimByClaimId (name, claimId) { serveClaimByClaimId (name, claimId) {
logger.debug(`Getting claim name: ${name} by claimid: ${claimId}`); logger.debug(`serving claim "${name}" with claimid "${claimId}"`);
const deferred = new Promise((resolve, reject) => { const deferred = new Promise((resolve, reject) => {
// 1. check locally for the claim // 1. check locally for the claim
const uri = `${name}#${claimId}`; const uri = `${name}#${claimId}`;
@ -201,37 +59,25 @@ module.exports = {
if (result) { if (result) {
logger.debug('local result found'); logger.debug('local result found');
// return the data for the file to be served // return the data for the file to be served
getShortUrlByClaimId(name, claimId) resolve(result.dataValues);
.then(shortUrl => { serveHelpers.updateFileIfNeeded(uri, result.dataValues.outpoint, result.dataValues.outpoint);
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues);
})
.catch(error => reject(error));
// update the file, as needed
updateFileIfNeeded(uri, result.dataValues.outpoint, result.dataValues.outpoint);
// 3. if a match was not found locally, use the daemon to retrieve the claim & return the db data once it is created // 3. if a match was not found locally, use the daemon to retrieve the claim & return the db data once it is created
} else { } else {
logger.debug('no local result found'); logger.debug('no local result found');
lbryApi lbryApi
.resolveUri(uri) .resolveUri(uri)
.then(result => { .then(result => {
logger.debug('resolve returned successfully');
if (result.claim && isFreePublicClaim(result.claim)) { // check to see if the claim is free & public if (result.claim && isFreePublicClaim(result.claim)) { // check to see if the claim is free & public
// get claim and serve // get claim and serve
getClaimAndReturnResponse(uri, result.claim.address, result.claim.height) serveHelpers
.getClaimAndReturnResponse(uri, result.claim.address, result.claim.height)
.then(result => { .then(result => {
logger.debug('get request returned'); resolve(result.dataValues);
getShortUrlByClaimId(name, claimId)
.then(shortUrl => {
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues);
})
.catch(error => reject(error));
}) })
.catch(error => reject(error)); .catch(error => reject(error));
} else { } else {
logger.debug('Resolve did not return a free, public claim'); logger.debug('Resolve did not return a free, public claim');
resolve(null, null); resolve(null);
} }
}) })
.catch(error => { .catch(error => {
@ -244,12 +90,13 @@ module.exports = {
}); });
return deferred; return deferred;
}, },
getClaimByShortUrl (name, shortUrl) { serveClaimByShortUrl (name, shortUrl) {
const deferred = new Promise((resolve, reject) => { const deferred = new Promise((resolve, reject) => {
let uri; let uri;
let claimId; let claimId;
// 1. validate the claim id & retrieve the full claim id if needed // 1. validate the claim id & retrieve the full claim id if needed
getClaimIdByShortUrl(name, shortUrl) serveHelpers
.getClaimIdByShortUrl(name, shortUrl)
.then(result => { .then(result => {
// 2. check locally for the claim // 2. check locally for the claim
uri = `${name}#${result}`; uri = `${name}#${result}`;
@ -260,10 +107,9 @@ module.exports = {
// 3. if a match is found locally, serve that claim // 3. if a match is found locally, serve that claim
if (result) { if (result) {
// return the data for the file to be served // return the data for the file to be served
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues); resolve(result.dataValues);
// update the file, as needed // update the file, as needed
updateFileIfNeeded(uri, result.dataValues.outpoint, result.dataValues.outpoint); serveHelpers.updateFileIfNeeded(uri, result.dataValues.outpoint, result.dataValues.outpoint);
// 3. if a match was not found locally, use the daemon to retrieve the claim & return the db data once it is created // 3. if a match was not found locally, use the daemon to retrieve the claim & return the db data once it is created
} else { } else {
lbryApi lbryApi
@ -271,16 +117,15 @@ module.exports = {
.then(result => { .then(result => {
if (result.claim && isFreePublicClaim(result.claim)) { // check to see if the claim is free & public if (result.claim && isFreePublicClaim(result.claim)) { // check to see if the claim is free & public
// get claim and serve // get claim and serve
getClaimAndReturnResponse(uri, result.claim.address, result.claim.height) serveHelpers
.getClaimAndReturnResponse(uri, result.claim.address, result.claim.height)
.then(result => { .then(result => {
logger.debug('returned');
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues); resolve(result.dataValues);
}) })
.catch(error => reject(error)); .catch(error => reject(error));
} else { } else {
logger.debug('Resolve did not return a free, public claim'); logger.debug('Resolve did not return a free, public claim');
resolve(null, null); resolve(null);
} }
}) })
.catch(error => reject(error)); .catch(error => reject(error));
@ -290,7 +135,4 @@ module.exports = {
}); });
return deferred; return deferred;
}, },
getAllClaims (claimName) {
return getAllFreePublicClaims(claimName);
},
}; };

View file

@ -0,0 +1,159 @@
const lbryApi = require('../helpers/libraries/lbryApi.js');
const db = require('../models');
const logger = require('winston');
const getAllFreePublicClaims = require('../helpers/functions/getAllFreePublicClaims.js');
const isFreePublicClaim = require('../helpers/functions/isFreePublicClaim.js');
const serveHelpers = require('../helpers/libraries/serveHelpers.js');
module.exports = {
showClaimByName (claimName) {
const deferred = new Promise((resolve, reject) => {
// 1. get the top free, public claims
getAllFreePublicClaims(claimName)
.then(freePublicClaimList => {
// check to make sure some claims were found
if (!freePublicClaimList) {
resolve(null);
return;
}
const name = freePublicClaimList[0].name;
const claimId = freePublicClaimList[0].claim_id;
const uri = `${name}#${claimId}`;
const height = freePublicClaimList[0].height;
const address = freePublicClaimList[0].address;
// 2. check to see if the file is available locally
db.File
.findOne({ where: { name, claimId } })
.then(result => {
// 3. if a matching record is found locally, serve it
if (result) {
// return the data for the file to be served
serveHelpers.getShortUrlByClaimId(name, claimId)
.then(shortUrl => {
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues);
})
.catch(error => reject(error));
// trigger update if needed
serveHelpers.updateFileIfNeeded(uri, result.dataValues.outpoint, result.dataValues.height);
// 3. otherwise use daemon to retrieve it
} else {
// get the claim and serve it
serveHelpers.getClaimAndHandleResponse(uri, address, height, resolve, reject);
}
})
.catch(error => {
reject(error);
});
})
.catch(error => {
reject(error);
});
});
return deferred;
},
showClaimByClaimId (name, claimId) {
logger.debug(`Getting claim name: ${name} by claimid: ${claimId}`);
const deferred = new Promise((resolve, reject) => {
// 1. check locally for the claim
const uri = `${name}#${claimId}`;
db.File
.findOne({ where: { name, claimId } })
.then(result => {
// 3. if a match is found locally, serve that claim
if (result) {
logger.debug('local result found');
// return the data for the file to be served
serveHelpers.getShortUrlByClaimId(name, claimId)
.then(shortUrl => {
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues);
})
.catch(error => reject(error));
// update the file, as needed
serveHelpers.updateFileIfNeeded(uri, result.dataValues.outpoint, result.dataValues.outpoint);
// 3. if a match was not found locally, use the daemon to retrieve the claim & return the db data once it is created
} else {
logger.debug('no local result found');
lbryApi
.resolveUri(uri)
.then(result => {
logger.debug('resolve returned successfully');
if (result.claim && isFreePublicClaim(result.claim)) { // check to see if the claim is free & public
// get claim and serve
serveHelpers.getClaimAndReturnResponse(uri, result.claim.address, result.claim.height)
.then(result => {
logger.debug('get request returned');
serveHelpers.getShortUrlByClaimId(name, claimId)
.then(shortUrl => {
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues);
})
.catch(error => reject(error));
})
.catch(error => reject(error));
} else {
logger.debug('Resolve did not return a free, public claim');
resolve(null, null);
}
})
.catch(error => {
logger.debug('resolve returned an error');
reject(error);
});
}
})
.catch(error => reject(error));
});
return deferred;
},
showClaimByShortUrl (name, shortUrl) {
const deferred = new Promise((resolve, reject) => {
let uri;
let claimId;
// 1. validate the claim id & retrieve the full claim id if needed
serveHelpers.getClaimIdByShortUrl(name, shortUrl)
.then(result => {
// 2. check locally for the claim
uri = `${name}#${result}`;
claimId = result;
return db.File.findOne({ where: { name, claimId } });
})
.then(result => {
// 3. if a match is found locally, serve that claim
if (result) {
// return the data for the file to be served
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues);
// update the file, as needed
serveHelpers.updateFileIfNeeded(uri, result.dataValues.outpoint, result.dataValues.outpoint);
// 3. if a match was not found locally, use the daemon to retrieve the claim & return the db data once it is created
} else {
lbryApi
.resolveUri(uri)
.then(result => {
if (result.claim && isFreePublicClaim(result.claim)) { // check to see if the claim is free & public
// get claim and serve
serveHelpers.getClaimAndReturnResponse(uri, result.claim.address, result.claim.height)
.then(result => {
logger.debug('returned');
result.dataValues['shortUrl'] = shortUrl;
resolve(result.dataValues);
})
.catch(error => reject(error));
} else {
logger.debug('Resolve did not return a free, public claim');
resolve(null, null);
}
})
.catch(error => reject(error));
}
})
.catch(error => reject(error));
});
return deferred;
},
showAllClaims (claimName) {
return getAllFreePublicClaims(claimName);
},
};

View file

@ -91,11 +91,9 @@ module.exports = {
params: { uri }, params: { uri },
}) })
.then(({ data }) => { .then(({ data }) => {
logger.debug('resolved successfully', data); if (data.result[uri].error) { // check for errors
// check for errors
if (data.result[uri].error) {
reject(data.result[uri].error); reject(data.result[uri].error);
} else { } else { // if no errors, resolve
resolve(data.result[uri]); resolve(data.result[uri]);
} }
}) })

View file

@ -1,21 +1,73 @@
const logger = require('winston'); const logger = require('winston');
// const db = require('../../models'); const db = require('../../models');
const { getClaimsList } = require('./lbryApi'); const lbryApi = require('./lbryApi');
function determineShortUrl (claimId, claimList) { function determineShortUrl (claimId, claimList) {
let shortUrl = claimId.substring(0, 1); logger.debug('determining short url based on claim id and claim list');
let i = 1; const thisClaim = claimList.filter(claim => { // find this claim in the list & store it
claimList = claimList.filter(claim => { // filter out this exact claim id return claim.claim_id === claimId;
})[0];
claimList = claimList.filter(claim => { // remove this claim from the claim list
return claim.claim_id !== claimId; return claim.claim_id !== claimId;
}); });
while (claimList.length !== 0) { // filter out matching claims until none or left if (claimList.length === 0) { // if there are no other claims, return the first letter of the claim id
shortUrl = claimId.substring(0, i); return claimId.substring(0, 1);
claimList = claimList.filter(claim => { } else {
return (claim.claim_id.substring(0, i) === shortUrl); let i = 0;
const claimListCopy = claimList;
while (claimList.length !== 0) { // filter out matching claims
i++;
claimList = claimList.filter(claim => {
return (claim.claim_id.substring(0, i) === claimId.substring(0, i));
});
}
i -= 1;
const lastMatch = claimId.substring(0, i);
const matchingClaims = claimListCopy.filter(claim => {
return (claim.claim_id.substring(0, i) === lastMatch);
}); });
i++; for (let j = 0; j < matchingClaims.length; j++) {
if (matchingClaims[j].height < thisClaim.height) {
return claimId.substring(0, i + 1);
}
}
return claimId.substring(0, i);
} }
return (shortUrl); }
function getClaimAndUpdate (uri, address, height) {
// 1. get the claim
lbryApi
.getClaim(uri)
.then(({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) => {
logger.debug(' Get returned outpoint: ', outpoint);
// 2. update the entry in db
db.File
.update({
outpoint,
height, // note: height is coming from the 'resolve', not 'get'.
address, // note: address is coming from the 'resolve', not 'get'.
fileName: file_name,
filePath: download_path,
fileType: mime_type,
nsfw : metadata.stream.metadata.nsfw,
}, {
where: {
name,
claimId: claim_id,
},
})
.then(result => {
logger.debug('successfully updated mysql record', result);
})
.catch(error => {
logger.error('sequelize error', error);
});
})
.catch(error => {
logger.error(`error while getting claim for ${uri} >> `, error);
});
} }
module.exports = { module.exports = {
@ -48,7 +100,7 @@ module.exports = {
}, },
getClaimIdByShortUrl (name, shortUrl) { getClaimIdByShortUrl (name, shortUrl) {
const deferred = new Promise((resolve, reject) => { const deferred = new Promise((resolve, reject) => {
getClaimsList(name) lbryApi.getClaimsList(name)
.then(({ claims }) => { .then(({ claims }) => {
const regex = new RegExp(`^${shortUrl}`); const regex = new RegExp(`^${shortUrl}`);
logger.debug('regex:', regex); logger.debug('regex:', regex);
@ -80,7 +132,7 @@ module.exports = {
getShortUrlByClaimId (name, claimId) { getShortUrlByClaimId (name, claimId) {
const deferred = new Promise((resolve, reject) => { const deferred = new Promise((resolve, reject) => {
// get a list of all the claims // get a list of all the claims
getClaimsList(name) lbryApi.getClaimsList(name)
// find the smallest possible unique url for this claim // find the smallest possible unique url for this claim
.then(({ claims }) => { .then(({ claims }) => {
const shortUrl = determineShortUrl(claimId, claims); const shortUrl = determineShortUrl(claimId, claims);
@ -95,4 +147,109 @@ module.exports = {
determineShortUrl (claimId, claimList) { determineShortUrl (claimId, claimList) {
return determineShortUrl(claimId, claimList); return determineShortUrl(claimId, claimList);
}, },
updateFileIfNeeded (uri, localOutpoint, localHeight) {
logger.debug(`Initiating resolve to check outpoint for ${uri}`);
// 1. resolve claim
lbryApi
.resolveUri(uri)
.then(result => {
// check to make sure the result is a claim
if (!result.claim) {
logger.debug('resolve did not return a claim');
return;
}
// logger.debug('resolved result:', result);
const resolvedOutpoint = `${result.claim.txid}:${result.claim.nout}`;
const resolvedHeight = result.claim.height;
const resolvedAddress = result.claim.address;
logger.debug('database outpoint:', localOutpoint);
logger.debug('resolved outpoint:', resolvedOutpoint);
// 2. if the outpoint's match, no further work needed
if (localOutpoint === resolvedOutpoint) {
logger.debug('local outpoint matched');
// 2. if the outpoints don't match, check the height
} else if (localHeight > resolvedHeight) {
logger.debug('local height was greater than resolved height');
// 2. get the resolved claim
} else {
logger.debug(`local outpoint did not match for ${uri}. Initiating update.`);
getClaimAndUpdate(uri, resolvedAddress, resolvedHeight);
}
})
.catch(error => {
logger.error(error);
});
},
getClaimAndHandleResponse (uri, address, height, resolve, reject) {
lbryApi
.getClaim(uri)
.then(({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) => {
// create entry in the db
logger.silly(`creating "${name}" record in File db`);
db.File
.create({
name,
claimId : claim_id,
address, // note: comes from parent 'resolve,' not this 'get' call
outpoint,
height, // note: comes from parent 'resolve,' not this 'get' call
fileName: file_name,
kauffj commented 2017-07-20 16:02:12 +02:00 (Migrated from github.com)
Review

Technically two claims could have the same height, though this is rather unlikely.

Technically two claims could have the same height, though this is rather unlikely.
filePath: download_path,
fileType: mime_type,
nsfw : metadata.stream.metadata.nsfw,
})
.then(result => {
logger.debug('successfully created mysql record');
})
.catch(error => {
logger.error('sequelize create error', error);
});
// resolve the request
resolve({
name,
claimId : claim_id,
fileName: file_name,
filePath: download_path,
fileType: mime_type,
});
})
.catch(error => {
reject(error);
});
},
getClaimAndReturnResponse (uri, address, height) {
const deferred = new Promise((resolve, reject) => {
lbryApi
.getClaim(uri)
.then(({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) => {
// create entry in the db
logger.silly(`Creating new File record`);
db.File
.create({
name,
claimId : claim_id,
address, // note: passed as an arguent, not from this 'get' call
outpoint,
height, // note: passed as an arguent, not from this 'get' call
fileName: file_name,
filePath: download_path,
fileType: mime_type,
nsfw : metadata.stream.metadata.nsfw,
})
.then(result => {
logger.debug('Successfully created File record');
resolve(result); // note: result.dataValues ?
})
.catch(error => {
logger.debug('db.File.create error');
reject(error);
});
})
.catch(error => {
logger.debug('lbryApi.getClaim error');
reject(error);
});
});
return deferred;
},
}; };

View file

@ -1,96 +0,0 @@
var canvas = document.getElementById('meme-canvas');
var img = document.getElementById('start-image');
var canvasWidth;
var canvasHeight;
var fontSize = 28;
var topText = document.getElementById('top-text');
var bottomText = document.getElementById('bottom-text');
var ctx = canvas.getContext('2d');
// create the canvas
img.onload = function() {
// get dimensions of the start img
canvasWidth = img.width;
canvasHeight = img.height;
// hide start image
img.hidden = true;
// size the canvas
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// draw the starting meme
drawMeme()
}
function newCanvas(image){
// hide start image
img = image;
// get dimensions of the start img
canvasHeight = canvasWidth * (img.height / img.width);
// size the canvas
canvas.width = canvasWidth;
canvas.height = canvasHeight;
// draw the meme
drawMeme()
}
// if the text changes, re-draw the meme
topText.addEventListener('keyup', drawMeme);
bottomText.addEventListener('keyup', drawMeme);
// draw the image and draw the text over it
function drawMeme() {
ctx.clearRect(0, 0, canvasWidth, canvasHeight);
ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight);
ctx.lineWidth = 4;
ctx.font = fontSize + 'px sans-serif';
ctx.strokeStyle = 'black';
ctx.fillStyle = 'white';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
var text1 = topText.value;
text1 = text1.toUpperCase();
x = canvasWidth / 2;
y = 5;
wrapText(ctx, text1, x, y, canvasWidth, fontSize, false);
ctx.textBaseline = 'bottom';
var text2 = bottomText.value;
text2 = text2.toUpperCase();
y = canvasHeight - 5;
wrapText(ctx, text2, x, y, canvasHeight, fontSize, true);
}
function wrapText(context, text, x, y, maxWidth, lineHeight, fromBottom) {
var pushMethod = (fromBottom)?'unshift':'push';
lineHeight = (fromBottom)?-lineHeight:lineHeight;
var lines = [];
var y = y;
var line ='';
var words = text.split(' ');
for (var i = 0; i < words.length; i++) {
var testLine = line + ' ' + words[i];
var metrics = context.measureText(testLine);
var testWidth = metrics.width;
if (testWidth > maxWidth) {
lines[pushMethod](line);
line = words[i] + ' ';
} else {
line = testLine;
}
}
lines[pushMethod](line);
for (var k in lines ) {
context.strokeText(lines[k], x, y + lineHeight * k);
context.fillText(lines[k], x, y + lineHeight * k);
}
}

View file

@ -1,50 +0,0 @@
// define variables
var socket = io();
var uploader = new SocketIOFileUpload(socket);
var stagedFiles = null;
var license = 'Creative Commons';
var nsfw = false;
var nameInput = document.getElementById("publish-name");
/* socketio-file-upload listeners */
uploader.addEventListener('start', function(event){
event.file.meta.name = nameInput.value;
event.file.meta.license = license;
event.file.meta.nsfw = nsfw;
event.file.meta.type = stagedFiles[0].type;
// re-set the html in the publish area
document.getElementById('publish-active-area').innerHTML = '<div id="publish-status"></div><div id="progress-bar"></div>';
// start a progress animation
createProgressBar(document.getElementById('progress-bar'), 12);
// google analytics
ga('send', {
hitType: 'event',
eventCategory: 'publish',
eventAction: nameInput.value
});
});
uploader.addEventListener('progress', function(event){
var percent = event.bytesLoaded / event.file.size * 100;
updatePublishStatus('File is ' + percent.toFixed(2) + '% loaded to the server');
});
/* socket.io message listeners */
socket.on('publish-status', function(msg){
updatePublishStatus(msg);
});
socket.on('publish-failure', function(msg){
document.getElementById('publish-active-area').innerHTML = '<p>' + JSON.stringify(msg) + '</p><p> --(✖╭╮✖)→ </p><strong>For help, post the above error text in the #speech channel on the <a href="https://lbry.slack.com/" target="_blank">LBRY slack</a></strong>';
});
socket.on('publish-complete', function(msg){
var publishResults;
var directUrl = '/' + msg.name + '/' + msg.result.claim_id;
// build new publish area
publishResults = '<p>Your publish is complete! View it here:</p>';
publishResults += '<p><a target="_blank" href="' + directUrl + '">spee.ch' + directUrl + '</a></p>';
publishResults += '<p><button class="copy-button">Copy to clipboard</button></p>';
publishResults += '<p><a target="_blank" href="https://explorer.lbry.io/#!/transaction/' + msg.result.txid + '">View the transaction details</a></p>';
publishResults += '<a href="/meme-fodder/play"><button>Reload</button></a></p>';
// update publish area
document.getElementById('publish-active-area').innerHTML = publishResults;
});

View file

@ -1,16 +1,16 @@
const { getClaimByClaimId, getClaimByShortUrl, getClaimByName } = require('../controllers/serveController.js'); const { serveClaimByName, serveClaimByClaimId, serveClaimByShortUrl } = require('../controllers/serveController.js');
const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js'); const { postToStats, sendGoogleAnalytics } = require('../controllers/statsController.js');
const errorHandlers = require('../helpers/libraries/errorHandlers.js'); const errorHandlers = require('../helpers/libraries/errorHandlers.js');
const { serveFile } = require('../helpers/libraries/serveHelpers.js'); const { serveFile } = require('../helpers/libraries/serveHelpers.js');
function validateClaimId (name, claimId) { function retrieveAssetInfo (name, claimId) {
const deferred = new Promise((resolve, reject) => { const deferred = new Promise((resolve, reject) => {
// if claim id is full 40 chars, retrieve the shortest possible url // if claim id is full 40 chars, retrieve the shortest possible url
if (claimId.length === 40) { if (claimId.length === 40) {
resolve(getClaimByClaimId(name, claimId)); resolve(serveClaimByClaimId(name, claimId));
// if the claim id is shorter than 40, retrieve the full claim id & shortest possible url // if the claim id is shorter than 40, retrieve the full claim id & shortest possible url
} else if (claimId.length < 40) { } else if (claimId.length < 40) {
resolve(getClaimByShortUrl(name, claimId)); resolve(serveClaimByShortUrl(name, claimId));
} else { } else {
reject(new Error('That Claim Id is longer than 40 characters.')); reject(new Error('That Claim Id is longer than 40 characters.'));
} }
@ -24,7 +24,7 @@ module.exports = (app) => {
// google analytics // google analytics
sendGoogleAnalytics('serve', headers, ip, originalUrl); sendGoogleAnalytics('serve', headers, ip, originalUrl);
// begin image-serve processes // begin image-serve processes
validateClaimId(params.name, params.claim_id) retrieveAssetInfo(params.name, params.claim_id)
.then((fileInfo) => { .then((fileInfo) => {
// check to make sure a file was found // check to make sure a file was found
if (!fileInfo) { if (!fileInfo) {
@ -32,7 +32,7 @@ module.exports = (app) => {
return; return;
} }
// serve the file or the show route // serve the file or the show route
if (headers['accept']) { // note: added b/c some requests errored out due to no accept param in header if (headers['accept']) {
const mimetypes = headers['accept'].split(','); const mimetypes = headers['accept'].split(',');
if (mimetypes.includes('text/html')) { if (mimetypes.includes('text/html')) {
postToStats('show', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success'); postToStats('show', originalUrl, ip, fileInfo.name, fileInfo.claimId, 'success');
@ -55,7 +55,7 @@ module.exports = (app) => {
// google analytics // google analytics
sendGoogleAnalytics('serve', headers, ip, originalUrl); sendGoogleAnalytics('serve', headers, ip, originalUrl);
// begin image-serve processes // begin image-serve processes
getClaimByName(params.name) serveClaimByName(params.name)
.then(fileInfo => { .then(fileInfo => {
// check to make sure a file was found // check to make sure a file was found
if (!fileInfo) { if (!fileInfo) {

View file

@ -1,15 +1,15 @@
const errorHandlers = require('../helpers/libraries/errorHandlers.js'); const errorHandlers = require('../helpers/libraries/errorHandlers.js');
const { getClaimByClaimId, getClaimByShortUrl, getClaimByName, getAllClaims } = require('../controllers/serveController.js'); const { showClaimByName, showClaimByClaimId, showClaimByShortUrl, showAllClaims } = require('../controllers/showController.js');
const { postToStats, getStatsSummary, getTrendingClaims } = require('../controllers/statsController.js'); const { postToStats, getStatsSummary, getTrendingClaims } = require('../controllers/statsController.js');
function validateClaimId (name, claimId) { function retrieveAssetInfo (name, claimId) {
const deferred = new Promise((resolve, reject) => { const deferred = new Promise((resolve, reject) => {
// if claim id is full 40 chars, retrieve the shortest possible url // if claim id is full 40 chars, retrieve the shortest possible url
if (claimId.length === 40) { if (claimId.length === 40) {
resolve(getClaimByClaimId(name, claimId)); resolve(showClaimByClaimId(name, claimId));
// if the claim id is shorter than 40, retrieve the full claim id & shortest possible url // if the claim id is shorter than 40, retrieve the full claim id & shortest possible url
} else if (claimId.length < 40) { } else if (claimId.length < 40) {
resolve(getClaimByShortUrl(name, claimId)); resolve(showClaimByShortUrl(name, claimId));
} else { } else {
reject(new Error('That Claim Id is longer than 40 characters.')); reject(new Error('That Claim Id is longer than 40 characters.'));
} }
@ -49,22 +49,10 @@ module.exports = (app) => {
errorHandlers.handleRequestError(error, res); errorHandlers.handleRequestError(error, res);
}); });
}); });
// route to show the meme-fodder meme maker
app.get('/meme-fodder/play', ({ ip, originalUrl }, res) => {
// get and render the content
getAllClaims('meme-fodder')
.then(orderedFreePublicClaims => {
postToStats('show', originalUrl, ip, null, null, 'success');
res.status(200).render('memeFodder', { claims: orderedFreePublicClaims });
})
.catch(error => {
errorHandlers.handleRequestError('show', originalUrl, ip, error, res);
});
});
// route to display all free public claims at a given name // route to display all free public claims at a given name
app.get('/:name/all', ({ ip, originalUrl, params }, res) => { app.get('/:name/all', ({ ip, originalUrl, params }, res) => {
// get and render the content // get and render the content
getAllClaims(params.name) showAllClaims(params.name)
.then(orderedFreePublicClaims => { .then(orderedFreePublicClaims => {
if (!orderedFreePublicClaims) { if (!orderedFreePublicClaims) {
res.status(307).render('noClaims'); res.status(307).render('noClaims');
@ -80,7 +68,7 @@ module.exports = (app) => {
// route to show a specific asset // route to show a specific asset
app.get('/show/:name/:claim_id', ({ ip, originalUrl, params }, res) => { app.get('/show/:name/:claim_id', ({ ip, originalUrl, params }, res) => {
// begin image-serve processes // begin image-serve processes
validateClaimId(params.name, params.claim_id) retrieveAssetInfo(params.name, params.claim_id)
.then((fileInfo) => { .then((fileInfo) => {
console.log('SHORT URL:', fileInfo.shortUrl); console.log('SHORT URL:', fileInfo.shortUrl);
// check to make sure a file was found // check to make sure a file was found
@ -93,13 +81,13 @@ module.exports = (app) => {
res.status(200).render('show', { fileInfo }); res.status(200).render('show', { fileInfo });
}) })
.catch(error => { .catch(error => {
errorHandlers.handleRequestError('serve', originalUrl, ip, error, res); errorHandlers.handleRequestError('show', originalUrl, ip, error, res);
}); });
}); });
// route to show the winning free, public claim // route to show the winning free, public claim
app.get('/show/:name', ({ ip, originalUrl, params }, res) => { app.get('/show/:name', ({ ip, originalUrl, params }, res) => {
// get and render the content // get and render the content
getClaimByName(params.name) showClaimByName(params.name)
.then(fileInfo => { .then(fileInfo => {
// check to make sure a file was found // check to make sure a file was found
if (!fileInfo) { if (!fileInfo) {
@ -111,7 +99,7 @@ module.exports = (app) => {
res.status(200).render('show', { fileInfo }); res.status(200).render('show', { fileInfo });
}) })
.catch(error => { .catch(error => {
errorHandlers.handleRequestError('serve', originalUrl, ip, error, res); errorHandlers.handleRequestError('show', originalUrl, ip, error, res);
}); });
}); });
}; };

View file

@ -1,15 +0,0 @@
<div class="wrapper">
{{> topBar}}
<div class="full">
{{> memeFodderMaker}}
{{> memeFodderResults}}
</div>
{{> footer}}
</div>
<script src="/socket.io/socket.io.js"></script>
<script src="/siofu/client.js"></script>
<script src="/assets/js/generalFunctions.js"></script>
<script src="/assets/js/memeFodder-draw.js"></script>
<script src="/assets/js/memeFodder-publish.js"></script>

View file

@ -6,19 +6,21 @@
<h2 class="subheader">Links</h2> <h2 class="subheader">Links</h2>
{{!--short direct link to asset--}} {{!--short direct link to asset--}}
<div class="share-option"> <div class="share-option">
<a href="/{{fileInfo.name}}/{{fileInfo.shortUrl}}">Direct Link</a> <a href="/{{fileInfo.name}}/{{fileInfo.shortUrl}}">Permanent Short Link</a>
<div class="input-error" id="input-error-copy-direct-link" hidden="true"></div> (most convenient)
<div class="input-error" id="input-error-copy-short-link" hidden="true"></div>
<br/> <br/>
<input type="text" id="direct-link" class="link" readonly spellcheck="false" value="https://spee.ch/{{fileInfo.name}}/{{fileInfo.shortUrl}}" onclick="select()"/> <input type="text" id="short-link" class="link" readonly spellcheck="false" value="https://spee.ch/{{fileInfo.name}}/{{fileInfo.shortUrl}}" onclick="select()"/>
<button class="copy-button" data-elementtocopy="direct-link" onclick="copyToClipboard(event)">copy</button> <button class="copy-button" data-elementtocopy="short-link" onclick="copyToClipboard(event)">copy</button>
</div> </div>
{{!-- link to show route for asset--}} {{!-- link to show route for asset--}}
<div class="share-option"> <div class="share-option">
<a href="/show/{{fileInfo.name}}/{{fileInfo.shortUrl}}">Details Link</a> <a href="/{{fileInfo.name}}/{{fileInfo.claimId}}">Permanent Long Link</a>
<div class="input-error" id="input-error-copy-show-link" hidden="true"></div> (fastest service)
<div class="input-error" id="input-error-copy-long-link" hidden="true"></div>
</br> </br>
<input type="text" id="show-link" class="link" readonly onclick="select()" spellcheck="false" value="https://spee.ch/show/{{fileInfo.name}}/{{fileInfo.shortUrl}}"/> <input type="text" id="long-link" class="link" readonly onclick="select()" spellcheck="false" value="https://spee.ch/{{fileInfo.name}}/{{fileInfo.claimId}}"/>
<button class="copy-button" data-elementtocopy="show-link" onclick="copyToClipboard(event)">copy</button> <button class="copy-button" data-elementtocopy="long-link" onclick="copyToClipboard(event)">copy</button>
</div> </div>
{{!-- html text for embedding asset--}} {{!-- html text for embedding asset--}}
<div class="share-option"> <div class="share-option">

View file

@ -1,31 +0,0 @@
<div class="panel" id="meme-fodder-maker">
<div>
<h2>#LBRYMemeFodder</h2>
<h3>Congratulations, you found the /meme-fodder game!</h3>
<p>Create a meme based on the current <i>lbry://meme-fodder</i> claims using the tool below.</p>
</div>
<div class="col-left">
<canvas id="meme-canvas">
If you can see this, the meme generator is not supported by your browser.
</canvas>
<img id="start-image" src="/meme-fodder" alt="a picture to make your meme with"/>
</div>
<div class="col-right">
<textarea id="direct-link-holder" hidden="true">No URL yet</textarea>
<div id="publish-active-area">
<p>
<label>Meme:</label><br/>
<input id="top-text" type="text" value="Hello" /><br/>
<input id="bottom-text" type="text" value="world!" /><br/>
</p>
<p>
<label for="publish-name">Claim Name:</label></br>
<input id="publish-name" type="text" placeholder="Your claim name" />
</p>
<p>
<button onclick="startPublish()">Save and Publish</button>
</p>
</div>
</div>
<p class="stop-float">Got a masterpiece? <a href="https://twitter.com/hashtag/LBRYMemeFodder" target="_blank">Share it with the community</a> and see what they think!</p>
</div>

View file

@ -1,11 +0,0 @@
<div class="stop-float panel">
<h2>Recent Meme Fodder</h2>
<div class="row">
<p>Below are the free, public images published to <a href="lbry://meme-fodder">lbry://meme-fodder</a>. Want to put a different image on the chopping block? Go publish it!</p>
</div>
<div class="row">
{{#each claims}}
<img class="asset-small" src="/{{this.name}}/{{this.claim_id}}" onclick="newCanvas(this)"/>
{{/each}}
</div>
</div>