data endpoint for entity 90008 (aka. a website)
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: keep track of global distance moved and show some stats for pet

dusk 5ad4b2ee cb01edcd

+137 -47
+1
.gitignore
··· 9 9 /bouncecount 10 10 /legitvisitcount 11 11 /fakevisitcount 12 + /distancetravelled 12 13 /notes 13 14 /note 14 15
+39 -7
src/components/pet.svelte
··· 1 + <script module lang="ts"> 2 + import { writable } from 'svelte/store'; 3 + 4 + export const localDistanceTravelled = writable(0.0); 5 + </script> 6 + 1 7 <script lang="ts"> 2 8 import { draggable } from '@neodrag/svelte'; 9 + import { browser } from '$app/environment'; 3 10 4 11 let lastDragged = 0; 5 12 let mouseX = 0; ··· 51 58 }; 52 59 53 60 // Add spring update to the move function 54 - setInterval(updateRotationSpring, tickRate); 61 + if (browser) setInterval(updateRotationSpring, tickRate); 55 62 56 63 const moveTowards = (from: number, to: number, by: number) => { 57 64 let d = (to - from) * 1.0; ··· 73 80 fetch('/pet/bounce'); 74 81 }; 75 82 83 + let deltaTravelled = 0.0; 84 + const updateDistanceTravelled = () => { 85 + if (deltaTravelled > 0.1 || deltaTravelled < -0.1) { 86 + localDistanceTravelled.update((n) => { 87 + n += deltaTravelled; 88 + return n; 89 + }); 90 + fetch('/pet/distance', { 91 + method: 'POST', 92 + body: deltaTravelled.toString() 93 + }); 94 + } 95 + deltaTravelled = 0.0; 96 + }; 97 + 76 98 const move = () => { 77 99 if (dragged) return; 78 100 ··· 87 109 velocityY *= fric; 88 110 89 111 // Update position 90 - position.x += velocityX * delta; 91 - position.y += velocityY * delta; 112 + const moveX = velocityX * delta; 113 + const moveY = velocityY * delta; 114 + position.x += moveX; 115 + position.y += moveY; 116 + 117 + deltaTravelled += Math.sqrt(moveX ** 2 + moveY ** 2); 118 + updateDistanceTravelled(); 92 119 93 120 // Handle window boundaries 94 121 const viewportWidth = window.innerWidth; ··· 145 172 } else { 146 173 sprite = '/pet/idle.webp'; 147 174 } 175 + 176 + deltaTravelled += Math.abs(moveByX); 177 + updateDistanceTravelled(); 148 178 }; 149 179 150 - setInterval(move, tickRate); 180 + if (browser) setInterval(move, tickRate); 151 181 152 182 const shake = (event: DeviceMotionEvent) => { 153 183 const accel = event.acceleration ?? event.accelerationIncludingGravity; ··· 160 190 sprite = '/pet/pick.webp'; 161 191 }; 162 192 163 - self.ondevicemotion = shake; 193 + if (browser) self.ondevicemotion = shake; 164 194 165 195 // this is for ios 166 196 const askForShakePermission = () => { ··· 195 225 }; 196 226 197 227 // Start the process 198 - setTimeout(pickNewTargetX, 1000); 228 + if (browser) setTimeout(pickNewTargetX, 1000); 199 229 </script> 200 230 201 231 <!-- svelte-ignore a11y_missing_attribute --> ··· 216 246 position.y = offsetY; 217 247 const mouseXD = event.movementX * delta; 218 248 const mouseYD = event.movementY * delta; 249 + deltaTravelled += Math.sqrt(mouseXD ** 2 + mouseYD ** 2); 219 250 // reset mouse movement if it's not moving in the same direction so it doesnt accumulate its weird!@!@ 220 251 mouseX = Math.sign(mouseXD) != Math.sign(mouseX) ? mouseXD : mouseX + mouseXD; 221 252 mouseY = Math.sign(mouseYD) != Math.sign(mouseY) ? mouseYD : mouseY + mouseYD; ··· 223 254 lastDragged = Date.now(); 224 255 }, 225 256 onDragEnd: () => { 226 - dragged = false; 227 257 // reset mouse movement if we stopped for longer than some time 228 258 if (Date.now() - lastDragged > 50) { 229 259 mouseX = 0.0; ··· 232 262 // apply velocity based on rotation since we already keep track of that 233 263 velocityX = mouseX * 70.0; 234 264 velocityY = mouseY * 50.0; 265 + updateDistanceTravelled(); 235 266 // reset mouse movement we dont want it to accumulate 236 267 mouseX = 0.0; 237 268 mouseY = 0.0; 269 + dragged = false; 238 270 } 239 271 }} 240 272 class="fixed bottom-[5vh] z-[1000] hover:animate-squiggle"
+33
src/lib/counter.ts
··· 1 + import { existsSync, readFileSync, writeFileSync } from 'fs'; 2 + import { get, writable } from 'svelte/store'; 3 + 4 + /** 5 + * Creates a persistent counter that is stored in a file 6 + * @param fileName The name of the file to store the count in 7 + * @param initialValue The initial value if the file doesn't exist 8 + * @returns An object with methods to get, increment, and set the count 9 + */ 10 + export const createFileCounter = (filePath: string, initialValue: number = 0) => { 11 + const counter = writable( 12 + parseInt(existsSync(filePath) ? readFileSync(filePath).toString() : initialValue.toString()) 13 + ); 14 + 15 + const saveToFile = (value: number) => { 16 + writeFileSync(filePath, value.toString()); 17 + return value; 18 + }; 19 + 20 + return { 21 + get: () => get(counter), 22 + increment: (amount: number = 1) => { 23 + const currentValue = get(counter) + amount; 24 + counter.set(currentValue); 25 + return saveToFile(currentValue); 26 + }, 27 + set: (value: number) => { 28 + counter.set(value); 29 + return saveToFile(value); 30 + }, 31 + subscribe: counter.subscribe 32 + }; 33 + };
+8 -38
src/lib/metrics.ts
··· 1 1 import { env } from '$env/dynamic/private'; 2 - import { existsSync, readFileSync, writeFileSync } from 'fs'; 3 2 import { pushMetrics } from 'prometheus-remote-write'; 4 - import { get, writable } from 'svelte/store'; 3 + import { createFileCounter } from './counter'; 5 4 6 5 const endpoint = env.PROMETHEUS_URL; 7 6 ··· 27 26 await pushMetric({ 28 27 gazesys_pet_bounce_total: bounceCount.get(), 29 28 gazesys_visit_fake_total: fakeVisitCount.get(), 30 - gazesys_visit_real_total: legitVisitCount.get() 29 + gazesys_visit_real_total: legitVisitCount.get(), 30 + gazesys_pet_distance_total: distanceTravelled.get() 31 31 }); 32 32 } catch (error) { 33 33 console.log(`failed to push metrics: ${error}`); 34 34 } 35 35 }; 36 36 37 - /** 38 - * Creates a persistent counter that is stored in a file 39 - * @param fileName The name of the file to store the count in 40 - * @param initialValue The initial value if the file doesn't exist 41 - * @returns An object with methods to get, increment, and set the count 42 - */ 43 - export const createFileCounter = (fileName: string, initialValue: number = 0) => { 44 - const filePath = `${env.WEBSITE_DATA_DIR}/${fileName}`; 45 - const counter = writable( 46 - parseInt(existsSync(filePath) ? readFileSync(filePath).toString() : initialValue.toString()) 47 - ); 48 - 49 - const saveToFile = (value: number) => { 50 - writeFileSync(filePath, value.toString()); 51 - return value; 52 - }; 53 - 54 - return { 55 - get: () => get(counter), 56 - increment: (amount: number = 1) => { 57 - const currentValue = get(counter) + amount; 58 - counter.set(currentValue); 59 - return saveToFile(currentValue); 60 - }, 61 - set: (value: number) => { 62 - counter.set(value); 63 - return saveToFile(value); 64 - }, 65 - subscribe: counter.subscribe 66 - }; 67 - }; 68 - 69 - export const bounceCount = createFileCounter('bouncecount'); 37 + export const bounceCount = createFileCounter(`${env.WEBSITE_DATA_DIR}/bouncecount`); 70 38 export const incrementBounceCount = bounceCount.increment; 71 39 72 - export const legitVisitCount = createFileCounter('legitvisitcount'); 40 + export const legitVisitCount = createFileCounter(`${env.WEBSITE_DATA_DIR}/legitvisitcount`); 73 41 export const incrementLegitVisitCount = legitVisitCount.increment; 74 42 75 - export const fakeVisitCount = createFileCounter('fakevisitcount'); 43 + export const fakeVisitCount = createFileCounter(`${env.WEBSITE_DATA_DIR}/fakevisitcount`); 76 44 export const incrementFakeVisitCount = fakeVisitCount.increment; 45 + 46 + export const distanceTravelled = createFileCounter(`${env.WEBSITE_DATA_DIR}/distancetravelled`);
+12 -1
src/routes/+layout.server.ts
··· 1 - import { incrementFakeVisitCount, incrementLegitVisitCount, pushMetric } from '$lib/metrics.js'; 1 + import { 2 + bounceCount, 3 + distanceTravelled, 4 + incrementFakeVisitCount, 5 + incrementLegitVisitCount, 6 + pushMetric 7 + } from '$lib/metrics.js'; 2 8 import { testUa } from '$lib/robots.js'; 3 9 import { addLastVisitor, incrementVisitCount, notifyDarkVisitors } from '$lib/visits.js'; 4 10 import { error } from '@sveltejs/kit'; 11 + import { localDistanceTravelled } from '../components/pet.svelte'; 12 + import { get } from 'svelte/store'; 5 13 6 14 export const csr = true; 7 15 export const ssr = true; ··· 27 35 28 36 return { 29 37 route: url.pathname, 38 + petTotalBounce: bounceCount.get(), 39 + petTotalDistance: distanceTravelled.get(), 40 + petLocalDistance: get(localDistanceTravelled), 30 41 visitCount: incrementVisitCount(request, cookies), 31 42 lastVisitors, 32 43 recentVisitCount
+31 -1
src/routes/+layout.svelte
··· 1 1 <script lang="ts"> 2 + import { browser } from '$app/environment'; 2 3 import getTitle from '$lib/getTitle'; 3 4 import NavButton from '../components/navButton.svelte'; 4 - import Pet from '../components/pet.svelte'; 5 + import Pet, { localDistanceTravelled } from '../components/pet.svelte'; 5 6 import Tooltip from '../components/tooltip.svelte'; 6 7 import '../styles/app.css'; 7 8 ··· 193 194 <a class="align-middle hover:underline" href="/log/_rss">log</a> 194 195 </div> 195 196 {/if} 197 + <Tooltip> 198 + {#snippet tooltipContent()} 199 + <p class="font-monospace"> 200 + <nobr> 201 + pet global bounce = <span class="text-ralsei-green-light text-shadow-green" 202 + >{data.petTotalBounce.toString().padStart(14, '.')}</span 203 + > 204 + </nobr> 205 + <nobr> 206 + pet global distance = <span class="text-ralsei-green-light text-shadow-green" 207 + >{data.petTotalDistance.toFixed(0).toString().padStart(12, '.')}</span 208 + > 209 + </nobr> 210 + {#if browser} 211 + <nobr> 212 + pet local distance = <span class="text-ralsei-green-light text-shadow-green" 213 + >{$localDistanceTravelled.toFixed(0).toString().padStart(13, '.')}</span 214 + > 215 + </nobr> 216 + {/if} 217 + </p> 218 + {/snippet} 219 + <div class="navbox"> 220 + <p> 221 + <span class="text-ralsei-green-light text-shadow-green">*</span> 222 + pet stats 223 + </p> 224 + </div> 225 + </Tooltip> 196 226 <Tooltip> 197 227 {#snippet tooltipContent()} 198 228 <p class="font-monospace">
+13
src/routes/pet/distance/+server.ts
··· 1 + import { distanceTravelled, pushMetric } from '$lib/metrics'; 2 + import { isBot } from '$lib/visits'; 3 + 4 + export const POST = async ({ request }) => { 5 + if (isBot(request)) return new Response(); 6 + try { 7 + const delta = parseFloat(await request.text()); 8 + await pushMetric({ gazesys_pet_distance_total: distanceTravelled.increment(delta) }); 9 + } catch (error) { 10 + console.log(`error while pushing bounce metric: ${error}`); 11 + } 12 + return new Response(); 13 + };