diff --git a/package.json b/package.json index dc1fa88a605cb46008ce99052559beb50f436155..e9e8f0edb1cad820b03788406ec61e28ba84f305 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "description": "", "main": "index.js", "scripts": { - "test": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- sitegin/test/ --recursive -R spec -u exports -t 60000" + "test": "./node_modules/istanbul/lib/cli.js cover ./node_modules/mocha/bin/_mocha -- sitegin/tests/ --recursive -R spec -u exports -t 60000" }, "author": "", "license": "UNSPECIFIED", diff --git a/sitegin/markdown.js b/sitegin/markdown.js index df8dd7188b8cb6df82d11f5041a43becc3f09197..7a04c7588ddeb1e5ab59d59ba6384fa0bed8623c 100644 --- a/sitegin/markdown.js +++ b/sitegin/markdown.js @@ -8,6 +8,7 @@ var renderer = new marked.Renderer(); var highlightjs = require('highlight.js'); var path = require('path'); var jobs = require('./jobs'); +var youtube = require('./utils/youtube.js'); var toURL = function(url) { return jobs.run('toURL', url); @@ -30,49 +31,68 @@ renderer.paragraph = function(text) { else return '<p>'+text+'</p>\n'; } -var renderImage = function(href, title, text, curFilename) { - var parseParams = function(params) { - for(let param of params.split(',')) { - param = param.trim(); - // 123x or x123 or 123x123 - if(param.match(/[0-9]*x[0-9]+/) || param.match(/[0-9]+x[0-9]*/)) { - options.size = param.split('x'); - if(options.size !== undefined) { - if(options.size[0].length > 0) { - options.width = options.size[0]; - } - if(options.size.length > 1 && options.size[1].length > 0) { - options.height = options.size[1]; - } - } - } else if(param == 'nolightbox') { - options.nolightbox = true; +var paramInHrefParser = function(href) { + var sepIndex = href.indexOf(' ='); + var ret = { + href: href, + options: {} + } + if(sepIndex < 0) { + return ret; + } else { + ret.href = href.substr(0, sepIndex); + var options = href.substr(sepIndex+2); + options = options // split by ',' but not '\,' + .replace('a,','\u0007') + .split(',') + .map(function(e) {return e.replace('\u0007','a,')}); + options.forEach(function(option) { + var index = option.indexOf('='); + if(index < 0) { + ret.options[option] = true; + } else { + var key = option.substr(0,index); + var value = option.substr(index+1); + ret.options[key] = value; } - } + }); + return ret; } +} - href = href.split(path.sep).join('/'); - href = href.split(' ='); - var params = href[1]; - var options = {}; +var renderYoutube = function(href, options) { + var info = youtube.info(href); + let out = '<div class="video-container"><div class="videodiv">'; + out += '<iframe src="https://www.youtube.com/embed/'+info.videoid+ + '?modestbranding&start='+info.time+'" frameborder="0" allowfullscreen></iframe>' + out += '</div></div>' - if(params) { - parseParams(params); - } - href = href[0]; - if(href.match('//(www.)?youtube.com/watch') || href.match('//youtu.be/')) { - var id; - if(href.match('//youtube.com/watch')) { - id = href.substr(href.indexOf('v=')+2).split('&')[0]; - } else { - id = href.substr(href.indexOf('.be/')+4).split('?')[0]; - } + return out; +} - let out = '<div class="video-container"><div class="videodiv">'; - out += '<iframe src="https://www.youtube.com/embed/'+id+'" frameborder="0" allowfullscreen></iframe>' - out += '</div></div>' +var renderImage = function(href, title, text, curFilename) { + var parsed = paramInHrefParser(href); + href = parsed.href; + var options = parsed.options; + + for(let option in options) { + if( !options.hasOwnProperty(option) ) continue; + + if(option.match(/x[0-9]+/) || option.match(/[0-9]+x[0-9]*/)) { // 123x or x123 or 123x123 + options.size = option.split('x'); + if(options.size !== undefined) { + if(options.size[0].length > 0) { + options.width = options.size[0]; + } + if(options.size.length > 1 && options.size[1].length > 0) { + options.height = options.size[1]; + } + } + } + } - return out; + if(youtube.isVideo(href)) { + return renderYoutube(href, options); } else { var rel = path.relative(process.cwd(),path.resolve(curFilename,href)); @@ -147,3 +167,9 @@ module.exports = function(obj) { }); return Promise.resolve(obj); } + +module.exports._test = { + renderImage: renderImage, + paramInHrefParser: paramInHrefParser, + renderYoutube: renderYoutube +}; diff --git a/sitegin/tests/markdownTest.js b/sitegin/tests/markdownTest.js new file mode 100644 index 0000000000000000000000000000000000000000..1590e4583485cb5fb08d232839664058e22e18e4 --- /dev/null +++ b/sitegin/tests/markdownTest.js @@ -0,0 +1,15 @@ +require('should'); + +var o = require('../markdown')._test; + +describe('Markdown', function() { + it('paramInHrefParser image.png =option,option2=123', function() { + o.paramInHrefParser('image.png =option,option2=123').should.be.eql({ + href: 'image.png', + options: { + option: true, + option2: '123' + } + }) + }) +}) diff --git a/sitegin/tests/youtubeTest.js b/sitegin/tests/youtubeTest.js new file mode 100644 index 0000000000000000000000000000000000000000..17f991428e61a7779958f3ff7d48439d81d132da --- /dev/null +++ b/sitegin/tests/youtubeTest.js @@ -0,0 +1,50 @@ +'use strict'; +/*jshint expr: true*/ +require('should'); + +var youtube = require('../utils/youtube.js'); + +describe('Youtube', function() { + let links = { + 'https://www.youtube.com/watch?v=QH2-TGUlwu4': true, + 'http://www.youtube.com/watch?v=QH2-TGUlwu4': true, + 'https://youtu.be/QH2-TGUlwu4': true, + 'https://youtu.be/QH2-TGUlwu4?t=3m30s': true, + 'https://www.youtube.com/watch?t=3m30s&v=QH2-TGUlwu4': true, + 'https://www.youtube.cz/watch?t=3m30s&v=QH2-TGUlwu4': true, + 'https://www.youtube.com/watch?app=desktop&gl=CZ&v=QH2-TGUlwu4&hl=cs&v=cTa1Q2mBeJE': true, + 'https://www.youtube.com/': false, + 'https://www.youtube.com/channel/UCzNxmbk_LA1jXvYgivCCkpw': false, + 'youtube.png': false + } + function testLink(link, val) { + it('isVideo '+link+' => '+val,function() { + youtube.isVideo(link).should.be.equal(val); + }) + } + for(let link in links) { + if(!links.hasOwnProperty(link)) continue; + testLink(link, links[link]); + } + + it('info https://youtu.be/wZZ7oFKsKzY?t=3h30m30s', function() { + var info = youtube.info('https://youtu.be/wZZ7oFKsKzY?t=3h30m30s'); + info.should.be.object; + info.time.should.be.eql(3*3600+30*60+30); + info.videoid.should.be.eql('wZZ7oFKsKzY'); + }) + + it('info https://youtu.be/QH2-TGUlwu4', function() { + var info = youtube.info('https://youtu.be/QH2-TGUlwu4'); + info.should.be.object; + info.time.should.be.eql(0); + info.videoid.should.be.eql('QH2-TGUlwu4'); + }) + + it('info https://www.youtube.com/watch?t=3m30s&v=QH2-TGUlwu4', function() { + var info = youtube.info('https://www.youtube.com/watch?t=3m30s&v=QH2-TGUlwu4'); + info.should.be.object; + info.time.should.be.eql(3*60+30); + info.videoid.should.be.eql('QH2-TGUlwu4'); + }) +}) diff --git a/sitegin/toURL.js b/sitegin/toURL.js index 997e3c0718518e8a037d631d1357de3dfc9de0ad..7d765bb6e886c4dfea799399a239f8dfc78d34a6 100644 --- a/sitegin/toURL.js +++ b/sitegin/toURL.js @@ -7,5 +7,5 @@ var latinise = function(l){return l.replace(/[^A-Za-z0-9\[\] ]/g,function(a){ret module.exports = function(tag) { if(tag === undefined) return undefined; - return latinise(tag.toLowerCase()).replace(/ /g,'-'); + return latinise(tag.toLowerCase()).replace(/ /g,'-').replace(/-+/g,'-'); } diff --git a/sitegin/utils/youtube.js b/sitegin/utils/youtube.js new file mode 100644 index 0000000000000000000000000000000000000000..46913cc29bb1b973d3993dabd2819176a7e05db2 --- /dev/null +++ b/sitegin/utils/youtube.js @@ -0,0 +1,57 @@ +'use strict'; + +var url = require('url'); +var querystring = require('querystring'); + +module.exports.isVideo = function(href) { + var o = url.parse(href); + if(!o.host) return false; + + if(o.host == 'youtu.be') { + return o.pathname.length > 1; + } + + // not youtube link + if(!o.host.match('youtube.[a-zA-Z]+$')) return false; + + var query = querystring.parse(o.query); + // not youtube video + if(!query.v) return false; + + return true; +} + +module.exports.info = function(href) { + href = url.parse(href); + var query = querystring.parse(href.query); + var info = { + videoid: false, + time: 0 + } + + if(href.host == 'youtu.be') { + if(href.pathname.length < 2) throw new Error(href+' is not video link'); + info.videoid = href.pathname.substr(1); + } else if(href.host.match('youtube.[a-zA-Z]+$')) { + if(Array.isArray(query.v)) + info.videoid = query.v[0]; + else + info.videoid = query.v; + } else { + throw new Error(href+' is not youtube url'); + } + if(query.t) { + var units = query.t.split(/[0-9]+/); + units.splice(0,1); + var values = query.t.split(/[^0-9]/); + values.splice(-1,1); + if(units.length != values.length) throw new Error('Youtube: Wrong time specifier: '+query.t); + for(let i = 0; i < units.length; i++) { + if(units[i] == 'h') info.time += Number(values[i])*3600; + else if(units[i] == 'm') info.time += Number(values[i])*60; + else if(units[i] == 's') info.time += Number(values[i]); + else throw new Error('Youtube: Wrong time specifier: '+query.t); + } + } + return info; +}