The restreamer spends most of its time iterating through segments (parsing them, determining the best one for each start time)
to serve large time ranges. Since this only depends on the list of filenames read from disk,
we can cache it for a given hour as long as that list is identical.
This is a little trickier than it sounds because best_segments_by_start is an iterator
and in most cases it won't be fully consumed. So we introduce a `CachedIterator` abstraction
that will both remember the previously yielded values, and keep track of the live iterator
so it can be resumed again if a previous invocation only partially consumed it.
This also has the nice side effect of merging simultaneous operations - if two requests come in
for the same hour at the same time, they'll share one iterator and both consume the results
as they come in.
We've seen cases where videos are not inserted even though the API call succeeded.
Our suspicion is that two concurrent insert calls for the same video are causing a race.
We try to avoid this by putting a lock around insert calls
The SQL args were the wrong way around, so we tried to set error to the id.
Thankfully this failed as the id queried is not a valid uuid.
Fix by making args named like every other usage of query()
* Add fullscreen functionality to Thrimbletrimmer video player
* Fix issue where clicking on fullscreen video pauses and unpauses instead of doing just one