From cca3d6373769ebf5474d221c80220ece42ab15da Mon Sep 17 00:00:00 2001 From: poka Date: Sat, 30 Apr 2022 01:48:17 +0200 Subject: [PATCH] Change API to official Rest, no GraphQL anymore --- lib/models/track.dart | 24 + lib/providers/home.dart | 179 ++++++- lib/screens/home.dart | 594 ++++++++---------------- pubspec.lock | 102 +--- pubspec.yaml | 2 - windows/flutter/generated_plugins.cmake | 8 + 6 files changed, 421 insertions(+), 488 deletions(-) create mode 100644 lib/models/track.dart diff --git a/lib/models/track.dart b/lib/models/track.dart new file mode 100644 index 0000000..99dc9a6 --- /dev/null +++ b/lib/models/track.dart @@ -0,0 +1,24 @@ +import 'dart:io'; + +class Track { + final int number; + final String title; + final String artiste; + final String? album; + String? image; + String? imageUrl; + String? id; + Duration? duration; + File? file; + + Track( + {required this.number, + required this.title, + required this.artiste, + this.album, + this.id, + this.duration, + this.file, + this.image, + this.imageUrl}); +} diff --git a/lib/providers/home.dart b/lib/providers/home.dart index d2330b0..823b75f 100644 --- a/lib/providers/home.dart +++ b/lib/providers/home.dart @@ -1,6 +1,183 @@ +// ignore_for_file: avoid_print + +import 'dart:convert'; +import 'dart:io'; +import 'package:fip_parser_ui/models/track.dart'; import 'package:flutter/material.dart'; +import 'package:kplayer/kplayer.dart'; +import 'package:path_provider/path_provider.dart'; +import 'package:youtube_explode_dart/youtube_explode_dart.dart'; +import 'package:fip_parser_ui/providers/player.dart'; +import 'package:provider/provider.dart'; +import 'package:http/http.dart'; class HomeProvider with ChangeNotifier { + Track? currentTrack; + PlayerController? player; + List trackList = []; + int trackNbr = 0; + int userPageNbr = 3; + + Future> getTracks(String radio, {String cursor = ''}) async { + int pageNbr = 0; + trackList.clear(); + trackNbr = 0; + bool stop = false; + while (pageNbr < userPageNbr && !stop) { + final req = Uri.parse( + 'https://www.radiofrance.fr/api/v1.7/stations/fip/webradios/$radio/songs?pageCursor=$cursor'); + + final res = await get(req, headers: { + "Access-Control-Allow-Origin": "*", + "Access-Control-Allow-Methods": "GET, HEAD, POST, OPTIONS" + }); + if (res.statusCode == 200) { + Map body = jsonDecode(res.body); + if (body['next'] != null) { + cursor = body['next']; + } else { + print('Page N°$pageNbr'); + stop = true; + } + + for (Map track in body['songs']) { + trackNbr++; + final String title = track['secondLine'] ?? ''; + final String artiste = track['firstLine'] ?? ''; + final String album = track['release']['title'] ?? ''; + final String image = track['visual']?['preview'] ?? ''; + final String imageUrl = track['visual']?['src'] ?? ''; + + final thisTrack = Track( + number: trackNbr, + title: title, + artiste: artiste, + album: album, + image: image, + imageUrl: imageUrl); + trackList.add(thisTrack); + } + pageNbr++; + } else { + throw "Unable to retrieve tracks."; + } + } + return trackList; + } + + Future playTrack(BuildContext context, Track track) async { + var yt = YoutubeExplode(); + PlayerProvider playerProvider = + Provider.of(context, listen: false); + HomeProvider homeProvider = + Provider.of(context, listen: false); + + // track = trackList[track.number - 1]; + currentTrack = track; + + final currentVolume = player?.volume ?? 1; + player?.dispose(); + Future.delayed(const Duration(milliseconds: 5)); + + if (track.file == null) { + 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; + } + player = Player.network( + "https://invidious.fdn.fr/embed/${track.id}?raw=1&?listen=1"); + print(track.id); + } else { + player = Player.asset(track.file!.path); + } + player!.volume = currentVolume; + + try { + player!.play(); + } catch (e) { + print('Play error: ' + e.toString()); + } + Future.delayed(const Duration(milliseconds: 500)); + player!.callback = (PlayerEvent event) { + if (event.name == 'position') { + currentTrack!.duration = player!.duration; + playerProvider.reload(); + } + if (event.name == 'status') { + var nextTrack = trackList + .firstWhere((element) => element.number == track.number + 1); + playTrack(context, nextTrack); + } + }; + + playerProvider.reload(); + homeProvider.reload(); + 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 filePath = await getDownloadsDirectory(); + final fileName = '${track.title} - ${track.artiste}' + .replaceAll('\\', '') + .replaceAll('/', '') + .replaceAll(':', '') + .replaceAll('*', '') + .replaceAll('?', '') + .replaceAll('"', '') + .replaceAll('<', '') + .replaceAll('>', '') + .replaceAll('|', ''); + var file = File('${filePath!.path}/$fileName.webm'); + var fileStream = file.openWrite(); + + await stream.pipe(fileStream); + + await fileStream.flush(); + await fileStream.close(); + yt.close(); + + // Play it + track.file = file; + // playTrack(context, track); + + print(file.path); + } + + List> get radioList { + List> menuItems = [ + const DropdownMenuItem(child: Text("FIP"), value: "fip"), + const DropdownMenuItem(child: Text("Electro"), value: "fip_electro"), + const DropdownMenuItem(child: Text("Groove"), value: "fip_groove"), + const DropdownMenuItem(child: Text("Rock"), value: "fip_rock"), + const DropdownMenuItem(child: Text("Jazz"), value: "fip_jazz"), + const DropdownMenuItem(child: Text("Pop"), value: "fip_pop"), + const DropdownMenuItem(child: Text("Reggae"), value: "fip_reggae"), + const DropdownMenuItem(child: Text("World"), value: "fip_world"), + const DropdownMenuItem( + child: Text("Nouveautés"), value: "fip_nouveautes"), + ]; + return menuItems; + } + + List> get pageList { + List> menuItems = [ + const DropdownMenuItem(child: Text("25"), value: "3"), + const DropdownMenuItem(child: Text("50"), value: "6"), + const DropdownMenuItem(child: Text("100"), value: "12"), + const DropdownMenuItem(child: Text("200"), value: "25"), + const DropdownMenuItem(child: Text("500"), value: "62"), + ]; + return menuItems; + } + void reload() { notifyListeners(); } @@ -10,4 +187,4 @@ class DownloadProvider with ChangeNotifier { void reload() { notifyListeners(); } -} \ No newline at end of file +} diff --git a/lib/screens/home.dart b/lib/screens/home.dart index 838ce16..ddf136d 100644 --- a/lib/screens/home.dart +++ b/lib/screens/home.dart @@ -1,26 +1,14 @@ // ignore_for_file: prefer_const_literals_to_create_immutables, avoid_print -import 'dart:io'; - -import 'package:fip_parser_ui/globals.dart'; +import 'dart:convert'; +import 'package:fip_parser_ui/models/track.dart'; import 'package:fip_parser_ui/providers/home.dart'; import 'package:fip_parser_ui/providers/player.dart'; import 'package:flutter/material.dart'; -import 'package:fip_parser_ui/queries.dart'; -import 'package:graphql/client.dart'; -import 'package:kplayer/kplayer.dart'; import 'package:miniplayer/miniplayer.dart'; -import 'package:path_provider/path_provider.dart'; import 'package:provider/provider.dart'; -import 'package:retry/retry.dart'; import 'package:youtube_explode_dart/youtube_explode_dart.dart'; -PlayerController? player; -Track? currentTrack; -List trackList = []; -String radio = 'groove'; -int isDownloading = -1; - class HomeScreen extends StatefulWidget { const HomeScreen({Key? key, required this.title}) : super(key: key); final String title; @@ -29,107 +17,147 @@ class HomeScreen extends StatefulWidget { } class _HomeScreenState extends State { + String radio = 'fip_groove'; + @override Widget build(BuildContext context) { + HomeProvider hp = Provider.of(context, listen: false); final MiniplayerController controller = MiniplayerController(); - const hours = 8; return Stack( children: [ Scaffold( - body: SingleChildScrollView( - child: Column( - children: [ - Container( - color: Colors.grey[900], - height: 50, - child: Center( - child: DropdownButton( - dropdownColor: Colors.grey[900], - value: radio, - style: TextStyle(fontSize: 15, color: Colors.grey[300]), - underline: const SizedBox(), - iconSize: 22, - onChanged: (String? newRadio) { - setState(() { - radio = newRadio!; - // getTracks(radio, hours); - }); - }, - items: radioList), - ), - ), - FutureBuilder>( - future: getTracks(radio, hours), - builder: ( - BuildContext context, - AsyncSnapshot> snapshot, - ) { - print(snapshot.connectionState); - if (snapshot.connectionState == ConnectionState.waiting) { - return Stack(children: [ - Container( - height: 10000, - width: 10000, - color: const Color(0xFF121212)), - Center( - child: Column(children: [ - const SizedBox(height: 20), - SizedBox( - height: 30, - width: 30, - child: CircularProgressIndicator( - color: Colors.amber[100], - ), - ), + body: RawScrollbar( + thumbColor: Colors.grey[600], + radius: const Radius.circular(20), + thickness: 12, + thumbVisibility: true, + mainAxisMargin: 70, + child: SingleChildScrollView( + child: Column( + children: [ + Container( + color: Colors.grey[900], + height: 50, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + DropdownButton( + dropdownColor: Colors.grey[900], + value: radio, + style: TextStyle( + fontSize: 15, color: Colors.grey[300]), + underline: const SizedBox(), + iconSize: 22, + onChanged: (String? newRadio) { + setState(() { + radio = newRadio!; + }); + }, + items: hp.radioList), + const SizedBox(width: 50), + DropdownButton( + dropdownColor: Colors.grey[900], + value: hp.userPageNbr.toString(), + style: TextStyle( + fontSize: 15, color: Colors.grey[300]), + underline: const SizedBox(), + iconSize: 22, + onChanged: (String? newPageNumber) { + setState(() { + hp.userPageNbr = int.parse(newPageNumber!); + }); + }, + items: hp.pageList), ]), - ), - ]); - } else if (snapshot.connectionState == - ConnectionState.done) { - if (snapshot.hasError) { - return const Text('Error'); - } else if (snapshot.hasData) { - return Table( - columnWidths: { - 0: const FlexColumnWidth(4), - 1: const FlexColumnWidth(2), - 2: const FlexColumnWidth(1), - }, - defaultVerticalAlignment: - TableCellVerticalAlignment.middle, - children: snapshot.data! - .map((item) => _buildTableRow(item, context)) - .toList() - ..insert( - 0, - _buildTableRow( - Track( - number: -1, - title: 'TITRE', - artiste: 'ARTISTE', - album: 'ALBUM', - id: 'URL'), - context), + ), + FutureBuilder>( + future: hp.getTracks(radio), + builder: ( + BuildContext context, + AsyncSnapshot> snapshot, + ) { + print(snapshot.connectionState); + if (snapshot.connectionState == + ConnectionState.waiting) { + return Stack(children: [ + Container( + height: 10000, + width: 10000, + color: const Color(0xFF121212)), + Center( + child: Column(children: [ + const SizedBox(height: 20), + SizedBox( + height: 30, + width: 30, + child: CircularProgressIndicator( + color: Colors.amber[100], + ), + ), + ]), ), - ); - } else { - return const Text('Empty data'); - } - } else { - return Text('State: ${snapshot.connectionState}'); - } - }, + ]); + } else if (snapshot.connectionState == + ConnectionState.done) { + if (snapshot.hasError) { + return Stack(children: [ + Container( + height: 10000, + width: 10000, + color: const Color(0xFF121212)), + Center( + child: Column(children: [ + const SizedBox(height: 20), + Text( + 'Error: ' + snapshot.error.toString(), + style: TextStyle(color: Colors.grey[500]), + ), + ]), + ), + ]); + } else if (snapshot.hasData) { + return Table( + columnWidths: { + 0: const FlexColumnWidth(4), + 1: const FlexColumnWidth(2), + 2: const FlexColumnWidth(1), + }, + defaultVerticalAlignment: + TableCellVerticalAlignment.middle, + children: snapshot.data! + .map((item) => _buildTableRow(item, context)) + .toList() + ..insert( + 0, + _buildTableRow( + Track( + number: -1, + title: 'TITRE', + artiste: 'ARTISTE', + album: 'ALBUM', + id: 'URL'), + context), + ), + ); + } else { + return const Text('Empty data'); + } + } else { + return Text('State: ${snapshot.connectionState}'); + } + }, + ), + const SizedBox(height: 70) + ], ), - ], - ), - ), + )), ), Consumer(builder: (context, playerProvider, _) { TextEditingController trackTitle = TextEditingController(); TextEditingController trackArtiste = TextEditingController(); - trackTitle.text = currentTrack?.title ?? ''; - trackArtiste.text = currentTrack?.artiste ?? ''; + trackTitle.text = hp.currentTrack?.title ?? ''; + trackArtiste.text = hp.currentTrack?.artiste ?? ''; return Miniplayer( controller: controller, backgroundColor: Colors.grey[900]!, @@ -139,12 +167,13 @@ class _HomeScreenState extends State { return Row( // mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - currentTrack?.id != null + hp.currentTrack?.imageUrl != '' && + hp.currentTrack?.imageUrl != null ? Image.network( - 'https://img.youtube.com/vi/${currentTrack?.id}/1.jpg', - width: 93, + hp.currentTrack!.imageUrl!, + width: 70, ) - : const SizedBox(width: 100), + : const SizedBox(width: 70), Expanded( child: Column(children: [ SizedBox( @@ -190,30 +219,33 @@ class _HomeScreenState extends State { Column(children: [ const Spacer(), Row(children: [ + const SizedBox(width: 70), Column(children: [ IconButton( + padding: const EdgeInsets.all(0), icon: Icon(Icons.skip_previous, color: Colors.grey[500], size: 32), onPressed: () { - if (currentTrack != null && - currentTrack!.number > 1) { - currentTrack = trackList.firstWhere((element) => - element.number == currentTrack!.number - 1); - playTrack(context, currentTrack!); + if (hp.currentTrack != null && + hp.currentTrack!.number > 1) { + hp.currentTrack = hp.trackList.firstWhere( + (element) => + element.number == + hp.currentTrack!.number - 1); + hp.playTrack(context, hp.currentTrack!); } }), - const SizedBox(height: 7), ]), - const SizedBox(width: 8), + const SizedBox(width: 1), ElevatedButton( onPressed: () { - player?.playing ?? false - ? player?.pause() - : player?.play(); + hp.player?.playing ?? false + ? hp.player?.pause() + : hp.player?.play(); playerProvider.reload(); }, child: Icon( - player?.playing ?? false + hp.player?.playing ?? false ? Icons.pause : Icons.play_arrow, color: Colors.grey[900], @@ -227,25 +259,29 @@ class _HomeScreenState extends State { ), Column(children: [ IconButton( + padding: const EdgeInsets.all(0), icon: Icon(Icons.skip_next, color: Colors.grey[500], size: 32), onPressed: () { - if (currentTrack != null && - currentTrack!.number < - trackList.last.number) { - currentTrack = trackList.firstWhere((element) => - element.number == currentTrack!.number + 1); - playTrack(context, currentTrack!); + 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(context, hp.currentTrack!); } }), - const SizedBox(height: 7), + // const SizedBox(height: 7), ]), ]), const Spacer(), Row(children: [ + const SizedBox(width: 70), Text( timeFormat( - player?.position ?? const Duration(seconds: 0)), + hp.player?.position ?? const Duration(seconds: 0)), style: TextStyle(color: Colors.grey[500], fontSize: 12), ), const SizedBox(width: 3), @@ -261,13 +297,14 @@ class _HomeScreenState extends State { width: 300, child: Slider( value: double.parse( - player?.position.inSeconds.toString() ?? '0'), + hp.player?.position.inSeconds.toString() ?? + '0'), max: double.parse( - player?.duration.inSeconds.toString() ?? + hp.player?.duration.inSeconds.toString() ?? '2000'), onChanged: (double value) { - if (player?.position != null) { - player!.position = + if (hp.player?.position != null) { + hp.player!.position = Duration(seconds: value.toInt()); playerProvider.reload(); } @@ -280,7 +317,7 @@ class _HomeScreenState extends State { const SizedBox(width: 3), Text( timeFormat( - player?.duration ?? const Duration(seconds: 0)), + hp.player?.duration ?? const Duration(seconds: 0)), style: TextStyle(color: Colors.grey[500], fontSize: 12), ), ]), @@ -297,11 +334,11 @@ class _HomeScreenState extends State { child: SizedBox( width: 130, child: Slider( - value: player?.volume ?? 1, + value: hp.player?.volume ?? 1, max: 1, onChanged: (double value) { - if (player?.volume != null) { - player!.volume = value; + if (hp.player?.volume != null) { + hp.player!.volume = value; playerProvider.reload(); } }, @@ -330,134 +367,11 @@ Widget trackLine(Track track) { ); } -class Track { - final int number; - final String title; - final String artiste; - final String? album; - String? id; - Duration? duration; - File? file; - - Track( - {required this.number, - required this.title, - required this.artiste, - this.album, - this.id, - this.duration, - this.file}); -} - -GraphQLClient initClient() { - final _httpLink = HttpLink( - 'https://openapi.radiofrance.fr/v1/graphql?x-token=$token', - ); - - final GraphQLClient client = GraphQLClient( - cache: GraphQLCache(), - link: _httpLink, - ); - - return client; -} - -Future> getTracks(String radio, int hours) async { - // TODO: Change API to one use on website: https://www.radiofrance.fr/api/v1.7/stations/fip/webradios/fip_groove/songs?pageCursor= - const int queryTimeout = 8; - - final client = initClient(); - - final now = (DateTime.now().millisecondsSinceEpoch ~/ 1000); - final yesterday = now - (hours * 3600); - final String radioQuery; - if (radio == 'fip') { - radioQuery = 'FIP'; - } else { - radioQuery = 'FIP_${radio.toUpperCase()}'; - } - - final QueryOptions options = QueryOptions( - document: gql(getSongs), - pollInterval: const Duration(milliseconds: 50), - variables: { - 'start': yesterday, - 'end': now, - 'radio': radioQuery, - }, - ); - - QueryResult result; - result = await retry( - () async => await client - .query(options) - .timeout(const Duration(seconds: queryTimeout)), - onRetry: (_) => print('Timeout, retry...'), - ); - - if (result.hasException) { - print(result.exception.toString()); - } - - final List data = result.data?['grid'] ?? []; - print(data.length.toString() + ' songs'); - - // ####### - - int trackNbr = 0; - - trackList.clear(); - // final yt = YoutubeExplode(); - // List resultUrlPool = []; - - for (Map track in data) { - track = track['track']; - trackNbr++; - final String title = track['title']; - final String artiste; - if (track['mainArtists'].isNotEmpty) { - artiste = track['mainArtists'].first; - } else { - artiste = ''; - } - final String album = track['albumTitle']; - - final thisTrack = - Track(number: trackNbr, title: title, artiste: artiste, album: album); - trackList.add(thisTrack); - - // final secondMatch = artiste == '' ? album : artiste; - // final resultUrl = yt.search.search(title + ' ' + secondMatch); - - // resultUrlPool.add(resultUrl); - - // resultUrl.then((value) { - // try { - // trackList[trackNbr - 1].id = value.first.id.value; - // } catch (e) { - // print( - // 'Error: ' + trackList[trackNbr - 1].title + ' -> ' + e.toString()); - // } - // }); - } - - // trackList.sort((a, b) => a.number.compareTo(b.number)); - - // final secondMatch = - // trackList[0].artiste == '' ? trackList[0].album : trackList[0].artiste; - // yt.search.search(trackList[0].title + ' ' + secondMatch!).then((resultUrl) { - // trackList[0].id = resultUrl.first.id.value; - - // player = Player.network( - // "https://invidious.fdn.fr/embed/${trackList[0].id}?raw=1&?listen=1"); - // currentTrack = trackList[0]; - // }); - return trackList; -} - TableRow _buildTableRow(Track track, BuildContext context) { DownloadProvider downloadProvider = Provider.of(context, listen: false); + HomeProvider hp = Provider.of(context, listen: false); + int isDownloading = -1; final textStyle = TextStyle( fontWeight: track.number == -1 ? FontWeight.w200 : FontWeight.normal, @@ -477,30 +391,38 @@ TableRow _buildTableRow(Track track, BuildContext context) { child: InkWell( onTap: () async { if (track.number != -1) { - playTrack(context, track); + hp.playTrack(context, track); } }, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Consumer( - builder: (context, playerProvider, _) { - return Text(track.title, - style: TextStyle( - fontWeight: FontWeight.normal, - color: currentTrack == track - ? Colors.green - : Colors.grey[350], - fontSize: 14)); - }), - const SizedBox(height: 5), - if (track.number != -1) - Text(track.artiste, - style: TextStyle( - fontWeight: FontWeight.normal, - color: Colors.grey[500], - fontSize: 13)) - ]), + child: Row(children: [ + track.number != -1 + ? track.image == '' + ? const SizedBox(width: 40) + : Image.memory(base64Decode(track.image!), height: 40) + : const SizedBox(), + const SizedBox(width: 10), + Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Consumer( + builder: (context, playerProvider, _) { + return Text(track.title, + style: TextStyle( + fontWeight: FontWeight.normal, + color: hp.currentTrack == track + ? Colors.green + : Colors.grey[350], + fontSize: 14)); + }), + const SizedBox(height: 2), + if (track.number != -1) + Text(track.artiste, + style: TextStyle( + fontWeight: FontWeight.normal, + color: Colors.grey[500], + fontSize: 13)) + ]), + ]), )), ), TableCell( @@ -524,7 +446,7 @@ TableRow _buildTableRow(Track track, BuildContext context) { track.id = resultUrl.first.id.value; } if (track.id != null) { - downloadMusic(context, track); + hp.downloadMusic(context, track); } isDownloading = -1; yt.close(); @@ -552,118 +474,6 @@ TableRow _buildTableRow(Track track, BuildContext context) { ]); } -Future playTrack(BuildContext context, Track track) async { - var yt = YoutubeExplode(); - PlayerProvider playerProvider = - Provider.of(context, listen: false); - HomeProvider homeProvider = Provider.of(context, listen: false); - - // track = trackList[track.number - 1]; - currentTrack = track; - - final currentVolume = player?.volume ?? 1; - player?.dispose(); - Future.delayed(const Duration(milliseconds: 5)); - - if (track.file == null) { - 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; - } - player = Player.network( - "https://invidious.fdn.fr/embed/${track.id}?raw=1&?listen=1"); - print(track.id); - } else { - player = Player.asset(track.file!.path); - } - player!.volume = currentVolume; - - try { - player!.play(); - } catch (e) { - print('Play error: ' + e.toString()); - } - Future.delayed(const Duration(milliseconds: 500)); - player!.callback = (PlayerEvent event) { - if (event.name == 'position') { - currentTrack!.duration = player!.duration; - playerProvider.reload(); - } - if (event.name == 'status') { - var nextTrack = - trackList.firstWhere((element) => element.number == track.number + 1); - playTrack(context, nextTrack); - } - }; - - playerProvider.reload(); - homeProvider.reload(); - 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 filePath = await getDownloadsDirectory(); - final fileName = '${track.title} - ${track.artiste}' - .replaceAll('\\', '') - .replaceAll('/', '') - .replaceAll(':', '') - .replaceAll('*', '') - .replaceAll('?', '') - .replaceAll('"', '') - .replaceAll('<', '') - .replaceAll('>', '') - .replaceAll('|', ''); - var file = File('${filePath!.path}/$fileName.webm'); - var fileStream = file.openWrite(); - - await stream.pipe(fileStream); - - await fileStream.flush(); - await fileStream.close(); - yt.close(); - - // Play it - track.file = file; - // playTrack(context, track); - - print(file.path); -} - -// final radioList = [ -// 'fip', -// 'electro', -// 'groove', -// 'rock', -// 'jazz', -// 'pop', -// 'reggae', -// 'world', -// 'nouveautes', -// ]; - -List> get radioList { - List> menuItems = [ - const DropdownMenuItem(child: Text("FIP"), value: "fip"), - const DropdownMenuItem(child: Text("Electro"), value: "electro"), - const DropdownMenuItem(child: Text("Groove"), value: "groove"), - const DropdownMenuItem(child: Text("Rock"), value: "rock"), - const DropdownMenuItem(child: Text("Jazz"), value: "jazz"), - const DropdownMenuItem(child: Text("Pop"), value: "pop"), - const DropdownMenuItem(child: Text("Reggae"), value: "reggae"), - const DropdownMenuItem(child: Text("World"), value: "world"), - const DropdownMenuItem(child: Text("Nouveautes"), value: "nouveautes"), - ]; - return menuItems; -} - String timeFormat(Duration d) { String dd = d.toString().split('.').first; String minutes = dd.toString().split(':')[1]; diff --git a/pubspec.lock b/pubspec.lock index 772d782..ade492c 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -56,7 +56,7 @@ packages: name: collection url: "https://pub.dartlang.org" source: hosted - version: "1.15.0" + version: "1.16.0" crypto: dependency: transitive description: @@ -98,7 +98,7 @@ packages: name: fake_async url: "https://pub.dartlang.org" source: hosted - version: "1.2.0" + version: "1.3.0" ffi: dependency: transitive description: @@ -142,69 +142,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" - gql: - dependency: transitive - description: - name: gql - url: "https://pub.dartlang.org" - source: hosted - version: "0.13.1" - gql_dedupe_link: - dependency: transitive - description: - name: gql_dedupe_link - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.2" - gql_error_link: - dependency: transitive - description: - name: gql_error_link - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.2" - gql_exec: - dependency: transitive - description: - name: gql_exec - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.0" - gql_http_link: - dependency: transitive - description: - name: gql_http_link - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - gql_link: - dependency: transitive - description: - name: gql_link - url: "https://pub.dartlang.org" - source: hosted - version: "0.4.2" - gql_transform_link: - dependency: transitive - description: - name: gql_transform_link - url: "https://pub.dartlang.org" - source: hosted - version: "0.2.2" - graphql: - dependency: "direct main" - description: - name: graphql - url: "https://pub.dartlang.org" - source: hosted - version: "5.1.1" - hive: - dependency: transitive - description: - name: hive - url: "https://pub.dartlang.org" - source: hosted - version: "2.1.0" html: dependency: transitive description: @@ -232,7 +169,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.3" + version: "0.6.4" json_annotation: dependency: transitive description: @@ -309,7 +246,7 @@ packages: name: material_color_utilities url: "https://pub.dartlang.org" source: hosted - version: "0.1.3" + version: "0.1.4" meta: dependency: transitive description: @@ -333,20 +270,13 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.0.0" - normalize: - dependency: transitive - description: - name: normalize - url: "https://pub.dartlang.org" - source: hosted - version: "0.6.0+1" path: dependency: transitive description: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.0" + version: "1.8.1" path_provider: dependency: "direct main" description: @@ -431,13 +361,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "6.0.2" - retry: - dependency: "direct main" - description: - name: retry - url: "https://pub.dartlang.org" - source: hosted - version: "3.1.0" rxdart: dependency: transitive description: @@ -456,7 +379,7 @@ packages: name: source_span url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.2" stack_trace: dependency: transitive description: @@ -491,7 +414,7 @@ packages: name: test_api url: "https://pub.dartlang.org" source: hosted - version: "0.4.8" + version: "0.4.9" typed_data: dependency: transitive description: @@ -568,14 +491,7 @@ packages: name: vector_math url: "https://pub.dartlang.org" source: hosted - version: "2.1.1" - web_socket_channel: - dependency: transitive - description: - name: web_socket_channel - url: "https://pub.dartlang.org" - source: hosted - version: "2.2.0" + version: "2.1.2" win32: dependency: transitive description: @@ -605,5 +521,5 @@ packages: source: hosted version: "1.11.0" sdks: - dart: ">=2.16.2 <3.0.0" + dart: ">=2.17.0-0 <3.0.0" flutter: ">=2.10.0" diff --git a/pubspec.yaml b/pubspec.yaml index fd55baf..6d1f799 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -11,9 +11,7 @@ dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 - graphql: ^5.0.0 youtube_explode_dart: ^1.10.9+1 - retry: ^3.1.0 url_launcher: ^6.1.0 http: ^0.13.4 kplayer: ^0.1.12 diff --git a/windows/flutter/generated_plugins.cmake b/windows/flutter/generated_plugins.cmake index 523e4c3..6a28a60 100644 --- a/windows/flutter/generated_plugins.cmake +++ b/windows/flutter/generated_plugins.cmake @@ -7,6 +7,9 @@ list(APPEND FLUTTER_PLUGIN_LIST url_launcher_windows ) +list(APPEND FLUTTER_FFI_PLUGIN_LIST +) + set(PLUGIN_BUNDLED_LIBRARIES) foreach(plugin ${FLUTTER_PLUGIN_LIST}) @@ -15,3 +18,8 @@ foreach(plugin ${FLUTTER_PLUGIN_LIST}) list(APPEND PLUGIN_BUNDLED_LIBRARIES $) list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${plugin}_bundled_libraries}) endforeach(plugin) + +foreach(ffi_plugin ${FLUTTER_FFI_PLUGIN_LIST}) + add_subdirectory(flutter/ephemeral/.plugin_symlinks/${ffi_plugin}/windows plugins/${ffi_plugin}) + list(APPEND PLUGIN_BUNDLED_LIBRARIES ${${ffi_plugin}_bundled_libraries}) +endforeach(ffi_plugin)