|
| 1 | +## 2021-02-09 #DLF #Querkoepfe |
| 2 | +*Author: @JensLincke* |
| 3 | + |
| 4 | + |
| 5 | +## #Evolution #MarkdownApp #DirectorySpecificApplication |
| 6 | + |
| 7 | + |
| 8 | + |
| 9 | +<http://localhost:9005/Dropbox/Music/dlf/Querkoepfe/index.md> |
| 10 | + |
| 11 | +(INFO: for this application to work, Lively4 does not have to be installed on localhost... Just a lively4 compatible file server, e.g. that can list (OPTIONS), GET, PUT, DELETE, and optionally MOVE files). In webwerkstatt (Lively2) we used apache webdav for it... our current protocol is custom. |
| 12 | + |
| 13 | +An evening of scripting looked like this.... |
| 14 | + |
| 15 | + |
| 16 | +| filename| date| user | host | size| |
| 17 | +|-------|---|--|---|--| |
| 18 | +| index.md | 22:10 | Bearbeitet von Jens Lincke | Desktop | 3,71 KB | |
| 19 | +| index.md | 22:01 | Bearbeitet von Jens Lincke | Desktop | 3,68 KB | |
| 20 | +| index.md | 21:56 | Bearbeitet von Jens Lincke | Desktop | 3,52 KB | |
| 21 | +| index.md | 21:54 | Bearbeitet von Jens Lincke | Desktop | 3,36 KB | |
| 22 | +| index.md | 21:51 | Bearbeitet von Jens Lincke | Desktop | 3,3 KB | |
| 23 | +| index.md | 21:48 | Bearbeitet von Jens Lincke | Desktop | 3,11 KB | |
| 24 | +| index.md | 21:47 | Bearbeitet von Jens Lincke | Desktop | 3,12 KB | |
| 25 | +| index.md | 21:43 | Bearbeitet von Jens Lincke | Desktop | 2,85 KB | |
| 26 | +| index.md | 21:42 | Bearbeitet von Jens Lincke | Desktop | 2,75 KB | |
| 27 | +| index.md | 21:40 | Bearbeitet von Jens Lincke | Desktop | 2,65 KB | |
| 28 | +| index.md | 21:33 | Bearbeitet von Jens Lincke | Desktop | 2,48 KB | |
| 29 | +| index.md | 21:30 | Bearbeitet von Jens Lincke | Desktop | 2,3 KB | |
| 30 | +| index.md | 21:29 | Bearbeitet von Jens Lincke | Desktop | 2,3 KB | |
| 31 | +| index.md | 21:19 | Bearbeitet von Jens Lincke | Desktop | 1,8 KB | |
| 32 | +| index.md | 21:17 | Bearbeitet von Jens Lincke | Desktop | 1,29 KB | |
| 33 | +| index.md | 21:15 | Bearbeitet von Jens Lincke | Desktop | 1,08 KB | |
| 34 | +| index.md | 21:14 | Bearbeitet von Jens Lincke | Desktop | 1,13 KB | |
| 35 | +| index.md | 21:12 | Bearbeitet von Jens Lincke | Desktop | 1,09 KB | |
| 36 | +| index.md | 21:08 | Bearbeitet von Jens Lincke | Desktop | 1.011 Bytes | |
| 37 | +| index.md | 21:06 | Bearbeitet von Jens Lincke | Desktop | 787 Bytes | |
| 38 | +| index.md | 21:04 | Bearbeitet von Jens Lincke | Desktop | 477 Bytes | |
| 39 | +| index.md | 21:01 | Bearbeitet von Jens Lincke | Desktop | 256 Bytes | |
| 40 | +| index.md | 20:59 | Bearbeitet von Jens Lincke | Desktop | 185 Bytes | |
| 41 | +| index.md | 20:57 | Hinzugefügt von Jens Lincke | Desktop | 15 Bytes | |
| 42 | + |
| 43 | + |
| 44 | +### Starting from a simple listing of files |
| 45 | + |
| 46 | + |
| 47 | +```javascript |
| 48 | +var container = lively.query(this, "lively-container") var dirURL = container.getDir() |
| 49 | + |
| 50 | +var stats |
| 51 | + |
| 52 | +(async () => { stats = await fetch(dirURL, {method: "OPTIONS"}).then(r => r.json()) |
| 53 | + |
| 54 | +return stats.contents })() |
| 55 | +``` |
| 56 | + |
| 57 | +### ... the script evolved in a bit over an hour into |
| 58 | + |
| 59 | +```javascript |
| 60 | + |
| 61 | +import Strings from 'src/client/strings.js' |
| 62 | + |
| 63 | +class QuerkoepfeApp { |
| 64 | + |
| 65 | + constructor(dirURL) { |
| 66 | + this.dirURL = dirURL |
| 67 | + } |
| 68 | + |
| 69 | + |
| 70 | + async loadDLFQuerkoepfe(isoDate) { |
| 71 | + var tab = await fetch(`http://localhost:9005/Dropbox/share/DLF/extract/${isoDate}.tab`).then(r => r.text()) |
| 72 | + |
| 73 | + var programm = tab.split(/\n/g).map(ea => ea.split(/\t/)) |
| 74 | + |
| 75 | + var querkoepfe = programm.filter(ea => ea[1] && ea[1].startsWith("Querköpfe"))[0] |
| 76 | + |
| 77 | + programm.map(ea => ea[0]) |
| 78 | + |
| 79 | + |
| 80 | + if (!querkoepfe || !querkoepfe[2]) return |
| 81 | + |
| 82 | + var div = <div></div> |
| 83 | + div.innerHTML = querkoepfe[2] |
| 84 | + div.querySelector("p").innerHTML.split(/<br>/) |
| 85 | + return div.querySelector("p").innerHTML.split(/<br>/) |
| 86 | + |
| 87 | + } |
| 88 | + |
| 89 | + |
| 90 | + |
| 91 | + async selectItem(item) { |
| 92 | + if (this.lastSelected) this.lastSelected.classList.remove("selected") |
| 93 | + item.classList.add("selected") |
| 94 | + this.lastSelected = item |
| 95 | + |
| 96 | + |
| 97 | + var m = item.textContent.match(/(20\d\d-\d\d-\d\d)/) |
| 98 | + if (m) { |
| 99 | + var isoDate = m[1] |
| 100 | + } else { |
| 101 | + return |
| 102 | + } |
| 103 | + |
| 104 | + var info = await this.loadDLFQuerkoepfe(isoDate) |
| 105 | + |
| 106 | + if (!info) { |
| 107 | + this.details.innerHTML = "no details" |
| 108 | + } else { |
| 109 | + this.details.innerHTML = JSON.stringify(info) |
| 110 | + this.lastSelected.info = info |
| 111 | + } |
| 112 | + |
| 113 | + } |
| 114 | + |
| 115 | + onItemClick(evt, item) { |
| 116 | + |
| 117 | + this.selectItem(item) |
| 118 | + |
| 119 | + // if (item.classList.contains("selected")) { |
| 120 | + // item.classList.remove("selected") |
| 121 | + // } else { |
| 122 | + // item.classList.add("selected") |
| 123 | + // } |
| 124 | + } |
| 125 | + |
| 126 | + async onRenameButton(evt) { |
| 127 | + if (!this.lastSelected || !this.lastSelected.info) return |
| 128 | + if (!this.lastSelected.file) return |
| 129 | + |
| 130 | + var rawPattern = "Wed_2105_querkoepfe" |
| 131 | + |
| 132 | + var filename = this.lastSelected.file.name |
| 133 | + if (!filename.match(rawPattern)) { |
| 134 | + lively.notify("file has already a custom name") |
| 135 | + return |
| 136 | + } |
| 137 | + |
| 138 | + |
| 139 | + var info = this.lastSelected.info |
| 140 | + var s ="Querkoepfe - " + info[1] |
| 141 | + if (info[2]) s += " - " + info[2] |
| 142 | + s = s.replace(/ /g, "_") |
| 143 | + s = s.replace(/[:.\/]/g, "_") |
| 144 | + |
| 145 | + s = s.replace(/_+/g, "_") |
| 146 | + |
| 147 | + var newFilename = filename.replace(rawPattern, s) |
| 148 | + |
| 149 | + var fromURL = this.dirURL + encodeURI(filename) |
| 150 | + var toURL = this.dirURL + encodeURI(newFilename) |
| 151 | + |
| 152 | + |
| 153 | + await lively.confirm("rename " + filename + " -> " + newFilename + " in " + this.dirURL) |
| 154 | + |
| 155 | + |
| 156 | + var resp = await lively.files.moveFile(fromURL, toURL) |
| 157 | + if (resp.status == 200) { |
| 158 | + this.lastSelected.innerHTML = newFilename |
| 159 | + } else { |
| 160 | + this.lastSelected.style.backgroundColor = "red" |
| 161 | + } |
| 162 | + |
| 163 | + // lively.warn("not implemented yet") |
| 164 | + |
| 165 | + } |
| 166 | + async createView() { |
| 167 | + var stats = await fetch(this.dirURL, {method: "OPTIONS"}).then(r => r.json()) |
| 168 | + |
| 169 | + |
| 170 | + var items = stats.contents |
| 171 | + .sortBy(ea => ea.name) |
| 172 | + .map(ea => { |
| 173 | + var item = <li>{ea.name}</li> |
| 174 | + item.file = ea |
| 175 | + item.addEventListener("click", evt => this.onItemClick(evt, item)) |
| 176 | + return item |
| 177 | + }) |
| 178 | + |
| 179 | + var list = <ul id="list">{...items}</ul> |
| 180 | + var style = document.createElement("style") // #ISSUE style tags conflict with Markdown rewriting.... |
| 181 | + style.innerHTML = ` |
| 182 | + li.selected { |
| 183 | + background-color: lightgray |
| 184 | + } |
| 185 | + |
| 186 | + #pane { |
| 187 | + height: 100%; |
| 188 | + } |
| 189 | + |
| 190 | + #list { |
| 191 | + height: 400px; |
| 192 | + overflow: auto; |
| 193 | + } |
| 194 | + |
| 195 | + ` |
| 196 | + this.details = <div id="details"></div> |
| 197 | + return <div> |
| 198 | + {style} |
| 199 | + <div id="pane"> |
| 200 | + <div id="buttons"><button click={evt => this.onRenameButton(evt)}>rename</button></div> |
| 201 | + {this.details} |
| 202 | + {list} |
| 203 | + </div> |
| 204 | + </div> |
| 205 | + } |
| 206 | + |
| 207 | +} |
| 208 | + |
| 209 | + |
| 210 | +var container = lively.query(this, "lively-container") |
| 211 | +new QuerkoepfeApp(container.getDir()).createView() |
| 212 | + |
| 213 | +``` |
| 214 | + |
| 215 | +I knew [the domain](https://lively-kernel.org/repository/webwerkstatt/users/jenslincke/DLF.xhtml), programmed similar applications before and could look at existing scripts when I ran into an issue with renaming umlauts. But this the (yet unpolished) typical kind of application I expect Lively4 users to build. Some parts of the overall application is handled outside of lively, e.g. the recording of the radio show and the downloading (and parsing) of the radio program and information. Since both approaches are long running and require full web access. Downloading and scraping other websites would is prevented by the browser and requires Lively additional help from a proxy server or in this case a shell script. |
| 216 | + |
| 217 | +The resulting Lively4 is a markdown file that is persisted beside the data (mp3 files) it works on. When browsing the directory of the files within lively will show "index.md" file and run the application. In a funny way, this is a context specific application inside a directory... I think Windows Explorer experimented with such "Active Desktop" in the 90ies... But the time was not right yet and everybody hated it, because it slowed down the computer. And I assume was a huge security risk. Which might be the same for this application... |
| 218 | + |
| 219 | + |
0 commit comments