nixamp 0.23.3 → 0.23.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -61,8 +61,10 @@ export declare function preferPlus(source: string): string;
61
61
  export declare function entryId(source: string): string;
62
62
  /**
63
63
  * Parse an extended m3u: `#EXTINF:-1 tvg-name="CNN" group-title="News",CNN HD`
64
- * decorates the URL on the next line, and `#EXTGRP:News` names the group for
65
- * lists that write it that way instead.
64
+ * decorates the URL on the next line, `#EXTGRP:News` names the group for
65
+ * lists that write it that way instead, and `#EXTIMG:https://...` is the
66
+ * picture for lists (a podcast's episodes, say) that carry one that way
67
+ * rather than as a tvg-logo attribute.
66
68
  */
67
69
  export declare function parseCatalog(text: string, base: string): CatalogEntry[];
68
70
  export interface Group {
package/dist/catalogs.js CHANGED
Binary file
package/dist/links.d.ts CHANGED
@@ -68,6 +68,7 @@ export declare const PLAYLIST_FETCH_TIMEOUT_MS = 15000;
68
68
  export declare function playlistFrom(text: string, base: string): {
69
69
  hls: boolean;
70
70
  sources: string[];
71
+ image: string;
71
72
  };
72
73
  /**
73
74
  * A pasted .m3u, read and turned into a channel's worth of entries. Fetched
package/dist/links.js CHANGED
@@ -97,12 +97,14 @@ export const PLAYLIST_FETCH_TIMEOUT_MS = 15_000;
97
97
  */
98
98
  export function playlistFrom(text, base) {
99
99
  if (/^#EXT-X-/m.test(text))
100
- return { hls: true, sources: [] };
101
- const sources = parseCatalog(text, base)
102
- .map((entry) => entry.source)
103
- .filter((source) => /^(https?|rtmps?):\/\//i.test(source))
100
+ return { hls: true, sources: [], image: "" };
101
+ const entries = parseCatalog(text, base)
102
+ .filter((entry) => /^(https?|rtmps?):\/\//i.test(entry.source))
104
103
  .slice(0, PLAYLIST_MAX_ENTRIES);
105
- return { hls: false, sources };
104
+ // The picture of the list is the first picture in it: a podcast's episodes
105
+ // all wear the show's art, and the newest is first.
106
+ const image = entries.map((entry) => pictureUrl(entry.logo)).find((one) => one !== "") ?? "";
107
+ return { hls: false, sources: entries.map((entry) => entry.source), image };
106
108
  }
107
109
  /**
108
110
  * A pasted .m3u, read and turned into a channel's worth of entries. Fetched
@@ -147,7 +149,7 @@ export async function resolvePlaylist(url, options = {}) {
147
149
  extractor: "playlist",
148
150
  ext: "",
149
151
  page: url,
150
- thumbnail: "",
152
+ thumbnail: list.image,
151
153
  about: "",
152
154
  playlist: list.sources,
153
155
  };
package/dist/server.js CHANGED
@@ -3117,6 +3117,18 @@ export function createHandler(engine, options) {
3117
3117
  return;
3118
3118
  }
3119
3119
  links.set(link, resolved);
3120
+ // A channel already on -- put back by a restart, which forgets where
3121
+ // it came from -- learns its picture and its line from the link pasted
3122
+ // again, rather than waiting to be taken off and put on.
3123
+ const already = options.channels.info(channelId);
3124
+ if (already) {
3125
+ if (!already.art && resolved.thumbnail)
3126
+ already.art = resolved.thumbnail;
3127
+ if (!already.about && resolved.about)
3128
+ already.about = resolved.about;
3129
+ if (already.art || already.about)
3130
+ options.rememberChannels?.(rememberedNow(options.channels));
3131
+ }
3120
3132
  if (!options.channels.has(channelId)) {
3121
3133
  // Asked of the site first, once, with the headers yt-dlp said to
3122
3134
  // send. A media address that answers nothing is a site refusing
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nixamp",
3
- "version": "0.23.3",
3
+ "version": "0.23.4",
4
4
  "description": "It really whips the terminal's ass. A Winamp-shaped audio player for your terminal.",
5
5
  "license": "MIT",
6
6
  "type": "module",
package/src/catalogs.ts CHANGED
Binary file
package/src/links.ts CHANGED
@@ -145,13 +145,15 @@ export const PLAYLIST_FETCH_TIMEOUT_MS = 15_000;
145
145
  * all -- a segment list with #EXT-X- tags -- and those are one stream for
146
146
  * ffmpeg to read as it is, not a list of streams.
147
147
  */
148
- export function playlistFrom(text: string, base: string): { hls: boolean; sources: string[] } {
149
- if (/^#EXT-X-/m.test(text)) return { hls: true, sources: [] };
150
- const sources = parseCatalog(text, base)
151
- .map((entry) => entry.source)
152
- .filter((source) => /^(https?|rtmps?):\/\//i.test(source))
148
+ export function playlistFrom(text: string, base: string): { hls: boolean; sources: string[]; image: string } {
149
+ if (/^#EXT-X-/m.test(text)) return { hls: true, sources: [], image: "" };
150
+ const entries = parseCatalog(text, base)
151
+ .filter((entry) => /^(https?|rtmps?):\/\//i.test(entry.source))
153
152
  .slice(0, PLAYLIST_MAX_ENTRIES);
154
- return { hls: false, sources };
153
+ // The picture of the list is the first picture in it: a podcast's episodes
154
+ // all wear the show's art, and the newest is first.
155
+ const image = entries.map((entry) => pictureUrl(entry.logo)).find((one) => one !== "") ?? "";
156
+ return { hls: false, sources: entries.map((entry) => entry.source), image };
155
157
  }
156
158
 
157
159
  /**
@@ -195,7 +197,7 @@ export async function resolvePlaylist(
195
197
  extractor: "playlist",
196
198
  ext: "",
197
199
  page: url,
198
- thumbnail: "",
200
+ thumbnail: list.image,
199
201
  about: "",
200
202
  playlist: list.sources,
201
203
  };
package/src/server.ts CHANGED
@@ -3666,6 +3666,15 @@ export function createHandler(engine: Engine, options: HandlerOptions) {
3666
3666
  return;
3667
3667
  }
3668
3668
  links.set(link, resolved);
3669
+ // A channel already on -- put back by a restart, which forgets where
3670
+ // it came from -- learns its picture and its line from the link pasted
3671
+ // again, rather than waiting to be taken off and put on.
3672
+ const already = options.channels.info(channelId);
3673
+ if (already) {
3674
+ if (!already.art && resolved.thumbnail) already.art = resolved.thumbnail;
3675
+ if (!already.about && resolved.about) already.about = resolved.about;
3676
+ if (already.art || already.about) options.rememberChannels?.(rememberedNow(options.channels));
3677
+ }
3669
3678
  if (!options.channels.has(channelId)) {
3670
3679
  // Asked of the site first, once, with the headers yt-dlp said to
3671
3680
  // send. A media address that answers nothing is a site refusing
package/web/dist/sw.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* nixamp service worker — generated, do not edit */
2
- const CACHE = "nixamp-1789274173964";
2
+ const CACHE = "nixamp-1789274541569";
3
3
  const PRECACHE = [
4
4
  "/",
5
5
  "/.well-known/openaccess.json",