mirror of
https://github.com/kremalicious/blog.git
synced 2025-01-03 10:25:07 +01:00
new photos
This commit is contained in:
parent
f0bd16ec65
commit
974f6d860c
@ -220,13 +220,15 @@ npm run new "Hello World"
|
||||
npm run new "Hello World" 2017-12-27
|
||||
```
|
||||
|
||||
Create a new photo post with date, title & description pre-filled from EXIF/IPTC data of a given image file:
|
||||
|
||||
```bash
|
||||
npm run new "Hello World" photo
|
||||
npm run new "Hello World" photo 2017-12-27
|
||||
npm run new photo /path/to/photo.jpg
|
||||
```
|
||||
|
||||
- [`scripts/new.js`](scripts/new.js)
|
||||
- [`scripts/new.md`](scripts/new.md)
|
||||
- [`scripts/new-photo.md`](scripts/new-photo.md)
|
||||
|
||||
## 🚚 Deployment
|
||||
|
||||
|
BIN
content/photos/2019-01-27-all-work-and-no-play.jpg
Normal file
BIN
content/photos/2019-01-27-all-work-and-no-play.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.3 MiB |
9
content/photos/2019-01-27-all-work-and-no-play.md
Normal file
9
content/photos/2019-01-27-all-work-and-no-play.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
type: photo
|
||||
date: 2019-01-27T00:00:00.000Z
|
||||
|
||||
title: All Work And No Play
|
||||
image: 2019-01-27-all-work-and-no-play.jpg
|
||||
---
|
||||
|
||||
Inside the [“Stanley Kubrick” exhibition](https://www.cccb.org/en/exhibitions/file/stanley-kubrick/228237) in the [Centre de Cultura Contemporània de Barcelona (CCCB)](https://www.cccb.org) in Barcelona, Catalonia, Spain.
|
BIN
content/photos/2019-02-25-edificio-italia.jpg
Normal file
BIN
content/photos/2019-02-25-edificio-italia.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.4 MiB |
9
content/photos/2019-02-25-edificio-italia.md
Normal file
9
content/photos/2019-02-25-edificio-italia.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
type: photo
|
||||
date: 2019-02-25T22:51:00.000Z
|
||||
|
||||
title: Edifício Itália
|
||||
image: 2019-02-25-edificio-italia.jpg
|
||||
---
|
||||
|
||||
View over São Paulo from the 46th floor of Edifício Itália.
|
Binary file not shown.
After Width: | Height: | Size: 2.3 MiB |
@ -0,0 +1,9 @@
|
||||
---
|
||||
type: photo
|
||||
date: 2019-03-06T17:52:46.000Z
|
||||
|
||||
title: Brazilian Museum of Sculpture and Ecology
|
||||
image: 2019-03-06-brazilian-museum-of-sculpture-and-ecology.jpg
|
||||
---
|
||||
|
||||
On the grounds of the Brazilian Museum of Sculpture and Ecology (MuBE) in São Paulo, Brazil.
|
BIN
content/photos/2019-03-13-paraty-mirim.jpg
Normal file
BIN
content/photos/2019-03-13-paraty-mirim.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.1 MiB |
9
content/photos/2019-03-13-paraty-mirim.md
Normal file
9
content/photos/2019-03-13-paraty-mirim.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
type: photo
|
||||
date: 2019-03-13T00:00:00.000Z
|
||||
|
||||
title: Paraty-Mirim
|
||||
image: 2019-03-13-paraty-mirim.jpg
|
||||
---
|
||||
|
||||
At the Paraty-Mirim beach in Paraty, Rio de Janeiro, Brazil.
|
BIN
content/photos/2019-09-29-arco-di-costantino.jpg
Normal file
BIN
content/photos/2019-09-29-arco-di-costantino.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 MiB |
9
content/photos/2019-09-29-arco-di-costantino.md
Normal file
9
content/photos/2019-09-29-arco-di-costantino.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
type: photo
|
||||
date: 2019-09-29T13:57:00.000Z
|
||||
|
||||
title: Arco di Costantino
|
||||
image: 2019-09-29-arco-di-costantino.jpg
|
||||
---
|
||||
|
||||
The Arch of Constantine seen through the Collosseum walls in Rome, Italy.
|
BIN
content/photos/2019-09-29-foro-di-cesare.jpg
Normal file
BIN
content/photos/2019-09-29-foro-di-cesare.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 MiB |
9
content/photos/2019-09-29-foro-di-cesare.md
Normal file
9
content/photos/2019-09-29-foro-di-cesare.md
Normal file
@ -0,0 +1,9 @@
|
||||
---
|
||||
type: photo
|
||||
date: 2019-09-29T15:31:00.000Z
|
||||
|
||||
title: Foro di Cesare
|
||||
image: 2019-09-29-foro-di-cesare.jpg
|
||||
---
|
||||
|
||||
View over the [Forum of Caesar](https://en.wikipedia.org/wiki/Forum_of_Caesar) within the [Imperial Forum](https://en.wikipedia.org/wiki/Imperial_fora) in Rome, Italy.
|
@ -54,6 +54,7 @@ const constructExifFields = (exifData, createNodeField, node) => {
|
||||
FNumber,
|
||||
ExposureTime,
|
||||
FocalLength,
|
||||
FocalLengthIn35mmFormat,
|
||||
ExposureBiasValue,
|
||||
ExposureMode,
|
||||
LensModel
|
||||
@ -61,7 +62,7 @@ const constructExifFields = (exifData, createNodeField, node) => {
|
||||
|
||||
const iso = `ISO ${ISO}`
|
||||
const fstop = `ƒ ${FNumber}`
|
||||
const focalLength = `${FocalLength}mm`
|
||||
const focalLength = `${FocalLengthIn35mmFormat || FocalLength}mm`
|
||||
|
||||
// Shutter speed
|
||||
const { n, d } = new Fraction(ExposureTime)
|
||||
|
@ -112,6 +112,7 @@
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^24.9.0",
|
||||
"markdownlint-cli": "^0.18.0",
|
||||
"node-iptc": "^1.0.5",
|
||||
"node-sass": "^4.12.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"ora": "^4.0.0",
|
||||
|
@ -6,4 +6,4 @@ title: TITLE
|
||||
image: DATE_SHORT-SLUG.jpg
|
||||
---
|
||||
|
||||
Beep Boop.
|
||||
DESCRIPTION
|
||||
|
@ -2,6 +2,8 @@ import fs from 'fs-extra'
|
||||
import path from 'path'
|
||||
import slugify from 'slugify'
|
||||
import ora from 'ora'
|
||||
import fastExif from 'fast-exif'
|
||||
import iptc from 'node-iptc'
|
||||
|
||||
const templatePath = path.join(__dirname, 'new.md')
|
||||
const templatePathPhoto = path.join(__dirname, 'new-photo.md')
|
||||
@ -14,24 +16,55 @@ if (!process.argv[2]) {
|
||||
spinner.fail('Use the format `npm run new "Title of post"`')
|
||||
}
|
||||
|
||||
const title = process.argv[2]
|
||||
const isPhoto = process.argv[3] === 'photo'
|
||||
let title = process.argv[2]
|
||||
const isPhoto = process.argv[2] === 'photo'
|
||||
|
||||
spinner.text = `Adding '${title}'.`
|
||||
|
||||
const titleSlug = slugify(title, { lower: true })
|
||||
let titleSlug = slugify(title, { lower: true })
|
||||
const postsPath = path.join('.', 'content', 'posts')
|
||||
const photosPath = path.join('.', 'content', 'photos')
|
||||
|
||||
let date = new Date().toISOString()
|
||||
|
||||
if (isPhoto) {
|
||||
if (process.argv[4]) {
|
||||
date = new Date(process.argv[4]).toISOString()
|
||||
async function getIptc(imagePath) {
|
||||
return new Promise((resolve, reject) => {
|
||||
fs.readFile(imagePath, (err, data) => {
|
||||
if (err) reject(err)
|
||||
const iptcData = iptc(data)
|
||||
return resolve(iptcData)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
async function getExif(imagePath) {
|
||||
let exifData
|
||||
try {
|
||||
exifData = await fastExif.read(imagePath, true)
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
|
||||
let iptcData
|
||||
try {
|
||||
iptcData = await getIptc(imagePath)
|
||||
} catch (error) {
|
||||
return null
|
||||
}
|
||||
|
||||
return { ...exifData, iptc: { ...iptcData } }
|
||||
}
|
||||
|
||||
async function createPhotoPost() {
|
||||
const photo = process.argv[3]
|
||||
const exifData = await getExif(photo)
|
||||
title = exifData.iptc.object_name || exifData.iptc.title
|
||||
titleSlug = slugify(title, { lower: true })
|
||||
date = new Date(exifData.exif.DateTimeOriginal).toISOString()
|
||||
const dateShort = date.slice(0, 10)
|
||||
const filePhoto = `${photosPath}/${dateShort}-${titleSlug}.md`
|
||||
const description = exifData.iptc.caption
|
||||
const fileName = `${dateShort}-${titleSlug}`
|
||||
const postPhoto = `${photosPath}/${fileName}.md`
|
||||
|
||||
const newContentsPhoto = templatePhoto
|
||||
.split('TITLE')
|
||||
@ -42,13 +75,23 @@ if (isPhoto) {
|
||||
.join(date)
|
||||
.split('DATE_SHORT')
|
||||
.join(dateShort)
|
||||
.split('DESCRIPTION')
|
||||
.join(description)
|
||||
|
||||
fs.appendFile(filePhoto, newContentsPhoto, err => {
|
||||
if (err) spinner.fail(`Error creating photo post: ${err}`)
|
||||
spinner.succeed(
|
||||
`New photo post '${title}' created.\n\n Use ${dateShort}-${titleSlug}.jpg as the photo file name.`
|
||||
)
|
||||
// copy photo file in place
|
||||
fs.copyFile(photo, `${photosPath}/${fileName}.jpg`, err => {
|
||||
if (err) spinner.fail(`Error copying photo file: ${err}`)
|
||||
})
|
||||
|
||||
// create photo post file
|
||||
fs.appendFile(postPhoto, newContentsPhoto, err => {
|
||||
if (err) spinner.fail(`Error creating photo post: ${err}`)
|
||||
spinner.succeed(`New photo post '${title}' as '${fileName}.md' created.`)
|
||||
})
|
||||
}
|
||||
|
||||
if (isPhoto) {
|
||||
createPhotoPost()
|
||||
} else {
|
||||
if (process.argv[3]) {
|
||||
date = new Date(process.argv[3]).toISOString()
|
||||
|
Loading…
Reference in New Issue
Block a user