From 06f5e56489871b6e43630f164789e7f68f8cb08d Mon Sep 17 00:00:00 2001 From: jscampucci Date: Fri, 28 Jun 2024 09:24:53 +0200 Subject: [PATCH 1/5] [clean] clean code --- .gitignore | 2 + .vscode/settings.json | 6 ++ lib/dlForm/cubit/dl_form_cubit.dart | 14 +++-- lib/dlForm/{dlForm.dart => dl_form.dart} | 10 +-- ...rmatDropdown.dart => format_dropdown.dart} | 17 +----- .../{submitButton.dart => submit_button.dart} | 3 +- ...{urlTextField.dart => url_text_field.dart} | 0 lib/main.dart | 1 - lib/models/Video.dart | 61 +++++++++++++++---- lib/screens/home.dart | 24 ++++---- lib/services/download.dart | 8 +-- pubspec.lock | 2 +- pubspec.yaml | 1 + 13 files changed, 89 insertions(+), 60 deletions(-) create mode 100644 .vscode/settings.json rename lib/dlForm/{dlForm.dart => dl_form.dart} (88%) rename lib/dlForm/formComponents/{formatDropdown.dart => format_dropdown.dart} (79%) rename lib/dlForm/formComponents/{submitButton.dart => submit_button.dart} (95%) rename lib/dlForm/formComponents/{urlTextField.dart => url_text_field.dart} (100%) diff --git a/.gitignore b/.gitignore index 6b48af0..b912ae6 100644 --- a/.gitignore +++ b/.gitignore @@ -42,3 +42,5 @@ app.*.map.json /android/app/debug /android/app/profile /android/app/release + +samples/ \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..46300ca --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "dart.analysisExcludedFolders": [ + "C:\\Users\\Skapdat\\Projets\\Dev\\NoTube-Flutter\\notube\\samples" + ], + "CodeGPT.apiKey": "Anthropic" +} diff --git a/lib/dlForm/cubit/dl_form_cubit.dart b/lib/dlForm/cubit/dl_form_cubit.dart index 6f8091a..1b3364b 100644 --- a/lib/dlForm/cubit/dl_form_cubit.dart +++ b/lib/dlForm/cubit/dl_form_cubit.dart @@ -2,11 +2,9 @@ import 'dart:convert'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; -import 'package:notube/models/Video.dart'; +import 'package:notube/models/video.dart'; import 'package:notube/services/download.dart'; -import 'dart:developer'; - part 'dl_form_state.dart'; class DlFormCubit extends Cubit { @@ -29,7 +27,7 @@ class DlFormCubit extends Cubit { void parseUrl() async { dlService = await DLServices.init(); - var shellStream = await dlService.analyseUrl(state.url!); + var shellStream = await dlService.analyseUrl(state.url); shellStream.listen((line) { if (line[0] == '{') { @@ -41,12 +39,16 @@ class DlFormCubit extends Cubit { var playlistTitle = dataInfos['title']; for (var videoTmp in dataInfos['entries']) { var video = Video.fromJson(videoTmp); - video.format = state.format; + video.copyWith( + format: state.format, + ); videos.add(video); } } else { var video = Video.fromJson(dataInfos); - video.format = state.format; + video.copyWith( + format: state.format, + ); videos.add(video); } emit(state.copyWith( diff --git a/lib/dlForm/dlForm.dart b/lib/dlForm/dl_form.dart similarity index 88% rename from lib/dlForm/dlForm.dart rename to lib/dlForm/dl_form.dart index ae5249e..05ea553 100644 --- a/lib/dlForm/dlForm.dart +++ b/lib/dlForm/dl_form.dart @@ -1,9 +1,9 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:notube/dlForm/cubit/dl_form_cubit.dart'; -import 'package:notube/dlForm/formComponents/formatDropdown.dart'; -import 'package:notube/dlForm/formComponents/submitButton.dart'; -import 'package:notube/dlForm/formComponents/urlTextField.dart'; +import 'package:notube/dlForm/formComponents/format_dropdown.dart'; +import 'package:notube/dlForm/formComponents/submit_button.dart'; +import 'package:notube/dlForm/formComponents/url_text_field.dart'; class DlForm extends StatelessWidget { const DlForm({super.key}); @@ -69,8 +69,8 @@ class DebugDlFormState extends StatelessWidget { return Column( children: [ - Text('Url: ${url}'), - Text('Format: ${format}'), + Text('Url: $url'), + Text('Format: $format'), ], ); }); diff --git a/lib/dlForm/formComponents/formatDropdown.dart b/lib/dlForm/formComponents/format_dropdown.dart similarity index 79% rename from lib/dlForm/formComponents/formatDropdown.dart rename to lib/dlForm/formComponents/format_dropdown.dart index 5646fe5..404e340 100644 --- a/lib/dlForm/formComponents/formatDropdown.dart +++ b/lib/dlForm/formComponents/format_dropdown.dart @@ -3,17 +3,6 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:notube/constants.dart'; import 'package:notube/dlForm/cubit/dl_form_cubit.dart'; -const List formatList = [ - "MP3", - "MP3 HD", - "MP4", - "MP4 HD", - "MP4 2K", - "3GP", - "FLV", - "M4A", -]; - class DropdownFormat extends StatelessWidget { const DropdownFormat({super.key}); @@ -37,10 +26,10 @@ class DropdownFormat extends StatelessWidget { context.read().setFormat(value!); }, underline: Container(), - items: formatList.map>((String value) { + items: Format.values.map>((Format format) { return DropdownMenuItem( - value: value, - child: Text(value), + value: format.format, + child: Text(format.format), ); }).toList(), )); diff --git a/lib/dlForm/formComponents/submitButton.dart b/lib/dlForm/formComponents/submit_button.dart similarity index 95% rename from lib/dlForm/formComponents/submitButton.dart rename to lib/dlForm/formComponents/submit_button.dart index 046b910..b0aaab7 100644 --- a/lib/dlForm/formComponents/submitButton.dart +++ b/lib/dlForm/formComponents/submit_button.dart @@ -2,9 +2,8 @@ import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:notube/constants.dart'; -import 'package:notube/models/Video.dart'; +import 'package:notube/models/video.dart'; import 'package:notube/videoList/cubit/videos_cubit.dart'; -import 'package:provider/provider.dart'; import 'package:notube/dlForm/cubit/dl_form_cubit.dart'; class SubmitButton extends StatefulWidget { diff --git a/lib/dlForm/formComponents/urlTextField.dart b/lib/dlForm/formComponents/url_text_field.dart similarity index 100% rename from lib/dlForm/formComponents/urlTextField.dart rename to lib/dlForm/formComponents/url_text_field.dart diff --git a/lib/main.dart b/lib/main.dart index 69e66c5..372446d 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,7 +6,6 @@ import 'package:window_manager/window_manager.dart'; import 'package:upgrader/upgrader.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:notube/videoList/cubit/videos_cubit.dart'; -import 'package:notube/models/Video.dart'; void main() async { WidgetsFlutterBinding.ensureInitialized(); diff --git a/lib/models/Video.dart b/lib/models/Video.dart index 79d6d90..de3b820 100644 --- a/lib/models/Video.dart +++ b/lib/models/Video.dart @@ -1,5 +1,7 @@ import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +@immutable class Video extends Equatable { Video({ this.id = '', @@ -17,19 +19,19 @@ class Video extends Equatable { this.filename = '', }); - String id; - String url; - String extractor; - bool isParsed; - String status; - String format; - String title; - String thumbnail; - String description; - String duration; - String uploader; - String uploadDate; - String filename; + final String id; + final String url; + final String extractor; + final bool isParsed; + final String status; + final String format; + final String title; + final String thumbnail; + final String description; + final String duration; + final String uploader; + final String uploadDate; + final String filename; factory Video.fromJson(Map json) { return Video( @@ -45,6 +47,39 @@ class Video extends Equatable { uploadDate: json['upload_date'] ?? ''); } + //set Status + Video copyWith({ + String? id, + String? url, + String? extractor, + bool? isParsed, + String? status, + String? format, + String? title, + String? thumbnail, + String? description, + String? duration, + String? uploader, + String? uploadDate, + String? filename, + }) { + return Video( + id: id ?? this.id, + url: url ?? this.url, + extractor: extractor ?? this.extractor, + isParsed: isParsed ?? this.isParsed, + status: status ?? this.status, + format: format ?? this.format, + title: title ?? this.title, + thumbnail: thumbnail ?? this.thumbnail, + description: description ?? this.description, + duration: duration ?? this.duration, + uploader: uploader ?? this.uploader, + uploadDate: uploadDate ?? this.uploadDate, + filename: filename ?? this.filename, + ); + } + @override List get props => [ id, diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 4a84ad3..11a913f 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,10 +1,8 @@ import 'package:flutter/material.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:notube/constants.dart'; -import 'package:notube/dlForm/dlForm.dart'; +import 'package:notube/dlForm/dl_form.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:notube/videoList/cubit/videos_cubit.dart'; -import 'package:notube/models/Video.dart'; class Home extends StatelessWidget { Home({super.key}); @@ -44,15 +42,17 @@ class Home extends StatelessWidget { itemBuilder: (context, index) { var currentVideo = state.videoList[index]; return ListTile( - leading: SizedBox( - width: 72, - height: 48, - child: Image.network( - currentVideo.thumbnail, - fit: BoxFit.cover), - ), - title: Text(currentVideo.title), - subtitle: Text(currentVideo.status)); + leading: SizedBox( + width: 72, + height: 48, + child: Image.network( + currentVideo.thumbnail, + fit: BoxFit.cover), + ), + title: Text(currentVideo.title), + subtitle: Text( + '${currentVideo.status} - ${currentVideo.format}'), + ); }, ); })), diff --git a/lib/services/download.dart b/lib/services/download.dart index 86e1c0c..448b6ea 100644 --- a/lib/services/download.dart +++ b/lib/services/download.dart @@ -1,16 +1,12 @@ -import 'dart:convert'; import 'dart:io'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:notube/constants.dart'; -import 'package:notube/models/Video.dart'; +import 'package:notube/models/video.dart'; import 'package:path_provider/path_provider.dart'; import 'package:process_run/shell.dart'; -import 'dart:developer'; - class DLServices { late Directory tempDir; late String assetName; @@ -71,7 +67,7 @@ class DLServices { var cleanTitle = video.title.replaceAll(RegExp(r'[^\w\s]+'), ''); var command = - '${video.url.trim()} --sub-langs "all,-live_chat" --embed-subs --embed-thumbnail --embed-metadata --progress -o "temp/%(playlist)s/${cleanTitle}_${video.format}_tmp.%(ext)s" -f "$formatCmd"'; + '${video.url.trim()} --sub-langs "all,-live_chat" --embed-subs --embed-thumbnail --embed-metadata --progress -o "temp/${video.id}_${video.format}_tmp.%(ext)s" -f "$formatCmd"'; var shellLinesController = ShellLinesController(); var shell = Shell(stdout: shellLinesController.sink, verbose: false); diff --git a/pubspec.lock b/pubspec.lock index 9da5489..436b689 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -18,7 +18,7 @@ packages: source: hosted version: "2.11.0" bloc: - dependency: transitive + dependency: "direct main" description: name: bloc sha256: "106842ad6569f0b60297619e9e0b1885c2fb9bf84812935490e6c5275777804e" diff --git a/pubspec.yaml b/pubspec.yaml index 25d96bb..c32579f 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -27,6 +27,7 @@ dependencies: flutter_bloc: ^8.1.6 equatable: ^2.0.5 json_annotation: ^4.9.0 + bloc: ^8.1.4 dev_dependencies: flutter_test: From 188733fdf42b14231e6527e7c7073e6a46e94e48 Mon Sep 17 00:00:00 2001 From: jscampucci Date: Tue, 2 Jul 2024 11:23:14 +0200 Subject: [PATCH 2/5] [conv] ffmpeg full conversion --- -vcodec | 0 lib/constants.dart | 36 ++++- lib/dlForm/cubit/dl_form_cubit.dart | 20 +-- lib/dlForm/cubit/dl_form_state.dart | 6 +- lib/dlForm/dl_form.dart | 2 +- .../formComponents/format_dropdown.dart | 6 +- lib/dlForm/formComponents/submit_button.dart | 2 +- lib/models/Video.dart | 7 +- lib/screens/home.dart | 2 +- lib/services/converter.dart | 46 +++++- lib/services/download.dart | 17 ++- lib/videoList/cubit/videos_cubit.dart | 132 +++++++++++++++--- macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 90 +++++++++++- pubspec.yaml | 2 + .../flutter/generated_plugin_registrant.cc | 6 + windows/flutter/generated_plugins.cmake | 2 + 17 files changed, 320 insertions(+), 58 deletions(-) create mode 100644 -vcodec diff --git a/-vcodec b/-vcodec new file mode 100644 index 0000000..e69de29 diff --git a/lib/constants.dart b/lib/constants.dart index f4e93b4..281db6f 100644 --- a/lib/constants.dart +++ b/lib/constants.dart @@ -8,8 +8,14 @@ const colorDarkRed = Color.fromRGBO(153, 0, 0, 1); const colorMainBlue = Color(0xFF1f74ad); enum Format { - mp3(format: 'MP3'), - mp3HD(format: 'MP3 HD'), + mp3( + format: 'MP3', + ffmpegCmd: '-f mp3 -loglevel quiet -ab 192k -vn', + extension: 'mp3'), + mp3HD( + format: 'MP3 HD', + ffmpegCmd: '-f mp3 -loglevel quiet -ab 320k -vn', + extension: 'mp3'), mp4(format: 'MP4'), mp4HD( ytCmd: @@ -19,16 +25,36 @@ enum Format { ytCmd: "bestvideo[height=1440][ext=mp4]+bestaudio[ext=m4a]/bestvideo[height<=1080][ext=mp4][vcodec~='^(avc|h264)']+bestaudio[ext=m4a]/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best", format: 'MP4 2K'), - tGP(format: '3GP'), - flv(format: 'FLV'), - m4a; + tGP( + format: '3GP', + ffmpegCmd: + '-movflags frag_keyframe+empty_moov -r 20 -s 352x288 -vb 400k -acodec aac -strict experimental -ac 1 -ar 8000 -ab 24k -f 3gp', + extension: '3gp'), + flv( + format: 'FLV', + ffmpegCmd: + '-vcodec libx264 -preset slower -b 512k -bt 512k -threads 0 -s 640x360 -aspect 16:9 -acodec libmp3lame -ar 44100 -ab 32 -progress pipe:1', + extension: 'flv'), + m4a(format: 'M4A'), + ; final String ytCmd; final String format; + final String ffmpegCmd; + final String extension; const Format({ this.ytCmd = '"18/22/bestvideo[ext=mp4]+bestaudio[ext=m4a]/best[ext=mp4]/best"', this.format = 'MP4', + this.ffmpegCmd = '', + this.extension = '', }); } + +const convertedFormats = [ + Format.mp3, + Format.mp3HD, + Format.tGP, + Format.flv, +]; diff --git a/lib/dlForm/cubit/dl_form_cubit.dart b/lib/dlForm/cubit/dl_form_cubit.dart index 1b3364b..8ce0e71 100644 --- a/lib/dlForm/cubit/dl_form_cubit.dart +++ b/lib/dlForm/cubit/dl_form_cubit.dart @@ -2,6 +2,8 @@ import 'dart:convert'; import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; +import 'package:flutter/material.dart'; +import 'package:notube/constants.dart'; import 'package:notube/models/video.dart'; import 'package:notube/services/download.dart'; @@ -12,7 +14,7 @@ class DlFormCubit extends Cubit { late DLServices dlService; - void setFormat(String newFormat) { + void setFormat(Format newFormat) { emit(state.copyWith( format: newFormat, )); @@ -39,17 +41,15 @@ class DlFormCubit extends Cubit { var playlistTitle = dataInfos['title']; for (var videoTmp in dataInfos['entries']) { var video = Video.fromJson(videoTmp); - video.copyWith( - format: state.format, - ); - videos.add(video); + videos.add(video.copyWith( + format: state.format, + filename: '${video.id}_${state.format.format}')); } } else { var video = Video.fromJson(dataInfos); - video.copyWith( - format: state.format, - ); - videos.add(video); + videos.add(video.copyWith( + format: state.format, + filename: '${video.id}_${state.format.format}')); } emit(state.copyWith( isParsed: true, @@ -60,7 +60,7 @@ class DlFormCubit extends Cubit { }); } - void clearVideos() { + void clearForm() { emit(state.copyWith( videos: [], isParsed: false, diff --git a/lib/dlForm/cubit/dl_form_state.dart b/lib/dlForm/cubit/dl_form_state.dart index 6eb3567..78fa55f 100644 --- a/lib/dlForm/cubit/dl_form_state.dart +++ b/lib/dlForm/cubit/dl_form_state.dart @@ -3,21 +3,21 @@ part of 'dl_form_cubit.dart'; class DlFormState extends Equatable { const DlFormState({ this.url = '', - this.format = 'MP3', + this.format = Format.mp4, this.videos = const [], this.isParsed = false, this.extractor = '', }); final String url; - final String format; + final Format format; final bool isParsed; final List