@lzwme/m3u8-dl 1.1.0 → 1.1.2

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.
@@ -17,10 +17,10 @@ async function m3u8Convert(options, data) {
17
17
  (0, fe_utils_1.mkdirp)((0, node_path_1.dirname)(filepath));
18
18
  if (ffmpegSupport) {
19
19
  const ffconcatFile = (0, node_path_1.resolve)((0, node_path_1.dirname)(data[0].tsOut), 'ffconcat.txt');
20
- let filesAllArr = data.map(d => (0, node_path_1.resolve)(d.tsOut)).filter(d => (0, node_fs_1.existsSync)(d));
20
+ let filesAllArr = data.filter(d => (0, node_fs_1.existsSync)(d.tsOut)).map(d => `file '${d.tsOut}'\nduration ${d.duration}`);
21
21
  if (process.platform === 'win32')
22
22
  filesAllArr = filesAllArr.map(d => d.replaceAll('\\', '/'));
23
- (0, node_fs_1.writeFileSync)(ffconcatFile, 'ffconcat version 1.0\nfile ' + filesAllArr.join('\nfile '));
23
+ (0, node_fs_1.writeFileSync)(ffconcatFile, 'ffconcat version 1.0\n' + filesAllArr.join('\n'));
24
24
  let headersString = '';
25
25
  if (options.headers) {
26
26
  for (const [key, value] of Object.entries(options.headers)) {
@@ -28,13 +28,15 @@ async function m3u8Convert(options, data) {
28
28
  }
29
29
  }
30
30
  // ffmpeg -i nz.ts -c copy -map 0:v -map 0:a -bsf:a aac_adtstoasc nz.mp4
31
- const cmd = `ffmpeg -y -f concat -safe 0 -i "${ffconcatFile}" -acodec copy -vcodec copy -bsf:a aac_adtstoasc ${headersString} "${filepath}"`;
31
+ // const cmd = `ffmpeg -async 1 -y -f concat -safe 0 -i "${ffconcatFile}" -acodec copy -vcodec copy -bsf:a aac_adtstoasc ${headersString} "${filepath}"`;
32
+ const cmd = `ffmpeg -async 1 -y -f concat -safe 0 -i "${ffconcatFile}" -c:v copy -c:a copy -movflags +faststart -fflags +genpts -bsf:a aac_adtstoasc ${headersString} "${filepath}"`;
32
33
  utils_1.logger.debug('[convert to mp4]cmd:', (0, console_log_colors_1.cyan)(cmd));
33
34
  const r = (0, fe_utils_1.execSync)(cmd);
34
35
  ffmpegSupport = !r.error;
35
36
  if (r.error)
36
37
  utils_1.logger.error('Conversion to mp4 failed. Please confirm that `ffmpeg` is installed!', r.stderr);
37
- (0, node_fs_1.unlinkSync)(ffconcatFile);
38
+ else
39
+ (0, node_fs_1.unlinkSync)(ffconcatFile);
38
40
  }
39
41
  if (!ffmpegSupport) {
40
42
  filepath = filepath.replace(/\.mp4$/, '.ts');
@@ -185,6 +185,7 @@ async function m3u8Download(url, options = {}) {
185
185
  remainingTime: 0,
186
186
  localM3u8: (0, local_play_js_1.toLocalM3u8)(m3u8Info.data).replace(options.cacheDir, '').replaceAll(node_path_1.sep, '/').slice(1),
187
187
  filename: options.filename,
188
+ threadNum: options.threadNum,
188
189
  };
189
190
  const runTask = (data) => {
190
191
  for (const info of data) {
@@ -234,6 +235,7 @@ async function m3u8Download(url, options = {}) {
234
235
  if (stats.speed > stats.avgSpeed)
235
236
  stats.remainingTime = stats.remainingTime * (stats.avgSpeed / stats.speed);
236
237
  stats.remainingTime = Math.ceil(stats.remainingTime);
238
+ stats.size = stats.downloadedSize * (stats.duration / stats.durationDownloaded);
237
239
  }
238
240
  if (options.showProgress) {
239
241
  const processBar = '='.repeat(Math.floor(stats.progress * 0.2)).padEnd(20, '-');
@@ -110,11 +110,10 @@ class DLServer {
110
110
  item.status = 'pause';
111
111
  }
112
112
  else {
113
- const isError = item.status === 'done' && item.options?.convert && (!item.localVideo || !(0, node_fs_1.existsSync)(item.localVideo));
113
+ const isError = item.status === 'done' && item.options?.convert !== false && (!item.localVideo || !(0, node_fs_1.existsSync)(item.localVideo));
114
114
  if (isError) {
115
115
  item.status = 'error';
116
116
  item.errmsg = '本地视频文件不存在';
117
- item.localVideo = '';
118
117
  }
119
118
  }
120
119
  this.dlCache.set(url, item);
@@ -83,6 +83,8 @@ export interface M3u8DLProgressStats {
83
83
  localVideo?: string;
84
84
  /** 本地保存的文件名 */
85
85
  filename?: string;
86
+ /** 并发下载线程数 */
87
+ threadNum?: number;
86
88
  /** 最新的错误信息 */
87
89
  errmsg?: string;
88
90
  }
package/client/index.html CHANGED
@@ -155,13 +155,11 @@
155
155
  class="text-blue-500 hover:text-blue-600">https://github.com/lzwme/m3u8-dl.git</a>
156
156
  </p>
157
157
  <p class="text-gray-600"><strong>问题反馈:</strong>
158
- <a href="https://github.com/lzwme/m3u8-dl/issues" target="_blank" rel="noopener"
159
- class="text-blue-500 hover:text-blue-600">
158
+ <a href="https://github.com/lzwme/m3u8-dl/issues" target="_blank" rel="noopener" class="text-blue-500 hover:text-blue-600">
160
159
  https://github.com/lzwme/m3u8-dl/issues</a>
161
160
  </p>
162
161
  <p class="text-gray-600"><strong>当前版本:</strong>
163
- <a href="https://github.com/lzwme/m3u8-dl/release" target="_blank" rel="noopener"
164
- class="text-blue-500 hover:text-blue-600">
162
+ <a href="https://github.com/lzwme/m3u8-dl/release" target="_blank" rel="noopener" class="text-blue-500 hover:text-blue-600">
165
163
  {{serverInfo.version}}</a>
166
164
  </p>
167
165
  </div>
@@ -192,8 +190,7 @@
192
190
  <h3 class="text-lg font-medium text-gray-900 mb-2">安装使用</h3>
193
191
  <div class="bg-gray-50 p-4 rounded-lg">
194
192
  <p class="text-gray-600 mb-2">全局安装:</p>
195
- <pre
196
- class="bg-gray-800 text-gray-100 p-3 rounded-lg overflow-x-auto">npm i -g @lzwme/m3u8-dl<br>m3u8dl -h</pre>
193
+ <pre class="bg-gray-800 text-gray-100 p-3 rounded-lg overflow-x-auto">npm i -g @lzwme/m3u8-dl<br>m3u8dl -h</pre>
197
194
  <p class="text-gray-600 mt-4 mb-2">使用 npx:</p>
198
195
  <pre class="bg-gray-800 text-gray-100 p-3 rounded-lg overflow-x-auto">npx @lzwme/m3u8-dl -h</pre>
199
196
  </div>
@@ -259,8 +256,7 @@ services:
259
256
  <label class="block text-sm font-bold text-gray-700 mb-1">下载完成后删除ts分片缓存</label>
260
257
  <div class="flex items-center mt-2">
261
258
  <label class="inline-flex items-center">
262
- <input type="checkbox" v-model="config.delCache"
263
- class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500">
259
+ <input type="checkbox" v-model="config.delCache" class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500">
264
260
  <span class="ml-2 text-gray-700">删除分片文件</span>
265
261
  </label>
266
262
  </div>
@@ -272,8 +268,7 @@ services:
272
268
  <label class="block text-sm font-bold text-gray-700 mb-1">下载完成后转换格式</label>
273
269
  <div class="flex items-center mt-2">
274
270
  <label class="inline-flex items-center">
275
- <input type="checkbox" v-model="config.convert"
276
- class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500">
271
+ <input type="checkbox" v-model="config.convert" class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500">
277
272
  <span class="ml-2 text-gray-700">合并转换为 MP4/TS 文件</span>
278
273
  </label>
279
274
  </div>
@@ -324,8 +319,8 @@ services:
324
319
  <div>
325
320
  <label class="block text-sm font-bold text-gray-700 mb-1">访问密码</label>
326
321
  <div class="flex">
327
- <input v-model="token" type="password" maxlength="256"
328
- class="w-full p-2 border rounded-lg focus:ring-blue-500" placeholder="请输入访问密码" />
322
+ <input v-model="token" type="password" maxlength="256" class="w-full p-2 border rounded-lg focus:ring-blue-500"
323
+ placeholder="请输入访问密码" />
329
324
  </div>
330
325
  <p class="mt-1 text-sm text-gray-500">若服务端设置了访问密码(token),请在此输入</p>
331
326
  </div>
@@ -349,8 +344,7 @@ services:
349
344
  <div class="flex justify-between items-center">
350
345
  <h2 class="text-xl font-semibold">下载任务</h2>
351
346
  <div class="flex space-x-2">
352
- <button @click="showNewDownloadDialog"
353
- class="px-3 py-1 text-sm bg-blue-500 hover:bg-blue-600 text-white rounded">
347
+ <button @click="showNewDownloadDialog" class="px-3 py-1 text-sm bg-blue-500 hover:bg-blue-600 text-white rounded">
354
348
  <i class="fas fa-plus mr-1"></i>新建
355
349
  </button>
356
350
  <button v-if="selectedTasks.length > 0" @click="pauseDownload(selectedTasks)"
@@ -383,23 +377,22 @@ services:
383
377
  <div class="flex-1">
384
378
  <div class="relative">
385
379
  <input type="text" v-model="searchQuery"
386
- class="w-full pl-10 pr-4 py-2 border rounded-lg focus:ring-blue-500 focus:border-blue-500"
387
- placeholder="搜索任务名称或URL" aria-label="搜索任务">
380
+ class="w-full pl-10 pr-4 py-2 border rounded-lg focus:ring-blue-500 focus:border-blue-500" placeholder="搜索任务名称或URL"
381
+ aria-label="搜索任务">
388
382
  <i class="fas fa-search absolute left-3 top-3 text-gray-400"></i>
389
383
  </div>
390
384
  </div>
391
385
  <div class="flex items-center space-x-2">
392
- <select v-model="statusFilter"
393
- class="px-3 py-2 border rounded-lg focus:ring-blue-500 focus:border-blue-500" title="按状态筛选"
386
+ <select v-model="statusFilter" class="px-3 py-2 border rounded-lg focus:ring-blue-500 focus:border-blue-500" title="按状态筛选"
394
387
  aria-label="按状态筛选">
395
388
  <option value="">全部状态</option>
396
389
  <option value="resume">下载中</option>
397
390
  <option value="pending">等待中</option>
398
391
  <option value="pause">已暂停</option>
392
+ <option value="error">异常</option>
399
393
  <option value="done">已完成</option>
400
394
  </select>
401
- <button @click="clearFilters" class="px-3 py-2 text-gray-600 hover:text-gray-800" title="清除筛选条件"
402
- aria-label="清除筛选条件">
395
+ <button @click="clearFilters" class="px-3 py-2 text-gray-600 hover:text-gray-800" title="清除筛选条件" aria-label="清除筛选条件">
403
396
  <i class="fas fa-times"></i>
404
397
  </button>
405
398
  </div>
@@ -431,32 +424,25 @@ services:
431
424
  <div class="flex items-center justify-between mb-2">
432
425
  <div class="flex-1">
433
426
  <div class="flex items-center">
434
- <input type="checkbox" :checked="selectedTasks.includes(task.url)"
435
- @change="toggleTaskSelection(task.url)"
427
+ <input type="checkbox" :checked="selectedTasks.includes(task.url)" @change="toggleTaskSelection(task.url)"
436
428
  class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500 mr-2"
437
429
  :aria-label="'选择任务:' + (task.localVideo || task.filename || task.url)">
438
430
  <h3 class="font-bold text-green-600 truncate" :title="task.url">
439
431
  {{ task.localVideo || task.filename || task.url }}
440
432
  </h3>
441
- <span v-if="task.status === 'pending'"
442
- class="ml-2 px-2 py-0.5 text-xs bg-yellow-100 text-yellow-800 rounded">等待中</span>
433
+ <span v-if="task.status === 'pending'" class="ml-2 px-2 py-0.5 text-xs bg-yellow-100 text-yellow-800 rounded">等待中</span>
443
434
  <span v-else-if="task.status === 'resume'"
444
435
  class="ml-2 px-2 py-0.5 text-xs bg-green-100 text-green-800 rounded">下载中</span>
445
- <span v-else-if="task.status === 'pause'"
446
- class="ml-2 px-2 py-0.5 text-xs bg-gray-100 text-gray-800 rounded">已暂停</span>
447
- <span v-else-if="task.status === 'done'"
448
- class="ml-2 px-2 py-0.5 text-xs bg-blue-100 text-blue-800 rounded">已完成</span>
449
- <span v-else-if="task.status === 'error'"
450
- class="ml-2 px-2 py-0.5 text-xs bg-red-100 text-red-600 rounded" :title="task.errmsg">异常<i
451
- class="fas fa-info-circle ml-1"></i></span>
436
+ <span v-else-if="task.status === 'pause'" class="ml-2 px-2 py-0.5 text-xs bg-gray-100 text-gray-800 rounded">已暂停</span>
437
+ <span v-else-if="task.status === 'done'" class="ml-2 px-2 py-0.5 text-xs bg-blue-100 text-blue-800 rounded">已完成</span>
438
+ <span v-else-if="task.status === 'error'" class="ml-2 px-2 py-0.5 text-xs bg-red-100 text-red-600 rounded"
439
+ :title="task.errmsg">异常<i class="fas fa-info-circle ml-1"></i></span>
452
440
  </div>
453
441
  <div class="flex items-center text-sm text-gray-500 mt-1 flex-wrap gap-2">
454
- <span v-if="config.showPreview" class="text-blue-500 hover:text-blue-600 cursor-pointer"
455
- @click="preview(task.url)">
442
+ <span v-if="config.showPreview" class="text-blue-500 hover:text-blue-600 cursor-pointer" @click="preview(task.url)">
456
443
  <i class="fas fa-eye mr-1"></i>预览
457
444
  </span>
458
- <span v-if="config.showLocalPlay" class="text-green-500 hover:text-green-600 cursor-pointer"
459
- @click="localPlay(task)">
445
+ <span v-if="config.showLocalPlay" class="text-green-500 hover:text-green-600 cursor-pointer" @click="localPlay(task)">
460
446
  <i class="fas fa-play-circle mr-1"></i>{{ task.localVideo ? '播放' : '边下边播' }}
461
447
  </span>
462
448
  <span v-if="task.duration" class="flex items-center">
@@ -491,17 +477,15 @@ services:
491
477
  </div>
492
478
  </div>
493
479
  <div class="flex space-x-2">
494
- <button v-if="task.status === 'resume' || task.status === 'pending'"
495
- @click="pauseDownload([task.url])" class="p-2 text-yellow-500 hover:bg-yellow-50 rounded"
496
- title="暂停">
480
+ <button v-if="task.status === 'resume' || task.status === 'pending'" @click="pauseDownload([task.url])"
481
+ class="p-2 text-yellow-500 hover:bg-yellow-50 rounded" title="暂停">
497
482
  <i class="fas fa-pause"></i>
498
483
  </button>
499
484
  <button v-if="task.status === 'pause' || task.status === 'error'" @click="resumeDownload([task.url])"
500
485
  class="p-2 text-green-500 hover:bg-green-50 rounded" title="继续">
501
486
  <i class="fas fa-play"></i>
502
487
  </button>
503
- <button @click="deleteDownload([task.url])" class="p-2 text-red-500 hover:bg-red-50 rounded"
504
- title="删除">
488
+ <button @click="deleteDownload([task.url])" class="p-2 text-red-500 hover:bg-red-50 rounded" title="删除">
505
489
  <i class="fas fa-trash"></i>
506
490
  </button>
507
491
  </div>
@@ -524,8 +508,7 @@ services:
524
508
  <div v-if="filteredTasks.length === 0" class="p-8 text-center text-gray-500">
525
509
  <i class="fas fa-download text-4xl mb-4"></i>
526
510
  <p>暂无下载任务</p>
527
- <button @click="showNewDownloadDialog"
528
- class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
511
+ <button @click="showNewDownloadDialog" class="mt-4 px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600">
529
512
  <i class="fas fa-plus mr-1"></i>添加下载任务
530
513
  </button>
531
514
  </div>
@@ -720,7 +703,7 @@ services:
720
703
  const ws = new WebSocket(`ws://${location.host}/ws?token=${this.token}`);
721
704
  this.ws = ws;
722
705
  ws.onmessage = (e) => {
723
- const { type, data } = T.safeJSONParse(e.data);
706
+ let { type, data } = T.safeJSONParse(e.data);
724
707
 
725
708
  switch (type) {
726
709
  case 'serverInfo':
@@ -877,7 +860,7 @@ services:
877
860
  if (typeof urls === 'string') urls = [urls];
878
861
  const r = await T.post(`/pause`, { urls, all: urls[0] === 'all' });
879
862
  if (!r.code) T.toast(r.message || '已暂停下载');
880
- this.tasks[url].status = 'pause';
863
+ if (urls === this.selectedTasks) this.selectedTasks = [];
881
864
  },
882
865
  /** 恢复下载 */
883
866
  resumeDownload: async function (urls) {
@@ -885,6 +868,60 @@ services:
885
868
  if (typeof urls === 'string') urls = [urls];
886
869
  const r = await T.post(`/resume`, { urls, all: urls[0] === 'all' });
887
870
  if (!r.code) T.toast(r.message || '已恢复下载');
871
+ if (urls === this.selectedTasks) this.selectedTasks = [];
872
+ },
873
+ /** 删除选中的任务 */
874
+ async deleteDownload(urls = this.selectedTasks) {
875
+ if (!urls.length) return;
876
+ try {
877
+ const result = await Swal.fire({
878
+ title: '确认删除',
879
+ html: `
880
+ <div class="text-left">
881
+ <div class="mb-4">
882
+ <label class="inline-flex items-center">
883
+ <input type="checkbox" id="deleteCache" class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500" checked>
884
+ <span class="ml-2 text-gray-700">同时删除已下载的缓存</span>
885
+ </label>
886
+ </div>
887
+ <div>
888
+ <label class="inline-flex items-center">
889
+ <input type="checkbox" id="deleteVideo" class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500" checked>
890
+ <span class="ml-2 text-red-700">同时删除已下载的视频</span>
891
+ </label>
892
+ </div>
893
+ </div>
894
+ `,
895
+ showCancelButton: true,
896
+ confirmButtonText: '确认删除',
897
+ cancelButtonText: '取消',
898
+ confirmButtonColor: '#ef4444',
899
+ focusConfirm: false,
900
+ preConfirm: () => {
901
+ return {
902
+ deleteCache: document.getElementById('deleteCache').checked,
903
+ deleteVideo: document.getElementById('deleteVideo').checked
904
+ };
905
+ }
906
+ });
907
+
908
+ if (result.isConfirmed) {
909
+ const r = await T.post(`/delete`, {
910
+ urls,
911
+ deleteCache: result.value.deleteCache,
912
+ deleteVideo: result.value.deleteVideo
913
+ });
914
+ if (!r.code) {
915
+ T.toast(r.message || '已删除选中的下载');
916
+ urls.forEach(url => (delete this.tasks[url]));
917
+ if (urls === this.selectedTasks) this.selectedTasks = [];
918
+ this.forceUpdate();
919
+ }
920
+ }
921
+ } catch (error) {
922
+ console.error('删除下载失败:', error);
923
+ T.alert('删除下载失败: ' + error.message);
924
+ }
888
925
  },
889
926
  getTasks: async function () {
890
927
  this.tasks = await T.get('/tasks');
@@ -893,17 +930,17 @@ services:
893
930
  localPlay: function (task) {
894
931
  const url = location.origin + '/localplay/' + encodeURIComponent(task.localVideo || task.localM3u8);
895
932
  console.log(task);
896
- if (task.localVideo) {
897
- Swal.fire({
898
- title: task?.options.filename || task.url,
899
- width: '1000px',
900
- showCloseButton: true,
901
- showConfirmButton: false,
902
- html: `<video autoplay width="100%" style="max-width: 1000px; min-height: 300px; max-height: 90vh" src="${url}" controls></video> `,
903
- });
904
- } else {
905
- window.open(`http://lzw.me/x/m3u8-player/?url=${encodeURIComponent(url)}`);
906
- }
933
+ // return window.open(`./play.html?url=${encodeURIComponent(url)}`);
934
+ Swal.fire({
935
+ title: task?.options.filename || task.url,
936
+ width: '1000px',
937
+ padding: 0,
938
+ allowOutsideClick: false,
939
+ showCloseButton: true,
940
+ showConfirmButton: false,
941
+ html: `<iframe src="./play.html?url=${encodeURIComponent(url)}" style="width: 100%; height: 550px; max-width: 1000px; max-height: 90vh" frameborder="0" allowfullscreen></iframe>`,
942
+ // html: `<video autoplay width="100%" style="max-width: 1000px; min-height: 300px; max-height: 90vh" src="${url}" controls></video> `,
943
+ });
907
944
  },
908
945
  // 预览
909
946
  preview: function (url) {
@@ -969,59 +1006,6 @@ services:
969
1006
  this.selectedTasks.splice(index, 1);
970
1007
  }
971
1008
  },
972
- /** 删除选中的任务 */
973
- async deleteDownload(urls = this.selectedTasks) {
974
- if (!urls.length) return;
975
- try {
976
- const result = await Swal.fire({
977
- title: '确认删除',
978
- html: `
979
- <div class="text-left">
980
- <div class="mb-4">
981
- <label class="inline-flex items-center">
982
- <input type="checkbox" id="deleteCache" class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500" checked>
983
- <span class="ml-2 text-gray-700">同时删除已下载的缓存</span>
984
- </label>
985
- </div>
986
- <div>
987
- <label class="inline-flex items-center">
988
- <input type="checkbox" id="deleteVideo" class="form-checkbox h-5 w-5 text-blue-500 rounded focus:ring-blue-500" checked>
989
- <span class="ml-2 text-red-700">同时删除已下载的视频</span>
990
- </label>
991
- </div>
992
- </div>
993
- `,
994
- showCancelButton: true,
995
- confirmButtonText: '确认删除',
996
- cancelButtonText: '取消',
997
- confirmButtonColor: '#ef4444',
998
- focusConfirm: false,
999
- preConfirm: () => {
1000
- return {
1001
- deleteCache: document.getElementById('deleteCache').checked,
1002
- deleteVideo: document.getElementById('deleteVideo').checked
1003
- };
1004
- }
1005
- });
1006
-
1007
- if (result.isConfirmed) {
1008
- const r = await T.post(`/delete`, {
1009
- urls,
1010
- deleteCache: result.value.deleteCache,
1011
- deleteVideo: result.value.deleteVideo
1012
- });
1013
- if (!r.code) {
1014
- T.toast(r.message || '已删除选中的下载');
1015
- urls.forEach(url => (delete this.tasks[url]));
1016
- this.selectedTasks = [];
1017
- this.forceUpdate();
1018
- }
1019
- }
1020
- } catch (error) {
1021
- console.error('删除下载失败:', error);
1022
- T.alert('删除下载失败: ' + error.message);
1023
- }
1024
- },
1025
1009
  },
1026
1010
  mounted() {
1027
1011
  T.reqHeaders.authorization = this.token ? `${this.token}` : '';
@@ -0,0 +1,44 @@
1
+ <!DOCTYPE html>
2
+ <html lang="zh">
3
+
4
+ <head>
5
+ <title>m3u8 在线播放</title>
6
+ <meta charset="utf-8">
7
+ <meta http-equiv="X-UA-Compatible" content="IE=edge">
8
+ <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0,viewport-fit=cover" name="viewport" />
9
+ <link crossorigin="anonymous" rel="stylesheet" href="https://lib.baomitu.com/dplayer/latest/DPlayer.min.css">
10
+ <style>
11
+ body {
12
+ margin: 0;
13
+ }
14
+ </style>
15
+ </head>
16
+
17
+ <body>
18
+ <div id="dplayer"></div>
19
+ <script crossorigin="anonymous"
20
+ integrity="sha512-yi//c0pOEPlBEqUMgK7Ia1VXQT9TwuMHJIRU+T2lyV7YxsMhbF35N/DGYkCFWfC9ebjdupP4xadFyFVTz/sgEg=="
21
+ src="https://lib.baomitu.com/hls.js/1.3.0/hls.min.js"></script>
22
+ <script crossorigin="anonymous" src="https://lib.baomitu.com/dplayer/latest/DPlayer.min.js"></script>
23
+
24
+ <script>
25
+ const url = location.href.split('url=')[1];
26
+ if (!url) {
27
+ document.getElementById('dplayer').innerText = '请传入播放地址参数 url=';
28
+ } else {
29
+ const dp = new DPlayer({
30
+ container: document.getElementById('dplayer'),
31
+ autoplay: true,
32
+ video: {
33
+ url: decodeURIComponent(url),
34
+ type: 'auto',
35
+ },
36
+ pluginOptions: {
37
+ hls: {},
38
+ },
39
+ });
40
+ }
41
+ </script>
42
+ </body>
43
+
44
+ </html>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lzwme/m3u8-dl",
3
- "version": "1.1.0",
3
+ "version": "1.1.2",
4
4
  "description": "Batch download of m3u8 files and convert to mp4",
5
5
  "main": "cjs/index.js",
6
6
  "types": "cjs/index.d.ts",