about summary refs log tree commit diff stats
path: root/src/pls.fnl
blob: b3bc57530ac93432d2af97e11d9f7ac8ba43a0ae (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
;;; PLS.fnl
;; a parser for *.pls files
;; Copyright (C) 2022 Case Duckworth <acdw@acdw.net>
;; License: Good Choices (https://acdw.casa/gcl)

;; https://en.wikipedia.org/wiki/PLS_(file_format)

(fn split-lines [str]
  "Split STR into a list of lines."
  (icollect [ln (: str :gmatch "([^\n]*)\n?")]
    ln))

(fn parse [str]
  "Parse a list of LINES into a playlist."
  ;; This /maybe/ should take a string, I suppose.
  (let [t []]
    (each [_ l (ipairs (split-lines str))]
      (let [(ltype num title) (: l :match "^(.*)([0-9]+)=(.*)")]
        (when (and ltype num title)
          (let [ltype (string.lower ltype)
                num (tonumber num)]
            (if (. t num)
                (tset t num ltype title)
                (tset t num {ltype title}))))))
    t))

(fn read [file]
  "Read a .pls FILE into a playlist."
  (with-open [p (io.open file)]
    (parse (: p :read :*a))))

(fn serialize [playlist]
  "Serialize a PLAYLIST into a .pls-formatted string."
  (let [s (icollect [n i (ipairs playlist)]
            (.. (string.format "File%d=%s\n" n (. i :file))
                (if (. i :title)
                    (string.format "Title%d=%s\n" n (. i :title))
                    "")
                (if (. i :length)
                    (string.format "Length%d=%s\n" n (. i :length))
                    "")))]
    (.. "[playlist]\n\n" (table.concat s "\n") "\n\n" :NumberOfEntries=
        (length s) "\n" "Version=2\n")))

(fn write [playlist file]
  "Write PLAYLIST to FILE."
  (with-open [p (io.open file :w)]
    (: p :write (serialize playlist))))

{: parse : read : serialize : write}