summaryrefslogtreecommitdiff
path: root/old/2/dl.go.bup
diff options
context:
space:
mode:
authorkaa <kaa@laptosh.my.domain>2024-07-03 08:41:58 -0700
committerkaa <kaa@laptosh.my.domain>2024-07-03 08:41:58 -0700
commit315e747a4c067752dfc69d3d2d6dc23f0c30d8c0 (patch)
tree691355b90ee7e104e58d6ba3f6615bcc9d114057 /old/2/dl.go.bup
Public release.
Diffstat (limited to 'old/2/dl.go.bup')
-rwxr-xr-xold/2/dl.go.bup247
1 files changed, 247 insertions, 0 deletions
diff --git a/old/2/dl.go.bup b/old/2/dl.go.bup
new file mode 100755
index 0000000..7562f48
--- /dev/null
+++ b/old/2/dl.go.bup
@@ -0,0 +1,247 @@
+/* Parse typography.com, find typeface file names. */
+/* Missing some styles. Use https://www.typography.com/api/v1/product_lines/100054?include=multipurpose_styles,office_styles,screen_smart_styles. */
+package main
+
+import (
+ "bufio"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "io"
+ "io/fs"
+ "log"
+ "net/http"
+ "os"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+const (
+ base = "https://typography.com/api/v1"
+)
+
+func request(url string) []byte {
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ rt, err := io.ReadAll(resp.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+ resp.Body.Close()
+
+ return rt
+}
+
+func dlThenRead(name, url string) []byte {
+ _, err := os.Stat(name)
+ if errors.Is(err, fs.ErrNotExist) {
+ log.Print(err)
+ out, err := os.Create(name)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer out.Close()
+
+ outWriter := bufio.NewWriter(out)
+ _, err = outWriter.Write(request(url))
+ if err != nil {
+ log.Fatal(err)
+ }
+ _ = outWriter.Flush()
+ } else if err != nil {
+ log.Fatal(err)
+ }
+
+ in, err := os.Open(name)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer in.Close()
+
+ inReader := bufio.NewReader(in)
+ data, err := io.ReadAll(inReader)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ return data
+}
+
+func parseAndPrint(shortName, css string) {
+ /* Grep for lines containing CSS rules with font names, */
+ for _, line := range strings.Split(css, "\n") {
+ match, err := regexp.Match("font-family:.*", []byte(line))
+ if err != nil {
+ log.Fatal(err)
+ }
+ if match {
+ /* Remove rule boilerplate. */
+ line = strings.Replace(line, " font-family: ", "", 1)
+ line = strings.Replace(line, ", Fallback, Courier;", "", 1)
+
+ /* Split list of file names. */
+ for _, style := range strings.Split(line, ", ") {
+ /* TDB or TDA should become TD. Decided
+ against the complexity of regexp for this. */
+ style = strings.Replace(style, "TDB", "TD", 1)
+ style = strings.Replace(style, "TDA", "TD", 1)
+
+ /* Each style has two files: one with most
+ of the glpyhs, another with just the ' '.
+ Both are necessary, and need merging later. */
+ fmt.Println(shortName, style)
+ fmt.Println(shortName, style+"-Space")
+ }
+ }
+ }
+}
+
+func traverse(name, shortName string, id string) {
+ //fmt.Printf("%s %s %s\n", id, name, shortName)
+
+ /* Create a directory for each typeface. The short name
+ used in URLs contains no spaces. It works well for this use. */
+ _, err := os.Stat(shortName)
+ if err != nil {
+ err = os.Mkdir(shortName, 0666)
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+ err = os.Chdir(shortName)
+ defer os.Chdir("..")
+
+ /* The long name of the typeface is worth keeping. */
+ _, err = os.Stat("name")
+ if errors.Is(err, fs.ErrNotExist) {
+ out, err := os.Create("name")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer out.Close()
+
+ _, err = out.Write([]byte(name))
+ if err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ /* Using the ID passed in from the initial JSON, retrieve new
+ JSON. This contains details on the actual typeface. */
+ /* Parsing for OTF names in progress. */
+ detailsJson := dlThenRead(id, base+"/product_lines/"+id+
+ "?include=special_offers,multipurpose_styles,office_styles,screen_smart_styles&quantity=1&serializer=array")
+ var details interface{}
+ json.Unmarshal(detailsJson, &details)
+ m := details.(map[string]interface{})
+
+ /* The important field is an alphabetic identifier. It must be used
+ in the following step. Hoop jumping. */
+ alphaId := m["desktop_try_code"].(string)
+
+ /* This JSON contains information about how the typeface
+ should be layed out. Embedded is a set of CSS rules.
+ The CSS rules contain the file names of each style of
+ the typeface. */
+ layoutJson := dlThenRead(alphaId, base+"/try/layout/"+
+ alphaId)
+ var layout interface{}
+ json.Unmarshal(layoutJson, &layout)
+ layoutMap := layout.(map[string]interface{})
+
+ /* Interesting data is a few layers deep. */
+ for _, mL2 := range layoutMap {
+ for _, mL3 := range mL2.(map[string]interface{}) {
+ switch mL3.(type) {
+ case map[string]interface{}:
+ mL4 := mL3.(map[string]interface{})
+ layoutL2Json := []byte(mL4["layout_data"].(string))
+ var layoutL2 interface{}
+ json.Unmarshal(layoutL2Json, &layoutL2)
+
+ /* Send the CSS for parsing. */
+ parseAndPrint(shortName,
+ layoutL2.(map[string]interface{})["css"].(string))
+ case string:
+ default:
+ }
+ }
+ }
+
+ /* OTF names. Base names are available as woff. */
+ otf := m["multipurpose_styles"].(map[string]interface{})["styles"].([]interface{})
+ for _, otf := range otf {
+ style := otf.(map[string]interface{})["file_name"].(string)
+ style = strings.TrimSuffix(style, ".otf")
+ style = strings.Replace(style, "-SC", "-TD", 1)
+ if !strings.Contains(style, "-TD") || strings.Contains(style,"_TD") ||
+ shortName == "whitney" {
+ continue
+ }
+ fmt.Println(shortName, style)
+ fmt.Println(shortName, style+"-Space")
+ }
+}
+
+func main() {
+ /* findByName serves as the index to each of
+ the typefaces. If it doesn't exist, download it. */
+ _, err := os.Stat("findByName")
+ if errors.Is(err, fs.ErrNotExist) {
+ log.Print(err)
+ out, err := os.Create("findByName")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer out.Close()
+
+ outWriter := bufio.NewWriter(out)
+ _, err = outWriter.Write(request(base +
+ "/findByName?serializer=array"))
+ if err != nil {
+ log.Fatal(err)
+ }
+ _ = outWriter.Flush()
+ }
+
+ in, err := os.Open("findByName")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer in.Close()
+
+ inReader := bufio.NewReader(in)
+ indexJson, err := io.ReadAll(inReader)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ /* findByName is in JSON. */
+ var index interface{}
+ err = json.Unmarshal(indexJson, &index)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ /* The actually interesting data is a few levels deep. */
+ m := index.(map[string]interface{})
+ for _, mL2 := range m {
+ for _, mL3 := range mL2.([]interface{}) {
+ arr := mL3.(map[string]interface{})
+ /* "name" is the full name, "slug" is the short name,
+ "type_id" is the identifier used in the traversal. */
+ traverse(arr["name"].(string),
+ arr["slug"].(string),
+ strconv.Itoa(int(arr["type_id"].(float64))))
+ }
+ }
+}