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.

scroll to active episode and caption, fix last provider being nonactive. caption delays mobile friendly input, bigger range caption delay range

Co-authored-by: Jip Frijlink <JipFr@users.noreply.github.com>

mrjvs a2968d3b ace10dde

+95 -44
+1 -1
src/components/Icon.tsx
··· 64 64 chevronDown: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-down"><polyline points="6 9 12 15 18 9"></polyline></svg>`, 65 65 chevronUp: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-up"><polyline points="18 15 12 9 6 15"></polyline></svg>`, 66 66 chevronRight: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-right"><polyline points="9 18 15 12 9 6"></polyline></svg>`, 67 - chevronLeft: `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-left"><polyline points="15 18 9 12 15 6"></polyline></svg>`, 67 + chevronLeft: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-chevron-left"><polyline points="15 18 9 12 15 6"></polyline></svg>`, 68 68 clapperBoard: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="currentColor" d="M326.1 160l127.4-127.4C451.7 32.39 449.9 32 448 32h-86.06l-128 128H326.1zM166.1 160l128-128H201.9l-128 128H166.1zM497.7 56.19L393.9 160H512V96C512 80.87 506.5 67.15 497.7 56.19zM134.1 32H64C28.65 32 0 60.65 0 96v64h6.062L134.1 32zM0 416c0 35.35 28.65 64 64 64h384c35.35 0 64-28.65 64-64V192H0V416z"/></svg>`, 69 69 film: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="currentColor" d="M463.1 32h-416C21.49 32-.0001 53.49-.0001 80v352c0 26.51 21.49 48 47.1 48h416c26.51 0 48-21.49 48-48v-352C511.1 53.49 490.5 32 463.1 32zM111.1 408c0 4.418-3.582 8-8 8H55.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8L111.1 408zM111.1 280c0 4.418-3.582 8-8 8H55.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8V280zM111.1 152c0 4.418-3.582 8-8 8H55.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8L111.1 152zM351.1 400c0 8.836-7.164 16-16 16H175.1c-8.836 0-16-7.164-16-16v-96c0-8.838 7.164-16 16-16h160c8.836 0 16 7.162 16 16V400zM351.1 208c0 8.836-7.164 16-16 16H175.1c-8.836 0-16-7.164-16-16v-96c0-8.838 7.164-16 16-16h160c8.836 0 16 7.162 16 16V208zM463.1 408c0 4.418-3.582 8-8 8h-47.1c-4.418 0-7.1-3.582-7.1-8l0-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8V408zM463.1 280c0 4.418-3.582 8-8 8h-47.1c-4.418 0-8-3.582-8-8v-48c0-4.418 3.582-8 8-8h47.1c4.418 0 8 3.582 8 8V280zM463.1 152c0 4.418-3.582 8-8 8h-47.1c-4.418 0-8-3.582-8-8l0-48c0-4.418 3.582-8 7.1-8h47.1c4.418 0 8 3.582 8 8V152z"/></svg>`, 70 70 dragon: `<svg xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" viewBox="0 0 640 512"><!--! Font Awesome Pro 6.0.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. --><path fill="currentColor" d="M18.43 255.8L192 224L100.8 292.6C90.67 302.8 97.8 320 112 320h222.7c-9.499-26.5-14.75-54.5-14.75-83.38V194.2L200.3 106.8C176.5 90.88 145 92.75 123.3 111.2l-117.5 116.4C-6.562 238 2.436 258 18.43 255.8zM575.2 289.9l-100.7-50.25c-16.25-8.125-26.5-24.75-26.5-43V160h63.99l28.12 22.62C546.1 188.6 554.2 192 562.7 192h30.1c11.1 0 23.12-6.875 28.5-17.75l14.37-28.62c5.374-10.87 4.25-23.75-2.999-33.5l-74.49-99.37C552.1 4.75 543.5 0 533.5 0H296C288.9 0 285.4 8.625 290.4 13.62L351.1 64L292.4 88.75c-5.874 3-5.874 11.37 0 14.37L351.1 128l-.0011 108.6c0 72 35.99 139.4 95.99 179.4c-195.6 6.75-344.4 41-434.1 60.88c-8.124 1.75-13.87 9-13.87 17.38C.0463 504 8.045 512 17.79 512h499.1c63.24 0 119.6-47.5 122.1-110.8C642.3 354 617.1 310.9 575.2 289.9zM489.1 66.25l45.74 11.38c-2.75 11-12.5 18.88-24.12 18.25C497.7 95.25 484.8 83.38 489.1 66.25z"/></svg>`,
+2 -2
src/components/player/atoms/Episodes.tsx
··· 123 123 content = <CenteredText>Loading...</CenteredText>; 124 124 else if (loadingState.value) { 125 125 content = ( 126 - <Menu.Section className="pb-6"> 126 + <Menu.ScrollToActiveSection className="pb-6"> 127 127 {loadingState.value.season.episodes.length === 0 ? ( 128 128 <Menu.TextDisplay title="No episodes found"> 129 129 There are no episodes in this season, check back later! ··· 173 173 </Menu.Link> 174 174 ); 175 175 })} 176 - </Menu.Section> 176 + </Menu.ScrollToActiveSection> 177 177 ); 178 178 } 179 179
+36 -33
src/components/player/atoms/settings/CaptionSettingsView.tsx
··· 77 77 }; 78 78 }, [isFocused]); 79 79 80 - function setNewValue(value: number) { 81 - props.onChange?.(Math.min(Math.max(value, props.min), props.max)); 82 - } 83 - 84 - const inputClasses = 85 - "px-3 py-1 bg-video-context-inputBg rounded w-20 text-left text-white cursor-text"; 80 + const inputClasses = `py-1 bg-video-context-inputBg rounded text-white cursor-text ${ 81 + props.controlButtons ? "text-center px-4 w-24" : "px-3 text-left w-20" 82 + }`; 83 + const arrowButtonClasses = 84 + "hover:text-white transition-colors duration-100 w-full h-full flex justify-center items-center hover:bg-video-context-buttonOverInputHover rounded"; 86 85 const textTransformer = props.textTransformer ?? ((s) => s); 87 86 88 87 return ( ··· 161 160 <button 162 161 className={classNames( 163 162 inputClasses, 164 - props.controlButtons ? "pr-8 relative" : undefined 163 + props.controlButtons ? "relative" : undefined 165 164 )} 166 165 type="button" 167 166 tabIndex={0} ··· 171 170 )} 172 171 </button> 173 172 {props.controlButtons ? ( 174 - <div className="actions w-6 h-full absolute right-0 top-0 flex items-center flex-col"> 175 - <button 176 - type="button" 177 - onClick={ 178 - () => 179 - setNewValue( 180 - props.value + 1 / 10 ** (props.decimalsAllowed ?? 0) 181 - ) // Add depending on the decimalsAllowed. If there's 1 decimal allowed, add 0.1. For 2, add 0.01, etc. 182 - } 183 - className="hover:text-white transition-colors duration-100" 184 - > 185 - <Icon icon={Icons.CHEVRON_UP} /> 186 - </button> 187 - <button 188 - type="button" 189 - onClick={ 190 - () => 191 - setNewValue( 192 - props.value - 1 / 10 ** (props.decimalsAllowed ?? 0) 193 - ) // Remove depending on the decimalsAllowed. If there's 1 decimal allowed, add 0.1. For 2, add 0.01, etc. 194 - } 195 - className="hover:text-white transition-colors duration-100" 196 - > 197 - <Icon icon={Icons.CHEVRON_DOWN} /> 198 - </button> 199 - </div> 173 + <> 174 + <div className="actions w-6 h-full absolute left-0 top-0 grid grid-cols-1 items-center justify-center"> 175 + <button 176 + type="button" 177 + onClick={ 178 + () => 179 + props.onChange?.( 180 + props.value - 1 / 10 ** (props.decimalsAllowed ?? 0) 181 + ) // Remove depending on the decimalsAllowed. If there's 1 decimal allowed, add 0.1. For 2, add 0.01, etc. 182 + } 183 + className={arrowButtonClasses} 184 + > 185 + <Icon icon={Icons.CHEVRON_LEFT} /> 186 + </button> 187 + </div> 188 + <div className="actions w-6 h-full absolute right-0 top-0 grid grid-cols-1 items-center justify-center"> 189 + <button 190 + type="button" 191 + onClick={ 192 + () => 193 + props.onChange?.( 194 + props.value + 1 / 10 ** (props.decimalsAllowed ?? 0) 195 + ) // Add depending on the decimalsAllowed. If there's 1 decimal allowed, add 0.1. For 2, add 0.01, etc. 196 + } 197 + className={arrowButtonClasses} 198 + > 199 + <Icon icon={Icons.CHEVRON_RIGHT} /> 200 + </button> 201 + </div> 202 + </> 200 203 ) : null} 201 204 </div> 202 205 )}
+9 -3
src/components/player/atoms/settings/CaptionsView.tsx
··· 42 42 error={props.error} 43 43 onClick={props.onClick} 44 44 > 45 - <span className="flex items-center"> 45 + <span 46 + data-active-link={props.selected ? true : undefined} 47 + className="flex items-center" 48 + > 46 49 <span data-code={props.countryCode} className="mr-3"> 47 50 <FlagIcon countryCode={countryCode} /> 48 51 </span> ··· 167 170 <Input value={searchQuery} onInput={setSearchQuery} /> 168 171 </div> 169 172 </div> 170 - <Menu.Section className="!pt-1 mt-2 pb-3"> 173 + <Menu.ScrollToActiveSection 174 + loaded={req.loading} 175 + className="!pt-1 mt-2 pb-3" 176 + > 171 177 <CaptionOption onClick={() => disable()} selected={!lang}> 172 178 Off 173 179 </CaptionOption> 174 180 {content} 175 - </Menu.Section> 181 + </Menu.ScrollToActiveSection> 176 182 </> 177 183 ); 178 184 }
+6 -1
src/components/player/internals/ContextMenu/Links.tsx
··· 74 74 75 75 if (!props.onClick) { 76 76 return ( 77 - <div className={classes} style={styles}> 77 + <div 78 + className={classes} 79 + style={styles} 80 + data-active-link={props.active ? true : undefined} 81 + > 78 82 {content} 79 83 </div> 80 84 ); ··· 86 90 className={classes} 87 91 style={styles} 88 92 onClick={props.onClick} 93 + data-active-link={props.active ? true : undefined} 89 94 > 90 95 {content} 91 96 </button>
+34
src/components/player/internals/ContextMenu/Sections.tsx
··· 1 1 import classNames from "classnames"; 2 + import { useEffect, useRef } from "react"; 2 3 3 4 export function SectionTitle(props: { 4 5 children: React.ReactNode; ··· 26 27 </div> 27 28 ); 28 29 } 30 + 31 + export function ScrollToActiveSection(props: { 32 + children: React.ReactNode; 33 + className?: string; 34 + loaded?: boolean; 35 + }) { 36 + const scrollingContainer = useRef<HTMLDivElement>(null); 37 + 38 + useEffect(() => { 39 + const active = 40 + scrollingContainer.current?.querySelector("[data-active-link]"); 41 + 42 + const boxRect = scrollingContainer.current?.getBoundingClientRect(); 43 + const activeLinkRect = active?.getBoundingClientRect(); 44 + if (!activeLinkRect || !boxRect) return; 45 + 46 + const activeYPos = activeLinkRect.top - boxRect.top; 47 + 48 + scrollingContainer.current?.scrollTo( 49 + 0, 50 + activeYPos - boxRect.height / 2 + activeLinkRect.height / 2 51 + ); 52 + }, [props.loaded]); 53 + 54 + return ( 55 + <div 56 + ref={scrollingContainer} 57 + className={classNames("pt-4 space-y-1", props.className)} 58 + > 59 + {props.children} 60 + </div> 61 + ); 62 + }
+5 -3
src/pages/parts/player/ScrapingPart.tsx
··· 41 41 const currentProvider = sourceOrder.find( 42 42 (s) => sources[s.id].status === "pending" 43 43 ); 44 - const currentProviderIndex = 45 - sourceOrder.findIndex((provider) => currentProvider?.id === provider.id) ?? 46 - sourceOrder.length - 1; 44 + let currentProviderIndex = sourceOrder.findIndex( 45 + (provider) => currentProvider?.id === provider.id 46 + ); 47 + if (currentProviderIndex === -1) 48 + currentProviderIndex = sourceOrder.length - 1; 47 49 48 50 return ( 49 51 <div className="h-full w-full relative" ref={containerRef}>
+1 -1
src/stores/subtitles/index.ts
··· 67 67 }, 68 68 setDelay(delay) { 69 69 set((s) => { 70 - s.delay = delay; 70 + s.delay = Math.max(Math.min(500, delay), -500); 71 71 }); 72 72 }, 73 73 })),
+1
tailwind.config.js
··· 148 148 buttonFocus: "#202836", 149 149 flagBg: "#202836", 150 150 inputBg: "#202836", 151 + buttonOverInputHover: "#283040", 151 152 inputPlaceholder: "#374A56", 152 153 cardBorder: "#1B262E", 153 154 slider: "#8787A8",