fix: drop SolidTorrents so games stop showing under TV (#33)

This commit is contained in:
bairon.dev
2026-07-02 01:01:51 -04:00
parent bf2daceb49
commit dbe543b433
8 changed files with 17 additions and 73 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ A short, hand-picked list of trusted sources:
| --- | --- | | --- | --- |
| Games | FitGirl | | Games | FitGirl |
| Movies | YTS, The Pirate Bay, 1337x | | Movies | YTS, The Pirate Bay, 1337x |
| TV | EZTV, SolidTorrents, The Pirate Bay, 1337x | | TV | EZTV, The Pirate Bay, 1337x |
| Anime | Nyaa, SubsPlease | | Anime | Nyaa, SubsPlease |
Games are the only category that can run code, so they come from FitGirl alone, a repacker with a long, trusted track record; everything else is plain video and subtitles. If a source is down, the search carries on without it, and torlink tells you which one is offline. Games are the only category that can run code, so they come from FitGirl alone, a repacker with a long, trusted track record; everything else is plain video and subtitles. If a source is down, the search carries on without it, and torlink tells you which one is offline.
-2
View File
@@ -2,7 +2,6 @@ import { eztv } from "./eztv";
import { fitgirl } from "./fitgirl"; import { fitgirl } from "./fitgirl";
import { nyaa } from "./nyaa"; import { nyaa } from "./nyaa";
import { subsplease } from "./subsplease"; import { subsplease } from "./subsplease";
import { solid } from "./solidtorrents";
import { tpbMovies, tpbTv } from "./piratebay"; import { tpbMovies, tpbTv } from "./piratebay";
import { x1337Movies, x1337Tv } from "./x1337"; import { x1337Movies, x1337Tv } from "./x1337";
import { yts } from "./yts"; import { yts } from "./yts";
@@ -14,7 +13,6 @@ export const SOURCES: readonly Source[] = [
tpbMovies, tpbMovies,
x1337Movies, x1337Movies,
eztv, eztv,
solid,
tpbTv, tpbTv,
x1337Tv, x1337Tv,
nyaa, nyaa,
-60
View File
@@ -1,60 +0,0 @@
import { fetchResilient, HttpError, USER_AGENT } from "../util/net";
import { buildMagnet } from "./magnet";
import type { SearchOptions, Source, TorrentResult } from "./types";
interface SolidResult {
infohash?: string;
title?: string;
size?: number;
seeders?: number;
leechers?: number;
updatedAt?: string;
}
interface SolidResponse {
success?: boolean;
results?: SolidResult[];
}
async function search(query: string, opts: SearchOptions = {}): Promise<TorrentResult[]> {
const q = query.trim() || "tv show";
const params = new URLSearchParams({ q });
const url = `https://solidtorrents.net/api/v1/search?${params.toString()}`;
const res = await fetchResilient(url, {
headers: { "User-Agent": USER_AGENT },
signal: opts.signal,
retries: 1,
});
if (!res.ok) throw new HttpError(res.status, `SolidTorrents returned ${res.status}`);
const json = (await res.json()) as SolidResponse;
const out: TorrentResult[] = [];
for (const item of json.results ?? []) {
if (!item.infohash) continue;
const infoHash = item.infohash.toLowerCase();
const name = item.title || "Unknown";
const added = item.updatedAt ? Math.floor(new Date(item.updatedAt).getTime() / 1000) : undefined;
out.push({
infoHash,
name,
sizeBytes: item.size ?? 0,
seeders: item.seeders ?? 0,
leechers: item.leechers ?? 0,
source: "solid",
magnet: buildMagnet(infoHash, name),
added,
});
}
return out;
}
export const solid: Source = {
id: "solid",
label: "Solid",
group: "TV",
homepage: "https://solidtorrents.net",
search,
};
-1
View File
@@ -4,7 +4,6 @@ export type SourceId =
| "eztv" | "eztv"
| "nyaa" | "nyaa"
| "subsplease" | "subsplease"
| "solid"
| "tpb-movies" | "tpb-movies"
| "tpb-tv" | "tpb-tv"
| "x1337-movies" | "x1337-movies"
+3 -3
View File
@@ -4,7 +4,7 @@ import { useStore, useQueueItems, useQueueHistory, type DownloadFocus } from "..
import { Panel } from "./Panel"; import { Panel } from "./Panel";
import { ProgressBar } from "./ProgressBar"; import { ProgressBar } from "./ProgressBar";
import { wrapStep, windowStart } from "../move"; import { wrapStep, windowStart } from "../move";
import { COLOR, GUTTER, ICON, SOURCE_STYLE } from "../theme"; import { COLOR, GUTTER, ICON, sourceStyle } from "../theme";
import { import {
cleanText, cleanText,
formatBytes, formatBytes,
@@ -146,7 +146,7 @@ export function Downloads() {
{activeVisible.map((it, i) => { {activeVisible.map((it, i) => {
const here = activeStart + i === clamped && focused && inActive; const here = activeStart + i === clamped && focused && inActive;
const sc = statusColor(it.status); const sc = statusColor(it.status);
const ss = SOURCE_STYLE[it.source ?? "fitgirl"]; const ss = sourceStyle(it.source);
return ( return (
<Box key={it.id} flexDirection="column"> <Box key={it.id} flexDirection="column">
<Box> <Box>
@@ -201,7 +201,7 @@ export function Downloads() {
{recentVisible.map((h: HistoryItem, i) => { {recentVisible.map((h: HistoryItem, i) => {
const here = recentStart + i === recentCursor && focused && !inActive; const here = recentStart + i === recentCursor && focused && !inActive;
const ss = SOURCE_STYLE[h.source ?? "fitgirl"]; const ss = sourceStyle(h.source);
const when = formatRelative(h.completedAt / 1000); const when = formatRelative(h.completedAt / 1000);
return ( return (
<Box key={h.id}> <Box key={h.id}>
+3 -3
View File
@@ -9,7 +9,7 @@ import { useConcurrentSearch } from "../hooks/useConcurrentSearch";
import { getSource, SOURCES } from "../../sources/registry"; import { getSource, SOURCES } from "../../sources/registry";
import { wrapStep, windowStart, resultsPanelOuter } from "../move"; import { wrapStep, windowStart, resultsPanelOuter } from "../move";
import { sortResults, nextSort, sortLabel, sortArrow, type Sort, type SortField } from "../sort"; import { sortResults, nextSort, sortLabel, sortArrow, type Sort, type SortField } from "../sort";
import { COLOR, GUTTER, ICON, SOURCE_STYLE } from "../theme"; import { COLOR, GUTTER, ICON, sourceStyle } from "../theme";
import { cleanText, formatBytes, formatRelative, truncate } from "../../util/format"; import { cleanText, formatBytes, formatRelative, truncate } from "../../util/format";
import type { Source, TorrentResult } from "../../sources/types"; import type { Source, TorrentResult } from "../../sources/types";
@@ -29,7 +29,7 @@ function DetailRow({ label, value }: { label: string; value: ReactNode }) {
} }
function Detail({ r, width }: { r: TorrentResult; width: number }) { function Detail({ r, width }: { r: TorrentResult; width: number }) {
const ss = SOURCE_STYLE[r.source]; const ss = sourceStyle(r.source);
const date = formatRelative(r.added); const date = formatRelative(r.added);
const health = const health =
r.seeders || r.leechers ? ( r.seeders || r.leechers ? (
@@ -363,7 +363,7 @@ export function Results() {
{visible.map((r, i) => { {visible.map((r, i) => {
const index = start + i; const index = start + i;
const here = index === clamped && focused && mode === "list"; const here = index === clamped && focused && mode === "list";
const ss = SOURCE_STYLE[r.source]; const ss = sourceStyle(r.source);
return ( return (
<Box key={r.infoHash}> <Box key={r.infoHash}>
<Box width={GUTTER} flexShrink={0}> <Box width={GUTTER} flexShrink={0}>
+2 -2
View File
@@ -3,7 +3,7 @@ import { Box, Text, useInput } from "ink";
import { useStore, useQueueHistory, useSeeds, type SeedFocus } from "../store"; import { useStore, useQueueHistory, useSeeds, type SeedFocus } from "../store";
import { Panel } from "./Panel"; import { Panel } from "./Panel";
import { wrapStep, windowStart } from "../move"; import { wrapStep, windowStart } from "../move";
import { COLOR, GUTTER, ICON, SOURCE_STYLE } from "../theme"; import { COLOR, GUTTER, ICON, sourceStyle } from "../theme";
import { cleanText, formatBytes, formatBytesPerSec, truncate } from "../../util/format"; import { cleanText, formatBytes, formatBytesPerSec, truncate } from "../../util/format";
import type { SeedItem } from "../../download/types"; import type { SeedItem } from "../../download/types";
@@ -134,7 +134,7 @@ export function Seeding() {
const seed = seeds.get(h.id); const seed = seeds.get(h.id);
const g = glyph(seed); const g = glyph(seed);
const st = statusCell(seed); const st = statusCell(seed);
const ss = SOURCE_STYLE[h.source ?? "fitgirl"]; const ss = sourceStyle(h.source);
return ( return (
<Box key={h.id}> <Box key={h.id}>
<Box width={MARK} flexShrink={0}> <Box width={MARK} flexShrink={0}>
+8 -1
View File
@@ -34,13 +34,20 @@ export const SOURCE_STYLE: Record<SourceId, { tag: string; color: string }> = {
eztv: { tag: "EZTV", color: COLOR.warn }, eztv: { tag: "EZTV", color: COLOR.warn },
nyaa: { tag: "NYAA", color: COLOR.bright }, nyaa: { tag: "NYAA", color: COLOR.bright },
subsplease: { tag: "SUB", color: "#b9a7e6" }, subsplease: { tag: "SUB", color: "#b9a7e6" },
solid: { tag: "SLD", color: "#60a5fa" },
"tpb-movies": { tag: "TPB", color: "#5fd0c5" }, "tpb-movies": { tag: "TPB", color: "#5fd0c5" },
"tpb-tv": { tag: "TPB", color: "#5fd0c5" }, "tpb-tv": { tag: "TPB", color: "#5fd0c5" },
"x1337-movies": { tag: "1337", color: "#f6a55c" }, "x1337-movies": { tag: "1337", color: "#f6a55c" },
"x1337-tv": { tag: "1337", color: "#f6a55c" }, "x1337-tv": { tag: "1337", color: "#f6a55c" },
}; };
// Tolerant lookup: a source id may be absent (a pasted magnet / bare infohash) or
// no longer exist (a removed source persisted in old history/seeds). Fall back to a
// neutral tag rather than indexing SOURCE_STYLE and crashing on `undefined`.
export function sourceStyle(id?: SourceId): { tag: string; color: string } {
const s = id ? (SOURCE_STYLE as Record<string, { tag: string; color: string }>)[id] : undefined;
return s ?? { tag: "•", color: COLOR.alt };
}
function rgb(hex: string): [number, number, number] { function rgb(hex: string): [number, number, number] {
const n = parseInt(hex.slice(1), 16); const n = parseInt(hex.slice(1), 16);
return [(n >> 16) & 255, (n >> 8) & 255, n & 255]; return [(n >> 16) & 255, (n >> 8) & 255, n & 255];