Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Download playlist #2018

Closed
wants to merge 9 commits into from
Closed
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/src/main/java/org/schabi/newpipe/RouterActivity.java
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,7 @@ private void openDownloadDialog() {
sortedVideoStreams);

android.support.v4.app.FragmentManager fm = getSupportFragmentManager();
DownloadDialog downloadDialog = DownloadDialog.newInstance(result);
DownloadDialog downloadDialog = DownloadDialog.newInstance(result, null);
downloadDialog.setVideoStreams(sortedVideoStreams);
downloadDialog.setAudioStreams(result.getAudioStreams());
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
Expand Down
73 changes: 62 additions & 11 deletions app/src/main/java/org/schabi/newpipe/download/DownloadDialog.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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<VideoStream> 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());
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -363,12 +381,35 @@ 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);

VishalNehra marked this conversation as resolved.
Show resolved Hide resolved
toolbar.setOnMenuItemClickListener(item -> {

if (item.getItemId() == R.id.okay) {
prepareSelectedDownload();
return true;

if (playlistDownloadCallback != null) {
if (smartDownloadCheckbox.isChecked() && downloadSetting != null) {
playlistDownloadCallback.accept(downloadSetting);
} else {
playlistDownloadCallback.accept(null);
}
}
} else if (item.getItemId() == R.id.skip) {
if (playlistDownloadCallback != null) {

playlistDownloadCallback.accept(null);
}
}
return false;

getDialog().dismiss();
return true;
});
}

Expand Down Expand Up @@ -779,20 +820,27 @@ 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;
}
break;
case R.id.video_button:
kind = 'v';
selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex);
VideoStream videoStream = videoStreamsAdapter.getItem(selectedVideoIndex);
videoResolution = videoStream.getResolution();
selectedStream = videoStream;

SecondaryStreamHelper<AudioStream> secondaryStream = videoStreamsAdapter
.getAllSecondary()
Expand All @@ -819,7 +867,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;
Expand All @@ -839,8 +889,9 @@ private void continueSelectedDownload(@NonNull StoredFileHelper storage) {
} else {
urls = new String[]{selectedStream.getUrl(), secondaryStreamUrl};
}

DownloadManagerService.startMission(context, urls, storage, kind, threads, currentInfo.getUrl(), psName, psArgs, nearLength);
this.downloadSetting = new DownloadSetting(storage, threads, urls, currentInfo.getUrl(), kind, psName, psArgs,
nearLength, videoResolution, audioBitrate, subtitleLocale);
DownloadManagerService.startMission(context, downloadSetting);

dismiss();
}
Expand Down
80 changes: 80 additions & 0 deletions app/src/main/java/org/schabi/newpipe/download/DownloadSetting.java
Original file line number Diff line number Diff line change
@@ -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;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a good idea using char for this, a enum would be much better.

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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1169,7 +1169,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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.Log;
Expand All @@ -23,6 +22,7 @@
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;
Expand All @@ -40,6 +40,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;
Expand Down Expand Up @@ -80,6 +81,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
private View headerPlayAllButton;
private View headerPopupButton;
private View headerBackgroundButton;
private View headerDownloadAllButton;

private MenuItem playlistBookmarkButton;

Expand Down Expand Up @@ -124,7 +126,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;
}
Expand Down Expand Up @@ -305,6 +307,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());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Strange use of the PlayQueue items here. Why not the items themselves?

}
});

headerBackgroundButton.setOnLongClickListener(view -> {
NavigationHelper.enqueueOnBackgroundPlayer(activity, getPlayQueue(), true);
return true;
Expand All @@ -317,8 +325,8 @@ private PlayQueue getPlayQueue() {

private PlayQueue getPlayQueue(final int index) {
final List<StreamInfoItem> 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);
}
}
Expand All @@ -331,6 +339,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);
Expand All @@ -346,7 +364,7 @@ public void handleNextItems(ListExtractor.InfoItemsPage result) {
//////////////////////////////////////////////////////////////////////////*/

@Override
protected boolean onError(Throwable exception) {
public boolean onError(Throwable exception) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should strictly remain for internal use only.

if (super.onError(exception)) return true;

int errorId = exception instanceof ExtractionException ? R.string.parsing_error : R.string.general_error;
Expand Down
Loading