()
| 206 | startLoadingBar(); |
| 207 | |
| 208 | const [movieRes, tvRes] = await Promise.all([ |
| 209 | apiClient.request(apiUrls.now_playing), |
| 210 | apiClient.request(apiUrls.tv_trending) |
| 211 | ]); |
| 212 | |
| 213 | |
| 214 | if (!movieRes.ok || !tvRes.ok) throw new Error('خطا در دریافت دادهها'); |
| 215 | |
| 216 | const [movieData, tvData] = await Promise.all([movieRes.json(), tvRes.json()]); |
| 217 | |
| 218 | movieContainer.innerHTML = tvContainer.innerHTML = ''; |
| 219 | const seenIds = new Set(); |
| 220 | |
| 221 | const renderItems = async (items, container, type) => { |
| 222 | const elements = await Promise.all(items.map(async item => { |
| 223 | if (seenIds.has(item.id)) return ''; |
| 224 | seenIds.add(item.id); |
| 225 | |
| 226 | const title = item.title || item.name || 'نامشخص'; |
| 227 | const rawDate = item.release_date || item.first_air_date || ''; |
| 228 | const year = rawDate ? rawDate.slice(0, 4) : ''; |
| 229 | const rating = item.vote_average ? Number(item.vote_average).toFixed(1) : ''; |
| 230 | const overview = item.overview ? item.overview.slice(0, 120) + '…' : 'توضیحات موجود نیست'; |
| 231 | const link = `/${type === 'movie' ? 'movie' : 'series'}/index.html?id=${item.id}`; |
| 232 | |
| 233 | // پوستر مستقیم از TMDB (سریع و پایدار) با fallback به پروکسی و سپس تصویر پیشفرض |
| 234 | const tmdbPoster = item.poster_path ? `${baseImageUrl}${item.poster_path}` : ''; |
| 235 | const proxiedPoster = tmdbPoster && window.FreeMovieApi ? window.FreeMovieApi.proxify(tmdbPoster) : ''; |
| 236 | const initialPoster = tmdbPoster || defaultPoster; |
| 237 | const fallback1 = (proxiedPoster && proxiedPoster !== initialPoster) ? proxiedPoster : defaultPoster; |
| 238 | const onError = `if(this.dataset.s==='2'){this.onerror=null;return;}if(this.dataset.s==='1'){this.dataset.s='2';this.src='${defaultPoster}';return;}this.dataset.s='1';this.src='${fallback1}';`; |
| 239 | |
| 240 | const homeStatusBadge = await buildHomepageStatusBadge(item, type); |
| 241 | |
| 242 | return ` |
| 243 | <div class="movie-card group"> |
| 244 | <a href="${link}" class="poster-wrap" aria-label="${title}"> |
| 245 | ${homeStatusBadge} |
| 246 | <img src="${initialPoster}" alt="پوستر ${title}" loading="lazy" class="poster-img" onerror="${onError}"> |
| 247 | <div class="poster-overlay"> |
| 248 | <p class="overlay-text">${overview}</p> |
| 249 | <span class="overlay-btn">مشاهده جزئیات</span> |
| 250 | </div> |
| 251 | </a> |
| 252 | <div class="card-info"> |
| 253 | <h3 class="card-title" title="${title}">${title}</h3> |
| 254 | <div class="card-meta"> |
| 255 | ${rating ? `<span class="card-rating"><i class="fas fa-star"></i> ${rating}</span>` : '<span></span>'} |
| 256 | ${year ? `<span class="card-year">${year}</span>` : ''} |
| 257 | </div> |
| 258 | <a href="${link}" class="card-btn">مشاهده</a> |
| 259 | </div> |
| 260 | </div> |
| 261 | `; |
| 262 | })); |
| 263 | container.innerHTML = elements.filter(Boolean).join('') || '<p class="text-center text-red-500 col-span-full">دادهای یافت نشد!</p>'; |
| 264 | }; |
| 265 |
no test coverage detected