package com.kpstv.youtube.services; import android.annotation.SuppressLint; import android.app.Notification; import android.app.NotificationChannel; import android.app.NotificationManager; import android.app.PendingIntent; import android.app.Service; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.media.MediaMetadataRetriever; import android.media.audiofx.BassBoost; import android.media.audiofx.Equalizer; import android.media.audiofx.LoudnessEnhancer; import android.media.audiofx.PresetReverb; import android.media.audiofx.Virtualizer; import android.media.audiofx.Visualizer; import android.net.Uri; import android.os.AsyncTask; import android.os.Build; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.PowerManager; import android.support.annotation.Nullable; import android.support.v4.app.NotificationCompat; import android.support.v4.app.NotificationManagerCompat; import android.support.v4.content.ContextCompat; import android.support.v4.media.MediaMetadataCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; import android.support.v7.graphics.Palette; import android.text.Html; import android.text.Spanned; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.widget.LinearLayout; import android.widget.Toast; import com.google.android.exoplayer2.C; import com.google.android.exoplayer2.ExoPlayer; import com.google.android.exoplayer2.ExoPlayerFactory; import com.google.android.exoplayer2.Player; import com.google.android.exoplayer2.SimpleExoPlayer; import com.google.android.exoplayer2.audio.AudioAttributes; import com.google.android.exoplayer2.source.ExtractorMediaSource; import com.google.android.exoplayer2.source.MediaSource; import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection; import com.google.android.exoplayer2.trackselection.DefaultTrackSelector; import com.google.android.exoplayer2.trackselection.TrackSelection; import com.google.android.exoplayer2.trackselection.TrackSelector; import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter; import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory; import com.google.android.exoplayer2.util.Util; import com.google.android.gms.ads.AdListener; import com.google.android.gms.ads.AdRequest; import com.google.android.gms.ads.InterstitialAd; import com.kpstv.youtube.AppInterface; import com.kpstv.youtube.AppSettings; import com.kpstv.youtube.MainActivity; import com.kpstv.youtube.PlayerActivity2; import com.kpstv.youtube.R; import com.kpstv.youtube.models.NPlayModel; import com.kpstv.youtube.models.YTConfig; import com.kpstv.youtube.receivers.SongBroadCast; import com.kpstv.youtube.utils.APIResponse; import com.kpstv.youtube.utils.DataUtils; import com.kpstv.youtube.utils.HttpHandler; import com.kpstv.youtube.utils.LyricsApi; import com.kpstv.youtube.utils.SoundCloud; import com.kpstv.youtube.utils.YTMeta; import com.kpstv.youtube.utils.YTStatistics; import com.kpstv.youtube.utils.YTutils; import com.naveed.ytextractor.ExtractorException; import com.naveed.ytextractor.YoutubeStreamExtractor; import com.naveed.ytextractor.model.YTMedia; import com.naveed.ytextractor.model.YoutubeMeta; import com.spyhunter99.supertooltips.ToolTip; import com.spyhunter99.supertooltips.ToolTipManager; import org.json.JSONException; import org.json.JSONObject; import java.io.File; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import static android.view.View.VISIBLE; import static android.view.View.inflate; import static com.kpstv.youtube.MainActivity.actionChannelTitle; import static com.kpstv.youtube.MainActivity.actionPlay; import static com.kpstv.youtube.MainActivity.actionTitle; import static com.kpstv.youtube.MainActivity.actionUp; import static com.kpstv.youtube.MainActivity.adView; import static com.kpstv.youtube.MainActivity.adViewLayout; import static com.kpstv.youtube.MainActivity.bottom_player; import static com.kpstv.youtube.MainActivity.libraryFrag; import static com.kpstv.youtube.MainActivity.loadProgress; import static com.kpstv.youtube.MainActivity.mUpdateTimeTask; import static com.kpstv.youtube.MainActivity.songProgress; import static com.kpstv.youtube.MainActivity.toolTipManager; import static com.kpstv.youtube.MainActivity.updateProgressBar; public class MusicService extends Service implements AppInterface { @Override public void onCreate() { super.onCreate(); functionInMainActivity(getApplicationContext()); createNotification(getApplicationContext()); Intent intent = new Intent(this,MusicService.class); intent.setAction("CLOSE_SERVICE"); PendingIntent pendingIntent = PendingIntent.getService(this,0,intent,0); Notification notification = new NotificationCompat.Builder(this,"channel_01") .setPriority(NotificationCompat.PRIORITY_LOW) .setContentTitle("Loading") .addAction(R.drawable.ic_close,"Cancel",pendingIntent) .setShowWhen(false) .setContentText("Please wait...") .setSmallIcon(R.drawable.ic_audio_pulse2) .build(); startForeground(1,notification); PowerManager pm = (PowerManager) getSystemService(Context.POWER_SERVICE); wakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "app:wakelockTag"); wakeLock.acquire(); } @Override public int onStartCommand(Intent intent, int flags, int startId) { String action = intent.getAction(); if (action==null) return START_NOT_STICKY; switch (action) { case "CLOSE_SERVICE": stopSelf(); break; case "PlayVideo_Local": String[] urls = intent.getStringArrayExtra("urls"); localPlayBack=true; yturls.clear(); if (LoadOffline !=null && LoadOffline.getStatus() == AsyncTask.Status.RUNNING) { player.stop(); player.release(); LoadOffline.cancel(true); } yturls.addAll(Arrays.asList(urls)); ytIndex = 0; LoadOffline = new loadVideo_Local(urls[ytIndex]); LoadOffline.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; case "PlayVideo_Local_pos": urls = intent.getStringArrayExtra("urls"); int position = intent.getIntExtra("pos",0); localPlayBack=true; yturls.clear(); if (LoadOffline !=null && LoadOffline.getStatus() == AsyncTask.Status.RUNNING) { player.stop(); player.release(); LoadOffline.cancel(true); } yturls.addAll(Arrays.asList(urls)); ytIndex = position; LoadOffline = new loadVideo_Local(urls[ytIndex]); LoadOffline.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; case "ChangeVideoOffline": localPlayBack=true; position = intent.getIntExtra("pos",0); if (LoadOffline !=null && LoadOffline.getStatus() == AsyncTask.Status.RUNNING) { player.stop(); player.release(); LoadOffline.cancel(true); } ytIndex = position; LoadOffline = new loadVideo_Local(yturls.get(ytIndex)); LoadOffline.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); break; case "PlayVideo": urls = intent.getStringArrayExtra("urls"); localPlayBack=false; yturls.clear(); if (LoadVideo !=null && LoadVideo.getStatus() == AsyncTask.Status.RUNNING) { player.stop(); player.release(); LoadVideo.cancel(true); } yturls.addAll(Arrays.asList(urls)); videoID = YTutils.getVideoID(yturls.get(0)); Log.e("VideoID_ToPLAY",videoID+""); LoadVideo = new loadVideo(); LoadVideo.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,videoID); break; case "PlayVideo_pos": urls = intent.getStringArrayExtra("urls"); position = intent.getIntExtra("pos",0); localPlayBack=false; yturls.clear(); if (LoadVideo !=null && LoadVideo.getStatus() == AsyncTask.Status.RUNNING) { player.stop(); player.release(); LoadVideo.cancel(true); } yturls.addAll(Arrays.asList(urls)); ytIndex = position; videoID = YTutils.getVideoID(yturls.get(position)); LoadVideo = new loadVideo(); LoadVideo.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,videoID); break; case "ChangeVideo": position = intent.getIntExtra("pos",0); localPlayBack=false; if (LoadVideo !=null && LoadVideo.getStatus() == AsyncTask.Status.RUNNING) { player.stop(); player.release(); LoadVideo.cancel(true); } ytIndex = position; videoID = YTutils.getVideoID(yturls.get(position)); LoadVideo = new loadVideo(); LoadVideo.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,videoID); break; } return START_NOT_STICKY; } @Nullable @Override public IBinder onBind(Intent intent) { return null; } @Override public void onDestroy() { if (Build.VERSION.SDK_INT>=Build.VERSION_CODES.O) { NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE); notificationManager.deleteNotificationChannel("channel_01"); notificationManager.deleteNotificationChannel("channel_02"); } isEqualizerSet = false; if (PlayerActivity2.activity!=null) { PlayerActivity2.activity.finish(); } try { bottom_player.setVisibility(View.GONE); adView.setVisibility(View.GONE); onClear(); MainActivity.activity.findViewById(R.id.adViewLayout_add) .setVisibility(View.GONE); }catch (Exception ignored){ } notificationManagerCompat.cancel(1); try { if (mEqualizer!=null) mEqualizer.release(); if (bassBoost!=null) bassBoost.release(); if (loudnessEnhancer!=null) loudnessEnhancer.release(); if (virtualizer!=null) virtualizer.release(); player.stop(); player.release(); }catch (Exception e) { e.printStackTrace(); } wakeLock.release(); activity = null; super.onDestroy(); } static AsyncTask<String,String,Void> LoadVideo; static AsyncTask<Void,Void,Void> LoadOffline; public static ArrayList<NPlayModel> nPlayModels; public static List<String> playListItems; public static SimpleExoPlayer player; public static boolean supportFFmpeg=false,loadedFavFrag=false; public static MediaSource mediaSource; private static final String TAG = "MusicService"; public static DefaultDataSourceFactory dataSourceFactory; public static DefaultBandwidthMeter BANDWIDTH_METER = new DefaultBandwidthMeter(); public static TrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(); public static TrackSelector trackSelector = new DefaultTrackSelector(trackSelectionFactory); public static String selectedItemText=""; public static int sleepSeconds; private static MediaSessionCompat mediaSession; PowerManager.WakeLock wakeLock; static SharedPreferences preferences; public static SharedPreferences settingPref; public static Context activity; public static void functionInMainActivity(Context activity) { // Toast.makeText(activity, "Function in MainActivity...!", Toast.LENGTH_SHORT).show(); MusicService.activity = activity.getApplicationContext(); settingPref = activity.getSharedPreferences("settings",MODE_PRIVATE); isEqualizerEnabled = settingPref.getBoolean("equalizer_enabled",false); dataSourceFactory = new DefaultDataSourceFactory(activity, Util.getUserAgent(activity, activity.getResources().getString(R.string.app_name)), BANDWIDTH_METER); player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector); createNotification(activity); playListItems = new ArrayList<>(); yturls = new ArrayList<>(); nPlayModels = new ArrayList<>(); ComponentName mediaButtonReceiverComponentName = new ComponentName( activity, SongBroadCast.class); Intent mediaButtonIntent = new Intent(Intent.ACTION_MEDIA_BUTTON); mediaButtonIntent.setComponent(mediaButtonReceiverComponentName); PendingIntent mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast( activity, 0, mediaButtonIntent, 0); mediaSession = new MediaSessionCompat(activity, "MusicPlayer", mediaButtonReceiverComponentName, mediaButtonReceiverPendingIntent); mediaSession.setFlags(MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS ); mediaSession.setCallback(mMediaSessionCallback); mediaSession.setActive(true); mediaSession.setMediaButtonReceiver(mediaButtonReceiverPendingIntent); preferences = activity.getSharedPreferences("history",MODE_PRIVATE); } static void setDefaultEqualizerValues() { try { boolean isSet = settingPref.getBoolean("equalizer_default",false); if (!isSet) { SharedPreferences.Editor editor = settingPref.edit(); int sessionId = player.getAudioComponent().getAudioSessionId(); mEqualizer = new Equalizer(1000,sessionId); short numberFrequencyBands = mEqualizer.getNumberOfBands(); final short lowerEqualizerBandLevel = mEqualizer.getBandLevelRange()[0]; final short upperEqualizerBandLevel = mEqualizer.getBandLevelRange()[1]; editor.putInt("bandLength",numberFrequencyBands); editor.putInt("lowerBand",lowerEqualizerBandLevel); editor.putInt("higherBand",upperEqualizerBandLevel); editor.putBoolean("equalizer_default",true); editor.apply(); mEqualizer.release(); } }catch (Exception ignored){} } private static final long MEDIA_SESSION_ACTIONS = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS | PlaybackStateCompat.ACTION_STOP | PlaybackStateCompat.ACTION_SEEK_TO; public static void updateMediaSessionPlaybackState() { PlaybackStateCompat.Builder stateBuilder = new PlaybackStateCompat.Builder() .setActions(MEDIA_SESSION_ACTIONS) .setState(isplaying ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED, player.getCurrentPosition(), 1); mediaSession.setPlaybackState(stateBuilder.build()); } public static MediaSessionCompat.Callback mMediaSessionCallback = new MediaSessionCompat.Callback() { @Override public void onPlay() { super.onPlay(); } @Override public void onPause() { super.onPause(); } @Override public void onSeekTo(long pos) { Log.e(TAG, "onSeekTo: Playing"+pos ); player.seekTo(pos); super.onSeekTo(pos); } @Override public void onPlayFromMediaId(String mediaId, Bundle extras) { super.onPlayFromMediaId(mediaId, extras); } }; public static String videoTitle = "", channelTitle = "", viewCounts, imgUrl, videoID,audioLink; public static int likeCounts,dislikeCounts; public static NotificationManagerCompat notificationManagerCompat; static NotificationManager notificationManager; static NotificationChannel notificationChannel; static PendingIntent prevPendingIntent,pausePendingIntent,nextPendingIntent,clickPendingIntent,favouritePendingIntent; public static Bitmap bitmapIcon; public static ArrayList<YTConfig> ytConfigs = new ArrayList<>(); static NotificationCompat.Builder builder; public static boolean isplaying, sleepEndTrack=false,localPlayBack=false, soundCloudPlayBack,isFavourite=false,isEqualizerEnabled=false; public static boolean isEqualizerSet=false,loadedFromData=false; // isLoop=false, public static Spanned lyricText;static boolean isFirstLaunch=true; public static long total_duration = 0; public static PresetReverb presetReverb; public static BassBoost bassBoost; public static Virtualizer virtualizer; public static LoudnessEnhancer loudnessEnhancer;static int trials=3; public static int total_seconds; public static int nColor; public static ArrayList<String> yturls; static boolean dontAllowToPlay=false; public static int ytIndex = 0; public static Visualizer visualizer; public static Equalizer mEqualizer;static int command=0; public static int repeatMode = 0; /** 0 - No repeat, 1 - Repeat playlist, 2 - Repeat current song */ static class loadVideo_Local extends AsyncTask<Void,Void,Void> { String filePath; boolean notExist=false; public loadVideo_Local(String filePath) { this.filePath = filePath; } @Override protected void onPostExecute(Void aVoid) { if (notExist) { playNext(); return; } if (YTutils.isInternetAvailable()) setLyricData(); try { Palette.generateAsync(bitmapIcon, palette -> { nColor = palette.getVibrantColor(activity.getResources().getColor(R.color.light_white)); Log.e(TAG, "loadData_ OFFLINE Changing nColor: "+MusicService.nColor +", ImageUri:"+MusicService.imgUrl); continueinMainThread("isPath:"+filePath); }); }catch (Exception e){ Log.e(TAG, "onPostExecute: "+e.getMessage()); } super.onPostExecute(aVoid); } @Override protected Void doInBackground(Void... voids) { File f = new File(filePath); if (!f.exists()) { notExist=true; return null; } Uri uri = Uri.fromFile(f); try { MediaMetadataRetriever mmr = new MediaMetadataRetriever(); mmr.setDataSource(activity,uri); String durationStr = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_DURATION); String artist = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST); String title = mmr.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE); byte [] data = mmr.getEmbeddedPicture(); if(data != null) { bitmapIcon = BitmapFactory.decodeByteArray(data, 0, data.length); Log.e(TAG, "BITMAP DATA: HERE...." ); } else bitmapIcon = YTutils.drawableToBitmap(ContextCompat.getDrawable(activity,R.drawable.ic_pulse)); if (artist==null) artist ="Unknown artist"; if (title==null) title = YTutils.getVideoTitle(f.getName()); if (title.contains(".")) title = title.split("\\.")[0]; videoTitle = title; channelTitle = artist; likeCounts = -1; dislikeCounts = -1; viewCounts = "-1"; videoID = f.getPath(); total_seconds = Integer.parseInt(durationStr); }catch (Exception e) { notExist=true; } return null; } @Override protected void onPreExecute() { commonPreExecute(); super.onPreExecute(); } } static void setLyricData() { new LyricsApi(activity,videoTitle,channelTitle){ @Override public void onLyricFound(Spanned data) { super.onLyricFound(data); lyricText = data; try { PlayerActivity2.setLyricData(lyricText); }catch (Exception e){} } }.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } static class loadVideo extends AsyncTask<String,String,Void> { @SuppressLint("StaticFieldLeak") @Override protected void onPostExecute(Void aVoid) { if (noInternet) { return; } if (skipSong) { if (souncloudFailed) Toast.makeText(activity, "Error: Parsing song "+videoTitle, Toast.LENGTH_SHORT).show(); if (command==1) playNext(); else if (command==2) playPrevious(); return; } if (bitmapIcon!=null) { Palette.generateAsync(bitmapIcon, palette -> { Log.e(TAG, "loadVideo: Changing nColor: "+MusicService.nColor + ", ImageUri: "+MusicService.imgUrl); nColor = palette.getVibrantColor(activity.getResources().getColor(R.color.light_white)); }); } setLyricData(); if (soundCloudPlayBack) { ytConfigs.clear(); ytConfigs.add(new YTConfig("Audio 128 kbit/s",soundCloud.getModel().getStreamUrl(), ".mp3",videoTitle,channelTitle,true,soundCloud.getModel().getImageUrl())); audioLink = soundCloud.getModel().getStreamUrl(); continueinMainThread(audioLink); return; } if (!loadedFromData) parseVideoNewMethod(YTutils.getYtUrl(videoID),videoTitle); else continueinMainThread(audioLink); super.onPostExecute(aVoid); } boolean skipSong, noInternet,souncloudFailed=false; SoundCloud soundCloud; @Override protected Void doInBackground(String... arg0) { trials=3; loadedFromData=false; soundCloudPlayBack=false;souncloudFailed=false; if (!YTutils.isInternetAvailable()) { Toast.makeText(activity, "No active internet connection", Toast.LENGTH_SHORT).show(); noInternet=true; return null; } videoID = arg0[0]; MusicService.playListItems = new ArrayList<>(); if (!localPlayBack) { String data = YTutils.readContent(activity,"removedList.csv"); if (data!=null && !data.isEmpty()) { if (data.contains(",")) MusicService.playListItems = new ArrayList<>(Arrays.asList(data.split(","))); else MusicService.playListItems.add(data.trim()); } if (playListItems.contains("ytID:"+videoID)||playListItems.contains("sd:"+videoID)) { skipSong =true; return null; } } if (videoID.contains("soundcloud.com")) { soundCloud = new SoundCloud(videoID); videoTitle = soundCloud.getModel().getTitle(); if (soundCloud.getModel()==null || soundCloud.getModel().getStreamUrl()==null) { skipSong=true; souncloudFailed=true; command=1; return null; } // soundCloud.captureViews(); soundCloudPlayBack=true; MusicService.videoTitle = soundCloud.getModel().getTitle(); MusicService.channelTitle = soundCloud.getModel().getAuthorName(); MusicService.imgUrl = soundCloud.getModel().getImageUrl(); likeCounts = -1; dislikeCounts = -1; viewCounts = "-1"; /* if (soundCloud.getViewCount()!=null && !soundCloud.getViewCount().isEmpty()) viewCounts =YTutils.getViewCount( Long.parseLong(soundCloud.getViewCount())); Log.e(TAG, "doInBackground: Here I am: " +soundCloud.getModel().getStreamUrl());*/ } else { String link = "https://www.googleapis.com/youtube/v3/videos?id=" + videoID + "&part=statistics"; APIResponse response = new APIResponse(link); String json = response.getJson(); /*int i = 0; int apiLength = API_KEYS.length; String json; json = jsonResponse(videoID, i); i++; } while (json.contains("\"error\":") && i < apiLength);*/ YTMeta ytMeta = new YTMeta(videoID); if (ytMeta.getVideMeta() != null) { MusicService.channelTitle = YTutils.getChannelTitle(ytMeta.getVideMeta().getTitle(), ytMeta.getVideMeta().getAuthor()); MusicService.videoTitle = YTutils.setVideoTitle(ytMeta.getVideMeta().getTitle()); MusicService.imgUrl = ytMeta.getVideMeta().getImgUrl(); } if (json.contains("\"error\"")) { YTStatistics ytStatistics = new YTStatistics(videoID); try { MusicService.viewCounts = YTutils.getViewCount(Long.parseLong(ytStatistics.getViewCount())); }catch (Exception e) { MusicService.viewCounts = "-1"; } try { MusicService.likeCounts = Integer.parseInt(ytStatistics.getLikeCount()); }catch (Exception e) { MusicService.likeCounts = 100; } try { MusicService.dislikeCounts = Integer.parseInt(ytStatistics.getDislikeCount()); }catch (Exception e) { MusicService.dislikeCounts = 0; } json = null; } if (json != null) { try { JSONObject statistics = new JSONObject(json).getJSONArray("items") .getJSONObject(0).getJSONObject("statistics"); viewCounts = YTutils.getViewCount(Long.parseLong(statistics.getString("viewCount"))); likeCounts = 100; dislikeCounts = 0; try { likeCounts = Integer.parseInt(statistics.getString("likeCount")); dislikeCounts = Integer.parseInt(statistics.getString("dislikeCount")); } catch (Exception e) { e.printStackTrace(); } } catch (JSONException e) { e.printStackTrace(); Log.e("PlayerActivity_JSON", e.getMessage()); } } DataUtils.DataModel dataModel = DataUtils.getSavedUrl(activity,videoID,videoTitle,channelTitle); if (dataModel!=null) { loadedFromData=true; audioLink = dataModel.getAudioLink(); ytConfigs = dataModel.getConfigs(); } } if (MusicService.imgUrl!=null) { Log.e(TAG, "doInBackground: Downloading Image..." ); try { bitmapIcon = YTutils.getBitmapFromURL(MusicService.imgUrl); }catch (Exception ignored){ } if (bitmapIcon==null) { Log.e(TAG, "doInBackground: Error: occurred, Refreshing" ); String modifiedImageUrl = YTutils.getImageUrlID_MQ(YTutils.getVideoID_ImageUri(MusicService.imgUrl)); bitmapIcon = YTutils.getBitmapFromURL(modifiedImageUrl); if (bitmapIcon != null) MusicService.imgUrl = modifiedImageUrl; Log.e(TAG, "doInBackground: New Image Url: "+MusicService.imgUrl); } } return null; } @Override protected void onPreExecute() { commonPreExecute(); super.onPreExecute(); } } static void commonPreExecute() { try { if (!localPlayBack) { PlayerActivity2.progressBar.setVisibility(VISIBLE); PlayerActivity2.hidePlayButton(); } }catch (Exception e){ Log.e(TAG, "commonPreExecute: Error: "+e.getMessage()); } try { bottom_player.setVisibility(VISIBLE); onClear(); if (AppSettings.showAds) { AdRequest adRequest = new AdRequest.Builder().addTestDevice("07153BA64BB64F7C3F726B71C4AE30B9").build(); MainActivity.adView.loadAd(adRequest); MainActivity.adView.setAdListener(new AdListener(){ @Override public void onAdLoaded() { MainActivity.adView.setVisibility(VISIBLE); super.onAdLoaded(); } @Override public void onAdFailedToLoad(int i) { adView.setVisibility(View.GONE); Log.e(TAG, "onAdFailedToLoad: Failed to load Ad"+i ); // Show built-in ads... try { LinearLayout l = MainActivity.activity.findViewById(R.id.adViewLayout_add); if (l!=null) { YTutils.addADView(MainActivity.activity,l); } }catch (Exception ignored) {} super.onAdFailedToLoad(i); } }); }else MainActivity.adView.setVisibility(View.GONE); }catch (Exception e){ Log.e(TAG, "commonPreExecute: Error: "+e.getMessage() ); } } private static void parseVideoNewMethod(String yturl, String videoTitle) { Log.e(TAG, "parseVideoNewMethod: Starting here...." ); new YoutubeStreamExtractor(new YoutubeStreamExtractor.ExtractorListner(){ @Override public void onExtractionGoesWrong(ExtractorException e) { if (trials>0) { trials--; Log.e(TAG, "onExtractionGoesWrong: Trial Count: "+trials ); parseVideoNewMethod(yturl,videoTitle); return; } playNext(); Toast.makeText(activity, videoTitle+": Couldn't get the required audio stream!", Toast.LENGTH_SHORT).show(); } @Override public void onExtractionDone(List<YTMedia> adativeStream, List<YTMedia> muxedStream, YoutubeMeta meta) { Log.e(TAG, "onExtractionDone: Parsing Audio using second method" ); if (adativeStream.isEmpty()) { if (trials>0) { trials--; Log.e(TAG, "onExtractionGoesWrong: Trial Count: "+trials ); parseVideoNewMethod(yturl,videoTitle); return; } playNext(); Toast.makeText(activity, videoTitle+": Couldn't get the required audio stream!", Toast.LENGTH_SHORT).show(); // showAlert("Failed!", "Couldn't get the required audio stream. Try again!", true); return; } Log.e("Method2","Extracted using new method"); if (muxedStream.size()>0) { Log.e(TAG, "onExtractionDone: Muxed exist" ); for (int i=0;i<muxedStream.size();i++) { Log.e(TAG, "onExtractionDone: Muxed ("+i+"): "+muxedStream.get(i).getUrl() ); } } else Log.e(TAG, "onExtractionDone: Muxed error" ); ytConfigs.clear(); // List<YTMedia> bestStream = getBestStream(adativeStream); Log.e(TAG, "onExtractionDone: Expires in: "+meta.getExpiresInSeconds()); Log.e(TAG, "onExtractionDone: Media Size: " +adativeStream.size()); for(int i=0; i<adativeStream.size();i++) addVideoToList(adativeStream.get(i),videoTitle,channelTitle); Log.e(TAG, "parseVideoNewMethod: Ending here...." ); continueinMainThread(audioLink); } }).useDefaultLogin().Extract(YTutils.getVideoID(yturl)); } public static void actionFavouriteClicked() { if (MusicService.total_seconds==0) { Toast.makeText(activity, "Player is still processing!", Toast.LENGTH_SHORT).show(); }else{ try { if (!MusicService.isFavourite) PlayerActivity2.favouriteButton.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_favorite_full)); else PlayerActivity2.favouriteButton.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_favorite)); }catch (Exception ignored){} MusicService.write_Favourite(); rebuildNotification(); } } public static void write_Favourite() { String t = YTutils.readContent(activity,"favourite.csv"); if (t!=null && !t.contains(MusicService.videoID)) { t += "\n"+MusicService.videoID+"|"+MusicService.total_seconds+"|"+MusicService.videoTitle+"|"+MusicService.channelTitle +"|"+MusicService.imgUrl; Toast.makeText(activity, "Added to favourites!", Toast.LENGTH_SHORT).show(); MusicService.isFavourite=true; }else if (t!=null && t.contains(MusicService.videoID)) { String[] lines = t.split("\n|\r"); StringBuilder builder = new StringBuilder(); for (String line : lines) { if (!line.contains(MusicService.videoID) && !line.isEmpty()) { builder.append("\n").append(line); } } t = builder.toString().trim(); Toast.makeText(activity, "Removed from favourites!", Toast.LENGTH_SHORT).show(); MusicService.isFavourite=false; }else { t =MusicService.videoID+"|"+MusicService.total_seconds+"|"+MusicService.videoTitle+"|"+MusicService.channelTitle +"|"+MusicService.imgUrl; Toast.makeText(activity, "Added to favourites!", Toast.LENGTH_SHORT).show(); MusicService.isFavourite=true; } YTutils.writeContent(activity,"favourite.csv",t.trim()); } private static void continueinMainThread(String link) { Log.e(TAG, "onExtractionDone: AudioLink: "+link ); player.stop(); player.release(); if (link.startsWith("isPath:")) { link = link.split(":")[1]; File f = new File(link); mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.fromFile(f)); }else mediaSource = new ExtractorMediaSource.Factory(dataSourceFactory).createMediaSource(Uri.parse(link)); player = ExoPlayerFactory.newSimpleInstance(activity, trackSelector); player.prepare(mediaSource); player.setPlayWhenReady(true); makePause(); isplaying = true; if (AppSettings.listenAudioChange) { AudioAttributes audioAttributes = new AudioAttributes.Builder() .setUsage(C.USAGE_MEDIA) .setContentType(C.CONTENT_TYPE_MOVIE) .build(); player.setAudioAttributes(audioAttributes, true); } player.addListener(new Player.EventListener() { @Override public void onPlayerStateChanged(boolean playWhenReady, int playbackState) { Log.e(TAG, "onPlayerStateChanged: playWhenReady: "+playWhenReady+", playbackState: " +YTutils.getPlayBackstate(playbackState)); /** A logic to listen to audio focus change listener */ if (!playWhenReady && playbackState== ExoPlayer.STATE_READY && AppSettings.listenAudioChange) { Log.e(TAG, "onPlayerStateChanged: Here I am..." ); makePlay(); isplaying = false; rebuildNotification(); } switch (playbackState) { case ExoPlayer.STATE_IDLE: break; case ExoPlayer.STATE_BUFFERING: try { if (!localPlayBack) { PlayerActivity2.progressBar.setVisibility(VISIBLE); PlayerActivity2.hidePlayButton(); } }catch (Exception ignored){} break; case ExoPlayer.STATE_ENDED: if (repeatMode!=2) { makePlay(); isplaying = false; playNext(); if (sleepEndTrack) { Log.e(TAG, "onPlayerStateChanged: tiggered"); sleepEndTrack = false; dontAllowToPlay = true; } }else playNext(); break; case ExoPlayer.STATE_READY: if(isFirstLaunch) { isFirstLaunch=false; setDefaultEqualizerValues(); } try { loadProgress.setVisibility(View.GONE); actionTitle.setVisibility(VISIBLE); actionChannelTitle.setVisibility(View.VISIBLE); songProgress.setVisibility(View.VISIBLE); actionPlay.setVisibility(View.VISIBLE); songProgress.setProgress(0); actionUp.setVisibility(View.VISIBLE); actionTitle.setText(videoTitle); actionChannelTitle.setText(" "+ Html.fromHtml("•")+" "+channelTitle); }catch (Exception e){ Log.e(TAG, "onPlayerStateChanged: Error: "+e.getMessage()); } total_duration = MusicService.player.getDuration(); total_seconds = (int) total_duration / 1000; try { if (!localPlayBack) { PlayerActivity2.progressBar.setVisibility(View.GONE); PlayerActivity2.showPlayButton(); } PlayerActivity2.loadAgain(); PlayerActivity2.totalDuration.setText(YTutils.milliSecondsToTimer(MusicService.total_duration)); }catch (Exception e) { Log.e("PlayerActivity","not loaded yet!"); } try { addEqualizer(); }catch (Exception e) {} /** Setting mediaSession metadata */ final MediaMetadataCompat.Builder metaData = new MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, channelTitle) .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, channelTitle) .putString(MediaMetadataCompat.METADATA_KEY_TITLE, videoTitle) .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, player.getDuration()) .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null); mediaSession.setMetadata(metaData.build()); rebuildNotification(); if (MainActivity.activity!=null) updateProgressBar(); // Store video into history if (!localPlayBack) new saveToHistory().execute(YTutils.getYtUrl(videoID)); if (dontAllowToPlay) { dontAllowToPlay=false; libraryFrag.onActivityResult(101,0,null); changePlayBack(false); } if (!settingPref.getBoolean("showPlayerTip",false)) { ToolTip toolTip = new ToolTip() .withText("Swipe player right and left to change song.") .withTextColor(activity.getResources().getColor(R.color.black)) .withColor(activity.getResources().getColor(R.color.colorAccent)) //or whatever you want .withAnimationType(ToolTip.AnimationType.FROM_MASTER_VIEW) .withShadow(); toolTipManager.showToolTip(toolTip,bottom_player); SharedPreferences.Editor editor = settingPref.edit(); editor.putBoolean("showPlayerTip",true); editor.apply(); } break; } } }); } public static void addEqualizer() { try { int audioSessionId = player.getAudioComponent().getAudioSessionId(); Log.e(TAG, "onAudioSessionId: AudioSessionID: "+audioSessionId ); if (mEqualizer!=null) mEqualizer.release(); if (presetReverb!=null) presetReverb.release(); if (bassBoost!=null) bassBoost.release(); if (virtualizer!=null) virtualizer.release(); if (loudnessEnhancer!=null) loudnessEnhancer.release(); mEqualizer = new Equalizer(1000, audioSessionId); mEqualizer.setEnabled(isEqualizerEnabled); presetReverb = new PresetReverb(0,audioSessionId); presetReverb.setEnabled(AppSettings.enableEqualizer); bassBoost = new BassBoost(0,audioSessionId); bassBoost.setEnabled(AppSettings.enableEqualizer); virtualizer = new Virtualizer(0,audioSessionId); virtualizer.setEnabled(AppSettings.enableEqualizer); loudnessEnhancer = new LoudnessEnhancer(audioSessionId); loudnessEnhancer.setEnabled(AppSettings.enableEqualizer); if (AppSettings.enableEqualizer) { int default_reverb = preferences.getInt("selected_reverb", 0); presetReverb.setPreset((short)default_reverb); int default_bass = preferences.getInt("selected_bass", 0); bassBoost.setStrength((short)default_bass); int default_virtualizer = preferences.getInt("selected_virtualizer", 0); virtualizer.setStrength((short)default_virtualizer); int default_loudness = preferences.getInt("selected_loudness", 0); loudnessEnhancer.setTargetGain((short)default_loudness); } isEqualizerSet=true; int current = settingPref.getInt("position", 0); if (current == 0) { for (short seek_id = 0; seek_id < mEqualizer.getNumberOfBands(); seek_id++) { int progressBar = settingPref.getInt("seek_" + seek_id, 1500); short equalizerBandIndex = seek_id; final short lowerEqualizerBandLevel = mEqualizer.getBandLevelRange()[0]; Log.i("seek_" + seek_id, ":" + progressBar); if (progressBar != 1500) { mEqualizer.setBandLevel(equalizerBandIndex, (short) (progressBar + lowerEqualizerBandLevel)); } else { mEqualizer.setBandLevel(equalizerBandIndex, (short) (progressBar + lowerEqualizerBandLevel)); } } } }catch (Exception ignored) {} } private static void addVideoToList(final YTMedia media, final String videoTitle, final String channelTitle) { YTMedia newMedia = media; String ytText=""; boolean isaudio=false; String ext = "m4a"; try { if (media.getAudioSampleRate() != 0) { isaudio = true; ytText = media.getBitrate()/1000 + " kbps"; } else { ext = "mp4"; Log.e(TAG, "addVideoToList: "+media.getHeight()); ytText = (media.getFps() == 60) ? media.getHeight() + "p60" : media.getHeight() + "p"; for(YTConfig config: ytConfigs) { if (config.getText().equals(ytText)) return; } } // Log.e(TAG, "addVideoToList: Title: "+ytText); }catch (Exception e){e.printStackTrace();} String audioSet=null; if (isaudio) { audioSet = media.getUrl(); if (media.getMimeType().contains("audio/mp4")) { Log.e(TAG, "addVideoToList: AudioUrlSet true" ); audioLink = media.getUrl(); } } if (audioLink==null) audioLink = audioSet; YTConfig ytConfig = new YTConfig(ytText, media.getUrl(), ext, videoTitle, channelTitle,isaudio,imgUrl); if (ytConfig.isAudio()) { ytConfig.setBitRate(media.getBitrate()/1000); }else ytConfig.setExt("mp4"); ytConfigs.add(ytConfig); } public static void rebuildNotification() { boolean setgoing = true; int icon = R.drawable.ic_pause_notify; int favicon = R.drawable.ic_favorite; if (!isplaying) { icon = R.drawable.ic_play_notify; setgoing = false; } if (isFavourite) favicon = R.drawable.ic_favorite_full; Intent intent = new Intent(activity,MusicService.class); intent.setAction("CLOSE_SERVICE"); PendingIntent pendingIntent = PendingIntent.getService(activity,0,intent,0); builder = new NotificationCompat.Builder(activity, "channel_01") .setVisibility(NotificationCompat.VISIBILITY_PUBLIC) .setPriority(NotificationCompat.PRIORITY_LOW) .setSmallIcon(R.drawable.ic_audio_pulse2) .addAction(R.drawable.ic_close,"Close",pendingIntent) .addAction(R.drawable.ic_previous_notify, "Previous", prevPendingIntent) .addAction(icon, "Pause", pausePendingIntent) .addAction(R.drawable.ic_next_notify, "Next", nextPendingIntent) .setStyle(new android.support.v4.media.app.NotificationCompat.MediaStyle() .setShowActionsInCompactView(1,2,3) .setMediaSession(mediaSession.getSessionToken())) .setShowWhen(false) .setContentTitle(videoTitle) .setOngoing(setgoing) .setSound(null) .setContentIntent(clickPendingIntent) .setContentText(channelTitle); try { if (bitmapIcon.getWidth()>1700) { double multiply_factor = 1700.0/(double)bitmapIcon.getWidth(); int height = (int)(bitmapIcon.getHeight() * multiply_factor); bitmapIcon = Bitmap.createScaledBitmap(bitmapIcon,1700,height,false); } builder.setLargeIcon(bitmapIcon); }catch (Exception ignored) { } if (!localPlayBack) builder.addAction(favicon,"Favourite",favouritePendingIntent); notificationManagerCompat.notify(1, builder.build()); } public static void createNotification(Context con) { /** Next song Listener */ Intent newintent = new Intent(con, SongBroadCast.class); newintent.setAction("com.kpstv.youtube.ACTION_NEXT"); nextPendingIntent = PendingIntent.getBroadcast(con, 1, newintent, 0); /** Previous song Listener */ newintent = new Intent(con, SongBroadCast.class); newintent.setAction("com.kpstv.youtube.ACTION_PREVIOUS"); prevPendingIntent = PendingIntent.getBroadcast(con, 2, newintent, 0); /** Play or Pause listener */ newintent = new Intent(con, SongBroadCast.class); newintent.setAction("com.kpstv.youtube.ACTION_PLAY"); pausePendingIntent = PendingIntent.getBroadcast(con, 3, newintent, 0); /** Focus on Click Listener */ newintent = new Intent(con, MainActivity.class); newintent.putExtra("DO", "focus"); clickPendingIntent = PendingIntent.getActivity(con, 4, newintent, 0); /** Favourite Pending intent */ newintent = new Intent(con,SongBroadCast.class); newintent.setAction("com.kpstv.youtube.FAVOURITE_SONG"); favouritePendingIntent = PendingIntent.getBroadcast(con,10,newintent,0); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { CharSequence name = con.getString(R.string.channel_name); String description = con.getString(R.string.channel_description); int importance = NotificationManager.IMPORTANCE_LOW; notificationChannel = new NotificationChannel("channel_01", name, importance); notificationChannel.setDescription(description); notificationManager = con.getSystemService(NotificationManager.class); notificationManager.createNotificationChannel(notificationChannel); NotificationChannel channel = new NotificationChannel("channel_02","Download",importance); notificationManager.createNotificationChannel(channel); } notificationManagerCompat = NotificationManagerCompat.from(con); } public static void changePlayBack(boolean isplay) { Log.e("PlayingState", "Playing State: " + player.isPlayingAd() + ", isPlay:" + isplay); if (isplay) { makePause(); MusicService.player.setPlayWhenReady(true); // updateDuration(); } else { makePlay(); MusicService.player.setPlayWhenReady(false); // mTimer.cancel(); } Log.e("CurrentDur", MusicService.player.getCurrentPosition() + ""); isplaying = isplay; rebuildNotification(); } public static void onClear() { loadProgress.setVisibility(VISIBLE); actionTitle.setVisibility(View.GONE); actionChannelTitle.setVisibility(View.GONE); songProgress.setVisibility(View.GONE); actionPlay.setVisibility(View.GONE); songProgress.setProgress(0); actionUp.setVisibility(View.GONE); player.stop(); player.release(); isplaying = false; total_duration = 0; total_seconds = 0; } public static void onMake() { loadProgress.setVisibility(View.GONE); actionTitle.setVisibility(VISIBLE); actionChannelTitle.setVisibility(View.VISIBLE); songProgress.setVisibility(View.VISIBLE); actionPlay.setVisibility(View.VISIBLE); songProgress.setProgress(0); actionUp.setVisibility(View.VISIBLE); actionTitle.setText(videoTitle); actionChannelTitle.setText(" "+ Html.fromHtml("•")+" "+channelTitle); commonPreExecute(); } public static void playPrevious() { if (ytIndex <= 0) { Toast.makeText(activity, "No previous song in playlist", Toast.LENGTH_SHORT).show(); return; } command=2; onClear(); videoID = YTutils.getVideoID(yturls.get(ytIndex-1)); ytIndex--; AppSettings.playAdCount++; showAd(activity); if (!localPlayBack) { LoadVideo = new loadVideo(); LoadVideo.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,videoID); } else { videoID = yturls.get(ytIndex); LoadOffline = new loadVideo_Local(yturls.get(ytIndex)); LoadOffline.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } public static void playSame() { player.seekTo(0); } public static void playNext() { switch (repeatMode) { case 0: if ((ytIndex + 1) == yturls.size()) { Toast.makeText(activity, "No new song in playlist", Toast.LENGTH_SHORT).show(); return; } case 1: if ((ytIndex + 1) == yturls.size()) { ytIndex=-1; } break; case 2: playSame(); return; } /* if (isLoop) { ytIndex=-1; }else { Toast.makeText(activity, "No new song in playlist", Toast.LENGTH_SHORT).show(); // bottom_player.setVisibility(View.GONE); return; }*/ command=1; onClear(); videoID = YTutils.getVideoID(yturls.get(ytIndex+1)); ytIndex++; AppSettings.playAdCount++; showAd(activity); if (!localPlayBack) { LoadVideo = new loadVideo(); LoadVideo.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR,videoID); }else { videoID = yturls.get(ytIndex); LoadOffline = new loadVideo_Local(yturls.get(ytIndex)); LoadOffline.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR); } } static void makePlay() { try { actionPlay.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_play_circle)); PlayerActivity2.makePlay(); }catch (Exception ignored) { Log.e("PlayerActivity","isnull"); } } static void makePause() { try { actionPlay.setImageDrawable(activity.getResources().getDrawable(R.drawable.ic_pause_circle)); PlayerActivity2.makePause(); }catch (Exception ignored) { Log.e("PlayerActivity","isnull"); } } public static void showAd(Context con) { if (AppSettings.playAdCount%AppSettings.adOffset==0 && AppSettings.playAdCount!=0 && AppSettings.showAds && !localPlayBack) { Log.e(TAG, "showAd: Showing Ad..." ); //TODO: Change ad unit ID, Sample ca-app-pub-3940256099942544/1033173712 try { PlayerActivity2.showAd(); }catch (Exception ex){ try { InterstitialAd mInterstitialAd = new InterstitialAd(con); mInterstitialAd.setAdUnitId("ca-app-pub-1164424526503510/4801416648"); mInterstitialAd.loadAd(new AdRequest.Builder().addTestDevice("07153BA64BB64F7C3F726B71C4AE30B9").build()); mInterstitialAd.setAdListener(new AdListener() { @Override public void onAdFailedToLoad(int i) { super.onAdFailedToLoad(i); Log.e(TAG, "onAdFailedToLoad: Ad failed to load: " + i); } @Override public void onAdLoaded() { super.onAdLoaded(); mInterstitialAd.show(); } }); } catch (Exception ignored){} } } } private static class saveToHistory extends AsyncTask<String, Void, Void> { @Override protected void onPostExecute(Void aVoid) { super.onPostExecute(aVoid); } @Override protected Void doInBackground(String... strings) { String url_link = strings[0]; String ytID = YTutils.getVideoID(url_link); String formattedDate = YTutils.getTodayDate(); int percent = 100; if (!url_link.contains("soundcloud.com")) { try { percent = likeCounts*100/(likeCounts+dislikeCounts); }catch (Exception e){e.printStackTrace();} } String videoTitle = MusicService.videoTitle.replace("|",""); String channelTitle = MusicService.channelTitle.replace("|",""); String insert_data = ytID+"|"+1+"|"+videoTitle+"|"+channelTitle+"|"+imgUrl+ "|" + formattedDate+"|"+percent; String historyData = YTutils.readContent(activity,"history.csv"); if (historyData!=null && !historyData.isEmpty()) { if (historyData.contains(ytID+"|")) { String[] childs = historyData.split("\n|\r"); StringBuilder builder = new StringBuilder(); builder.append(insert_data); for (int i=0;i<childs.length;i++) { if (!childs[i].startsWith(ytID)) builder.append("\n").append(childs[i]); } YTutils.writeContent(activity,"history.csv",builder.toString().trim()); }else YTutils.writeContent(activity,"history.csv", insert_data+"\n"+historyData.trim()); }else YTutils.writeContent(activity,"history.csv", insert_data); /** A logic to calculate no of times a song is played and saved to list */ String data = YTutils.readContent(activity,"library.csv"); if (data!=null && !data.isEmpty()) { boolean ifExist=false; if (data.contains(ytID)) { String[] items = data.split("\n|\r"); for (int i=0;i<items.length;i++) { if (items[i].contains(ytID)) { ifExist=true; int count = Integer.parseInt(items[i].split("\\|")[1]); items[i] = ytID+"|"+ (++count)+"|"+videoTitle+"|"+channelTitle+"|"+imgUrl+ "|" + formattedDate+"|"+percent; String lines = YTutils.join(items,'\n'); YTutils.writeContent(activity,"library.csv",lines.trim()); break; } } } if (!ifExist) { YTutils.writeContent(activity,"library.csv", data.trim()+"\n"+insert_data); } }else YTutils.writeContent(activity,"library.csv",insert_data); if (!loadedFromData) DataUtils.saveUrl(activity,videoID,audioLink,ytConfigs); /*// Get playlist ArrayList<String> urls = new ArrayList<>(); if (!Objects.requireNonNull(set).isEmpty()) { urls.addAll(Arrays.asList(set.split(","))); } // Add to playlist by removing it first for (int i = 0; i < urls.size(); i++) { if (urls.get(i).contains(Objects.requireNonNull(YTutils.getVideoID(url_link)))) { urls.remove(i); } } Log.e("StringtoAdd", url_link + "|" + formattedDate+"|"+percent); urls.add(0, url_link + "|" + formattedDate+"|"+percent); // Save playlist StringBuilder sb = new StringBuilder(); for (int i = 0; i < urls.size(); i++) { sb.append(urls.get(i)).append(","); } SharedPreferences.Editor prefsEditor = preferences.edit(); prefsEditor.putString("urls", sb.toString()); prefsEditor.apply();*/ return null; } } }