播放页面Ui

This commit is contained in:
litingting 2024-09-25 10:31:03 +08:00
parent 7f065a1835
commit 96eecd07e7
18 changed files with 676 additions and 163 deletions

View File

@ -59,6 +59,8 @@ dependencies {
//----------media3 //----------media3
implementation("androidx.media3:media3-exoplayer:1.4.1") implementation("androidx.media3:media3-exoplayer:1.4.1")
implementation("androidx.media3:media3-exoplayer-dash:1.4.1")
implementation("androidx.media3:media3-session:1.4.1") implementation("androidx.media3:media3-session:1.4.1")
implementation("androidx.media3:media3-ui:1.4.1")
//----------media3 //----------media3
} }

View File

@ -0,0 +1,9 @@
package com.hi.music.player.api;
public interface MediaControllerListener {
void onMediaControllerComplete(boolean isOk);
void onPlayStatus(int playStatus);
}

View File

@ -62,4 +62,22 @@ public class CommonUtils {
} }
return statusBarHeight; return statusBarHeight;
} }
//time 3:45
public static long convertToMilliseconds(String time) {
String[] parts = time.split(":");
int minutes = Integer.parseInt(parts[0]);
int seconds = Integer.parseInt(parts[1]);
return (minutes * 60 + seconds) * 1000; // 转换为毫秒
}
public static String convertMillisToTime(long millis) {
long seconds = (millis / 1000) % 60;
long minutes = (millis / (1000 * 60)) % 60;
return String.format("%d:%02d", minutes, seconds); // 格式化为 mm:ss
}
} }

View File

@ -0,0 +1,39 @@
package com.hi.music.player.javabean.requestbody;
import com.hi.music.player.javabean.requestbody.child.ContextBody;
import java.io.Serializable;
/**
* 首页接口请求体
*/
public class BodyPlayUrl implements Serializable {
private String videoId ;
private ContextBody context = new ContextBody();
public String getVideoId() {
return videoId;
}
public void setVideoId(String videoId) {
this.videoId = videoId;
}
public ContextBody getContext() {
return context;
}
public void setContext(ContextBody context) {
this.context = context;
}
}

View File

@ -7,6 +7,13 @@ public class ContextBody {
private Client client = new Client(); private Client client = new Client();
private ThirdParty thirdParty = new ThirdParty();
public ThirdParty getThirdParty() {
return thirdParty;
}
public Client getClient() { public Client getClient() {
return client; return client;
} }
@ -16,7 +23,7 @@ public class ContextBody {
} }
public class Client implements Serializable { public static class Client implements Serializable {
private String clientName = "WEB_REMIX"; private String clientName = "WEB_REMIX";
private String clientVersion = "1.20220918"; private String clientVersion = "1.20220918";
private String hl = Locale.getDefault().getLanguage(); private String hl = Locale.getDefault().getLanguage();
@ -32,5 +39,27 @@ public class ContextBody {
public void setVisitorData(String visitorData) { public void setVisitorData(String visitorData) {
this.visitorData = visitorData; this.visitorData = visitorData;
} }
public void setClientName(String clientName) {
this.clientName = clientName;
}
public void setClientVersion(String clientVersion) {
this.clientVersion = clientVersion;
}
public void setPlatform(String platform) {
this.platform = platform;
}
}
public static class ThirdParty{
//https://www.youtube.com/watch?v=UqyT8IEBkvY
private String embedUrl;
public void setEmbedUrl(String embedUrl) {
this.embedUrl = embedUrl;
}
} }
} }

View File

@ -16,7 +16,7 @@ public class ResponseHome {
private String continuation; private String continuation;
@Nullable @Nullable
//用于更多数据请求的visitorData(只有第一个接口会返回该值) //用于更多数据请求的visitorData(只有第一个接口会返回该值,youtubei/v1/browse?prettyPrint=false)
private String visitorData; private String visitorData;
@Nullable @Nullable

View File

@ -1,6 +1,6 @@
package com.hi.music.player.javabean.response; package com.hi.music.player.javabean.response;
public class ResponsePlay { public class ResponsePlayListInfo {
//封面 //封面
private String covert; private String covert;
@ -20,11 +20,22 @@ public class ResponsePlay {
private String Duration; private String Duration;
//歌曲时长 毫秒
private long DurationMs;
private String videoId; private String videoId;
private String playlistId; private String playlistId;
private String params; private String params;
private String musicVideoType; private String musicVideoType;
public long getDurationMs() {
return DurationMs;
}
public void setDurationMs(long durationMs) {
DurationMs = durationMs;
}
public String getDuration() { public String getDuration() {
return Duration; return Duration;

View File

@ -0,0 +1,55 @@
package com.hi.music.player.javabean.response;
public class ResponsePlayUrl {
private String status;
private String audioUrlLow;
private String audioUrlMedium;
private String videoId;
public String getAudioUrlMedium() {
return audioUrlMedium;
}
public void setAudioUrlMedium(String audioUrlMedium) {
this.audioUrlMedium = audioUrlMedium;
}
///AUDIO_QUALITY_MEDIUMAUDIO_QUALITY_LOW
// private String audioQuality;
//
//
// public String getAudioQuality() {
// return audioQuality;
// }
//
// public void setAudioQuality(String audioQuality) {
// this.audioQuality = audioQuality;
// }
public String getVideoId() {
return videoId;
}
public void setVideoId(String videoId) {
this.videoId = videoId;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getAudioUrlLow() {
return audioUrlLow;
}
public void setAudioUrlLow(String audioUrlLow) {
this.audioUrlLow = audioUrlLow;
}
}

View File

@ -0,0 +1,13 @@
package com.hi.music.player.media3;
import android.content.Context;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.ui.PlayerControlView;
@UnstableApi
public class MyControllerView extends PlayerControlView{
public MyControllerView(Context context) {
super(context);
}
}

View File

@ -2,16 +2,22 @@ package com.hi.music.player.media3;
import android.content.ComponentName; import android.content.ComponentName;
import androidx.annotation.OptIn;
import androidx.media3.common.MediaItem; import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata; import androidx.media3.common.MediaMetadata;
import androidx.media3.common.PlaybackException;
import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.session.MediaController; import androidx.media3.session.MediaController;
import androidx.media3.session.SessionToken; import androidx.media3.session.SessionToken;
import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors; import com.google.common.util.concurrent.MoreExecutors;
import com.hi.music.player.MusicApplication; import com.hi.music.player.MusicApplication;
import com.hi.music.player.api.MediaControllerListener;
import com.hi.music.player.helper.CommonUtils; import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlay; import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.network.RetrofitManager; import com.hi.music.player.network.RetrofitManager;
import java.util.ArrayList; import java.util.ArrayList;
@ -34,7 +40,7 @@ public class MyMediaControllerManager {
return myMediaControllerManagerInstance; return myMediaControllerManagerInstance;
} }
public void init(){ public void init(MediaControllerListener mediaControllerListener){
SessionToken sessionToken = SessionToken sessionToken =
new SessionToken(MusicApplication.myApplication, new ComponentName(MusicApplication.myApplication, PlaybackService.class)); new SessionToken(MusicApplication.myApplication, new ComponentName(MusicApplication.myApplication, PlaybackService.class));
ListenableFuture<MediaController> controllerFuture = ListenableFuture<MediaController> controllerFuture =
@ -46,8 +52,30 @@ public class MyMediaControllerManager {
// playerView.setPlayer(controllerFuture.get()); // playerView.setPlayer(controllerFuture.get());
try { try {
mediaController = controllerFuture.get(); mediaController = controllerFuture.get();
mediaController.addListener(new Player.Listener() {
@Override
public void onPlayerError(PlaybackException error) {
CommonUtils.LogMsg("=-----PlaybackException+"+error.getMessage());
}
@Override
public void onPlaybackStateChanged(int playbackState) {
CommonUtils.LogMsg("=-----playbackState+"+playbackState);
mediaControllerListener.onPlayStatus(playbackState);
}
@Override
public void onPositionDiscontinuity(Player.PositionInfo oldPosition, Player.PositionInfo newPosition, int reason) {
// 快进快退等操作
CommonUtils.LogMsg("=-----newPosition+"+newPosition.positionMs);
// mediaControllerListener.onPlayStatus(playbackState);
}
});
mediaControllerListener.onMediaControllerComplete(true);
CommonUtils.LogMsg("=-----mediaController+"+mediaController);
} catch (ExecutionException | InterruptedException e) { } catch (ExecutionException | InterruptedException e) {
CommonUtils.LogErrorMsg(e.getMessage()); CommonUtils.LogErrorMsg(e.getMessage());
mediaControllerListener.onMediaControllerComplete(false);
} }
}, MoreExecutors.directExecutor()); }, MoreExecutors.directExecutor());
@ -55,17 +83,33 @@ public class MyMediaControllerManager {
} }
public void addMusicPlay(ResponsePlay responsePlay){ public MediaController getMediaController() {
return mediaController;
}
public long getContentPos() {
return mediaController.getContentPosition();
}
@OptIn(markerClass = UnstableApi.class)
public void addMusicPlay(ResponsePlayListInfo playInfo, ResponsePlayUrl responsePlay){
List<MediaItem> mediaItems = new ArrayList<>(); List<MediaItem> mediaItems = new ArrayList<>();
MediaItem.Builder builder = new MediaItem.Builder(); MediaItem.Builder builder = new MediaItem.Builder();
builder.setUri(responsePlay.getVideoId()); if(responsePlay.getAudioUrlMedium()!= null){
builder.setUri(responsePlay.getAudioUrlMedium());
}else {
builder.setUri(responsePlay.getAudioUrlLow());
}
builder.setMediaId(responsePlay.getVideoId());
MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder(); MediaMetadata.Builder MediaMetadata_builder = new MediaMetadata.Builder();
// MediaMetadata_builder.setMediaType();
// MediaMetadata_builder.setAlbumTitle(); MediaMetadata_builder.setArtist(playInfo.getSingerName());
// MediaMetadata_builder.setArtist(); // MediaMetadata_builder.setDurationMs( );
// MediaMetadata_builder.setDurationMs(); MediaMetadata_builder.setAlbumArtist(playInfo.getCovert());
// MediaMetadata_builder.setTitle(); MediaMetadata_builder.setTitle(playInfo.getSongTitle());
// MediaMetadata_builder.setRecordingYear(); // MediaMetadata_builder.setRecordingYear(Integer.parseInt(playInfo.getYear()));
builder.setMediaMetadata(MediaMetadata_builder.build()); builder.setMediaMetadata(MediaMetadata_builder.build());
mediaItems.add(builder.build()); mediaItems.add(builder.build());
@ -76,4 +120,6 @@ public class MyMediaControllerManager {
public void play(){ public void play(){
mediaController.play(); mediaController.play();
} }
} }

View File

@ -1,18 +1,64 @@
package com.hi.music.player.media3; package com.hi.music.player.media3;
import android.content.Intent;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.media3.common.AudioAttributes;
import androidx.media3.common.C;
import androidx.media3.common.MediaItem;
import androidx.media3.common.MediaMetadata;
import androidx.media3.common.Player;
import androidx.media3.exoplayer.ExoPlayer; import androidx.media3.exoplayer.ExoPlayer;
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory;
import androidx.media3.exoplayer.source.MediaSource;
import androidx.media3.session.MediaSession; import androidx.media3.session.MediaSession;
import androidx.media3.session.MediaSessionService; import androidx.media3.session.MediaSessionService;
import com.google.common.util.concurrent.ListenableFuture;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import java.util.ArrayList;
import java.util.List;
public class PlaybackService extends MediaSessionService { public class PlaybackService extends MediaSessionService {
private MediaSession mediaSession = null; private MediaSession mediaSession = null;
private ExoPlayer player;
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
ExoPlayer player = new ExoPlayer.Builder(this).build();
mediaSession = new MediaSession.Builder(this, player).build(); AudioAttributes audioAttributes = new AudioAttributes.Builder().setUsage(AudioAttributes.DEFAULT.usage)
.setContentType(AudioAttributes.DEFAULT.contentType)
.build();
// MediaSource.Factory mediaSourceFactory =
// new DefaultMediaSourceFactory(context)
// .setDataSourceFactory(cacheDataSourceFactory)
// .setLocalAdInsertionComponents(adsLoaderProvider);
player = new ExoPlayer.Builder(this)
.setWakeMode(C.WAKE_MODE_LOCAL)
// .setMediaSourceFactory(mediaSourceFactory)
.setAudioAttributes(audioAttributes, true).build();
mediaSession = new MediaSession.Builder(this, player).setCallback(new MediaSession.Callback() {
@Override
public ListenableFuture<List<MediaItem>> onAddMediaItems(MediaSession mediaSession, MediaSession.ControllerInfo controller, List<MediaItem> mediaItems) {
CommonUtils.LogMsg("--------mediaItems="+mediaItems.get(0).mediaMetadata.title);
// player.addMediaItems(mediaItems);
return MediaSession.Callback.super.onAddMediaItems(mediaSession, controller, mediaItems);
} }
})
.build();
}
@ -22,6 +68,16 @@ public class PlaybackService extends MediaSessionService {
return mediaSession; return mediaSession;
} }
@Override
public void onTaskRemoved(@Nullable Intent rootIntent) {
Player player = mediaSession.getPlayer();
// if (player.getPlayWhenReady()) {
// // Make sure the service is not in foreground.
// player.pause();
// }
// stopSelf();
}
@Override @Override
public void onDestroy() { public void onDestroy() {
mediaSession.getPlayer().release(); mediaSession.getPlayer().release();

View File

@ -1,7 +1,8 @@
package com.hi.music.player.network; package com.hi.music.player.network;
import com.hi.music.player.helper.CommonUtils; import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponsePlay; import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.javabean.response.child.ResponseCategory; import com.hi.music.player.javabean.response.child.ResponseCategory;
import com.hi.music.player.javabean.response.ResponseHome; import com.hi.music.player.javabean.response.ResponseHome;
import com.hi.music.player.javabean.response.child.ResponseHomeChild; import com.hi.music.player.javabean.response.child.ResponseHomeChild;
@ -21,20 +22,11 @@ public class JsonHelper {
public static ResponseHome ResolveHomeJson(JSONObject jsonObject) { public static ResponseHome ResolveHomeJson(JSONObject jsonObject) {
ResponseHome responseHome = new ResponseHome(); ResponseHome responseHome = new ResponseHome();
try { try {
String bgUrl = getJsonUrl(jsonObject String bgUrl = getJsonUrl(jsonObject.getJSONObject("background"));
.getJSONObject("background"));
JSONObject sectionListRenderer = jsonObject JSONObject sectionListRenderer = jsonObject.getJSONObject("contents").getJSONObject("singleColumnBrowseResultsRenderer").getJSONArray("tabs").getJSONObject(0).getJSONObject("tabRenderer").getJSONObject("content").getJSONObject("sectionListRenderer");
.getJSONObject("contents")
.getJSONObject("singleColumnBrowseResultsRenderer")
.getJSONArray("tabs")
.getJSONObject(0)
.getJSONObject("tabRenderer")
.getJSONObject("content")
.getJSONObject("sectionListRenderer");
JSONObject responseContext = jsonObject JSONObject responseContext = jsonObject.getJSONObject("responseContext");
.getJSONObject("responseContext");
JSONArray serviceTrackingParams = responseContext.getJSONArray("serviceTrackingParams"); JSONArray serviceTrackingParams = responseContext.getJSONArray("serviceTrackingParams");
String visitorData = responseContext.getString("visitorData"); String visitorData = responseContext.getString("visitorData");
CommonUtils.LogMsg("---------参数-visitorData=" + visitorData); CommonUtils.LogMsg("---------参数-visitorData=" + visitorData);
@ -58,13 +50,10 @@ public class JsonHelper {
ResponseHome responseHome = new ResponseHome(); ResponseHome responseHome = new ResponseHome();
try { try {
JSONObject sectionListContinuation = jsonObject JSONObject sectionListContinuation = jsonObject.getJSONObject("continuationContents").getJSONObject("sectionListContinuation");
.getJSONObject("continuationContents")
.getJSONObject("sectionListContinuation");
JSONObject responseContext = jsonObject JSONObject responseContext = jsonObject.getJSONObject("responseContext");
.getJSONObject("responseContext");
JSONArray serviceTrackingParams = responseContext.getJSONArray("serviceTrackingParams"); JSONArray serviceTrackingParams = responseContext.getJSONArray("serviceTrackingParams");
getCommonHome(sectionListContinuation, responseHome); getCommonHome(sectionListContinuation, responseHome);
@ -77,73 +66,10 @@ public class JsonHelper {
return responseHome; return responseHome;
} }
public static List<ResponsePlay> ResolvePlayJson(JSONObject jsonObject) {
List<ResponsePlay> list = new ArrayList<>();
try {
JSONObject playlistPanelRenderer = jsonObject.getJSONObject("contents")
.getJSONObject("singleColumnMusicWatchNextResultsRenderer")
.getJSONObject("tabbedRenderer")
.getJSONObject("watchNextTabbedResultsRenderer")
.getJSONArray("tabs")
.getJSONObject(0)
.getJSONObject("tabRenderer")
.getJSONObject("content")
.getJSONObject("musicQueueRenderer")
.getJSONObject("content")
.getJSONObject("playlistPanelRenderer");
JSONArray contents = playlistPanelRenderer.getJSONArray("contents");
for (int i = 0; i < contents.length(); i++) {
ResponsePlay responsePlay = new ResponsePlay();
JSONObject playlistPanelVideoRenderer = contents.getJSONObject(i)
.getJSONObject("playlistPanelVideoRenderer");
String jsonUrl = getJsonUrl(playlistPanelVideoRenderer);
String songName = getJsonTitle(playlistPanelVideoRenderer.getJSONObject("title"), 0);
JSONObject longBylineText = playlistPanelVideoRenderer.getJSONObject("longBylineText");
String singerName = getJsonTitle(longBylineText, 0);
String AlbumTitle = getJsonTitle(longBylineText, 2);
String YearRelease = getJsonTitle(longBylineText, 4);
String SongDuration = getJsonTitle(playlistPanelVideoRenderer.getJSONObject("lengthText"), 0);
String[] watchEndPoint = getWatchEndPoint(playlistPanelVideoRenderer);
responsePlay.setCovert(jsonUrl);
responsePlay.setSongTitle(songName);
responsePlay.setSingerName(singerName);
responsePlay.setAlbumTitle(AlbumTitle);
responsePlay.setYear(YearRelease);
responsePlay.setDuration(SongDuration);
responsePlay.setVideoId(watchEndPoint[0]);
responsePlay.setPlaylistId(watchEndPoint[1]);
responsePlay.setParams(watchEndPoint[2]);
responsePlay.setMusicVideoType(watchEndPoint[3]);
list.add(responsePlay);
CommonUtils.LogMsg("----------歌曲名字=" + songName + "---" + Arrays.toString(watchEndPoint));
}
} catch (JSONException exception) {
CommonUtils.LogMsg("----------exception=");
exception.printStackTrace();
}
return list;
}
private static void getCommonHome(JSONObject sectionListRenderer, ResponseHome responseHome) throws JSONException { private static void getCommonHome(JSONObject sectionListRenderer, ResponseHome responseHome) throws JSONException {
JSONObject nextContinuationData = sectionListRenderer JSONObject nextContinuationData = sectionListRenderer.getJSONArray("continuations").getJSONObject(0).getJSONObject("nextContinuationData");
.getJSONArray("continuations")
.getJSONObject(0)
.getJSONObject("nextContinuationData");
//token=continuation,cit= clickTrackingParams //token=continuation,cit= clickTrackingParams
@ -154,8 +80,7 @@ public class JsonHelper {
responseHome.setClickTrackingParams(clickTrackingParams); responseHome.setClickTrackingParams(clickTrackingParams);
responseHome.setContinuation(continuation); responseHome.setContinuation(continuation);
JSONArray contents = sectionListRenderer JSONArray contents = sectionListRenderer.getJSONArray("contents");
.getJSONArray("contents");
List<ResponseHomeChild> childList = new ArrayList<>(); List<ResponseHomeChild> childList = new ArrayList<>();
@ -167,14 +92,10 @@ public class JsonHelper {
if (musicCarouselShelfRenderer != null) { if (musicCarouselShelfRenderer != null) {
//模块标题 //模块标题
String title = getJsonTitle(musicCarouselShelfRenderer String title = getJsonTitle(musicCarouselShelfRenderer.getJSONObject("header").getJSONObject("musicCarouselShelfBasicHeaderRenderer").getJSONObject("title"), 0);
.getJSONObject("header")
.getJSONObject("musicCarouselShelfBasicHeaderRenderer")
.getJSONObject("title"), 0);
CommonUtils.LogMsg("----------headertitle=" + title); CommonUtils.LogMsg("----------headertitle=" + title);
responseHomeChild.setHeaderTitle(title); responseHomeChild.setHeaderTitle(title);
JSONArray childContents = musicCarouselShelfRenderer JSONArray childContents = musicCarouselShelfRenderer.getJSONArray("contents");
.getJSONArray("contents");
List<ResponseCategory> categoryList = new ArrayList<>(); List<ResponseCategory> categoryList = new ArrayList<>();
@ -185,8 +106,7 @@ public class JsonHelper {
if (musicResponsiveListItemRenderer != null) { if (musicResponsiveListItemRenderer != null) {
ResponseSingle responseSingle = new ResponseSingle(); ResponseSingle responseSingle = new ResponseSingle();
String SingerHead = getJsonUrl(musicResponsiveListItemRenderer String SingerHead = getJsonUrl(musicResponsiveListItemRenderer.getJSONObject("thumbnail"));
.getJSONObject("thumbnail"));
JSONArray flexColumns = musicResponsiveListItemRenderer.getJSONArray("flexColumns"); JSONArray flexColumns = musicResponsiveListItemRenderer.getJSONArray("flexColumns");
@ -196,16 +116,12 @@ public class JsonHelper {
String SingerName = ""; String SingerName = "";
String Description = ""; String Description = "";
for (int g = 0; g < flexColumns.length(); g++) { for (int g = 0; g < flexColumns.length(); g++) {
JSONObject jsonObject = musicResponsiveListItemRenderer.getJSONArray("flexColumns") JSONObject jsonObject = musicResponsiveListItemRenderer.getJSONArray("flexColumns").getJSONObject(g).getJSONObject("musicResponsiveListItemFlexColumnRenderer").getJSONObject("text");
.getJSONObject(g)
.getJSONObject("musicResponsiveListItemFlexColumnRenderer")
.getJSONObject("text");
String text = getJsonTitle(jsonObject, 0); String text = getJsonTitle(jsonObject, 0);
if (g == 0) { if (g == 0) {
SongTitle = text; SongTitle = text;
JSONObject runs = jsonObject.getJSONArray("runs") JSONObject runs = jsonObject.getJSONArray("runs").getJSONObject(0);
.getJSONObject(0);
String[] watchEndPoint = getWatchEndPoint(runs); String[] watchEndPoint = getWatchEndPoint(runs);
@ -229,8 +145,7 @@ public class JsonHelper {
JSONObject musicTwoRowItemRenderer = jsonList.optJSONObject("musicTwoRowItemRenderer"); JSONObject musicTwoRowItemRenderer = jsonList.optJSONObject("musicTwoRowItemRenderer");
if (musicTwoRowItemRenderer != null) { if (musicTwoRowItemRenderer != null) {
ResponseCategory responseCategory = new ResponseCategory(); ResponseCategory responseCategory = new ResponseCategory();
String covert = getJsonUrl(musicTwoRowItemRenderer String covert = getJsonUrl(musicTwoRowItemRenderer.getJSONObject("thumbnailRenderer"));
.getJSONObject("thumbnailRenderer"));
JSONObject title1 = musicTwoRowItemRenderer.getJSONObject("title"); JSONObject title1 = musicTwoRowItemRenderer.getJSONObject("title");
String twoTitle = getJsonTitle(title1, 0); String twoTitle = getJsonTitle(title1, 0);
@ -259,14 +174,107 @@ public class JsonHelper {
} }
public static List<ResponsePlayListInfo> ResolvePlayListJson(JSONObject jsonObject) {
List<ResponsePlayListInfo> list = new ArrayList<>();
try {
JSONObject playlistPanelRenderer = jsonObject.getJSONObject("contents").getJSONObject("singleColumnMusicWatchNextResultsRenderer").getJSONObject("tabbedRenderer").getJSONObject("watchNextTabbedResultsRenderer").getJSONArray("tabs").getJSONObject(0).getJSONObject("tabRenderer").getJSONObject("content").getJSONObject("musicQueueRenderer").getJSONObject("content").getJSONObject("playlistPanelRenderer");
JSONArray contents = playlistPanelRenderer.getJSONArray("contents");
for (int i = 0; i < contents.length(); i++) {
ResponsePlayListInfo responsePlayListInfo = new ResponsePlayListInfo();
JSONObject playlistPanelVideoRenderer = contents.getJSONObject(i).getJSONObject("playlistPanelVideoRenderer");
String jsonUrl = getJsonUrl(playlistPanelVideoRenderer);
String songName = getJsonTitle(playlistPanelVideoRenderer.getJSONObject("title"), 0);
JSONObject longBylineText = playlistPanelVideoRenderer.getJSONObject("longBylineText");
String singerName = getJsonTitle(longBylineText, 0);
String AlbumTitle = getJsonTitle(longBylineText, 2);
String YearRelease = getJsonTitle(longBylineText, 4);
String SongDuration = getJsonTitle(playlistPanelVideoRenderer.getJSONObject("lengthText"), 0);
long ms = CommonUtils.convertToMilliseconds(SongDuration);
String[] watchEndPoint = getWatchEndPoint(playlistPanelVideoRenderer);
responsePlayListInfo.setCovert(jsonUrl);
responsePlayListInfo.setSongTitle(songName);
responsePlayListInfo.setSingerName(singerName);
responsePlayListInfo.setAlbumTitle(AlbumTitle);
responsePlayListInfo.setYear(YearRelease);
responsePlayListInfo.setDuration(SongDuration);
responsePlayListInfo.setDurationMs(ms);
responsePlayListInfo.setVideoId(watchEndPoint[0]);
responsePlayListInfo.setPlaylistId(watchEndPoint[1]);
responsePlayListInfo.setParams(watchEndPoint[2]);
responsePlayListInfo.setMusicVideoType(watchEndPoint[3]);
list.add(responsePlayListInfo);
CommonUtils.LogMsg("----------歌曲名字=" + songName + "---" + Arrays.toString(watchEndPoint));
}
} catch (JSONException exception) {
CommonUtils.LogMsg("----------exception=");
exception.printStackTrace();
}
return list;
}
public static ResponsePlayUrl ResolvePlayUrlJson(JSONObject jsonObject) {
try {
ResponsePlayUrl responsePlayUrl = new ResponsePlayUrl();
String status = jsonObject.getJSONObject("playabilityStatus").getString("status");
JSONArray jsonArray = jsonObject.getJSONObject("streamingData").getJSONArray("adaptiveFormats");
for (int i = 0; i < jsonArray.length(); i++) {
JSONObject jsonIndex = jsonArray.getJSONObject(i);
String mimeType = jsonIndex.getString("mimeType");
String itag = jsonIndex.getString("itag");
if (mimeType.contains("audio/mp4")) {
String url = jsonIndex.getString("url");
boolean audioQuality1 = jsonIndex.has("audioQuality");
CommonUtils.LogMsg("------------itag="+itag+"---------audioQuality1="+audioQuality1);
if (jsonIndex.has("audioQuality")) {
String audioQuality = jsonIndex.getString("audioQuality");
if (audioQuality.equals("AUDIO_QUALITY_MEDIUM")) {
responsePlayUrl.setAudioUrlMedium(url);
} else {
responsePlayUrl.setAudioUrlLow(url);
}
}
}
}
String videoId = jsonObject.getJSONObject("videoDetails").getString("videoId");
responsePlayUrl.setVideoId(videoId);
responsePlayUrl.setStatus(status);
return responsePlayUrl;
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
private static String[] getWatchEndPoint(JSONObject job) { private static String[] getWatchEndPoint(JSONObject job) {
String[] strings = new String[4]; String[] strings = new String[4];
try { try {
JSONObject watchEndpoint = job JSONObject watchEndpoint = job.getJSONObject("navigationEndpoint").getJSONObject("watchEndpoint");
.getJSONObject("navigationEndpoint")
.getJSONObject("watchEndpoint");
if (watchEndpoint.has("videoId")) { if (watchEndpoint.has("videoId")) {
strings[0] = watchEndpoint.getString("videoId"); strings[0] = watchEndpoint.getString("videoId");
} }
@ -277,9 +285,7 @@ public class JsonHelper {
strings[2] = watchEndpoint.getString("params"); strings[2] = watchEndpoint.getString("params");
} }
if (watchEndpoint.has("watchEndpointMusicSupportedConfigs")) { if (watchEndpoint.has("watchEndpointMusicSupportedConfigs")) {
strings[3] = watchEndpoint.getJSONObject("watchEndpointMusicSupportedConfigs") strings[3] = watchEndpoint.getJSONObject("watchEndpointMusicSupportedConfigs").getJSONObject("watchEndpointMusicConfig").getString("musicVideoType");
.getJSONObject("watchEndpointMusicConfig")
.getString("musicVideoType");
} }
// String videoId = watchEndpoint.getString("videoId"); // String videoId = watchEndpoint.getString("videoId");
// String playlistId = watchEndpoint.getString("playlistId"); // String playlistId = watchEndpoint.getString("playlistId");
@ -300,13 +306,10 @@ public class JsonHelper {
if (b) { if (b) {
jsonObject = jsonObject.getJSONObject("musicThumbnailRenderer"); jsonObject = jsonObject.getJSONObject("musicThumbnailRenderer");
} }
JSONArray jsonArray = jsonObject JSONArray jsonArray = jsonObject.getJSONObject("thumbnail").getJSONArray("thumbnails");
.getJSONObject("thumbnail")
.getJSONArray("thumbnails");
int length = jsonArray.length(); int length = jsonArray.length();
CommonUtils.LogMsg("----------length=" + (length - 1)); CommonUtils.LogMsg("----------length=" + (length - 1));
String pngUrl = jsonArray.getJSONObject(length - 1) String pngUrl = jsonArray.getJSONObject(length - 1).getString("url");
.getString("url");
return pngUrl; return pngUrl;
} catch (JSONException exception) { } catch (JSONException exception) {
@ -320,9 +323,7 @@ public class JsonHelper {
try { try {
JSONArray runs = jsonObject.getJSONArray("runs"); JSONArray runs = jsonObject.getJSONArray("runs");
if (index < runs.length()) { if (index < runs.length()) {
text = runs text = runs.getJSONObject(index).getString("text");
.getJSONObject(index)
.getString("text");
} }
} catch (JSONException exception) { } catch (JSONException exception) {

View File

@ -4,6 +4,7 @@ import io.reactivex.Observable;
import okhttp3.RequestBody; import okhttp3.RequestBody;
import okhttp3.ResponseBody; import okhttp3.ResponseBody;
import retrofit2.http.Body; import retrofit2.http.Body;
import retrofit2.http.GET;
import retrofit2.http.Header; import retrofit2.http.Header;
import retrofit2.http.Headers; import retrofit2.http.Headers;
import retrofit2.http.POST; import retrofit2.http.POST;
@ -31,10 +32,25 @@ public interface MusicApi {
// X-Goog-FieldMask: contents.singleColumnMusicWatchNextResultsRenderer.tabbedRenderer.watchNextTabbedResultsRenderer.tabs.tabRenderer.content.musicQueueRenderer.content.playlistPanelRenderer(continuations,contents(automixPreviewVideoRenderer,playlistPanelVideoRenderer(title,navigationEndpoint,longBylineText,shortBylineText,thumbnail,lengthText))) // X-Goog-FieldMask: contents.singleColumnMusicWatchNextResultsRenderer.tabbedRenderer.watchNextTabbedResultsRenderer.tabs.tabRenderer.content.musicQueueRenderer.content.playlistPanelRenderer(continuations,contents(automixPreviewVideoRenderer,playlistPanelVideoRenderer(title,navigationEndpoint,longBylineText,shortBylineText,thumbnail,lengthText)))
//获取播放列表
@POST("youtubei/v1/next?prettyPrint=false") @POST("youtubei/v1/next?prettyPrint=false")
@Headers("X-Goog-Api-Key:AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8") @Headers("X-Goog-Api-Key:AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8")
Observable<ResponseBody> getMusicPlayPage(@Header("X-Goog-FieldMask") String customHeader, @Body RequestBody requestBody); Observable<ResponseBody> getMusicPlayPage(@Header("X-Goog-FieldMask") String customHeader, @Body RequestBody requestBody);
@POST("youtubei/v1/player?prettyPrint=false")
@Headers({"X-Goog-Api-Key:AIzaSyAO_FJ2SlqU8Q4STEHLGCilw_Y9_11qcW8",
"X-Goog-FieldMask:playabilityStatus.status,playerConfig.audioConfig,streamingData.adaptiveFormats,videoDetails.videoId"})
Observable<ResponseBody> getMusicPlayUrl(@Body RequestBody requestBody);
@GET("videoplayback?expire=1727100941&ei=rSPxZoSXJ_eM2_gPgqT8mAs&ip=146.19.167.8&id=o-ADGacaLEhb3NOOc74tfR50VCTKy0vnUb2_GAm-tPlv9n&itag=137&source=youtube&requiressl=yes&xpc=EgVo2aDSNQ%3D%3D&mh=f8&mm=31%2C29&mn=sn-tt1e7nlz%2Csn-vgqsknzd&ms=au%2Crdu&mv=m&mvi=2&pl=24&gcr=us&initcwndbps=6450000&vprv=1&svpuc=1&mime=video%2Fmp4&rqh=1&gir=yes&clen=4444925&dur=293.280&lmt=1688643558849956&mt=1727078942&fvip=3&keepalive=yes&fexp=51299152&c=ANDROID_MUSIC&txp=4532434&sparams=expire%2Cei%2Cip%2Cid%2Citag%2Csource%2Crequiressl%2Cxpc%2Cgcr%2Cvprv%2Csvpuc%2Cmime%2Crqh%2Cgir%2Cclen%2Cdur%2Clmt&sig=AJfQdSswRgIhAKjjifMN7NMLqeoVXyqHPK1uHqev1PcnVMoycknt4QGfAiEAiCEcEYPDpQsCbE0tJ6MXjvPs4HmT0yM8Yoa26rWpc7M%3D&lsparams=mh%2Cmm%2Cmn%2Cms%2Cmv%2Cmvi%2Cpl%2Cinitcwndbps&lsig=ABPmVW0wRAIgeur5lMiKDgdWV5rrRTkmt0jbOQnifmVQwoTXk_Y17E0CIBfjGXpbdW2u3mtu1I-")
Observable<ResponseBody> getTest();
} }

View File

@ -2,12 +2,10 @@ package com.hi.music.player.network;
import com.google.gson.Gson; import com.google.gson.Gson;
import com.hi.music.player.api.RequestListener; import com.hi.music.player.api.RequestListener;
import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.requestbody.BodyHome; import com.hi.music.player.javabean.requestbody.BodyHome;
import com.hi.music.player.javabean.requestbody.BodyPlay; import com.hi.music.player.javabean.requestbody.BodyPlay;
import com.hi.music.player.javabean.response.ResponseHome; import com.hi.music.player.javabean.requestbody.BodyPlayUrl;
import com.hi.music.player.javabean.requestbody.child.ContextBody;
import org.json.JSONObject;
import java.util.HashMap; import java.util.HashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -26,6 +24,8 @@ import retrofit2.converter.gson.GsonConverterFactory;
public class RetrofitManager { public class RetrofitManager {
private String base_Host = "https://music.youtube.com/"; private String base_Host = "https://music.youtube.com/";
private String base_Host_test = "https://rr2---sn-tt1e7nlz.googlevideo.com/";
private static volatile RetrofitManager REQUEST_MANAGER; private static volatile RetrofitManager REQUEST_MANAGER;
private Retrofit retrofit; private Retrofit retrofit;
@ -110,7 +110,7 @@ public class RetrofitManager {
} }
public void getNext(String params,String playlistId,String videoId,String musicVideoType,RequestListener<ResponseBody> requestListener) { public void getPlayList(String params, String playlistId, String videoId, String musicVideoType, RequestListener<ResponseBody> requestListener) {
BodyPlay bodyPlay = new BodyPlay(); BodyPlay bodyPlay = new BodyPlay();
bodyPlay.setParams(params); bodyPlay.setParams(params);
bodyPlay.setPlaylistId(playlistId); bodyPlay.setPlaylistId(playlistId);
@ -125,4 +125,29 @@ public class RetrofitManager {
.observeOn(AndroidSchedulers.mainThread()) .observeOn(AndroidSchedulers.mainThread())
.subscribe(new ObserverWrapper<ResponseBody>(requestListener)); .subscribe(new ObserverWrapper<ResponseBody>(requestListener));
} }
public void getPlayUrl(String videoId,RequestListener<ResponseBody> requestListener) {
BodyPlayUrl bodyPlay = new BodyPlayUrl();
bodyPlay.setVideoId(videoId);
ContextBody.Client client = bodyPlay.getContext().getClient();
client.setClientName("ANDROID_MUSIC");
client.setClientVersion("5.28.1");
client.setPlatform("MOBILE");
bodyPlay.getContext().getThirdParty().setEmbedUrl("https://www.youtube.com/watch?v="+videoId);
Gson gson = new Gson();
String s = gson.toJson(bodyPlay);
RequestBody requestBody = RequestBody.Companion.create(s, JSON);
musicApi.getMusicPlayUrl(requestBody)
.subscribeOn(Schedulers.io())
.unsubscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe(new ObserverWrapper<ResponseBody>(requestListener));
}
} }

View File

@ -2,11 +2,17 @@ package com.hi.music.player.ui.activity;
import android.content.Intent; import android.content.Intent;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Handler;
import android.view.View; import android.view.View;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.OptIn;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.Observer; import androidx.lifecycle.Observer;
import androidx.media3.common.Player;
import androidx.media3.common.util.UnstableApi;
import androidx.media3.session.MediaController;
import com.bumptech.glide.Glide; import com.bumptech.glide.Glide;
import com.bumptech.glide.load.DataSource; import com.bumptech.glide.load.DataSource;
@ -17,10 +23,12 @@ import com.bumptech.glide.request.RequestOptions;
import com.bumptech.glide.request.target.Target; import com.bumptech.glide.request.target.Target;
import com.hi.music.player.MusicApplication; import com.hi.music.player.MusicApplication;
import com.hi.music.player.R; import com.hi.music.player.R;
import com.hi.music.player.api.MediaControllerListener;
import com.hi.music.player.databinding.ActivityPlayBinding; import com.hi.music.player.databinding.ActivityPlayBinding;
import com.hi.music.player.helper.CommonUtils; import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.helper.MyValue; import com.hi.music.player.helper.MyValue;
import com.hi.music.player.javabean.response.ResponsePlay; import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.javabean.response.child.ResponseSingle; import com.hi.music.player.javabean.response.child.ResponseSingle;
import com.hi.music.player.media3.MyMediaControllerManager; import com.hi.music.player.media3.MyMediaControllerManager;
import com.hi.music.player.ui.activity.viewmodel.VMPlay; import com.hi.music.player.ui.activity.viewmodel.VMPlay;
@ -32,7 +40,13 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
private ResponseSingle responseSingle; private ResponseSingle responseSingle;
private VMPlay vmPlay; private VMPlay vmPlay;
private MyMediaControllerManager mediaController; private List<ResponsePlayListInfo> mPlayList;
private ResponsePlayUrl mCurPlayInfo;
private ResponsePlayListInfo musicInfo;
private Handler mHandler;
private Runnable mRunnable;
private MyMediaControllerManager mediaControllerManager;
@Override @Override
protected ActivityPlayBinding getViewBinding() { protected ActivityPlayBinding getViewBinding() {
@ -44,21 +58,78 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
Intent intent = getIntent(); Intent intent = getIntent();
responseSingle = (ResponseSingle) intent.getSerializableExtra(MyValue.KEY_PLAY_ACTIVITY_SINGER); responseSingle = (ResponseSingle) intent.getSerializableExtra(MyValue.KEY_PLAY_ACTIVITY_SINGER);
vmPlay = getActivityScopeViewModel(VMPlay.class); vmPlay = getActivityScopeViewModel(VMPlay.class);
vmPlay.getPlay(responseSingle); vmPlay.getPlayUrl(responseSingle);
vmPlay.getPlayMusicList(responseSingle);
initPlayerView();
initMediaController();
vmPlay.data.observe(this, new Observer<List<ResponsePlay>>() { vmPlay.data.observe(this, new Observer<List<ResponsePlayListInfo>>() {
@Override @Override
public void onChanged(List<ResponsePlay> playList) { public void onChanged(List<ResponsePlayListInfo> playList) {
if (playList.size() > 0) { if (playList.size() > 0) {
ResponsePlay responsePlay = playList.get(0); mPlayList = playList;
loadCovert(responsePlay.getCovert()); musicInfo = playList.get(0);
loadInfo(responsePlay); loadCovert(musicInfo.getCovert());
loadInfo(musicInfo);
startPlayMusic();
} }
} }
}); });
vmPlay.playUrlLiveData.observe(this, new Observer<ResponsePlayUrl>() {
@Override
public void onChanged(ResponsePlayUrl responsePlayUrl) {
mCurPlayInfo = responsePlayUrl;
CommonUtils.LogMsg("---------mCurPlayInfo=" + mCurPlayInfo.getAudioUrlLow());
startPlayMusic();
}
});
}
@OptIn(markerClass = UnstableApi.class)
private void initPlayerView() {
vb.playerView.setShowRewindButton(false);
vb.playerView.setShowPreviousButton(false);
vb.playerView.setDefaultArtwork(ContextCompat.getDrawable(this, R.mipmap.ic_launcher));
}
private void initMediaController() {
mediaControllerManager = MyMediaControllerManager.getInstance();
mediaControllerManager.init(new MediaControllerListener() {
@Override
public void onMediaControllerComplete(boolean isOk) {
MediaController mediaController1 = mediaControllerManager.getMediaController();
vb.playerView.setPlayer(mediaController1);
startPlayMusic();
}
@Override
public void onPlayStatus(int playStatus) {
switch (playStatus) {
case Player.STATE_READY:
mHandler.post(mRunnable);
vb.progressBar.setVisibility(View.GONE);
break;
case Player.STATE_ENDED:
mHandler.removeCallbacks(mRunnable); // 停止更新
break;
case Player.STATE_BUFFERING:
break;
}
}
});
} }
@Override @Override
@ -66,14 +137,49 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
vb.btnPlay.setOnClickListener(this::onClick); vb.btnPlay.setOnClickListener(this::onClick);
} }
private void loadInfo(ResponsePlay data) {
/**
* 更新播放进度Ui
*/
private void updatePlaybackProgress() {
// 获取当前播放位置
long contentPos = mediaControllerManager.getContentPos();
long currentPosition = mediaControllerManager.getMediaController().getCurrentPosition();
long duration = mediaControllerManager.getMediaController().getContentDuration();
long durationMs = musicInfo.getDurationMs();
String s = CommonUtils.convertMillisToTime(contentPos);
CommonUtils.LogMsg("---------播放进度-----contentPos=" + contentPos+"----currentPosition="+currentPosition+"------duration="+duration);
vb.tvCurrent.setText(s);
vb.seekbar.setValue(contentPos);
}
/**
* 初始化当前播放歌曲信息
* @param data
*/
private void loadInfo(ResponsePlayListInfo data) {
vb.tvSongName.setText(data.getSongTitle()); vb.tvSongName.setText(data.getSongTitle());
vb.tvSingerName.setText(data.getSingerName()); vb.tvSingerName.setText(data.getSingerName());
vb.tvDuration.setText(data.getDuration()); vb.tvDuration.setText(data.getDuration());
vb.seekbar.setValueTo(data.getDurationMs());
}
private void startPlayMusic() {
initProgressHandler();
CommonUtils.LogMsg("00000");
MediaController mediaController = mediaControllerManager.getMediaController();
if (mCurPlayInfo != null && mediaController != null && mPlayList != null) {
mediaControllerManager.addMusicPlay(mPlayList.get(0), mCurPlayInfo);
mediaControllerManager.play();
CommonUtils.LogMsg("111");
}
mediaController = MyMediaControllerManager.getInstance();
mediaController.init();
mediaController.addMusicPlay(data);
} }
private void loadCovert(String url) { private void loadCovert(String url) {
@ -89,8 +195,11 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
return false; return false;
} }
@OptIn(markerClass = UnstableApi.class)
@Override @Override
public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) { public boolean onResourceReady(@NonNull Drawable resource, @NonNull Object model, Target<Drawable> target, @NonNull DataSource dataSource, boolean isFirstResource) {
vb.playerView.setDefaultArtwork(resource);
return false; return false;
} }
}) })
@ -98,11 +207,16 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
} }
private void initProgressHandler() {
mHandler = new Handler();
mRunnable = new Runnable() {
@Override @Override
public void onStart() { public void run() {
super.onStart(); updatePlaybackProgress();
// 继续定时更新
mHandler.postDelayed(this, 1000); // 每秒更新一次
}
};
} }
@Override @Override
@ -117,9 +231,16 @@ public class PlayActivity extends BaseActivity<ActivityPlayBinding> {
@Override @Override
public void onClick(View v) { public void onClick(View v) {
if(v.equals(vb.btnPlay)){ if (v.equals(vb.btnPlay)) {
mediaController.play(); vb.btnPlay.setSelected(!vb.btnPlay.isSelected());
} }
} }
@Override
protected void onDestroy() {
super.onDestroy();
if (mHandler != null && mRunnable != null)
mHandler.removeCallbacks(mRunnable);
}
} }

View File

@ -6,8 +6,8 @@ import androidx.lifecycle.ViewModel;
import com.hi.music.player.api.RequestListener; import com.hi.music.player.api.RequestListener;
import com.hi.music.player.helper.CommonUtils; import com.hi.music.player.helper.CommonUtils;
import com.hi.music.player.javabean.response.ResponseHome; import com.hi.music.player.javabean.response.ResponsePlayListInfo;
import com.hi.music.player.javabean.response.ResponsePlay; import com.hi.music.player.javabean.response.ResponsePlayUrl;
import com.hi.music.player.javabean.response.child.ResponseSingle; import com.hi.music.player.javabean.response.child.ResponseSingle;
import com.hi.music.player.network.JsonHelper; import com.hi.music.player.network.JsonHelper;
import com.hi.music.player.network.RetrofitManager; import com.hi.music.player.network.RetrofitManager;
@ -21,18 +21,22 @@ import okhttp3.ResponseBody;
public class VMPlay extends ViewModel { public class VMPlay extends ViewModel {
private MutableLiveData<List<ResponsePlay>> _data = new MutableLiveData<List<ResponsePlay>>(); private MutableLiveData<List<ResponsePlayListInfo>> _data = new MutableLiveData<List<ResponsePlayListInfo>>();
public LiveData<List<ResponsePlay>> data = _data; public LiveData<List<ResponsePlayListInfo>> data = _data;
private MutableLiveData<ResponsePlayUrl> _playUrlMutableLiveData = new MutableLiveData<ResponsePlayUrl>();
public LiveData<ResponsePlayUrl> playUrlLiveData = _playUrlMutableLiveData;
private String continuation, clickTrackingParams, visitorData; private String continuation, clickTrackingParams, visitorData;
public void getPlay(ResponseSingle responseSingle) { public void getPlayMusicList(ResponseSingle responseSingle) {
String playlistId = responseSingle.getPlaylistId(); String playlistId = responseSingle.getPlaylistId();
String videoId = responseSingle.getVideoId(); String videoId = responseSingle.getVideoId();
String params = responseSingle.getParams(); String params = responseSingle.getParams();
String musicVideoType = responseSingle.getMusicVideoType(); String musicVideoType = responseSingle.getMusicVideoType();
RetrofitManager.getInstance().getNext(params, playlistId, videoId, musicVideoType, new RequestListener<ResponseBody>() { RetrofitManager.getInstance().getPlayList(params, playlistId, videoId, musicVideoType, new RequestListener<ResponseBody>() {
@Override @Override
public void onFail(String errorMsg) { public void onFail(String errorMsg) {
@ -43,8 +47,8 @@ public class VMPlay extends ViewModel {
public void onSuccess(ResponseBody data) { public void onSuccess(ResponseBody data) {
JSONObject jsonObject = CommonUtils.toJsonObject(data); JSONObject jsonObject = CommonUtils.toJsonObject(data);
if (jsonObject != null) { if (jsonObject != null) {
List<ResponsePlay> responsePlays = JsonHelper.ResolvePlayJson(jsonObject); List<ResponsePlayListInfo> responsePlayListInfos = JsonHelper.ResolvePlayListJson(jsonObject);
_data.setValue(responsePlays); _data.setValue(responsePlayListInfos);
} else { } else {
_data.setValue(null); _data.setValue(null);
} }
@ -53,5 +57,28 @@ public class VMPlay extends ViewModel {
}); });
} }
public void getPlayUrl(ResponseSingle responseSingle) {
String videoId = responseSingle.getVideoId();
RetrofitManager.getInstance().getPlayUrl(videoId, new RequestListener<ResponseBody>() {
@Override
public void onFail(String errorMsg) {
_playUrlMutableLiveData.setValue(null);
}
@Override
public void onSuccess(ResponseBody data) {
JSONObject jsonObject = CommonUtils.toJsonObject(data);
if (jsonObject != null) {
ResponsePlayUrl responsePlayUrl = JsonHelper.ResolvePlayUrlJson(jsonObject);
_playUrlMutableLiveData.setValue(responsePlayUrl);
} else {
_playUrlMutableLiveData.setValue(null);
}
}
});
}
} }

View File

@ -54,9 +54,11 @@ public class HomeFragment extends BaseFragment<FragmentHomeBinding> implements C
vmHome.getHome(); vmHome.getHome();
vmHome.data.observe(getViewLifecycleOwner(), new Observer<ResponseHome>() { vmHome.data.observe(getViewLifecycleOwner(), new Observer<ResponseHome>() {
@Override @Override
public void onChanged(ResponseHome responseHome) { public void onChanged(ResponseHome responseHome) {
if(responseHome == null)return;
List<ResponseHomeChild> childList1 = responseHome.getChildList(); List<ResponseHomeChild> childList1 = responseHome.getChildList();
childList.addAll(childList1); childList.addAll(childList1);
adapterHome.removeLoadingFooter(); adapterHome.removeLoadingFooter();

View File

@ -31,6 +31,32 @@
app:layout_constraintRight_toRightOf="parent" app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back" /> app:layout_constraintTop_toBottomOf="@id/im_back" />
<androidx.media3.ui.PlayerView
android:id="@+id/player_view"
android:layout_width="match_parent"
android:layout_height="0dp"
app:show_buffering="when_playing"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toBottomOf="@id/im_back"
app:show_shuffle_button="true"/>
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="@id/im_covert"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
android:indeterminateTint="@color/white"
android:id="@+id/progressBar"
android:visibility="invisible"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toTopOf="@id/im_covert" />
<TextView <TextView
android:id="@+id/tv_song_name" android:id="@+id/tv_song_name"
android:layout_width="wrap_content" android:layout_width="wrap_content"
@ -53,10 +79,24 @@
app:layout_constraintLeft_toLeftOf="@id/tv_song_name" app:layout_constraintLeft_toLeftOf="@id/tv_song_name"
app:layout_constraintTop_toBottomOf="@id/tv_song_name" /> app:layout_constraintTop_toBottomOf="@id/tv_song_name" />
<SeekBar <com.google.android.material.slider.Slider
android:id="@+id/seekbar" android:id="@+id/seekbar"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:valueFrom="0"
app:layout_constraintLeft_toLeftOf="@id/im_covert"
app:layout_constraintRight_toRightOf="@id/im_covert"
app:layout_constraintTop_toBottomOf="@id/tv_singer_name"
app:labelBehavior="gone"
app:thumbColor="@color/white"
app:thumbRadius="6dp"
app:trackColorActive="@color/white"
app:trackColorInactive="#00000000"
app:trackHeight="3dp" />
<SeekBar
android:id="@+id/seekbar1"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="25dp" android:layout_marginTop="25dp"
android:maxHeight="3dp" android:maxHeight="3dp"
android:paddingStart="0dp" android:paddingStart="0dp"
@ -64,6 +104,7 @@
android:paddingEnd="0dp" android:paddingEnd="0dp"
android:paddingRight="0dp" android:paddingRight="0dp"
android:progress="10" android:progress="10"
android:visibility="gone"
android:progressDrawable="@drawable/seekbar_progress_drawable" android:progressDrawable="@drawable/seekbar_progress_drawable"
android:thumb="@drawable/seekbar_thumb" android:thumb="@drawable/seekbar_thumb"
app:layout_constraintLeft_toLeftOf="@id/im_covert" app:layout_constraintLeft_toLeftOf="@id/im_covert"
@ -131,4 +172,6 @@
app:layout_constraintLeft_toLeftOf="@id/im_covert" /> app:layout_constraintLeft_toLeftOf="@id/im_covert" />
</androidx.constraintlayout.widget.ConstraintLayout> </androidx.constraintlayout.widget.ConstraintLayout>