1
1
package org .schabi .newpipe .player .mediabrowser ;
2
2
3
+ import android .net .Uri ;
3
4
import android .os .Bundle ;
4
- import android .support .v4 .media .MediaBrowserCompat ;
5
+ import android .support .v4 .media .MediaBrowserCompat .MediaItem ;
6
+ import android .support .v4 .media .MediaDescriptionCompat ;
7
+ import android .support .v4 .media .session .MediaSessionCompat ;
5
8
import android .util .Log ;
6
9
7
10
import androidx .annotation .NonNull ;
8
11
import androidx .annotation .Nullable ;
9
12
import androidx .media .MediaBrowserServiceCompat ;
13
+ import androidx .media .MediaBrowserServiceCompat .Result ;
14
+ import androidx .media .utils .MediaConstants ;
10
15
16
+ import org .schabi .newpipe .NewPipeDatabase ;
17
+ import org .schabi .newpipe .R ;
18
+ import org .schabi .newpipe .database .AppDatabase ;
19
+ import org .schabi .newpipe .database .playlist .PlaylistMetadataEntry ;
20
+ import org .schabi .newpipe .database .playlist .PlaylistStreamEntry ;
21
+ import org .schabi .newpipe .local .playlist .LocalPlaylistManager ;
11
22
import org .schabi .newpipe .player .PlayerService ;
23
+ import org .schabi .newpipe .player .playqueue .PlayQueue ;
24
+ import org .schabi .newpipe .player .playqueue .SinglePlayQueue ;
25
+ import org .schabi .newpipe .util .NavigationHelper ;
12
26
13
27
import java .util .ArrayList ;
14
28
import java .util .List ;
29
+ import java .util .regex .Matcher ;
30
+ import java .util .regex .Pattern ;
31
+ import java .util .stream .Collectors ;
15
32
16
- public class MediaBrowserConnector {
33
+ public class MediaBrowserConnector extends MediaSessionCompat . Callback {
17
34
private static final String TAG = MediaBrowserConnector .class .getSimpleName ();
18
35
19
36
private final PlayerService playerService ;
37
+ private AppDatabase database ;
38
+ private LocalPlaylistManager localPlaylistManager ;
20
39
21
40
public MediaBrowserConnector (@ NonNull final PlayerService playerService ) {
22
41
this .playerService = playerService ;
23
42
playerService .setSessionToken (playerService .getMediaSession ().getSessionToken ());
43
+ playerService .getMediaSession ().setCallback (this );
24
44
}
25
45
26
46
@ NonNull
27
47
private static final String MY_MEDIA_ROOT_ID = "media_root_id" ;
48
+ @ NonNull
49
+ private static final String MY_MEDIA_BOOKMARKS_ID = "media_playlists" ;
50
+ @ NonNull
51
+ private static final String MY_MEDIA_HISTORY_ID = "media_history" ;
52
+ @ NonNull
53
+ private static final String MY_MEDIA_BOOKMARKS_PREFIX = "media_playlist_" ;
54
+ @ NonNull
55
+ private static final String MY_MEDIA_ITEM_PREFIX = "media_item_" ;
56
+
57
+ private MediaItem createRootMediaItem (final String mediaId , final String folderName ) {
58
+ final var builder = new MediaDescriptionCompat .Builder ();
59
+ builder .setMediaId (mediaId );
60
+ builder .setTitle (folderName );
61
+
62
+ final var extras = new Bundle ();
63
+ extras .putString (MediaConstants .DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE ,
64
+ "NewPipe" );
65
+ builder .setExtras (extras );
66
+ return new MediaItem (builder .build (), MediaItem .FLAG_BROWSABLE );
67
+ }
68
+
69
+ private MediaItem createPlaylistMediaItem (final PlaylistMetadataEntry playlist ) {
70
+ final var builder = new MediaDescriptionCompat .Builder ();
71
+ builder .setMediaId (createMediaIdForPlaylist (playlist .uid ))
72
+ .setTitle (playlist .name )
73
+ .setIconUri (Uri .parse (playlist .thumbnailUrl ));
74
+
75
+ final var extras = new Bundle ();
76
+ extras .putString (MediaConstants .DESCRIPTION_EXTRAS_KEY_CONTENT_STYLE_GROUP_TITLE ,
77
+ playerService .getResources ().getString (R .string .tab_bookmarks ));
78
+ builder .setExtras (extras );
79
+ return new MediaItem (builder .build (), MediaItem .FLAG_BROWSABLE );
80
+ }
81
+
82
+ private String createMediaIdForPlaylist (final long playlistId ) {
83
+ return MY_MEDIA_BOOKMARKS_PREFIX + playlistId ;
84
+ }
85
+
86
+ private MediaItem createPlaylistStreamMediaItem (final PlaylistMetadataEntry playlist ,
87
+ final PlaylistStreamEntry item ,
88
+ final int index ) {
89
+ final var builder = new MediaDescriptionCompat .Builder ();
90
+ builder .setMediaId (createMediaIdForItem (playlist .uid , index ))
91
+ .setTitle (item .getStreamEntity ().getTitle ())
92
+ .setIconUri (Uri .parse (item .getStreamEntity ().getThumbnailUrl ()));
93
+
94
+ return new MediaItem (builder .build (), MediaItem .FLAG_PLAYABLE );
95
+ }
96
+
97
+ private String createMediaIdForItem (final long playlistId , final int index ) {
98
+ return MY_MEDIA_ITEM_PREFIX + playlistId + "_" + index ;
99
+ }
28
100
29
101
@ Nullable
30
- public MediaBrowserServiceCompat .BrowserRoot onGetRoot (@ NonNull final String clientPackageName , final int clientUid ,
102
+ public MediaBrowserServiceCompat .BrowserRoot onGetRoot (@ NonNull final String clientPackageName ,
103
+ final int clientUid ,
31
104
@ Nullable final Bundle rootHints ) {
32
105
Log .d (TAG , String .format ("MediaBrowserService.onGetRoot(%s, %s, %s)" ,
33
106
clientPackageName , clientUid , rootHints ));
@@ -36,11 +109,93 @@ public MediaBrowserServiceCompat.BrowserRoot onGetRoot(@NonNull final String cli
36
109
}
37
110
38
111
public void onLoadChildren (@ NonNull final String parentId ,
39
- @ NonNull final MediaBrowserServiceCompat . Result <List <MediaBrowserCompat . MediaItem >> result ) {
112
+ @ NonNull final Result <List <MediaItem >> result ) {
40
113
Log .d (TAG , String .format ("MediaBrowserService.onLoadChildren(%s)" , parentId ));
41
114
42
- final List <MediaBrowserCompat . MediaItem > mediaItems = new ArrayList <>();
115
+ final List <MediaItem > mediaItems = new ArrayList <>();
43
116
117
+ if (parentId .equals (MY_MEDIA_ROOT_ID )) {
118
+ mediaItems .add (
119
+ createRootMediaItem (MY_MEDIA_BOOKMARKS_ID ,
120
+ playerService .getResources ().getString (R .string .tab_bookmarks )));
121
+ mediaItems .add (
122
+ createRootMediaItem (MY_MEDIA_HISTORY_ID ,
123
+ playerService .getResources ().getString (R .string .action_history )));
124
+ } else if (parentId .startsWith (MY_MEDIA_BOOKMARKS_ID )) {
125
+ populateBookmarks (mediaItems );
126
+ } else if (parentId .startsWith (MY_MEDIA_BOOKMARKS_PREFIX )) {
127
+ populatePlaylist (extractPlaylistId (parentId ), mediaItems );
128
+ }
44
129
result .sendResult (mediaItems );
45
130
}
131
+
132
+ private Long extractPlaylistId (final String mediaId ) {
133
+ return Long .valueOf (mediaId .substring (MY_MEDIA_BOOKMARKS_PREFIX .length ()));
134
+ }
135
+
136
+ private LocalPlaylistManager getPlaylistManager () {
137
+ if (database == null ) {
138
+ database = NewPipeDatabase .getInstance (playerService );
139
+ }
140
+ if (localPlaylistManager == null ) {
141
+ localPlaylistManager = new LocalPlaylistManager (database );
142
+ }
143
+ return localPlaylistManager ;
144
+ }
145
+
146
+ private void populateBookmarks (final List <MediaItem > mediaItems ) {
147
+ // TODO async
148
+ final var playlists = getPlaylistManager ().getPlaylists ().blockingFirst ();
149
+ mediaItems .addAll (playlists .stream ().map (it -> createPlaylistMediaItem (it ))
150
+ .collect (Collectors .toList ()));
151
+ }
152
+
153
+ private void populatePlaylist (final Long playlistId , final List <MediaItem > mediaItems ) {
154
+ // TODO async
155
+ getPlaylistManager ().getPlaylists ().blockingFirst ()
156
+ .stream ().filter (it -> it .uid == playlistId ).findFirst ()
157
+ .ifPresent (playlist -> {
158
+ final var items = getPlaylistManager ().getPlaylistStreams (playlist .uid )
159
+ .blockingFirst ();
160
+ int index = 0 ;
161
+ for (final var item : items ) {
162
+ mediaItems .add (createPlaylistStreamMediaItem (playlist , item , index ));
163
+ ++index ;
164
+ }
165
+ });
166
+ }
167
+
168
+ @ Override
169
+ public void onPlay () {
170
+ super .onPlay ();
171
+ NavigationHelper .playOnBackgroundPlayer (playerService , null , true );
172
+ }
173
+
174
+ @ Override
175
+ public void onPlayFromMediaId (final String mediaId , final Bundle extras ) {
176
+ super .onPlayFromMediaId (mediaId , extras );
177
+ final var playQueue = extractPlayQueueFromMediaId (mediaId );
178
+ NavigationHelper .playOnBackgroundPlayer (playerService , playQueue , true );
179
+ }
180
+
181
+ Pattern playlistMediaIdRe = Pattern .compile (MY_MEDIA_ITEM_PREFIX + "(\\ d+)_(\\ d+)" );
182
+ private PlayQueue extractPlayQueueFromMediaId (final String mediaId ) {
183
+ final Matcher m = playlistMediaIdRe .matcher (mediaId );
184
+ if (!m .matches ()) {
185
+ return null ;
186
+ }
187
+ final Long playlistId = Long .valueOf (m .group (1 ));
188
+ final int index = Integer .valueOf (m .group (2 ));
189
+
190
+ final var items = getPlaylistManager ().getPlaylists ().blockingFirst ()
191
+ .stream ().filter (it -> it .uid == playlistId ).findFirst ()
192
+ .map (playlist -> {
193
+ return getPlaylistManager ().getPlaylistStreams (playlist .uid )
194
+ .blockingFirst ().stream ()
195
+ .map (it -> it .toStreamInfoItem ())
196
+ .collect (Collectors .toList ());
197
+ }).orElse (new ArrayList <>());
198
+
199
+ return new SinglePlayQueue (items , index );
200
+ }
46
201
}
0 commit comments