Compare commits

...

2 Commits

Author SHA1 Message Date
poka 7f06a7b96e feat: add keyboard media controls 2023-04-16 03:30:01 +02:00
poka d7cb5885f7 fix: show download button on player 2023-04-16 03:11:06 +02:00
7 changed files with 136 additions and 99 deletions

View File

@ -1,3 +1,4 @@
import 'package:fipy/providers/download.dart';
import 'package:fipy/providers/home.dart';
import 'package:fipy/providers/player.dart';
import 'package:fipy/screens/home.dart';
@ -18,6 +19,7 @@ class FipyApp extends StatelessWidget {
providers: [
ChangeNotifierProvider(create: (_) => PlayerProvider()),
ChangeNotifierProvider(create: (_) => HomeProvider()),
ChangeNotifierProvider(create: (_) => DownloadProvider()),
],
child: MaterialApp(
title: 'Fipy',

View File

@ -0,0 +1,61 @@
// ignore_for_file: use_build_context_synchronously
import 'dart:io';
import 'package:fipy/globals.dart';
import 'package:fipy/models/track.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
class DownloadProvider with ChangeNotifier {
Future downloadMusic(BuildContext context, Track track) async {
var yt = YoutubeExplode();
var manifest = await yt.videos.streamsClient.getManifest(track.id);
var streamManifest = StreamManifest(manifest.streams);
var streamInfo = streamManifest.audioOnly.withHighestBitrate();
var stream = yt.videos.streamsClient.get(streamInfo);
final fileName = '${track.title} - ${track.artiste}'
.replaceAll('\\', '')
.replaceAll('/', '')
.replaceAll(':', '')
.replaceAll('*', '')
.replaceAll('?', '')
.replaceAll('"', '')
.replaceAll('<', '')
.replaceAll('>', '')
.replaceAll('|', '');
if (!kIsWeb) {
final filePath = Platform.isAndroid
? Directory('/storage/emulated/0/Download')
: await getDownloadsDirectory();
var file = File('${filePath!.path}/$fileName.webm');
var fileStream = file.openWrite();
await stream.pipe(fileStream);
await fileStream.flush();
await fileStream.close();
yt.close();
// convertToMp3(file.path);
track.file = file;
ScaffoldMessenger.of(playerContext).showSnackBar(
SnackBar(
content:
SizedBox(height: 90, child: Text('Son téléchargé: ${file.path}')),
),
);
log.d(file.path);
}
}
void reload() {
notifyListeners();
}
}

View File

@ -1,12 +1,7 @@
// ignore_for_file: avoid_print, use_build_context_synchronously
import 'dart:convert';
import 'package:fipy/globals.dart';
import 'package:flutter/foundation.dart';
import 'package:universal_io/io.dart';
import 'package:fipy/models/track.dart';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:youtube_explode_dart/youtube_explode_dart.dart';
import 'package:fipy/providers/player.dart';
import 'package:provider/provider.dart';
@ -42,7 +37,7 @@ class HomeProvider with ChangeNotifier {
if (body['next'] != null) {
cursor = body['next'];
} else {
print('Page N°$pageNbr');
log.d('Page N°$pageNbr');
stop = true;
}
@ -100,10 +95,10 @@ class HomeProvider with ChangeNotifier {
try {
final source = UrlSource(
"https://${invidiousUrl[3]}/latest_version?id=${track.id}&itag=140&local=true&listen=1");
print(source.url);
log.d(source.url);
await player.play(source);
} catch (e) {
print('Play error: $e');
log.d('Play error: $e');
}
Future.delayed(const Duration(milliseconds: 50));
@ -129,52 +124,6 @@ class HomeProvider with ChangeNotifier {
yt.close();
}
Future downloadMusic(BuildContext context, Track track) async {
var yt = YoutubeExplode();
var manifest = await yt.videos.streamsClient.getManifest(track.id);
var streamManifest = StreamManifest(manifest.streams);
var streamInfo = streamManifest.audioOnly.withHighestBitrate();
var stream = yt.videos.streamsClient.get(streamInfo);
final fileName = '${track.title} - ${track.artiste}'
.replaceAll('\\', '')
.replaceAll('/', '')
.replaceAll(':', '')
.replaceAll('*', '')
.replaceAll('?', '')
.replaceAll('"', '')
.replaceAll('<', '')
.replaceAll('>', '')
.replaceAll('|', '');
if (!kIsWeb) {
final filePath = Platform.isAndroid
? Directory('/storage/emulated/0/Download')
: await getDownloadsDirectory();
var file = File('${filePath!.path}/$fileName.webm');
var fileStream = file.openWrite();
await stream.pipe(fileStream);
await fileStream.flush();
await fileStream.close();
yt.close();
// convertToMp3(file.path);
track.file = file;
notifyListeners();
ScaffoldMessenger.of(playerContext).showSnackBar(
SnackBar(
content:
SizedBox(height: 90, child: Text('Son téléchargé: ${file.path}')),
),
);
print(file.path);
}
}
List<DropdownMenuItem<String>> get radioList {
List<DropdownMenuItem<String>> menuItems = [
const DropdownMenuItem(value: "fip", child: Text("FIP")),

View File

@ -30,12 +30,34 @@ class _HomeScreenState extends State<HomeScreen> {
autofocus: true,
focusNode: FocusNode(),
onKey: (RawKeyEvent event) {
if (event.runtimeType == RawKeyDownEvent &&
event.data.logicalKey.keyId == 32) //Enter Key ID from keyboard
log.d(event.data.logicalKey.keyId);
if (event.runtimeType == RawKeyDownEvent) //Enter Key ID from keyboard
{
hp.player.state.name == 'playing'
? hp.player.pause()
: hp.player.resume();
switch (event.data.logicalKey.keyId) {
case 32:
case 112:
case 4294969861:
hp.player.state.name == 'playing'
? hp.player.pause()
: hp.player.resume();
break;
case 110:
case 94489280688:
if (hp.currentTrack != null &&
hp.currentTrack!.number < hp.trackList.last.number) {
hp.currentTrack = hp.trackList.firstWhere(
(element) => element.number == hp.currentTrack!.number + 1);
hp.playTrack(hp.currentTrack!);
}
break;
case 98:
case 94489280689:
if (hp.currentTrack != null && hp.currentTrack!.number > 1) {
hp.currentTrack = hp.trackList.firstWhere(
(element) => element.number == hp.currentTrack!.number - 1);
hp.playTrack(hp.currentTrack!);
}
}
}
},
child: Stack(

View File

@ -1,5 +1,5 @@
import 'package:fipy/globals.dart';
import 'package:fipy/models/track.dart';
import 'package:fipy/providers/download.dart';
import 'package:fipy/providers/home.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
@ -12,47 +12,50 @@ class DownloadTrack extends StatelessWidget {
@override
Widget build(BuildContext context) {
final hp = Provider.of<HomeProvider>(context, listen: false);
int isDownloading = -1;
final hp = Provider.of<HomeProvider>(context, listen: true);
final dl = Provider.of<DownloadProvider>(context, listen: false);
int isDownloading = -2;
final yt = YoutubeExplode();
final track = this.track ??
hp.currentTrack ??
Track(number: -1, title: 'title', artiste: 'artiste');
Track(number: -3, title: 'title', artiste: 'artiste');
return Visibility(
visible: track.number != -1,
child: InkWell(onTap: () async {
isDownloading = track.number;
hp.reload();
if (track.id == null) {
final secondMatch = track.artiste == '' ? track.album : track.artiste;
final resultUrl =
await yt.search.search('${track.title} ${secondMatch!}');
track.id = resultUrl.first.id.value;
}
if (track.id != null) {
// ignore: use_build_context_synchronously
hp.downloadMusic(context, track);
}
isDownloading = -1;
yt.close();
// hp.reload();
}, child: Consumer<HomeProvider>(builder: (context, _, __) {
return Row(children: [
const SizedBox(width: 37),
isDownloading == track.number
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.grey[500],
),
)
: Icon(Icons.download, color: Colors.grey[500]),
]);
})),
);
return InkWell(
onTap: track.number == -3
? null
: () async {
isDownloading = track.number;
dl.reload();
if (track.id == null) {
final secondMatch =
track.artiste == '' ? track.album : track.artiste;
final resultUrl =
await yt.search.search('${track.title} ${secondMatch!}');
track.id = resultUrl.first.id.value;
}
if (track.id != null) {
// ignore: use_build_context_synchronously
await dl.downloadMusic(context, track);
}
isDownloading = -2;
yt.close();
dl.reload();
},
child: Consumer<DownloadProvider>(builder: (context, _, __) {
return Row(children: [
const SizedBox(width: 37),
isDownloading == track.number
? SizedBox(
height: 20,
width: 20,
child: CircularProgressIndicator(
strokeWidth: 2,
color: Colors.grey[500],
),
)
: Icon(Icons.download, color: Colors.grey[500]),
]);
}));
}
}

View File

@ -58,4 +58,4 @@ class PlayerTitle extends StatelessWidget {
]),
);
}
}
}

View File

@ -33,4 +33,4 @@ class PlayerVolume extends StatelessWidget {
),
);
}
}
}