-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathorg-fit.html
324 lines (317 loc) · 15 KB
/
org-fit.html
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">
<head>
<!-- 2024-02-25 So 12:31 -->
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>org-fit or what it means to work on the utterly useless</title>
<meta name="author" content="uni" />
<meta name="generator" content="Org Mode" />
<style>
#content { max-width: 60em; margin: auto; }
.title { text-align: center;
margin-bottom: .2em; }
.subtitle { text-align: center;
font-size: medium;
font-weight: bold;
margin-top:0; }
.todo { font-family: monospace; color: red; }
.done { font-family: monospace; color: green; }
.priority { font-family: monospace; color: orange; }
.tag { background-color: #eee; font-family: monospace;
padding: 2px; font-size: 80%; font-weight: normal; }
.timestamp { color: #bebebe; }
.timestamp-kwd { color: #5f9ea0; }
.org-right { margin-left: auto; margin-right: 0px; text-align: right; }
.org-left { margin-left: 0px; margin-right: auto; text-align: left; }
.org-center { margin-left: auto; margin-right: auto; text-align: center; }
.underline { text-decoration: underline; }
#postamble p, #preamble p { font-size: 90%; margin: .2em; }
p.verse { margin-left: 3%; }
pre {
border: 1px solid #e6e6e6;
border-radius: 3px;
background-color: #f2f2f2;
padding: 8pt;
font-family: monospace;
overflow: auto;
margin: 1.2em;
}
pre.src {
position: relative;
overflow: auto;
}
pre.src:before {
display: none;
position: absolute;
top: -8px;
right: 12px;
padding: 3px;
color: #555;
background-color: #f2f2f299;
}
pre.src:hover:before { display: inline; margin-top: 14px;}
/* Languages per Org manual */
pre.src-asymptote:before { content: 'Asymptote'; }
pre.src-awk:before { content: 'Awk'; }
pre.src-authinfo::before { content: 'Authinfo'; }
pre.src-C:before { content: 'C'; }
/* pre.src-C++ doesn't work in CSS */
pre.src-clojure:before { content: 'Clojure'; }
pre.src-css:before { content: 'CSS'; }
pre.src-D:before { content: 'D'; }
pre.src-ditaa:before { content: 'ditaa'; }
pre.src-dot:before { content: 'Graphviz'; }
pre.src-calc:before { content: 'Emacs Calc'; }
pre.src-emacs-lisp:before { content: 'Emacs Lisp'; }
pre.src-fortran:before { content: 'Fortran'; }
pre.src-gnuplot:before { content: 'gnuplot'; }
pre.src-haskell:before { content: 'Haskell'; }
pre.src-hledger:before { content: 'hledger'; }
pre.src-java:before { content: 'Java'; }
pre.src-js:before { content: 'Javascript'; }
pre.src-latex:before { content: 'LaTeX'; }
pre.src-ledger:before { content: 'Ledger'; }
pre.src-lisp:before { content: 'Lisp'; }
pre.src-lilypond:before { content: 'Lilypond'; }
pre.src-lua:before { content: 'Lua'; }
pre.src-matlab:before { content: 'MATLAB'; }
pre.src-mscgen:before { content: 'Mscgen'; }
pre.src-ocaml:before { content: 'Objective Caml'; }
pre.src-octave:before { content: 'Octave'; }
pre.src-org:before { content: 'Org mode'; }
pre.src-oz:before { content: 'OZ'; }
pre.src-plantuml:before { content: 'Plantuml'; }
pre.src-processing:before { content: 'Processing.js'; }
pre.src-python:before { content: 'Python'; }
pre.src-R:before { content: 'R'; }
pre.src-ruby:before { content: 'Ruby'; }
pre.src-sass:before { content: 'Sass'; }
pre.src-scheme:before { content: 'Scheme'; }
pre.src-screen:before { content: 'Gnu Screen'; }
pre.src-sed:before { content: 'Sed'; }
pre.src-sh:before { content: 'shell'; }
pre.src-sql:before { content: 'SQL'; }
pre.src-sqlite:before { content: 'SQLite'; }
/* additional languages in org.el's org-babel-load-languages alist */
pre.src-forth:before { content: 'Forth'; }
pre.src-io:before { content: 'IO'; }
pre.src-J:before { content: 'J'; }
pre.src-makefile:before { content: 'Makefile'; }
pre.src-maxima:before { content: 'Maxima'; }
pre.src-perl:before { content: 'Perl'; }
pre.src-picolisp:before { content: 'Pico Lisp'; }
pre.src-scala:before { content: 'Scala'; }
pre.src-shell:before { content: 'Shell Script'; }
pre.src-ebnf2ps:before { content: 'ebfn2ps'; }
/* additional language identifiers per "defun org-babel-execute"
in ob-*.el */
pre.src-cpp:before { content: 'C++'; }
pre.src-abc:before { content: 'ABC'; }
pre.src-coq:before { content: 'Coq'; }
pre.src-groovy:before { content: 'Groovy'; }
/* additional language identifiers from org-babel-shell-names in
ob-shell.el: ob-shell is the only babel language using a lambda to put
the execution function name together. */
pre.src-bash:before { content: 'bash'; }
pre.src-csh:before { content: 'csh'; }
pre.src-ash:before { content: 'ash'; }
pre.src-dash:before { content: 'dash'; }
pre.src-ksh:before { content: 'ksh'; }
pre.src-mksh:before { content: 'mksh'; }
pre.src-posh:before { content: 'posh'; }
/* Additional Emacs modes also supported by the LaTeX listings package */
pre.src-ada:before { content: 'Ada'; }
pre.src-asm:before { content: 'Assembler'; }
pre.src-caml:before { content: 'Caml'; }
pre.src-delphi:before { content: 'Delphi'; }
pre.src-html:before { content: 'HTML'; }
pre.src-idl:before { content: 'IDL'; }
pre.src-mercury:before { content: 'Mercury'; }
pre.src-metapost:before { content: 'MetaPost'; }
pre.src-modula-2:before { content: 'Modula-2'; }
pre.src-pascal:before { content: 'Pascal'; }
pre.src-ps:before { content: 'PostScript'; }
pre.src-prolog:before { content: 'Prolog'; }
pre.src-simula:before { content: 'Simula'; }
pre.src-tcl:before { content: 'tcl'; }
pre.src-tex:before { content: 'TeX'; }
pre.src-plain-tex:before { content: 'Plain TeX'; }
pre.src-verilog:before { content: 'Verilog'; }
pre.src-vhdl:before { content: 'VHDL'; }
pre.src-xml:before { content: 'XML'; }
pre.src-nxml:before { content: 'XML'; }
/* add a generic configuration mode; LaTeX export needs an additional
(add-to-list 'org-latex-listings-langs '(conf " ")) in .emacs */
pre.src-conf:before { content: 'Configuration File'; }
table { border-collapse:collapse; }
caption.t-above { caption-side: top; }
caption.t-bottom { caption-side: bottom; }
td, th { vertical-align:top; }
th.org-right { text-align: center; }
th.org-left { text-align: center; }
th.org-center { text-align: center; }
td.org-right { text-align: right; }
td.org-left { text-align: left; }
td.org-center { text-align: center; }
dt { font-weight: bold; }
.footpara { display: inline; }
.footdef { margin-bottom: 1em; }
.figure { padding: 1em; }
.figure p { text-align: center; }
.equation-container {
display: table;
text-align: center;
width: 100%;
}
.equation {
vertical-align: middle;
}
.equation-label {
display: table-cell;
text-align: right;
vertical-align: middle;
}
.inlinetask {
padding: 10px;
border: 2px solid gray;
margin: 10px;
background: #ffffcc;
}
#org-div-home-and-up
{ text-align: right; font-size: 70%; white-space: nowrap; }
textarea { overflow-x: auto; }
.linenr { font-size: smaller }
.code-highlighted { background-color: #ffff00; }
.org-info-js_info-navigation { border-style: none; }
#org-info-js_console-label
{ font-size: 10px; font-weight: bold; white-space: nowrap; }
.org-info-js_search-highlight
{ background-color: #ffff00; color: #000000; font-weight: bold; }
.org-svg { }
</style>
</head>
<body>
<div id="content" class="content">
<h1 class="title">org-fit or what it means to work on the utterly useless</h1>
<div id="table-of-contents" role="doc-toc">
<h2>Table of Contents</h2>
<div id="text-table-of-contents" role="doc-toc">
<ul>
<li><a href="#org4e3348f">1. background</a></li>
<li><a href="#org79d57e8">2. idea</a>
<ul>
<li><a href="#org8c7edc3">2.1. failed attempt</a></li>
<li><a href="#org5e22c80">2.2. the two-layer solution</a></li>
</ul>
</li>
<li><a href="#org122fe51">3. result</a></li>
</ul>
</div>
</div>
<div id="outline-container-org4e3348f" class="outline-2">
<h2 id="org4e3348f"><span class="section-number-2">1.</span> background</h2>
<div class="outline-text-2" id="text-1">
<p>
Over the course of late 2022 and early 2023, I started to integrate more and
more data of my daily life into org mode. This included <a href="https://github.com/novoid/Memacs/blob/master/docs/memacs_lastfm.org">last.fm scrobbles</a>, <a href="https://github.com/karlicoss/orger/blob/master/modules/youtube.py">my YouTube watch history</a>, <a href="personal-train-tracking.html">train and bus rides</a> and the topic of this entry, <i>going outside</i>, touching grass, even.
</p>
</div>
</div>
<div id="outline-container-org79d57e8" class="outline-2">
<h2 id="org79d57e8"><span class="section-number-2">2.</span> idea</h2>
<div class="outline-text-2" id="text-2">
<p>
Despite the questionable consequences for my privacy, I’ve been using <a href="https://www.google.com/fit/">Google Fit</a> for a while now,
though mostly as a basic step counter and movement time tracker. Since I was using the <a href="https://orgmode.org/manual/Clocking-Work-Time.html">org mode clock</a>
way more extensively back then, my plan was to incorporate the Google Fit activity data into the clock times
of a specific task.
</p>
</div>
<div id="outline-container-org8c7edc3" class="outline-3">
<h3 id="org8c7edc3"><span class="section-number-3">2.1.</span> failed attempt</h3>
<div class="outline-text-3" id="text-2-1">
<p>
Since this is essentially a tool for Emacs, my first idea was to write the entire thing in Emacs Lisp.
This most importantly includes the Google API calls and authentification steps, which follow the standard
<a href="https://oauth.net/2/">OAuth2</a> protocol. Now while there are <a href="https://elpa.gnu.org/packages/oauth2.html">Emacs implementations</a>, I couldn’t <a href="https://github.com/uniwuni/elisp-oauth-2">the one of my choice</a> working no matter the effort,
since some step of the authentification simply failed no matter what I did, it seems to be a problem
in the flow of the library.
</p>
</div>
</div>
<div id="outline-container-org5e22c80" class="outline-3">
<h3 id="org5e22c80"><span class="section-number-3">2.2.</span> the two-layer solution</h3>
<div class="outline-text-3" id="text-2-2">
<p>
So I instead checked for Haskell implementations of the OAuth2 flow, and indeed found a <a href="https://github.com/pbrisbin/google-oauth2">specific repository</a>
that addressed the Google API auth flow.
Because I’m absolutely horrible at package management, I decided not to use the package directly, but
rather just <a href="https://github.com/uniwuni/org-fit-hs">fork the repository</a> and change the example app in a truly cursed act of desperation.
Getting this to a working state still took quite a lot of effort, so the details of the tool are still
worth explaining a little.
After sending the request, a decently fucked up JSON parsing bit is required to simplify the data - in
both of these steps, the conversion of 3 different date formats (nanoseconds since epoch for the Google API,
half a dozen of different date datatypes for Haskell, not entirely standard conforming UTC timestamps for
Org mode) proved to be the most difficult step. From there on, all that the program does is print the
Org clock lines and ignore activities that are too short or of type 0 (driving), to not clutter the clock
report.
</p>
<p>
Of course this wasn’t the end of the story, one still needs an Emacs Lisp layer to actually add the
generated data to the Org logbooks in question. Enter <a href="https://github.com/uniwuni/org-fit">org-fit</a>, an almost as confusingly named package
that’s not even <i>that</i> hacky and even follows a proper packaging standard, too.
Its utility to the user is rather limited - it provides the function <a href="org-fit-update">org-fit-update</a>, which by default
runs the <code>get-fit</code> tool from the Haskell stage and passes the current time as an argument.
The heading given by the customizable ID is then found using the handy <a href="https://github.com/tkf/org-mode/blob/master/lisp/org-id.el">org-id</a>. If any lines are
generated by the tool, they’re added to the logbook drawer and the tool updates a property indicating
the time the last update occurred. This is done by jumping to the headline in question, searching for
the logbook drawer via regexp<sup><a id="fnr.1" class="footref" href="#fn.1" role="doc-backlink">1</a></sup>, then iteratively inserting the data and having org mode update the
clocking durations, too. In a somewhat early stage, I even tried to add seconds to the clock times (because why
even bother with data that isn’t as exact as it possibly could be, right?), but it turned out Org mode
does not handle this well, sadly, so I had to resort to minutes.
</p>
<p>
As I had no prior experience in writing “real” Emacs lisp, the whole concept of marker mangling, save and
buffer excursion strategies took me a while to get used to - it’s a
style of string manipulation that diverges a lot from “modern” programming, but it turned out to be
really interesting and definitely worth exploring more.
</p>
</div>
</div>
</div>
<div id="outline-container-org122fe51" class="outline-2">
<h2 id="org122fe51"><span class="section-number-2">3.</span> result</h2>
<div class="outline-text-2" id="text-3">
<p>
This whole setup works out really well - by using <a href="run-with-timer">run-with-timer</a>, the file automatically updates once
an hour without any problems. However, after a few days of inactivity per computer (which occurs decently
frequently, since I use both a desktop PC and a notebook), the API credentials run stale and I have to
manually run <code>get-fit</code> in a terminal to initiate the auth process once again. At least, the update time
is not changed since <code>org-fit</code> doesn’t detect any output, so the data gets retrieved at a later point.
There’s probably a way to do this directly within Emacs, but I honestly can’t be bothered.
</p>
<p>
The main problem is my recent lack of interest - while it’s still nice to collect this data, I tend to use
the clock function much less than I once did, so it’s more of a curiosity than anything else now, then
again, that seems to be the point of most of my weirdly specific projects to begin with. hm.
</p>
</div>
</div>
<div id="footnotes">
<h2 class="footnotes">Footnotes: </h2>
<div id="text-footnotes">
<div class="footdef"><sup><a id="fn.1" class="footnum" href="#fnr.1" role="doc-backlink">1</a></sup> <div class="footpara" role="doc-footnote"><p class="footpara">
not to be confused with regex! Emacs regexp is by absolutely no means the same thing and conforms to
pretty much no standards at all, sadly.
</p></div></div>
</div>
</div></div>
<div id="postamble" class="status">
<p class="author">Author: uni</p>
<p class="date">Created: 2024-02-25 So 12:31</p>
</div>
</body>
</html>