pstream is dead; long live pstream taciturnaxolotl.github.io/pstream-ng/
1
fork

Configure Feed

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

Revert "thumbs up or down skip intros"

This reverts commit 7ea4b1d23bfb34865b1b8a5fc99ebfbf2da5fddf.

Pas 4024aecd a0a095bb

+20 -155
-4
src/assets/locales/en.json
··· 735 735 "device": "device", 736 736 "enabled": "Casting to device 🎬" 737 737 }, 738 - "skipIntro": { 739 - "feedback": "Was this skip helpful?", 740 - "skip": "Skip Intro" 741 - }, 742 738 "menus": { 743 739 "downloads": { 744 740 "button": "Attempt download",
-4
src/components/Icon.tsx
··· 83 83 RELOAD = "reload", 84 84 REPEAT = "repeat", 85 85 PLUS = "plus", 86 - THUMBS_UP = "thumbsUp", 87 - THUMBS_DOWN = "thumbsDown", 88 86 } 89 87 90 88 export interface IconProps { ··· 185 183 reload: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 640 640" fill="currentColor"><!--!Font Awesome Free v7.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M544.1 256L552 256C565.3 256 576 245.3 576 232L576 88C576 78.3 570.2 69.5 561.2 65.8C552.2 62.1 541.9 64.2 535 71L483.3 122.8C439 86.1 382 64 320 64C191 64 84.3 159.4 66.6 283.5C64.1 301 76.2 317.2 93.7 319.7C111.2 322.2 127.4 310 129.9 292.6C143.2 199.5 223.3 128 320 128C364.4 128 405.2 143 437.7 168.3L391 215C384.1 221.9 382.1 232.2 385.8 241.2C389.5 250.2 398.3 256 408 256L544.1 256zM573.5 356.5C576 339 563.8 322.8 546.4 320.3C529 317.8 512.7 330 510.2 347.4C496.9 440.4 416.8 511.9 320.1 511.9C275.7 511.9 234.9 496.9 202.4 471.6L249 425C255.9 418.1 257.9 407.8 254.2 398.8C250.5 389.8 241.7 384 232 384L88 384C74.7 384 64 394.7 64 408L64 552C64 561.7 69.8 570.5 78.8 574.2C87.8 577.9 98.1 575.8 105 569L156.8 517.2C201 553.9 258 576 320 576C449 576 555.7 480.6 573.4 356.5z"/></svg>`, 186 184 repeat: `<svg viewBox="0 0 24 24" width="1em" height="1em" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round" class="css-i6dzq1"><polyline points="17 1 21 5 17 9"></polyline><path d="M3 11V9a4 4 0 0 1 4-4h14"></path><polyline points="7 23 3 19 7 15"></polyline><path d="M21 13v2a4 4 0 0 1-4 4H3"></path></svg>`, 187 185 plus: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 640" width="1em" height="1em" fill="currentColor"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2025 Fonticons, Inc.--><path d="M352 128C352 110.3 337.7 96 320 96C302.3 96 288 110.3 288 128L288 288L128 288C110.3 288 96 302.3 96 320C96 337.7 110.3 352 128 352L288 352L288 512C288 529.7 302.3 544 320 544C337.7 544 352 529.7 352 512L352 352L512 352C529.7 352 544 337.7 544 320C544 302.3 529.7 288 512 288L352 288L352 128z"/></svg>`, 188 - thumbsUp: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 640 640"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M144 224C161.7 224 176 238.3 176 256L176 512C176 529.7 161.7 544 144 544L96 544C78.3 544 64 529.7 64 512L64 256C64 238.3 78.3 224 96 224L144 224zM334.6 80C361.9 80 384 102.1 384 129.4L384 133.6C384 140.4 382.7 147.2 380.2 153.5L352 224L512 224C538.5 224 560 245.5 560 272C560 291.7 548.1 308.6 531.1 316C548.1 323.4 560 340.3 560 360C560 383.4 543.2 402.9 521 407.1C525.4 414.4 528 422.9 528 432C528 454.2 513 472.8 492.6 478.3C494.8 483.8 496 489.8 496 496C496 522.5 474.5 544 448 544L360.1 544C323.8 544 288.5 531.6 260.2 508.9L248 499.2C232.8 487.1 224 468.7 224 449.2L224 262.6C224 247.7 227.5 233 234.1 219.7L290.3 107.3C298.7 90.6 315.8 80 334.6 80z"/></svg>`, 189 - thumbsDown: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" fill="currentColor" viewBox="0 0 640 640"><!--!Font Awesome Free v7.1.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2026 Fonticons, Inc.--><path d="M448 96C474.5 96 496 117.5 496 144C496 150.3 494.7 156.2 492.6 161.7C513 167.2 528 185.8 528 208C528 217.1 525.4 225.6 521 232.9C543.2 237.1 560 256.6 560 280C560 299.7 548.1 316.6 531.1 324C548.1 331.4 560 348.3 560 368C560 394.5 538.5 416 512 416L352 416L380.2 486.4C382.7 492.7 384 499.5 384 506.3L384 510.5C384 537.8 361.9 559.9 334.6 559.9C315.9 559.9 298.8 549.3 290.4 532.6L234.1 420.3C227.4 407 224 392.3 224 377.4L224 190.8C224 171.4 232.9 153 248 140.8L260.2 131.1C288.6 108.4 323.8 96 360.1 96L448 96zM144 160C161.7 160 176 174.3 176 192L176 448C176 465.7 161.7 480 144 480L96 480C78.3 480 64 465.7 64 448L64 192C64 174.3 78.3 160 96 160L144 160z"/></svg>`, 190 186 }; 191 187 192 188 export const Icon = memo((props: IconProps) => {
+20 -147
src/components/player/atoms/SkipIntroButton.tsx
··· 1 1 import classNames from "classnames"; 2 - import { useCallback, useEffect, useRef, useState } from "react"; 3 - import { useTranslation } from "react-i18next"; 2 + import { useCallback } from "react"; 4 3 5 4 import { Icon, Icons } from "@/components/Icon"; 6 5 import { useSkipTracking } from "@/components/player/hooks/useSkipTracking"; ··· 51 50 const display = usePlayerStore((s) => s.display); 52 51 const meta = usePlayerStore((s) => s.meta); 53 52 const { addSkipEvent } = useSkipTracking(20); 54 - const [showFeedback, setShowFeedback] = useState(false); 55 - const [feedbackSubmitted, setFeedbackSubmitted] = useState(false); 56 - const timeoutRef = useRef<ReturnType<typeof setTimeout> | null>(null); 57 - const pendingSkipDataRef = useRef<{ 58 - startTime: number; 59 - endTime: number; 60 - skipDuration: number; 61 - } | null>(null); 62 53 const showingState = shouldShowSkipButton(time, props.skipTime); 63 54 const animation = showingState === "hover" ? "slide-up" : "fade"; 64 55 let bottom = "bottom-[calc(6rem+env(safe-area-inset-bottom))]"; ··· 68 59 : "bottom-[calc(3rem+env(safe-area-inset-bottom))]"; 69 60 } 70 61 71 - const { t } = useTranslation(); 72 - 73 - const reportSkip = useCallback( 74 - (confidence: number) => { 75 - if (!pendingSkipDataRef.current) return; 62 + const handleSkip = useCallback(() => { 63 + if (typeof props.skipTime === "number" && display) { 64 + const startTime = time; 65 + const endTime = props.skipTime; 66 + const skipDuration = endTime - startTime; 76 67 77 - const { startTime, endTime, skipDuration } = pendingSkipDataRef.current; 68 + display.setTime(props.skipTime); 78 69 70 + // Add manual skip event with high confidence (user explicitly clicked skip intro) 79 71 addSkipEvent({ 80 72 startTime, 81 73 endTime, 82 74 skipDuration, 83 - confidence, 75 + confidence: 0.95, // High confidence for explicit user action 84 76 meta: meta 85 77 ? { 86 78 title: ··· 96 88 }); 97 89 98 90 // eslint-disable-next-line no-console 99 - console.log( 100 - `Skip intro reported: ${skipDuration}s total, confidence: ${confidence}`, 101 - ); 102 - 103 - // Clean up 104 - pendingSkipDataRef.current = null; 105 - setShowFeedback(false); 106 - setFeedbackSubmitted(true); 107 - if (timeoutRef.current) { 108 - clearTimeout(timeoutRef.current); 109 - timeoutRef.current = null; 110 - } 111 - }, 112 - [addSkipEvent, meta], 113 - ); 114 - 115 - const handleThumbsUp = useCallback(() => { 116 - reportSkip(0.95); 117 - }, [reportSkip]); 118 - 119 - const handleThumbsDown = useCallback(() => { 120 - reportSkip(0.7); 121 - }, [reportSkip]); 122 - 123 - const handleSkip = useCallback(() => { 124 - if (typeof props.skipTime === "number" && display) { 125 - const startTime = time; 126 - const endTime = props.skipTime; 127 - const skipDuration = endTime - startTime; 128 - 129 - display.setTime(props.skipTime); 130 - 131 - // Store skip data temporarily 132 - pendingSkipDataRef.current = { 133 - startTime, 134 - endTime, 135 - skipDuration, 136 - }; 137 - 138 - // Show feedback UI 139 - setShowFeedback(true); 140 - setFeedbackSubmitted(false); 141 - 142 - // Start 10-second timeout 143 - timeoutRef.current = setTimeout(() => { 144 - // Hide component immediately to prevent flicker 145 - setShowFeedback(false); 146 - setFeedbackSubmitted(true); 147 - reportSkip(0.8); 148 - }, 10000); 149 - 150 - // eslint-disable-next-line no-console 151 91 console.log(`Skip intro button used: ${skipDuration}s total`); 152 92 } 153 - }, [props.skipTime, display, time, reportSkip]); 154 - 155 - // Reset feedback state when content changes 156 - useEffect(() => { 157 - setShowFeedback(false); 158 - setFeedbackSubmitted(false); 159 - if (timeoutRef.current) { 160 - clearTimeout(timeoutRef.current); 161 - timeoutRef.current = null; 162 - } 163 - pendingSkipDataRef.current = null; 164 - }, [meta?.tmdbId]); 165 - 166 - // Cleanup timeout on unmount 167 - useEffect(() => { 168 - return () => { 169 - if (timeoutRef.current) { 170 - clearTimeout(timeoutRef.current); 171 - } 172 - }; 173 - }, []); 174 - 93 + }, [props.skipTime, display, time, addSkipEvent, meta]); 175 94 if (!props.inControl) return null; 176 95 177 96 let show = false; 178 - // Don't show anything if feedback has been submitted 179 - if (feedbackSubmitted) { 180 - show = false; 181 - } else if (showFeedback) { 182 - // Always show feedback UI when active 183 - show = true; 184 - } else if (showingState === "always") { 185 - // Show skip button when always visible 186 - show = true; 187 - } else if (showingState === "hover" && props.controlsShowing) { 188 - // Show skip button on hover when controls are showing 189 - show = true; 190 - } 97 + if (showingState === "always") show = true; 98 + else if (showingState === "hover" && props.controlsShowing) show = true; 191 99 if (status !== "playing") show = false; 192 100 193 101 return ( ··· 198 106 > 199 107 <div 200 108 className={classNames([ 201 - "absolute bottom-0 right-0 transition-[bottom] duration-200 flex items-center", 202 - showFeedback ? "flex-col space-y-2" : "space-x-3", 109 + "absolute bottom-0 right-0 transition-[bottom] duration-200 flex items-center space-x-3", 203 110 bottom, 204 111 ])} 205 112 > 206 - {showFeedback ? ( 207 - <> 208 - <div className="text-sm font-medium text-white"> 209 - {t("player.skipIntro.feedback")} 210 - </div> 211 - <div className="flex items-center space-x-3"> 212 - <button 213 - type="button" 214 - onClick={handleThumbsUp} 215 - className={classNames( 216 - "h-10 w-10 rounded-full flex items-center justify-center", 217 - "bg-buttons-primary hover:bg-buttons-primaryHover text-buttons-primaryText", 218 - "scale-95 hover:scale-100 transition-all duration-200", 219 - )} 220 - aria-label="Thumbs up" 221 - > 222 - <Icon className="text-xl" icon={Icons.THUMBS_UP} /> 223 - </button> 224 - <button 225 - type="button" 226 - onClick={handleThumbsDown} 227 - className={classNames( 228 - "h-10 w-10 rounded-full flex items-center justify-center", 229 - "bg-buttons-primary hover:bg-buttons-primaryHover text-buttons-primaryText", 230 - "scale-95 hover:scale-100 transition-all duration-200", 231 - )} 232 - aria-label="Thumbs down" 233 - > 234 - <Icon className="text-xl" icon={Icons.THUMBS_DOWN} /> 235 - </button> 236 - </div> 237 - </> 238 - ) : ( 239 - <Button 240 - onClick={handleSkip} 241 - className="bg-buttons-primary hover:bg-buttons-primaryHover text-buttons-primaryText flex justify-center items-center" 242 - > 243 - <Icon className="text-xl mr-1" icon={Icons.SKIP_EPISODE} /> 244 - {t("player.skipIntro.skip")} 245 - </Button> 246 - )} 113 + <Button 114 + onClick={handleSkip} 115 + className="bg-buttons-primary hover:bg-buttons-primaryHover text-buttons-primaryText flex justify-center items-center" 116 + > 117 + <Icon className="text-xl mr-1" icon={Icons.SKIP_EPISODE} /> 118 + Skip Intro 119 + </Button> 247 120 </div> 248 121 </Transition> 249 122 );