diff --git a/app/src/main/java/org/schabi/newpipe/RouterActivity.java b/app/src/main/java/org/schabi/newpipe/RouterActivity.java index 1be6e096a22..e355348ed65 100644 --- a/app/src/main/java/org/schabi/newpipe/RouterActivity.java +++ b/app/src/main/java/org/schabi/newpipe/RouterActivity.java @@ -436,7 +436,7 @@ private void openDownloadDialog() { sortedVideoStreams); FragmentManager fm = getSupportFragmentManager(); - DownloadDialog downloadDialog = DownloadDialog.newInstance(result); + DownloadDialog downloadDialog = DownloadDialog.newInstance(result, null); downloadDialog.setVideoStreams(sortedVideoStreams); downloadDialog.setAudioStreams(result.getAudioStreams()); downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex); diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java index 1d536ea1a73..d2033c50651 100644 --- a/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java @@ -23,9 +23,11 @@ import android.util.Log; import android.util.SparseArray; import android.view.LayoutInflater; +import android.view.MenuItem; import android.view.View; import android.view.ViewGroup; import android.widget.AdapterView; +import android.widget.CheckBox; import android.widget.EditText; import android.widget.RadioButton; import android.widget.RadioGroup; @@ -46,6 +48,7 @@ import org.schabi.newpipe.extractor.stream.SubtitlesStream; import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.extractor.utils.Localization; +import org.schabi.newpipe.fragments.list.playlist.PlaylistFragment; import org.schabi.newpipe.report.ErrorActivity; import org.schabi.newpipe.report.UserAction; import org.schabi.newpipe.settings.NewPipeSettings; @@ -76,7 +79,8 @@ import us.shandian.giga.service.DownloadManagerService.DownloadManagerBinder; import us.shandian.giga.service.MissionState; -public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener { +public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheckedChangeListener, + AdapterView.OnItemSelectedListener { private static final String TAG = "DialogFragment"; private static final boolean DEBUG = MainActivity.DEBUG; private static final int REQUEST_DOWNLOAD_SAVE_AS = 0x1230; @@ -107,21 +111,27 @@ public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheck private RadioGroup radioStreamsGroup; private TextView threadsCountTextView; private SeekBar threadsSeekBar; + private CheckBox smartDownloadCheckbox; + private DownloadSetting downloadSetting; + + @Nullable + private PlaylistFragment.PlaylistDownloadCallback playlistDownloadCallback; private SharedPreferences prefs; - public static DownloadDialog newInstance(StreamInfo info) { + public static DownloadDialog newInstance(StreamInfo info, @Nullable PlaylistFragment.PlaylistDownloadCallback callback) { DownloadDialog dialog = new DownloadDialog(); dialog.setInfo(info); + dialog.setPlaylistCallback(callback); return dialog; } - public static DownloadDialog newInstance(Context context, StreamInfo info) { + public static DownloadDialog newInstance(Context context, StreamInfo info, @Nullable PlaylistFragment.PlaylistDownloadCallback callback) { final ArrayList streamsList = new ArrayList<>(ListHelper.getSortedStreamVideosList(context, info.getVideoStreams(), info.getVideoOnlyStreams(), false)); final int selectedStreamIndex = ListHelper.getDefaultResolutionIndex(context, streamsList); - final DownloadDialog instance = newInstance(info); + final DownloadDialog instance = newInstance(info, callback); instance.setVideoStreams(streamsList); instance.setSelectedVideoStream(selectedStreamIndex); instance.setAudioStreams(info.getAudioStreams()); @@ -162,6 +172,10 @@ public void setSelectedVideoStream(int selectedVideoIndex) { this.selectedVideoIndex = selectedVideoIndex; } + public void setPlaylistCallback(PlaylistFragment.PlaylistDownloadCallback callback) { + this.playlistDownloadCallback = callback; + } + public void setSelectedAudioStream(int selectedAudioIndex) { this.selectedAudioIndex = selectedAudioIndex; } @@ -258,6 +272,10 @@ public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceStat radioStreamsGroup = view.findViewById(R.id.video_audio_group); radioStreamsGroup.setOnCheckedChangeListener(this); + smartDownloadCheckbox = view.findViewById(R.id.dialog_download_checkbox_intelligent); + if (playlistDownloadCallback != null) + smartDownloadCheckbox.setVisibility(View.VISIBLE); + initToolbar(view.findViewById(R.id.toolbar)); setupDownloadOptions(); @@ -364,12 +382,29 @@ private void initToolbar(Toolbar toolbar) { okButton = toolbar.findViewById(R.id.okay); okButton.setEnabled(false);// disable until the download service connection is done + if (playlistDownloadCallback != null) { + toolbar.setTitle(getResources().getString(R.string.download) + " (" + + getResources().getString(R.string.playlist) + ")"); + MenuItem menuItem = toolbar.getMenu().findItem(R.id.skip); + menuItem.setVisible(true); + } else { + toolbar.setTitle(R.string.download_dialog_title); + } + toolbar.setOnMenuItemClickListener(item -> { + if (item.getItemId() == R.id.okay) { prepareSelectedDownload(); - return true; + + } else if (item.getItemId() == R.id.skip) { + if (playlistDownloadCallback != null) { + + playlistDownloadCallback.accept(null); + } } - return false; + + getDialog().dismiss(); + return true; }); } @@ -780,12 +815,17 @@ private void continueSelectedDownload(@NonNull StoredFileHelper storage) { String[] psArgs = null; String secondaryStreamUrl = null; long nearLength = 0; + String videoResolution = null; + int audioBitrate = -1; + Locale subtitleLocale = null; // more download logic: select muxer, subtitle converter, etc. switch (radioStreamsGroup.getCheckedRadioButtonId()) { case R.id.audio_button: kind = 'a'; - selectedStream = audioStreamsAdapter.getItem(selectedAudioIndex); + AudioStream audioStream = audioStreamsAdapter.getItem(selectedAudioIndex); + audioBitrate = audioStream.getAverageBitrate(); + selectedStream = audioStream; if (selectedStream.getFormat() == MediaFormat.M4A) { psName = Postprocessing.ALGORITHM_M4A_NO_DASH; @@ -793,7 +833,9 @@ private void continueSelectedDownload(@NonNull StoredFileHelper storage) { break; case R.id.video_button: kind = 'v'; - selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex); + VideoStream videoStream = videoStreamsAdapter.getItem(selectedVideoIndex); + videoResolution = videoStream.getResolution(); + selectedStream = videoStream; SecondaryStreamHelper secondaryStream = videoStreamsAdapter .getAllSecondary() @@ -820,7 +862,9 @@ private void continueSelectedDownload(@NonNull StoredFileHelper storage) { case R.id.subtitle_button: threads = 1;// use unique thread for subtitles due small file size kind = 's'; - selectedStream = subtitleStreamsAdapter.getItem(selectedSubtitleIndex); + SubtitlesStream subtitlesStream = subtitleStreamsAdapter.getItem(selectedSubtitleIndex); + subtitleLocale = subtitlesStream.getLocale(); + selectedStream = subtitlesStream; if (selectedStream.getFormat() == MediaFormat.TTML) { psName = Postprocessing.ALGORITHM_TTML_CONVERTER; @@ -840,8 +884,17 @@ private void continueSelectedDownload(@NonNull StoredFileHelper storage) { } else { urls = new String[]{selectedStream.getUrl(), secondaryStreamUrl}; } + this.downloadSetting = new DownloadSetting(storage, threads, urls, currentInfo.getUrl(), kind, psName, psArgs, + nearLength, videoResolution, audioBitrate, subtitleLocale); + DownloadManagerService.startMission(context, downloadSetting); - DownloadManagerService.startMission(context, urls, storage, kind, threads, currentInfo.getUrl(), psName, psArgs, nearLength); + if (playlistDownloadCallback != null) { + if (smartDownloadCheckbox.isChecked() && downloadSetting != null) { + playlistDownloadCallback.accept(downloadSetting); + } else { + playlistDownloadCallback.accept(null); + } + } dismiss(); } diff --git a/app/src/main/java/org/schabi/newpipe/download/DownloadSetting.java b/app/src/main/java/org/schabi/newpipe/download/DownloadSetting.java new file mode 100644 index 00000000000..26ff1b32829 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/download/DownloadSetting.java @@ -0,0 +1,80 @@ +package org.schabi.newpipe.download; + +import java.util.Locale; + +import us.shandian.giga.io.StoredFileHelper; + +public class DownloadSetting { + + private StoredFileHelper storedFileHelper; + private int threadCount; + private String[] urls; + private char kind; + private String psName; + private String[] psArgs; + private Long nearLength; + private String source; + private String videoResolution; + private int audioBitRate; + private Locale subtitleLocale; + + public DownloadSetting(StoredFileHelper storedFileHelper, int threadCount, String[] urls, + String source, char kind, String psName, String[] psArgs, Long nearLength, + String videoResolution, int audioBitRate, Locale subtitleLocale) { + this.storedFileHelper = storedFileHelper; + this.threadCount = threadCount; + this.urls = urls; + this.kind = kind; + this.psName = psName; + this.psArgs = psArgs; + this.nearLength = nearLength; + this.source = source; + this.videoResolution = videoResolution; + this.audioBitRate = audioBitRate; + this.subtitleLocale = subtitleLocale; + } + + public StoredFileHelper getStoredFileHelper() { + return storedFileHelper; + } + + public int getThreadCount() { + return threadCount; + } + + public String[] getUrls() { + return urls; + } + + public char getKind() { + return this.kind; + } + + public String getPsName() { + return this.psName; + } + + public String[] getPsArgs() { + return this.psArgs; + } + + public Long getNearLength() { + return this.nearLength; + } + + public String getSource() { + return this.source; + } + + public String getVideoResolution() { + return this.videoResolution; + } + + public int getAudioBitRate() { + return this.audioBitRate; + } + + public Locale getSubtitleLocale() { + return this.subtitleLocale; + } +} diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java index 37d8851ea42..4245d21b2d0 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/VideoDetailFragment.java @@ -1168,7 +1168,7 @@ public void handleResult(@NonNull StreamInfo info) { public void openDownloadDialog() { try { - DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo); + DownloadDialog downloadDialog = DownloadDialog.newInstance(currentInfo, null); downloadDialog.setVideoStreams(sortedVideoStreams); downloadDialog.setAudioStreams(currentInfo.getAudioStreams()); downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex); diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java index 32b83bb2252..371e82a8d9f 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/playlist/PlaylistFragment.java @@ -3,9 +3,6 @@ import android.app.Activity; import android.content.Context; import android.os.Bundle; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.appcompat.app.AppCompatActivity; import android.text.TextUtils; import android.util.Log; import android.view.LayoutInflater; @@ -17,11 +14,16 @@ import android.widget.ImageView; import android.widget.TextView; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.appcompat.app.AppCompatActivity; + import org.reactivestreams.Subscriber; import org.reactivestreams.Subscription; import org.schabi.newpipe.NewPipeDatabase; import org.schabi.newpipe.R; import org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity; +import org.schabi.newpipe.download.DownloadSetting; import org.schabi.newpipe.extractor.InfoItem; import org.schabi.newpipe.extractor.ListExtractor; import org.schabi.newpipe.extractor.NewPipe; @@ -39,6 +41,7 @@ import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.ImageDisplayConstants; import org.schabi.newpipe.util.NavigationHelper; +import org.schabi.newpipe.util.PermissionHelper; import org.schabi.newpipe.util.ShareUtils; import org.schabi.newpipe.util.StreamDialogEntry; import org.schabi.newpipe.util.ThemeHelper; @@ -79,6 +82,7 @@ public class PlaylistFragment extends BaseListInfoFragment { private View headerPlayAllButton; private View headerPopupButton; private View headerBackgroundButton; + private View headerDownloadAllButton; private MenuItem playlistBookmarkButton; @@ -123,7 +127,7 @@ protected View getListHeader() { headerPlayAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_all_button); headerPopupButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_popup_button); headerBackgroundButton = headerRootLayout.findViewById(R.id.playlist_ctrl_play_bg_button); - + headerDownloadAllButton = headerRootLayout.findViewById(R.id.playlist_ctrl_download_all_button); return headerRootLayout; } @@ -304,6 +308,12 @@ public void handleResult(@NonNull final PlaylistInfo result) { return true; }); + headerDownloadAllButton.setOnClickListener(view -> { + if (PermissionHelper.checkStoragePermissions(activity, PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE)) { + NavigationHelper.downloadPlaylist(this, getPlayQueue()); + } + }); + headerBackgroundButton.setOnLongClickListener(view -> { NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true); return true; @@ -316,8 +326,8 @@ private PlayQueue getPlayQueue() { private PlayQueue getPlayQueue(final int index) { final List infoItems = new ArrayList<>(); - for(InfoItem i : infoListAdapter.getItemsList()) { - if(i instanceof StreamInfoItem) { + for (InfoItem i : infoListAdapter.getItemsList()) { + if (i instanceof StreamInfoItem) { infoItems.add((StreamInfoItem) i); } } @@ -330,6 +340,16 @@ private PlayQueue getPlayQueue(final int index) { ); } + public interface PlaylistDownloadCallback { + /** + * Callback for next item in playlist queue to invoke download dialog for next item + * + * @param downloadSetting if smart download checkbox was checked, in which case, + * we should skip presenting the dialog for each video + */ + void accept(DownloadSetting downloadSetting); + } + @Override public void handleNextItems(ListExtractor.InfoItemsPage result) { super.handleNextItems(result); @@ -345,7 +365,7 @@ public void handleNextItems(ListExtractor.InfoItemsPage result) { //////////////////////////////////////////////////////////////////////////*/ @Override - protected boolean onError(Throwable exception) { + public boolean onError(Throwable exception) { if (super.onError(exception)) return true; int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error; diff --git a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java index e2b03c8e830..b7802a2afd1 100644 --- a/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/NavigationHelper.java @@ -15,6 +15,7 @@ import androidx.fragment.app.FragmentTransaction; import androidx.appcompat.app.AlertDialog; import android.util.Log; +import android.util.SparseArray; import android.widget.Toast; import com.nostra13.universalimageloader.core.ImageLoader; @@ -24,12 +25,16 @@ import org.schabi.newpipe.RouterActivity; import org.schabi.newpipe.about.AboutActivity; import org.schabi.newpipe.download.DownloadActivity; +import org.schabi.newpipe.download.DownloadDialog; +import org.schabi.newpipe.download.DownloadSetting; +import org.schabi.newpipe.extractor.MediaFormat; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.StreamingService; import org.schabi.newpipe.extractor.exceptions.ExtractionException; import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.Stream; import org.schabi.newpipe.extractor.stream.StreamInfo; +import org.schabi.newpipe.extractor.stream.SubtitlesStream; import org.schabi.newpipe.extractor.stream.VideoStream; import org.schabi.newpipe.fragments.MainFragment; import org.schabi.newpipe.fragments.detail.VideoDetailFragment; @@ -52,9 +57,21 @@ import org.schabi.newpipe.player.PopupVideoPlayerActivity; import org.schabi.newpipe.player.VideoPlayer; import org.schabi.newpipe.player.playqueue.PlayQueue; +import org.schabi.newpipe.player.playqueue.PlayQueueItem; import org.schabi.newpipe.settings.SettingsActivity; +import org.schabi.newpipe.util.StreamItemAdapter.StreamSizeWrapper; +import java.io.IOException; import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import io.reactivex.Completable; +import io.reactivex.functions.Predicate; +import us.shandian.giga.io.StoredDirectoryHelper; +import us.shandian.giga.io.StoredFileHelper; +import us.shandian.giga.postprocessing.Postprocessing; +import us.shandian.giga.service.DownloadManagerService; @SuppressWarnings({"unused", "WeakerAccess"}) public class NavigationHelper { @@ -138,6 +155,231 @@ public static void playOnBackgroundPlayer(final Context context, final PlayQueue startService(context, getPlayerIntent(context, BackgroundPlayer.class, queue, resumePlayback)); } + public static void downloadPlaylist(final PlaylistFragment context, final PlayQueue queue) { + List events = queue.getStreams(); + Iterator eventsIterator = events.listIterator(); + if (eventsIterator.hasNext()) { + startDownloadPlaylist(context, eventsIterator, null); + } + } + + private static void startDownloadPlaylist(final PlaylistFragment activity, + final Iterator itemIterator, + DownloadSetting downloadSetting) { + if (downloadSetting != null) { + Completable.create(emitter -> { + while (itemIterator.hasNext()) { + PlayQueueItem queueItem = itemIterator.next(); + queueItem.getStream().filter(streamInfo -> + streamInfo != null).subscribe(streamInfo -> startDownloadFromDownloadSetting(activity, + downloadSetting, streamInfo), activity::onError); + } + emitter.onComplete(); + }).subscribe(); + } else { + try { + if (itemIterator.hasNext()) { + PlayQueueItem item = itemIterator.next(); + item.getStream().subscribe(streamInfo -> startDownloadFromStreamInfo(activity, streamInfo, itemIterator), + activity::onError); + } + } catch (Exception e) { + Toast.makeText(activity.getActivity(), + R.string.could_not_setup_download_menu, + Toast.LENGTH_LONG).show(); + e.printStackTrace(); + } + } + } + + /** + * Starts downloading video without invoking the {@link DownloadDialog} + * + * @param activity + * @param downloadSetting + * @param streamInfo + */ + private static void startDownloadFromDownloadSetting(PlaylistFragment activity, DownloadSetting downloadSetting, StreamInfo streamInfo) { + + DownloadSetting downloadSettingNew = refactorDownloadSetting(activity, downloadSetting, streamInfo); + + if (downloadSettingNew == null) return; + + DownloadManagerService.startMission(activity.getContext(), downloadSettingNew); + } + + /** + * Refactors the download setting for the new stream info + * + * @param activity + * @param downloadSetting + * @param streamInfo + * @return + */ + private static DownloadSetting refactorDownloadSetting(PlaylistFragment activity, DownloadSetting downloadSetting, + StreamInfo streamInfo) { + Stream selectedStream; + String[] urls; + String psName = null; + String[] psArgs = null; + String secondaryStreamUrl = null; + long nearLength = 0; + String fileName = streamInfo.getName().concat("."); + String mime; + + + List sortedVideoStream = ListHelper.getSortedStreamVideosList(activity.getActivity(), + streamInfo.getVideoStreams(), streamInfo.getVideoOnlyStreams(), false); + + StreamItemAdapter.StreamSizeWrapper wrappedVideoStreams = new StreamSizeWrapper<>(sortedVideoStream, activity.getContext()); + StreamItemAdapter.StreamSizeWrapper wrappedAudioStreams = new StreamSizeWrapper<>(streamInfo.getAudioStreams(), activity.getContext()); + StreamItemAdapter.StreamSizeWrapper wrappedSubtitleStreams = new StreamSizeWrapper<>(streamInfo.getSubtitles(), activity.getContext()); + + SparseArray> secondaryAudioStreams = new SparseArray<>(4); + for (int i = 0; i < sortedVideoStream.size(); i++) { + if (!sortedVideoStream.get(i).isVideoOnly()) continue; + AudioStream audioStream = SecondaryStreamHelper.getAudioStreamFor(wrappedAudioStreams.getStreamsList(), sortedVideoStream.get(i)); + + if (audioStream != null) { + secondaryAudioStreams.append(i, new SecondaryStreamHelper<>(wrappedAudioStreams, audioStream)); + } + } + + StreamItemAdapter audioStreamsAdapter = new StreamItemAdapter<>(activity.getActivity(), + wrappedAudioStreams); + StreamItemAdapter videoStreamsAdapter = new StreamItemAdapter<>(activity.getActivity(), + wrappedVideoStreams, secondaryAudioStreams); + StreamItemAdapter subtitleStreamsAdapter = new StreamItemAdapter<>(activity.getActivity(), + wrappedSubtitleStreams); + + switch (downloadSetting.getKind()) { + case 'a': + AudioStream audioStream = null; + for (AudioStream currentStream : audioStreamsAdapter.getAll()) { + if (currentStream.getAverageBitrate() == downloadSetting.getAudioBitRate()) { + audioStream = currentStream; + break; + } + } + if (audioStream == null) { + audioStream = audioStreamsAdapter.getItem(0); + } + if (audioStream.getFormat() == MediaFormat.M4A) { + psName = Postprocessing.ALGORITHM_M4A_NO_DASH; + } + fileName += audioStream.getFormat().getSuffix(); + mime = audioStream.getFormat().getMimeType(); + selectedStream = audioStream; + break; + case 'v': + VideoStream videoStream = null; + for (VideoStream currentStream : sortedVideoStream) { + if (currentStream.getResolution().equals(downloadSetting.getVideoResolution())) { + videoStream = currentStream; + break; + } + } + if (videoStream == null) { + videoStream = sortedVideoStream.get(0); + } + SecondaryStreamHelper secondaryStream = videoStreamsAdapter + .getAllSecondary() + .get(wrappedVideoStreams.getStreamsList().indexOf(videoStream)); + if (secondaryStream != null) { + secondaryStreamUrl = secondaryStream.getStream().getUrl(); + + if (videoStream.getFormat() == MediaFormat.MPEG_4) + psName = Postprocessing.ALGORITHM_MP4_FROM_DASH_MUXER; + else + psName = Postprocessing.ALGORITHM_WEBM_MUXER; + + psArgs = null; + long videoSize = wrappedVideoStreams.getSizeInBytes(videoStream); + + // set nearLength, only, if both sizes are fetched or known. This probably + // does not work on slow networks but is later updated in the downloader + if (secondaryStream.getSizeInBytes() > 0 && videoSize > 0) { + nearLength = secondaryStream.getSizeInBytes() + videoSize; + } + } + fileName += videoStream.getFormat().getSuffix(); + mime = videoStream.getFormat().getMimeType(); + selectedStream = videoStream; + break; + case 's': + SubtitlesStream subtitlesStream = null; + for (SubtitlesStream currentStream : subtitleStreamsAdapter.getAll()) { + if (currentStream.getLocale().equals(downloadSetting.getSubtitleLocale())) { + subtitlesStream = currentStream; + break; + } + } + if (subtitlesStream == null) { + subtitlesStream = subtitleStreamsAdapter.getItem(0); + } + if (subtitlesStream.getFormat() == MediaFormat.TTML) { + psName = Postprocessing.ALGORITHM_TTML_CONVERTER; + psArgs = new String[]{ + subtitlesStream.getFormat().getSuffix(), + "false",// ignore empty frames + "false",// detect youtube duplicate lines + }; + } + fileName += subtitlesStream.getFormat() == MediaFormat.TTML ? MediaFormat.SRT.suffix : + subtitlesStream.getFormat().suffix; + mime = subtitlesStream.getFormat().getMimeType(); + selectedStream = subtitlesStream; + break; + default: + return null; + } + + if (secondaryStreamUrl == null) { + urls = new String[]{selectedStream.getUrl()}; + } else { + urls = new String[]{selectedStream.getUrl(), secondaryStreamUrl}; + } + StoredFileHelper storedFileHelper = downloadSetting.getStoredFileHelper(); + try { + StoredDirectoryHelper storedDirectoryHelper = new StoredDirectoryHelper(activity.getContext(), + storedFileHelper.getParentUri(), storedFileHelper.getTag()); + StoredFileHelper storedFileHelperNew = storedDirectoryHelper.createFile(fileName, mime); + if(storedFileHelperNew == null) { + return null; + } + DownloadSetting downloadSettingNew = new DownloadSetting(storedFileHelperNew, downloadSetting.getThreadCount(), + urls, streamInfo.getUrl(), downloadSetting.getKind(), psName, psArgs, + nearLength, downloadSetting.getVideoResolution(), downloadSetting.getAudioBitRate(), + downloadSetting.getSubtitleLocale()); + return downloadSettingNew; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + /** + * Invokes the {@link DownloadDialog} for each play queue item + * + * @param activity + * @param streamInfo + * @param itemIterator + */ + private static void startDownloadFromStreamInfo(PlaylistFragment activity, StreamInfo streamInfo, Iterator itemIterator) { + DownloadDialog downloadDialog = DownloadDialog.newInstance(streamInfo, smartDownload -> { + if (itemIterator.hasNext()) + startDownloadPlaylist(activity, itemIterator, smartDownload); + }); + List sortedVideoStream = ListHelper.getSortedStreamVideosList(activity.getActivity(), + streamInfo.getVideoStreams(), streamInfo.getVideoOnlyStreams(), false); + downloadDialog.setVideoStreams(sortedVideoStream); + downloadDialog.setAudioStreams(streamInfo.getAudioStreams()); + downloadDialog.setSelectedVideoStream(ListHelper.getDefaultResolutionIndex(activity.getActivity(), streamInfo.getVideoStreams())); + downloadDialog.setSubtitleStreams(streamInfo.getSubtitles()); + + downloadDialog.show(activity.getActivity().getSupportFragmentManager(), "downloadDialog"); + } + public static void enqueueOnPopupPlayer(final Context context, final PlayQueue queue, final boolean resumePlayback) { enqueueOnPopupPlayer(context, queue, false, resumePlayback); } @@ -499,7 +741,7 @@ public static Intent getIntentByLink(Context context, StreamingService service, case STREAM: rIntent.putExtra(VideoDetailFragment.AUTO_PLAY, PreferenceManager.getDefaultSharedPreferences(context) - .getBoolean(context.getString(R.string.autoplay_through_intent_key), false)); + .getBoolean(context.getString(R.string.autoplay_through_intent_key), false)); break; } @@ -532,6 +774,7 @@ private static void installApp(Context context, String packageName) { /** * Start an activity to install Kore + * * @param context the context */ public static void installKore(Context context) { @@ -540,13 +783,12 @@ public static void installKore(Context context) { /** * Start Kore app to show a video on Kodi - * * For a list of supported urls see the * - * Kore source code + * Kore source code * . * - * @param context the context to use + * @param context the context to use * @param videoURL the url to the video */ public static void playWithKore(Context context, Uri videoURL) { diff --git a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java index 461787b624b..42d0222ab74 100755 --- a/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java +++ b/app/src/main/java/us/shandian/giga/service/DownloadManagerService.java @@ -35,6 +35,7 @@ import org.schabi.newpipe.R; import org.schabi.newpipe.download.DownloadActivity; +import org.schabi.newpipe.download.DownloadSetting; import org.schabi.newpipe.player.helper.LockManager; import java.io.File; @@ -364,31 +365,23 @@ public void updateForegroundState(boolean state) { /** * Start a new download mission * - * @param context the activity context - * @param urls the list of urls to download - * @param storage where the file is saved - * @param kind type of file (a: audio v: video s: subtitle ?: file-extension defined) - * @param threads the number of threads maximal used to download chunks of the file. - * @param psName the name of the required post-processing algorithm, or {@code null} to ignore. - * @param source source url of the resource - * @param psArgs the arguments for the post-processing algorithm. - * @param nearLength the approximated final length of the file + * @param context the activity context + * @param downloadSetting downloadSetting */ - public static void startMission(Context context, String[] urls, StoredFileHelper storage, char kind, - int threads, String source, String psName, String[] psArgs, long nearLength) { + public static void startMission(Context context, DownloadSetting downloadSetting) { Intent intent = new Intent(context, DownloadManagerService.class); intent.setAction(Intent.ACTION_RUN); - intent.putExtra(EXTRA_URLS, urls); - intent.putExtra(EXTRA_KIND, kind); - intent.putExtra(EXTRA_THREADS, threads); - intent.putExtra(EXTRA_SOURCE, source); - intent.putExtra(EXTRA_POSTPROCESSING_NAME, psName); - intent.putExtra(EXTRA_POSTPROCESSING_ARGS, psArgs); - intent.putExtra(EXTRA_NEAR_LENGTH, nearLength); - - intent.putExtra(EXTRA_PARENT_PATH, storage.getParentUri()); - intent.putExtra(EXTRA_PATH, storage.getUri()); - intent.putExtra(EXTRA_STORAGE_TAG, storage.getTag()); + intent.putExtra(EXTRA_URLS, downloadSetting.getUrls()); + intent.putExtra(EXTRA_KIND, downloadSetting.getKind()); + intent.putExtra(EXTRA_THREADS, downloadSetting.getThreadCount()); + intent.putExtra(EXTRA_SOURCE, downloadSetting.getSource()); + intent.putExtra(EXTRA_POSTPROCESSING_NAME, downloadSetting.getPsName()); + intent.putExtra(EXTRA_POSTPROCESSING_ARGS, downloadSetting.getPsArgs()); + intent.putExtra(EXTRA_NEAR_LENGTH, downloadSetting.getNearLength()); + + intent.putExtra(EXTRA_PARENT_PATH, downloadSetting.getStoredFileHelper().getParentUri()); + intent.putExtra(EXTRA_PATH, downloadSetting.getStoredFileHelper().getUri()); + intent.putExtra(EXTRA_STORAGE_TAG, downloadSetting.getStoredFileHelper().getTag()); context.startService(intent); } diff --git a/app/src/main/res/layout/download_dialog.xml b/app/src/main/res/layout/download_dialog.xml index 985ce03f5e3..6acf2bd238b 100644 --- a/app/src/main/res/layout/download_dialog.xml +++ b/app/src/main/res/layout/download_dialog.xml @@ -61,11 +61,24 @@ android:text="@string/caption_setting_title"/> + + + + + + + + - + +