11 changed files with 336 additions and 21 deletions
-
41config/default.js
-
5package-lock.json
-
1package.json
-
4src/app.js
-
2src/args.js
-
96src/content/fetch.js
-
5src/content/gfycat.js
-
119src/content/store.js
-
4src/feeds/feeds.js
-
4src/utils/http.js
-
76src/utils/slugify.js
@ -1,6 +1,47 @@ |
|||
module.exports = { |
|||
library: { |
|||
temp: 'output/temp', |
|||
base: { |
|||
feed: 'output/{feed.name}/', |
|||
direct: 'output/{host.slug}/', |
|||
}, |
|||
feed: { |
|||
image: '{base.feed}{post.date}{div}{item.id}{div}{post.title}{ext}', |
|||
video: '{base.feed}{post.date}{div}{item.id}{div}{post.title}{ext}', |
|||
text: '{base.feed}{post.date}{div}{item.id}{div}{post.title}', |
|||
album: { |
|||
image: '{base.feed}{post.date}{div}{album.id}{div}{post.title}/{item.index}{div}{item.id}{ext}', |
|||
video: '{base.feed}{post.date}{div}{album.id}{div}{post.title}/{item.index}{div}{item.id}{ext}', |
|||
}, |
|||
}, |
|||
direct: { |
|||
image: '{base.direct}{item.date}{div}{item.id}{divs.item.title}{item.title}{ext}', |
|||
video: '{base.direct}{item.date}{div}{item.id}{divs.item.title}{item.title}{ext}', |
|||
text: '{base.direct}{item.date}{div}{item.id}{divs.item.title}{item.title}', |
|||
album: { |
|||
image: '{base.direct}{album.date}{div}{album.id}{divs.album.title}{album.title}/{item.index}{div}{item.id}{ext}', |
|||
video: '{base.direct}{album.date}{div}{album.id}{divs.album.title}{album.title}/{item.index}{div}{item.id}{ext}', |
|||
}, |
|||
}, |
|||
extractSingleAlbumItem: true, |
|||
profile: { |
|||
image: '{base.feed}{feed.name}{ext}', |
|||
bio: '{base.feed}{feed.name}', |
|||
}, |
|||
index: { |
|||
file: '{base.feed}index', |
|||
}, |
|||
dateFormat: 'YYYYMMDD', |
|||
divider: ' - ', |
|||
slashSubstitute: '#', |
|||
truncate: { |
|||
limit: 250, |
|||
truncator: '...', |
|||
}, |
|||
}, |
|||
limits: { |
|||
requestInterval: 1000, |
|||
requestConcurrency: 1, |
|||
attempts: 3, |
|||
}, |
|||
}; |
@ -0,0 +1,119 @@ |
|||
'use strict'; |
|||
|
|||
const config = require('config'); |
|||
const Promise = require('bluebird'); |
|||
const path = require('path'); |
|||
const fsPromises = require('fs').promises; |
|||
const format = require('template-format'); |
|||
const moment = require('moment'); |
|||
|
|||
const logger = require('../logger')(__filename); |
|||
|
|||
function interpolate(item, post, feed) { |
|||
const type = item.type.split('/')[0]; |
|||
|
|||
const pattern = feed.type === 'direct' |
|||
? config.library.direct[type] |
|||
: config.library.feed[type]; |
|||
|
|||
const data = {}; |
|||
|
|||
if (feed) { |
|||
data.feed = { |
|||
name: feed.name, |
|||
type: feed.type, |
|||
}; |
|||
} |
|||
|
|||
if (post) { |
|||
data.post = { |
|||
title: post.title, |
|||
}; |
|||
|
|||
data.host = { |
|||
name: post.host.name, |
|||
slug: post.host.slug, |
|||
}; |
|||
} |
|||
|
|||
if (item) { |
|||
data.item = { |
|||
id: item.id, |
|||
title: item.title, |
|||
description: item.description, |
|||
date: item.date && moment(item.date).format(config.library.dateFormat), |
|||
}; |
|||
|
|||
data.ext = `.${item.extension}`; |
|||
} |
|||
|
|||
const dividers = Object.entries(data).reduce((acc, [key, value]) => { |
|||
if (typeof value === 'string') { |
|||
return { |
|||
...acc, |
|||
[key]: value ? config.library.divider : '', |
|||
}; |
|||
} |
|||
|
|||
return { |
|||
...acc, |
|||
[key]: Object.entries(value).reduce((subacc, [subkey, subvalue]) => ({ |
|||
...subacc, |
|||
[subkey]: subvalue ? config.library.divider : '', |
|||
}), {}), |
|||
}; |
|||
}, {}); |
|||
|
|||
const interpolated = format(pattern, { |
|||
...data, |
|||
base: { |
|||
feed: format(config.library.base.feed, data), |
|||
direct: format(config.library.base.direct, data), |
|||
}, |
|||
dividers, |
|||
divider: config.library.divider, |
|||
div: config.library.divider, |
|||
divs: dividers, |
|||
}); |
|||
|
|||
return interpolated; |
|||
} |
|||
|
|||
async function storeItem(item, post, feed) { |
|||
if (!item.tempPath) { |
|||
return item; |
|||
} |
|||
|
|||
const destination = interpolate(item, post, feed); |
|||
|
|||
logger.info(`Storing '${item.title || post.title}' from '${feed.name}' at ${destination}`); |
|||
|
|||
await fsPromises.mkdir(path.parse(destination).dir, { recursive: true }); |
|||
await fsPromises.rename(item.tempPath, destination); |
|||
|
|||
return item; |
|||
} |
|||
|
|||
async function storeContent(post, feed) { |
|||
if (!post.content) { |
|||
return post; |
|||
} |
|||
|
|||
const storedItems = await Promise.map( |
|||
post.content.items, |
|||
async (item) => storeItem(item, post, feed), |
|||
{ concurrency: 20 }, |
|||
); |
|||
|
|||
return { |
|||
...post, |
|||
content: { |
|||
...post.content, |
|||
items: storedItems, |
|||
}, |
|||
}; |
|||
} |
|||
|
|||
module.exports = { |
|||
storeContent, |
|||
}; |
@ -0,0 +1,76 @@ |
|||
'use strict'; |
|||
|
|||
const substitutes = { |
|||
à: 'a', |
|||
á: 'a', |
|||
ä: 'a', |
|||
å: 'a', |
|||
ã: 'a', |
|||
æ: 'ae', |
|||
ç: 'c', |
|||
è: 'e', |
|||
é: 'e', |
|||
ë: 'e', |
|||
ẽ: 'e', |
|||
ì: 'i', |
|||
í: 'i', |
|||
ï: 'i', |
|||
ĩ: 'i', |
|||
ǹ: 'n', |
|||
ń: 'n', |
|||
ñ: 'n', |
|||
ò: 'o', |
|||
ó: 'o', |
|||
ö: 'o', |
|||
õ: 'o', |
|||
ø: 'o', |
|||
œ: 'oe', |
|||
ß: 'ss', |
|||
ù: 'u', |
|||
ú: 'u', |
|||
ü: 'u', |
|||
ũ: 'u', |
|||
ỳ: 'y', |
|||
ý: 'y', |
|||
ÿ: 'y', |
|||
ỹ: 'y', |
|||
}; |
|||
|
|||
function slugify(string, delimiter = '-', { |
|||
encode = false, |
|||
removeAccents = true, |
|||
removePunctuation = false, |
|||
limit = 1000, |
|||
} = {}) { |
|||
if (!string || typeof string !== 'string') { |
|||
return string; |
|||
} |
|||
|
|||
const slugComponents = string |
|||
.trim() |
|||
.toLowerCase() |
|||
.replace(removePunctuation && /[.,:;'"]/g, '') |
|||
.match(/[A-Za-zÀ-ÖØ-öø-ÿ0-9]+/g); |
|||
|
|||
if (!slugComponents) { |
|||
return ''; |
|||
} |
|||
|
|||
const slug = slugComponents.reduce((acc, component, index) => { |
|||
const accSlug = `${acc}${index > 0 ? delimiter : ''}${component}`; |
|||
|
|||
if (accSlug.length < limit) { |
|||
if (removeAccents) { |
|||
return accSlug.replace(/[à-ÿ]/g, (match) => substitutes[match] || ''); |
|||
} |
|||
|
|||
return accSlug; |
|||
} |
|||
|
|||
return acc; |
|||
}, ''); |
|||
|
|||
return encode ? encodeURI(slug) : slug; |
|||
} |
|||
|
|||
module.exports = slugify; |
Write
Preview
Loading…
Cancel
Save
Reference in new issue