@@ -160,168 +160,3 @@ <h2>🎬 Continuous Video Rating</h2>
160160</ html >
161161
162162
163-
164-
165-
166- <!DOCTYPE html>
167- < html lang ="en ">
168- < head >
169- < meta charset ="UTF-8 ">
170- < meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
171- < title > Continuous Video Rating | Lin Brain Lab</ title >
172- < style >
173- body {
174- font-family : sans-serif;
175- margin : 40px ;
176- max-width : 700px ;
177- line-height : 1.6 ;
178- }
179- h2 { color : # 007bff ; }
180- iframe {
181- width : 100% ;
182- max-width : 700px ;
183- height : 400px ;
184- border : none;
185- margin-top : 15px ;
186- }
187- input [type = "range" ] {
188- width : 100% ;
189- margin-top : 25px ;
190- accent-color : # 007bff ;
191- }
192- .value-display {
193- text-align : center;
194- font-size : 18px ;
195- margin-top : 10px ;
196- }
197- button {
198- margin-top : 25px ;
199- padding : 10px 20px ;
200- font-size : 16px ;
201- background-color : # 007bff ;
202- color : white;
203- border : none;
204- border-radius : 6px ;
205- cursor : pointer;
206- transition : background-color 0.2s ;
207- }
208- button : hover {
209- background-color : # 0056b3 ;
210- }
211- .message {
212- margin-top : 15px ;
213- font-weight : bold;
214- }
215- </ style >
216- </ head >
217- < body >
218- < h2 > 🎬 Continuous Video Rating</ h2 >
219- < p >
220- Watch the following video and continuously adjust the slider between
221- < strong > -1</ strong > (very negative) and < strong > +1</ strong > (very positive)
222- to reflect your feelings in real-time. Ratings are automatically recorded every few seconds.
223- </ p >
224-
225- <!-- Pre-selected video -->
226- < iframe
227- id ="videoPlayer "
228- src ="https://drive.google.com/file/d/1fns2A7stkoZZTtcSIaGDaT9Kgy_N5014/preview "
229- allow ="autoplay ">
230- </ iframe >
231-
232- <!-- Continuous slider -->
233- < div style ="margin-top: 25px; ">
234- < label for ="rating "> Your Rating (-1 to +1):</ label >
235- < input type ="range " id ="rating " min ="-1 " max ="1 " step ="0.01 " value ="0 ">
236- < div class ="value-display "> Current value: < span id ="ratingValue "> 0</ span > </ div >
237- </ div >
238-
239- <!-- Control buttons -->
240- < button id ="startBtn "> ▶️ Start Recording</ button >
241- < button id ="stopBtn " disabled > ⏹ Stop Recording</ button >
242- < div class ="message " id ="message "> </ div >
243-
244- < script >
245- const ratingSlider = document . getElementById ( 'rating' ) ;
246- const ratingValue = document . getElementById ( 'ratingValue' ) ;
247- const startBtn = document . getElementById ( 'startBtn' ) ;
248- const stopBtn = document . getElementById ( 'stopBtn' ) ;
249- const message = document . getElementById ( 'message' ) ;
250- const GOOGLE_SCRIPT_URL = "https://script.google.com/macros/s/AKfycbxMQof9YkBtEmX4iapHRSQ5DLVbhYbOS-BhN13dQE6v0BOxEt-Ozc2_vUc1iWt5T8lGDg/exec" ;
251- const samplingInterval = 5 ; // seconds between logs
252-
253- let recording = false ;
254- let timer = null ;
255- let playTime = '' ;
256- let ipAddress = '' ;
257-
258- // Update display
259- ratingSlider . addEventListener ( 'input' , ( ) => {
260- ratingValue . textContent = ratingSlider . value ;
261- } ) ;
262-
263- // Fetch viewer IP
264- async function getIP ( ) {
265- try {
266- const res = await fetch ( 'https://api.ipify.org?format=json' ) ;
267- const data = await res . json ( ) ;
268- return data . ip ;
269- } catch {
270- return 'unknown' ;
271- }
272- }
273-
274- // Send one rating to Google Sheet
275- async function sendRating ( rating , timestamp ) {
276- const payload = {
277- videoName,
278- playTime,
279- rateTime : timestamp ,
280- rating,
281- ip : ipAddress
282- } ;
283-
284- try {
285- await fetch ( GOOGLE_SCRIPT_URL + "?ip=" + encodeURIComponent ( ipAddress ) , {
286- method : "POST" ,
287- mode : "no-cors" ,
288- headers : { "Content-Type" : "application/json" } ,
289- body : JSON . stringify ( payload )
290- } ) ;
291- } catch ( err ) {
292- console . error ( "Error sending rating:" , err ) ;
293- }
294- }
295-
296- // Start continuous logging
297- startBtn . addEventListener ( 'click' , async ( ) => {
298- if ( recording ) return ;
299- ipAddress = await getIP ( ) ;
300- playTime = new Date ( ) . toISOString ( ) ;
301- recording = true ;
302- message . style . color = 'green' ;
303- message . textContent = "⏺ Recording started. Ratings will be logged every " + samplingInterval + " seconds." ;
304- startBtn . disabled = true ;
305- stopBtn . disabled = false ;
306-
307- // send ratings periodically
308- timer = setInterval ( async ( ) => {
309- const currentRating = ratingSlider . value ;
310- const now = new Date ( ) . toISOString ( ) ;
311- await sendRating ( currentRating , now ) ;
312- } , samplingInterval * 1000 ) ;
313- } ) ;
314-
315- // Stop continuous logging
316- stopBtn . addEventListener ( 'click' , ( ) => {
317- if ( ! recording ) return ;
318- clearInterval ( timer ) ;
319- recording = false ;
320- message . style . color = 'blue' ;
321- message . textContent = "✅ Recording stopped." ;
322- startBtn . disabled = false ;
323- stopBtn . disabled = true ;
324- } ) ;
325- </ script >
326- </ body >
327- </ html >
0 commit comments