SponsorBlock: Merge branch 'dev' into sponsorblock

This commit is contained in:
polymorphicshade 2020-09-05 22:13:36 -06:00
commit 62b109171c
17 changed files with 154 additions and 52 deletions

View file

@ -164,7 +164,7 @@ dependencies {
exclude module: 'support-annotations'
}
implementation 'com.github.TeamNewPipe:NewPipeExtractor:5ac80624a40f4c600ae493e66881b5bf008f0ddb'
implementation 'com.github.TeamNewPipe:NewPipeExtractor:6633f26ec5a73a8e932de575b7a0643b6ad6c890'
implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
implementation "org.jsoup:jsoup:1.13.1"

View file

@ -68,6 +68,14 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
return false;
}
}
final View seekBar = child.findViewById(R.id.playbackSeekBar);
if (seekBar != null) {
final boolean visible = seekBar.getGlobalVisibleRect(globalRect);
if (visible && globalRect.contains((int) ev.getRawX(), (int) ev.getRawY())) {
allowScroll = false;
return false;
}
}
allowScroll = true;
switch (ev.getActionMasked()) {
case MotionEvent.ACTION_DOWN:

View file

@ -4,10 +4,12 @@ import android.net.Uri;
import android.os.Parcel;
import android.os.Parcelable;
import java.io.Serializable;
/**
* Class for storing information about a software license.
*/
public class License implements Parcelable {
public class License implements Parcelable, Serializable {
public static final Creator<License> CREATOR = new Creator<License>() {
@Override
public License createFromParcel(final Parcel source) {

View file

@ -1,7 +1,6 @@
package org.schabi.newpipe.about;
import android.app.Activity;
import android.content.Context;
import android.os.Bundle;
import android.view.ContextMenu;
import android.view.LayoutInflater;
@ -11,12 +10,14 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import org.schabi.newpipe.R;
import org.schabi.newpipe.util.ShareUtils;
import java.io.Serializable;
import java.util.Arrays;
/**
@ -26,6 +27,8 @@ public class LicenseFragment extends Fragment {
private static final String ARG_COMPONENTS = "components";
private SoftwareComponent[] softwareComponents;
private SoftwareComponent componentForContextMenu;
private License activeLicense;
private static final String LICENSE_KEY = "ACTIVE_LICENSE";
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
if (softwareComponents == null) {
@ -44,8 +47,8 @@ public class LicenseFragment extends Fragment {
* @param context the context to use
* @param license the license to show
*/
private static void showLicense(final Context context, final License license) {
new LicenseFragmentHelper((Activity) context).execute(license);
private static void showLicense(final Activity context, final License license) {
new LicenseFragmentHelper(context).execute(license);
}
@Override
@ -54,6 +57,12 @@ public class LicenseFragment extends Fragment {
softwareComponents = (SoftwareComponent[]) getArguments()
.getParcelableArray(ARG_COMPONENTS);
if (savedInstanceState != null) {
final Serializable license = savedInstanceState.getSerializable(LICENSE_KEY);
if (license != null) {
activeLicense = (License) license;
}
}
// Sort components by name
Arrays.sort(softwareComponents, (o1, o2) -> o1.getName().compareTo(o2.getName()));
}
@ -66,8 +75,10 @@ public class LicenseFragment extends Fragment {
final ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components);
final View licenseLink = rootView.findViewById(R.id.app_read_license);
licenseLink.setOnClickListener(v ->
showLicense(getActivity(), StandardLicenses.GPL3));
licenseLink.setOnClickListener(v -> {
activeLicense = StandardLicenses.GPL3;
showLicense(getActivity(), StandardLicenses.GPL3);
});
for (final SoftwareComponent component : softwareComponents) {
final View componentView = inflater
@ -81,11 +92,16 @@ public class LicenseFragment extends Fragment {
component.getLicense().getAbbreviation()));
componentView.setTag(component);
componentView.setOnClickListener(v ->
showLicense(getActivity(), component.getLicense()));
componentView.setOnClickListener(v -> {
activeLicense = component.getLicense();
showLicense(getActivity(), component.getLicense());
});
softwareComponentsView.addView(componentView);
registerForContextMenu(componentView);
}
if (activeLicense != null) {
showLicense(getActivity(), activeLicense);
}
return rootView;
}
@ -101,7 +117,7 @@ public class LicenseFragment extends Fragment {
}
@Override
public boolean onContextItemSelected(final MenuItem item) {
public boolean onContextItemSelected(@NonNull final MenuItem item) {
// item.getMenuInfo() is null so we use the tag of the view
final SoftwareComponent component = componentForContextMenu;
if (component == null) {
@ -116,4 +132,12 @@ public class LicenseFragment extends Fragment {
}
return false;
}
@Override
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
if (activeLicense != null) {
savedInstanceState.putSerializable(LICENSE_KEY, activeLicense);
}
}
}

View file

@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity;
public final class Migrations {
public static final int DB_VER_1 = 1;
@ -14,7 +14,7 @@ public final class Migrations {
public static final int DB_VER_3 = 3;
private static final String TAG = Migrations.class.getName();
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
public static final boolean DEBUG = MainActivity.DEBUG;
public static final Migration MIGRATION_1_2 = new Migration(DB_VER_1, DB_VER_2) {
@Override

View file

@ -516,7 +516,23 @@ public class DownloadDialog extends DialogFragment
videoButton.setVisibility(isVideoStreamsAvailable ? View.VISIBLE : View.GONE);
subtitleButton.setVisibility(isSubtitleStreamsAvailable ? View.VISIBLE : View.GONE);
if (isVideoStreamsAvailable) {
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
final String defaultMedia = prefs.getString(getString(R.string.last_used_download_type),
getString(R.string.last_download_type_video_key));
if (isVideoStreamsAvailable
&& (defaultMedia.equals(getString(R.string.last_download_type_video_key)))) {
videoButton.setChecked(true);
setupVideoSpinner();
} else if (isAudioStreamsAvailable
&& (defaultMedia.equals(getString(R.string.last_download_type_audio_key)))) {
audioButton.setChecked(true);
setupAudioSpinner();
} else if (isSubtitleStreamsAvailable
&& (defaultMedia.equals(getString(R.string.last_download_type_subtitle_key)))) {
subtitleButton.setChecked(true);
setupSubtitleSpinner();
} else if (isVideoStreamsAvailable) {
videoButton.setChecked(true);
setupVideoSpinner();
} else if (isAudioStreamsAvailable) {
@ -595,6 +611,7 @@ public class DownloadDialog extends DialogFragment
final StoredDirectoryHelper mainStorage;
final MediaFormat format;
final String mime;
final String selectedMediaType;
// first, build the filename and get the output folder (if possible)
// later, run a very very very large file checking logic
@ -603,6 +620,7 @@ public class DownloadDialog extends DialogFragment
switch (radioStreamsGroup.getCheckedRadioButtonId()) {
case R.id.audio_button:
selectedMediaType = getString(R.string.last_download_type_audio_key);
mainStorage = mainStorageAudio;
format = audioStreamsAdapter.getItem(selectedAudioIndex).getFormat();
switch (format) {
@ -617,12 +635,14 @@ public class DownloadDialog extends DialogFragment
}
break;
case R.id.video_button:
selectedMediaType = getString(R.string.last_download_type_video_key);
mainStorage = mainStorageVideo;
format = videoStreamsAdapter.getItem(selectedVideoIndex).getFormat();
mime = format.mimeType;
filename += format.suffix;
break;
case R.id.subtitle_button:
selectedMediaType = getString(R.string.last_download_type_subtitle_key);
mainStorage = mainStorageVideo; // subtitle & video files go together
format = subtitleStreamsAdapter.getItem(selectedSubtitleIndex).getFormat();
mime = format.mimeType;
@ -664,6 +684,11 @@ public class DownloadDialog extends DialogFragment
// check for existing file with the same name
checkSelectedDownload(mainStorage, mainStorage.findFile(filename), filename, mime);
// remember the last media type downloaded by the user
prefs.edit()
.putString(getString(R.string.last_used_download_type), selectedMediaType)
.apply();
}
private void checkSelectedDownload(final StoredDirectoryHelper mainStorage,

View file

@ -202,6 +202,7 @@ public class VideoDetailFragment
private ImageView thumbnailImageView;
private ImageView thumbnailPlayButton;
private AnimatedProgressBar positionView;
private ViewGroup playerPlaceholder;
private View videoTitleRoot;
private TextView videoTitleTextView;
@ -336,6 +337,7 @@ public class VideoDetailFragment
stopPlayerListener();
playerService = null;
player = null;
saveCurrentAndRestoreDefaultBrightness();
}
}
@ -424,7 +426,7 @@ public class VideoDetailFragment
if (currentWorker != null) {
currentWorker.dispose();
}
setupBrightness(true);
saveCurrentAndRestoreDefaultBrightness();
PreferenceManager.getDefaultSharedPreferences(getContext())
.edit()
.putString(getString(R.string.stream_info_selected_tab_key),
@ -438,7 +440,7 @@ public class VideoDetailFragment
activity.sendBroadcast(new Intent(ACTION_VIDEO_FRAGMENT_RESUMED));
setupBrightness(false);
setupBrightness();
if (updateFlags != 0) {
if (!isLoading.get() && currentInfo != null) {
@ -705,6 +707,7 @@ public class VideoDetailFragment
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
playerPlaceholder = rootView.findViewById(R.id.player_placeholder);
contentRootLayoutHiding = rootView.findViewById(R.id.detail_content_root_hiding);
@ -1265,17 +1268,15 @@ public class VideoDetailFragment
return;
}
final FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
// Check if viewHolder already contains a child
if (player.getRootView().getParent() != viewHolder) {
if (player.getRootView().getParent() != playerPlaceholder) {
removeVideoPlayerView();
}
setHeightThumbnail();
// Prevent from re-adding a view multiple times
if (player.getRootView().getParent() == null) {
viewHolder.addView(player.getRootView());
playerPlaceholder.addView(player.getRootView());
}
}
@ -1290,9 +1291,8 @@ public class VideoDetailFragment
return;
}
final FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
viewHolder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
viewHolder.requestLayout();
playerPlaceholder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
playerPlaceholder.requestLayout();
}
private void prepareDescription(final Description description) {
@ -1770,9 +1770,19 @@ public class VideoDetailFragment
private void showPlaybackProgress(final long progress, final long duration) {
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
// If the old and the new progress values have a big difference then use
// animation. Otherwise don't because it affects CPU
final boolean shouldAnimate = Math.abs(positionView.getProgress() - progressSeconds) > 2;
positionView.setMax(durationSeconds);
if (shouldAnimate) {
positionView.setProgressAnimated(progressSeconds);
detailPositionView.setText(Localization.getDurationString(progressSeconds));
} else {
positionView.setProgress(progressSeconds);
}
final String position = Localization.getDurationString(progressSeconds);
if (position != detailPositionView.getText()) {
detailPositionView.setText(position);
}
if (positionView.getVisibility() != View.VISIBLE) {
animateView(positionView, true, 100);
animateView(detailPositionView, true, 100);
@ -1899,6 +1909,7 @@ public class VideoDetailFragment
@Override
public void onFullscreenStateChanged(final boolean fullscreen) {
setupBrightness();
if (playerService.getView() == null || player.getParentActivity() == null) {
return;
}
@ -1949,7 +1960,7 @@ public class VideoDetailFragment
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
final ValueAnimator valueAnimator = ValueAnimator
.ofInt(0, -getView().findViewById(R.id.player_placeholder).getHeight());
.ofInt(0, -playerPlaceholder.getHeight());
valueAnimator.setInterpolator(new DecelerateInterpolator());
valueAnimator.addUpdateListener(animation -> {
behavior.setTopAndBottomOffset((int) animation.getAnimatedValue());
@ -2013,30 +2024,42 @@ public class VideoDetailFragment
&& player.getPlayer().getPlaybackState() != Player.STATE_IDLE;
}
private void setupBrightness(final boolean save) {
private void saveCurrentAndRestoreDefaultBrightness() {
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
if (lp.screenBrightness == -1) {
return;
}
// Save current brightness level
PlayerHelper.setScreenBrightness(activity, lp.screenBrightness);
// Restore the old brightness when fragment.onPause() called or
// when a player is in portrait
lp.screenBrightness = -1;
activity.getWindow().setAttributes(lp);
}
private void setupBrightness() {
if (activity == null) {
return;
}
final WindowManager.LayoutParams lp = activity.getWindow().getAttributes();
if (save) {
// Save current brightness level
PlayerHelper.setScreenBrightness(activity, lp.screenBrightness);
// Restore the old brightness when fragment.onPause() called.
// It means when user leaves this fragment brightness will be set to system brightness
lp.screenBrightness = -1;
if (player == null
|| !player.videoPlayerSelected()
|| !player.isFullscreen()
|| bottomSheetState != BottomSheetBehavior.STATE_EXPANDED) {
// Apply system brightness when the player is not in fullscreen
saveCurrentAndRestoreDefaultBrightness();
} else {
// Restore already saved brightness level
final float brightnessLevel = PlayerHelper.getScreenBrightness(activity);
if (brightnessLevel <= 0.0f && brightnessLevel > 1.0f) {
if (brightnessLevel == lp.screenBrightness) {
return;
}
lp.screenBrightness = brightnessLevel;
}
activity.getWindow().setAttributes(lp);
}
}
private void checkLandscape() {
if ((!player.isPlaying() && player.getPlayQueue() != playQueue)
@ -2158,6 +2181,7 @@ public class VideoDetailFragment
* @param toMain if true than the main fragment will be focused or the player otherwise
*/
private void moveFocusToMainFragment(final boolean toMain) {
setupBrightness();
final ViewGroup mainFragment = requireActivity().findViewById(R.id.fragment_holder);
// Hamburger button steels a focus even under bottomSheet
final Toolbar toolbar = requireActivity().findViewById(R.id.toolbar);
@ -2181,7 +2205,7 @@ public class VideoDetailFragment
* Bottom padding should be equal to the mini player's height in this case
*
* @param showMore whether main fragment should be expanded or not
* */
*/
private void manageSpaceAtTheBottom(final boolean showMore) {
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
final ViewGroup holder = requireActivity().findViewById(R.id.fragment_holder);

View file

@ -55,8 +55,8 @@ import com.nostra13.universalimageloader.core.assist.FailReason;
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
import org.schabi.newpipe.App;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.DownloaderImpl;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
import org.schabi.newpipe.SponsorBlockApiTask;
import org.schabi.newpipe.extractor.stream.StreamInfo;
@ -103,7 +103,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
@SuppressWarnings({"WeakerAccess"})
public abstract class BasePlayer implements
Player.EventListener, PlaybackListener, ImageLoadingListener {
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
public static final boolean DEBUG = MainActivity.DEBUG;
@NonNull
public static final String TAG = "BasePlayer";
@ -989,7 +989,6 @@ public abstract class BasePlayer implements
}
setRecovery();
final Throwable cause = error.getCause();
if (error instanceof BehindLiveWindowException) {
reload();
} else {
@ -1516,6 +1515,11 @@ public abstract class BasePlayer implements
return;
}
final StreamInfo currentInfo = currentMetadata.getMetadata();
if (playQueue != null) {
// Save current position. It will help to restore this position once a user
// wants to play prev or next stream from the queue
playQueue.setRecovery(playQueue.getIndex(), simpleExoPlayer.getContentPosition());
}
savePlaybackState(currentInfo, simpleExoPlayer.getCurrentPosition());
}

View file

@ -184,6 +184,9 @@ public final class MainPlayer extends Service {
@Override
public void onTaskRemoved(final Intent rootIntent) {
super.onTaskRemoved(rootIntent);
if (!playerImpl.videoPlayerSelected()) {
return;
}
onDestroy();
// Unload from memory completely
Runtime.getRuntime().halt(0);

View file

@ -329,18 +329,16 @@ public class VideoPlayerImpl extends VideoPlayer
if (popupPlayerSelected()) {
final float captionRatio = (captionScale - 1.0f) / 5.0f + 1.0f;
view.setFractionalTextSize(SubtitleView.DEFAULT_TEXT_SIZE_FRACTION * captionRatio);
view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT));
view.setStyle(captionStyle);
} else {
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels);
final float captionRatioInverse = 20f + 4f * (1.0f - captionScale);
view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX,
(float) minimumLength / captionRatioInverse);
}
view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT));
view.setStyle(captionStyle);
}
}
/**
* This method ensures that popup and main players have different look.

View file

@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@ -25,7 +26,7 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
private boolean skippingInterception = false;
private final List<Integer> skipInterceptionOfElements = Arrays.asList(
R.id.detail_content_root_layout, R.id.relatedStreamsLayout,
R.id.playQueuePanel, R.id.viewpager);
R.id.playQueuePanel, R.id.viewpager, R.id.bottomControls);
@Override
public boolean onInterceptTouchEvent(@NonNull final CoordinatorLayout parent,
@ -51,6 +52,13 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
visible = viewGroup.getGlobalVisibleRect(globalRect);
if (visible
&& globalRect.contains((int) event.getRawX(), (int) event.getRawY())) {
// Makes bottom part of the player draggable in portrait when
// playbackControlRoot is hidden
if (element == R.id.bottomControls
&& child.findViewById(R.id.playbackControlRoot)
.getVisibility() != View.VISIBLE) {
return super.onInterceptTouchEvent(parent, child, event);
}
skippingInterception = true;
return false;
}

View file

@ -202,7 +202,8 @@ public class PlayerGestureListener
private boolean onScrollInMain(final MotionEvent initialEvent, final MotionEvent movingEvent,
final float distanceX, final float distanceY) {
if (!isVolumeGestureEnabled && !isBrightnessGestureEnabled) {
if ((!isVolumeGestureEnabled && !isBrightnessGestureEnabled)
|| !playerImpl.isFullscreen()) {
return false;
}

View file

@ -7,7 +7,7 @@ import androidx.annotation.Nullable;
import org.reactivestreams.Subscriber;
import org.reactivestreams.Subscription;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.player.playqueue.events.AppendEvent;
import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
import org.schabi.newpipe.player.playqueue.events.InitEvent;
@ -44,7 +44,7 @@ import io.reactivex.subjects.BehaviorSubject;
*/
public abstract class PlayQueue implements Serializable {
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
public static final boolean DEBUG = MainActivity.DEBUG;
private ArrayList<PlayQueueItem> backup;
private ArrayList<PlayQueueItem> streams;

View file

@ -106,7 +106,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
SELECTION_FLAG_AUTOSELECT,
PlayerHelper.captionLanguageOf(context, subtitle));
final MediaSource textSource = dataSource.getSampleMediaSourceFactory()
.createMediaSource(Uri.parse(subtitle.getURL()), textFormat, TIME_UNSET);
.createMediaSource(Uri.parse(subtitle.getUrl()), textFormat, TIME_UNSET);
mediaSources.add(textSource);
}
}

View file

@ -4,12 +4,12 @@ import android.os.Bundle;
import androidx.preference.Preference;
import org.schabi.newpipe.BuildConfig;
import org.schabi.newpipe.CheckForNewAppVersionTask;
import org.schabi.newpipe.MainActivity;
import org.schabi.newpipe.R;
public class MainSettingsFragment extends BasePreferenceFragment {
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
public static final boolean DEBUG = MainActivity.DEBUG;
@Override
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {

View file

@ -155,7 +155,7 @@ public class DownloadMissionRecover extends Thread {
for (SubtitlesStream subtitles : mExtractor.getSubtitles(mRecovery.format)) {
String tag = subtitles.getLanguageTag();
if (tag.equals(mRecovery.desired) && subtitles.isAutoGenerated() == mRecovery.desired2) {
url = subtitles.getURL();
url = subtitles.getUrl();
break;
}
}

View file

@ -236,6 +236,11 @@
<string name="clear_playback_states_key" translatable="false">clear_playback_states</string>
<string name="clear_search_history_key" translatable="false">clear_search_history</string>
<string name="last_used_download_type" translatable="false">@string/last_download_type_video_key</string>
<string name="last_download_type_video_key" translatable="false">last_dl_type_video</string>
<string name="last_download_type_audio_key" translatable="false">last_dl_type_audio</string>
<string name="last_download_type_subtitle_key" translatable="false">last_dl_type_subtitle</string>
<string name="downloads_storage_ask" translatable="false">downloads_storage_ask</string>
<string name="storage_use_saf" translatable="false">storage_use_saf</string>