spectator_sport 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +27 -0
- data/app/helpers/spectator_sport/script_helper.rb +4 -0
- data/app/views/spectator_sport/events/index.js +57 -6
- data/lib/spectator_sport/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ce7e9837080e5b1f96455b0f135fda0aff65832e57ef01c9cc42763be9579a46
|
|
4
|
+
data.tar.gz: be3679d719d26e852867510b223983e763de348c5c3c44bb58592e4960ae7fd2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 3c076b0fd70e3667bf2d8b19f939995589332ee853d63dd30d0281248416df8788f627b7d5ca15bd534bdaf63d4fca377befe8a58941c69769c3d38dbd1b42d3
|
|
7
|
+
data.tar.gz: e8e8901c34d153bbe77a4718bc9da962d89d91e52d6f618be9d524a1bb045f2f907245a9b89888c5d4f9b7602268cf58089666aa2cbe0bb3db5b7f2d72e17de0
|
data/README.md
CHANGED
|
@@ -69,6 +69,18 @@ This renders a hidden `<meta>` element signed by the server. The recording clien
|
|
|
69
69
|
|
|
70
70
|
**Note:** this requires the `spectator_sport_session_window_tags` migration to be applied (`bin/rails spectator_sport:install:migrations && bin/rails db:migrate`). If the migration hasn't been run, the feature is silently disabled.
|
|
71
71
|
|
|
72
|
+
## Stopping recording
|
|
73
|
+
|
|
74
|
+
You can pause recording for a page by calling `spectator_sport_stop_recording` in any template:
|
|
75
|
+
|
|
76
|
+
```erb
|
|
77
|
+
<%= spectator_sport_stop_recording %>
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
This renders a hidden `<meta>` element that the recording client detects on page load. When present, rrweb recording is stopped and no events are buffered or sent. Recording automatically resumes when the user navigates to a page that does not have this tag.
|
|
81
|
+
|
|
82
|
+
This is useful when navigating via Turbo to pages that shouldn't be recorded — without this tag the recorder would continue running across navigations.
|
|
83
|
+
|
|
72
84
|
## Dashboard authorization
|
|
73
85
|
|
|
74
86
|
It is advisable to manually install and set up authorization for the **Player Dashboard** and refrain from making it public.
|
|
@@ -153,6 +165,21 @@ open http://localhost:3000
|
|
|
153
165
|
# 6. Make changes, see the result, commit and make a PR!
|
|
154
166
|
```
|
|
155
167
|
|
|
168
|
+
## Releasing a new version
|
|
169
|
+
|
|
170
|
+
1. Update the version in `lib/spectator_sport/version.rb`
|
|
171
|
+
2. Run `bundle install` to update `Gemfile.lock`
|
|
172
|
+
3. Commit the version bump and updated `Gemfile.lock`:
|
|
173
|
+
```bash
|
|
174
|
+
git add lib/spectator_sport/version.rb Gemfile.lock
|
|
175
|
+
git commit -m "Bump version to x.y.z"
|
|
176
|
+
```
|
|
177
|
+
3. Build and publish to RubyGems, tag, and push to GitHub:
|
|
178
|
+
```bash
|
|
179
|
+
bundle exec rake release
|
|
180
|
+
```
|
|
181
|
+
4. Create a GitHub Release at https://github.com/bensheldon/spectator_sport/releases using the new `vx.y.z` tag.
|
|
182
|
+
|
|
156
183
|
## License
|
|
157
184
|
|
|
158
185
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
@@ -8,5 +8,9 @@ module SpectatorSport
|
|
|
8
8
|
signed = Rails.application.message_verifier(:spectator_sport_tag_recording).generate(tag_value)
|
|
9
9
|
tag.meta(name: "spectator-sport-recording-tag", content: signed)
|
|
10
10
|
end
|
|
11
|
+
|
|
12
|
+
def spectator_sport_stop_recording
|
|
13
|
+
tag.meta(name: "spectator-sport-stop")
|
|
14
|
+
end
|
|
11
15
|
end
|
|
12
16
|
end
|
|
@@ -29,6 +29,8 @@ function log(...args) {
|
|
|
29
29
|
const POST_URL = new URL("./events", document.currentScript.src).href;
|
|
30
30
|
const POST_INTERVAL_SECONDS = 15;
|
|
31
31
|
const KEEPALIVE_BYTE_LIMIT = 60000; // Fetch payloads >64kb cannot use keepalive: true
|
|
32
|
+
const RECORDING_TAG_SELECTOR = 'meta[name="spectator-sport-recording-tag"]';
|
|
33
|
+
const STOP_SELECTOR = 'meta[name="spectator-sport-stop"]';
|
|
32
34
|
|
|
33
35
|
class Recorder {
|
|
34
36
|
constructor() {
|
|
@@ -173,7 +175,7 @@ class TagWatcher {
|
|
|
173
175
|
}
|
|
174
176
|
|
|
175
177
|
start() {
|
|
176
|
-
document.querySelectorAll(
|
|
178
|
+
document.querySelectorAll(RECORDING_TAG_SELECTOR).forEach(el => {
|
|
177
179
|
this.enqueue(el.content);
|
|
178
180
|
});
|
|
179
181
|
|
|
@@ -181,10 +183,10 @@ class TagWatcher {
|
|
|
181
183
|
for (const mutation of mutations) {
|
|
182
184
|
for (const node of mutation.addedNodes) {
|
|
183
185
|
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
184
|
-
if (node.matches(
|
|
186
|
+
if (node.matches(RECORDING_TAG_SELECTOR)) {
|
|
185
187
|
this.enqueue(node.content);
|
|
186
188
|
}
|
|
187
|
-
node.querySelectorAll(
|
|
189
|
+
node.querySelectorAll(RECORDING_TAG_SELECTOR).forEach(el => {
|
|
188
190
|
this.enqueue(el.content);
|
|
189
191
|
});
|
|
190
192
|
}
|
|
@@ -222,15 +224,62 @@ class TagWatcher {
|
|
|
222
224
|
}
|
|
223
225
|
}
|
|
224
226
|
|
|
227
|
+
class StopWatcher {
|
|
228
|
+
constructor(recorder) {
|
|
229
|
+
this.recorder = recorder;
|
|
230
|
+
this.observer = null;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
start() {
|
|
234
|
+
this.observer = new MutationObserver((mutations) => {
|
|
235
|
+
let changed = false;
|
|
236
|
+
for (const mutation of mutations) {
|
|
237
|
+
for (const node of [...mutation.addedNodes, ...mutation.removedNodes]) {
|
|
238
|
+
if (node.nodeType !== Node.ELEMENT_NODE) continue;
|
|
239
|
+
if (node.matches(STOP_SELECTOR) ||
|
|
240
|
+
node.querySelector(STOP_SELECTOR)) {
|
|
241
|
+
changed = true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
if (changed) {
|
|
246
|
+
this.update();
|
|
247
|
+
}
|
|
248
|
+
});
|
|
249
|
+
this.observer.observe(document.documentElement, { childList: true, subtree: true });
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
update() {
|
|
253
|
+
if (document.querySelector(STOP_SELECTOR)) {
|
|
254
|
+
this.recorder.stop();
|
|
255
|
+
} else {
|
|
256
|
+
this.recorder.start();
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
function isStopped() {
|
|
262
|
+
return !!document.querySelector(STOP_SELECTOR);
|
|
263
|
+
}
|
|
264
|
+
|
|
225
265
|
const recorder = new Recorder();
|
|
226
|
-
|
|
266
|
+
if (!isStopped()) {
|
|
267
|
+
recorder.start();
|
|
268
|
+
}
|
|
227
269
|
|
|
228
270
|
const tagWatcher = new TagWatcher(recorder.sessionId, recorder.windowId);
|
|
229
271
|
tagWatcher.start();
|
|
230
272
|
|
|
273
|
+
const stopWatcher = new StopWatcher(recorder);
|
|
274
|
+
stopWatcher.start();
|
|
275
|
+
|
|
231
276
|
window.addEventListener("pageshow", function(_event) {
|
|
232
277
|
log("pageshow");
|
|
233
|
-
|
|
278
|
+
if (isStopped()) {
|
|
279
|
+
recorder.stop();
|
|
280
|
+
} else {
|
|
281
|
+
recorder.start();
|
|
282
|
+
}
|
|
234
283
|
});
|
|
235
284
|
|
|
236
285
|
window.addEventListener("pagehide", function(_event) {
|
|
@@ -241,7 +290,9 @@ window.addEventListener("pagehide", function(_event) {
|
|
|
241
290
|
document.addEventListener("visibilitychange", function(_event) {
|
|
242
291
|
log("visibilitychange", document.visibilityState);
|
|
243
292
|
if (document.visibilityState === "visible") {
|
|
244
|
-
|
|
293
|
+
if (!isStopped()) {
|
|
294
|
+
recorder.unpause();
|
|
295
|
+
}
|
|
245
296
|
} else if (document.visibilityState === "hidden") {
|
|
246
297
|
recorder.pause();
|
|
247
298
|
}
|