flamebyrd: (Default)
flamebyrd ([personal profile] flamebyrd) wrote2016-10-25 07:22 pm

Script: AO3 reading time estimate

After a certain friend of mine remarked that she'd been up until 3AM reading fic three nights in a row (a "fictim", as Tumblr would have it), I remarked that it should be pretty straightforward to write a script that will estimate how long it will take to read a fic and pop up a warning when it thinks you'll finish too late for comfort.

So there's now a bookmarklet that will calculate how long it will take you to read a fic, and also a userscript that will do the same and then warn you if it think you'll finish after 1AM (or however you configure it).

These are both still in very early beta, so please let me know if you encounter any weirdness or have suggestions.


I thought I'd start with a bookmarklet to calculate the estimated reading period and finish time, because it would involve less fiddly time maths.

Step 1 was actually to figure out how to hook into AO3's modal dialogue. I spent far too long poking at the page source and attached scripts before I remembered I could just search GitHub, ahem. Eventually I found the source for the modal dialogue and poked around in the console again until I knew how to trigger it.
For reference, something like:
window.ao3modal.setContent('Content goes here', 'Reading Time Estimate');

I didn't have success setting the content before I used the show method.

So once I had that working, I googled up a default value for reading speed (it said 250 wpm average, 300 for college students who read a lot, so I went with 300). Then I divided the work word count AO3 provides by the "words per minute" value and piped it into my modal. Easy.

But wait, I thought. Many longer works are divided into chapters, so wouldn't it make sense to also provide the reading time for the current chapter? Only, AO3 doesn't provide the chapter length (except in subscription emails, oddly) so I knew I'd have to fudge it. A quick forage in Google suggested a very naive regex - since this was an estimate anyway I figured it didn't matter and rolled on ahead.

So, now it calculated reading time for the entire work and for chapters (if it had them - or, more accurately, if it doesn't see "1/1" as the chapter count). But I knew my reading speed was higher than 300, so I removed my magic numbers and made that configurable.

I hit another snag when I tried to make it output the finish time in a human readable format. Since AO3 includes jQuery UI I could use the $.datepicker.formatDate method, except that it won't output the time values. So I pulled a combination of those into what I wanted. (TODO: make this configurable?)

Then I built the web interface for it and my usual hacked together bookmarklet options setting. (It fetches the script as text and does a string replacement. I'm not proud.)

I threw it up on Twitter, and a little while later [personal profile] cimorene pointed out that the chapter calculator got confused when you viewed a work in full (rather than chapter by chapter). Oops. So I fixed that.

The next day, I decided it was time for time maths.

My goal was to write a script that would take a time and a reading speed, and warn you when it calculated you would finish reading a work after the specified time.

Javascript doesn't had a particularly good time library, and I didn't want to import an entire jQuery time library just for my silly little user script, so I had to try and understand it myself. Ugh.

My first concern was that I wanted the user to be able to enter their preferred notice time in a language they would understand. After a lot of increasingly frustrated poking at the console it became clear that Javascript would not let you parse a time string without a date attached. Rather than fudge a date in I decided to just do what the people of StackOverflow tell other people with this problem to do - write your own. Only I'm lazy so I used this method for parsing a time string with javascript.

Once that was working, I could easily set that time on the new date object, compare it to the Date.now() result, and that would be it.

But wait. What if the user set the time to 1am? That was the most likely use case, after all, and 10pm today was after 1am today, so the script would always fire. OK, I thought, so if the specified time has already passed, add a day to it.

Only, this meant if you absent-mindedly start reading a fic at 1:03am the script would never warn you.

I went back and forth on this issue for a while, and eventually decided to fudge it - if the specified time is before six hours ago, add a day to it. So if you start reading between 1 and 7am, you'll get a warning, but if you start at 8am you don't receive a warning until the next day. When researching how to do this, I discovered that Javascript sensibly interprets negative numbers and invalid day values (eg. March 24th) and shifts the date backwards or to the next month accordingly.

And then I threw the link up on Twitter for testing. (I'm not sure if anybody actually has yet.)

sqbr: I lay on the couch, suffering an out of spoons error (spoons)

[personal profile] sqbr 2016-10-25 09:02 pm (UTC)(link)
On the one hand I like to help out and test out this kind of thing on the other I feel like I'm happier without having a precise number :) For me reading fic and insomnia's causality is the other way around.

EDIT: But I think this is really cool and clever and useful for people who work differently to me. Oops, forgot that didn't go without saying.
Edited 2016-10-25 21:03 (UTC)