Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
91 changes: 89 additions & 2 deletions web/app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -1447,6 +1447,86 @@ input:focus {
font-weight: 900;
}

/* ── Telegram settings ───────────────────────────────────────────────────── */
.tg-center {
display: flex;
flex-direction: column;
align-items: center;
gap: 16px;
padding: 12px 0 4px;
text-align: center;
}

.tg-lead {
max-width: 460px;
color: var(--text, #fff);
}

.tg-error {
color: var(--pink, #ff4d6d);
}

.tg-fineprint {
font-size: 12px;
}

.tg-actions {
display: flex;
align-items: center;
gap: 12px;
flex-wrap: wrap;
justify-content: center;
}

.tg-qr {
display: inline-flex;
padding: 14px;
background: #fff;
border-radius: 16px;
}

.tg-qr img {
display: block;
border-radius: 4px;
}

.tg-connected {
display: flex;
align-items: center;
justify-content: space-between;
gap: 16px;
flex-wrap: wrap;
padding: 6px 0;
}

.tg-badge {
display: flex;
flex-direction: column;
gap: 2px;
padding: 12px 16px;
border-radius: 12px;
background: rgba(52, 199, 89, 0.12);
border: 1px solid rgba(52, 199, 89, 0.28);
}

.tg-badge strong {
color: #34c759;
}

.tg-badge span {
color: var(--muted);
font-size: 13px;
}

.danger-button {
background: rgba(255, 77, 109, 0.14);
border: 1px solid rgba(255, 77, 109, 0.4);
color: var(--pink, #ff4d6d);
border-radius: 999px;
padding: 10px 18px;
cursor: pointer;
}

.toast {
position: fixed;
left: 50%;
Expand Down Expand Up @@ -6999,12 +7079,13 @@ button,

.source-panel {
position: relative;
margin-top: 10px;
z-index: 1;
width: min(1440px, 100%);
height: min(88dvh, 940px);
max-height: calc(100dvh - clamp(24px, 4.4vh, 48px));
display: grid;
grid-template-rows: auto auto auto minmax(0, 1fr);
display: flex;
flex-direction: column;
gap: 16px;
border: 1px solid rgba(255, 255, 255, 0.16);
border-radius: 22px;
Expand Down Expand Up @@ -7116,6 +7197,10 @@ button,
overflow-x: auto;
padding-bottom: 2px;
scrollbar-width: none;
height: 50px;
/* overflow-x:auto lets this collapse to 0 min-height, so in the flex column
the tall source list's shrink pressure would crush it. Pin its size. */
flex: 0 0 50px;
}

.source-addon-tabs::-webkit-scrollbar {
Expand All @@ -7127,6 +7212,7 @@ button,
}

.source-picker-list {
flex: 1 1 auto;
min-height: 0;
overflow: auto;
display: grid;
Expand Down Expand Up @@ -10086,6 +10172,7 @@ button,
collapsing/clamping rows regardless of their content height. */
.source-picker-list {
display: block !important;
margin-top: 40px;
}

.source-picker-row {
Expand Down
17 changes: 7 additions & 10 deletions web/components/details/DetailsDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -421,16 +421,19 @@ function SourcePickerModal({
}, [visible, item?.id, selectedEpisode?.season, selectedEpisode?.episode]);

const addons = useMemo(() => {
// Only surface addons that actually returned sources for this title. Seeding a
// chip for every installed stream-capable addon meant subtitle providers
// (OpenSubtitles, Ktuvit, Wizdom) — whose manifests also declare a "stream"
// resource — showed up as empty source filters. A name lookup from the
// installed list keeps the pretty addon names.
const nameById = new Map(installedAddons.map((addon) => [addon.id, addon.name]));
const unique = new Map<string, { id: string; name: string; count: number }>();
installedAddons
.filter((addon) => addon.enabled !== false && addonHasResource(addon, "stream"))
.forEach((addon) => unique.set(addon.id, { id: addon.id, name: addon.name, count: 0 }));
streams.forEach((stream) => {
const id = stream.addonId || stream.addonName;
const existing = unique.get(id);
unique.set(id, {
id,
name: existing?.name || stream.addonName,
name: existing?.name || nameById.get(id) || stream.addonName,
count: (existing?.count ?? 0) + 1
});
});
Expand Down Expand Up @@ -791,12 +794,6 @@ function streamBadges(stream: StreamSource) {
}).slice(0, 7);
}

function addonHasResource(addon: InstalledAddon, resource: string) {
const resources = addon.resources ?? [];
if (!resources.length) return true;
return resources.some((item) => typeof item === "string" ? item === resource : item.name === resource);
}

function detectSourceBadge(text: string) {
if (text.includes("2160") || text.includes("4k")) return "4K";
if (text.includes("1080")) return "1080p";
Expand Down
Loading
Loading