commit
cdbd20d4fd
16 changed files with 406 additions and 280 deletions
|
@ -4,12 +4,10 @@ const lbryApi = require('../helpers/libraries/lbryApi.js');
|
||||||
const config = require('config');
|
const config = require('config');
|
||||||
const walledAddress = config.get('WalletConfig.lbryAddress');
|
const walledAddress = config.get('WalletConfig.lbryAddress');
|
||||||
const errorHandlers = require('../helpers/libraries/errorHandlers.js');
|
const errorHandlers = require('../helpers/libraries/errorHandlers.js');
|
||||||
|
const db = require('../models');
|
||||||
|
|
||||||
function createPublishParams (claim, filePath, license, nsfw) {
|
function createPublishParams (claim, filePath, license, nsfw) {
|
||||||
logger.debug(`Creating Publish Parameters for "${claim}"`);
|
logger.debug(`Creating Publish Parameters for "${claim}"`);
|
||||||
if (typeof nsfw === 'string') {
|
|
||||||
nsfw = (nsfw.toLowerCase() === 'on');
|
|
||||||
}
|
|
||||||
const publishParams = {
|
const publishParams = {
|
||||||
name : claim,
|
name : claim,
|
||||||
file_path: filePath,
|
file_path: filePath,
|
||||||
|
@ -36,24 +34,63 @@ function deleteTemporaryFile (filePath) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function upsert (Model, values, condition) {
|
||||||
|
return Model
|
||||||
|
.findOne({ where: condition })
|
||||||
|
.then(function (obj) {
|
||||||
|
if (obj) { // update
|
||||||
|
return obj.update(values);
|
||||||
|
} else { // insert
|
||||||
|
return Model.create(values);
|
||||||
|
}
|
||||||
|
}).catch(function (error) {
|
||||||
|
logger.error('Sequelize findOne error', error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
publish (claim, fileName, filePath, fileType, license, nsfw, socket, visitor) {
|
publish (name, fileName, filePath, fileType, license, nsfw, socket, visitor) {
|
||||||
|
console.log('nsfw:', nsfw);
|
||||||
|
// validate nsfw
|
||||||
|
if (typeof nsfw === 'string') {
|
||||||
|
nsfw = (nsfw.toLowerCase() === 'true');
|
||||||
|
}
|
||||||
// update the client
|
// update the client
|
||||||
socket.emit('publish-status', 'Your image is being published (this might take a second)...');
|
socket.emit('publish-status', 'Your image is being published (this might take a second)...');
|
||||||
// send to analytics
|
// send to analytics
|
||||||
visitor.event('Publish Route', 'Publish Request', filePath).send();
|
visitor.event('Publish Route', 'Publish Request', filePath).send();
|
||||||
// create the publish object
|
// create the publish object
|
||||||
const publishParams = createPublishParams(claim, filePath, license, nsfw);
|
const publishParams = createPublishParams(name, filePath, license, nsfw);
|
||||||
// get a promise to publish
|
// 1. publish the file
|
||||||
lbryApi
|
lbryApi
|
||||||
.publishClaim(publishParams, fileName, fileType)
|
.publishClaim(publishParams, fileName, fileType)
|
||||||
.then(result => {
|
.then(result => {
|
||||||
logger.info(`Successfully published ${fileName}`);
|
logger.info(`Successfully published ${fileName}`, result);
|
||||||
|
// google analytics
|
||||||
visitor.event('Publish Route', 'Publish Success', filePath).send();
|
visitor.event('Publish Route', 'Publish Success', filePath).send();
|
||||||
socket.emit('publish-complete', { name: claim, result });
|
// 2. update old record of create new one (update is in case the claim has been published before by this daemon)
|
||||||
|
upsert(
|
||||||
|
db.File,
|
||||||
|
{
|
||||||
|
name,
|
||||||
|
claimId : result.claim_id,
|
||||||
|
outpoint: `${result.txid}:${result.nout}`,
|
||||||
|
height : 0,
|
||||||
|
fileName,
|
||||||
|
filePath,
|
||||||
|
fileType,
|
||||||
|
nsfw,
|
||||||
|
},
|
||||||
|
{ name, claimId: result.claim_id }
|
||||||
|
).catch(error => {
|
||||||
|
logger.error('Sequelize findOne error', error);
|
||||||
|
});
|
||||||
|
// update client
|
||||||
|
socket.emit('publish-complete', { name, result });
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
logger.error(`Error publishing ${fileName}`, error);
|
logger.error(`Error publishing ${fileName}`, error);
|
||||||
|
// google analytics
|
||||||
visitor.event('Publish Route', 'Publish Failure', filePath).send();
|
visitor.event('Publish Route', 'Publish Failure', filePath).send();
|
||||||
socket.emit('publish-failure', errorHandlers.handlePublishError(error));
|
socket.emit('publish-failure', errorHandlers.handlePublishError(error));
|
||||||
deleteTemporaryFile(filePath);
|
deleteTemporaryFile(filePath);
|
||||||
|
|
|
@ -4,10 +4,92 @@ 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');
|
||||||
|
|
||||||
function getClaimAndHandleResponse (claimUri, resolve, reject) {
|
function updateFileIfNeeded (uri, claimName, claimId, localOutpoint, localHeight) {
|
||||||
|
logger.debug(`A mysql record was found for ${claimId}`);
|
||||||
|
logger.debug('initiating resolve on claim to check outpoint');
|
||||||
|
// 1. resolve claim
|
||||||
lbryApi
|
lbryApi
|
||||||
.getClaim(claimUri)
|
.resolveUri(uri)
|
||||||
.then(({ file_name, download_path, mime_type }) => {
|
.then(result => {
|
||||||
|
// logger.debug('resolved result:', result);
|
||||||
|
const resolvedOutpoint = `${result[uri].claim.txid}:${result[uri].claim.nout}`;
|
||||||
|
const resolvedHeight = result[uri].claim.height;
|
||||||
|
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, resolvedHeight);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
logger.error(`error resolving "${uri}" >> `, error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getClaimAndUpdate (uri, 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 '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, height, resolve, reject) {
|
||||||
|
lbryApi
|
||||||
|
.getClaim(uri)
|
||||||
|
.then(({ name, claim_id, outpoint, file_name, download_path, mime_type, metadata }) => {
|
||||||
|
// create entry in the db
|
||||||
|
logger.debug('creating new record in db');
|
||||||
|
db.File
|
||||||
|
.create({
|
||||||
|
name,
|
||||||
|
claimId : claim_id,
|
||||||
|
outpoint,
|
||||||
|
height,
|
||||||
|
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({
|
resolve({
|
||||||
fileName: file_name,
|
fileName: file_name,
|
||||||
filePath: download_path,
|
filePath: download_path,
|
||||||
|
@ -22,35 +104,31 @@ function getClaimAndHandleResponse (claimUri, resolve, reject) {
|
||||||
module.exports = {
|
module.exports = {
|
||||||
getClaimByName (claimName) {
|
getClaimByName (claimName) {
|
||||||
const deferred = new Promise((resolve, reject) => {
|
const deferred = new Promise((resolve, reject) => {
|
||||||
// get all free public claims
|
// 1. get the top free, public claims
|
||||||
getAllFreePublicClaims(claimName)
|
getAllFreePublicClaims(claimName)
|
||||||
.then(freePublicClaimList => {
|
.then(freePublicClaimList => {
|
||||||
const claimId = freePublicClaimList[0].claim_id;
|
|
||||||
const name = freePublicClaimList[0].name;
|
const name = freePublicClaimList[0].name;
|
||||||
const freePublicClaimOutpoint = `${freePublicClaimList[0].txid}:${freePublicClaimList[0].nout}`;
|
const claimId = freePublicClaimList[0].claim_id;
|
||||||
const freePublicClaimUri = `${name}#${claimId}`;
|
const uri = `${name}#${claimId}`;
|
||||||
// check to see if the file is available locally
|
const height = freePublicClaimList[0].height;
|
||||||
|
// 2. check to see if the file is available locally
|
||||||
db.File
|
db.File
|
||||||
.findOne({ where: { name: name, claimId: claimId } })
|
.findOne({ where: { name, claimId } })
|
||||||
.then(claim => {
|
.then(claim => {
|
||||||
// if a matching claim is found locally...
|
// 3. if a matching claim_id is found locally, serve it
|
||||||
if (claim) {
|
if (claim) {
|
||||||
logger.debug(`A mysql record was found for ${claimId}`);
|
// serve the file
|
||||||
// if the outpoint's match return it
|
resolve(claim.dataValues);
|
||||||
if (claim.dataValues.outpoint === freePublicClaimOutpoint) {
|
// trigger update if needed
|
||||||
logger.debug(`local outpoint matched for ${claimId}`);
|
updateFileIfNeeded(uri, name, claimId, claim.dataValues.outpoint, claim.dataValues.height);
|
||||||
resolve(claim.dataValues);
|
// 3. otherwise use daemon to retrieve it
|
||||||
// if the outpoint's don't match, fetch updated claim
|
|
||||||
} else {
|
|
||||||
logger.debug(`local outpoint did not match for ${claimId}`);
|
|
||||||
getClaimAndHandleResponse(freePublicClaimUri, resolve, reject);
|
|
||||||
}
|
|
||||||
// ... otherwise use daemon to retrieve it
|
|
||||||
} else {
|
} else {
|
||||||
getClaimAndHandleResponse(freePublicClaimUri, resolve, reject);
|
// get the claim and serve it
|
||||||
|
getClaimAndHandleResponse(uri, height, resolve, reject);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
logger.error('sequelize error', error);
|
||||||
reject(error);
|
reject(error);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
|
@ -60,42 +138,37 @@ module.exports = {
|
||||||
});
|
});
|
||||||
return deferred;
|
return deferred;
|
||||||
},
|
},
|
||||||
getClaimByClaimId (claimName, claimId) {
|
getClaimByClaimId (name, claimId) {
|
||||||
const deferred = new Promise((resolve, reject) => {
|
const deferred = new Promise((resolve, reject) => {
|
||||||
const uri = `${claimName}#${claimId}`;
|
const uri = `${name}#${claimId}`;
|
||||||
// resolve the Uri
|
// 1. check locally for the claim
|
||||||
lbryApi
|
db.File
|
||||||
.resolveUri(uri) // note: use 'spread' and make parallel with db.File.findOne()
|
.findOne({ where: { name, claimId } })
|
||||||
.then(result => {
|
.then(claim => {
|
||||||
const resolvedOutpoint = `${result[uri].claim.txid}:${result[uri].claim.nout}`;
|
// 2. if a match is found locally, serve it
|
||||||
// check locally for the claim
|
if (claim) {
|
||||||
db.File
|
// serve the file
|
||||||
.findOne({ where: { name: claimName, claimId: claimId } })
|
resolve(claim.dataValues);
|
||||||
.then(claim => {
|
// trigger an update if needed
|
||||||
// if a found locally...
|
updateFileIfNeeded(uri, name, claimId, claim.dataValues.outpoint, claim.dataValues.outpoint);
|
||||||
if (claim) {
|
// 2. otherwise use daemon to retrieve it
|
||||||
logger.debug(`A mysql record was found for ${claimId}`);
|
} else {
|
||||||
// if the outpoint's match return it
|
// 3. resolve the Uri
|
||||||
if (claim.dataValues.outpoint === resolvedOutpoint) {
|
lbryApi
|
||||||
logger.debug(`local outpoint matched for ${claimId}`);
|
.resolveUri(uri)
|
||||||
resolve(claim.dataValues);
|
.then(result => {
|
||||||
// if the outpoint's don't match, fetch updated claim
|
// 4. check to see if the claim is free & public
|
||||||
} else {
|
|
||||||
logger.debug(`local outpoint did not match for ${claimId}`);
|
|
||||||
getClaimAndHandleResponse(uri, resolve, reject);
|
|
||||||
}
|
|
||||||
// ... otherwise use daemon to retrieve it
|
|
||||||
} else {
|
|
||||||
if (isFreePublicClaim(result[uri].claim)) {
|
if (isFreePublicClaim(result[uri].claim)) {
|
||||||
getClaimAndHandleResponse(uri, resolve, reject);
|
// 5. get claim and serve
|
||||||
|
getClaimAndHandleResponse(uri, result[uri].claim.height, resolve, reject);
|
||||||
} else {
|
} else {
|
||||||
reject('NO_FREE_PUBLIC_CLAIMS');
|
reject('NO_FREE_PUBLIC_CLAIMS');
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
})
|
.catch(error => {
|
||||||
.catch(error => {
|
reject(error);
|
||||||
reject(error);
|
});
|
||||||
});
|
}
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
reject(error);
|
||||||
|
|
|
@ -16,8 +16,8 @@ function filterForFreePublicClaims (claimsListArray) {
|
||||||
return freePublicClaims;
|
return freePublicClaims;
|
||||||
}
|
}
|
||||||
|
|
||||||
function orderTopClaims (claimsListArray) {
|
function orderClaims (claimsListArray) {
|
||||||
logger.debug('ordering the top claims');
|
logger.debug('ordering the free public claims');
|
||||||
claimsListArray.sort((a, b) => {
|
claimsListArray.sort((a, b) => {
|
||||||
if (a.amount === b.amount) {
|
if (a.amount === b.amount) {
|
||||||
return a.height < b.height;
|
return a.height < b.height;
|
||||||
|
@ -51,7 +51,7 @@ module.exports = claimName => {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// order the claims
|
// order the claims
|
||||||
const orderedPublicClaims = orderTopClaims(freePublicClaims);
|
const orderedPublicClaims = orderClaims(freePublicClaims);
|
||||||
// resolve the promise
|
// resolve the promise
|
||||||
resolve(orderedPublicClaims);
|
resolve(orderedPublicClaims);
|
||||||
})
|
})
|
||||||
|
|
|
@ -2,7 +2,7 @@ const logger = require('winston');
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
handleRequestError (error, res) {
|
handleRequestError (error, res) {
|
||||||
logger.error('Request Error,', error);
|
logger.error('Request Error >>', error);
|
||||||
if (error === 'NO_CLAIMS' || error === 'NO_FREE_PUBLIC_CLAIMS') {
|
if (error === 'NO_CLAIMS' || error === 'NO_FREE_PUBLIC_CLAIMS') {
|
||||||
res.status(307).render('noClaims');
|
res.status(307).render('noClaims');
|
||||||
} else if (error.response) {
|
} else if (error.response) {
|
||||||
|
@ -10,11 +10,11 @@ module.exports = {
|
||||||
} else if (error.code === 'ECONNREFUSED') {
|
} else if (error.code === 'ECONNREFUSED') {
|
||||||
res.status(400).send('Connection refused. The daemon may not be running.');
|
res.status(400).send('Connection refused. The daemon may not be running.');
|
||||||
} else {
|
} else {
|
||||||
res.status(400).send(error.toString());
|
res.status(400).send(JSON.stringify(error));
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
handlePublishError (error) {
|
handlePublishError (error) {
|
||||||
logger.error('Publish Error,', error);
|
logger.error('Publish Error >>', error);
|
||||||
if (error.code === 'ECONNREFUSED') {
|
if (error.code === 'ECONNREFUSED') {
|
||||||
return 'Connection refused. The daemon may not be running.';
|
return 'Connection refused. The daemon may not be running.';
|
||||||
} else if (error.response.data.error) {
|
} else if (error.response.data.error) {
|
||||||
|
|
|
@ -1,15 +1,6 @@
|
||||||
const axios = require('axios');
|
const axios = require('axios');
|
||||||
const db = require('../../models');
|
|
||||||
const logger = require('winston');
|
const logger = require('winston');
|
||||||
|
|
||||||
function createFilesRecord (name, claimId, outpoint, fileName, filePath, fileType, nsfw) {
|
|
||||||
db.File
|
|
||||||
.create({ name, claimId, outpoint, fileName, filePath, fileType, nsfw })
|
|
||||||
.catch(error => {
|
|
||||||
logger.error(`Sequelize File.create error`, error);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
publishClaim (publishParams, fileName, fileType) {
|
publishClaim (publishParams, fileName, fileType) {
|
||||||
logger.debug(`Publishing claim for "${fileName}"`);
|
logger.debug(`Publishing claim for "${fileName}"`);
|
||||||
|
@ -21,8 +12,6 @@ module.exports = {
|
||||||
})
|
})
|
||||||
.then(response => {
|
.then(response => {
|
||||||
const result = response.data.result;
|
const result = response.data.result;
|
||||||
createFilesRecord(
|
|
||||||
publishParams.name, result.claim_id, `${result.txid}:${result.nout}`, fileName, publishParams.file_path, fileType, publishParams.metadata.nsfw);
|
|
||||||
resolve(result);
|
resolve(result);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
@ -50,11 +39,7 @@ module.exports = {
|
||||||
/*
|
/*
|
||||||
note: put in a check to make sure we do not resolve until the download is actually complete (response.data.completed === true)
|
note: put in a check to make sure we do not resolve until the download is actually complete (response.data.completed === true)
|
||||||
*/
|
*/
|
||||||
// save a record of the file to the Files table
|
resolve(data.result);
|
||||||
const result = data.result;
|
|
||||||
createFilesRecord(
|
|
||||||
result.name, result.claim_id, result.outpoint, result.file_name, result.download_path, result.mime_type, result.metadata.stream.metadata.nsfw);
|
|
||||||
resolve(result);
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
reject(error);
|
reject(error);
|
||||||
|
@ -88,6 +73,11 @@ module.exports = {
|
||||||
params: { uri },
|
params: { uri },
|
||||||
})
|
})
|
||||||
.then(({ data }) => {
|
.then(({ data }) => {
|
||||||
|
// check for errors
|
||||||
|
if (data.result[uri].error) {
|
||||||
|
reject(data.result[uri].error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
resolve(data.result);
|
resolve(data.result);
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
module.exports = (sequelize, { STRING, BOOLEAN }) => {
|
module.exports = (sequelize, { STRING, BOOLEAN, INTEGER }) => {
|
||||||
const File = sequelize.define(
|
const File = sequelize.define(
|
||||||
'File',
|
'File',
|
||||||
{
|
{
|
||||||
|
@ -14,6 +14,11 @@ module.exports = (sequelize, { STRING, BOOLEAN }) => {
|
||||||
type : STRING,
|
type : STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
},
|
},
|
||||||
|
height: {
|
||||||
|
type : INTEGER,
|
||||||
|
allowNull: false,
|
||||||
|
default : 0,
|
||||||
|
},
|
||||||
fileName: {
|
fileName: {
|
||||||
type : STRING,
|
type : STRING,
|
||||||
allowNull: false,
|
allowNull: false,
|
||||||
|
|
|
@ -14,10 +14,10 @@ const sequelize = new Sequelize(connectionUri, {
|
||||||
sequelize
|
sequelize
|
||||||
.authenticate()
|
.authenticate()
|
||||||
.then(() => {
|
.then(() => {
|
||||||
logger.info('Sequelize has has been established mysql connection successfully.');
|
logger.info('Sequelize has established mysql connection successfully.');
|
||||||
})
|
})
|
||||||
.catch(err => {
|
.catch(err => {
|
||||||
logger.error('Sequelize was nable to connect to the database:', err);
|
logger.error('Sequelize was unable to connect to the database:', err);
|
||||||
});
|
});
|
||||||
|
|
||||||
fs.readdirSync(__dirname).filter(file => file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js').forEach(file => {
|
fs.readdirSync(__dirname).filter(file => file.indexOf('.') !== 0 && file !== basename && file.slice(-3) === '.js').forEach(file => {
|
||||||
|
|
158
public/assets/js/claimPublish.js
Normal file
158
public/assets/js/claimPublish.js
Normal file
|
@ -0,0 +1,158 @@
|
||||||
|
// 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 = '<p>|';
|
||||||
|
for (var i = 0; i < x; i++){ bars += ' | '; }
|
||||||
|
bars += '</p>';
|
||||||
|
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) {
|
||||||
|
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
|
||||||
|
} 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').checked;
|
||||||
|
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 = '<div id="publish-status"></div><div id="progress-bar"></div>';
|
||||||
|
// 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 = '<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><span id="tweet-meme-button"></span>Your publish is complete! <a target="_blank" href="' + directUrl + '">View it here!</a></p>';
|
||||||
|
publishResults += '<p><a target="_blank" href="https://explorer.lbry.io/#!/transaction/' + msg.result.txid + '">View the transaction details</a></p>';
|
||||||
|
publishResults += '<a href="/"><button>Reload</button></a></p>';
|
||||||
|
// update publish area
|
||||||
|
document.getElementById('publish-active-area').innerHTML = publishResults;
|
||||||
|
// add a tweet button
|
||||||
|
twttr.widgets
|
||||||
|
.createShareButton(
|
||||||
|
document.getElementById('tweet-meme-button'),
|
||||||
|
{
|
||||||
|
text: 'Check out my image, hosted for free on the distributed awesomeness that is the LBRY blockchain!',
|
||||||
|
url: 'https://spee.ch/' + directUrl,
|
||||||
|
hashtags: 'LBRY',
|
||||||
|
via: 'lbryio'
|
||||||
|
})
|
||||||
|
.then( function( el ) {
|
||||||
|
console.log('Tweet button added.');
|
||||||
|
});
|
||||||
|
});
|
|
@ -22,6 +22,18 @@ img.onload = function() {
|
||||||
drawMeme()
|
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
|
// if the text changes, re-draw the meme
|
||||||
topText.addEventListener('keyup', drawMeme);
|
topText.addEventListener('keyup', drawMeme);
|
||||||
bottomText.addEventListener('keyup', drawMeme);
|
bottomText.addEventListener('keyup', drawMeme);
|
||||||
|
@ -40,14 +52,14 @@ function drawMeme() {
|
||||||
var text1 = topText.value;
|
var text1 = topText.value;
|
||||||
text1 = text1.toUpperCase();
|
text1 = text1.toUpperCase();
|
||||||
x = canvasWidth / 2;
|
x = canvasWidth / 2;
|
||||||
y = 0;
|
y = 5;
|
||||||
|
|
||||||
wrapText(ctx, text1, x, y, canvasWidth, fontSize, false);
|
wrapText(ctx, text1, x, y, canvasWidth, fontSize, false);
|
||||||
|
|
||||||
ctx.textBaseline = 'bottom';
|
ctx.textBaseline = 'bottom';
|
||||||
var text2 = bottomText.value;
|
var text2 = bottomText.value;
|
||||||
text2 = text2.toUpperCase();
|
text2 = text2.toUpperCase();
|
||||||
y = canvasHeight;
|
y = canvasHeight - 5;
|
||||||
|
|
||||||
wrapText(ctx, text2, x, y, canvasHeight, fontSize, true);
|
wrapText(ctx, text2, x, y, canvasHeight, fontSize, true);
|
||||||
|
|
||||||
|
|
|
@ -114,23 +114,20 @@ socket.on('publish-failure', function(msg){
|
||||||
});
|
});
|
||||||
socket.on('publish-complete', function(msg){
|
socket.on('publish-complete', function(msg){
|
||||||
var publishResults;
|
var publishResults;
|
||||||
var directUrl = 'https://spee.ch/' + msg.name + '/' + msg.result.claim_id;
|
var directUrl = '/' + msg.name + '/' + msg.result.claim_id;
|
||||||
// build new publish area
|
// build new publish area
|
||||||
publishResults = '<p><span id="tweet-meme-button"></span>Your publish is complete! Go ahead, share it with the world!</p>';
|
publishResults = '<p><span id="tweet-meme-button"></span>Your publish is complete! <a target="_blank" href="' + directUrl + '">View it here!</a></p>';
|
||||||
publishResults += '<p><strong>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.</strong></p>';
|
publishResults += '<p><a target="_blank" href="https://explorer.lbry.io/#!/transaction/' + msg.result.txid + '">View the transaction details</a></p>';
|
||||||
publishResults += '<p>Your meme has been published to <a target="_blank" href="/' + msg.name + '">http://spee.ch/' + msg.name + '</a></p>';
|
publishResults += '<a href="/"><button>Reload</button></a></p>';
|
||||||
publishResults += '<p>Here is a direct link to where your meme will be stored: <a target="_blank" href="' + directUrl + '">' + directUrl + '</a></p>';
|
|
||||||
publishResults += '<p>Your Transaction ID is: <a target="_blank" href="https://explorer.lbry.io/#!/transaction?id=' + msg.result.txid + '">' + msg.result.txid + '</a></p>';
|
|
||||||
publishResults += '<p><a href="/meme-fodder/play">Reload to publish another</a></p>';
|
|
||||||
// update publish area
|
// update publish area
|
||||||
document.getElementById('publish-active-area').innerHTML = publishResults;
|
document.getElementById('publish-active-area').innerHTML = publishResults;
|
||||||
// add a tweet button
|
// add a tweet button
|
||||||
twttr.widgets
|
twttr.widgets
|
||||||
.createShareButton(
|
.createShareButton(
|
||||||
directUrl,
|
|
||||||
document.getElementById('tweet-meme-button'),
|
document.getElementById('tweet-meme-button'),
|
||||||
{
|
{
|
||||||
text: 'Check out my meme creation on the LBRY blockchain!',
|
text: 'Check out my meme creation on the LBRY blockchain!',
|
||||||
|
url: 'https://spee.ch/' + directUrl,
|
||||||
hashtags: 'LBRYMemeFodder',
|
hashtags: 'LBRYMemeFodder',
|
||||||
via: 'lbryio'
|
via: 'lbryio'
|
||||||
})
|
})
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<h3>All Claims</h3>
|
<h3>All Claims</h3>
|
||||||
<p>These are all the free, public assets at that claim. You can publish more at <a href="/">spee.ch</a>.</p>
|
<p>These are all the free, public assets at that claim. You can publish more at <a href="/">spee.ch</a>.</p>
|
||||||
{{#each claims}}
|
{{#each claims}}
|
||||||
<img class="all-claims-img" src="https://spee.ch/{{this.name}}/{{this.claim_id}}" />
|
<img class="all-claims-img" src="/{{this.name}}/{{this.claim_id}}" />
|
||||||
<div class="card card-block">
|
<div class="card card-block">
|
||||||
<p>claim_id: {{this.claim_id}}</p>
|
<p>claim_id: {{this.claim_id}}</p>
|
||||||
<p>direct link <a href="/{{this.name}}/{{this.claim_id}}">here</a></p>
|
<p>direct link <a href="/{{this.name}}/{{this.claim_id}}">here</a></p>
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{{> topBar}}
|
{{> topBar}}
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{> examples}}
|
{{> publish}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{> publish}}
|
{{> examples}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{> documentation}}
|
{{> documentation}}
|
||||||
|
@ -14,151 +14,9 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||||
|
|
||||||
<script src="/socket.io/socket.io.js"></script>
|
<script src="/socket.io/socket.io.js"></script>
|
||||||
<script src="/siofu/client.js"></script>
|
<script src="/siofu/client.js"></script>
|
||||||
<script>
|
|
||||||
// define variables
|
|
||||||
var socket = io();
|
|
||||||
var uploader = new SocketIOFileUpload(socket);
|
|
||||||
var stagedFiles = null;
|
|
||||||
|
|
||||||
/* helper functions */
|
<script src="/assets/js/claimPublish.js"></script>
|
||||||
// create a progress animation
|
|
||||||
function createProgressBar(element, size){
|
|
||||||
var x = 1;
|
|
||||||
var adder = 1;
|
|
||||||
function addOne(){
|
|
||||||
var bars = '<p>|';
|
|
||||||
for (var i = 0; i < x; i++){ bars += ' | '; }
|
|
||||||
bars += '</p>';
|
|
||||||
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) {
|
|
||||||
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
|
|
||||||
} 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 = '<div id="publish-status"></div><div id="progress-bar"></div>';
|
|
||||||
// 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 = '<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 = '<p>Your publish is complete!</p>';
|
|
||||||
publishResults += '<p><strong>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.</strong></p>';
|
|
||||||
publishResults += '<p>Your Transaction ID is: <a target="_blank" href="https://explorer.lbry.io/#!/transaction?id=' + msg.result.txid + '">' + msg.result.txid + '</a></p>';
|
|
||||||
publishResults += '<p>Your Claim ID is: ' + msg.result.claim_id + '</p>';
|
|
||||||
publishResults += '<p>Here is a link to the claim where your asset will be published: <a target="_blank" href="https://spee.ch/' + msg.name + '">spee.ch/' + msg.name + '</a></p>';
|
|
||||||
publishResults += '<p>Here is a direct link to where your asset will be stored: <a target="_blank" href="https://spee.ch/' + msg.name + '/' + msg.result.claim_id + '">spee.ch/' + msg.name + '/' + msg.result.claim_id + '</a></p>';
|
|
||||||
publishResults += '<p><a href="/">Reload to publish another asset</a></p>';
|
|
||||||
document.getElementById('publish-active-area').innerHTML = publishResults;
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -1,17 +1,18 @@
|
||||||
<div class="container">
|
<div class="container">
|
||||||
{{> topBar}}
|
{{> topBar}}
|
||||||
{{ image }}
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{> memeMaker}}
|
{{> memeFodderMaker}}
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{> memeResults}}
|
{{> memeFodderResults}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="/assets/js/memeDraw.js"></script>
|
|
||||||
|
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
||||||
|
|
||||||
<script src="/socket.io/socket.io.js"></script>
|
<script src="/socket.io/socket.io.js"></script>
|
||||||
<script src="/siofu/client.js"></script>
|
<script src="/siofu/client.js"></script>
|
||||||
|
|
||||||
|
<script src="/assets/js/memeDraw.js"></script>
|
||||||
<script src="/assets/js/memePublish.js"></script>
|
<script src="/assets/js/memePublish.js"></script>
|
|
@ -7,9 +7,8 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<h3>Congratulations, you found the /meme-fodder game</h3>
|
<h3>Congratulations, you found the /meme-fodder game</h3>
|
||||||
<p>Here's how it's played...</p>
|
<p>Create a meme based on the current <i>lbry://meme-fodder</i> claims using the tool below. Got a masterpiece? <a href="https://twitter.com/hashtag/LBRYMemeFodder" target="_blank">Share it with the community</a> and see what they think!</p>
|
||||||
<p>Create a meme based on the current /meme-fodder claim using the tools below. Got a masterpiece? <a href="https://twitter.com/hashtag/LBRYMemeFodder" target="_blank">Share it with the community</a> and see what they think!</p>
|
<p>Spee.ch/meme-fodder/play uses the free, public images at the claim <a href="lbry://meme-fodder">lbry://meme-fodder</a>. Want to put a different image on the chopping block? Go publish it!</p>
|
||||||
<p>Note: <i>/meme-fodder</i> will always use the public, free image at the claim <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>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
@ -49,5 +48,3 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
|
|
|
@ -6,14 +6,13 @@
|
||||||
<div class="card-block" id="publish-active-area">
|
<div class="card-block" id="publish-active-area">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
<p>Below are some of the most recent images that have been fuel for our enjoyment on /meme-fodder</p>
|
<p>Below are the images published to /meme-fodder. Click one to choose it as your canvas.</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
{{#each claims}}
|
{{#each claims}}
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<a href="/{{this.name}}/{{this.claim_id}}">
|
<img class="all-claims-img" src="/{{this.name}}/{{this.claim_id}}" onclick="newCanvas(this)"/>
|
||||||
<img class="all-claims-img" src="/{{this.name}}/{{this.claim_id}}" /></a>
|
|
||||||
</div>
|
</div>
|
||||||
<hr>
|
<hr>
|
||||||
{{/each}}
|
{{/each}}
|
|
@ -3,8 +3,7 @@
|
||||||
<div class="card-title card-block grey lighten-1 white-text">
|
<div class="card-title card-block grey lighten-1 white-text">
|
||||||
<h2>Publish Your Own</h2>
|
<h2>Publish Your Own</h2>
|
||||||
</div>
|
</div>
|
||||||
<div class="card-block" id="publish-active-area">
|
<div class="card-block">
|
||||||
<form id="publish-form" action="" method="" enctype="multipart/form-data">
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
<div id="drop-zone" ondrop="drop_handler(event);" ondragover="dragover_handler(event);" ondragend="dragend_handler(event)">
|
<div id="drop-zone" ondrop="drop_handler(event);" ondragover="dragover_handler(event);" ondragend="dragend_handler(event)">
|
||||||
|
@ -13,28 +12,28 @@
|
||||||
</div>
|
</div>
|
||||||
<img id="image-preview" src="" height="200" alt="Image preview..."/>
|
<img id="image-preview" src="" height="200" alt="Image preview..."/>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-6">
|
<div id="publish-active-area" class="col-md-6">
|
||||||
<div class="md-form">
|
<form>
|
||||||
<input type="text" id="publish-name" value="Name" class="form-control">
|
<div class="md-form">
|
||||||
</div>
|
<input type="text" id="publish-name" value="Name" class="form-control">
|
||||||
<fieldset class="form-group">
|
</div>
|
||||||
License:
|
<fieldset class="form-group">
|
||||||
<select type="text" id="publish-license" name="license" value="license">
|
License:
|
||||||
<option value="Public Domain">Public Domain</option>
|
<select type="text" id="publish-license" name="license" value="license">
|
||||||
<option value="Creative Commons">Creative Commons</option>
|
<option value="Public Domain">Public Domain</option>
|
||||||
</select>
|
<option value="Creative Commons">Creative Commons</option>
|
||||||
</fieldset>
|
</select>
|
||||||
<fieldset class="form-group">
|
</fieldset>
|
||||||
<input type="checkbox" id="publish-nsfw">
|
<fieldset class="form-group">
|
||||||
<label for="publish-nsfw">NSFW</label>
|
<input type="checkbox" id="publish-nsfw">
|
||||||
</fieldset>
|
<label for="publish-nsfw">NSFW</label>
|
||||||
<p><i>By clicking 'Publish' I attest that I have read and agree to the <a href="https://lbry.io/termsofservice" target="_blank">LBRY terms of service</a>.</i></p>
|
</fieldset>
|
||||||
<button id="publish-submit">Publish</button>
|
<p><i>By clicking 'Publish' I attest that I have read and agree to the <a href="https://lbry.io/termsofservice" target="_blank">LBRY terms of service</a>.</i></p>
|
||||||
<button id="publish-reset">Reset</button>
|
<button id="publish-submit">Publish</button>
|
||||||
|
<button id="publish-reset">Reset</button>
|
||||||
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
Loading…
Reference in a new issue