Skip to content

Instantly share code, notes, and snippets.

@Vap0r1ze
Last active October 11, 2023 00:34
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Vap0r1ze/4b2ab7e41f6883a0cae7fce3d6bbd701 to your computer and use it in GitHub Desktop.
Save Vap0r1ze/4b2ab7e41f6883a0cae7fce3d6bbd701 to your computer and use it in GitHub Desktop.
get circular fonts
const fs = require('fs')
const { queue } = require('async')
const request = require('superagent')
async function main() {
const fonts = []
const page = await request
.get('https://lineto.com/typefaces/circular/')
.set('user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36')
fontCutsIndices = []
let i = -1
while((i = page.text.indexOf('fontCuts:[', i+1)) >= 0) fontCutsIndices.push(i)
for (const fontCutsIndex of fontCutsIndices) {
let dataString = ''
let openBracket = 0
i = fontCutsIndex + 9
do {
if (page.text[i] === '[') openBracket++
if (page.text[i] === ']') openBracket--
dataString += page.text[i++]
} while (openBracket > 0)
const vars = dataString
.replace(/"([^"]|\\.)+"/g, '')
.replace(/[\w\$]+:/g, ':')
.match(/[a-z\$_][\w\$]*/gi)
.filter((v, i, a) => a.indexOf(v) === i)
const json = dataString
.replace(/([\w\$]+):/g, '"$1":')
.replace(/(?:[^\w\$][\w\$]+)+([^\w\$])/gi, (m, s) => {
return m.replace(/[\w\$]+/g, v => {
if (vars.includes(v) && s !== '"') return 'null'
return v
})
})
const data = JSON.parse(json)
for (const fontData of data) {
fonts.push({
name: fontData.fullName,
asset: 'https://lineto.com' + fontData.assets.woff
})
}
}
const circularFonts = fonts.filter(font => font.name && font.name.startsWith('Circular') && !font.name.startsWith('Circular Mono'))
const cookies = page.header['set-cookie'].map(cookie => {
cookie = cookie.split(';')[0]
return [cookie.split('=')[0], cookie.split('=').slice(1).join('=')]
})
if (!fs.existsSync('fonts')) fs.mkdirSync('fonts')
const q = queue((font, callback) => {
const stream = fs.createWriteStream('fonts/' + font.name.split(' ').join('-').toLowerCase() + '.woff')
request.get(font.asset)
.set('cookie', cookies.map(kv => kv.join('=')).join(';'))
.set('user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36')
.set('origin', 'https://lineto.com')
.set('referer', 'https://lineto.com/typefaces/circular/')
.pipe(stream)
stream.on('close', () => {
callback()
})
}, 4)
q.push(circularFonts)
}
main()
@adryd325
Copy link

adryd325 commented Aug 19, 2021

EDIT: I should've checked before making this comment; these fonts don't seem to have a valid WOFF2 header, I've tried setting user agent and referrer similar to the above script but they don't seem to make a difference

I'm not sure what happened since I hadn't taken appart the site when this was made, but fontData.fullName, and fontData.assets don't exist anymore, and all values in the "data" variable of this script are null, so I went and made a quick snippet that does similar to this, except it downloads everything with curl, and it's pasted in the browser.

copy(
  __NUXT__.state.font.fontFamilies
    .flatMap((a) => a.fontShopSets)
    .flatMap((a) => a.fontCuts)
    .flatMap((a) =>
      `curl https://lineto.com/api/front/font-cuts/${a.id}/web-font?format=woff2 -o "${a.fontFamily.name} ${a.name}.woff2"`
    )
    .join("\n")
);

@qxygene
Copy link

qxygene commented Jan 19, 2023

TypeError: Cannot read properties of undefined (reading 'woff')

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment