LibreSpark/LibreTV

一分钟搭建影视站,支持Docker等部署方式

TypeScript★ 18,227+978 that day#4 on trending

Analyzed October 16, 2026 at a24ad33 (main) with jscpd v5 in 1.0s.

B75.9/100
Project health21,420 lines of code (M)
Duplication91
0.9% in typescript, tsx, bash, perl, javascript
Dead code96
0.2%
Complexity50
52.1%

The score is jscpd's own --health model: markup, data and text left out, tests kept. The numbers below are the trending scan's.

0.93%duplicated code · 163 of 17,617 lines
16clones in code
105code files of 141 scanned
1.02%duplicated over all files · 24 clones

The code number leaves out tests, fixtures, docs, examples, data files, styles, translations and vendored code.

Largest clones in the code

  • 15 lines in 3 placestypescript78 tokens
    85export function stripLeadAdGroup(m3u8Content: string): string {
    86  if (!m3u8Content) return '';
    87  const lines = m3u8Content.split('\n');
    88  const isDisc = (l: string) => l.trim() === '#EXT-X-DISCONTINUITY';
    89  const isSegment = (l: string) => {
    90    const t = l.trim();
    91    return t !== '' && !t.startsWith('#');
    92  };
    93
    94  // 多分组封装(采集站把流按固定块切分、每个衔接处都打 DISCONTINUITY)不是广告。
    
    169function stripMarkedAdGroups(m3u8Content: string): string {
    170  if (!m3u8Content) return '';
    171  const lines = m3u8Content.split('\n');
    172  const isDisc = (l: string) => l.trim() === '#EXT-X-DISCONTINUITY';
    173  const isSegment = (l: string) => {
    174    const t = l.trim();
    175    return t !== '' && !t.startsWith('#');
    176  };
    177
    178  const drop = new Array<boolean>(lines.length).fill(false);
    

    First 10 of 15 lines, the second copy on the right.

  • 19 lines in 2 placestsx110 tokens
    120      {name}
    121    </ChipButton>
    122  ))}
    123</div>
    124
    125{query.isError ? (
    126  <p className="text-center text-sm text-faint py-8">推荐内容加载失败,可稍后重试或在设置中关闭</p>
    127) : query.isLoading ? (
    128  <GridSkeleton />
    129) : (
    

    First 10 of 19 lines.

  • 10 lines in 2 placestypescript107 tokens
    231for (let i = 1; i <= total; i++) {
    232  if (signal.aborted) return;
    233  await pause.waitIfPaused();
    234  const resp = await cache.match(new Request(chunkKey(i)));
    235  if (!resp) throw new Error(`分片 ${i} 缓存丢失,请重试`);
    236  let data = await resp.arrayBuffer();
    237  if (aesKey && parsed.aesConf) {
    238    data = await decryptSegment(data, aesKey, parsed.aesConf.iv, parsed.mediaSequence, i - 1);
    239  }
    240  await transmuxer.pushAndTransmux(new Uint8Array(data));
    
    244for (let i = 1; i <= total; i++) {
    245  if (signal.aborted) return;
    246  await pause.waitIfPaused();
    247  const resp = await cache.match(new Request(chunkKey(i)));
    248  if (!resp) throw new Error(`分片 ${i} 缓存丢失,请重试`);
    249  let data = await resp.arrayBuffer();
    250  if (aesKey && parsed.aesConf) {
    251    data = await decryptSegment(data, aesKey, parsed.aesConf.iv, parsed.mediaSequence, i - 1);
    252  }
    253  await target.write(new Uint8Array(data));
    
7 more
Largest clones over all files, tests and data included
  • 15 lines in 3 placestypescript78 tokens
    85export function stripLeadAdGroup(m3u8Content: string): string {
    86  if (!m3u8Content) return '';
    87  const lines = m3u8Content.split('\n');
    88  const isDisc = (l: string) => l.trim() === '#EXT-X-DISCONTINUITY';
    89  const isSegment = (l: string) => {
    90    const t = l.trim();
    91    return t !== '' && !t.startsWith('#');
    92  };
    93
    94  // 多分组封装(采集站把流按固定块切分、每个衔接处都打 DISCONTINUITY)不是广告。
    
    169function stripMarkedAdGroups(m3u8Content: string): string {
    170  if (!m3u8Content) return '';
    171  const lines = m3u8Content.split('\n');
    172  const isDisc = (l: string) => l.trim() === '#EXT-X-DISCONTINUITY';
    173  const isSegment = (l: string) => {
    174    const t = l.trim();
    175    return t !== '' && !t.startsWith('#');
    176  };
    177
    178  const drop = new Array<boolean>(lines.length).fill(false);
    

    First 10 of 15 lines, the second copy on the right.

  • 19 lines in 2 placestsx110 tokens
    120      {name}
    121    </ChipButton>
    122  ))}
    123</div>
    124
    125{query.isError ? (
    126  <p className="text-center text-sm text-faint py-8">推荐内容加载失败,可稍后重试或在设置中关闭</p>
    127) : query.isLoading ? (
    128  <GridSkeleton />
    129) : (
    

    First 10 of 19 lines.

  • 10 lines in 2 placestypescript107 tokens
    231for (let i = 1; i <= total; i++) {
    232  if (signal.aborted) return;
    233  await pause.waitIfPaused();
    234  const resp = await cache.match(new Request(chunkKey(i)));
    235  if (!resp) throw new Error(`分片 ${i} 缓存丢失,请重试`);
    236  let data = await resp.arrayBuffer();
    237  if (aesKey && parsed.aesConf) {
    238    data = await decryptSegment(data, aesKey, parsed.aesConf.iv, parsed.mediaSequence, i - 1);
    239  }
    240  await transmuxer.pushAndTransmux(new Uint8Array(data));
    
    244for (let i = 1; i <= total; i++) {
    245  if (signal.aborted) return;
    246  await pause.waitIfPaused();
    247  const resp = await cache.match(new Request(chunkKey(i)));
    248  if (!resp) throw new Error(`分片 ${i} 缓存丢失,请重试`);
    249  let data = await resp.arrayBuffer();
    250  if (aesKey && parsed.aesConf) {
    251    data = await decryptSegment(data, aesKey, parsed.aesConf.iv, parsed.mediaSequence, i - 1);
    252  }
    253  await target.write(new Uint8Array(data));
    
  • 6 lines in 2 placescssstyles103 tokens
  • 6 lines in 3 placestypescript51 tokens
By format, code only
FormatFilesLinesClonesDuplicated linesDuplication
tsx338,4108901.07%
typescript618,3198730.88%
bash9694000%
perl1168000%
javascript126000%
By format, all files
FormatFilesLinesClonesDuplicated linesDuplication
typescript8912,122121030.85%
tsx338,4108901.07%
yaml33453288.12%
css1156163.85%
bash10710000%
markdown1246000%
perl1168000%
json262000%
javascript126000%

Trending appearances

DayRankStarsFilesLinesClonesAll filesCodeHealthCommit
Oct 16, 2026#418,227 (+978)14122,245241.02%0.93%B 75.9a24ad33

Want this for your own project? Install jscpd and run jscpd ., or measure it the way the baselines were measured.