|
2 | 2 |
|
3 | 3 | import static org.schabi.newpipe.error.ErrorUtil.showUiErrorSnackbar; |
4 | 4 | import static org.schabi.newpipe.ktx.ViewUtils.animate; |
| 5 | +import static org.schabi.newpipe.local.playlist.PlayListShareMode.JUST_URLS; |
| 6 | +import static org.schabi.newpipe.local.playlist.PlayListShareMode.WITH_TITLES; |
| 7 | +import static org.schabi.newpipe.local.playlist.PlayListShareMode.YOUTUBE_TEMP_PLAYLIST; |
5 | 8 | import static org.schabi.newpipe.util.ThemeHelper.shouldUseGridLayout; |
6 | 9 |
|
7 | 10 | import android.content.Context; |
|
64 | 67 | import java.util.List; |
65 | 68 | import java.util.concurrent.atomic.AtomicBoolean; |
66 | 69 | import java.util.stream.Collectors; |
| 70 | +import java.util.stream.Stream; |
67 | 71 |
|
68 | 72 | import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; |
69 | 73 | import io.reactivex.rxjava3.core.Single; |
70 | 74 | import io.reactivex.rxjava3.disposables.CompositeDisposable; |
71 | 75 | import io.reactivex.rxjava3.disposables.Disposable; |
72 | 76 | import io.reactivex.rxjava3.schedulers.Schedulers; |
| 77 | +import okhttp3.HttpUrl; |
73 | 78 |
|
74 | 79 | public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistStreamEntry>, Void> |
75 | 80 | implements PlaylistControlViewHolder, DebounceSavable { |
@@ -385,34 +390,76 @@ public boolean onOptionsItemSelected(final MenuItem item) { |
385 | 390 | } |
386 | 391 |
|
387 | 392 | /** |
388 | | - * Shares the playlist as a list of stream URLs if {@code shouldSharePlaylistDetails} is |
| 393 | + * FIXME update this |
| 394 | + * |
| 395 | + * Shares the playlist as a list of stream URLs if {@code shareMode} is |
389 | 396 | * set to {@code false}. Shares the playlist name along with a list of video titles and URLs |
390 | | - * if {@code shouldSharePlaylistDetails} is set to {@code true}. |
| 397 | + * if {@code shareMode} is set to {@code true}. |
391 | 398 | * |
392 | | - * @param shouldSharePlaylistDetails Whether the playlist details should be included in the |
393 | | - * shared content. |
| 399 | + * @param shareMode Whether the playlist details should be included in the |
| 400 | + * shared content. |
394 | 401 | */ |
395 | | - private void sharePlaylist(final boolean shouldSharePlaylistDetails) { |
| 402 | + private void sharePlaylist(PlayListShareMode shareMode) { |
396 | 403 | final Context context = requireContext(); |
397 | 404 |
|
398 | 405 | disposables.add(playlistManager.getPlaylistStreams(playlistId) |
399 | | - .flatMapSingle(playlist -> Single.just(playlist.stream() |
400 | | - .map(PlaylistStreamEntry::getStreamEntity) |
401 | | - .map(streamEntity -> { |
402 | | - if (shouldSharePlaylistDetails) { |
403 | | - return context.getString(R.string.video_details_list_item, |
404 | | - streamEntity.getTitle(), streamEntity.getUrl()); |
405 | | - } else { |
406 | | - return streamEntity.getUrl(); |
407 | | - } |
408 | | - }) |
409 | | - .collect(Collectors.joining("\n")))) |
410 | | - .observeOn(AndroidSchedulers.mainThread()) |
411 | | - .subscribe(urlsText -> ShareUtils.shareText( |
412 | | - context, name, shouldSharePlaylistDetails |
413 | | - ? context.getString(R.string.share_playlist_content_details, |
414 | | - name, urlsText) : urlsText), |
415 | | - throwable -> showUiErrorSnackbar(this, "Sharing playlist", throwable))); |
| 406 | + .flatMapSingle(playlist -> Single.just(export( shareMode |
| 407 | + , playlist.stream().map(PlaylistStreamEntry::getStreamEntity) |
| 408 | + , context |
| 409 | + ) |
| 410 | + )) |
| 411 | + .observeOn(AndroidSchedulers.mainThread()) |
| 412 | + .subscribe( urlsText -> ShareUtils.shareText( context |
| 413 | + , name |
| 414 | + , shareMode == JUST_URLS ? urlsText |
| 415 | + : context.getString(R.string.share_playlist_content_details, name, urlsText)) |
| 416 | + , throwable -> showUiErrorSnackbar(this, "Sharing playlist", throwable)) |
| 417 | + ); |
| 418 | + } |
| 419 | + |
| 420 | + static String export(PlayListShareMode shareMode, Stream<StreamEntity> entityStream, Context context) { |
| 421 | + |
| 422 | + return switch(shareMode) { |
| 423 | + |
| 424 | + case WITH_TITLES -> exportWithTitles(entityStream, context); |
| 425 | + case JUST_URLS -> exportJustUrls(entityStream); |
| 426 | + case YOUTUBE_TEMP_PLAYLIST -> exportAsYoutubeTempPlaylist(entityStream); |
| 427 | + }; |
| 428 | + } |
| 429 | + |
| 430 | + static String exportWithTitles(Stream<StreamEntity> entityStream, Context context) { |
| 431 | + |
| 432 | + return entityStream |
| 433 | + .map(entity -> context.getString(R.string.video_details_list_item, entity.getTitle(), entity.getUrl())) |
| 434 | + .collect(Collectors.joining("\n")); |
| 435 | + } |
| 436 | + |
| 437 | + static String exportJustUrls(Stream<StreamEntity> entityStream) { |
| 438 | + |
| 439 | + return entityStream |
| 440 | + .map(StreamEntity::getUrl) |
| 441 | + .collect(Collectors.joining("\n")); |
| 442 | + } |
| 443 | + |
| 444 | + static String exportAsYoutubeTempPlaylist(Stream<StreamEntity> entityStream) { |
| 445 | + |
| 446 | + String videoIDs = entityStream |
| 447 | + .map(entity -> getYouTubeId(entity.getUrl())) |
| 448 | + .collect(Collectors.joining(",")); |
| 449 | + |
| 450 | + return "http://www.youtube.com/watch_videos?video_ids=" + videoIDs; |
| 451 | + } |
| 452 | + |
| 453 | + /** |
| 454 | + * Gets the video id from a YouTube URL |
| 455 | + */ |
| 456 | + static String getYouTubeId(String url) { |
| 457 | + |
| 458 | + HttpUrl httpUrl = HttpUrl.parse(url); |
| 459 | + |
| 460 | + return httpUrl == null ? null |
| 461 | + : httpUrl.queryParameter("v") |
| 462 | + ; |
416 | 463 | } |
417 | 464 |
|
418 | 465 | public void removeWatchedStreams(final boolean removePartiallyWatched) { |
@@ -875,10 +922,13 @@ private void createShareConfirmationDialog() { |
875 | 922 | .setMessage(R.string.share_playlist_with_titles_message) |
876 | 923 | .setCancelable(true) |
877 | 924 | .setPositiveButton(R.string.share_playlist_with_titles, (dialog, which) -> |
878 | | - sharePlaylist(/* shouldSharePlaylistDetails= */ true) |
| 925 | + sharePlaylist(WITH_TITLES) |
| 926 | + ) |
| 927 | + .setNeutralButton("Share as YouTube temporary playlist", (dialog, which) -> // TODO R.string.share_playlist_as_YouTube_temporary_playlist |
| 928 | + sharePlaylist(YOUTUBE_TEMP_PLAYLIST) |
879 | 929 | ) |
880 | 930 | .setNegativeButton(R.string.share_playlist_with_list, (dialog, which) -> |
881 | | - sharePlaylist(/* shouldSharePlaylistDetails= */ false) |
| 931 | + sharePlaylist(JUST_URLS) |
882 | 932 | ) |
883 | 933 | .show(); |
884 | 934 | } |
|
0 commit comments