Page MenuHomeDevCentral
Paste P335

Parse CSS
ActivePublic

Authored by dereckson on May 26 2023, 02:06.
Referenced Files
F2227963: Parse CSS
May 26 2023, 02:06
Subscribers
None
import tinycss2
with open('data/SourceSansPro.css', "rb") as fd:
css = fd.read()
rules = tinycss2.parse_stylesheet_bytes(css)
print(rules)
print(rules[0])
print(rules[0][0])
print(rules[0][0].content)
for node in rules[0][0].content:
print(node)

Event Timeline

Example output for a CSS @font-face rule:

[<WhitespaceToken>, <IdentToken font-family>, <LiteralToken :>, <WhitespaceToken>, <StringToken "Source Sans Pro">, <LiteralToken ;>, <WhitespaceToken>, <IdentToken font-style>, <LiteralToken :>, <WhitespaceToken>, <IdentToken italic>, <LiteralToken ;>, <WhitespaceToken>, <IdentToken font-weight>, <LiteralToken :>, <WhitespaceToken>, <NumberToken 400>, <LiteralToken ;>, <WhitespaceToken>, <IdentToken font-display>, <LiteralToken :>, <WhitespaceToken>, <IdentToken swap>, <LiteralToken ;>, <WhitespaceToken>, <IdentToken src>, <LiteralToken :>, <WhitespaceToken>, <URLToken url(https://fonts.gstatic.com/s/sourcesanspro/v21/6xK1dSBYKcSV-LCoeQqfX1RYOo3qPa7g.ttf)>, <WhitespaceToken>, <FunctionBlock format()>, <LiteralToken ;>, <WhitespaceToken>]

Plan for T1881 is to download assets with a <family>-<style>-<weight>.<format> filename scheme.

From the tokens we can do this:

  • Determine this is a font-family rule with has_ident_token(rule, "font-family")
  • Search IdentToken font-family, and then the first StringToken, remove spaces (e.g. "Source Sans Pro" -> "SourceSansPro")
  • Search IdentToken font-style, and then the first IdentToken (e.g. "italic")
  • Search IdentToken font-weight, and then the first NumberToken (e.g. 400)
  • Search IdentToken src, and then the first URLToken, get also extension (e.g. ttf)
  • wget -O dist/SourceSansPro-italic-400.ttf <url>

Then we need to output the rule after replacing the URLToken by https://assets.nasqueron.org/webfonts/SourceSansPro-italic-400.ttf

The exercice must be done in TTF and woff2.

def has_ident_token(rule, token):

return any(token.type == 'IDENT' and token.lower_value == token for token in rule.content)