Files
gopeed/ui/flutter/lib/api/model/task.dart
T
sun 4f74101b3a feat(hls): add native HLS (m3u8) download protocol
New hls protocol in internal/protocol/hls (registered ahead of http):
- master playlist variant picking (highest bandwidth), RFC3986 segment
  URL resolution, fMP4 init segments, EXT-X-BYTERANGE, EXT-X-GAP skip
- AES-128 decryption with mid-playlist key rotation and sequence-derived
  IVs; explicit errors for live streams, SAMPLE-AES and multi-period fMP4
- concurrent segment downloads with retry, journal-based resume across
  pause/app restarts, automatic in-order merge into a single .ts/.mp4
- best-effort Content-Length probing for determinate progress
- anti-hotlink Referer/Cookie/UA via task extra headers (Go transport
  does not filter them)

Core: fix SchemeFilter extension match for URLs with query strings
(also benefits .torrent links); Flutter: Protocol.hls enum, hls protocol
config model (prevents config round-trip wipe) and HLS settings block
with localized labels in all 22 locales.

Tests: parser/crypto unit tests, httptest e2e (Referer-enforced CDN,
encrypted streams, byterange, pause/resume, store/restore) and an
opt-in live-site acceptance gate (HLS_LIVE_URL).
2026-09-14 09:55:31 +08:00

123 lines
2.6 KiB
Dart

import 'package:json_annotation/json_annotation.dart';
import 'meta.dart';
part 'task.g.dart';
enum Status { ready, running, pause, wait, error, done }
enum Protocol { http, bt, ed2k, hls }
// ExtractStatus enum matching Go backend
enum ExtractStatus {
@JsonValue('')
none,
@JsonValue('queued')
queued,
@JsonValue('extracting')
extracting,
@JsonValue('done')
done,
@JsonValue('error')
error,
@JsonValue('waitingParts')
waitingParts,
}
@JsonSerializable(explicitToJson: true)
class Task {
String id;
String name;
Protocol? protocol;
Meta meta;
Status status;
bool uploading;
Progress progress;
DateTime createdAt;
DateTime updatedAt;
Task({
required this.id,
required this.name,
required this.meta,
required this.status,
required this.uploading,
required this.progress,
required this.createdAt,
required this.updatedAt,
});
factory Task.fromJson(Map<String, dynamic> json) => _$TaskFromJson(json);
Map<String, dynamic> toJson() => _$TaskToJson(this);
}
@JsonSerializable()
class Progress {
int used;
int speed;
int downloaded;
int uploadSpeed;
int uploaded;
ExtractStatus extractStatus;
int extractProgress;
Progress({
required this.used,
required this.speed,
required this.downloaded,
required this.uploadSpeed,
required this.uploaded,
this.extractStatus = ExtractStatus.none,
this.extractProgress = 0,
});
factory Progress.fromJson(Map<String, dynamic> json) => _$ProgressFromJson(json);
Map<String, dynamic> toJson() => _$ProgressToJson(this);
}
@JsonSerializable()
class FileRuntimeStatus {
int index;
int size;
int downloaded;
FileRuntimeStatus({required this.index, required this.size, required this.downloaded});
factory FileRuntimeStatus.fromJson(Map<String, dynamic> json) => _$FileRuntimeStatusFromJson(json);
Map<String, dynamic> toJson() => _$FileRuntimeStatusToJson(this);
}
@JsonSerializable(explicitToJson: true)
class TaskRuntimeStatus {
Status status;
int used;
int speed;
int downloaded;
int total;
int uploadSpeed;
int uploaded;
ExtractStatus extractStatus;
int extractProgress;
List<FileRuntimeStatus> files;
TaskRuntimeStatus({
required this.status,
required this.used,
required this.speed,
required this.downloaded,
required this.total,
required this.uploadSpeed,
required this.uploaded,
this.extractStatus = ExtractStatus.none,
this.extractProgress = 0,
required this.files,
});
factory TaskRuntimeStatus.fromJson(Map<String, dynamic> json) => _$TaskRuntimeStatusFromJson(json);
Map<String, dynamic> toJson() => _$TaskRuntimeStatusToJson(this);
}