Skip to content

Commit

Permalink
Merge pull request #80 from gokadzev/v3.0.0
Browse files Browse the repository at this point in the history
V3.0.0
  • Loading branch information
gokadzev authored Aug 21, 2022
2 parents b5318a4 + 5ea0b2f commit 63663d1
Show file tree
Hide file tree
Showing 39 changed files with 836 additions and 638 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
Play Local / Downloaded Songs Support :open_file_folder: <br>
High Quality mp3 / m4a / flac Format :fire:<br>
Lyrics Support :pencil:<br>
SponsorBlock Support :scissors: <br>
No Ads :no_entry_sign:<br>
No Subscriptions :dollar:<br>
12 Supported Languages :us:<br>
Expand Down
6 changes: 6 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ linter:
- non_constant_identifier_names
- noop_primitive_operations
- null_closures
- omit_local_variable_types
- overridden_fields
- package_api_docs
- package_names
Expand All @@ -64,9 +65,13 @@ linter:
- prefer_single_quotes
- prefer_typing_uninitialized_variables
- recursive_getters
- require_trailing_commas
- sized_box_for_whitespace
- slash_for_doc_comments
- sort_child_properties_last
- sort_constructors_first
- sort_pub_dependencies
- sort_unnamed_constructors_first
- test_types_in_equals
- throw_in_finally
- type_init_formals
Expand All @@ -88,5 +93,6 @@ linter:
- use_is_even_rather_than_modulo
- use_named_constants
- use_rethrow_when_possible
- use_super_parameters
- valid_regexps
- void_checks
2 changes: 2 additions & 0 deletions android/app/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ android {
targetSdkVersion 33
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
multiDexEnabled true
}

signingConfigs {
Expand Down Expand Up @@ -91,4 +92,5 @@ flutter {

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
implementation 'com.android.support:multidex:1.0.3'
}
7 changes: 0 additions & 7 deletions flutter_launcher_icons.yaml

This file was deleted.

8 changes: 0 additions & 8 deletions flutter_native_splash.yaml

This file was deleted.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
176 changes: 106 additions & 70 deletions lib/API/musify.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ import 'package:youtube_explode_dart/youtube_explode_dart.dart';
final yt = YoutubeExplode();
final OnAudioQuery _audioQuery = OnAudioQuery();

final random = Random();

List ytplaylists = [];
List searchedList = [];
List playlists = [];
Expand All @@ -30,14 +32,14 @@ List<SongModel> localSongs = [];

final lyrics = ValueNotifier<String>('null');
String _lastLyricsUrl = '';
String _alternateApiUrl = '';

int id = 0;

Future<List> fetchSongsList(String searchQuery) async {
final List list = await yt.search.search(searchQuery);
searchedList = [];
for (final s in list) {
searchedList.add(
searchedList = [
for (final s in list)
returnSongLayout(
0,
s.id.toString(),
Expand All @@ -48,17 +50,17 @@ Future<List> fetchSongsList(String searchQuery) async {
s.thumbnails.lowResUrl.toString(),
s.thumbnails.maxResUrl.toString(),
s.title.split('-')[0].toString(),
),
);
}
)
];

return searchedList;
}

Future get10Music(dynamic playlistid) async {
final List playlistSongs =
await getData('cache', 'playlist10Songs$playlistid') ?? [];
if (playlistSongs.isEmpty) {
int index = 0;
var index = 0;
await for (final song in yt.playlists.getVideos(playlistid).take(10)) {
playlistSongs.add(
returnSongLayout(
Expand Down Expand Up @@ -154,47 +156,25 @@ Future<List> searchPlaylist(String query) async {
}

return playlists
.where((playlist) =>
playlist['title'].toLowerCase().contains(query.toLowerCase()))
.where(
(playlist) =>
playlist['title'].toLowerCase().contains(query.toLowerCase()),
)
.toList();
}

Future<Map> getRandomSong() async {
if (playlists.isEmpty) {
playlists =
json.decode(await rootBundle.loadString('assets/db/playlists.db.json'))
as List;
}
final random = Random();
final playlistId = playlists[random.nextInt(playlists.length)]['ytid'];
final playlistSongs =
await getData('cache', 'playlistSongs$playlistId') ?? [];
final playlistId = 'PLgzTt0k8mXzEk586ze4BjvDXR7c-TUSnx';
final List playlistSongs = await getSongsFromPlaylist(playlistId);

if (playlistSongs.isEmpty) {
final songs = await yt.playlists.getVideos(playlistId).take(5).toList();
final choosedSong = songs[random.nextInt(playlistSongs.length)];

return returnSongLayout(
0,
choosedSong.id.toString(),
formatSongTitle(
choosedSong.title.split('-')[choosedSong.title.split('-').length - 1],
),
choosedSong.thumbnails.standardResUrl,
choosedSong.thumbnails.lowResUrl,
choosedSong.thumbnails.maxResUrl,
choosedSong.title.split('-')[0],
);
} else {
return playlistSongs[random.nextInt(playlistSongs.length)];
}
return playlistSongs[random.nextInt(playlistSongs.length)];
}

Future getSongsFromPlaylist(dynamic playlistid) async {
final List playlistSongs =
await getData('cache', 'playlistSongs$playlistid') ?? [];
if (playlistSongs.isEmpty) {
int index = 0;
var index = 0;
await for (final song in yt.playlists.getVideos(playlistid)) {
playlistSongs.add(
returnSongLayout(
Expand All @@ -221,13 +201,13 @@ Future<void> setActivePlaylist(List plist) async {
if (plist is List<SongModel>) {
activePlaylist = [];
id = 0;
final List<MediaItem> activeTempPlaylist = [];
for (final song in plist) {
activeTempPlaylist.add(songModelToMediaItem(song, song.data));
}
final activeTempPlaylist = <MediaItem>[
for (final song in plist) songModelToMediaItem(song, song.data)
];

await MyAudioHandler().addQueueItems(activeTempPlaylist);

await play();
play();
} else {
activePlaylist = plist;
id = 0;
Expand All @@ -253,14 +233,13 @@ Future getPlaylistInfoForWidget(dynamic id) async {
return playlist;
}

Future<String> getSongUrl(dynamic songId) async {
final manifest = await yt.videos.streamsClient.getManifest(songId);
return manifest.audioOnly.withHighestBitrate().url.toString();
}

Future getSongStream(dynamic songId) async {
Future<dynamic> getSong(dynamic songId, bool geturl) async {
final manifest = await yt.videos.streamsClient.getManifest(songId);
return manifest.audioOnly.withHighestBitrate();
if (geturl) {
return manifest.audioOnly.withHighestBitrate().url.toString();
} else {
return manifest.audioOnly.withHighestBitrate();
}
}

Future getSongDetails(dynamic songIndex, dynamic songId) async {
Expand All @@ -277,33 +256,87 @@ Future getSongDetails(dynamic songIndex, dynamic songId) async {
}

Future<List<SongModel>> getLocalSongs() async {
// DEFAULT:
// SongSortType.TITLE,
// OrderType.ASC_OR_SMALLER,
// UriType.EXTERNAL,
if (localSongs.isEmpty) {
if (await Permission.storage.request().isGranted) {
localSongs = await _audioQuery.querySongs(uriType: UriType.EXTERNAL);
localSongs.addAll(await _audioQuery.querySongs(
path: await ExtStorageProvider.getExtStorage(dirName: 'Musify')));
}
if (await Permission.storage.request().isGranted) {
localSongs = [
...await _audioQuery.querySongs(uriType: UriType.EXTERNAL),
...await _audioQuery.querySongs(
path: await ExtStorageProvider.getExtStorage(dirName: 'Musify'),
)
];
}

return localSongs;
}

Future<List<Map<String, int>>> getSkipSegments(String id) async {
try {
final res = await http.get(
Uri(
scheme: 'https',
host: 'sponsor.ajay.app',
path: '/api/skipSegments',
queryParameters: {
'videoID': id,
'category': [
'sponsor',
'selfpromo',
'interaction',
'intro',
'outro',
'music_offtopic'
],
'actionType': 'skip'
},
),
);
if (res.body != 'Not Found') {
final data = jsonDecode(res.body);
final segments = data.map((obj) {
return Map.castFrom<String, dynamic, String, int>({
'start': obj['segment'].first.toInt(),
'end': obj['segment'].last.toInt(),
});
}).toList();
return List.castFrom<dynamic, Map<String, int>>(segments);
} else {
return List.castFrom<dynamic, Map<String, int>>([]);
}
} catch (e, stack) {
debugPrint('$e $stack');
return List.castFrom<dynamic, Map<String, int>>([]);
}
}

Future<void> getAlternateApiUrl() async {
final response = await http.get(
Uri.parse('https://jsapi.apiary.io/apis/lyricsovh'),
headers: {'Accept': 'application/json'},
).timeout(const Duration(seconds: 10));

if (response.statusCode == 200) {
final proxyResponse = await json.decode(response.body);
if (proxyResponse['urls']['proxy'] != null) {
_alternateApiUrl = proxyResponse['urls']['proxy'];
}
}
}

Future getSongLyrics(String artist, String title) async {
if (_lastLyricsUrl !=
'https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}') {
if (await getData('cache',
'lyrics-https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}') !=
null) {
lyrics.value = await getData('cache',
'lyrics-https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}');
String currentApiUrl;
if (_alternateApiUrl != '') {
currentApiUrl =
'$_alternateApiUrl${artist.replaceAll(RegExp(r'[^\w\s]+'), '')}/${title.split(" (")[0].split("|")[0].trim().replaceAll(RegExp(r'[^\w\s]+'), '')}';
} else {
currentApiUrl =
'https://api.lyrics.ovh/v1/${artist.replaceAll(RegExp(r'[^\w\s]+'), '')}/${title.split(" (")[0].split("|")[0].trim().replaceAll(RegExp(r'[^\w\s]+'), '')}';
}

if (_lastLyricsUrl != currentApiUrl) {
if (await getData('cache', 'lyrics-$artist-$title') != null) {
lyrics.value = await getData('cache', 'lyrics-$artist-$title');
} else {
lyrics.value = 'null';
_lastLyricsUrl =
'https://api.lyrics.ovh/v1/$artist/${title.split(" (")[0].split("|")[0].trim()}';
_lastLyricsUrl = currentApiUrl;
final response = await http.get(
Uri.parse(_lastLyricsUrl),
headers: {'Accept': 'application/json'},
Expand All @@ -313,8 +346,11 @@ Future getSongLyrics(String artist, String title) async {
final lyricsResponse = await json.decode(response.body);
if (lyricsResponse['lyrics'] != null) {
lyrics.value = lyricsResponse['lyrics'].toString();
addOrUpdateData('cache', 'lyrics-$_lastLyricsUrl',
lyricsResponse['lyrics'].toString());
addOrUpdateData(
'cache',
'lyrics-$artist-$title',
lyricsResponse['lyrics'].toString(),
);
} else {
lyrics.value = 'not found';
}
Expand Down
4 changes: 2 additions & 2 deletions lib/customWidgets/custom_animated_bottom_bar.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import 'package:musify/ui/rootPage.dart';

class CustomAnimatedBottomBar extends StatelessWidget {
CustomAnimatedBottomBar({
Key? key,
super.key,
this.showElevation = true,
this.onTap,
this.selectedItemColor,
Expand All @@ -17,7 +17,7 @@ class CustomAnimatedBottomBar extends StatelessWidget {
this.curve = Curves.easeOutQuint,
this.radius = BorderRadius.zero,
required this.items,
}) : super(key: key);
});
final Color? backgroundColor;
final bool showElevation;
final List<BottomNavBarItem> items;
Expand Down
22 changes: 11 additions & 11 deletions lib/customWidgets/delayed_display.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,16 @@ import 'dart:async';
import 'package:flutter/material.dart';

class DelayedDisplay extends StatefulWidget {
/// DelayedDisplay constructor
const DelayedDisplay({
required this.child,
this.delay = Duration.zero,
this.fadingDuration = const Duration(milliseconds: 800),
this.slidingCurve = Curves.decelerate,
this.slidingBeginOffset = const Offset(0, 0.35),
this.fadeIn = true,
});

/// Child that will be displayed with the animation and delay
final Widget child;

Expand All @@ -23,16 +33,6 @@ class DelayedDisplay extends StatefulWidget {
/// If true, make the child appear, disappear otherwise. Default to true.
final bool fadeIn;

/// DelayedDisplay constructor
const DelayedDisplay({
required this.child,
this.delay = Duration.zero,
this.fadingDuration = const Duration(milliseconds: 800),
this.slidingCurve = Curves.decelerate,
this.slidingBeginOffset = const Offset(0, 0.35),
this.fadeIn = true,
});

@override
_DelayedDisplayState createState() => _DelayedDisplayState();
}
Expand Down Expand Up @@ -74,7 +74,7 @@ class _DelayedDisplayState extends State<DelayedDisplay>
duration: opacityTransitionDuration,
);

final CurvedAnimation curvedAnimation = CurvedAnimation(
final curvedAnimation = CurvedAnimation(
curve: slidingCurve,
parent: _opacityController,
);
Expand Down
Loading

0 comments on commit 63663d1

Please sign in to comment.