1
0
mirror of https://github.com/TeamNewPipe/NewPipe synced 2025-04-07 19:26:44 +00:00

[] Share as YouTube temporary playlist

Initial commit.
This commit is contained in:
Thiago F. G. Albuquerque 2025-02-14 21:14:42 -03:00
parent c6e1721884
commit 2339f51ad4
3 changed files with 138 additions and 25 deletions
app/src
main/java/org/schabi/newpipe/local/playlist
test/java/org/schabi/newpipe/local/playlist

@ -2,6 +2,9 @@ package org.schabi.newpipe.local.playlist;
import static org.schabi.newpipe.error.ErrorUtil.showUiErrorSnackbar;
import static org.schabi.newpipe.ktx.ViewUtils.animate;
import static org.schabi.newpipe.local.playlist.PlayListShareMode.JUST_URLS;
import static org.schabi.newpipe.local.playlist.PlayListShareMode.WITH_TITLES;
import static org.schabi.newpipe.local.playlist.PlayListShareMode.YOUTUBE_TEMP_PLAYLIST;
import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout;
import android.content.Context;
@ -64,12 +67,14 @@ import java.util.Collections;
import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.disposables.CompositeDisposable;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.schedulers.Schedulers;
import okhttp3.HttpUrl;
public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void>
implements PlaylistControlViewHolder, DebounceSavable {
@ -385,34 +390,76 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
}
/**
* Shares the playlist as a list of stream URLs if {@code shouldSharePlaylistDetails} is
* set to {@code false}. Shares the playlist name along with a list of video titles and URLs
* if {@code shouldSharePlaylistDetails} is set to {@code true}.
* FIXME update this
*
* @param shouldSharePlaylistDetails Whether the playlist details should be included in the
* shared content.
* Shares the playlist as a list of stream URLs if {@code shareMode} is
* set to {@code false}. Shares the playlist name along with a list of video titles and URLs
* if {@code shareMode} is set to {@code true}.
*
* @param shareMode Whether the playlist details should be included in the
* shared content.
*/
private void sharePlaylist(final boolean shouldSharePlaylistDetails) {
private void sharePlaylist(PlayListShareMode shareMode) {
final Context context = requireContext();
disposables.add(playlistManager.getPlaylistStreams(playlistId)
.flatMapSingle(playlist -> Single.just(playlist.stream()
.map(PlaylistStreamEntry::getStreamEntity)
.map(streamEntity -> {
if (shouldSharePlaylistDetails) {
return context.getString(R.string.video_details_list_item,
streamEntity.getTitle(), streamEntity.getUrl());
} else {
return streamEntity.getUrl();
}
})
.collect(Collectors.joining("\n"))))
.observeOn(AndroidSchedulers.mainThread())
.subscribe(urlsText -> ShareUtils.shareText(
context, name, shouldSharePlaylistDetails
? context.getString(R.string.share_playlist_content_details,
name, urlsText) : urlsText),
throwable -> showUiErrorSnackbar(this, "Sharing playlist", throwable)));
.flatMapSingle(playlist -> Single.just(export( shareMode
, playlist.stream().map(PlaylistStreamEntry::getStreamEntity)
, context
)
))
.observeOn(AndroidSchedulers.mainThread())
.subscribe( urlsText -> ShareUtils.shareText( context
, name
, shareMode == JUST_URLS ? urlsText
: context.getString(R.string.share_playlist_content_details, name, urlsText))
, throwable -> showUiErrorSnackbar(this, "Sharing playlist", throwable))
);
}
static String export(PlayListShareMode shareMode, Stream<StreamEntity> entityStream, Context context) {
return switch(shareMode) {
case WITH_TITLES -> exportWithTitles(entityStream, context);
case JUST_URLS -> exportJustUrls(entityStream);
case YOUTUBE_TEMP_PLAYLIST -> exportAsYoutubeTempPlaylist(entityStream);
};
}
static String exportWithTitles(Stream<StreamEntity> entityStream, Context context) {
return entityStream
.map(entity -> context.getString(R.string.video_details_list_item, entity.getTitle(), entity.getUrl()))
.collect(Collectors.joining("\n"));
}
static String exportJustUrls(Stream<StreamEntity> entityStream) {
return entityStream
.map(StreamEntity::getUrl)
.collect(Collectors.joining("\n"));
}
static String exportAsYoutubeTempPlaylist(Stream<StreamEntity> entityStream) {
String videoIDs = entityStream
.map(entity -> getYouTubeId(entity.getUrl()))
.collect(Collectors.joining(","));
return "http://www.youtube.com/watch_videos?video_ids=" + videoIDs;
}
/**
* Gets the video id from a YouTube URL
*/
static String getYouTubeId(String url) {
HttpUrl httpUrl = HttpUrl.parse(url);
return httpUrl == null ? null
: httpUrl.queryParameter("v")
;
}
public void removeWatchedStreams(final boolean removePartiallyWatched) {
@ -875,10 +922,13 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
.setMessage(R.string.share_playlist_with_titles_message)
.setCancelable(true)
.setPositiveButton(R.string.share_playlist_with_titles, (dialog, which) ->
sharePlaylist(/* shouldSharePlaylistDetails= */ true)
sharePlaylist(WITH_TITLES)
)
.setNeutralButton("Share as YouTube temporary playlist", (dialog, which) -> // TODO R.string.share_playlist_as_YouTube_temporary_playlist
sharePlaylist(YOUTUBE_TEMP_PLAYLIST)
)
.setNegativeButton(R.string.share_playlist_with_list, (dialog, which) ->
sharePlaylist(/* shouldSharePlaylistDetails= */ false)
sharePlaylist(JUST_URLS)
)
.show();
}

@ -0,0 +1,8 @@
package org.schabi.newpipe.local.playlist;
public enum PlayListShareMode {
JUST_URLS
,WITH_TITLES
,YOUTUBE_TEMP_PLAYLIST
}

@ -0,0 +1,55 @@
package org.schabi.newpipe.local.playlist;
import static org.schabi.newpipe.local.playlist.PlayListShareMode.YOUTUBE_TEMP_PLAYLIST;
import androidx.annotation.NonNull;
import org.junit.Assert;
import org.junit.Test;
import org.schabi.newpipe.database.stream.model.StreamEntity;
import org.schabi.newpipe.extractor.stream.StreamType;
import java.util.List;
import java.util.stream.Stream;
public class LocalPlaylistFragmentTest {
@Test
public void youTubeTempPlaylist() {
Stream<StreamEntity> entityStream = List.of(
"https://www.youtube.com/watch?v=1"
,"https://www.youtube.com/watch?v=2"
,"https://www.youtube.com/watch?v=3"
)
.stream()
.map(LocalPlaylistFragmentTest::newStreamEntity)
;
String url = LocalPlaylistFragment.export(YOUTUBE_TEMP_PLAYLIST, entityStream, null);
Assert.assertEquals("http://www.youtube.com/watch_videos?video_ids=1,2,3", url);
}
@NonNull
static StreamEntity newStreamEntity(String url) {
return new StreamEntity(
0
, 1
, url
, "Title"
, StreamType.VIDEO_STREAM
, 100
, "Uploader"
, null
, null
, null
, null
, null
, null
);
}
}