Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/majodev/google-webfonts-helper

A Hassle-Free Way to Self-Host Google Fonts. Get eot, ttf, svg, woff and woff2 files + CSS snippets
https://github.com/majodev/google-webfonts-helper

Last synced: 4 days ago
JSON representation

A Hassle-Free Way to Self-Host Google Fonts. Get eot, ttf, svg, woff and woff2 files + CSS snippets

Awesome Lists containing this project

README

        

# google-webfonts-helper [![Uptime Robot status](https://img.shields.io/uptimerobot/status/m793130668-adecafe120852713ed46d6c6)](https://gwfh.mranftl.com) [![Uptime Robot ratio (30 days)](https://img.shields.io/uptimerobot/ratio/m793130668-adecafe120852713ed46d6c6)](https://gwfh.mranftl.com) [![GitHub Sponsors](https://img.shields.io/github/sponsors/majodev)](https://github.com/sponsors/majodev)
> A Hassle-Free Way to Self-Host Google Fonts

✅ **[https://gwfh.mranftl.com](https://gwfh.mranftl.com)**

## Current Sponsors

> *Help me keep this service alive by [sponsoring me](https://github.com/sponsors/majodev). Thank you. ❤️*

[](https://sponsors.mranftl.com/profile/0)
[](https://sponsors.mranftl.com/profile/1)
[](https://sponsors.mranftl.com/profile/2)
[](https://sponsors.mranftl.com/profile/3)
[](https://sponsors.mranftl.com/profile/4)
[](https://sponsors.mranftl.com/profile/5)
[](https://sponsors.mranftl.com/profile/6)
[](https://sponsors.mranftl.com/profile/7)
[](https://sponsors.mranftl.com/profile/8)
[](https://sponsors.mranftl.com/profile/9)
[](https://sponsors.mranftl.com/profile/10)
[](https://sponsors.mranftl.com/profile/11)
[](https://sponsors.mranftl.com/profile/12)
[](https://sponsors.mranftl.com/profile/13)
[](https://sponsors.mranftl.com/profile/14)
[](https://sponsors.mranftl.com/profile/15)
[](https://sponsors.mranftl.com/profile/16)
[](https://sponsors.mranftl.com/profile/17)
[](https://sponsors.mranftl.com/profile/18)
[](https://sponsors.mranftl.com/profile/19)
[](https://sponsors.mranftl.com/profile/20)
[](https://sponsors.mranftl.com/profile/21)
[](https://sponsors.mranftl.com/profile/22)
[](https://sponsors.mranftl.com/profile/23)
[](https://sponsors.mranftl.com/profile/24)
[](https://sponsors.mranftl.com/profile/25)
[](https://sponsors.mranftl.com/profile/26)
[](https://sponsors.mranftl.com/profile/27)
[](https://sponsors.mranftl.com/profile/28)
[](https://sponsors.mranftl.com/profile/29)
[](https://sponsors.mranftl.com/profile/30)
[](https://sponsors.mranftl.com/profile/31)
[](https://sponsors.mranftl.com/profile/32)
[](https://sponsors.mranftl.com/profile/33)
[](https://sponsors.mranftl.com/profile/34)
[](https://sponsors.mranftl.com/profile/35)
[](https://sponsors.mranftl.com/profile/36)
[](https://sponsors.mranftl.com/profile/37)
[](https://sponsors.mranftl.com/profile/38)
[](https://sponsors.mranftl.com/profile/39)
[](https://sponsors.mranftl.com/profile/40)
[](https://sponsors.mranftl.com/profile/41)
[](https://sponsors.mranftl.com/profile/42)
[](https://sponsors.mranftl.com/profile/43)
[](https://sponsors.mranftl.com/profile/44)
[](https://sponsors.mranftl.com/profile/45)
[](https://sponsors.mranftl.com/profile/46)
[](https://sponsors.mranftl.com/profile/47)
[](https://sponsors.mranftl.com/profile/48)
[](https://sponsors.mranftl.com/profile/49)
[](https://sponsors.mranftl.com/profile/50)
[](https://sponsors.mranftl.com/profile/51)
[](https://sponsors.mranftl.com/profile/52)
[](https://sponsors.mranftl.com/profile/53)
[](https://sponsors.mranftl.com/profile/54)
[](https://sponsors.mranftl.com/profile/55)
[](https://sponsors.mranftl.com/profile/56)
[](https://sponsors.mranftl.com/profile/57)
[](https://sponsors.mranftl.com/profile/58)
[](https://sponsors.mranftl.com/profile/59)
[](https://sponsors.mranftl.com/profile/60)
[](https://sponsors.mranftl.com/profile/61)
[](https://sponsors.mranftl.com/profile/62)
[](https://sponsors.mranftl.com/profile/63)
[](https://sponsors.mranftl.com/profile/64)
[](https://sponsors.mranftl.com/profile/65)
[](https://sponsors.mranftl.com/profile/66)
[](https://sponsors.mranftl.com/profile/67)
[](https://sponsors.mranftl.com/profile/68)

## ToC

- [google-webfonts-helper ](#google-webfonts-helper---)
- [Current Sponsors](#current-sponsors)
- [ToC](#toc)
- [Give it a try: https://gwfh.mranftl.com](#give-it-a-try-httpsgwfhmranftlcom)
- [Running gwfh on your own server](#running-gwfh-on-your-own-server)
- [Development](#development)
- [Quickstart](#quickstart)
- [Production build](#production-build)
- [JSON API](#json-api)
- [GET `/api/fonts`](#get-apifonts)
- [GET `/api/fonts/[id]?subsets=latin,latin-ext`](#get-apifontsidsubsetslatinlatin-ext)
- [GET `/api/fonts/[id]?download=zip&subsets=latin&formats=woff,woff2&variants=regular`](#get-apifontsiddownloadzipsubsetslatinformatswoffwoff2variantsregular)
- [History](#history)
- [License](#license)

## Give it a try: [https://gwfh.mranftl.com](https://gwfh.mranftl.com)

This service might be handy if you want to host a specific [Google font](https://fonts.google.com/) on your **own** server:
* font style and charset customization
* CSS snippets
* `.eot`, `.woff`, `.woff2`, `.svg`, `.ttf` font file formats download (zipped).

[![pic running](https://mranftl.com/static/apps/google-webfonts-helper/full_view.png)](https://gwfh.mranftl.com)

## Running gwfh on your own server

I provide prebuilt Docker images via [GitHub Packages](https://github.com/majodev/google-webfonts-helper/pkgs/container/google-webfonts-helper). You can use them as follows:
```bash
# See https://developers.google.com/fonts/docs/developer_api for creating your own API-Key.

docker run -e GOOGLE_FONTS_API_KEY= -p 8080:8080 ghcr.io/majodev/google-webfonts-helper:
# Express server listening on 8080, in production mode
```

## Development

### Quickstart

Do this to setup a development environment:
```bash
# Ensure to set the GOOGLE_FONTS_API_KEY env var inside your own gitignored .env file
# See https://developers.google.com/fonts/docs/developer_api for creating your own API-Key.
echo "GOOGLE_FONTS_API_KEY=" > .env

# Start up the development docker container (multistage Dockerfile, stage 1 only)
./docker-helper.sh --up
# [+] Running 1/0
# ⠿ Container gwfh-service-1 Running
# node@3b506a285f7f:/app$

# within this development container:
node$ yarn --pure-lockfile
node$ ./node_modules/.bin/bower install

# start development server
node$ grunt serve
# [...]
# Express server listening on 9000, in development mode

# The application is now available at http://127.0.0.1:9000 (watching for code changes)

# start production server (same command as within the final docker multistage build)
node$ grunt build
node$ NODE_ENV=production node dist/server/app.js
# Express server listening on 8080, in production mode
```

### Production build

If you want to build and run your own **production** container locally:
```bash
# Build the production docker container (final stage)
docker build . -t

# Run it (if you have previously started the development container, halt it!)
./docker-helper.sh --halt
docker run -e GOOGLE_FONTS_API_KEY= -p 8080:8080
# Express server listening on 8080, in production mode
```

To mitigate security issues especially with the projects' deprecated dependencies, the final image is based on a minimal container image. It runs rootless and has no development dependencies.

## JSON API
The API is public, feel free to use it directly (rate-limits may apply).

### GET `/api/fonts`
Returns a list of all fonts, sorted by popularity. E.g. `curl https://gwfh.mranftl.com/api/fonts`:
```json
[{
"id": "open-sans",
"family": "Open Sans",
"variants": ["300", "300italic", "regular", "italic", "600", "600italic", "700", "700italic", "800", "800italic"],
"subsets": ["devanagari", "greek", "latin", "cyrillic-ext", "cyrillic", "greek-ext", "vietnamese", "latin-ext"],
"category": "sans-serif",
"version": "v10",
"lastModified": "2014-10-17",
"popularity": 1,
"defSubset": "latin",
"defVariant": "regular"
} [...]
]
```

### GET `/api/fonts/[id]?subsets=latin,latin-ext`
Returns a font with urls to the actual font files google's servers. `subsets` is optional (will serve the `defSubset` if unspecified). E.g. `curl "https://gwfh.mranftl.com/api/fonts/modern-antiqua?subsets=latin,latin-ext"` (the double quotes are important as query parameters may else be stripped!):

```json
{
"id": "modern-antiqua",
"family": "Modern Antiqua",
"variants": [{
"id": "regular",
"eot": "https://fonts.gstatic.com/s/modernantiqua/v6/8qX_tr6Xzy4t9fvZDXPkhzThM-TJeMvVB0dIsYy4U7E.eot",
"fontFamily": "'Modern Antiqua'",
"fontStyle": "normal",
"fontWeight": "400",
"woff": "https://fonts.gstatic.com/s/modernantiqua/v6/8qX_tr6Xzy4t9fvZDXPkh1bbnkJREviNM815YSrb1io.woff",
"local": ["Modern Antiqua Regular", "ModernAntiqua-Regular"],
"ttf": "https://fonts.gstatic.com/s/modernantiqua/v6/8qX_tr6Xzy4t9fvZDXPkhxr_S_FdaWWVbb1LgBbjq4o.ttf",
"svg": "https://fonts.gstatic.com/l/font?kit=8qX_tr6Xzy4t9fvZDXPkh0sAoW0rAsWAgyWthbXBUKs#ModernAntiqua",
"woff2": "https://fonts.gstatic.com/s/modernantiqua/v6/8qX_tr6Xzy4t9fvZDXPkh08GHjg64nS_BBLu6wRo0k8.woff2"
}],
"subsets": ["latin", "latin-ext"],
"category": "display",
"version": "v6",
"lastModified": "2014-08-28",
"popularity": 522,
"defSubset": "latin",
"defVariant": "regular",
"subsetMap": {
"latin": true,
"latin-ext": true
},
"storeID": "latin-ext_latin"
}
```

### GET `/api/fonts/[id]?download=zip&subsets=latin&formats=woff,woff2&variants=regular`

Download a zipped archive with all `.eot`, `.woff`, `.woff2`, `.svg`, `.ttf` files of a specified font. The query parameters `formats` and `variants` are optional (includes everything if no filtering is applied). is E.g. `curl -o fontfiles.zip "https://gwfh.mranftl.com/api/fonts/lato?download=zip&subsets=latin,latin-ext&variants=regular,700&formats=woff"` (the double quotes are important as query parameters may else be stripped!)

## History

> 2023:

* Project upgraded to be compatible with Node.js v18+.
* Automated prebuilt Docker images via [GitHub Actions](https://github.com/majodev/google-webfonts-helper/actions).
* `/server` was fully refactored/modernized (async/await) and now compiles with TypeScript.
* Switch to `node:18` for the final image.
* `/client` can still be considered very legacy Angular code.

> 2022:

This service was mostly on life-support, most of its code and dependencies can be considered deprecated. The current docker image wrapping `[email protected]` runs rootless and is hopefully enough to keep the bandits out. API attack surface should be minimal anyways.

> 2014:

This service was originally a prototype I've created to get familiar with Angular and Express. All magic by [generator-angular-fullstack](https://github.com/DaftMonk/generator-angular-fullstack). See [my note here](http://mranftl.com/2014/12/23/self-hosting-google-web-fonts/).

Idea originally by Clemens Lang who created an [awesome bash script](https://neverpanic.de/blog/2014/03/19/downloading-google-web-fonts-for-local-hosting/) to download Google fonts in all formats.

## License
(c) Mario Ranftl
[MIT License](http://majodev.mit-license.org/)

[Google Fonts Open Source Font Attribution](https://fonts.google.com/attribution)