From 54d92a2c083524fd33cc3dfd479b302bd6e85cdd Mon Sep 17 00:00:00 2001 From: bill bittner Date: Mon, 19 Jun 2017 22:37:36 -0700 Subject: [PATCH 1/7] basic meme builder in place --- routes/show-routes.js | 5 ++ views/memeFodder.handlebars | 90 +++++++++++++++++++++++++++++ views/partials/memeMaker.handlebars | 23 ++++++++ 3 files changed, 118 insertions(+) create mode 100644 views/memeFodder.handlebars create mode 100644 views/partials/memeMaker.handlebars diff --git a/routes/show-routes.js b/routes/show-routes.js index 0c8b5e6e..65fcb562 100644 --- a/routes/show-routes.js +++ b/routes/show-routes.js @@ -3,6 +3,11 @@ const showController = require('../controllers/showController.js'); const logger = require('winston'); module.exports = (app, ua, googleAnalyticsId) => { + // route to fetch all free public claims + app.get('/meme-fodder', ({ originalUrl }, res) => { + logger.debug(`GET request on ${originalUrl}`); + res.status(200).render('memeFodder'); + }); // route to fetch all free public claims app.get('/:name/all', ({ originalUrl, params }, res) => { logger.debug(`GET request on ${originalUrl}`); diff --git a/views/memeFodder.handlebars b/views/memeFodder.handlebars new file mode 100644 index 00000000..7b952641 --- /dev/null +++ b/views/memeFodder.handlebars @@ -0,0 +1,90 @@ +
+ {{> topBar}} +
+ {{> memeMaker}} +
+
+ + diff --git a/views/partials/memeMaker.handlebars b/views/partials/memeMaker.handlebars new file mode 100644 index 00000000..3e4249fa --- /dev/null +++ b/views/partials/memeMaker.handlebars @@ -0,0 +1,23 @@ +
+
+
+

Meme Generator

+
+
+
+
+
+ + If you can see this, canvas is not supported. + + +
+
+ + +
+
+
+
+
+
\ No newline at end of file From 0eebf30d480d3750708b59181f21fc5a1e0f7401 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 20 Jun 2017 13:07:49 -0700 Subject: [PATCH 2/7] added file download to meme --- public/assets/css/style.css | 6 + public/assets/js/memeDraw.js | 98 +++++++++++++ public/assets/js/memePublish.js | 144 ++++++++++++++++++++ routes/show-routes.js | 2 +- views/memeFodder.handlebars | 89 +----------- views/partials/documentation.handlebars | 2 +- views/partials/examples.handlebars | 28 ++-- views/partials/memeFodderResults.handlebars | 14 ++ views/partials/memeMaker.handlebars | 35 ++++- 9 files changed, 319 insertions(+), 99 deletions(-) create mode 100644 public/assets/js/memeDraw.js create mode 100644 public/assets/js/memePublish.js create mode 100644 views/partials/memeFodderResults.handlebars diff --git a/public/assets/css/style.css b/public/assets/css/style.css index 4d815c6f..b9395e60 100644 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -15,4 +15,10 @@ .row { margin: 10px 0px 10px 0px; +} + +canvas { + background-color: blue; + width: 100%; + height: auto; } \ No newline at end of file diff --git a/public/assets/js/memeDraw.js b/public/assets/js/memeDraw.js new file mode 100644 index 00000000..4e4ea0a2 --- /dev/null +++ b/public/assets/js/memeDraw.js @@ -0,0 +1,98 @@ +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'); +var downloadLink = document.getElementById("meme-download-link"); +var memeFileName = document.getElementById("meme-file-name"); + +// 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() +} + +// 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 = 0; + + wrapText(ctx, text1, x, y, canvasWidth, fontSize, false); + + ctx.textBaseline = 'bottom'; + var text2 = bottomText.value; + text2 = text2.toUpperCase(); + y = canvasHeight; + + 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); + } +} + +// save the meme +function downloadMeme() { + var dt = canvas.toDataURL('image/jpeg'); + this.href = dt; +}; + +function updateFileName(){ + downloadLink.download = this.value; +} + +memeFileName.addEventListener('keyup', updateFileName); + +downloadLink.addEventListener('click', downloadMeme, false); \ No newline at end of file diff --git a/public/assets/js/memePublish.js b/public/assets/js/memePublish.js new file mode 100644 index 00000000..99db22d9 --- /dev/null +++ b/public/assets/js/memePublish.js @@ -0,0 +1,144 @@ + +// define variables +var socket = io(); +var uploader = new SocketIOFileUpload(socket); +var stagedFiles = null; + +/* helper functions */ +// create a progress animation +function createProgressBar(element, size){ + var x = 1; + var adder = 1; + function addOne(){ + var bars = '

|'; + for (var i = 0; i < x; i++){ bars += ' | '; } + bars += '

'; + element.innerHTML = bars; + if (x === size){ + adder = -1; + } else if ( x === 0){ + adder = 1; + } + x += adder; + }; + setInterval(addOne, 300); +} +// preview file and stage the image for upload +function previewAndStageFile(selectedFile){ + var preview = document.getElementById('image-preview'); + var dropzone = document.getElementById('drop-zone'); + var previewReader = new FileReader(); + + preview.style.display = 'block'; + dropzone.style.display = 'none'; + + previewReader.onloadend = function () { + preview.src = previewReader.result; + }; + + if (selectedFile) { + previewReader.readAsDataURL(selectedFile); // reads the data and sets the img src + document.getElementById('publish-name').value = selectedFile.name.substring(0, selectedFile.name.indexOf('.')); // updates metadata inputs + stagedFiles = [selectedFile]; // stores the selected file for upload + } else { + preview.src = ''; + } +} +// update the publish status +function updatePublishStatus(msg){ + document.getElementById('publish-status').innerHTML = msg; +} +// process the drop-zone drop +function drop_handler(ev) { + console.log("drop"); + ev.preventDefault(); + // if dropped items aren't files, reject them + var dt = ev.dataTransfer; + if (dt.items) { + if (dt.items[0].kind == 'file') { + var droppedFile = dt.items[0].getAsFile(); + previewAndStageFile(droppedFile); + } else { + console.log("no files were found") + } + } else { + console.log("no items were found") + } +} +// prevent the browser's default drag behavior +function dragover_handler(ev) { + ev.preventDefault(); +} +// remove all of the drag data +function dragend_handler(ev) { + var dt = ev.dataTransfer; + if (dt.items) { + for (var i = 0; i < dt.items.length; i++) { + dt.items.remove(i); + } + } else { + ev.dataTransfer.clearData(); + } +} + +/* configure the submit button */ +document.getElementById('publish-submit').addEventListener('click', function(event){ + event.preventDefault(); + // make sure a file was selected + if (stagedFiles) { + // make sure only 1 file was selected + if (stagedFiles.length > 1) { + alert("Only one file allowed at a time"); + return; + } + // make sure the content type is acceptable + switch (stagedFiles[0].type) { + case "image/png": + case "image/jpeg": + case "image/gif": + case "video/mp4": + uploader.submitFiles(stagedFiles); + break; + default: + alert("Only .png, .jpeg, .gif, and .mp4 files are currently supported"); + break; + } + } +}) + +/* socketio-file-upload listeners */ +uploader.addEventListener('start', function(event){ + var name = document.getElementById('publish-name').value; + var license = document.getElementById('publish-license').value; + var nsfw = document.getElementById('publish-nsfw').value; + event.file.meta.name = name; + 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 = '
'; + // start a progress animation + createProgressBar(document.getElementById('progress-bar'), 12); +}); +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 = '

' + JSON.stringify(msg) + '

--(✖╭╮✖)→

For help, post the above error text in the #speech channel on the lbry slack'; +}); +socket.on('publish-complete', function(msg){ + var publishResults = '

Your publish is complete!

'; + publishResults += '

NOTE: the transaction still needs to be mined by the network before you can access it! This will take a few minutes. To view the transaction on the blockchain explorer click the Transaction ID link below.

'; + publishResults += '

Your Transaction ID is: ' + msg.result.txid + '

'; + publishResults += '

Your Claim ID is: ' + msg.result.claim_id + '

'; + publishResults += '

Here is a link to the claim where your asset will be published: spee.ch/' + msg.name + '

'; + publishResults += '

Here is a direct link to where your asset will be stored: spee.ch/' + msg.name + '/' + msg.result.claim_id + '

'; + publishResults += '

Reload to publish another asset

'; + document.getElementById('publish-active-area').innerHTML = publishResults; +}); \ No newline at end of file diff --git a/routes/show-routes.js b/routes/show-routes.js index 65fcb562..82d633c3 100644 --- a/routes/show-routes.js +++ b/routes/show-routes.js @@ -4,7 +4,7 @@ const logger = require('winston'); module.exports = (app, ua, googleAnalyticsId) => { // route to fetch all free public claims - app.get('/meme-fodder', ({ originalUrl }, res) => { + app.get('/lbrymemefodder', ({ originalUrl }, res) => { logger.debug(`GET request on ${originalUrl}`); res.status(200).render('memeFodder'); }); diff --git a/views/memeFodder.handlebars b/views/memeFodder.handlebars index 7b952641..9f42ddc3 100644 --- a/views/memeFodder.handlebars +++ b/views/memeFodder.handlebars @@ -1,90 +1,15 @@
{{> topBar}} + {{ image }}
{{> memeMaker}}
+
+ {{> memeFodderResults}} +
- - // set the size - var img = document.getElementById('start-image'); - var canvasWidth = 400; - var canvasHeight = 300; - canvas.width = canvasWidth; - canvas.height = canvasHeight; - - - var topText = document.getElementById('top-text'); - var bottomText = document.getElementById('bottom-text'); - - img.onload = function() { - drawMeme() - } - - topText.addEventListener('keydown', drawMeme); - topText.addEventListener('keyup', drawMeme); - topText.addEventListener('change', drawMeme); - - bottomText.addEventListener('keydown', drawMeme); - bottomText.addEventListener('keyup', drawMeme); - bottomText.addEventListener('change', drawMeme); - - function drawMeme() { - ctx.clearRect(0, 0, canvasWidth, canvasHeight); - ctx.drawImage(img, 0, 0, canvasWidth, canvasHeight); - ctx.lineWidth = 4; - ctx.font = '20pt sans-serif'; - ctx.strokeStyle = 'black'; - ctx.fillStyle = 'white'; - ctx.textAlign = 'center'; - ctx.textBaseline = 'top'; - - var text1 = document.getElementById('top-text').value; - text1 = text1.toUpperCase(); - x = canvasWidth / 2; - y = 0; - - wrapText(ctx, text1, x, y, 300, 28, false); - - ctx.textBaseline = 'bottom'; - var text2 = document.getElementById('bottom-text').value; - text2 = text2.toUpperCase(); - y = canvasHeight; - - wrapText(ctx, text2, x, y, 300, 28, 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); - } - } - - + + diff --git a/views/partials/documentation.handlebars b/views/partials/documentation.handlebars index a7d8243a..412b7815 100644 --- a/views/partials/documentation.handlebars +++ b/views/partials/documentation.handlebars @@ -1,7 +1,7 @@
-

Site Navigation

+

Documentation

diff --git a/views/partials/examples.handlebars b/views/partials/examples.handlebars index 3535d957..36aad374 100644 --- a/views/partials/examples.handlebars +++ b/views/partials/examples.handlebars @@ -1,16 +1,26 @@
-

Examples

+

What Is Spee.ch?

-
- +
+
+

Spee.ch is for sharing

+

Spee.ch is a platform by which you can publish images to the Lbry blockchain. Just upload an image, title it, and send it off into the lbry ecosystem.

+

Spee.ch is also a platform to serve you those images. It's like have a personal chef that will serve you a meal anywhere in the world. All you have to do is ask for it, by using "spee.ch/" + the name of a claim.

+

If you want a specific image, just ask for it with the claim_id by using "spee.ch/" + the name of the claim + "/" + the claim id.

+
+
+

Examples

+
Use spee.ch to serve the top asset at a lbry claim:
+ spee.ch/coconuts
+ spee.ch/wood
+ spee.ch/doitlive
+
Use spee.ch to show you all the assets at a lbry claim:
+ spee.ch/doitlive/all +
Use spee.ch to serve you a specific asset by claim id:
+ spee.ch/doitlive/ca3023187e901df9e9aabd95d6ae09b6cc69b3f0 +
\ No newline at end of file diff --git a/views/partials/memeFodderResults.handlebars b/views/partials/memeFodderResults.handlebars new file mode 100644 index 00000000..dc547eb6 --- /dev/null +++ b/views/partials/memeFodderResults.handlebars @@ -0,0 +1,14 @@ +
+
+
+

Recent Publishes

+
+
+
+

Below are some of the most recent entries published via /meme-fodder

+ (pull all the claims published to 'lbryMemeFodder' and display most recent 20 here) + (maybe a voting system? Is there a way to allow people to donate funds to a claimId so that it will show up higher in the results?) +
+
+
+
\ No newline at end of file diff --git a/views/partials/memeMaker.handlebars b/views/partials/memeMaker.handlebars index 3e4249fa..bf3740a2 100644 --- a/views/partials/memeMaker.handlebars +++ b/views/partials/memeMaker.handlebars @@ -1,23 +1,46 @@
-

Meme Generator

+

/LbryMemeFodder

-
+
+

Congratulations, you found /LbryMemeFodder. Here's the game...

+

(1) /LbryMemeFodder will always use the winning public, free image published to lbry://meme-fodder. (meaning the most recent, highest bid). Want to put a different image on the chopping block? Go publish it!

+

(2) Create a meme based on the current claim with the tool below. Think you got a winner? Share it with the community and see what they think!

+
If you can see this, canvas is not supported. - + a picture to make your meme with
- - +
+
+ + +
+
+
+
+ +
+
+
+
+ + +
+
+
-
\ No newline at end of file From b13dc53f0122d99c0d84d6f63ed8da33dc3be95c Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 20 Jun 2017 16:36:19 -0700 Subject: [PATCH 3/7] meme publish works --- config/development.json | 2 +- controllers/publishController.js | 7 +- helpers/logging/loggerSetup.js | 10 ++- public/assets/js/memeDraw.js | 50 +++++++---- public/assets/js/memePublish.js | 83 +++++-------------- routes/home-routes.js | 2 +- views/index.handlebars | 1 + views/memeFodder.handlebars | 4 +- views/partials/memeMaker.handlebars | 10 +-- ...ults.handlebars => memeResults.handlebars} | 0 10 files changed, 76 insertions(+), 93 deletions(-) rename views/partials/{memeFodderResults.handlebars => memeResults.handlebars} (100%) diff --git a/config/development.json b/config/development.json index 2c64d379..2712bde3 100644 --- a/config/development.json +++ b/config/development.json @@ -10,7 +10,7 @@ "PublishUploadPath": "C:\\lbry\\speech\\hosted_content" }, "Logging": { - "LogLevel": "debug", + "LogLevel": "silly", "LogDirectory": "C:\\lbry\\speech\\logs\\" } } \ No newline at end of file diff --git a/controllers/publishController.js b/controllers/publishController.js index eb1d7660..fc632836 100644 --- a/controllers/publishController.js +++ b/controllers/publishController.js @@ -7,6 +7,9 @@ const errorHandlers = require('../helpers/libraries/errorHandlers.js'); function createPublishParams (claim, filePath, license, nsfw) { logger.debug(`Creating Publish Parameters for "${claim}"`); + if (typeof nsfw === 'string') { + nsfw = (nsfw.toLowerCase() === 'on'); + } const publishParams = { name : claim, file_path: filePath, @@ -17,11 +20,12 @@ function createPublishParams (claim, filePath, license, nsfw) { author : 'spee.ch', language : 'en', license, - nsfw : nsfw.toLowerCase() === 'on', + nsfw, }, claim_address : walledAddress, change_address: walledAddress, }; + logger.debug('publishParams:', publishParams); return publishParams; } @@ -49,6 +53,7 @@ module.exports = { socket.emit('publish-complete', { name: claim, result }); }) .catch(error => { + logger.error(`Error publishing ${fileName}`, error); visitor.event('Publish Route', 'Publish Failure', filePath).send(); socket.emit('publish-failure', errorHandlers.handlePublishError(error)); deleteTemporaryFile(filePath); diff --git a/helpers/logging/loggerSetup.js b/helpers/logging/loggerSetup.js index 61c5e192..7a0b2e41 100644 --- a/helpers/logging/loggerSetup.js +++ b/helpers/logging/loggerSetup.js @@ -8,10 +8,12 @@ module.exports = (winston, logLevel, logDir) => { winston.configure({ transports: [ new (winston.transports.Console)({ - level : logLevel, - timestamp : false, - colorize : true, - prettyPrint: true, + level : logLevel, + timestamp : false, + colorize : true, + prettyPrint : true, + handleExceptions : true, + humanReadableUnhandledException: true, }), new (winston.transports.File)({ filename : `${logDir}/speechLogs.log`, diff --git a/public/assets/js/memeDraw.js b/public/assets/js/memeDraw.js index 4e4ea0a2..76d6ba3e 100644 --- a/public/assets/js/memeDraw.js +++ b/public/assets/js/memeDraw.js @@ -6,8 +6,7 @@ var fontSize = 28; var topText = document.getElementById('top-text'); var bottomText = document.getElementById('bottom-text'); var ctx = canvas.getContext('2d'); -var downloadLink = document.getElementById("meme-download-link"); -var memeFileName = document.getElementById("meme-file-name"); +var fileNameInput = document.getElementById("file-name-input"); // create the canvas img.onload = function() { @@ -60,12 +59,13 @@ function wrapText(context, text, x, y, maxWidth, lineHeight, fromBottom) { lineHeight = (fromBottom)?-lineHeight:lineHeight; var lines = []; - var y = y; - var line =''; + 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 testLine = line + ' ' + words[i]; + var metrics = context.measureText(testLine); var testWidth = metrics.width; if (testWidth > maxWidth) { @@ -75,6 +75,7 @@ function wrapText(context, text, x, y, maxWidth, lineHeight, fromBottom) { line = testLine; } } + lines[pushMethod](line); for (var k in lines ) { @@ -83,16 +84,33 @@ function wrapText(context, text, x, y, maxWidth, lineHeight, fromBottom) { } } -// save the meme -function downloadMeme() { - var dt = canvas.toDataURL('image/jpeg'); - this.href = dt; -}; +function dataURItoBlob(dataURI) { + // convert base64/URLEncoded data component to raw binary data held in a string + var byteString; + if (dataURI.split(',')[0].indexOf('base64') >= 0) + byteString = atob(dataURI.split(',')[1]); + else + byteString = unescape(dataURI.split(',')[1]); -function updateFileName(){ - downloadLink.download = this.value; + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + + // write the bytes of the string to a typed array + var ia = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + return new Blob([ia], {type:mimeString}); } -memeFileName.addEventListener('keyup', updateFileName); - -downloadLink.addEventListener('click', downloadMeme, false); \ No newline at end of file +// save the meme +function startPublish() { + //download the image + var dataUrl = canvas.toDataURL('image/jpeg'); + var blob = dataURItoBlob(dataUrl) + var filename = fileNameInput.value; + var file = new File([blob], filename, {type: 'image/jpeg', lastModified: Date.now()}); + console.log(file); + publishMeme(file); // note: this function is in memePublish.js +}; \ No newline at end of file diff --git a/public/assets/js/memePublish.js b/public/assets/js/memePublish.js index 99db22d9..57192811 100644 --- a/public/assets/js/memePublish.js +++ b/public/assets/js/memePublish.js @@ -3,6 +3,9 @@ var socket = io(); var uploader = new SocketIOFileUpload(socket); var stagedFiles = null; +var name = 'meme-fodder-entry'; +var license = 'Creative Commons'; +var nsfw = false; /* helper functions */ // create a progress animation @@ -23,67 +26,16 @@ function createProgressBar(element, size){ }; setInterval(addOne, 300); } -// preview file and stage the image for upload -function previewAndStageFile(selectedFile){ - var preview = document.getElementById('image-preview'); - var dropzone = document.getElementById('drop-zone'); - var previewReader = new FileReader(); - preview.style.display = 'block'; - dropzone.style.display = 'none'; - - previewReader.onloadend = function () { - preview.src = previewReader.result; - }; - - if (selectedFile) { - previewReader.readAsDataURL(selectedFile); // reads the data and sets the img src - document.getElementById('publish-name').value = selectedFile.name.substring(0, selectedFile.name.indexOf('.')); // updates metadata inputs - stagedFiles = [selectedFile]; // stores the selected file for upload - } else { - preview.src = ''; - } -} -// update the publish status -function updatePublishStatus(msg){ - document.getElementById('publish-status').innerHTML = msg; -} -// process the drop-zone drop -function drop_handler(ev) { - console.log("drop"); - ev.preventDefault(); - // if dropped items aren't files, reject them - var dt = ev.dataTransfer; - if (dt.items) { - if (dt.items[0].kind == 'file') { - var droppedFile = dt.items[0].getAsFile(); - previewAndStageFile(droppedFile); - } else { - console.log("no files were found") - } - } else { - console.log("no items were found") - } -} -// prevent the browser's default drag behavior -function dragover_handler(ev) { - ev.preventDefault(); -} -// remove all of the drag data -function dragend_handler(ev) { - var dt = ev.dataTransfer; - if (dt.items) { - for (var i = 0; i < dt.items.length; i++) { - dt.items.remove(i); - } - } else { - ev.dataTransfer.clearData(); - } -} - -/* configure the submit button */ -document.getElementById('publish-submit').addEventListener('click', function(event){ - event.preventDefault(); +function publishMeme(file) { + // get image data + //var imgData = ctx.getImageData(0, 0, canvasWidth, canvasHeight); + //console.log(imgData); + // stage files + stagedFiles = [file]; // stores the selected file for upload + //stagedFiles = [selectedFile.getAsFile()]; // stores the selected file for upload + console.log(stagedFiles[0]); + console.log('file staged'); // make sure a file was selected if (stagedFiles) { // make sure only 1 file was selected @@ -104,13 +56,16 @@ document.getElementById('publish-submit').addEventListener('click', function(eve break; } } -}) + +} + +// update the publish status +function updatePublishStatus(msg){ + document.getElementById('publish-status').innerHTML = msg; +} /* socketio-file-upload listeners */ uploader.addEventListener('start', function(event){ - var name = document.getElementById('publish-name').value; - var license = document.getElementById('publish-license').value; - var nsfw = document.getElementById('publish-nsfw').value; event.file.meta.name = name; event.file.meta.license = license; event.file.meta.nsfw = nsfw; diff --git a/routes/home-routes.js b/routes/home-routes.js index e389b4ae..09c40644 100644 --- a/routes/home-routes.js +++ b/routes/home-routes.js @@ -7,7 +7,7 @@ module.exports = app => { }); // a catch-all route if someone visits a page that does not exist app.use('*', (req, res) => { - logger.error(`Get request on ${req.originalUrl} which was 404`); + logger.error(`Get request on ${req.originalUrl} which was a 404`); res.status(404).render('fourOhFour'); }); }; diff --git a/views/index.handlebars b/views/index.handlebars index ea81218f..120edfff 100644 --- a/views/index.handlebars +++ b/views/index.handlebars @@ -55,6 +55,7 @@ }; if (selectedFile) { + console.log(selectedFile); previewReader.readAsDataURL(selectedFile); // reads the data and sets the img src document.getElementById('publish-name').value = selectedFile.name.substring(0, selectedFile.name.indexOf('.')); // updates metadata inputs stagedFiles = [selectedFile]; // stores the selected file for upload diff --git a/views/memeFodder.handlebars b/views/memeFodder.handlebars index 9f42ddc3..7b9bb451 100644 --- a/views/memeFodder.handlebars +++ b/views/memeFodder.handlebars @@ -5,7 +5,7 @@ {{> memeMaker}}
- {{> memeFodderResults}} + {{> memeResults}}
@@ -13,3 +13,5 @@ + + diff --git a/views/partials/memeMaker.handlebars b/views/partials/memeMaker.handlebars index bf3740a2..520f3283 100644 --- a/views/partials/memeMaker.handlebars +++ b/views/partials/memeMaker.handlebars @@ -16,27 +16,27 @@ a picture to make your meme with
-
+
- +
- +
- +
- +
diff --git a/views/partials/memeFodderResults.handlebars b/views/partials/memeResults.handlebars similarity index 100% rename from views/partials/memeFodderResults.handlebars rename to views/partials/memeResults.handlebars From adfeea123286277027b7a02199989f586edbf8d5 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 20 Jun 2017 16:49:33 -0700 Subject: [PATCH 4/7] updated directions --- routes/show-routes.js | 2 +- views/partials/memeMaker.handlebars | 11 +++++++---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/routes/show-routes.js b/routes/show-routes.js index 82d633c3..24f67cd3 100644 --- a/routes/show-routes.js +++ b/routes/show-routes.js @@ -4,7 +4,7 @@ const logger = require('winston'); module.exports = (app, ua, googleAnalyticsId) => { // route to fetch all free public claims - app.get('/lbrymemefodder', ({ originalUrl }, res) => { + app.get('/meme-fodder/play', ({ originalUrl }, res) => { logger.debug(`GET request on ${originalUrl}`); res.status(200).render('memeFodder'); }); diff --git a/views/partials/memeMaker.handlebars b/views/partials/memeMaker.handlebars index 520f3283..48427098 100644 --- a/views/partials/memeMaker.handlebars +++ b/views/partials/memeMaker.handlebars @@ -1,13 +1,16 @@
-

/LbryMemeFodder

+

#LbryMemeFodder

-

Congratulations, you found /LbryMemeFodder. Here's the game...

-

(1) /LbryMemeFodder will always use the winning public, free image published to lbry://meme-fodder. (meaning the most recent, highest bid). Want to put a different image on the chopping block? Go publish it!

-

(2) Create a meme based on the current claim with the tool below. Think you got a winner? Share it with the community and see what they think!

+
+

Congratulations, you found the /meme-fodder game!

+

Here's how it is played...

+

(1) /meme-fodder will always use the winning public, free image published to lbry://meme-fodder. (meaning the most recent, highest bid). Want to put a different image on the chopping block? Go publish it!

+

(2) Create a meme based on the current claim with the tool below. Think you got a winner? Share it with the community and see what they think!

+
From 2a2dff47e00e7939ea3cd8eeeca3040e0afecfc4 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Tue, 20 Jun 2017 17:39:41 -0700 Subject: [PATCH 5/7] added 'recent entries' to meme-fodder --- public/assets/js/memePublish.js | 9 ++++----- routes/show-routes.js | 13 +++++++++++-- views/partials/memeMaker.handlebars | 2 +- views/partials/memeResults.handlebars | 19 +++++++++++++++---- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/public/assets/js/memePublish.js b/public/assets/js/memePublish.js index 57192811..0696db86 100644 --- a/public/assets/js/memePublish.js +++ b/public/assets/js/memePublish.js @@ -89,11 +89,10 @@ socket.on('publish-failure', function(msg){ }); socket.on('publish-complete', function(msg){ var publishResults = '

Your publish is complete!

'; - publishResults += '

NOTE: the transaction still needs to be mined by the network before you can access it! This will take a few minutes. To view the transaction on the blockchain explorer click the Transaction ID link below.

'; + publishResults += '

NOTE: the blockchain will need a few minutes to process your amazing work. Please allow some time for your asset to appear in the entries below.

'; + publishResults += '

Your meme has been published to spee.ch/' + msg.name + '

'; + publishResults += '

Here is a direct link to where your meme will be stored: spee.ch/' + msg.name + '/' + msg.result.claim_id + '

'; publishResults += '

Your Transaction ID is: ' + msg.result.txid + '

'; - publishResults += '

Your Claim ID is: ' + msg.result.claim_id + '

'; - publishResults += '

Here is a link to the claim where your asset will be published: spee.ch/' + msg.name + '

'; - publishResults += '

Here is a direct link to where your asset will be stored: spee.ch/' + msg.name + '/' + msg.result.claim_id + '

'; - publishResults += '

Reload to publish another asset

'; + publishResults += '

Reload to publish another

'; document.getElementById('publish-active-area').innerHTML = publishResults; }); \ No newline at end of file diff --git a/routes/show-routes.js b/routes/show-routes.js index 24f67cd3..d446404e 100644 --- a/routes/show-routes.js +++ b/routes/show-routes.js @@ -5,15 +5,24 @@ const logger = require('winston'); module.exports = (app, ua, googleAnalyticsId) => { // route to fetch all free public claims app.get('/meme-fodder/play', ({ originalUrl }, res) => { + // google analytics logger.debug(`GET request on ${originalUrl}`); - res.status(200).render('memeFodder'); + // get and serve content + showController + .getAllClaims('meme-fodder-entry') + .then(orderedFreePublicClaims => { + res.status(200).render('memeFodder', { claims: orderedFreePublicClaims }); + }) + .catch(error => { + errorHandlers.handleRequestError(error, res); + }); }); // route to fetch all free public claims app.get('/:name/all', ({ originalUrl, params }, res) => { logger.debug(`GET request on ${originalUrl}`); // google analytics ua(googleAnalyticsId, { https: true }).event('Show Routes', '/name/all', `${params.name}/all`).send(); - // fetch all free public claims + // get and serve content showController .getAllClaims(params.name) .then(orderedFreePublicClaims => { diff --git a/views/partials/memeMaker.handlebars b/views/partials/memeMaker.handlebars index 48427098..e6f59058 100644 --- a/views/partials/memeMaker.handlebars +++ b/views/partials/memeMaker.handlebars @@ -7,7 +7,7 @@

Congratulations, you found the /meme-fodder game!

-

Here's how it is played...

+

Here's how it's played...

(1) /meme-fodder will always use the winning public, free image published to lbry://meme-fodder. (meaning the most recent, highest bid). Want to put a different image on the chopping block? Go publish it!

(2) Create a meme based on the current claim with the tool below. Think you got a winner? Share it with the community and see what they think!

diff --git a/views/partials/memeResults.handlebars b/views/partials/memeResults.handlebars index dc547eb6..1c147bfa 100644 --- a/views/partials/memeResults.handlebars +++ b/views/partials/memeResults.handlebars @@ -1,13 +1,24 @@
-

Recent Publishes

+

Recent Entries

-

Below are some of the most recent entries published via /meme-fodder

- (pull all the claims published to 'lbryMemeFodder' and display most recent 20 here) - (maybe a voting system? Is there a way to allow people to donate funds to a claimId so that it will show up higher in the results?) +
+

Below are some of the most recent entries published via /meme-fodder

+ (pull all the claims published to 'lbryMemeFodder' and display most recent 20 here) + (maybe a voting system? Is there a way to allow people to donate funds to a claimId so that it will show up higher in the results?) +
+
+
+ {{#each claims}} +
+ + +
+
+ {{/each}}
From 9e793467b3d8e0a88f61b50271d6cd2e0a504dbc Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 21 Jun 2017 07:43:45 -0700 Subject: [PATCH 6/7] changed meme publish to use custom claim --- public/assets/js/memeDraw.js | 11 +++++++---- public/assets/js/memePublish.js | 17 +++++------------ views/partials/memeMaker.handlebars | 4 ++-- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/public/assets/js/memeDraw.js b/public/assets/js/memeDraw.js index 76d6ba3e..d85c2743 100644 --- a/public/assets/js/memeDraw.js +++ b/public/assets/js/memeDraw.js @@ -6,7 +6,7 @@ var fontSize = 28; var topText = document.getElementById('top-text'); var bottomText = document.getElementById('bottom-text'); var ctx = canvas.getContext('2d'); -var fileNameInput = document.getElementById("file-name-input"); +var claimNameInput = document.getElementById("file-name-input"); // create the canvas img.onload = function() { @@ -104,13 +104,16 @@ function dataURItoBlob(dataURI) { return new Blob([ia], {type:mimeString}); } +var claimName; + // save the meme function startPublish() { //download the image var dataUrl = canvas.toDataURL('image/jpeg'); var blob = dataURItoBlob(dataUrl) - var filename = fileNameInput.value; - var file = new File([blob], filename, {type: 'image/jpeg', lastModified: Date.now()}); + claimName = claimNameInput.value; + var fileName = claimNameInput.value + ".jpg"; + var file = new File([blob], fileName, {type: 'image/jpeg', lastModified: Date.now()}); console.log(file); - publishMeme(file); // note: this function is in memePublish.js + stageAndPublish(file); // note: this function is in memePublish.js }; \ No newline at end of file diff --git a/public/assets/js/memePublish.js b/public/assets/js/memePublish.js index 0696db86..0ceec956 100644 --- a/public/assets/js/memePublish.js +++ b/public/assets/js/memePublish.js @@ -3,7 +3,6 @@ var socket = io(); var uploader = new SocketIOFileUpload(socket); var stagedFiles = null; -var name = 'meme-fodder-entry'; var license = 'Creative Commons'; var nsfw = false; @@ -27,20 +26,14 @@ function createProgressBar(element, size){ setInterval(addOne, 300); } -function publishMeme(file) { - // get image data - //var imgData = ctx.getImageData(0, 0, canvasWidth, canvasHeight); - //console.log(imgData); +function stageAndPublish(file) { // stage files - stagedFiles = [file]; // stores the selected file for upload - //stagedFiles = [selectedFile.getAsFile()]; // stores the selected file for upload - console.log(stagedFiles[0]); - console.log('file staged'); + stagedFiles = [file]; // stores the selected file for // make sure a file was selected if (stagedFiles) { // make sure only 1 file was selected - if (stagedFiles.length > 1) { - alert("Only one file allowed at a time"); + if (stagedFiles.length < 1) { + alert("A file is needed"); return; } // make sure the content type is acceptable @@ -66,7 +59,7 @@ function updatePublishStatus(msg){ /* socketio-file-upload listeners */ uploader.addEventListener('start', function(event){ - event.file.meta.name = name; + event.file.meta.name = claimName; event.file.meta.license = license; event.file.meta.nsfw = nsfw; event.file.meta.type = stagedFiles[0].type; diff --git a/views/partials/memeMaker.handlebars b/views/partials/memeMaker.handlebars index e6f59058..fec29cda 100644 --- a/views/partials/memeMaker.handlebars +++ b/views/partials/memeMaker.handlebars @@ -33,8 +33,8 @@
- - + +
From 5b6e75cbeeb17f03ec05f32a4fd500202906a4f5 Mon Sep 17 00:00:00 2001 From: bill bittner Date: Wed, 21 Jun 2017 09:14:53 -0700 Subject: [PATCH 7/7] added twitter button on publish --- public/assets/css/style.css | 26 ++++++++---- public/assets/js/memeDraw.js | 36 +--------------- public/assets/js/memePublish.js | 61 ++++++++++++++++++++++++--- routes/show-routes.js | 2 +- views/memeFodder.handlebars | 2 +- views/partials/memeMaker.handlebars | 52 ++++++++++++----------- views/partials/memeResults.handlebars | 8 ++-- 7 files changed, 107 insertions(+), 80 deletions(-) diff --git a/public/assets/css/style.css b/public/assets/css/style.css index b9395e60..2f2d4137 100644 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -1,3 +1,9 @@ +canvas { + background-color: blue; + width: 100%; + height: auto; +} + #drop-zone { border: 1px dashed lightgrey; padding: 1em; @@ -5,20 +11,22 @@ width: 100%; } -.all-claims-img { - height: 200px; -} - #image-preview { display: none; } +#tweet-meme-button { + float: left; + margin-right: 5px; +} + .row { margin: 10px 0px 10px 0px; } -canvas { - background-color: blue; - width: 100%; - height: auto; -} \ No newline at end of file +.all-claims-img { + height: 200px; +} + + + diff --git a/public/assets/js/memeDraw.js b/public/assets/js/memeDraw.js index d85c2743..db1cf2c5 100644 --- a/public/assets/js/memeDraw.js +++ b/public/assets/js/memeDraw.js @@ -82,38 +82,4 @@ function wrapText(context, text, x, y, maxWidth, lineHeight, fromBottom) { context.strokeText(lines[k], x, y + lineHeight * k); context.fillText(lines[k], x, y + lineHeight * k); } -} - -function dataURItoBlob(dataURI) { - // convert base64/URLEncoded data component to raw binary data held in a string - var byteString; - if (dataURI.split(',')[0].indexOf('base64') >= 0) - byteString = atob(dataURI.split(',')[1]); - else - byteString = unescape(dataURI.split(',')[1]); - - // separate out the mime component - var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; - - // write the bytes of the string to a typed array - var ia = new Uint8Array(byteString.length); - for (var i = 0; i < byteString.length; i++) { - ia[i] = byteString.charCodeAt(i); - } - - return new Blob([ia], {type:mimeString}); -} - -var claimName; - -// save the meme -function startPublish() { - //download the image - var dataUrl = canvas.toDataURL('image/jpeg'); - var blob = dataURItoBlob(dataUrl) - claimName = claimNameInput.value; - var fileName = claimNameInput.value + ".jpg"; - var file = new File([blob], fileName, {type: 'image/jpeg', lastModified: Date.now()}); - console.log(file); - stageAndPublish(file); // note: this function is in memePublish.js -}; \ No newline at end of file +} \ No newline at end of file diff --git a/public/assets/js/memePublish.js b/public/assets/js/memePublish.js index 0ceec956..1d020aab 100644 --- a/public/assets/js/memePublish.js +++ b/public/assets/js/memePublish.js @@ -5,6 +5,38 @@ var uploader = new SocketIOFileUpload(socket); var stagedFiles = null; var license = 'Creative Commons'; var nsfw = false; +var claimName; + +function dataURItoBlob(dataURI) { + // convert base64/URLEncoded data component to raw binary data held in a string + var byteString; + if (dataURI.split(',')[0].indexOf('base64') >= 0) + byteString = atob(dataURI.split(',')[1]); + else + byteString = unescape(dataURI.split(',')[1]); + + // separate out the mime component + var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; + + // write the bytes of the string to a typed array + var ia = new Uint8Array(byteString.length); + for (var i = 0; i < byteString.length; i++) { + ia[i] = byteString.charCodeAt(i); + } + + return new Blob([ia], {type:mimeString}); +} + +function startPublish() { + //download the image + var dataUrl = canvas.toDataURL('image/jpeg'); // canvas defined in memeDraw.js + var blob = dataURItoBlob(dataUrl) + claimName = claimNameInput.value; // claimNameInput.value defined in memeDraw.js + var fileName = claimNameInput.value + ".jpg"; + var file = new File([blob], fileName, {type: 'image/jpeg', lastModified: Date.now()}); + console.log(file); + stageAndPublish(file); +}; /* helper functions */ // create a progress animation @@ -78,14 +110,31 @@ socket.on('publish-status', function(msg){ updatePublishStatus(msg); }); socket.on('publish-failure', function(msg){ - document.getElementById('publish-active-area').innerHTML = '

' + JSON.stringify(msg) + '

--(✖╭╮✖)→

For help, post the above error text in the #speech channel on the lbry slack'; + document.getElementById('publish-active-area').innerHTML = '

' + JSON.stringify(msg) + '

--(✖╭╮✖)→

For help, post the above error text in the #speech channel on the LBRY slack'; }); socket.on('publish-complete', function(msg){ - var publishResults = '

Your publish is complete!

'; - publishResults += '

NOTE: the blockchain will need a few minutes to process your amazing work. Please allow some time for your asset to appear in the entries below.

'; - publishResults += '

Your meme has been published to spee.ch/' + msg.name + '

'; - publishResults += '

Here is a direct link to where your meme will be stored: spee.ch/' + msg.name + '/' + msg.result.claim_id + '

'; + var publishResults; + var directUrl = 'https://spee.ch/' + msg.name + '/' + msg.result.claim_id; + // build new publish area + publishResults = '

Your publish is complete! Go ahead, share it with the world!

'; + publishResults += '

NOTE: the blockchain will need a few minutes to process your amazing work. Please allow some time for your meme to appear at your link.

'; + publishResults += '

Your meme has been published to http://spee.ch/' + msg.name + '

'; + publishResults += '

Here is a direct link to where your meme will be stored: ' + directUrl + '

'; publishResults += '

Your Transaction ID is: ' + msg.result.txid + '

'; publishResults += '

Reload to publish another

'; - document.getElementById('publish-active-area').innerHTML = publishResults; + // update publish area + document.getElementById('publish-active-area').innerHTML = publishResults; + // add a tweet button + twttr.widgets + .createShareButton( + directUrl, + document.getElementById('tweet-meme-button'), + { + text: 'Check out my meme creation on the LBRY blockchain!', + hashtags: 'LBRYMemeFodder', + via: 'lbryio' + }) + .then( function( el ) { + console.log('Tweet button added.'); + }); }); \ No newline at end of file diff --git a/routes/show-routes.js b/routes/show-routes.js index d446404e..6bd16fe4 100644 --- a/routes/show-routes.js +++ b/routes/show-routes.js @@ -9,7 +9,7 @@ module.exports = (app, ua, googleAnalyticsId) => { logger.debug(`GET request on ${originalUrl}`); // get and serve content showController - .getAllClaims('meme-fodder-entry') + .getAllClaims('meme-fodder') .then(orderedFreePublicClaims => { res.status(200).render('memeFodder', { claims: orderedFreePublicClaims }); }) diff --git a/views/memeFodder.handlebars b/views/memeFodder.handlebars index 7b9bb451..4257bf0c 100644 --- a/views/memeFodder.handlebars +++ b/views/memeFodder.handlebars @@ -14,4 +14,4 @@ - + \ No newline at end of file diff --git a/views/partials/memeMaker.handlebars b/views/partials/memeMaker.handlebars index fec29cda..99ad5638 100644 --- a/views/partials/memeMaker.handlebars +++ b/views/partials/memeMaker.handlebars @@ -1,49 +1,53 @@
-

#LbryMemeFodder

+

#LBRYMemeFodder

-
+

Congratulations, you found the /meme-fodder game!

Here's how it's played...

-

(1) /meme-fodder will always use the winning public, free image published to lbry://meme-fodder. (meaning the most recent, highest bid). Want to put a different image on the chopping block? Go publish it!

-

(2) Create a meme based on the current claim with the tool below. Think you got a winner? Share it with the community and see what they think!

+

(1) /meme-fodder will always use the winning public, free image published to LBRY://meme-fodder. (meaning the most recent, highest bid). Want to put a different image on the chopping block? Go publish it!

+

(2) Create a meme based on the current claim with the tool below. Think you got a winner? Share it with the community and see what they think!

-
+
If you can see this, canvas is not supported. a picture to make your meme with
-
-
-
- - +
+
+
+
+ + +
-
-
-
- +
+
+ +
-
-
-
- - +
+
+ + +
-
-
-
- +
+
+ +
-
\ No newline at end of file +
+ + \ No newline at end of file diff --git a/views/partials/memeResults.handlebars b/views/partials/memeResults.handlebars index 1c147bfa..2c336a14 100644 --- a/views/partials/memeResults.handlebars +++ b/views/partials/memeResults.handlebars @@ -1,14 +1,12 @@
-

Recent Entries

+

Recent Meme Fodder

-

Below are some of the most recent entries published via /meme-fodder

- (pull all the claims published to 'lbryMemeFodder' and display most recent 20 here) - (maybe a voting system? Is there a way to allow people to donate funds to a claimId so that it will show up higher in the results?) +

Below are some of the most recent images that have been fuel for our enjoyment on /meme-fodder

@@ -20,6 +18,8 @@
{{/each}}
+

(ideally I'd like to display what users have submitted here)

+

(maybe a voting system? Is there a way to allow people to donate funds to a claimId so that it will show up higher in the results?)

\ No newline at end of file