Skip to content

Commit

Permalink
Merge pull request #1 from jeroensmink98/dev/v1.01
Browse files Browse the repository at this point in the history
Merge v1.01
  • Loading branch information
jeroensmink98 authored Aug 25, 2021
2 parents fe26aad + e16a306 commit 6569b42
Show file tree
Hide file tree
Showing 6 changed files with 217 additions and 134 deletions.
8 changes: 5 additions & 3 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,9 @@ dist
*.woff
*.woff2

# Exclude json
json/
# Exlude fonts and css folders

css/
fonts/


css/
5 changes: 4 additions & 1 deletion README.MD
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ Give a URL of the typekit fonts and let the script run. It will download all the
With this tool you can increase your performance of your website since the site does not need to retrieve the fonts anymore from a local source, instead it has all the files needed locally avaliable.

# Get started
First create a new folder called `css` and a new folder `fonts` in the root of the project. Then install the node packages and run `npm run scrape` to start the download of the fonts.
- Install `node_modules` by running ``npm install`` from the root of the project
- Inside `app.js` set the ``FONT_KIT_URL`` variable with a valid font-kit css url.
- Execute the script by running `npm run fonts`
- The tool with create a folder ``fonts`` and a folder ``css``. The ``css`` folder contains a file with the font definition which you can include in your own project.

# Acknowlegment
This tool might be against the Terms of Service/EULA of Adobe.
263 changes: 167 additions & 96 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
// Import modules
/* eslint-env node, es6 */
const fs = require("fs");
const log = require("fancy-log");
const https = require('https');
const fs = require('fs');
const cssJson = require('cssjson');
const cssjson = require('cssjson');
const { v4: uuidv4 } = require('uuid');

const FONTS_FOLDER = '/fonts'
const CSS_FOLDER = './css';
const FONTS_FOLDER = './fonts';

// Supply your Typekit URL HERE
// Example: https://use.typekit.net/qeq2vnm.css
const FONT_KIT_URL = '';
var FONT_FAMILY_NAME = ''

// URL of the font you want to scrape
const STYLE_URL = 'https://use.typekit.net/cdd8oev.css';

const FORMAT_USER_AGENTS = {
woff: 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:27.0) Gecko/20100101 Firefox/27.0',
Expand All @@ -23,93 +26,131 @@ const FORMAT_EXTENSIONS = {
'embedded-opentype': 'eot',
};

const CSS_OBJ = {}
// Reject non-https requests
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';

// Create and empty object that we will use to house the font objects later
const downloadedFonts = {};

// Create a new folder in the dist directory where we will house our special css files and fonts
!fs.existsSync(CSS_FOLDER) && fs.mkdirSync(CSS_FOLDER, { recursive: true });
!fs.existsSync(FONTS_FOLDER) && fs.mkdirSync(FONTS_FOLDER, { recursive: true });

const downloadedFonts = {};
process.env.NODE_TLS_REJECT_UNAUTHORIZED = '1';



function createFile(filename, data) {
fs.writeFileSync(filename, data, function (err) {
if (err) throw err;
})
}



// Create new CSS File
https.get(STYLE_URL, (response) => {
if (response.statusCode !== 200) {
throw new Error(`Request failed. Status Code: ${response.statusCode}.`);
}

// Content is the body of the HTTP response
let content = '';
response.on('data', (chunk) => {
// append the byte stream to the content variable
content += chunk;
});
}

// when the response is finished append the content of the variable to
// a new file we will use later as our .css file
response.on('end', () => {
const fontFamily = content.match(/font-family:\s*"([^"]+)"/)[1];
createFile(`css/${fontFamily}.css`, content)
})
});

// Retrieve fonts
for (const format in FORMAT_USER_AGENTS) {
const headers = { 'User-Agent': FORMAT_USER_AGENTS[format] };
https.get(STYLE_URL, { headers }, (response) => {
if (response.statusCode !== 200) {
throw new Error(`Request failed. Status Code: ${response.statusCode}.`);
// Create new CSS File with our font definitions
async function create_definition() {
return new Promise(resolve => {
if(FONT_KIT_URL == ''){
throw new Error(`Font kit url cannot be empty`);
}
https.get(FONT_KIT_URL, (response) => {
if (response.statusCode !== 200) {
throw new Error(`Request failed. Status Code: ${response.statusCode}.`);
}

// Content is the body of the HTTP response
let content = '';
response.on('data', (chunk) => {
content += chunk;
});

response.on('end', () => {
for (const fontFaceRule of content.match(/@font-face {[^}]+}/g)) {
const fontFamily = fontFaceRule.match(/font-family:\s*"([^"]+)"/)[1];
const fontWeight = fontFaceRule.match(/font-weight:\s*([^;]+);/)[1];
const fontStyle = fontFaceRule.match(/font-style:\s*([^;]+);/)[1];
const fontUrlAndFormats = fontFaceRule.match(/url\("([^"]+)"\)\s+format\("([^"]+)"\)/g);

// Content is the body of the HTTP response
let content = '';
response.on('data', (chunk) => {
// append the byte stream to the content variable
content += chunk;
});

for (const fontUrlAndFormat of fontUrlAndFormats) {
const fontUrl = fontUrlAndFormat.match(/url\("([^"]+)"\)/)[1];
// when the response is finished append the content of the variable to
// a new file we will use later as our .css file
response.on('end', () => {
const fontFamily = content.match(/font-family:\s*"([^"]+)"/)[1];
empty_content = ''

// Create class name we want to add to the .css
css_class_str = `.tk-${fontFamily} { font-family: "${fontFamily}",serif; }`

// First check if the definition already exists
fileExists(`${CSS_FOLDER}/${fontFamily}-definition.css`).then(res => {
if (res) {
// File exists so we should remove it
try {
fs.unlinkSync(`${CSS_FOLDER}/${fontFamily}-definition.css`)
createFile(`${CSS_FOLDER}/${fontFamily}-definition.css`, empty_content);
//file removed
resolve()
} catch (err) {
console.error(err)
}
} else {
// File does not exists so no need to remove it
createFile(`${CSS_FOLDER}/${fontFamily}-definition.css`, empty_content);
resolve()
}
})

const fontFormat = fontUrlAndFormat.match(/format\("([^"]+)"\)/)[1].toLowerCase();
const extension = FORMAT_EXTENSIONS[fontFormat] || fontFormat;
});
});
})
}

const filename = `${fontFamily}_${fontWeight}_${fontStyle}.${extension}`;
// Download the font source files
async function download_fontfiles() {
return new Promise(resolve => {
// Retrieve remote font source files
for (const format in FORMAT_USER_AGENTS) {
const headers = { 'User-Agent': FORMAT_USER_AGENTS[format] };
https.get(FONT_KIT_URL, { headers }, (response) => {
if (response.statusCode !== 200) {
throw new Error(`Request failed. Status Code: ${response.statusCode}.`);
}

if (!downloadedFonts[filename]) {
https.get(fontUrl, (response) => {
console.log(`Downloaded "${fontFamily}" font family for "${fontFormat}" format in ${fontWeight} weight and ${fontStyle} style.`);
response.pipe(fs.createWriteStream(`fonts/${filename}`));
});
// Content is the body of the HTTP response
let content = '';
response.on('data', (chunk) => {
content += chunk;
});

response.on('end', () => {
for (const fontFaceRule of content.match(/@font-face {[^}]+}/g)) {
const fontFamily = fontFaceRule.match(/font-family:\s*"([^"]+)"/)[1];
const fontWeight = fontFaceRule.match(/font-weight:\s*([^;]+);/)[1];
const fontStyle = fontFaceRule.match(/font-style:\s*([^;]+);/)[1];
const fontUrlAndFormats = fontFaceRule.match(/url\("([^"]+)"\)\s+format\("([^"]+)"\)/g);


for (const fontUrlAndFormat of fontUrlAndFormats) {
const fontUrl = fontUrlAndFormat.match(/url\("([^"]+)"\)/)[1];

const fontFormat = fontUrlAndFormat.match(/format\("([^"]+)"\)/)[1].toLowerCase();
const extension = FORMAT_EXTENSIONS[fontFormat] || fontFormat;

const filename = `${fontFamily}_${fontWeight}_${fontStyle}.${extension}`;

if (!downloadedFonts[filename]) {
https.get(fontUrl, (response) => {
//log(`Downloaded "${fontFamily}" font family for "${fontFormat}" format in ${fontWeight} weight and ${fontStyle} style.`);
response.pipe(fs.createWriteStream(`${FONTS_FOLDER}/${filename}`));
});
}
}
}
}
}
});
});
resolve(FONT_FAMILY_NAME);
});
});
}
})
}


async function retrieve_font_css_definition() {
async function http_call() {
return new Promise(resolve => {
// Set HTTP Headers

// Make HTTP Request
https.get(STYLE_URL, (response) => {
https.get(FONT_KIT_URL, (response) => {
// Error handeling
if (response.statusCode !== 200) {
throw new Error(`Request failed. Status Code: ${response.statusCode}.`);
Expand All @@ -123,43 +164,74 @@ async function retrieve_font_css_definition() {

// When the HTTP connection is closed we continue our journey
response.on('end', () => {
resolve(content)
})
})
resolve(content);
});
});
});

}

// Return a boolean that checks if a file/folder exists on the given path
async function fileExists(path) {
return new Promise(resolve => {
if (fs.existsSync(path)) {
resolve(true);
} else {
resolve(false);
}
})
}

async function add_style_class(file_url, font_family){
return new Promise(resolve => {
str = `.tk-${font_family} { font-family: "${font_family}",serif; }`
fs.appendFileSync(file_url, str, function (err) {
if (err) throw (err);
resolve('done')
});
})
}

// First we create a definition file
create_definition().then(() => {

retrieve_font_css_definition().then((body) => {
// The body of the http request consists of a body
// with object, these object contain urls
for (const fontFaceRule of body.match(/@font-face {[^}]+}/g)) {
// Fontface properties
const fontFamily = fontFaceRule.match(/font-family:\s*"([^"]+)"/)[1];
const fontWeight = fontFaceRule.match(/font-weight:\s*([^;]+);/)[1];
const fontStyle = fontFaceRule.match(/font-style:\s*([^;]+);/)[1];
const fontUrlAndFormats = fontFaceRule.match(/url\("([^"]+)"\)\s+format\("([^"]+)"\)/g);
// Now we should download the font source files
download_fontfiles().then(() => {

// Parse the content of the HTTP body (our .CSS) to JSON
font = cssjson.toJSON(fontFaceRule);
// Set the content for the definition file
http_call().then((body) => {
// The body of the http request consists of a body
// with object, these object contain urls
for (const fontFaceRule of body.match(/@font-face {[^}]+}/g)) {
// Fontface properties
const fontFamily = fontFaceRule.match(/font-family:\s*"([^"]+)"/)[1];
const fontWeight = fontFaceRule.match(/font-weight:\s*([^;]+);/)[1];
const fontStyle = fontFaceRule.match(/font-style:\s*([^;]+);/)[1];
const fontUrlAndFormats = fontFaceRule.match(/url\("([^"]+)"\)\s+format\("([^"]+)"\)/g);
FONT_FAMILY_NAME = fontFamily;
// Parse the content of the HTTP body (our .CSS) to JSON
font = cssJson.toJSON(fontFaceRule);

// We have to create a filename for the font entry
font_filename = `url("../fonts/${fontFamily}_${fontWeight}_${fontStyle}.woff") format("woff"),url("${fontFamily}_${fontWeight}_${fontStyle}.woff2") format("woff2"),url("${fontFamily}_${fontWeight}_${fontStyle}.otf") format("opentype")`
// We have to create a filename for the font entry
font_filename = `url(".${FONTS_FOLDER}/${fontFamily}_${fontWeight}_${fontStyle}.woff") format("woff"),url(".${FONTS_FOLDER}/${fontFamily}_${fontWeight}_${fontStyle}.woff2") format("woff2"),url(".${FONTS_FOLDER}/${fontFamily}_${fontWeight}_${fontStyle}.otf") format("opentype")`

// Overide the src value in our JSON object
font.children['@font-face']['attributes']['src'] = font_filename;
// Overide the src value in our JSON object
font.children['@font-face']['attributes']['src'] = font_filename;

// Parse our JSON Object to a string
cssString = cssjson.toCSS(font)
// Parse our JSON Object to a string
cssString = cssJson.toCSS(font)

// Inside the loop we can append the content of the font object to our css file
fs.appendFile('css/font_definition.css', cssString, function (err) {
if (err) throw (err)
console.log('append content');
})
}
fs.appendFileSync(`${CSS_FOLDER}/${fontFamily}-definition.css`, cssString, function (err) {
if (err) throw (err);
});
}

// Now we should add the class definition to our css file
add_style_class(`${CSS_FOLDER}/${FONT_FAMILY_NAME}-definition.css`,FONT_FAMILY_NAME ).then((res) => {
log(res)
})
});
})
})


Expand All @@ -169,4 +241,3 @@ retrieve_font_css_definition().then((body) => {




27 changes: 0 additions & 27 deletions index.html

This file was deleted.

Loading

0 comments on commit 6569b42

Please sign in to comment.