2022-04-30 01:48:17 +02:00
|
|
|
// ignore_for_file: avoid_print
|
|
|
|
|
|
|
|
import 'dart:convert';
|
|
|
|
import 'dart:io';
|
|
|
|
import 'package:fip_parser_ui/models/track.dart';
|
2022-04-28 21:24:26 +02:00
|
|
|
import 'package:flutter/material.dart';
|
2022-04-30 01:48:17 +02:00
|
|
|
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';
|
2022-04-28 21:24:26 +02:00
|
|
|
|
|
|
|
class HomeProvider with ChangeNotifier {
|
2022-04-30 01:48:17 +02:00
|
|
|
Track? currentTrack;
|
|
|
|
PlayerController? player;
|
|
|
|
List<Track> trackList = [];
|
|
|
|
int trackNbr = 0;
|
|
|
|
int userPageNbr = 3;
|
|
|
|
|
|
|
|
Future<List<Track>> 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<PlayerProvider>(context, listen: false);
|
|
|
|
HomeProvider homeProvider =
|
|
|
|
Provider.of<HomeProvider>(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<DropdownMenuItem<String>> get radioList {
|
|
|
|
List<DropdownMenuItem<String>> 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<DropdownMenuItem<String>> get pageList {
|
|
|
|
List<DropdownMenuItem<String>> 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;
|
|
|
|
}
|
|
|
|
|
2022-04-28 21:24:26 +02:00
|
|
|
void reload() {
|
|
|
|
notifyListeners();
|
|
|
|
}
|
|
|
|
}
|
2022-04-29 12:18:26 +02:00
|
|
|
|
|
|
|
class DownloadProvider with ChangeNotifier {
|
|
|
|
void reload() {
|
|
|
|
notifyListeners();
|
|
|
|
}
|
2022-04-30 01:48:17 +02:00
|
|
|
}
|