2016-03-25 19:01:22 +01:00
|
|
|
package org.schabi.newpipe.download;
|
2015-09-21 21:12:48 +02:00
|
|
|
|
|
|
|
import android.os.Bundle;
|
2017-05-15 05:57:57 +02:00
|
|
|
import android.support.annotation.IdRes;
|
2016-04-29 12:40:03 +02:00
|
|
|
import android.support.annotation.Nullable;
|
2015-09-21 21:12:48 +02:00
|
|
|
import android.support.v4.app.DialogFragment;
|
2016-04-29 12:40:03 +02:00
|
|
|
import android.support.v7.widget.Toolbar;
|
2015-09-21 21:12:48 +02:00
|
|
|
import android.util.Log;
|
2016-04-29 12:40:03 +02:00
|
|
|
import android.view.LayoutInflater;
|
|
|
|
import android.view.MenuItem;
|
|
|
|
import android.view.View;
|
|
|
|
import android.view.ViewGroup;
|
2017-05-15 05:57:57 +02:00
|
|
|
import android.widget.AdapterView;
|
|
|
|
import android.widget.ArrayAdapter;
|
2016-04-29 12:40:03 +02:00
|
|
|
import android.widget.EditText;
|
2016-09-26 20:18:32 +02:00
|
|
|
import android.widget.RadioButton;
|
2017-05-15 05:57:57 +02:00
|
|
|
import android.widget.RadioGroup;
|
2016-04-29 12:40:03 +02:00
|
|
|
import android.widget.SeekBar;
|
2017-05-15 05:57:57 +02:00
|
|
|
import android.widget.Spinner;
|
2016-04-29 12:40:03 +02:00
|
|
|
import android.widget.TextView;
|
2015-09-21 21:12:48 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
import org.schabi.newpipe.MainActivity;
|
2016-03-25 19:01:22 +01:00
|
|
|
import org.schabi.newpipe.R;
|
2017-05-15 05:57:57 +02:00
|
|
|
import org.schabi.newpipe.extractor.MediaFormat;
|
|
|
|
import org.schabi.newpipe.extractor.stream_info.AudioStream;
|
|
|
|
import org.schabi.newpipe.extractor.stream_info.StreamInfo;
|
|
|
|
import org.schabi.newpipe.extractor.stream_info.VideoStream;
|
|
|
|
import org.schabi.newpipe.fragments.detail.SpinnerToolbarAdapter;
|
2017-01-10 11:41:24 +01:00
|
|
|
import org.schabi.newpipe.settings.NewPipeSettings;
|
2017-05-15 05:57:57 +02:00
|
|
|
import org.schabi.newpipe.util.PermissionHelper;
|
2017-04-26 21:32:04 +02:00
|
|
|
import org.schabi.newpipe.util.ThemeHelper;
|
2017-05-15 05:57:57 +02:00
|
|
|
import org.schabi.newpipe.util.Utils;
|
2016-03-25 19:01:22 +01:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
import java.io.Serializable;
|
2016-01-07 14:22:55 +01:00
|
|
|
import java.util.ArrayList;
|
|
|
|
import java.util.List;
|
2015-09-21 21:12:48 +02:00
|
|
|
|
2016-04-29 12:40:03 +02:00
|
|
|
import us.shandian.giga.service.DownloadManagerService;
|
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
public class DownloadDialog extends DialogFragment implements RadioGroup.OnCheckedChangeListener, AdapterView.OnItemSelectedListener {
|
|
|
|
private static final String TAG = "DialogFragment";
|
|
|
|
private static final boolean DEBUG = MainActivity.DEBUG;
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
private static final String INFO_KEY = "info_key";
|
|
|
|
private static final String SORTED_VIDEOS_LIST_KEY = "sorted_videos_list_key";
|
|
|
|
private static final String SELECTED_VIDEO_KEY = "selected_video_key";
|
|
|
|
private static final String SELECTED_AUDIO_KEY = "selected_audio_key";
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
private StreamInfo currentInfo;
|
|
|
|
private ArrayList<VideoStream> sortedStreamVideosList;
|
|
|
|
private int selectedVideoIndex;
|
|
|
|
private int selectedAudioIndex;
|
|
|
|
|
|
|
|
private EditText nameEditText;
|
|
|
|
private Spinner streamsSpinner;
|
|
|
|
private RadioGroup radioVideoAudioGroup;
|
|
|
|
private TextView threadsCountTextView;
|
|
|
|
private SeekBar threadsSeekBar;
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
public static DownloadDialog newInstance(StreamInfo info, ArrayList<VideoStream> sortedStreamVideosList, int selectedVideoIndex) {
|
2016-04-29 12:40:03 +02:00
|
|
|
DownloadDialog dialog = new DownloadDialog();
|
2017-05-15 05:57:57 +02:00
|
|
|
dialog.setInfo(info, sortedStreamVideosList, selectedVideoIndex);
|
2016-04-29 12:40:03 +02:00
|
|
|
dialog.setStyle(DialogFragment.STYLE_NO_TITLE, 0);
|
|
|
|
return dialog;
|
|
|
|
}
|
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
private void setInfo(StreamInfo info, ArrayList<VideoStream> sortedStreamVideosList, int selectedVideoIndex) {
|
|
|
|
this.currentInfo = info;
|
|
|
|
this.selectedVideoIndex = selectedVideoIndex;
|
|
|
|
this.sortedStreamVideosList = sortedStreamVideosList;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// LifeCycle
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
2015-09-21 21:12:48 +02:00
|
|
|
@Override
|
2017-05-15 05:57:57 +02:00
|
|
|
public void onCreate(@Nullable Bundle savedInstanceState) {
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
if (DEBUG) Log.d(TAG, "onCreate() called with: savedInstanceState = [" + savedInstanceState + "]");
|
|
|
|
if (!PermissionHelper.checkStoragePermissions(getActivity())) {
|
|
|
|
getDialog().dismiss();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (savedInstanceState != null) {
|
|
|
|
Serializable serial = savedInstanceState.getSerializable(INFO_KEY);
|
|
|
|
if (serial instanceof StreamInfo) currentInfo = (StreamInfo) serial;
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
serial = savedInstanceState.getSerializable(SORTED_VIDEOS_LIST_KEY);
|
|
|
|
if (serial instanceof ArrayList) { //noinspection unchecked
|
|
|
|
sortedStreamVideosList = (ArrayList<VideoStream>) serial;
|
|
|
|
}
|
2016-02-17 21:39:41 +01:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
selectedVideoIndex = savedInstanceState.getInt(SELECTED_VIDEO_KEY, 0);
|
|
|
|
selectedAudioIndex = savedInstanceState.getInt(SELECTED_AUDIO_KEY, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
|
|
|
if (DEBUG) Log.d(TAG, "onCreateView() called with: inflater = [" + inflater + "], container = [" + container + "], savedInstanceState = [" + savedInstanceState + "]");
|
2016-04-29 12:40:03 +02:00
|
|
|
return inflater.inflate(R.layout.dialog_url, container);
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
|
|
|
|
super.onViewCreated(view, savedInstanceState);
|
2017-05-15 05:57:57 +02:00
|
|
|
nameEditText = ((EditText) view.findViewById(R.id.file_name));
|
|
|
|
nameEditText.setText(createFileName(currentInfo.title));
|
|
|
|
selectedAudioIndex = Utils.getPreferredAudioFormat(getContext(), currentInfo.audio_streams);
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
streamsSpinner = (Spinner) view.findViewById(R.id.quality_spinner);
|
|
|
|
streamsSpinner.setOnItemSelectedListener(this);
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
threadsCountTextView = (TextView) view.findViewById(R.id.threads_count);
|
|
|
|
threadsSeekBar = (SeekBar) view.findViewById(R.id.threads);
|
|
|
|
radioVideoAudioGroup = (RadioGroup) view.findViewById(R.id.video_audio_group);
|
|
|
|
radioVideoAudioGroup.setOnCheckedChangeListener(this);
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
initToolbar((Toolbar) view.findViewById(R.id.toolbar));
|
|
|
|
checkDownloadOptions(view);
|
|
|
|
setupVideoSpinner(sortedStreamVideosList, streamsSpinner);
|
|
|
|
|
|
|
|
int def = 3;
|
|
|
|
threadsCountTextView.setText(String.valueOf(def));
|
|
|
|
threadsSeekBar.setProgress(def - 1);
|
|
|
|
threadsSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
2016-04-29 12:40:03 +02:00
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onProgressChanged(SeekBar seekbar, int progress, boolean fromUser) {
|
2017-05-15 05:57:57 +02:00
|
|
|
threadsCountTextView.setText(String.valueOf(progress + 1));
|
2016-04-29 12:40:03 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStartTrackingTouch(SeekBar p1) {
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onStopTrackingTouch(SeekBar p1) {
|
|
|
|
|
|
|
|
}
|
|
|
|
});
|
2017-05-15 05:57:57 +02:00
|
|
|
}
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
@Override
|
|
|
|
public void onSaveInstanceState(Bundle outState) {
|
|
|
|
super.onSaveInstanceState(outState);
|
|
|
|
outState.putSerializable(INFO_KEY, currentInfo);
|
|
|
|
outState.putSerializable(SORTED_VIDEOS_LIST_KEY, sortedStreamVideosList);
|
|
|
|
outState.putInt(SELECTED_VIDEO_KEY, selectedVideoIndex);
|
|
|
|
outState.putInt(SELECTED_AUDIO_KEY, selectedAudioIndex);
|
|
|
|
}
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Inits
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
private void initToolbar(Toolbar toolbar) {
|
|
|
|
if (DEBUG) Log.d(TAG, "initToolbar() called with: toolbar = [" + toolbar + "]");
|
|
|
|
toolbar.setTitle(R.string.download_dialog_title);
|
|
|
|
toolbar.setNavigationIcon(ThemeHelper.isLightThemeSelected(getActivity()) ? R.drawable.ic_arrow_back_black_24dp : R.drawable.ic_arrow_back_white_24dp);
|
|
|
|
toolbar.inflateMenu(R.menu.dialog_url);
|
|
|
|
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
|
|
|
|
@Override
|
|
|
|
public void onClick(View v) {
|
|
|
|
getDialog().dismiss();
|
|
|
|
}
|
|
|
|
});
|
2016-04-29 12:40:03 +02:00
|
|
|
|
|
|
|
toolbar.setOnMenuItemClickListener(new Toolbar.OnMenuItemClickListener() {
|
|
|
|
@Override
|
|
|
|
public boolean onMenuItemClick(MenuItem item) {
|
|
|
|
if (item.getItemId() == R.id.okay) {
|
2017-05-15 05:57:57 +02:00
|
|
|
downloadSelected();
|
2016-04-29 12:40:03 +02:00
|
|
|
return true;
|
2017-05-15 05:57:57 +02:00
|
|
|
} else return false;
|
2016-04-29 12:40:03 +02:00
|
|
|
}
|
|
|
|
});
|
2017-05-15 05:57:57 +02:00
|
|
|
}
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
public void setupAudioSpinner(final List<AudioStream> audioStreams, Spinner spinner) {
|
|
|
|
String[] items = new String[audioStreams.size()];
|
|
|
|
for (int i = 0; i < audioStreams.size(); i++) {
|
|
|
|
AudioStream audioStream = audioStreams.get(i);
|
|
|
|
items[i] = MediaFormat.getNameById(audioStream.format) + " " + audioStream.avgBitrate + "kbps";
|
|
|
|
}
|
|
|
|
|
|
|
|
ArrayAdapter<String> itemAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, items);
|
|
|
|
spinner.setAdapter(itemAdapter);
|
|
|
|
spinner.setSelection(selectedAudioIndex);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setupVideoSpinner(final List<VideoStream> videoStreams, Spinner spinner) {
|
|
|
|
spinner.setAdapter(new SpinnerToolbarAdapter(getContext(), videoStreams, true));
|
|
|
|
spinner.setSelection(selectedVideoIndex);
|
2016-04-29 12:40:03 +02:00
|
|
|
}
|
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Radio group Video&Audio options - Listener
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
|
|
|
|
if (DEBUG) Log.d(TAG, "onCheckedChanged() called with: group = [" + group + "], checkedId = [" + checkedId + "]");
|
|
|
|
switch (checkedId) {
|
|
|
|
case R.id.audio_button:
|
|
|
|
setupAudioSpinner(currentInfo.audio_streams, streamsSpinner);
|
|
|
|
break;
|
|
|
|
case R.id.video_button:
|
|
|
|
setupVideoSpinner(sortedStreamVideosList, streamsSpinner);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Streams Spinner Listener
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
|
|
|
if (DEBUG) Log.d(TAG, "onItemSelected() called with: parent = [" + parent + "], view = [" + view + "], position = [" + position + "], id = [" + id + "]");
|
|
|
|
switch (radioVideoAudioGroup.getCheckedRadioButtonId()) {
|
|
|
|
case R.id.audio_button:
|
|
|
|
selectedAudioIndex = position;
|
|
|
|
break;
|
|
|
|
case R.id.video_button:
|
|
|
|
selectedVideoIndex = position;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void onNothingSelected(AdapterView<?> parent) {
|
|
|
|
}
|
|
|
|
|
|
|
|
/*//////////////////////////////////////////////////////////////////////////
|
|
|
|
// Utils
|
|
|
|
//////////////////////////////////////////////////////////////////////////*/
|
|
|
|
|
|
|
|
protected void checkDownloadOptions(View view) {
|
2016-09-26 20:18:32 +02:00
|
|
|
RadioButton audioButton = (RadioButton) view.findViewById(R.id.audio_button);
|
|
|
|
RadioButton videoButton = (RadioButton) view.findViewById(R.id.video_button);
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
if (currentInfo.audio_streams == null || currentInfo.audio_streams.size() == 0) {
|
2016-09-26 20:18:32 +02:00
|
|
|
audioButton.setVisibility(View.GONE);
|
|
|
|
videoButton.setChecked(true);
|
2017-05-15 05:57:57 +02:00
|
|
|
} else if (sortedStreamVideosList == null || sortedStreamVideosList.size() == 0) {
|
2016-09-26 20:18:32 +02:00
|
|
|
videoButton.setVisibility(View.GONE);
|
|
|
|
audioButton.setChecked(true);
|
2016-02-17 21:39:41 +01:00
|
|
|
}
|
2015-09-21 21:12:48 +02:00
|
|
|
}
|
|
|
|
|
2016-01-07 14:22:55 +01:00
|
|
|
/**
|
2017-06-28 07:27:32 +02:00
|
|
|
* #143 #44 #42 #22: make sure that the filename does not contain illegal chars.
|
2016-01-07 14:22:55 +01:00
|
|
|
* This should fix some of the "cannot download" problems.
|
2017-04-26 21:32:04 +02:00
|
|
|
*/
|
2017-05-15 05:57:57 +02:00
|
|
|
private String createFileName(String fileName) {
|
2016-01-07 14:22:55 +01:00
|
|
|
// from http://eng-przemelek.blogspot.de/2009/07/how-to-create-valid-file-name.html
|
|
|
|
|
2017-04-26 21:32:04 +02:00
|
|
|
List<String> forbiddenCharsPatterns = new ArrayList<>();
|
2016-01-07 14:22:55 +01:00
|
|
|
forbiddenCharsPatterns.add("[:]+"); // Mac OS, but it looks that also Windows XP
|
|
|
|
forbiddenCharsPatterns.add("[\\*\"/\\\\\\[\\]\\:\\;\\|\\=\\,]+"); // Windows
|
|
|
|
forbiddenCharsPatterns.add("[^\\w\\d\\.]+"); // last chance... only latin letters and digits
|
2017-05-15 05:57:57 +02:00
|
|
|
String nameToTest = fileName;
|
2016-01-07 14:22:55 +01:00
|
|
|
for (String pattern : forbiddenCharsPatterns) {
|
|
|
|
nameToTest = nameToTest.replaceAll(pattern, "_");
|
|
|
|
}
|
|
|
|
return nameToTest;
|
|
|
|
}
|
2016-02-17 21:39:41 +01:00
|
|
|
|
2016-04-29 12:40:03 +02:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
private void downloadSelected() {
|
|
|
|
String url, location;
|
2016-02-17 21:39:41 +01:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
String fileName = nameEditText.getText().toString().trim();
|
|
|
|
if (fileName.isEmpty()) fileName = createFileName(currentInfo.title);
|
2016-02-17 21:39:41 +01:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
boolean isAudio = radioVideoAudioGroup.getCheckedRadioButtonId() == R.id.audio_button;
|
|
|
|
url = isAudio ? currentInfo.audio_streams.get(selectedAudioIndex).url : sortedStreamVideosList.get(selectedVideoIndex).url;
|
|
|
|
location = isAudio ? NewPipeSettings.getAudioDownloadPath(getContext()) : NewPipeSettings.getVideoDownloadPath(getContext());
|
2016-03-25 19:01:22 +01:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
if (isAudio) fileName += "." + MediaFormat.getSuffixById(currentInfo.audio_streams.get(selectedAudioIndex).format);
|
|
|
|
else fileName += "." + MediaFormat.getSuffixById(sortedStreamVideosList.get(selectedVideoIndex).format);
|
2016-03-25 19:01:22 +01:00
|
|
|
|
2017-05-15 05:57:57 +02:00
|
|
|
DownloadManagerService.startMission(getContext(), url, location, fileName, isAudio, threadsSeekBar.getProgress() + 1);
|
|
|
|
getDialog().dismiss();
|
2016-02-17 21:39:41 +01:00
|
|
|
}
|
2015-09-21 21:12:48 +02:00
|
|
|
}
|