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 |
| Movies | YTS, The Pirate Bay, 1337x |
| TV | EZTV, SolidTorrents, The Pirate Bay, 1337x |
| TV | EZTV, The Pirate Bay, 1337x |
| 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.
-2
View File
@@ -2,7 +2,6 @@ import { eztv } from "./eztv";
import { fitgirl } from "./fitgirl";
import { nyaa } from "./nyaa";
import { subsplease } from "./subsplease";
import { solid } from "./solidtorrents";
import { tpbMovies, tpbTv } from "./piratebay";
import { x1337Movies, x1337Tv } from "./x1337";
import { yts } from "./yts";
@@ -14,7 +13,6 @@ export const SOURCES: readonly Source[] = [
tpbMovies,
x1337Movies,
eztv,
solid,
tpbTv,
x1337Tv,
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"
| "nyaa"
| "subsplease"
| "solid"
| "tpb-movies"
| "tpb-tv"
| "x1337-movies"
+3 -3
View File
@@ -4,7 +4,7 @@ import { useStore, useQueueItems, useQueueHistory, type DownloadFocus } from "..
import { Panel } from "./Panel";
import { ProgressBar } from "./ProgressBar";
import { wrapStep, windowStart } from "../move";
import { COLOR, GUTTER, ICON, SOURCE_STYLE } from "../theme";
import { COLOR, GUTTER, ICON, sourceStyle } from "../theme";
import {
cleanText,
formatBytes,
@@ -146,7 +146,7 @@ export function Downloads() {
{activeVisible.map((it, i) => {
const here = activeStart + i === clamped && focused && inActive;
const sc = statusColor(it.status);
const ss = SOURCE_STYLE[it.source ?? "fitgirl"];
const ss = sourceStyle(it.source);
return (
<Box key={it.id} flexDirection="column">
<Box>
@@ -201,7 +201,7 @@ export function Downloads() {
{recentVisible.map((h: HistoryItem, i) => {
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);
return (
<Box key={h.id}>
+3 -3
View File
@@ -9,7 +9,7 @@ import { useConcurrentSearch } from "../hooks/useConcurrentSearch";
import { getSource, SOURCES } from "../../sources/registry";
import { wrapStep, windowStart, resultsPanelOuter } from "../move";
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 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 }) {
const ss = SOURCE_STYLE[r.source];
const ss = sourceStyle(r.source);
const date = formatRelative(r.added);
const health =
r.seeders || r.leechers ? (
@@ -363,7 +363,7 @@ export function Results() {
{visible.map((r, i) => {
const index = start + i;
const here = index === clamped && focused && mode === "list";
const ss = SOURCE_STYLE[r.source];
const ss = sourceStyle(r.source);
return (
<Box key={r.infoHash}>
<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 { Panel } from "./Panel";
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 type { SeedItem } from "../../download/types";
@@ -134,7 +134,7 @@ export function Seeding() {
const seed = seeds.get(h.id);
const g = glyph(seed);
const st = statusCell(seed);
const ss = SOURCE_STYLE[h.source ?? "fitgirl"];
const ss = sourceStyle(h.source);
return (
<Box key={h.id}>
<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 },
nyaa: { tag: "NYAA", color: COLOR.bright },
subsplease: { tag: "SUB", color: "#b9a7e6" },
solid: { tag: "SLD", color: "#60a5fa" },
"tpb-movies": { tag: "TPB", color: "#5fd0c5" },
"tpb-tv": { tag: "TPB", color: "#5fd0c5" },
"x1337-movies": { 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] {
const n = parseInt(hex.slice(1), 16);
return [(n >> 16) & 255, (n >> 8) & 255, n & 255];