mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-04-18 21:22:07 +00:00
Add subtitle support for video downloads and playback
This commit is contained in:
parent
b2fa09c214
commit
8eaeca2123
5 changed files with 81 additions and 4 deletions
|
|
@ -268,7 +268,7 @@ class _AnimeStreamPageState extends riv.ConsumerState<AnimeStreamPage>
|
|||
);
|
||||
final file = defaultTrack.file ?? "";
|
||||
final label = defaultTrack.label;
|
||||
final track = file.startsWith("http")
|
||||
final track = (file.startsWith("http") || file.startsWith("file"))
|
||||
? SubtitleTrack.uri(file, title: label, language: label)
|
||||
: SubtitleTrack.data(file, title: label, language: label);
|
||||
_player.setSubtitleTrack(track);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import 'package:mangayomi/main.dart';
|
|||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/download.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/modules/manga/download/providers/convert_to_cbz.dart';
|
||||
import 'package:mangayomi/modules/more/settings/downloads/providers/downloads_state_provider.dart';
|
||||
import 'package:mangayomi/providers/l10n_providers.dart';
|
||||
|
|
@ -75,7 +76,7 @@ Future<void> downloadChapter(
|
|||
final mangaMainDirectory = await storageProvider.getMangaMainDirectory(
|
||||
chapter,
|
||||
);
|
||||
|
||||
List<Track>? subtitles;
|
||||
bool isOk = false;
|
||||
final manga = chapter.manga.value!;
|
||||
final chapterName = chapter.name!.replaceForbiddenCharacters(' ');
|
||||
|
|
@ -199,11 +200,13 @@ Future<void> downloadChapter(
|
|||
hasM3U8File = nonM3U8File ? false : m3u8Urls.isNotEmpty;
|
||||
final videosUrls = nonM3U8File ? nonM3u8Urls : m3u8Urls;
|
||||
if (videosUrls.isNotEmpty) {
|
||||
subtitles = videosUrls.first.subtitles;
|
||||
if (hasM3U8File) {
|
||||
m3u8Downloader = M3u8Downloader(
|
||||
m3u8Url: videosUrls.first.url,
|
||||
downloadDir: chapterDirectory.path,
|
||||
headers: videosUrls.first.headers ?? {},
|
||||
subtitles: subtitles,
|
||||
fileName: p.join(mangaMainDirectory!.path, "$chapterName.mp4"),
|
||||
chapter: chapter,
|
||||
);
|
||||
|
|
@ -339,7 +342,12 @@ Future<void> downloadChapter(
|
|||
});
|
||||
} else {
|
||||
savePageUrls();
|
||||
await MDownloader(chapter: chapter, pageUrls: pages).download((progress) {
|
||||
await MDownloader(
|
||||
chapter: chapter,
|
||||
pageUrls: pages,
|
||||
subtitles: subtitles,
|
||||
subDownloadDir: chapterDirectory.path,
|
||||
).download((progress) {
|
||||
setProgress(progress);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import 'dart:isolate';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:mangayomi/services/http/rhttp/src/model/settings.dart';
|
||||
import 'package:mangayomi/services/download_manager/m3u8/models/download.dart';
|
||||
|
|
@ -25,6 +26,7 @@ class M3u8Downloader {
|
|||
final String fileName;
|
||||
final int concurrentDownloads;
|
||||
final Chapter chapter;
|
||||
final List<Track>? subtitles;
|
||||
Isolate? _isolate;
|
||||
ReceivePort? _receivePort;
|
||||
static var httpClient = MClient.httpClient(
|
||||
|
|
@ -40,6 +42,7 @@ class M3u8Downloader {
|
|||
this.headers,
|
||||
required this.chapter,
|
||||
this.concurrentDownloads = 2,
|
||||
required this.subtitles,
|
||||
});
|
||||
|
||||
void _log(String message) {
|
||||
|
|
@ -139,6 +142,26 @@ class M3u8Downloader {
|
|||
mediaSequence,
|
||||
onProgress,
|
||||
);
|
||||
for (var element in subtitles ?? <Track>[]) {
|
||||
final subtitleFile = File(
|
||||
path.join('${downloadDir}_subtitles', '${element.label}.srt'),
|
||||
);
|
||||
if (subtitleFile.existsSync()) {
|
||||
_log('Subtitle file already exists: ${element.label}');
|
||||
continue;
|
||||
}
|
||||
_log('Downloading subtitle file: ${element.label}');
|
||||
subtitleFile.createSync(recursive: true);
|
||||
final response = await _withRetry(
|
||||
() => httpClient.get(Uri.parse(element.file ?? ''), headers: headers),
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
_log('Warning: Failed to download subtitle file: ${element.label}');
|
||||
continue;
|
||||
}
|
||||
_log('Subtitle file downloaded: ${element.label}');
|
||||
await subtitleFile.writeAsBytes(response.bodyBytes);
|
||||
}
|
||||
} catch (e) {
|
||||
throw M3u8DownloaderException('Download failed', e);
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -8,16 +8,20 @@ import 'package:http/http.dart';
|
|||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga.dart';
|
||||
import 'package:mangayomi/models/page.dart';
|
||||
import 'package:mangayomi/models/video.dart';
|
||||
import 'package:mangayomi/services/http/m_client.dart';
|
||||
import 'package:mangayomi/services/http/rhttp/src/model/settings.dart';
|
||||
import 'package:mangayomi/services/download_manager/m3u8/m3u8_downloader.dart';
|
||||
import 'package:mangayomi/services/download_manager/m3u8/models/download.dart';
|
||||
import 'package:mangayomi/src/rust/frb_generated.dart';
|
||||
import 'package:path/path.dart' as path;
|
||||
|
||||
class MDownloader {
|
||||
List<PageUrl> pageUrls;
|
||||
final int concurrentDownloads;
|
||||
final Chapter chapter;
|
||||
final List<Track>? subtitles;
|
||||
final String? subDownloadDir;
|
||||
Isolate? _isolate;
|
||||
ReceivePort? _receivePort;
|
||||
static var httpClient = MClient.httpClient(
|
||||
|
|
@ -29,6 +33,8 @@ class MDownloader {
|
|||
MDownloader({
|
||||
required this.chapter,
|
||||
required this.pageUrls,
|
||||
required this.subtitles,
|
||||
required this.subDownloadDir,
|
||||
this.concurrentDownloads = 2,
|
||||
});
|
||||
|
||||
|
|
@ -76,6 +82,27 @@ class MDownloader {
|
|||
Future<void> download(void Function(DownloadProgress) onProgress) async {
|
||||
try {
|
||||
await _downloadFilesWithProgress(pageUrls, onProgress);
|
||||
for (var element in subtitles ?? <Track>[]) {
|
||||
final subtitleFile = File(
|
||||
path.join('${subDownloadDir}_subtitles', '${element.label}.srt'),
|
||||
);
|
||||
if (subtitleFile.existsSync()) {
|
||||
_log('Subtitle file already exists: ${element.label}');
|
||||
continue;
|
||||
}
|
||||
_log('Downloading subtitle file: ${element.label}');
|
||||
subtitleFile.createSync(recursive: true);
|
||||
final response = await _withRetryStatic(
|
||||
() => httpClient.get(Uri.parse(element.file ?? '')),
|
||||
3,
|
||||
);
|
||||
if (response.statusCode != 200) {
|
||||
_log('Warning: Failed to download subtitle file: ${element.label}');
|
||||
continue;
|
||||
}
|
||||
_log('Subtitle file downloaded: ${element.label}');
|
||||
await subtitleFile.writeAsBytes(response.bodyBytes);
|
||||
}
|
||||
} catch (e) {
|
||||
throw MDownloaderException('Download failed', e);
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -28,9 +28,28 @@ Future<(List<Video>, bool, List<String>)> getVideoList(
|
|||
);
|
||||
List<String> infoHashes = [];
|
||||
if (await File(mp4animePath).exists() || isLocalArchive) {
|
||||
final chapterDirectory = (await storageProvider.getMangaChapterDirectory(
|
||||
episode,
|
||||
mangaMainDirectory: mangaDirectory,
|
||||
))!;
|
||||
final path = isLocalArchive ? episode.archivePath : mp4animePath;
|
||||
final subtitlesDir = Directory(
|
||||
p.join('${chapterDirectory.path}_subtitles'),
|
||||
);
|
||||
List<Track> subtitles = [];
|
||||
if (subtitlesDir.existsSync()) {
|
||||
for (var element in subtitlesDir.listSync()) {
|
||||
if (element is File) {
|
||||
final subtitle = Track(
|
||||
label: element.uri.pathSegments.last.replaceAll('.srt', ''),
|
||||
file: element.uri.toString(),
|
||||
);
|
||||
subtitles.add(subtitle);
|
||||
}
|
||||
}
|
||||
}
|
||||
return (
|
||||
[Video(path!, episode.name!, path, subtitles: [])],
|
||||
[Video(path!, episode.name!, path, subtitles: subtitles)],
|
||||
true,
|
||||
infoHashes,
|
||||
);
|
||||
|
|
|
|||
Loading…
Reference in a new issue