From 886475de426140ace0b9919be756c099f3313e7d Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Thu, 28 Aug 2025 11:49:18 +0000 Subject: [PATCH] Improve video thumbnail loading and display with fallback options Refactor thumbnail loading logic in VideoCard and VideoPage components to directly display a placeholder on error. Update BunnyService to prioritize custom thumbnail filenames from Bunny.net. Replit-Commit-Author: Agent Replit-Commit-Session-Id: d7424866-83d1-4486-a212-ac12b4c7becf Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/d7424866-83d1-4486-a212-ac12b4c7becf/eJ5eRgX --- attached_assets/image_1756381693052.png | Bin 0 -> 2569 bytes attached_assets/image_1756381719563.png | Bin 0 -> 2326 bytes client/src/components/video-card.tsx | 21 ++++++++++----------- client/src/pages/VideoPage.tsx | 19 +++++++++---------- server/bunny.ts | 8 +++++--- 5 files changed, 24 insertions(+), 24 deletions(-) create mode 100644 attached_assets/image_1756381693052.png create mode 100644 attached_assets/image_1756381719563.png diff --git a/attached_assets/image_1756381693052.png b/attached_assets/image_1756381693052.png new file mode 100644 index 0000000000000000000000000000000000000000..27895e691350fd87dabce4a58609b6c06f0deb37 GIT binary patch literal 2569 zcmaJ@c|6qH8~#esFbG-Z+OkuTeaSM-WGCy?h%okSSu-MTC`70KjH!q-PBP4C3Hi z^gI*TF)Ku5}i%R-@q{Xb&|4K-86UHCs{C3>;@JzcxZwQ8*;GC1tg5zvg z;Ea|Ok8>6~V`>0x*E^e?%paF{{whon%FSu3%m63BuV%YRI1>Bonl`0XMQtR`Z*sxQx0Eg6S`fsu@!8=M&_mTzTfiJKXragA($Sz^c9=joWk%wpKq|Ll6J$69@ zxM9%g(fGT>i{f{~W1p6!l&eM$70;Ht8*}iH&JedFu8=7bt=H3Pd8#>eyJJmA|M9(Y znX1_c3~#SRODPr=5~&3GTIicn_tz3<-tTsGq9*d#Urslo{kZ(|33$W3n-;;^FS+u)|&1DHZuj?8OGn zyM;b>eRdkJbqal;R05ZzcnOj{>XUGaC;rK$k}P_jfPi=4_N3RYh9AR(R8V^Xk}ZT%=0L-B&Gn3#;rpa7z{qJR*h^Hgdfwy z3k!>k;Pi$-j@=C0y;3vzH(Ekp4Q8Z!Uo_Ogysn@z=s9!nX)@h22ori|oZXO9j?ZCZ zK*c3EhdVR8b4cCVSrG<8$2P{4V~=NS7Fp;RM-^Vt1T<)5T_pq2(5F$ah0t^1V>g$K zR-`*{7w~kIH}Mhq9P9O03N@%Rym72T2L(%a!a`T`AkBLP6nt}+&R6E&J0($h{FA;w zLSkZTL*-BK62*C;*8wo%V5#N9V+ob(!ujZIs5{Z2l zW>3hzl91Z6)iWCh@Jk2b+QR%ja7JKvf4}JHo1aoA;^4xnA*C5&h3j>?=%~!Ggo?>W4Vz5| zaLK9{v@e1Jy0x|^Vfn~0?WgOXopToOc)gyv`-_2x+4P9G8tbN7_XR4U8?72Q6jl#; zKVuSW^2uX}5FfmP-}6tV^GYu1FMUzxlh+fbO01M1$(0N-epOc4JgBdYH~vm$Q|0~ z>8g!%z}mjwJzAG~2n7g@=f-aCiCv*OgxuRK#t%+Rq)o1myFCC?N{eJa>-B-t@Q5Q& zuAEkyV!(Vb*1#y4Cn$F9qUct{(FP-TGT+=ZZa%HMZt}0IR_=lju1G^ReosgD8VQh3 z7_3GsHN03NKJ^y9PRMG|YOKb~_3PeaSX;g0*mK4kR#u{gMMZifPP%H(WOg*^AYA`k zTgw7NN7t9<_5MgWhWCQor)LCzH6! z%ZR7Y>;9pM_2*)6C-ESK$&;Bv$NYxPrR+JTe?-nC%rI1tM-14j+-2eD63H(jqF#f@ zpfpe-0c2-V-}ls&6`7zX>y=ei=Rw$ikkH*Pi>j)OMm!0A;Sr3#PleyHvHq=Rb@Vlz zIYPHr1nao=bKnxlB!f5yjk{F7Fm2&RR%fgR$n};$2!cX&AEXjSOUbqC7Wd;fq1|~? za~&I>O1^rJFr0MuaK!BlbnBqyomxJT1{Pee*0!Bk@PMd1z8ehvvqDR!%zgE}0nG`K z{PGOrt6a@vj+pko$?wn?WpcB8EW?r*yxORek{Wa7bL9+BVomjw1;I=co)u)rP87Eq z!)0t8upfVnhAP{rs*TJ~qW3g{_a~F5MQN-@YAMeAQaM$(!IDP7)%pL|I&{Wtw0yR< S_=z#_F;uKd%HY008`EDC4W3Ujhxm z%>|AWo7X#_WAndiY6O&ZN&Nx?h^wK6Aple)z;2P#vwZ0U(x;6O(DX$sVFkMSrm zBw$IJi<(wj(ycPdvGr2Ve|Bu{++2Miw@Q=PdxkJKJa#pI7l6C06ttc+etZhgb4AYF z!RS!5NQMw+{{Nc7K(UN3sd$)`XACa2e?FWe0H8lI$1iR~#_d>3OZXPm6 z$6DE6ji|UHXpTmv20DYQ>o5X0^z3IWny2Tu2ed{B6A>+0UGk(qZ@|p2qjj#meO97E zFiuvGSko^^ca~LRP84Yg{hd1bfO`o45Gfn*F@?hh5`|mlj*WxOU}m$m>^O*103a@| zH%+&szdI@YeArSp%+iUbQj1%Bp-J!=^ud+saQS~xD?X-^senugOcRsMIp0@V^fSoa z9Ru!fqfnrxhJ>F(W|5^!RWmZ!07#xRPmKLF8w1u8dBOd!3;JU33p*Q?By9RMQK&v6 zp^+I27(x!eXQ!C0h&z(3d|wnnm1l0`9Pk#XSxk^oEBF$%6{Z1Uo0-?-esO9_w2j`L zETulLO_}jS6O&wRds_Pu9?d?QdA}Ugfo2CR;Vo6Sg~<+Q=d}xV%mvBW#ISLy1D0yOqjEXNkrp%osqK6WE(bAsJV%tY zd+r03F3?GTL)AOFK3|l z!=xk_98=Vf-&o6$Tn;z9J`k%n5t;rsOp6u7(6`gGPpU-nguu3%7yWYOLbb<~p&)dx zo=Obddg;N!uiP+vB-0`IFn$ng5kWr&-sp%G$zIQ%V?tKFb=V=t=4!8okqc*7w;Z>2K2f>?{hGg!!<6r*xNP+yJeVDwci*G7MZ5BShkdkRBUy8?Q-4=Dci`~^yGl#Vf@DKRvp)thk=CC@tx-`JJ>_4Uz90= z3RDfYxb(6oHih1vxiWynyrdsJs2{C8kgJ>+KmFV`uT*;McTMqIWO$8)^fh5AFy}2( z^#~fQr`V=|^YAJ}YWHEJ%Z2~)=&k=quRciPWxP^)SE6l=kIJK{x4$KHLNN3G8y8B6 z&R&ejLlFUlr3qR`rd#{c8}v8?@EvO0#jdD zPra-B!8ZMRI1~c#@$uyy{N>l8g5CN@Ub~+#_c@J(l>)o5gf37*C;nI%j+@MRWMu#Q zPS7C0(2q__>JPB%ExS&u=ziS3qtQLS!gY3l{JzsFGRiQE{McSPDs{um zGh=A~PHC1dGpIS8P2C zUR^^O{*xRS{w)*1Q}`h=BvD8fM$%SlGs!}u(-m9LDv?tIJyRHhE}cF%%)7KfjBpT- zWPH{x^`u#w_`?6uIn&n7@u|O+{l%O`F>(be#adSf)kvyb|Fpr(b5~^*O8LadCZRT) zeDR69?qK{gpThGQ4W|qLobzJDmb8V32r`!&w?Mi(D*W)&KT$cNOmVx!LBo3{F==ZE zW2KuNXMhz~=787qtV_$?#`tHF)t;9?MLbco>Ljmxkuhkv;c7Yg_nD;5L59yXh6BWS zn`Qt_Ok-&^l&`mCsi~?)jA4d7y?IyHz*92)NPGNzd@Z?_*_-?3#5s#oLsgPRIZ}7x z%5~u~fT}71#;t~J^+%(TPBcIN$`gkNorKhb8l%K#ZAyuhcYzSFQ$Tr$*#24Z>s=sR zQJ>Gp>xb6NMk);Dup$%a*%uC;w(WaM{N)Gb>mt!!RV}z>BT$i<1bu6)SkQCD${V^# zg?7-W53q6DY|l%(*Ha3wVHa8>QMBU51$+fv zFCXwAb1Ww!@tX}lR|w7cZ`N4L`lClybH2EzXl^ssc^=r^G;nrjDvBPAU2%goZBMh{ zNISt9A71u=F;;3)1;^wh&Kj8-Oyc%hOs(!dN7BYkaV^FR78%2m>lj;g`$anN?h;U7 zs~^}zQT>(Rwj`MS8BwEs16bvhh!IKPq%xe>I0hZfeuW{De?GM?;*`+;HPsW!*2QW2 VD$Y#cEcllJ%uFsDml-)e`4?$(Y?=T7 literal 0 HcmV?d00001 diff --git a/client/src/components/video-card.tsx b/client/src/components/video-card.tsx index ded2469..9df0b88 100644 --- a/client/src/components/video-card.tsx +++ b/client/src/components/video-card.tsx @@ -60,17 +60,16 @@ export default function VideoCard({ video, onClick }: VideoCardProps) { decoding="async" onError={(e) => { const target = e.target as HTMLImageElement; - // Try backup thumbnail URL - const backupUrl = `https://iframe.mediadelivery.net/embed/476412/${video.id}/thumbnail.jpg`; - if (!target.src.includes('iframe.mediadelivery.net')) { - target.src = backupUrl; - } else { - // If both fail, show placeholder - target.style.display = 'none'; - if (target.parentElement) { - target.parentElement.style.background = 'linear-gradient(45deg, #374151, #4b5563)'; - target.parentElement.innerHTML += '
Video
'; - } + console.log('Thumbnail failed to load:', target.src); + + // Show placeholder immediately instead of trying multiple URLs + target.style.display = 'none'; + if (target.parentElement && !target.parentElement.querySelector('.thumbnail-placeholder')) { + target.parentElement.style.background = 'linear-gradient(135deg, #1f2937, #374151)'; + const placeholder = document.createElement('div'); + placeholder.className = 'thumbnail-placeholder absolute inset-0 flex flex-col items-center justify-center text-white'; + placeholder.innerHTML = '
🎬
Video
'; + target.parentElement.appendChild(placeholder); } }} /> diff --git a/client/src/pages/VideoPage.tsx b/client/src/pages/VideoPage.tsx index 1779868..1268678 100644 --- a/client/src/pages/VideoPage.tsx +++ b/client/src/pages/VideoPage.tsx @@ -244,16 +244,15 @@ export default function VideoPage() { className="w-full h-full object-cover" onError={(e) => { const target = e.target as HTMLImageElement; - // Try backup thumbnail URL - const backupUrl = `https://iframe.mediadelivery.net/embed/476412/${video.id}/thumbnail.jpg`; - if (!target.src.includes('iframe.mediadelivery.net')) { - target.src = backupUrl; - } else { - target.style.display = 'none'; - if (target.parentElement) { - target.parentElement.style.background = 'linear-gradient(45deg, #374151, #4b5563)'; - target.parentElement.innerHTML += '
Video
'; - } + console.log('Sidebar thumbnail failed:', target.src); + + target.style.display = 'none'; + if (target.parentElement && !target.parentElement.querySelector('.thumbnail-placeholder')) { + target.parentElement.style.background = 'linear-gradient(135deg, #1f2937, #374151)'; + const placeholder = document.createElement('div'); + placeholder.className = 'thumbnail-placeholder absolute inset-0 flex items-center justify-center text-white text-xs'; + placeholder.innerHTML = '
🎬
'; + target.parentElement.appendChild(placeholder); } }} /> diff --git a/server/bunny.ts b/server/bunny.ts index 20b92d6..8ec3c97 100644 --- a/server/bunny.ts +++ b/server/bunny.ts @@ -52,9 +52,11 @@ export class BunnyService { } private bunnyVideoToVideo(bunnyVideo: BunnyVideo): Video { - // Generate multiple thumbnail URL options - const thumbnailUrl = `https://${this.hostname}/${bunnyVideo.guid}/thumbnail.jpg`; - const backupThumbnailUrl = `https://iframe.mediadelivery.net/embed/${this.libraryId}/${bunnyVideo.guid}/thumbnail.jpg`; + // Generate thumbnail URL from Bunny CDN - try multiple formats + // Some videos may have custom thumbnails, others auto-generated + const thumbnailUrl = bunnyVideo.thumbnailFileName + ? `https://${this.hostname}/${bunnyVideo.guid}/${bunnyVideo.thumbnailFileName}` + : `https://${this.hostname}/${bunnyVideo.guid}/thumbnail.jpg`; // Generate signed HLS URL for private video access const hlsUrl = this.generateSignedUrl(bunnyVideo.guid);