Advertisement
Guest User

Untitled

a guest
Feb 17th, 2021
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 31.63 KB | None | 0 0
  1. import 'dart:async';
  2. import 'package:BlackHole/playlist.dart';
  3. import 'package:http/http.dart';
  4. import 'dart:math';
  5. import 'dart:convert';
  6. import 'package:des_plugin/des_plugin.dart';
  7. import 'package:audio_service/audio_service.dart';
  8. import 'package:audio_session/audio_session.dart';
  9. import 'package:flutter/foundation.dart';
  10. import 'package:flutter/material.dart';
  11. import 'package:just_audio/just_audio.dart';
  12. import 'package:rxdart/rxdart.dart';
  13.  
  14. class TempScreen extends StatelessWidget {
  15. @override
  16. Widget build(BuildContext context) {
  17. return Container(
  18. decoration: BoxDecoration(
  19. gradient: LinearGradient(
  20. begin: Alignment.topLeft,
  21. end: Alignment.bottomRight,
  22. // stops: [0, 0.2, 0.8, 1],
  23. colors: Theme.of(context).brightness == Brightness.dark
  24. ? [
  25. Colors.grey[850],
  26. Colors.grey[900],
  27. Colors.black,
  28. ]
  29. : [
  30. Colors.white,
  31. Theme.of(context).canvasColor,
  32. ],
  33. ),
  34. ),
  35. child: Scaffold(
  36. backgroundColor: Colors.transparent,
  37. // appBar: AppBar(
  38. // title: Text('Now Playing'),
  39. // centerTitle: true,
  40. // ),
  41. body: SafeArea(
  42. child: SingleChildScrollView(
  43. child: StreamBuilder<bool>(
  44. stream: AudioService.runningStream,
  45. builder: (context, snapshot) {
  46. if (snapshot.connectionState != ConnectionState.active) {
  47. return SizedBox();
  48. }
  49. final running = snapshot.data ?? false;
  50. return Column(
  51. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  52. children: [
  53. if (!running) ...[
  54. audioPlayerButton(),
  55. ] else ...[
  56. Container(
  57. height: MediaQuery.of(context).size.height * 0.0725,
  58. child: Row(
  59. children: [
  60. IconButton(
  61. icon: Icon(Icons.keyboard_arrow_down_rounded),
  62. onPressed: () {
  63. Navigator.pop(context);
  64. }),
  65. ],
  66. ),
  67. ),
  68. Container(
  69. height: MediaQuery.of(context).size.width * 0.925,
  70. child: Hero(
  71. tag: 'image',
  72. child: Card(
  73. elevation: 10,
  74. shape: RoundedRectangleBorder(
  75. borderRadius: BorderRadius.circular(15)),
  76. clipBehavior: Clip.antiAlias,
  77. child: Stack(
  78. children: [
  79. Image(
  80. image: AssetImage('assets/cover.jpg'),
  81. height:
  82. MediaQuery.of(context).size.width * 0.925,
  83. ),
  84. StreamBuilder<QueueState>(
  85. stream: _queueStateStream,
  86. builder: (context, snapshot) {
  87. final queueState = snapshot.data;
  88. // final queue = queueState?.queue ?? [];
  89. final mediaItem = queueState?.mediaItem;
  90. return mediaItem == null
  91. ? Image(
  92. image: AssetImage(
  93. 'assets/cover.jpg'),
  94. height: MediaQuery.of(context)
  95. .size
  96. .width *
  97. 0.925,
  98. )
  99. : Image(
  100. image: NetworkImage(
  101. mediaItem.artUri),
  102. height: MediaQuery.of(context)
  103. .size
  104. .width *
  105. 0.925,
  106. );
  107. }),
  108. ],
  109. ),
  110. ),
  111. ),
  112. ),
  113.  
  114. //Title and subtitle
  115.  
  116. Container(
  117. height: (MediaQuery.of(context).size.height * 0.9 -
  118. MediaQuery.of(context).size.width * 0.925) /
  119. 3,
  120. child: Padding(
  121. padding: const EdgeInsets.fromLTRB(15, 25, 15, 0),
  122. child: StreamBuilder<QueueState>(
  123. stream: _queueStateStream,
  124. builder: (context, snapshot) {
  125. final queueState = snapshot.data;
  126. final mediaItem = queueState?.mediaItem;
  127. return Column(
  128. mainAxisAlignment: MainAxisAlignment.end,
  129. children: [
  130. // Title container
  131. Container(
  132. height:
  133. (MediaQuery.of(context).size.height *
  134. 0.9 -
  135. MediaQuery.of(context)
  136. .size
  137. .width *
  138. 0.925) *
  139. 2 /
  140. 14.0,
  141. child: FittedBox(
  142. child: Text(
  143. (mediaItem?.title != null)
  144. ? (mediaItem.title)
  145. : 'Unknown',
  146. textAlign: TextAlign.center,
  147. style: TextStyle(
  148. fontSize: 50,
  149. fontWeight: FontWeight.bold,
  150. color:
  151. Theme.of(context).accentColor),
  152. )),
  153. ),
  154.  
  155. //Subtitle container
  156. Container(
  157. height:
  158. (MediaQuery.of(context).size.height *
  159. 0.9 -
  160. MediaQuery.of(context)
  161. .size
  162. .width *
  163. 0.925) *
  164. 1 /
  165. 16.0,
  166. child: Text(
  167. (mediaItem?.artist != null)
  168. ? (mediaItem.artist)
  169. : 'Unknown',
  170. textAlign: TextAlign.center,
  171. style: TextStyle(
  172. fontWeight: FontWeight.w500),
  173. overflow: TextOverflow.ellipsis,
  174. ),
  175. ),
  176. ],
  177. );
  178. }),
  179. ),
  180. ),
  181. //Seekbar starts from here
  182. Container(
  183. height: (MediaQuery.of(context).size.height * 0.9 -
  184. MediaQuery.of(context).size.width * 0.925) /
  185. 3.5,
  186. child: Column(
  187. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  188. children: [
  189. StreamBuilder<MediaState>(
  190. stream: _mediaStateStream,
  191. builder: (context, snapshot) {
  192. final mediaState = snapshot.data;
  193.  
  194. return SeekBar(
  195. duration: mediaState?.mediaItem?.duration ??
  196. Duration.zero,
  197. position:
  198. mediaState?.position ?? Duration.zero,
  199. onChangeEnd: (newPosition) {
  200. AudioService.seekTo(newPosition);
  201. },
  202. );
  203. },
  204. ),
  205. ],
  206. ),
  207. ),
  208.  
  209. Container(
  210. height: (MediaQuery.of(context).size.height * 0.9 -
  211. MediaQuery.of(context).size.width * 0.925) /
  212. 3,
  213. child: Row(
  214. mainAxisAlignment: MainAxisAlignment.spaceEvenly,
  215. crossAxisAlignment: CrossAxisAlignment.center,
  216. children: [
  217. StreamBuilder<QueueState>(
  218. stream: _queueStateStream,
  219. builder: (context, snapshot) {
  220. final queueState = snapshot.data;
  221. final queue = queueState?.queue ?? [];
  222. final mediaItem = queueState?.mediaItem;
  223. return (queue != null && queue.isNotEmpty)
  224. ? IconButton(
  225. icon: Icon(Icons.skip_previous_rounded),
  226. iconSize: 45.0,
  227. onPressed: mediaItem == queue.first
  228. ? null
  229. : AudioService.skipToPrevious,
  230. )
  231. : IconButton(
  232. icon: Icon(Icons.skip_previous_rounded),
  233. iconSize: 45.0,
  234. onPressed: null);
  235. },
  236. ),
  237. Stack(
  238. children: [
  239. Center(
  240. child: StreamBuilder<AudioProcessingState>(
  241. stream: AudioService.playbackStateStream
  242. .map((state) => state.processingState)
  243. .distinct(),
  244. builder: (context, snapshot) {
  245. final processingState = snapshot.data ??
  246. AudioProcessingState.none;
  247. return describeEnum(processingState) !=
  248. 'ready'
  249. ? SizedBox(
  250. height: 65,
  251. width: 65,
  252. child:
  253. CircularProgressIndicator(),
  254. )
  255. : SizedBox();
  256. },
  257. ),
  258. ),
  259. Center(
  260. child: StreamBuilder<bool>(
  261. stream: AudioService.playbackStateStream
  262. .map((state) => state.playing)
  263. .distinct(),
  264. builder: (context, snapshot) {
  265. final playing = snapshot.data ?? false;
  266. return Container(
  267. height: 65,
  268. width: 65,
  269. child: Center(
  270. child: SizedBox(
  271. height: 59,
  272. width: 59,
  273. child: playing
  274. ? pauseButton()
  275. : playButton(),
  276. ),
  277. ),
  278. );
  279. },
  280. ),
  281. ),
  282. ],
  283. ),
  284. // Queue display/controls.
  285. StreamBuilder<QueueState>(
  286. stream: _queueStateStream,
  287. builder: (context, snapshot) {
  288. final queueState = snapshot.data;
  289. final queue = queueState?.queue ?? [];
  290. final mediaItem = queueState?.mediaItem;
  291. return (queue != null && queue.isNotEmpty)
  292. ? IconButton(
  293. icon: Icon(Icons.skip_next_rounded),
  294. iconSize: 45.0,
  295. onPressed: mediaItem == queue.last
  296. ? null
  297. : AudioService.skipToNext,
  298. )
  299. : IconButton(
  300. icon: Icon(Icons.skip_next_rounded),
  301. iconSize: 45.0,
  302. onPressed: null);
  303. },
  304. ),
  305. ],
  306. ),
  307. ),
  308. ],
  309. ],
  310. );
  311. },
  312. ),
  313. ),
  314. ),
  315. ),
  316. );
  317. }
  318.  
  319. /// A stream reporting the combined state of the current media item and its
  320. /// current position.
  321. Stream<MediaState> get _mediaStateStream =>
  322. Rx.combineLatest2<MediaItem, Duration, MediaState>(
  323. AudioService.currentMediaItemStream,
  324. AudioService.positionStream,
  325. (mediaItem, position) => MediaState(mediaItem, position));
  326.  
  327. /// A stream reporting the combined state of the current queue and the current
  328. /// media item within that queue.
  329. Stream<QueueState> get _queueStateStream =>
  330. Rx.combineLatest2<List<MediaItem>, MediaItem, QueueState>(
  331. AudioService.queueStream,
  332. AudioService.currentMediaItemStream,
  333. (queue, mediaItem) => QueueState(queue, mediaItem));
  334.  
  335. audioPlayerButton() {
  336. AudioService.start(
  337. backgroundTaskEntrypoint: _audioPlayerTaskEntrypoint,
  338. androidNotificationChannelName: 'Audio Service Demo',
  339. androidNotificationColor: 0xFF2196f3,
  340. androidNotificationIcon: 'mipmap/ic_launcher',
  341. androidEnableQueue: true,
  342. );
  343. List<MediaItem> queue = MediaLibrary().items;
  344. print('queue is $queue');
  345. AudioService.updateQueue(queue);
  346. AudioService.setRepeatMode(AudioServiceRepeatMode.none);
  347. AudioService.setShuffleMode(AudioServiceShuffleMode.none);
  348. AudioService.play();
  349. }
  350.  
  351. FloatingActionButton playButton() => FloatingActionButton(
  352. elevation: 10,
  353. child: Icon(
  354. Icons.play_arrow_rounded,
  355. size: 40.0,
  356. color: Colors.white,
  357. ),
  358. onPressed: AudioService.play,
  359. );
  360.  
  361. FloatingActionButton pauseButton() => FloatingActionButton(
  362. elevation: 10,
  363. child: Icon(
  364. Icons.pause_rounded,
  365. color: Colors.white,
  366. size: 40.0,
  367. ),
  368. onPressed: AudioService.pause,
  369. );
  370.  
  371. // IconButton stopButton() => IconButton(
  372. // icon: Icon(Icons.stop),
  373. // iconSize: 64.0,
  374. // onPressed: AudioService.stop,
  375. // );
  376. }
  377.  
  378. class QueueState {
  379. final List<MediaItem> queue;
  380. final MediaItem mediaItem;
  381.  
  382. QueueState(this.queue, this.mediaItem);
  383. }
  384.  
  385. class MediaState {
  386. final MediaItem mediaItem;
  387. final Duration position;
  388.  
  389. MediaState(this.mediaItem, this.position);
  390. }
  391.  
  392. class SeekBar extends StatefulWidget {
  393. final Duration duration;
  394. final Duration position;
  395. final ValueChanged<Duration> onChanged;
  396. final ValueChanged<Duration> onChangeEnd;
  397.  
  398. SeekBar({
  399. @required this.duration,
  400. @required this.position,
  401. this.onChanged,
  402. this.onChangeEnd,
  403. });
  404.  
  405. @override
  406. _SeekBarState createState() => _SeekBarState();
  407. }
  408.  
  409. class _SeekBarState extends State<SeekBar> {
  410. double _dragValue;
  411. bool _dragging = false;
  412.  
  413. @override
  414. Widget build(BuildContext context) {
  415. final value = min(_dragValue ?? widget.position?.inMilliseconds?.toDouble(),
  416. widget.duration.inMilliseconds.toDouble());
  417. if (_dragValue != null && !_dragging) {
  418. _dragValue = null;
  419. }
  420. return Column(
  421. children: [
  422. Slider(
  423. min: 0.0,
  424. max: widget.duration.inMilliseconds.toDouble(),
  425. value: value,
  426. activeColor: Theme.of(context).accentColor,
  427. inactiveColor: Theme.of(context).backgroundColor,
  428. onChanged: (value) {
  429. if (!_dragging) {
  430. _dragging = true;
  431. }
  432. setState(() {
  433. _dragValue = value;
  434. });
  435. if (widget.onChanged != null) {
  436. widget.onChanged(Duration(milliseconds: value.round()));
  437. }
  438. },
  439. onChangeEnd: (value) {
  440. if (widget.onChangeEnd != null) {
  441. widget.onChangeEnd(Duration(milliseconds: value.round()));
  442. }
  443. _dragging = false;
  444. },
  445. ),
  446. Row(
  447. mainAxisAlignment: MainAxisAlignment.spaceBetween,
  448. children: [
  449. Padding(
  450. padding: const EdgeInsets.only(left: 20.0),
  451. child: Text(
  452. RegExp(r'((^0*[1-9]\d*:)?\d{2}:\d{2})\.\d+$')
  453. .firstMatch("$_position")
  454. ?.group(1) ??
  455. '$_position',
  456. // style: Theme.of(context).textTheme.caption,
  457. ),
  458. ),
  459. Padding(
  460. padding: const EdgeInsets.only(right: 20.0),
  461. child: Text(
  462. RegExp(r'((^0*[1-9]\d*:)?\d{2}:\d{2})\.\d+$')
  463. .firstMatch("$_duration")
  464. ?.group(1) ??
  465. '$_duration',
  466. // style: Theme.of(context).textTheme.caption,
  467. ),
  468. ),
  469. ],
  470. ),
  471. ],
  472. );
  473. }
  474.  
  475. // Duration get _remaining => widget.duration - widget.position;
  476. Duration get _position => widget.position;
  477. Duration get _duration => widget.duration;
  478. }
  479.  
  480. void _audioPlayerTaskEntrypoint() async {
  481. AudioServiceBackground.run(() => AudioPlayerTask());
  482. }
  483.  
  484. class AudioPlayerTask extends BackgroundAudioTask {
  485. final _mediaLibrary = MediaLibrary();
  486. AudioPlayer _player = new AudioPlayer();
  487. // AudioProcessingState _skipState;
  488. Seeker _seeker;
  489. StreamSubscription<PlaybackEvent> _eventSubscription;
  490. String kUrl = '';
  491. String key = "38346591";
  492. String decrypt = "";
  493. String preferredQuality = '320';
  494. List<MediaItem> get queue => _mediaLibrary.items;
  495. int get index => _player.currentIndex == null ? 0 : _player.currentIndex;
  496. MediaItem get mediaItem => index == null ? null : queue[index];
  497.  
  498. fetchSongUrl(songId) async {
  499. print('starting fetching url');
  500. String songUrl =
  501. "https://www.jiosaavn.com/api.php?app_version=5.18.3&api_version=4&readable_version=5.18.3&v=79&_format=json&__call=song.getDetails&pids=" +
  502. songId;
  503. var res = await get(songUrl, headers: {"Accept": "application/json"});
  504. var resEdited = (res.body).split("-->");
  505. var getMain = jsonDecode(resEdited[1]);
  506. kUrl = await DesPlugin.decrypt(
  507. key, getMain[songId]["more_info"]["encrypted_media_url"]);
  508. kUrl = kUrl.replaceAll('96', '$preferredQuality');
  509. print('fetched url');
  510. return kUrl;
  511. }
  512.  
  513. @override
  514. Future<void> onStart(Map<String, dynamic> params) async {
  515. final session = await AudioSession.instance;
  516. await session.configure(AudioSessionConfiguration.speech());
  517. // Broadcast media item changes.
  518. _player.currentIndexStream.listen((index) {
  519. if (index != null) AudioServiceBackground.setMediaItem(queue[index]);
  520. });
  521. // Propagate all events from the audio player to AudioService clients.
  522. _eventSubscription = _player.playbackEventStream.listen((event) {
  523. _broadcastState();
  524. });
  525. // Special processing for state transitions.
  526. _player.processingStateStream.listen((state) {
  527. switch (state) {
  528. case ProcessingState.completed:
  529. // In this example, the service stops when reaching the end.
  530. // onStop();
  531. onSkipToQueueItem(queue[index + 1].id);
  532. break;
  533. case ProcessingState.ready:
  534. // If we just came from skipping between tracks, clear the skip
  535. // state now that we're ready to play.
  536. // _skipState = null;
  537. break;
  538. default:
  539. break;
  540. }
  541. });
  542.  
  543. // Load and broadcast the queue
  544. // AudioServiceBackground.setQueue(queue);
  545. print('queue is');
  546. print(queue);
  547. print('Index is $index');
  548. print('MediaItem is');
  549. print(queue[index]);
  550. // print(queue[index + 1]);
  551. try {
  552. if (queue[index].extras == null) {
  553. queue[index] = queue[index].copyWith(extras: {
  554. 'URL': await fetchSongUrl(queue[index].id),
  555. });
  556. }
  557.  
  558. await AudioServiceBackground.setQueue(queue);
  559. await _player.setUrl(queue[index].extras['URL']);
  560. onPlay();
  561. // await _player.setAudioSource(ConcatenatingAudioSource(
  562. // children:
  563. // queue.map((item) => AudioSource.uri(Uri.parse(item.id))).toList(),
  564. // ));
  565. // onPlay();
  566. } catch (e) {
  567. print("Error: $e");
  568. onStop();
  569. }
  570. }
  571.  
  572. @override
  573. Future<void> onSkipToQueueItem(String mediaId) async {
  574. // Then default implementations of onSkipToNext and onSkipToPrevious will
  575. // delegate to this method.
  576. final newIndex = queue.indexWhere((item) => item.id == mediaId);
  577. if (newIndex == -1) return;
  578. _player.pause();
  579. if (queue[newIndex].extras == null) {
  580. queue[newIndex] = queue[newIndex].copyWith(extras: {
  581. 'URL': await fetchSongUrl(queue[newIndex].id),
  582. });
  583. await AudioServiceBackground.setQueue(queue);
  584. // AudioService.updateQueue(queue);
  585. }
  586. await _player.setUrl(queue[newIndex].extras['URL']);
  587. _player.play();
  588. await AudioServiceBackground.setMediaItem(queue[newIndex]);
  589.  
  590. // _skipState = newIndex > index
  591. // ? AudioProcessingState.skippingToNext
  592. // : AudioProcessingState.skippingToPrevious;
  593. // This jumps to the beginning of the queue item at newIndex.
  594. // _player.seek(Duration.zero, index: newIndex);
  595. // Demonstrate custom events.
  596. // AudioServiceBackground.sendCustomEvent('skip to $newIndex');
  597. }
  598.  
  599. @override
  600. Future<void> onUpdateQueue(List<MediaItem> queue) {
  601. AudioServiceBackground.setQueue(queue = queue);
  602. return super.onUpdateQueue(queue);
  603. }
  604.  
  605. @override
  606. Future<void> onPlay() => _player.play();
  607.  
  608. @override
  609. Future<void> onPause() => _player.pause();
  610.  
  611. @override
  612. Future<void> onSeekTo(Duration position) => _player.seek(position);
  613.  
  614. @override
  615. Future<void> onFastForward() => _seekRelative(fastForwardInterval);
  616.  
  617. @override
  618. Future<void> onRewind() => _seekRelative(-rewindInterval);
  619.  
  620. @override
  621. Future<void> onSeekForward(bool begin) async => _seekContinuously(begin, 1);
  622.  
  623. @override
  624. Future<void> onSeekBackward(bool begin) async => _seekContinuously(begin, -1);
  625.  
  626. @override
  627. Future<void> onStop() async {
  628. await _player.dispose();
  629. _eventSubscription.cancel();
  630. // It is important to wait for this state to be broadcast before we shut
  631. // down the task. If we don't, the background task will be destroyed before
  632. // the message gets sent to the UI.
  633. await _broadcastState();
  634. // Shut down this task
  635. await super.onStop();
  636. }
  637.  
  638. /// Jumps away from the current position by [offset].
  639. Future<void> _seekRelative(Duration offset) async {
  640. var newPosition = _player.position + offset;
  641. // Make sure we don't jump out of bounds.
  642. if (newPosition < Duration.zero) newPosition = Duration.zero;
  643. if (newPosition > mediaItem.duration) newPosition = mediaItem.duration;
  644. // Perform the jump via a seek.
  645. await _player.seek(newPosition);
  646. }
  647.  
  648. /// Begins or stops a continuous seek in [direction]. After it begins it will
  649. /// continue seeking forward or backward by 10 seconds within the audio, at
  650. /// intervals of 1 second in app time.
  651. void _seekContinuously(bool begin, int direction) {
  652. _seeker?.stop();
  653. if (begin) {
  654. _seeker = Seeker(_player, Duration(seconds: 10 * direction),
  655. Duration(seconds: 1), mediaItem)
  656. ..start();
  657. }
  658. }
  659.  
  660. /// Broadcasts the current state to all clients.
  661. Future<void> _broadcastState() async {
  662. await AudioServiceBackground.setState(
  663. controls: [
  664. MediaControl.skipToPrevious,
  665. if (_player.playing) MediaControl.pause else MediaControl.play,
  666. MediaControl.stop,
  667. MediaControl.skipToNext,
  668. ],
  669. systemActions: [
  670. MediaAction.seekTo,
  671. MediaAction.seekForward,
  672. MediaAction.seekBackward,
  673. ],
  674. androidCompactActions: [0, 1, 3],
  675. processingState: _getProcessingState(),
  676. playing: _player.playing,
  677. position: _player.position,
  678. bufferedPosition: _player.bufferedPosition,
  679. speed: _player.speed,
  680. );
  681. }
  682.  
  683. /// Maps just_audio's processing state into into audio_service's playing
  684. /// state. If we are in the middle of a skip, we use [_skipState] instead.
  685. AudioProcessingState _getProcessingState() {
  686. // if (_skipState != null) return _skipState;
  687. switch (_player.processingState) {
  688. case ProcessingState.idle:
  689. return AudioProcessingState.stopped;
  690. case ProcessingState.loading:
  691. return AudioProcessingState.connecting;
  692. case ProcessingState.buffering:
  693. return AudioProcessingState.buffering;
  694. case ProcessingState.ready:
  695. return AudioProcessingState.ready;
  696. case ProcessingState.completed:
  697. return AudioProcessingState.completed;
  698. default:
  699. throw Exception("Invalid state: ${_player.processingState}");
  700. }
  701. }
  702. }
  703.  
  704. /// Provides access to a library of media items. In your app, this could come
  705. /// from a database or web service.
  706. class MediaLibrary {
  707. // final _items = nowPlaying
  708. // .map((e) => MediaItem(
  709. // id: e['id'],
  710. // album: e['more_info']['album'],
  711. // title: e['title'],
  712. // artist: e['subtitle'],
  713. // artUri: e['image'],
  714. // duration: Duration(seconds: int.parse(e['more_info']['duration'])),
  715. // ))
  716. // .toList();
  717. // [
  718. // MediaItem(
  719. // id: "S3dGvXSb",
  720. // title: "Señorita",
  721. // artist: "Shawn Mendes, Camila Cabello",
  722. // album: "Señorita",
  723. // artUri:
  724. // "https://c.saavncdn.com/624/Se-orita-English-2019-20190822022326-500x500.jpg",
  725. // duration: Duration(seconds: 242),
  726. // ),
  727. // MediaItem(
  728. // id: "SEX82677",
  729. // title: "Past Life",
  730. // artist: "Trevor Daniel, Selena Gomez",
  731. // album: "Past Life",
  732. // artUri:
  733. // "https://c.saavncdn.com/022/Past-Life-English-2020-20200626000840-500x500.jpg",
  734. // duration: Duration(seconds: 242),
  735. // ),
  736. // MediaItem(
  737. // id: "v6NrwMud",
  738. // album: "Faraar",
  739. // title: "Faraar",
  740. // artist: "Akull",
  741. // duration: Duration(minutes: 3),
  742. // artUri:
  743. // "https://c.saavncdn.com/660/Faraar-Hindi-2021-20210113053337-500x500.jpg",
  744. // ),
  745. // ];
  746. MediaItem temp(e) {
  747. return MediaItem(
  748. id: e['id'],
  749. album: e['more_info']['album'],
  750. title: e['title'],
  751. artist: e['subtitle'],
  752. artUri: e['image'],
  753. duration: Duration(seconds: int.parse(e['more_info']['duration'])),
  754. );
  755. }
  756.  
  757. List<MediaItem> get items {
  758. // nowPlaying is the json response conveted into list of dictionaries which contain all details.
  759. final _items = nowPlaying.map((e) => temp(e)).toList();
  760. print('The items setted are $_items');
  761. return _items;
  762. }
  763. }
  764.  
  765. /// An object that performs interruptable sleep.
  766. class Sleeper {
  767. Completer _blockingCompleter;
  768.  
  769. /// Sleep for a duration. If sleep is interrupted, a
  770. /// [SleeperInterruptedException] will be thrown.
  771. Future<void> sleep([Duration duration]) async {
  772. _blockingCompleter = Completer();
  773. if (duration != null) {
  774. await Future.any([Future.delayed(duration), _blockingCompleter.future]);
  775. } else {
  776. await _blockingCompleter.future;
  777. }
  778. final interrupted = _blockingCompleter.isCompleted;
  779. _blockingCompleter = null;
  780. if (interrupted) {
  781. throw SleeperInterruptedException();
  782. }
  783. }
  784.  
  785. /// Interrupt any sleep that's underway.
  786. void interrupt() {
  787. if (_blockingCompleter?.isCompleted == false) {
  788. _blockingCompleter.complete();
  789. }
  790. }
  791. }
  792.  
  793. class SleeperInterruptedException {}
  794.  
  795. class Seeker {
  796. final AudioPlayer player;
  797. final Duration positionInterval;
  798. final Duration stepInterval;
  799. final MediaItem mediaItem;
  800. bool _running = false;
  801.  
  802. Seeker(
  803. this.player,
  804. this.positionInterval,
  805. this.stepInterval,
  806. this.mediaItem,
  807. );
  808.  
  809. start() async {
  810. _running = true;
  811. while (_running) {
  812. Duration newPosition = player.position + positionInterval;
  813. if (newPosition < Duration.zero) newPosition = Duration.zero;
  814. if (newPosition > mediaItem.duration) newPosition = mediaItem.duration;
  815. player.seek(newPosition);
  816. await Future.delayed(stepInterval);
  817. }
  818. }
  819.  
  820. stop() {
  821. _running = false;
  822. }
  823. }
  824.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement