mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2024-12-23 08:30:44 +00:00
Merge branch 'dev' into pr3178
This commit is contained in:
commit
97ff9e9c5b
1
.github/CONTRIBUTING.md
vendored
1
.github/CONTRIBUTING.md
vendored
@ -33,6 +33,7 @@ with your GitHub account.
|
|||||||
|
|
||||||
## Code contribution
|
## Code contribution
|
||||||
|
|
||||||
|
* If you want to add a feature or change one, please open an issue describing your change. This gives the team and community a chance to give feedback before you spend any time on something that could be done differently or not done at all. It also prevents two contributors from working on the same thing and one being disappointed when only one user's code can be added.
|
||||||
* Stick to NewPipe's style conventions: follow [checkStyle](https://github.com/checkstyle/checkstyle). It will run each time you build the project.
|
* Stick to NewPipe's style conventions: follow [checkStyle](https://github.com/checkstyle/checkstyle). It will run each time you build the project.
|
||||||
* Do not bring non-free software (e.g. binary blobs) into the project. Also, make sure you do not introduce Google
|
* Do not bring non-free software (e.g. binary blobs) into the project. Also, make sure you do not introduce Google
|
||||||
libraries.
|
libraries.
|
||||||
|
@ -164,7 +164,7 @@ dependencies {
|
|||||||
exclude module: 'support-annotations'
|
exclude module: 'support-annotations'
|
||||||
}
|
}
|
||||||
|
|
||||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:5ac80624a40f4c600ae493e66881b5bf008f0ddb'
|
implementation 'com.github.TeamNewPipe:NewPipeExtractor:6633f26ec5a73a8e932de575b7a0643b6ad6c890'
|
||||||
|
|
||||||
implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
|
implementation "com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751"
|
||||||
implementation "org.jsoup:jsoup:1.13.1"
|
implementation "org.jsoup:jsoup:1.13.1"
|
||||||
|
@ -21,13 +21,13 @@ public class ErrorInfoTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void errorInfoTestParcelable() {
|
public void errorInfoTestParcelable() {
|
||||||
ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request",
|
final ErrorInfo info = ErrorInfo.make(UserAction.USER_REPORT, "youtube", "request",
|
||||||
R.string.general_error);
|
R.string.general_error);
|
||||||
// Obtain a Parcel object and write the parcelable object to it:
|
// Obtain a Parcel object and write the parcelable object to it:
|
||||||
Parcel parcel = Parcel.obtain();
|
final Parcel parcel = Parcel.obtain();
|
||||||
info.writeToParcel(parcel, 0);
|
info.writeToParcel(parcel, 0);
|
||||||
parcel.setDataPosition(0);
|
parcel.setDataPosition(0);
|
||||||
ErrorInfo infoFromParcel = ErrorInfo.CREATOR.createFromParcel(parcel);
|
final ErrorInfo infoFromParcel = ErrorInfo.CREATOR.createFromParcel(parcel);
|
||||||
|
|
||||||
assertEquals(UserAction.USER_REPORT, infoFromParcel.userAction);
|
assertEquals(UserAction.USER_REPORT, infoFromParcel.userAction);
|
||||||
assertEquals("youtube", infoFromParcel.serviceName);
|
assertEquals("youtube", infoFromParcel.serviceName);
|
||||||
|
@ -23,6 +23,7 @@
|
|||||||
android:logo="@mipmap/ic_launcher"
|
android:logo="@mipmap/ic_launcher"
|
||||||
android:requestLegacyExternalStorage="true"
|
android:requestLegacyExternalStorage="true"
|
||||||
android:theme="@style/OpeningTheme"
|
android:theme="@style/OpeningTheme"
|
||||||
|
android:resizeableActivity="true"
|
||||||
tools:ignore="AllowBackup">
|
tools:ignore="AllowBackup">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
@ -318,5 +319,11 @@
|
|||||||
<service
|
<service
|
||||||
android:name=".RouterActivity$FetcherService"
|
android:name=".RouterActivity$FetcherService"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
|
<!-- see https://github.com/TeamNewPipe/NewPipe/issues/3947 -->
|
||||||
|
<!-- Version < 3.0. DeX Mode and Screen Mirroring support -->
|
||||||
|
<meta-data android:name="com.samsung.android.keepalive.density" android:value="true"/>
|
||||||
|
<!-- Version >= 3.0. DeX Dual Mode support -->
|
||||||
|
<meta-data android:name="com.samsung.android.multidisplay.keep_process_alive" android:value="true"/>
|
||||||
</application>
|
</application>
|
||||||
</manifest>
|
</manifest>
|
||||||
|
@ -150,7 +150,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
// from its saved state, where the fragment manager has already
|
// from its saved state, where the fragment manager has already
|
||||||
// taken care of restoring the fragments we previously had instantiated.
|
// taken care of restoring the fragments we previously had instantiated.
|
||||||
if (mFragments.size() > position) {
|
if (mFragments.size() > position) {
|
||||||
Fragment f = mFragments.get(position);
|
final Fragment f = mFragments.get(position);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
@ -160,12 +160,12 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
mCurTransaction = mFragmentManager.beginTransaction();
|
mCurTransaction = mFragmentManager.beginTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
Fragment fragment = getItem(position);
|
final Fragment fragment = getItem(position);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
|
Log.v(TAG, "Adding item #" + position + ": f=" + fragment);
|
||||||
}
|
}
|
||||||
if (mSavedState.size() > position) {
|
if (mSavedState.size() > position) {
|
||||||
Fragment.SavedState fss = mSavedState.get(position);
|
final Fragment.SavedState fss = mSavedState.get(position);
|
||||||
if (fss != null) {
|
if (fss != null) {
|
||||||
fragment.setInitialSavedState(fss);
|
fragment.setInitialSavedState(fss);
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
@Override
|
@Override
|
||||||
public void destroyItem(@NonNull final ViewGroup container, final int position,
|
public void destroyItem(@NonNull final ViewGroup container, final int position,
|
||||||
@NonNull final Object object) {
|
@NonNull final Object object) {
|
||||||
Fragment fragment = (Fragment) object;
|
final Fragment fragment = (Fragment) object;
|
||||||
|
|
||||||
if (mCurTransaction == null) {
|
if (mCurTransaction == null) {
|
||||||
mCurTransaction = mFragmentManager.beginTransaction();
|
mCurTransaction = mFragmentManager.beginTransaction();
|
||||||
@ -217,7 +217,7 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
@SuppressWarnings({"ReferenceEquality", "deprecation"})
|
@SuppressWarnings({"ReferenceEquality", "deprecation"})
|
||||||
public void setPrimaryItem(@NonNull final ViewGroup container, final int position,
|
public void setPrimaryItem(@NonNull final ViewGroup container, final int position,
|
||||||
@NonNull final Object object) {
|
@NonNull final Object object) {
|
||||||
Fragment fragment = (Fragment) object;
|
final Fragment fragment = (Fragment) object;
|
||||||
if (fragment != mCurrentPrimaryItem) {
|
if (fragment != mCurrentPrimaryItem) {
|
||||||
if (mCurrentPrimaryItem != null) {
|
if (mCurrentPrimaryItem != null) {
|
||||||
mCurrentPrimaryItem.setMenuVisibility(false);
|
mCurrentPrimaryItem.setMenuVisibility(false);
|
||||||
@ -267,17 +267,17 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
Bundle state = null;
|
Bundle state = null;
|
||||||
if (mSavedState.size() > 0) {
|
if (mSavedState.size() > 0) {
|
||||||
state = new Bundle();
|
state = new Bundle();
|
||||||
Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
|
final Fragment.SavedState[] fss = new Fragment.SavedState[mSavedState.size()];
|
||||||
mSavedState.toArray(fss);
|
mSavedState.toArray(fss);
|
||||||
state.putParcelableArray("states", fss);
|
state.putParcelableArray("states", fss);
|
||||||
}
|
}
|
||||||
for (int i = 0; i < mFragments.size(); i++) {
|
for (int i = 0; i < mFragments.size(); i++) {
|
||||||
Fragment f = mFragments.get(i);
|
final Fragment f = mFragments.get(i);
|
||||||
if (f != null && f.isAdded()) {
|
if (f != null && f.isAdded()) {
|
||||||
if (state == null) {
|
if (state == null) {
|
||||||
state = new Bundle();
|
state = new Bundle();
|
||||||
}
|
}
|
||||||
String key = "f" + i;
|
final String key = "f" + i;
|
||||||
mFragmentManager.putFragment(state, key, f);
|
mFragmentManager.putFragment(state, key, f);
|
||||||
|
|
||||||
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
||||||
@ -294,9 +294,9 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
@Override
|
@Override
|
||||||
public void restoreState(@Nullable final Parcelable state, @Nullable final ClassLoader loader) {
|
public void restoreState(@Nullable final Parcelable state, @Nullable final ClassLoader loader) {
|
||||||
if (state != null) {
|
if (state != null) {
|
||||||
Bundle bundle = (Bundle) state;
|
final Bundle bundle = (Bundle) state;
|
||||||
bundle.setClassLoader(loader);
|
bundle.setClassLoader(loader);
|
||||||
Parcelable[] fss = bundle.getParcelableArray("states");
|
final Parcelable[] fss = bundle.getParcelableArray("states");
|
||||||
mSavedState.clear();
|
mSavedState.clear();
|
||||||
mFragments.clear();
|
mFragments.clear();
|
||||||
if (fss != null) {
|
if (fss != null) {
|
||||||
@ -304,11 +304,11 @@ public abstract class FragmentStatePagerAdapterMenuWorkaround extends PagerAdapt
|
|||||||
mSavedState.add((Fragment.SavedState) fss[i]);
|
mSavedState.add((Fragment.SavedState) fss[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Iterable<String> keys = bundle.keySet();
|
final Iterable<String> keys = bundle.keySet();
|
||||||
for (String key: keys) {
|
for (final String key : keys) {
|
||||||
if (key.startsWith("f")) {
|
if (key.startsWith("f")) {
|
||||||
int index = Integer.parseInt(key.substring(1));
|
final int index = Integer.parseInt(key.substring(1));
|
||||||
Fragment f = mFragmentManager.getFragment(bundle, key);
|
final Fragment f = mFragmentManager.getFragment(bundle, key);
|
||||||
if (f != null) {
|
if (f != null) {
|
||||||
while (mFragments.size() <= index) {
|
while (mFragments.size() <= index) {
|
||||||
mFragments.add(null);
|
mFragments.add(null);
|
||||||
|
@ -30,19 +30,18 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
public boolean onRequestChildRectangleOnScreen(
|
public boolean onRequestChildRectangleOnScreen(
|
||||||
@NonNull final CoordinatorLayout coordinatorLayout, @NonNull final AppBarLayout child,
|
@NonNull final CoordinatorLayout coordinatorLayout, @NonNull final AppBarLayout child,
|
||||||
@NonNull final Rect rectangle, final boolean immediate) {
|
@NonNull final Rect rectangle, final boolean immediate) {
|
||||||
|
|
||||||
focusScrollRect.set(rectangle);
|
focusScrollRect.set(rectangle);
|
||||||
|
|
||||||
coordinatorLayout.offsetDescendantRectToMyCoords(child, focusScrollRect);
|
coordinatorLayout.offsetDescendantRectToMyCoords(child, focusScrollRect);
|
||||||
|
|
||||||
int height = coordinatorLayout.getHeight();
|
final int height = coordinatorLayout.getHeight();
|
||||||
|
|
||||||
if (focusScrollRect.top <= 0 && focusScrollRect.bottom >= height) {
|
if (focusScrollRect.top <= 0 && focusScrollRect.bottom >= height) {
|
||||||
// the child is too big to fit inside ourselves completely, ignore request
|
// the child is too big to fit inside ourselves completely, ignore request
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int dy;
|
final int dy;
|
||||||
|
|
||||||
if (focusScrollRect.bottom > height) {
|
if (focusScrollRect.bottom > height) {
|
||||||
dy = focusScrollRect.top;
|
dy = focusScrollRect.top;
|
||||||
@ -54,7 +53,7 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
int consumed = scroll(coordinatorLayout, child, dy, getMaxDragOffset(child), 0);
|
final int consumed = scroll(coordinatorLayout, child, dy, getMaxDragOffset(child), 0);
|
||||||
|
|
||||||
return consumed == dy;
|
return consumed == dy;
|
||||||
}
|
}
|
||||||
@ -69,6 +68,14 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
return false;
|
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;
|
allowScroll = true;
|
||||||
switch (ev.getActionMasked()) {
|
switch (ev.getActionMasked()) {
|
||||||
case MotionEvent.ACTION_DOWN:
|
case MotionEvent.ACTION_DOWN:
|
||||||
@ -106,14 +113,14 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private OverScroller getScrollerField() {
|
private OverScroller getScrollerField() {
|
||||||
try {
|
try {
|
||||||
Class<?> headerBehaviorType = this.getClass()
|
final Class<?> headerBehaviorType = this.getClass()
|
||||||
.getSuperclass().getSuperclass().getSuperclass();
|
.getSuperclass().getSuperclass().getSuperclass();
|
||||||
if (headerBehaviorType != null) {
|
if (headerBehaviorType != null) {
|
||||||
Field field = headerBehaviorType.getDeclaredField("scroller");
|
final Field field = headerBehaviorType.getDeclaredField("scroller");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
return ((OverScroller) field.get(this));
|
return ((OverScroller) field.get(this));
|
||||||
}
|
}
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
} catch (final NoSuchFieldException | IllegalAccessException e) {
|
||||||
// ?
|
// ?
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
@ -122,34 +129,35 @@ public final class FlingBehavior extends AppBarLayout.Behavior {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private Field getLastNestedScrollingChildRefField() {
|
private Field getLastNestedScrollingChildRefField() {
|
||||||
try {
|
try {
|
||||||
Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass();
|
final Class<?> headerBehaviorType = this.getClass().getSuperclass().getSuperclass();
|
||||||
if (headerBehaviorType != null) {
|
if (headerBehaviorType != null) {
|
||||||
Field field = headerBehaviorType.getDeclaredField("lastNestedScrollingChildRef");
|
final Field field
|
||||||
|
= headerBehaviorType.getDeclaredField("lastNestedScrollingChildRef");
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
} catch (NoSuchFieldException e) {
|
} catch (final NoSuchFieldException e) {
|
||||||
// ?
|
// ?
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void resetNestedScrollingChild() {
|
private void resetNestedScrollingChild() {
|
||||||
Field field = getLastNestedScrollingChildRefField();
|
final Field field = getLastNestedScrollingChildRefField();
|
||||||
if (field != null) {
|
if (field != null) {
|
||||||
try {
|
try {
|
||||||
Object value = field.get(this);
|
final Object value = field.get(this);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
field.set(this, null);
|
field.set(this, null);
|
||||||
}
|
}
|
||||||
} catch (IllegalAccessException e) {
|
} catch (final IllegalAccessException e) {
|
||||||
// ?
|
// ?
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void stopAppBarLayoutFling() {
|
private void stopAppBarLayoutFling() {
|
||||||
OverScroller scroller = getScrollerField();
|
final OverScroller scroller = getScrollerField();
|
||||||
if (scroller != null) {
|
if (scroller != null) {
|
||||||
scroller.forceFinished(true);
|
scroller.forceFinished(true);
|
||||||
}
|
}
|
||||||
|
@ -104,7 +104,7 @@ public class App extends Application {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected Downloader getDownloader() {
|
protected Downloader getDownloader() {
|
||||||
DownloaderImpl downloader = DownloaderImpl.init(null);
|
final DownloaderImpl downloader = DownloaderImpl.init(null);
|
||||||
setCookiesToDownloader(downloader);
|
setCookiesToDownloader(downloader);
|
||||||
return downloader;
|
return downloader;
|
||||||
}
|
}
|
||||||
@ -208,7 +208,7 @@ public class App extends Application {
|
|||||||
.setBuildConfigClass(BuildConfig.class)
|
.setBuildConfigClass(BuildConfig.class)
|
||||||
.build();
|
.build();
|
||||||
ACRA.init(this, acraConfig);
|
ACRA.init(this, acraConfig);
|
||||||
} catch (ACRAConfigurationException ace) {
|
} catch (final ACRAConfigurationException ace) {
|
||||||
ace.printStackTrace();
|
ace.printStackTrace();
|
||||||
ErrorActivity.reportError(this,
|
ErrorActivity.reportError(this,
|
||||||
ace,
|
ace,
|
||||||
@ -231,10 +231,10 @@ public class App extends Application {
|
|||||||
// Keep this below DEFAULT to avoid making noise on every notification update
|
// Keep this below DEFAULT to avoid making noise on every notification update
|
||||||
final int importance = NotificationManager.IMPORTANCE_LOW;
|
final int importance = NotificationManager.IMPORTANCE_LOW;
|
||||||
|
|
||||||
NotificationChannel mChannel = new NotificationChannel(id, name, importance);
|
final NotificationChannel mChannel = new NotificationChannel(id, name, importance);
|
||||||
mChannel.setDescription(description);
|
mChannel.setDescription(description);
|
||||||
|
|
||||||
NotificationManager mNotificationManager =
|
final NotificationManager mNotificationManager =
|
||||||
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
mNotificationManager.createNotificationChannel(mChannel);
|
mNotificationManager.createNotificationChannel(mChannel);
|
||||||
|
|
||||||
@ -255,11 +255,11 @@ public class App extends Application {
|
|||||||
final String appUpdateDescription
|
final String appUpdateDescription
|
||||||
= getString(R.string.app_update_notification_channel_description);
|
= getString(R.string.app_update_notification_channel_description);
|
||||||
|
|
||||||
NotificationChannel appUpdateChannel
|
final NotificationChannel appUpdateChannel
|
||||||
= new NotificationChannel(appUpdateId, appUpdateName, importance);
|
= new NotificationChannel(appUpdateId, appUpdateName, importance);
|
||||||
appUpdateChannel.setDescription(appUpdateDescription);
|
appUpdateChannel.setDescription(appUpdateDescription);
|
||||||
|
|
||||||
NotificationManager appUpdateNotificationManager
|
final NotificationManager appUpdateNotificationManager
|
||||||
= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
= (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
|
||||||
appUpdateNotificationManager.createNotificationChannel(appUpdateChannel);
|
appUpdateNotificationManager.createNotificationChannel(appUpdateChannel);
|
||||||
}
|
}
|
||||||
|
@ -62,7 +62,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
packageInfo = pm.getPackageInfo(packageName, flags);
|
packageInfo = pm.getPackageInfo(packageName, flags);
|
||||||
} catch (PackageManager.NameNotFoundException e) {
|
} catch (final PackageManager.NameNotFoundException e) {
|
||||||
ErrorActivity.reportError(APP, e, null, null,
|
ErrorActivity.reportError(APP, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
||||||
"Could not find package info", R.string.app_ui_crash));
|
"Could not find package info", R.string.app_ui_crash));
|
||||||
@ -77,7 +77,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
try {
|
try {
|
||||||
final CertificateFactory cf = CertificateFactory.getInstance("X509");
|
final CertificateFactory cf = CertificateFactory.getInstance("X509");
|
||||||
c = (X509Certificate) cf.generateCertificate(input);
|
c = (X509Certificate) cf.generateCertificate(input);
|
||||||
} catch (CertificateException e) {
|
} catch (final CertificateException e) {
|
||||||
ErrorActivity.reportError(APP, e, null, null,
|
ErrorActivity.reportError(APP, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.SOMETHING_ELSE, "none",
|
||||||
"Certificate error", R.string.app_ui_crash));
|
"Certificate error", R.string.app_ui_crash));
|
||||||
@ -86,7 +86,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
String hexString = null;
|
String hexString = null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
MessageDigest md = MessageDigest.getInstance("SHA1");
|
final MessageDigest md = MessageDigest.getInstance("SHA1");
|
||||||
final byte[] publicKey = md.digest(c.getEncoded());
|
final byte[] publicKey = md.digest(c.getEncoded());
|
||||||
hexString = byte2HexFormatted(publicKey);
|
hexString = byte2HexFormatted(publicKey);
|
||||||
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
|
} catch (NoSuchAlgorithmException | CertificateEncodingException e) {
|
||||||
@ -167,7 +167,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
|
|
||||||
compareAppVersionAndShowNotification(versionName, apkLocationUrl, versionCode);
|
compareAppVersionAndShowNotification(versionName, apkLocationUrl, versionCode);
|
||||||
|
|
||||||
} catch (JsonParserException e) {
|
} catch (final JsonParserException e) {
|
||||||
// connectivity problems, do not alarm user and fail silently
|
// connectivity problems, do not alarm user and fail silently
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.w(TAG, Log.getStackTraceString(e));
|
Log.w(TAG, Log.getStackTraceString(e));
|
||||||
@ -187,7 +187,7 @@ public class CheckForNewAppVersionTask extends AsyncTask<Void, Void, String> {
|
|||||||
private void compareAppVersionAndShowNotification(final String versionName,
|
private void compareAppVersionAndShowNotification(final String versionName,
|
||||||
final String apkLocationUrl,
|
final String apkLocationUrl,
|
||||||
final int versionCode) {
|
final int versionCode) {
|
||||||
int notificationId = 2000;
|
final int notificationId = 2000;
|
||||||
|
|
||||||
if (BuildConfig.VERSION_CODE < versionCode) {
|
if (BuildConfig.VERSION_CODE < versionCode) {
|
||||||
|
|
||||||
|
@ -94,18 +94,18 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
private static void enableModernTLS(final OkHttpClient.Builder builder) {
|
private static void enableModernTLS(final OkHttpClient.Builder builder) {
|
||||||
try {
|
try {
|
||||||
// get the default TrustManager
|
// get the default TrustManager
|
||||||
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
|
final TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
|
||||||
TrustManagerFactory.getDefaultAlgorithm());
|
TrustManagerFactory.getDefaultAlgorithm());
|
||||||
trustManagerFactory.init((KeyStore) null);
|
trustManagerFactory.init((KeyStore) null);
|
||||||
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
|
final TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
|
||||||
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
|
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
|
||||||
throw new IllegalStateException("Unexpected default trust managers:"
|
throw new IllegalStateException("Unexpected default trust managers:"
|
||||||
+ Arrays.toString(trustManagers));
|
+ Arrays.toString(trustManagers));
|
||||||
}
|
}
|
||||||
X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
|
final X509TrustManager trustManager = (X509TrustManager) trustManagers[0];
|
||||||
|
|
||||||
// insert our own TLSSocketFactory
|
// insert our own TLSSocketFactory
|
||||||
SSLSocketFactory sslSocketFactory = TLSSocketFactoryCompat.getInstance();
|
final SSLSocketFactory sslSocketFactory = TLSSocketFactoryCompat.getInstance();
|
||||||
|
|
||||||
builder.sslSocketFactory(sslSocketFactory, trustManager);
|
builder.sslSocketFactory(sslSocketFactory, trustManager);
|
||||||
|
|
||||||
@ -114,16 +114,16 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
// Necessary because some servers (e.g. Framatube.org)
|
// Necessary because some servers (e.g. Framatube.org)
|
||||||
// don't support the old cipher suites.
|
// don't support the old cipher suites.
|
||||||
// https://github.com/square/okhttp/issues/4053#issuecomment-402579554
|
// https://github.com/square/okhttp/issues/4053#issuecomment-402579554
|
||||||
List<CipherSuite> cipherSuites = new ArrayList<>();
|
final List<CipherSuite> cipherSuites = new ArrayList<>();
|
||||||
cipherSuites.addAll(ConnectionSpec.MODERN_TLS.cipherSuites());
|
cipherSuites.addAll(ConnectionSpec.MODERN_TLS.cipherSuites());
|
||||||
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
|
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA);
|
||||||
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
|
cipherSuites.add(CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA);
|
||||||
ConnectionSpec legacyTLS = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
final ConnectionSpec legacyTLS = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
|
||||||
.cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
|
.cipherSuites(cipherSuites.toArray(new CipherSuite[0]))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
builder.connectionSpecs(Arrays.asList(legacyTLS, ConnectionSpec.CLEARTEXT));
|
builder.connectionSpecs(Arrays.asList(legacyTLS, ConnectionSpec.CLEARTEXT));
|
||||||
} catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
} catch (final KeyManagementException | NoSuchAlgorithmException | KeyStoreException e) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -131,15 +131,15 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getCookies(final String url) {
|
public String getCookies(final String url) {
|
||||||
List<String> resultCookies = new ArrayList<>();
|
final List<String> resultCookies = new ArrayList<>();
|
||||||
if (url.contains(YOUTUBE_DOMAIN)) {
|
if (url.contains(YOUTUBE_DOMAIN)) {
|
||||||
String youtubeCookie = getCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY);
|
final String youtubeCookie = getCookie(YOUTUBE_RESTRICTED_MODE_COOKIE_KEY);
|
||||||
if (youtubeCookie != null) {
|
if (youtubeCookie != null) {
|
||||||
resultCookies.add(youtubeCookie);
|
resultCookies.add(youtubeCookie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Recaptcha cookie is always added TODO: not sure if this is necessary
|
// Recaptcha cookie is always added TODO: not sure if this is necessary
|
||||||
String recaptchaCookie = getCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY);
|
final String recaptchaCookie = getCookie(ReCaptchaActivity.RECAPTCHA_COOKIES_KEY);
|
||||||
if (recaptchaCookie != null) {
|
if (recaptchaCookie != null) {
|
||||||
resultCookies.add(recaptchaCookie);
|
resultCookies.add(recaptchaCookie);
|
||||||
}
|
}
|
||||||
@ -159,9 +159,9 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateYoutubeRestrictedModeCookies(final Context context) {
|
public void updateYoutubeRestrictedModeCookies(final Context context) {
|
||||||
String restrictedModeEnabledKey =
|
final String restrictedModeEnabledKey =
|
||||||
context.getString(R.string.youtube_restricted_mode_enabled);
|
context.getString(R.string.youtube_restricted_mode_enabled);
|
||||||
boolean restrictedModeEnabled = PreferenceManager.getDefaultSharedPreferences(context)
|
final boolean restrictedModeEnabled = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getBoolean(restrictedModeEnabledKey, false);
|
.getBoolean(restrictedModeEnabledKey, false);
|
||||||
updateYoutubeRestrictedModeCookies(restrictedModeEnabled);
|
updateYoutubeRestrictedModeCookies(restrictedModeEnabled);
|
||||||
}
|
}
|
||||||
@ -186,9 +186,9 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
try {
|
try {
|
||||||
final Response response = head(url);
|
final Response response = head(url);
|
||||||
return Long.parseLong(response.getHeader("Content-Length"));
|
return Long.parseLong(response.getHeader("Content-Length"));
|
||||||
} catch (NumberFormatException e) {
|
} catch (final NumberFormatException e) {
|
||||||
throw new IOException("Invalid content length", e);
|
throw new IOException("Invalid content length", e);
|
||||||
} catch (ReCaptchaException e) {
|
} catch (final ReCaptchaException e) {
|
||||||
throw new IOException(e);
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,7 +199,7 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
.method("GET", null).url(siteUrl)
|
.method("GET", null).url(siteUrl)
|
||||||
.addHeader("User-Agent", USER_AGENT);
|
.addHeader("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
String cookies = getCookies(siteUrl);
|
final String cookies = getCookies(siteUrl);
|
||||||
if (!cookies.isEmpty()) {
|
if (!cookies.isEmpty()) {
|
||||||
requestBuilder.addHeader("Cookie", cookies);
|
requestBuilder.addHeader("Cookie", cookies);
|
||||||
}
|
}
|
||||||
@ -218,7 +218,7 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return body.byteStream();
|
return body.byteStream();
|
||||||
} catch (ReCaptchaException e) {
|
} catch (final ReCaptchaException e) {
|
||||||
throw new IOException(e.getMessage(), e.getCause());
|
throw new IOException(e.getMessage(), e.getCause());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -240,18 +240,18 @@ public final class DownloaderImpl extends Downloader {
|
|||||||
.method(httpMethod, requestBody).url(url)
|
.method(httpMethod, requestBody).url(url)
|
||||||
.addHeader("User-Agent", USER_AGENT);
|
.addHeader("User-Agent", USER_AGENT);
|
||||||
|
|
||||||
String cookies = getCookies(url);
|
final String cookies = getCookies(url);
|
||||||
if (!cookies.isEmpty()) {
|
if (!cookies.isEmpty()) {
|
||||||
requestBuilder.addHeader("Cookie", cookies);
|
requestBuilder.addHeader("Cookie", cookies);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Map.Entry<String, List<String>> pair : headers.entrySet()) {
|
for (final Map.Entry<String, List<String>> pair : headers.entrySet()) {
|
||||||
final String headerName = pair.getKey();
|
final String headerName = pair.getKey();
|
||||||
final List<String> headerValueList = pair.getValue();
|
final List<String> headerValueList = pair.getValue();
|
||||||
|
|
||||||
if (headerValueList.size() > 1) {
|
if (headerValueList.size() > 1) {
|
||||||
requestBuilder.removeHeader(headerName);
|
requestBuilder.removeHeader(headerName);
|
||||||
for (String headerValue : headerValueList) {
|
for (final String headerValue : headerValueList) {
|
||||||
requestBuilder.addHeader(headerName, headerValue);
|
requestBuilder.addHeader(headerName, headerValue);
|
||||||
}
|
}
|
||||||
} else if (headerValueList.size() == 1) {
|
} else if (headerValueList.size() == 1) {
|
||||||
|
@ -27,7 +27,7 @@ import android.os.Bundle;
|
|||||||
public class ExitActivity extends Activity {
|
public class ExitActivity extends Activity {
|
||||||
|
|
||||||
public static void exitAndRemoveFromRecentApps(final Activity activity) {
|
public static void exitAndRemoveFromRecentApps(final Activity activity) {
|
||||||
Intent intent = new Intent(activity, ExitActivity.class);
|
final Intent intent = new Intent(activity, ExitActivity.class);
|
||||||
|
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK
|
||||||
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
|
||||||
|
@ -140,7 +140,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
setSupportActionBar(findViewById(R.id.toolbar));
|
setSupportActionBar(findViewById(R.id.toolbar));
|
||||||
try {
|
try {
|
||||||
setupDrawer();
|
setupDrawer();
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError(this, e);
|
ErrorActivity.reportUiError(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,8 +155,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
drawerItems = findViewById(R.id.navigation);
|
drawerItems = findViewById(R.id.navigation);
|
||||||
|
|
||||||
//Tabs
|
//Tabs
|
||||||
int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
final int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||||
StreamingService service = NewPipe.getService(currentServiceId);
|
final StreamingService service = NewPipe.getService(currentServiceId);
|
||||||
|
|
||||||
int kioskId = 0;
|
int kioskId = 0;
|
||||||
|
|
||||||
@ -228,7 +228,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
case R.id.menu_tabs_group:
|
case R.id.menu_tabs_group:
|
||||||
try {
|
try {
|
||||||
tabSelected(item);
|
tabSelected(item);
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError(this, e);
|
ErrorActivity.reportUiError(this, e);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -269,8 +269,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
NavigationHelper.openStatisticFragment(getSupportFragmentManager());
|
NavigationHelper.openStatisticFragment(getSupportFragmentManager());
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
final int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||||
StreamingService service = NewPipe.getService(currentServiceId);
|
final StreamingService service = NewPipe.getService(currentServiceId);
|
||||||
String serviceName = "";
|
String serviceName = "";
|
||||||
|
|
||||||
int kioskId = 0;
|
int kioskId = 0;
|
||||||
@ -299,8 +299,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupDrawerHeader() {
|
private void setupDrawerHeader() {
|
||||||
NavigationView navigationView = findViewById(R.id.navigation);
|
final NavigationView navigationView = findViewById(R.id.navigation);
|
||||||
View hView = navigationView.getHeaderView(0);
|
final View hView = navigationView.getHeaderView(0);
|
||||||
|
|
||||||
serviceArrow = hView.findViewById(R.id.drawer_arrow);
|
serviceArrow = hView.findViewById(R.id.drawer_arrow);
|
||||||
headerServiceIcon = hView.findViewById(R.id.drawer_header_service_icon);
|
headerServiceIcon = hView.findViewById(R.id.drawer_header_service_icon);
|
||||||
@ -335,7 +335,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
} else {
|
} else {
|
||||||
try {
|
try {
|
||||||
showTabs();
|
showTabs();
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError(this, e);
|
ErrorActivity.reportUiError(this, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -344,11 +344,11 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
private void showServices() {
|
private void showServices() {
|
||||||
serviceArrow.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
|
serviceArrow.setImageResource(R.drawable.ic_arrow_drop_up_white_24dp);
|
||||||
|
|
||||||
for (StreamingService s : NewPipe.getServices()) {
|
for (final StreamingService s : NewPipe.getServices()) {
|
||||||
final String title = s.getServiceInfo().getName()
|
final String title = s.getServiceInfo().getName()
|
||||||
+ (ServiceHelper.isBeta(s) ? " (beta)" : "");
|
+ (ServiceHelper.isBeta(s) ? " (beta)" : "");
|
||||||
|
|
||||||
MenuItem menuItem = drawerItems.getMenu()
|
final MenuItem menuItem = drawerItems.getMenu()
|
||||||
.add(R.id.menu_services_group, s.getServiceId(), ORDER, title)
|
.add(R.id.menu_services_group, s.getServiceId(), ORDER, title)
|
||||||
.setIcon(ServiceHelper.getIcon(s.getServiceId()));
|
.setIcon(ServiceHelper.getIcon(s.getServiceId()));
|
||||||
|
|
||||||
@ -362,20 +362,20 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void enhancePeertubeMenu(final StreamingService s, final MenuItem menuItem) {
|
private void enhancePeertubeMenu(final StreamingService s, final MenuItem menuItem) {
|
||||||
PeertubeInstance currentInstace = PeertubeHelper.getCurrentInstance();
|
final PeertubeInstance currentInstace = PeertubeHelper.getCurrentInstance();
|
||||||
menuItem.setTitle(currentInstace.getName() + (ServiceHelper.isBeta(s) ? " (beta)" : ""));
|
menuItem.setTitle(currentInstace.getName() + (ServiceHelper.isBeta(s) ? " (beta)" : ""));
|
||||||
Spinner spinner = (Spinner) LayoutInflater.from(this)
|
final Spinner spinner = (Spinner) LayoutInflater.from(this)
|
||||||
.inflate(R.layout.instance_spinner_layout, null);
|
.inflate(R.layout.instance_spinner_layout, null);
|
||||||
List<PeertubeInstance> instances = PeertubeHelper.getInstanceList(this);
|
final List<PeertubeInstance> instances = PeertubeHelper.getInstanceList(this);
|
||||||
List<String> items = new ArrayList<>();
|
final List<String> items = new ArrayList<>();
|
||||||
int defaultSelect = 0;
|
int defaultSelect = 0;
|
||||||
for (PeertubeInstance instance : instances) {
|
for (final PeertubeInstance instance : instances) {
|
||||||
items.add(instance.getName());
|
items.add(instance.getName());
|
||||||
if (instance.getUrl().equals(currentInstace.getUrl())) {
|
if (instance.getUrl().equals(currentInstace.getUrl())) {
|
||||||
defaultSelect = items.size() - 1;
|
defaultSelect = items.size() - 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
|
final ArrayAdapter<String> adapter = new ArrayAdapter<>(this,
|
||||||
R.layout.instance_spinner_item, items);
|
R.layout.instance_spinner_item, items);
|
||||||
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
spinner.setAdapter(adapter);
|
spinner.setAdapter(adapter);
|
||||||
@ -384,7 +384,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public void onItemSelected(final AdapterView<?> parent, final View view,
|
public void onItemSelected(final AdapterView<?> parent, final View view,
|
||||||
final int position, final long id) {
|
final int position, final long id) {
|
||||||
PeertubeInstance newInstance = instances.get(position);
|
final PeertubeInstance newInstance = instances.get(position);
|
||||||
if (newInstance.getUrl().equals(PeertubeHelper.getCurrentInstance().getUrl())) {
|
if (newInstance.getUrl().equals(PeertubeHelper.getCurrentInstance().getUrl())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -410,8 +410,8 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
serviceArrow.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp);
|
serviceArrow.setImageResource(R.drawable.ic_arrow_drop_down_white_24dp);
|
||||||
|
|
||||||
//Tabs
|
//Tabs
|
||||||
int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
final int currentServiceId = ServiceHelper.getSelectedServiceId(this);
|
||||||
StreamingService service = NewPipe.getService(currentServiceId);
|
final StreamingService service = NewPipe.getService(currentServiceId);
|
||||||
|
|
||||||
int kioskId = 0;
|
int kioskId = 0;
|
||||||
|
|
||||||
@ -476,11 +476,12 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
headerServiceView.post(() -> headerServiceView.setSelected(true));
|
headerServiceView.post(() -> headerServiceView.setSelected(true));
|
||||||
toggleServiceButton.setContentDescription(
|
toggleServiceButton.setContentDescription(
|
||||||
getString(R.string.drawer_header_description) + selectedServiceName);
|
getString(R.string.drawer_header_description) + selectedServiceName);
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError(this, e);
|
ErrorActivity.reportUiError(this, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
|
final SharedPreferences sharedPreferences
|
||||||
|
= PreferenceManager.getDefaultSharedPreferences(this);
|
||||||
if (sharedPreferences.getBoolean(Constants.KEY_THEME_CHANGE, false)) {
|
if (sharedPreferences.getBoolean(Constants.KEY_THEME_CHANGE, false)) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Theme has changed, recreating activity...");
|
Log.d(TAG, "Theme has changed, recreating activity...");
|
||||||
@ -513,7 +514,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (intent != null) {
|
if (intent != null) {
|
||||||
// Return if launched from a launcher (e.g. Nova Launcher, Pixel Launcher ...)
|
// Return if launched from a launcher (e.g. Nova Launcher, Pixel Launcher ...)
|
||||||
// to not destroy the already created backstack
|
// to not destroy the already created backstack
|
||||||
String action = intent.getAction();
|
final String action = intent.getAction();
|
||||||
if ((action != null && action.equals(Intent.ACTION_MAIN))
|
if ((action != null && action.equals(Intent.ACTION_MAIN))
|
||||||
&& intent.hasCategory(Intent.CATEGORY_LAUNCHER)) {
|
&& intent.hasCategory(Intent.CATEGORY_LAUNCHER)) {
|
||||||
return;
|
return;
|
||||||
@ -546,7 +547,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (DeviceUtils.isTv(this)) {
|
if (DeviceUtils.isTv(this)) {
|
||||||
View drawerPanel = findViewById(R.id.navigation);
|
final View drawerPanel = findViewById(R.id.navigation);
|
||||||
if (drawer.isDrawerOpen(drawerPanel)) {
|
if (drawer.isDrawerOpen(drawerPanel)) {
|
||||||
drawer.closeDrawers();
|
drawer.closeDrawers();
|
||||||
return;
|
return;
|
||||||
@ -594,7 +595,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
public void onRequestPermissionsResult(final int requestCode,
|
public void onRequestPermissionsResult(final int requestCode,
|
||||||
@NonNull final String[] permissions,
|
@NonNull final String[] permissions,
|
||||||
@NonNull final int[] grantResults) {
|
@NonNull final int[] grantResults) {
|
||||||
for (int i : grantResults) {
|
for (final int i : grantResults) {
|
||||||
if (i == PackageManager.PERMISSION_DENIED) {
|
if (i == PackageManager.PERMISSION_DENIED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -604,7 +605,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
NavigationHelper.openDownloads(this);
|
NavigationHelper.openDownloads(this);
|
||||||
break;
|
break;
|
||||||
case PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE:
|
case PermissionHelper.DOWNLOAD_DIALOG_REQUEST_CODE:
|
||||||
Fragment fragment = getSupportFragmentManager()
|
final Fragment fragment = getSupportFragmentManager()
|
||||||
.findFragmentById(R.id.fragment_player_holder);
|
.findFragmentById(R.id.fragment_player_holder);
|
||||||
if (fragment instanceof VideoDetailFragment) {
|
if (fragment instanceof VideoDetailFragment) {
|
||||||
((VideoDetailFragment) fragment).openDownloadDialog();
|
((VideoDetailFragment) fragment).openDownloadDialog();
|
||||||
@ -656,13 +657,14 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
super.onCreateOptionsMenu(menu);
|
super.onCreateOptionsMenu(menu);
|
||||||
|
|
||||||
Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
|
final Fragment fragment
|
||||||
|
= getSupportFragmentManager().findFragmentById(R.id.fragment_holder);
|
||||||
if (!(fragment instanceof SearchFragment)) {
|
if (!(fragment instanceof SearchFragment)) {
|
||||||
findViewById(R.id.toolbar).findViewById(R.id.toolbar_search_container)
|
findViewById(R.id.toolbar).findViewById(R.id.toolbar_search_container)
|
||||||
.setVisibility(View.GONE);
|
.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
}
|
}
|
||||||
@ -677,7 +679,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "onOptionsItemSelected() called with: item = [" + item + "]");
|
Log.d(TAG, "onOptionsItemSelected() called with: item = [" + item + "]");
|
||||||
}
|
}
|
||||||
int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
@ -745,13 +747,13 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (intent.hasExtra(Constants.KEY_LINK_TYPE)) {
|
if (intent.hasExtra(Constants.KEY_LINK_TYPE)) {
|
||||||
String url = intent.getStringExtra(Constants.KEY_URL);
|
final String url = intent.getStringExtra(Constants.KEY_URL);
|
||||||
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||||
String title = intent.getStringExtra(Constants.KEY_TITLE);
|
final String title = intent.getStringExtra(Constants.KEY_TITLE);
|
||||||
switch (((StreamingService.LinkType) intent
|
switch (((StreamingService.LinkType) intent
|
||||||
.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
|
.getSerializableExtra(Constants.KEY_LINK_TYPE))) {
|
||||||
case STREAM:
|
case STREAM:
|
||||||
boolean autoPlay = intent
|
final boolean autoPlay = intent
|
||||||
.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
|
.getBooleanExtra(VideoDetailFragment.AUTO_PLAY, false);
|
||||||
final String intentCacheKey = intent
|
final String intentCacheKey = intent
|
||||||
.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY);
|
.getStringExtra(VideoPlayer.PLAY_QUEUE_KEY);
|
||||||
@ -780,7 +782,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
if (searchString == null) {
|
if (searchString == null) {
|
||||||
searchString = "";
|
searchString = "";
|
||||||
}
|
}
|
||||||
int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
final int serviceId = intent.getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||||
NavigationHelper.openSearchFragment(
|
NavigationHelper.openSearchFragment(
|
||||||
getSupportFragmentManager(),
|
getSupportFragmentManager(),
|
||||||
serviceId,
|
serviceId,
|
||||||
@ -789,7 +791,7 @@ public class MainActivity extends AppCompatActivity {
|
|||||||
} else {
|
} else {
|
||||||
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
|
NavigationHelper.gotoMainFragment(getSupportFragmentManager());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError(this, e);
|
ErrorActivity.reportUiError(this, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +46,7 @@ public final class NewPipeDatabase {
|
|||||||
if (databaseInstance == null) {
|
if (databaseInstance == null) {
|
||||||
throw new IllegalStateException("database is not initialized");
|
throw new IllegalStateException("database is not initialized");
|
||||||
}
|
}
|
||||||
Cursor c = databaseInstance.query("pragma wal_checkpoint(full)", null);
|
final Cursor c = databaseInstance.query("pragma wal_checkpoint(full)", null);
|
||||||
if (c.moveToFirst() && c.getInt(0) == 1) {
|
if (c.moveToFirst() && c.getInt(0) == 1) {
|
||||||
throw new RuntimeException("Checkpoint was blocked from completing");
|
throw new RuntimeException("Checkpoint was blocked from completing");
|
||||||
}
|
}
|
||||||
|
@ -31,7 +31,7 @@ public class PanicResponderActivity extends Activity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
|
if (intent != null && PANIC_TRIGGER_ACTION.equals(intent.getAction())) {
|
||||||
// TODO: Explicitly clear the search results
|
// TODO: Explicitly clear the search results
|
||||||
// once they are restored when the app restarts
|
// once they are restored when the app restarts
|
||||||
|
@ -61,7 +61,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
ThemeHelper.setTheme(this);
|
ThemeHelper.setTheme(this);
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_recaptcha);
|
setContentView(R.layout.activity_recaptcha);
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
String url = getIntent().getStringExtra(RECAPTCHA_URL_EXTRA);
|
String url = getIntent().getStringExtra(RECAPTCHA_URL_EXTRA);
|
||||||
@ -76,7 +76,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
webView = findViewById(R.id.reCaptchaWebView);
|
webView = findViewById(R.id.reCaptchaWebView);
|
||||||
|
|
||||||
// enable Javascript
|
// enable Javascript
|
||||||
WebSettings webSettings = webView.getSettings();
|
final WebSettings webSettings = webView.getSettings();
|
||||||
webSettings.setJavaScriptEnabled(true);
|
webSettings.setJavaScriptEnabled(true);
|
||||||
|
|
||||||
webView.setWebViewClient(new WebViewClient() {
|
webView.setWebViewClient(new WebViewClient() {
|
||||||
@ -84,7 +84,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean shouldOverrideUrlLoading(final WebView view,
|
public boolean shouldOverrideUrlLoading(final WebView view,
|
||||||
final WebResourceRequest request) {
|
final WebResourceRequest request) {
|
||||||
String url = request.getUrl().toString();
|
final String url = request.getUrl().toString();
|
||||||
if (MainActivity.DEBUG) {
|
if (MainActivity.DEBUG) {
|
||||||
Log.d(TAG, "shouldOverrideUrlLoading: request.url=" + url);
|
Log.d(TAG, "shouldOverrideUrlLoading: request.url=" + url);
|
||||||
}
|
}
|
||||||
@ -113,7 +113,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
// cleaning cache, history and cookies from webView
|
// cleaning cache, history and cookies from webView
|
||||||
webView.clearCache(true);
|
webView.clearCache(true);
|
||||||
webView.clearHistory();
|
webView.clearHistory();
|
||||||
android.webkit.CookieManager cookieManager = CookieManager.getInstance();
|
final android.webkit.CookieManager cookieManager = CookieManager.getInstance();
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
cookieManager.removeAllCookies(aBoolean -> {
|
cookieManager.removeAllCookies(aBoolean -> {
|
||||||
});
|
});
|
||||||
@ -128,7 +128,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||||
getMenuInflater().inflate(R.menu.menu_recaptcha, menu);
|
getMenuInflater().inflate(R.menu.menu_recaptcha, menu);
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(false);
|
actionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
actionBar.setTitle(R.string.title_activity_recaptcha);
|
actionBar.setTitle(R.string.title_activity_recaptcha);
|
||||||
@ -145,7 +145,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case R.id.menu_item_done:
|
case R.id.menu_item_done:
|
||||||
saveCookiesAndFinish();
|
saveCookiesAndFinish();
|
||||||
@ -173,7 +173,7 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
setResult(RESULT_OK);
|
setResult(RESULT_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent intent = new Intent(this, org.schabi.newpipe.MainActivity.class);
|
final Intent intent = new Intent(this, org.schabi.newpipe.MainActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
NavUtils.navigateUpTo(this, intent);
|
NavUtils.navigateUpTo(this, intent);
|
||||||
}
|
}
|
||||||
@ -188,13 +188,13 @@ public class ReCaptchaActivity extends AppCompatActivity {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String cookies = CookieManager.getInstance().getCookie(url);
|
final String cookies = CookieManager.getInstance().getCookie(url);
|
||||||
handleCookies(cookies);
|
handleCookies(cookies);
|
||||||
|
|
||||||
// sometimes cookies are inside the url
|
// sometimes cookies are inside the url
|
||||||
int abuseStart = url.indexOf("google_abuse=");
|
final int abuseStart = url.indexOf("google_abuse=");
|
||||||
if (abuseStart != -1) {
|
if (abuseStart != -1) {
|
||||||
int abuseEnd = url.indexOf("+path");
|
final int abuseEnd = url.indexOf("+path");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
String abuseCookie = url.substring(abuseStart + 13, abuseEnd);
|
String abuseCookie = url.substring(abuseStart + 13, abuseEnd);
|
||||||
|
@ -310,7 +310,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int id = 12345;
|
int id = 12345;
|
||||||
for (AdapterChoiceItem item : choices) {
|
for (final AdapterChoiceItem item : choices) {
|
||||||
final RadioButton radioButton
|
final RadioButton radioButton
|
||||||
= (RadioButton) inflater.inflate(R.layout.list_radio_icon_item, null);
|
= (RadioButton) inflater.inflate(R.layout.list_radio_icon_item, null);
|
||||||
radioButton.setText(item.description);
|
radioButton.setText(item.description);
|
||||||
@ -330,7 +330,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
getString(R.string.preferred_open_action_last_selected_key), null);
|
getString(R.string.preferred_open_action_last_selected_key), null);
|
||||||
if (!TextUtils.isEmpty(lastSelectedPlayer)) {
|
if (!TextUtils.isEmpty(lastSelectedPlayer)) {
|
||||||
for (int i = 0; i < choices.size(); i++) {
|
for (int i = 0; i < choices.size(); i++) {
|
||||||
AdapterChoiceItem c = choices.get(i);
|
final AdapterChoiceItem c = choices.get(i);
|
||||||
if (lastSelectedPlayer.equals(c.key)) {
|
if (lastSelectedPlayer.equals(c.key)) {
|
||||||
selectedRadioPosition = i;
|
selectedRadioPosition = i;
|
||||||
break;
|
break;
|
||||||
@ -362,9 +362,9 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
final SharedPreferences preferences = PreferenceManager
|
final SharedPreferences preferences = PreferenceManager
|
||||||
.getDefaultSharedPreferences(this);
|
.getDefaultSharedPreferences(this);
|
||||||
boolean isExtVideoEnabled = preferences.getBoolean(
|
final boolean isExtVideoEnabled = preferences.getBoolean(
|
||||||
getString(R.string.use_external_video_player_key), false);
|
getString(R.string.use_external_video_player_key), false);
|
||||||
boolean isExtAudioEnabled = preferences.getBoolean(
|
final boolean isExtAudioEnabled = preferences.getBoolean(
|
||||||
getString(R.string.use_external_audio_player_key), false);
|
getString(R.string.use_external_audio_player_key), false);
|
||||||
|
|
||||||
returnList.add(new AdapterChoiceItem(getString(R.string.show_info_key),
|
returnList.add(new AdapterChoiceItem(getString(R.string.show_info_key),
|
||||||
@ -410,9 +410,9 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void handleText() {
|
private void handleText() {
|
||||||
String searchString = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
final String searchString = getIntent().getStringExtra(Intent.EXTRA_TEXT);
|
||||||
int serviceId = getIntent().getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
final int serviceId = getIntent().getIntExtra(Constants.KEY_SERVICE_ID, 0);
|
||||||
Intent intent = new Intent(getThemeWrapperContext(), MainActivity.class);
|
final Intent intent = new Intent(getThemeWrapperContext(), MainActivity.class);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
NavigationHelper.openSearch(getThemeWrapperContext(), serviceId, searchString);
|
NavigationHelper.openSearch(getThemeWrapperContext(), serviceId, searchString);
|
||||||
@ -479,14 +479,14 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe((@NonNull StreamInfo result) -> {
|
.subscribe((@NonNull StreamInfo result) -> {
|
||||||
List<VideoStream> sortedVideoStreams = ListHelper
|
final List<VideoStream> sortedVideoStreams = ListHelper
|
||||||
.getSortedStreamVideosList(this, result.getVideoStreams(),
|
.getSortedStreamVideosList(this, result.getVideoStreams(),
|
||||||
result.getVideoOnlyStreams(), false);
|
result.getVideoOnlyStreams(), false);
|
||||||
int selectedVideoStreamIndex = ListHelper
|
final int selectedVideoStreamIndex = ListHelper
|
||||||
.getDefaultResolutionIndex(this, sortedVideoStreams);
|
.getDefaultResolutionIndex(this, sortedVideoStreams);
|
||||||
|
|
||||||
FragmentManager fm = getSupportFragmentManager();
|
final FragmentManager fm = getSupportFragmentManager();
|
||||||
DownloadDialog downloadDialog = DownloadDialog.newInstance(result);
|
final DownloadDialog downloadDialog = DownloadDialog.newInstance(result);
|
||||||
downloadDialog.setVideoStreams(sortedVideoStreams);
|
downloadDialog.setVideoStreams(sortedVideoStreams);
|
||||||
downloadDialog.setAudioStreams(result.getAudioStreams());
|
downloadDialog.setAudioStreams(result.getAudioStreams());
|
||||||
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
downloadDialog.setSelectedVideoStream(selectedVideoStreamIndex);
|
||||||
@ -504,7 +504,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
public void onRequestPermissionsResult(final int requestCode,
|
public void onRequestPermissionsResult(final int requestCode,
|
||||||
@NonNull final String[] permissions,
|
@NonNull final String[] permissions,
|
||||||
@NonNull final int[] grantResults) {
|
@NonNull final int[] grantResults) {
|
||||||
for (int i : grantResults) {
|
for (final int i : grantResults) {
|
||||||
if (i == PackageManager.PERMISSION_DENIED) {
|
if (i == PackageManager.PERMISSION_DENIED) {
|
||||||
finish();
|
finish();
|
||||||
return;
|
return;
|
||||||
@ -634,7 +634,7 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
if (!(serializable instanceof Choice)) {
|
if (!(serializable instanceof Choice)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Choice playerChoice = (Choice) serializable;
|
final Choice playerChoice = (Choice) serializable;
|
||||||
handleChoice(playerChoice);
|
handleChoice(playerChoice);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,13 +682,13 @@ public class RouterActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
final SharedPreferences preferences = PreferenceManager
|
final SharedPreferences preferences = PreferenceManager
|
||||||
.getDefaultSharedPreferences(this);
|
.getDefaultSharedPreferences(this);
|
||||||
boolean isExtVideoEnabled = preferences.getBoolean(
|
final boolean isExtVideoEnabled = preferences.getBoolean(
|
||||||
getString(R.string.use_external_video_player_key), false);
|
getString(R.string.use_external_video_player_key), false);
|
||||||
boolean isExtAudioEnabled = preferences.getBoolean(
|
final boolean isExtAudioEnabled = preferences.getBoolean(
|
||||||
getString(R.string.use_external_audio_player_key), false);
|
getString(R.string.use_external_audio_player_key), false);
|
||||||
|
|
||||||
PlayQueue playQueue;
|
PlayQueue playQueue;
|
||||||
String playerChoice = choice.playerChoice;
|
final String playerChoice = choice.playerChoice;
|
||||||
|
|
||||||
if (info instanceof StreamInfo) {
|
if (info instanceof StreamInfo) {
|
||||||
if (playerChoice.equals(backgroundPlayerKey) && isExtAudioEnabled) {
|
if (playerChoice.equals(backgroundPlayerKey) && isExtAudioEnabled) {
|
||||||
|
@ -88,7 +88,7 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
setContentView(R.layout.activity_about);
|
setContentView(R.layout.activity_about);
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
|
||||||
// Create the adapter that will return a fragment for each of the three
|
// Create the adapter that will return a fragment for each of the three
|
||||||
@ -99,13 +99,13 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
mViewPager = findViewById(R.id.container);
|
mViewPager = findViewById(R.id.container);
|
||||||
mViewPager.setAdapter(mSectionsPagerAdapter);
|
mViewPager.setAdapter(mSectionsPagerAdapter);
|
||||||
|
|
||||||
TabLayout tabLayout = findViewById(R.id.tabs);
|
final TabLayout tabLayout = findViewById(R.id.tabs);
|
||||||
tabLayout.setupWithViewPager(mViewPager);
|
tabLayout.setupWithViewPager(mViewPager);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
|
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
@ -134,25 +134,25 @@ public class AboutActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
|
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
|
||||||
final Bundle savedInstanceState) {
|
final Bundle savedInstanceState) {
|
||||||
View rootView = inflater.inflate(R.layout.fragment_about, container, false);
|
final View rootView = inflater.inflate(R.layout.fragment_about, container, false);
|
||||||
Context context = this.getContext();
|
final Context context = this.getContext();
|
||||||
|
|
||||||
TextView version = rootView.findViewById(R.id.app_version);
|
final TextView version = rootView.findViewById(R.id.app_version);
|
||||||
version.setText(BuildConfig.VERSION_NAME);
|
version.setText(BuildConfig.VERSION_NAME);
|
||||||
|
|
||||||
View githubLink = rootView.findViewById(R.id.github_link);
|
final View githubLink = rootView.findViewById(R.id.github_link);
|
||||||
githubLink.setOnClickListener(nv ->
|
githubLink.setOnClickListener(nv ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.github_url)));
|
openUrlInBrowser(context, context.getString(R.string.github_url)));
|
||||||
|
|
||||||
View donationLink = rootView.findViewById(R.id.donation_link);
|
final View donationLink = rootView.findViewById(R.id.donation_link);
|
||||||
donationLink.setOnClickListener(v ->
|
donationLink.setOnClickListener(v ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.donation_url)));
|
openUrlInBrowser(context, context.getString(R.string.donation_url)));
|
||||||
|
|
||||||
View websiteLink = rootView.findViewById(R.id.website_link);
|
final View websiteLink = rootView.findViewById(R.id.website_link);
|
||||||
websiteLink.setOnClickListener(nv ->
|
websiteLink.setOnClickListener(nv ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.website_url)));
|
openUrlInBrowser(context, context.getString(R.string.website_url)));
|
||||||
|
|
||||||
View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link);
|
final View privacyPolicyLink = rootView.findViewById(R.id.privacy_policy_link);
|
||||||
privacyPolicyLink.setOnClickListener(v ->
|
privacyPolicyLink.setOnClickListener(v ->
|
||||||
openUrlInBrowser(context, context.getString(R.string.privacy_policy_url)));
|
openUrlInBrowser(context, context.getString(R.string.privacy_policy_url)));
|
||||||
|
|
||||||
|
@ -4,10 +4,12 @@ import android.net.Uri;
|
|||||||
import android.os.Parcel;
|
import android.os.Parcel;
|
||||||
import android.os.Parcelable;
|
import android.os.Parcelable;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class for storing information about a software license.
|
* 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>() {
|
public static final Creator<License> CREATOR = new Creator<License>() {
|
||||||
@Override
|
@Override
|
||||||
public License createFromParcel(final Parcel source) {
|
public License createFromParcel(final Parcel source) {
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
package org.schabi.newpipe.about;
|
package org.schabi.newpipe.about;
|
||||||
|
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.content.Context;
|
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.view.ContextMenu;
|
import android.view.ContextMenu;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
@ -11,12 +10,14 @@ import android.view.View;
|
|||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.util.ShareUtils;
|
import org.schabi.newpipe.util.ShareUtils;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -26,13 +27,15 @@ public class LicenseFragment extends Fragment {
|
|||||||
private static final String ARG_COMPONENTS = "components";
|
private static final String ARG_COMPONENTS = "components";
|
||||||
private SoftwareComponent[] softwareComponents;
|
private SoftwareComponent[] softwareComponents;
|
||||||
private SoftwareComponent componentForContextMenu;
|
private SoftwareComponent componentForContextMenu;
|
||||||
|
private License activeLicense;
|
||||||
|
private static final String LICENSE_KEY = "ACTIVE_LICENSE";
|
||||||
|
|
||||||
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
|
public static LicenseFragment newInstance(final SoftwareComponent[] softwareComponents) {
|
||||||
if (softwareComponents == null) {
|
if (softwareComponents == null) {
|
||||||
throw new NullPointerException("softwareComponents is null");
|
throw new NullPointerException("softwareComponents is null");
|
||||||
}
|
}
|
||||||
LicenseFragment fragment = new LicenseFragment();
|
final LicenseFragment fragment = new LicenseFragment();
|
||||||
Bundle bundle = new Bundle();
|
final Bundle bundle = new Bundle();
|
||||||
bundle.putParcelableArray(ARG_COMPONENTS, softwareComponents);
|
bundle.putParcelableArray(ARG_COMPONENTS, softwareComponents);
|
||||||
fragment.setArguments(bundle);
|
fragment.setArguments(bundle);
|
||||||
return fragment;
|
return fragment;
|
||||||
@ -44,8 +47,8 @@ public class LicenseFragment extends Fragment {
|
|||||||
* @param context the context to use
|
* @param context the context to use
|
||||||
* @param license the license to show
|
* @param license the license to show
|
||||||
*/
|
*/
|
||||||
private static void showLicense(final Context context, final License license) {
|
private static void showLicense(final Activity context, final License license) {
|
||||||
new LicenseFragmentHelper((Activity) context).execute(license);
|
new LicenseFragmentHelper(context).execute(license);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,6 +57,12 @@ public class LicenseFragment extends Fragment {
|
|||||||
softwareComponents = (SoftwareComponent[]) getArguments()
|
softwareComponents = (SoftwareComponent[]) getArguments()
|
||||||
.getParcelableArray(ARG_COMPONENTS);
|
.getParcelableArray(ARG_COMPONENTS);
|
||||||
|
|
||||||
|
if (savedInstanceState != null) {
|
||||||
|
final Serializable license = savedInstanceState.getSerializable(LICENSE_KEY);
|
||||||
|
if (license != null) {
|
||||||
|
activeLicense = (License) license;
|
||||||
|
}
|
||||||
|
}
|
||||||
// Sort components by name
|
// Sort components by name
|
||||||
Arrays.sort(softwareComponents, (o1, o2) -> o1.getName().compareTo(o2.getName()));
|
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 ViewGroup softwareComponentsView = rootView.findViewById(R.id.software_components);
|
||||||
|
|
||||||
final View licenseLink = rootView.findViewById(R.id.app_read_license);
|
final View licenseLink = rootView.findViewById(R.id.app_read_license);
|
||||||
licenseLink.setOnClickListener(v ->
|
licenseLink.setOnClickListener(v -> {
|
||||||
showLicense(getActivity(), StandardLicenses.GPL3));
|
activeLicense = StandardLicenses.GPL3;
|
||||||
|
showLicense(getActivity(), StandardLicenses.GPL3);
|
||||||
|
});
|
||||||
|
|
||||||
for (final SoftwareComponent component : softwareComponents) {
|
for (final SoftwareComponent component : softwareComponents) {
|
||||||
final View componentView = inflater
|
final View componentView = inflater
|
||||||
@ -81,11 +92,16 @@ public class LicenseFragment extends Fragment {
|
|||||||
component.getLicense().getAbbreviation()));
|
component.getLicense().getAbbreviation()));
|
||||||
|
|
||||||
componentView.setTag(component);
|
componentView.setTag(component);
|
||||||
componentView.setOnClickListener(v ->
|
componentView.setOnClickListener(v -> {
|
||||||
showLicense(getActivity(), component.getLicense()));
|
activeLicense = component.getLicense();
|
||||||
|
showLicense(getActivity(), component.getLicense());
|
||||||
|
});
|
||||||
softwareComponentsView.addView(componentView);
|
softwareComponentsView.addView(componentView);
|
||||||
registerForContextMenu(componentView);
|
registerForContextMenu(componentView);
|
||||||
}
|
}
|
||||||
|
if (activeLicense != null) {
|
||||||
|
showLicense(getActivity(), activeLicense);
|
||||||
|
}
|
||||||
return rootView;
|
return rootView;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +117,7 @@ public class LicenseFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
// item.getMenuInfo() is null so we use the tag of the view
|
||||||
final SoftwareComponent component = componentForContextMenu;
|
final SoftwareComponent component = componentForContextMenu;
|
||||||
if (component == null) {
|
if (component == null) {
|
||||||
@ -116,4 +132,12 @@ public class LicenseFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSaveInstanceState(@NonNull final Bundle savedInstanceState) {
|
||||||
|
super.onSaveInstanceState(savedInstanceState);
|
||||||
|
if (activeLicense != null) {
|
||||||
|
savedInstanceState.putSerializable(LICENSE_KEY, activeLicense);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ public class LicenseFragmentHelper extends AsyncTask<Object, Void, Integer> {
|
|||||||
// split the HTML file and insert the stylesheet into the HEAD of the file
|
// split the HTML file and insert the stylesheet into the HEAD of the file
|
||||||
webViewData = licenseContent.toString().replace("</head>",
|
webViewData = licenseContent.toString().replace("</head>",
|
||||||
"<style>" + getLicenseStylesheet(context) + "</style></head>");
|
"<style>" + getLicenseStylesheet(context) + "</style></head>");
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
throw new IllegalArgumentException(
|
throw new IllegalArgumentException(
|
||||||
"Could not get license file: " + license.getFilename(), e);
|
"Could not get license file: " + license.getFilename(), e);
|
||||||
}
|
}
|
||||||
|
@ -49,7 +49,7 @@ public final class Converters {
|
|||||||
|
|
||||||
@TypeConverter
|
@TypeConverter
|
||||||
public static FeedGroupIcon feedGroupIconOf(final Integer id) {
|
public static FeedGroupIcon feedGroupIconOf(final Integer id) {
|
||||||
for (FeedGroupIcon icon : FeedGroupIcon.values()) {
|
for (final FeedGroupIcon icon : FeedGroupIcon.values()) {
|
||||||
if (icon.getId() == id) {
|
if (icon.getId() == id) {
|
||||||
return icon;
|
return icon;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ import androidx.annotation.NonNull;
|
|||||||
import androidx.room.migration.Migration;
|
import androidx.room.migration.Migration;
|
||||||
import androidx.sqlite.db.SupportSQLiteDatabase;
|
import androidx.sqlite.db.SupportSQLiteDatabase;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.MainActivity;
|
||||||
|
|
||||||
public final class Migrations {
|
public final class Migrations {
|
||||||
public static final int DB_VER_1 = 1;
|
public static final int DB_VER_1 = 1;
|
||||||
@ -14,7 +14,7 @@ public final class Migrations {
|
|||||||
public static final int DB_VER_3 = 3;
|
public static final int DB_VER_3 = 3;
|
||||||
|
|
||||||
private static final String TAG = Migrations.class.getName();
|
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) {
|
public static final Migration MIGRATION_1_2 = new Migration(DB_VER_1, DB_VER_2) {
|
||||||
@Override
|
@Override
|
||||||
|
@ -50,7 +50,7 @@ public class SubscriptionEntity {
|
|||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
public static SubscriptionEntity from(@NonNull final ChannelInfo info) {
|
public static SubscriptionEntity from(@NonNull final ChannelInfo info) {
|
||||||
SubscriptionEntity result = new SubscriptionEntity();
|
final SubscriptionEntity result = new SubscriptionEntity();
|
||||||
result.setServiceId(info.getServiceId());
|
result.setServiceId(info.getServiceId());
|
||||||
result.setUrl(info.getUrl());
|
result.setUrl(info.getUrl());
|
||||||
result.setData(info.getName(), info.getAvatarUrl(), info.getDescription(),
|
result.setData(info.getName(), info.getAvatarUrl(), info.getDescription(),
|
||||||
@ -124,7 +124,7 @@ public class SubscriptionEntity {
|
|||||||
|
|
||||||
@Ignore
|
@Ignore
|
||||||
public ChannelInfoItem toChannelInfoItem() {
|
public ChannelInfoItem toChannelInfoItem() {
|
||||||
ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
final ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
||||||
item.setThumbnailUrl(getAvatarUrl());
|
item.setThumbnailUrl(getAvatarUrl());
|
||||||
item.setSubscriberCount(getSubscriberCount());
|
item.setSubscriberCount(getSubscriberCount());
|
||||||
item.setDescription(getDescription());
|
item.setDescription(getDescription());
|
||||||
|
@ -29,7 +29,7 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
protected void onCreate(final Bundle savedInstanceState) {
|
protected void onCreate(final Bundle savedInstanceState) {
|
||||||
// Service
|
// Service
|
||||||
Intent i = new Intent();
|
final Intent i = new Intent();
|
||||||
i.setClass(this, DownloadManagerService.class);
|
i.setClass(this, DownloadManagerService.class);
|
||||||
startService(i);
|
startService(i);
|
||||||
|
|
||||||
@ -38,10 +38,10 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
setContentView(R.layout.activity_downloader);
|
setContentView(R.layout.activity_downloader);
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
actionBar.setTitle(R.string.downloads_title);
|
actionBar.setTitle(R.string.downloads_title);
|
||||||
@ -63,7 +63,7 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateFragments() {
|
private void updateFragments() {
|
||||||
MissionsFragment fragment = new MissionsFragment();
|
final MissionsFragment fragment = new MissionsFragment();
|
||||||
|
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.replace(R.id.frame, fragment, MISSIONS_FRAGMENT_TAG)
|
.replace(R.id.frame, fragment, MISSIONS_FRAGMENT_TAG)
|
||||||
@ -74,7 +74,7 @@ public class DownloadActivity extends AppCompatActivity {
|
|||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||||
super.onCreateOptionsMenu(menu);
|
super.onCreateOptionsMenu(menu);
|
||||||
MenuInflater inflater = getMenuInflater();
|
final MenuInflater inflater = getMenuInflater();
|
||||||
|
|
||||||
inflater.inflate(R.menu.download_menu, menu);
|
inflater.inflate(R.menu.download_menu, menu);
|
||||||
|
|
||||||
|
@ -124,7 +124,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
private SharedPreferences prefs;
|
private SharedPreferences prefs;
|
||||||
|
|
||||||
public static DownloadDialog newInstance(final StreamInfo info) {
|
public static DownloadDialog newInstance(final StreamInfo info) {
|
||||||
DownloadDialog dialog = new DownloadDialog();
|
final DownloadDialog dialog = new DownloadDialog();
|
||||||
dialog.setInfo(info);
|
dialog.setInfo(info);
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
@ -208,14 +208,15 @@ public class DownloadDialog extends DialogFragment
|
|||||||
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
|
setStyle(STYLE_NO_TITLE, ThemeHelper.getDialogTheme(context));
|
||||||
Icepick.restoreInstanceState(this, savedInstanceState);
|
Icepick.restoreInstanceState(this, savedInstanceState);
|
||||||
|
|
||||||
SparseArray<SecondaryStreamHelper<AudioStream>> secondaryStreams = new SparseArray<>(4);
|
final SparseArray<SecondaryStreamHelper<AudioStream>> secondaryStreams
|
||||||
List<VideoStream> videoStreams = wrappedVideoStreams.getStreamsList();
|
= new SparseArray<>(4);
|
||||||
|
final List<VideoStream> videoStreams = wrappedVideoStreams.getStreamsList();
|
||||||
|
|
||||||
for (int i = 0; i < videoStreams.size(); i++) {
|
for (int i = 0; i < videoStreams.size(); i++) {
|
||||||
if (!videoStreams.get(i).isVideoOnly()) {
|
if (!videoStreams.get(i).isVideoOnly()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
AudioStream audioStream = SecondaryStreamHelper
|
final AudioStream audioStream = SecondaryStreamHelper
|
||||||
.getAudioStreamFor(wrappedAudioStreams.getStreamsList(), videoStreams.get(i));
|
.getAudioStreamFor(wrappedAudioStreams.getStreamsList(), videoStreams.get(i));
|
||||||
|
|
||||||
if (audioStream != null) {
|
if (audioStream != null) {
|
||||||
@ -232,13 +233,13 @@ public class DownloadDialog extends DialogFragment
|
|||||||
this.audioStreamsAdapter = new StreamItemAdapter<>(context, wrappedAudioStreams);
|
this.audioStreamsAdapter = new StreamItemAdapter<>(context, wrappedAudioStreams);
|
||||||
this.subtitleStreamsAdapter = new StreamItemAdapter<>(context, wrappedSubtitleStreams);
|
this.subtitleStreamsAdapter = new StreamItemAdapter<>(context, wrappedSubtitleStreams);
|
||||||
|
|
||||||
Intent intent = new Intent(context, DownloadManagerService.class);
|
final Intent intent = new Intent(context, DownloadManagerService.class);
|
||||||
context.startService(intent);
|
context.startService(intent);
|
||||||
|
|
||||||
context.bindService(intent, new ServiceConnection() {
|
context.bindService(intent, new ServiceConnection() {
|
||||||
@Override
|
@Override
|
||||||
public void onServiceConnected(final ComponentName cname, final IBinder service) {
|
public void onServiceConnected(final ComponentName cname, final IBinder service) {
|
||||||
DownloadManagerBinder mgr = (DownloadManagerBinder) service;
|
final DownloadManagerBinder mgr = (DownloadManagerBinder) service;
|
||||||
|
|
||||||
mainStorageAudio = mgr.getMainStorageAudio();
|
mainStorageAudio = mgr.getMainStorageAudio();
|
||||||
mainStorageVideo = mgr.getMainStorageVideo();
|
mainStorageVideo = mgr.getMainStorageVideo();
|
||||||
@ -296,7 +297,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
|
|
||||||
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
|
|
||||||
int threads = prefs.getInt(getString(R.string.default_download_threads), 3);
|
final int threads = prefs.getInt(getString(R.string.default_download_threads), 3);
|
||||||
threadsCountTextView.setText(String.valueOf(threads));
|
threadsCountTextView.setText(String.valueOf(threads));
|
||||||
threadsSeekBar.setProgress(threads - 1);
|
threadsSeekBar.setProgress(threads - 1);
|
||||||
threadsSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
threadsSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
|
||||||
@ -373,13 +374,13 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (FilePickerActivityHelper.isOwnFileUri(context, data.getData())) {
|
if (FilePickerActivityHelper.isOwnFileUri(context, data.getData())) {
|
||||||
File file = Utils.getFileForUri(data.getData());
|
final File file = Utils.getFileForUri(data.getData());
|
||||||
checkSelectedDownload(null, Uri.fromFile(file), file.getName(),
|
checkSelectedDownload(null, Uri.fromFile(file), file.getName(),
|
||||||
StoredFileHelper.DEFAULT_MIME);
|
StoredFileHelper.DEFAULT_MIME);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
final DocumentFile docFile = DocumentFile.fromSingleUri(context, data.getData());
|
||||||
if (docFile == null) {
|
if (docFile == null) {
|
||||||
showFailedDialog(R.string.general_error);
|
showFailedDialog(R.string.general_error);
|
||||||
return;
|
return;
|
||||||
@ -564,7 +565,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String getNameEditText() {
|
private String getNameEditText() {
|
||||||
String str = nameEditText.getText().toString().trim();
|
final String str = nameEditText.getText().toString().trim();
|
||||||
|
|
||||||
return FilenameUtils.createFilename(context, str.isEmpty() ? currentInfo.getName() : str);
|
return FilenameUtils.createFilename(context, str.isEmpty() ? currentInfo.getName() : str);
|
||||||
}
|
}
|
||||||
@ -591,9 +592,9 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void prepareSelectedDownload() {
|
private void prepareSelectedDownload() {
|
||||||
StoredDirectoryHelper mainStorage;
|
final StoredDirectoryHelper mainStorage;
|
||||||
MediaFormat format;
|
final MediaFormat format;
|
||||||
String mime;
|
final String mime;
|
||||||
|
|
||||||
// first, build the filename and get the output folder (if possible)
|
// first, build the filename and get the output folder (if possible)
|
||||||
// later, run a very very very large file checking logic
|
// later, run a very very very large file checking logic
|
||||||
@ -683,15 +684,17 @@ public class DownloadDialog extends DialogFragment
|
|||||||
storage = new StoredFileHelper(context, mainStorage.getUri(), targetFile,
|
storage = new StoredFileHelper(context, mainStorage.getUri(), targetFile,
|
||||||
mainStorage.getTag());
|
mainStorage.getTag());
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
showErrorActivity(e);
|
showErrorActivity(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check if is our file
|
// check if is our file
|
||||||
MissionState state = downloadManager.checkForExistingMission(storage);
|
final MissionState state = downloadManager.checkForExistingMission(storage);
|
||||||
@StringRes int msgBtn;
|
@StringRes
|
||||||
@StringRes int msgBody;
|
final int msgBtn;
|
||||||
|
@StringRes
|
||||||
|
final int msgBody;
|
||||||
|
|
||||||
switch (state) {
|
switch (state) {
|
||||||
case Finished:
|
case Finished:
|
||||||
@ -744,8 +747,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final AlertDialog.Builder askDialog = new AlertDialog.Builder(context)
|
||||||
AlertDialog.Builder askDialog = new AlertDialog.Builder(context)
|
|
||||||
.setTitle(R.string.download_dialog_title)
|
.setTitle(R.string.download_dialog_title)
|
||||||
.setMessage(msgBody)
|
.setMessage(msgBody)
|
||||||
.setNegativeButton(android.R.string.cancel, null);
|
.setNegativeButton(android.R.string.cancel, null);
|
||||||
@ -787,7 +789,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
// try take (or steal) the file
|
// try take (or steal) the file
|
||||||
storageNew = new StoredFileHelper(context, mainStorage.getUri(),
|
storageNew = new StoredFileHelper(context, mainStorage.getUri(),
|
||||||
targetFile, mainStorage.getTag());
|
targetFile, mainStorage.getTag());
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
Log.e(TAG, "Failed to take (or steal) the file in "
|
Log.e(TAG, "Failed to take (or steal) the file in "
|
||||||
+ targetFile.toString());
|
+ targetFile.toString());
|
||||||
storageNew = null;
|
storageNew = null;
|
||||||
@ -825,18 +827,18 @@ public class DownloadDialog extends DialogFragment
|
|||||||
if (storage.length() > 0) {
|
if (storage.length() > 0) {
|
||||||
storage.truncate();
|
storage.truncate();
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (final IOException e) {
|
||||||
Log.e(TAG, "failed to truncate the file: " + storage.getUri().toString(), e);
|
Log.e(TAG, "failed to truncate the file: " + storage.getUri().toString(), e);
|
||||||
showFailedDialog(R.string.overwrite_failed);
|
showFailedDialog(R.string.overwrite_failed);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stream selectedStream;
|
final Stream selectedStream;
|
||||||
Stream secondaryStream = null;
|
Stream secondaryStream = null;
|
||||||
char kind;
|
final char kind;
|
||||||
int threads = threadsSeekBar.getProgress() + 1;
|
int threads = threadsSeekBar.getProgress() + 1;
|
||||||
String[] urls;
|
final String[] urls;
|
||||||
MissionRecoveryInfo[] recoveryInfo;
|
final MissionRecoveryInfo[] recoveryInfo;
|
||||||
String psName = null;
|
String psName = null;
|
||||||
String[] psArgs = null;
|
String[] psArgs = null;
|
||||||
long nearLength = 0;
|
long nearLength = 0;
|
||||||
@ -857,7 +859,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
kind = 'v';
|
kind = 'v';
|
||||||
selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex);
|
selectedStream = videoStreamsAdapter.getItem(selectedVideoIndex);
|
||||||
|
|
||||||
SecondaryStreamHelper<AudioStream> secondary = videoStreamsAdapter
|
final SecondaryStreamHelper<AudioStream> secondary = videoStreamsAdapter
|
||||||
.getAllSecondary()
|
.getAllSecondary()
|
||||||
.get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream));
|
.get(wrappedVideoStreams.getStreamsList().indexOf(selectedStream));
|
||||||
|
|
||||||
@ -871,7 +873,7 @@ public class DownloadDialog extends DialogFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
psArgs = null;
|
psArgs = null;
|
||||||
long videoSize = wrappedVideoStreams
|
final long videoSize = wrappedVideoStreams
|
||||||
.getSizeInBytes((VideoStream) selectedStream);
|
.getSizeInBytes((VideoStream) selectedStream);
|
||||||
|
|
||||||
// set nearLength, only, if both sizes are fetched or known. This probably
|
// set nearLength, only, if both sizes are fetched or known. This probably
|
||||||
|
@ -230,7 +230,7 @@ public abstract class BaseStateFragment<I> extends BaseFragment implements ViewC
|
|||||||
}
|
}
|
||||||
Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
Toast.makeText(activity, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
||||||
// Starting ReCaptcha Challenge Activity
|
// Starting ReCaptcha Challenge Activity
|
||||||
Intent intent = new Intent(activity, ReCaptchaActivity.class);
|
final Intent intent = new Intent(activity, ReCaptchaActivity.class);
|
||||||
intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, exception.getUrl());
|
intent.putExtra(ReCaptchaActivity.RECAPTCHA_URL_EXTRA, exception.getUrl());
|
||||||
startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST);
|
startActivityForResult(intent, ReCaptchaActivity.RECAPTCHA_REQUEST);
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
public void onResume() {
|
public void onResume() {
|
||||||
super.onResume();
|
super.onResume();
|
||||||
|
|
||||||
boolean youtubeRestrictedModeEnabled =
|
final boolean youtubeRestrictedModeEnabled =
|
||||||
PreferenceManager.getDefaultSharedPreferences(getContext())
|
PreferenceManager.getDefaultSharedPreferences(getContext())
|
||||||
.getBoolean(youtubeRestrictedModeEnabledKey, false);
|
.getBoolean(youtubeRestrictedModeEnabledKey, false);
|
||||||
if (previousYoutubeRestrictedModeEnabled != youtubeRestrictedModeEnabled) {
|
if (previousYoutubeRestrictedModeEnabled != youtubeRestrictedModeEnabled) {
|
||||||
@ -137,7 +137,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
}
|
}
|
||||||
inflater.inflate(R.menu.main_fragment_menu, menu);
|
inflater.inflate(R.menu.main_fragment_menu, menu);
|
||||||
|
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (supportActionBar != null) {
|
if (supportActionBar != null) {
|
||||||
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
}
|
}
|
||||||
@ -148,11 +148,9 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
switch (item.getItemId()) {
|
switch (item.getItemId()) {
|
||||||
case R.id.action_search:
|
case R.id.action_search:
|
||||||
try {
|
try {
|
||||||
NavigationHelper.openSearchFragment(
|
NavigationHelper.openSearchFragment(getFM(),
|
||||||
getFragmentManager(),
|
ServiceHelper.getSelectedServiceId(activity), "");
|
||||||
ServiceHelper.getSelectedServiceId(activity),
|
} catch (final Exception e) {
|
||||||
"");
|
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -239,7 +237,7 @@ public class MainFragment extends BaseFragment implements TabLayout.OnTabSelecte
|
|||||||
Fragment fragment = null;
|
Fragment fragment = null;
|
||||||
try {
|
try {
|
||||||
fragment = tab.getFragment(context);
|
fragment = tab.getFragment(context);
|
||||||
} catch (ExtractionException e) {
|
} catch (final ExtractionException e) {
|
||||||
throwable = e;
|
throwable = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,9 +14,9 @@ public abstract class OnScrollBelowItemsListener extends RecyclerView.OnScrollLi
|
|||||||
super.onScrolled(recyclerView, dx, dy);
|
super.onScrolled(recyclerView, dx, dy);
|
||||||
if (dy > 0) {
|
if (dy > 0) {
|
||||||
int pastVisibleItems = 0;
|
int pastVisibleItems = 0;
|
||||||
int visibleItemCount;
|
final int visibleItemCount;
|
||||||
int totalItemCount;
|
final int totalItemCount;
|
||||||
RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
|
final RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
|
||||||
|
|
||||||
visibleItemCount = layoutManager.getChildCount();
|
visibleItemCount = layoutManager.getChildCount();
|
||||||
totalItemCount = layoutManager.getItemCount();
|
totalItemCount = layoutManager.getItemCount();
|
||||||
@ -26,7 +26,7 @@ public abstract class OnScrollBelowItemsListener extends RecyclerView.OnScrollLi
|
|||||||
pastVisibleItems = ((LinearLayoutManager) layoutManager)
|
pastVisibleItems = ((LinearLayoutManager) layoutManager)
|
||||||
.findFirstVisibleItemPosition();
|
.findFirstVisibleItemPosition();
|
||||||
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
} else if (layoutManager instanceof StaggeredGridLayoutManager) {
|
||||||
int[] positions = ((StaggeredGridLayoutManager) layoutManager)
|
final int[] positions = ((StaggeredGridLayoutManager) layoutManager)
|
||||||
.findFirstVisibleItemPositions(null);
|
.findFirstVisibleItemPositions(null);
|
||||||
if (positions != null && positions.length > 0) {
|
if (positions != null && positions.length > 0) {
|
||||||
pastVisibleItems = positions[0];
|
pastVisibleItems = positions[0];
|
||||||
|
@ -50,7 +50,7 @@ public class TabAdaptor extends FragmentPagerAdapter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void updateItem(final String title, final Fragment fragment) {
|
public void updateItem(final String title, final Fragment fragment) {
|
||||||
int index = mFragmentTitleList.indexOf(title);
|
final int index = mFragmentTitleList.indexOf(title);
|
||||||
if (index != -1) {
|
if (index != -1) {
|
||||||
updateItem(index, fragment);
|
updateItem(index, fragment);
|
||||||
}
|
}
|
||||||
|
@ -18,6 +18,12 @@ import android.os.Handler;
|
|||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.preference.PreferenceManager;
|
import android.preference.PreferenceManager;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
|
import android.text.Html;
|
||||||
|
import android.text.Spanned;
|
||||||
|
import android.text.TextUtils;
|
||||||
|
import android.text.util.Linkify;
|
||||||
|
import android.util.DisplayMetrics;
|
||||||
|
import android.util.Log;
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@ -30,31 +36,25 @@ import android.widget.ImageView;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.RelativeLayout;
|
import android.widget.RelativeLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.appcompat.app.AlertDialog;
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.app.AppCompatActivity;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
import androidx.appcompat.widget.Toolbar;
|
import androidx.appcompat.widget.Toolbar;
|
||||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||||
|
import androidx.core.content.ContextCompat;
|
||||||
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.viewpager.widget.ViewPager;
|
||||||
|
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.PlaybackParameters;
|
import com.google.android.exoplayer2.PlaybackParameters;
|
||||||
import com.google.android.exoplayer2.Player;
|
import com.google.android.exoplayer2.Player;
|
||||||
import com.google.android.material.appbar.AppBarLayout;
|
import com.google.android.material.appbar.AppBarLayout;
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||||
import com.google.android.material.tabs.TabLayout;
|
import com.google.android.material.tabs.TabLayout;
|
||||||
import androidx.fragment.app.Fragment;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import androidx.viewpager.widget.ViewPager;
|
|
||||||
import android.text.Html;
|
|
||||||
import android.text.Spanned;
|
|
||||||
import android.text.TextUtils;
|
|
||||||
import android.text.util.Linkify;
|
|
||||||
import android.util.DisplayMetrics;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.appcompat.app.AppCompatActivity;
|
|
||||||
import androidx.appcompat.content.res.AppCompatResources;
|
|
||||||
|
|
||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||||
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
||||||
@ -93,8 +93,8 @@ import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
|||||||
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
import org.schabi.newpipe.player.playqueue.SinglePlayQueue;
|
||||||
import org.schabi.newpipe.report.ErrorActivity;
|
import org.schabi.newpipe.report.ErrorActivity;
|
||||||
import org.schabi.newpipe.report.UserAction;
|
import org.schabi.newpipe.report.UserAction;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
import org.schabi.newpipe.util.ImageDisplayConstants;
|
import org.schabi.newpipe.util.ImageDisplayConstants;
|
||||||
import org.schabi.newpipe.util.InfoCache;
|
import org.schabi.newpipe.util.InfoCache;
|
||||||
@ -112,7 +112,6 @@ import java.util.Collection;
|
|||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
@ -125,9 +124,9 @@ import io.reactivex.disposables.Disposable;
|
|||||||
import io.reactivex.schedulers.Schedulers;
|
import io.reactivex.schedulers.Schedulers;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.COMMENTS;
|
||||||
|
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
||||||
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
import static org.schabi.newpipe.player.helper.PlayerHelper.isClearingQueueConfirmationRequired;
|
||||||
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
import static org.schabi.newpipe.player.playqueue.PlayQueueItem.RECOVERY_UNSET;
|
||||||
import static org.schabi.newpipe.extractor.stream.StreamExtractor.NO_AGE_LIMIT;
|
|
||||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||||
|
|
||||||
public class VideoDetailFragment
|
public class VideoDetailFragment
|
||||||
@ -203,6 +202,7 @@ public class VideoDetailFragment
|
|||||||
private ImageView thumbnailImageView;
|
private ImageView thumbnailImageView;
|
||||||
private ImageView thumbnailPlayButton;
|
private ImageView thumbnailPlayButton;
|
||||||
private AnimatedProgressBar positionView;
|
private AnimatedProgressBar positionView;
|
||||||
|
private ViewGroup playerPlaceholder;
|
||||||
|
|
||||||
private View videoTitleRoot;
|
private View videoTitleRoot;
|
||||||
private TextView videoTitleTextView;
|
private TextView videoTitleTextView;
|
||||||
@ -372,7 +372,7 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
public static VideoDetailFragment getInstance(final int serviceId, final String videoUrl,
|
public static VideoDetailFragment getInstance(final int serviceId, final String videoUrl,
|
||||||
final String name, final PlayQueue playQueue) {
|
final String name, final PlayQueue playQueue) {
|
||||||
VideoDetailFragment instance = new VideoDetailFragment();
|
final VideoDetailFragment instance = new VideoDetailFragment();
|
||||||
instance.setInitialData(serviceId, videoUrl, name, playQueue);
|
instance.setInitialData(serviceId, videoUrl, name, playQueue);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -505,7 +505,7 @@ public class VideoDetailFragment
|
|||||||
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
case ReCaptchaActivity.RECAPTCHA_REQUEST:
|
||||||
if (resultCode == Activity.RESULT_OK) {
|
if (resultCode == Activity.RESULT_OK) {
|
||||||
NavigationHelper
|
NavigationHelper
|
||||||
.openVideoDetailFragment(getFragmentManager(), serviceId, url, name);
|
.openVideoDetailFragment(getFM(), serviceId, url, name);
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "ReCaptcha failed");
|
Log.e(TAG, "ReCaptcha failed");
|
||||||
}
|
}
|
||||||
@ -579,9 +579,9 @@ public class VideoDetailFragment
|
|||||||
openPopupPlayer(false);
|
openPopupPlayer(false);
|
||||||
break;
|
break;
|
||||||
case R.id.detail_controls_playlist_append:
|
case R.id.detail_controls_playlist_append:
|
||||||
if (getFragmentManager() != null && currentInfo != null) {
|
if (getFM() != null && currentInfo != null) {
|
||||||
PlaylistAppendDialog.fromStreamInfo(currentInfo)
|
PlaylistAppendDialog.fromStreamInfo(currentInfo)
|
||||||
.show(getFragmentManager(), TAG);
|
.show(getFM(), TAG);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case R.id.detail_controls_download:
|
case R.id.detail_controls_download:
|
||||||
@ -634,12 +634,9 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
private void openChannel(final String subChannelUrl, final String subChannelName) {
|
private void openChannel(final String subChannelUrl, final String subChannelName) {
|
||||||
try {
|
try {
|
||||||
NavigationHelper.openChannelFragment(
|
NavigationHelper.openChannelFragment(getFM(), currentInfo.getServiceId(),
|
||||||
getFragmentManager(),
|
subChannelUrl, subChannelName);
|
||||||
currentInfo.getServiceId(),
|
} catch (final Exception e) {
|
||||||
subChannelUrl,
|
|
||||||
subChannelName);
|
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -709,6 +706,7 @@ public class VideoDetailFragment
|
|||||||
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
|
thumbnailBackgroundButton = rootView.findViewById(R.id.detail_thumbnail_root_layout);
|
||||||
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
|
thumbnailImageView = rootView.findViewById(R.id.detail_thumbnail_image_view);
|
||||||
thumbnailPlayButton = rootView.findViewById(R.id.detail_thumbnail_play_button);
|
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);
|
contentRootLayoutHiding = rootView.findViewById(R.id.detail_content_root_hiding);
|
||||||
|
|
||||||
@ -1066,7 +1064,7 @@ public class VideoDetailFragment
|
|||||||
if (pageAdapter.getCount() < 2) {
|
if (pageAdapter.getCount() < 2) {
|
||||||
tabLayout.setVisibility(View.GONE);
|
tabLayout.setVisibility(View.GONE);
|
||||||
} else {
|
} else {
|
||||||
int position = pageAdapter.getItemPositionByTitle(selectedTabTag);
|
final int position = pageAdapter.getItemPositionByTitle(selectedTabTag);
|
||||||
if (position != -1) {
|
if (position != -1) {
|
||||||
viewPager.setCurrentItem(position);
|
viewPager.setCurrentItem(position);
|
||||||
}
|
}
|
||||||
@ -1080,7 +1078,7 @@ public class VideoDetailFragment
|
|||||||
.getServiceInfo()
|
.getServiceInfo()
|
||||||
.getMediaCapabilities()
|
.getMediaCapabilities()
|
||||||
.contains(COMMENTS);
|
.contains(COMMENTS);
|
||||||
} catch (ExtractionException e) {
|
} catch (final ExtractionException e) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1177,7 +1175,7 @@ public class VideoDetailFragment
|
|||||||
|
|
||||||
// Video view can have elements visible from popup,
|
// Video view can have elements visible from popup,
|
||||||
// We hide it here but once it ready the view will be shown in handleIntent()
|
// We hide it here but once it ready the view will be shown in handleIntent()
|
||||||
Objects.requireNonNull(playerService.getView()).setVisibility(View.GONE);
|
playerService.getView().setVisibility(View.GONE);
|
||||||
addVideoPlayerView();
|
addVideoPlayerView();
|
||||||
|
|
||||||
final Intent playerIntent = NavigationHelper
|
final Intent playerIntent = NavigationHelper
|
||||||
@ -1269,17 +1267,15 @@ public class VideoDetailFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
|
|
||||||
|
|
||||||
// Check if viewHolder already contains a child
|
// Check if viewHolder already contains a child
|
||||||
if (player.getRootView().getParent() != viewHolder) {
|
if (player.getRootView().getParent() != playerPlaceholder) {
|
||||||
removeVideoPlayerView();
|
removeVideoPlayerView();
|
||||||
}
|
}
|
||||||
setHeightThumbnail();
|
setHeightThumbnail();
|
||||||
|
|
||||||
// Prevent from re-adding a view multiple times
|
// Prevent from re-adding a view multiple times
|
||||||
if (player.getRootView().getParent() == null) {
|
if (player.getRootView().getParent() == null) {
|
||||||
viewHolder.addView(player.getRootView());
|
playerPlaceholder.addView(player.getRootView());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1294,9 +1290,8 @@ public class VideoDetailFragment
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final FrameLayout viewHolder = getView().findViewById(R.id.player_placeholder);
|
playerPlaceholder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
|
||||||
viewHolder.getLayoutParams().height = FrameLayout.LayoutParams.MATCH_PARENT;
|
playerPlaceholder.requestLayout();
|
||||||
viewHolder.requestLayout();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void prepareDescription(final Description description) {
|
private void prepareDescription(final Description description) {
|
||||||
@ -1308,7 +1303,7 @@ public class VideoDetailFragment
|
|||||||
if (description.getType() == Description.HTML) {
|
if (description.getType() == Description.HTML) {
|
||||||
disposables.add(Single.just(description.getContent())
|
disposables.add(Single.just(description.getContent())
|
||||||
.map((@NonNull String descriptionText) -> {
|
.map((@NonNull String descriptionText) -> {
|
||||||
Spanned parsedDescription;
|
final Spanned parsedDescription;
|
||||||
if (Build.VERSION.SDK_INT >= 24) {
|
if (Build.VERSION.SDK_INT >= 24) {
|
||||||
parsedDescription = Html.fromHtml(descriptionText, 0);
|
parsedDescription = Html.fromHtml(descriptionText, 0);
|
||||||
} else {
|
} else {
|
||||||
@ -1351,7 +1346,7 @@ public class VideoDetailFragment
|
|||||||
final int height;
|
final int height;
|
||||||
if (player != null && player.isFullscreen()) {
|
if (player != null && player.isFullscreen()) {
|
||||||
height = isInMultiWindow()
|
height = isInMultiWindow()
|
||||||
? Objects.requireNonNull(getView()).getHeight()
|
? requireView().getHeight()
|
||||||
: activity.getWindow().getDecorView().getHeight();
|
: activity.getWindow().getDecorView().getHeight();
|
||||||
} else {
|
} else {
|
||||||
height = isPortrait
|
height = isPortrait
|
||||||
@ -1413,7 +1408,7 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
IntentFilter intentFilter = new IntentFilter();
|
final IntentFilter intentFilter = new IntentFilter();
|
||||||
intentFilter.addAction(ACTION_SHOW_MAIN_PLAYER);
|
intentFilter.addAction(ACTION_SHOW_MAIN_PLAYER);
|
||||||
intentFilter.addAction(ACTION_HIDE_MAIN_PLAYER);
|
intentFilter.addAction(ACTION_HIDE_MAIN_PLAYER);
|
||||||
activity.registerReceiver(broadcastReceiver, intentFilter);
|
activity.registerReceiver(broadcastReceiver, intentFilter);
|
||||||
@ -1516,7 +1511,7 @@ public class VideoDetailFragment
|
|||||||
uploaderThumb.setVisibility(View.GONE);
|
uploaderThumb.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
Drawable buddyDrawable = AppCompatResources.getDrawable(activity, R.drawable.buddy);
|
final Drawable buddyDrawable = AppCompatResources.getDrawable(activity, R.drawable.buddy);
|
||||||
subChannelThumb.setImageDrawable(buddyDrawable);
|
subChannelThumb.setImageDrawable(buddyDrawable);
|
||||||
uploaderThumb.setImageDrawable(buddyDrawable);
|
uploaderThumb.setImageDrawable(buddyDrawable);
|
||||||
|
|
||||||
@ -1680,7 +1675,7 @@ public class VideoDetailFragment
|
|||||||
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
|
downloadDialog.setSubtitleStreams(currentInfo.getSubtitles());
|
||||||
|
|
||||||
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
downloadDialog.show(activity.getSupportFragmentManager(), "downloadDialog");
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
final ErrorActivity.ErrorInfo info = ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
final ErrorActivity.ErrorInfo info = ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||||
ServiceList.all()
|
ServiceList.all()
|
||||||
.get(currentInfo
|
.get(currentInfo
|
||||||
@ -1706,7 +1701,7 @@ public class VideoDetailFragment
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int errorId = exception instanceof YoutubeStreamExtractor.DecryptException
|
final int errorId = exception instanceof YoutubeStreamExtractor.DecryptException
|
||||||
? R.string.youtube_signature_decryption_error
|
? R.string.youtube_signature_decryption_error
|
||||||
: exception instanceof ExtractionException
|
: exception instanceof ExtractionException
|
||||||
? R.string.parsing_error
|
? R.string.parsing_error
|
||||||
@ -1774,9 +1769,19 @@ public class VideoDetailFragment
|
|||||||
private void showPlaybackProgress(final long progress, final long duration) {
|
private void showPlaybackProgress(final long progress, final long duration) {
|
||||||
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
|
final int progressSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(progress);
|
||||||
final int durationSeconds = (int) TimeUnit.MILLISECONDS.toSeconds(duration);
|
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);
|
positionView.setMax(durationSeconds);
|
||||||
positionView.setProgressAnimated(progressSeconds);
|
if (shouldAnimate) {
|
||||||
detailPositionView.setText(Localization.getDurationString(progressSeconds));
|
positionView.setProgressAnimated(progressSeconds);
|
||||||
|
} else {
|
||||||
|
positionView.setProgress(progressSeconds);
|
||||||
|
}
|
||||||
|
final String position = Localization.getDurationString(progressSeconds);
|
||||||
|
if (position != detailPositionView.getText()) {
|
||||||
|
detailPositionView.setText(position);
|
||||||
|
}
|
||||||
if (positionView.getVisibility() != View.VISIBLE) {
|
if (positionView.getVisibility() != View.VISIBLE) {
|
||||||
animateView(positionView, true, 100);
|
animateView(positionView, true, 100);
|
||||||
animateView(detailPositionView, true, 100);
|
animateView(detailPositionView, true, 100);
|
||||||
@ -1953,7 +1958,7 @@ public class VideoDetailFragment
|
|||||||
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
||||||
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
|
final AppBarLayout.Behavior behavior = (AppBarLayout.Behavior) params.getBehavior();
|
||||||
final ValueAnimator valueAnimator = ValueAnimator
|
final ValueAnimator valueAnimator = ValueAnimator
|
||||||
.ofInt(0, -getView().findViewById(R.id.player_placeholder).getHeight());
|
.ofInt(0, -playerPlaceholder.getHeight());
|
||||||
valueAnimator.setInterpolator(new DecelerateInterpolator());
|
valueAnimator.setInterpolator(new DecelerateInterpolator());
|
||||||
valueAnimator.addUpdateListener(animation -> {
|
valueAnimator.addUpdateListener(animation -> {
|
||||||
behavior.setTopAndBottomOffset((int) animation.getAnimatedValue());
|
behavior.setTopAndBottomOffset((int) animation.getAnimatedValue());
|
||||||
@ -2116,11 +2121,11 @@ public class VideoDetailFragment
|
|||||||
if (sortedVideoStreams == null) {
|
if (sortedVideoStreams == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
CharSequence[] resolutions = new CharSequence[sortedVideoStreams.size()];
|
final CharSequence[] resolutions = new CharSequence[sortedVideoStreams.size()];
|
||||||
for (int i = 0; i < sortedVideoStreams.size(); i++) {
|
for (int i = 0; i < sortedVideoStreams.size(); i++) {
|
||||||
resolutions[i] = sortedVideoStreams.get(i).getResolution();
|
resolutions[i] = sortedVideoStreams.get(i).getResolution();
|
||||||
}
|
}
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(activity)
|
final AlertDialog.Builder builder = new AlertDialog.Builder(activity)
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.setNeutralButton(R.string.open_in_browser, (dialog, i) ->
|
.setNeutralButton(R.string.open_in_browser, (dialog, i) ->
|
||||||
ShareUtils.openUrlInBrowser(requireActivity(), url)
|
ShareUtils.openUrlInBrowser(requireActivity(), url)
|
||||||
@ -2180,6 +2185,30 @@ public class VideoDetailFragment
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When the mini player exists the view underneath it is not touchable.
|
||||||
|
* 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);
|
||||||
|
final int newBottomPadding;
|
||||||
|
if (showMore) {
|
||||||
|
newBottomPadding = 0;
|
||||||
|
} else {
|
||||||
|
newBottomPadding = peekHeight;
|
||||||
|
}
|
||||||
|
if (holder.getPaddingBottom() == newBottomPadding) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
holder.setPadding(holder.getPaddingLeft(),
|
||||||
|
holder.getPaddingTop(),
|
||||||
|
holder.getPaddingRight(),
|
||||||
|
newBottomPadding);
|
||||||
|
}
|
||||||
|
|
||||||
private void setupBottomPlayer() {
|
private void setupBottomPlayer() {
|
||||||
final CoordinatorLayout.LayoutParams params =
|
final CoordinatorLayout.LayoutParams params =
|
||||||
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
(CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
|
||||||
@ -2190,6 +2219,7 @@ public class VideoDetailFragment
|
|||||||
bottomSheetBehavior.setState(bottomSheetState);
|
bottomSheetBehavior.setState(bottomSheetState);
|
||||||
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
|
final int peekHeight = getResources().getDimensionPixelSize(R.dimen.mini_player_height);
|
||||||
if (bottomSheetState != BottomSheetBehavior.STATE_HIDDEN) {
|
if (bottomSheetState != BottomSheetBehavior.STATE_HIDDEN) {
|
||||||
|
manageSpaceAtTheBottom(false);
|
||||||
bottomSheetBehavior.setPeekHeight(peekHeight);
|
bottomSheetBehavior.setPeekHeight(peekHeight);
|
||||||
if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) {
|
if (bottomSheetState == BottomSheetBehavior.STATE_COLLAPSED) {
|
||||||
overlay.setAlpha(MAX_OVERLAY_ALPHA);
|
overlay.setAlpha(MAX_OVERLAY_ALPHA);
|
||||||
@ -2207,12 +2237,14 @@ public class VideoDetailFragment
|
|||||||
switch (newState) {
|
switch (newState) {
|
||||||
case BottomSheetBehavior.STATE_HIDDEN:
|
case BottomSheetBehavior.STATE_HIDDEN:
|
||||||
moveFocusToMainFragment(true);
|
moveFocusToMainFragment(true);
|
||||||
|
manageSpaceAtTheBottom(true);
|
||||||
|
|
||||||
bottomSheetBehavior.setPeekHeight(0);
|
bottomSheetBehavior.setPeekHeight(0);
|
||||||
cleanUp();
|
cleanUp();
|
||||||
break;
|
break;
|
||||||
case BottomSheetBehavior.STATE_EXPANDED:
|
case BottomSheetBehavior.STATE_EXPANDED:
|
||||||
moveFocusToMainFragment(false);
|
moveFocusToMainFragment(false);
|
||||||
|
manageSpaceAtTheBottom(false);
|
||||||
|
|
||||||
bottomSheetBehavior.setPeekHeight(peekHeight);
|
bottomSheetBehavior.setPeekHeight(peekHeight);
|
||||||
// Disable click because overlay buttons located on top of buttons
|
// Disable click because overlay buttons located on top of buttons
|
||||||
|
@ -136,7 +136,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
final RecyclerView.ViewHolder itemHolder =
|
final RecyclerView.ViewHolder itemHolder =
|
||||||
itemsList.findContainingViewHolder(focusedItem);
|
itemsList.findContainingViewHolder(focusedItem);
|
||||||
return itemHolder.getAdapterPosition();
|
return itemHolder.getAdapterPosition();
|
||||||
} catch (NullPointerException e) {
|
} catch (final NullPointerException e) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -169,7 +169,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
}
|
}
|
||||||
|
|
||||||
itemsList.post(() -> {
|
itemsList.post(() -> {
|
||||||
RecyclerView.ViewHolder focusedHolder =
|
final RecyclerView.ViewHolder focusedHolder =
|
||||||
itemsList.findViewHolderForAdapterPosition(position);
|
itemsList.findViewHolderForAdapterPosition(position);
|
||||||
|
|
||||||
if (focusedHolder != null) {
|
if (focusedHolder != null) {
|
||||||
@ -279,7 +279,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
selectedItem.getServiceId(),
|
selectedItem.getServiceId(),
|
||||||
selectedItem.getUrl(),
|
selectedItem.getUrl(),
|
||||||
selectedItem.getName());
|
selectedItem.getName());
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,7 +294,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
selectedItem.getServiceId(),
|
selectedItem.getServiceId(),
|
||||||
selectedItem.getUrl(),
|
selectedItem.getUrl(),
|
||||||
selectedItem.getName());
|
selectedItem.getName());
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -367,7 +367,7 @@ public abstract class BaseListFragment<I, N> extends BaseStateFragment<I>
|
|||||||
+ "menu = [" + menu + "], inflater = [" + inflater + "]");
|
+ "menu = [" + menu + "], inflater = [" + inflater + "]");
|
||||||
}
|
}
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (supportActionBar != null) {
|
if (supportActionBar != null) {
|
||||||
supportActionBar.setDisplayShowTitleEnabled(true);
|
supportActionBar.setDisplayShowTitleEnabled(true);
|
||||||
if (useAsFrontPage) {
|
if (useAsFrontPage) {
|
||||||
|
@ -98,7 +98,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
|
|
||||||
public static ChannelFragment getInstance(final int serviceId, final String url,
|
public static ChannelFragment getInstance(final int serviceId, final String url,
|
||||||
final String name) {
|
final String name) {
|
||||||
ChannelFragment instance = new ChannelFragment();
|
final ChannelFragment instance = new ChannelFragment();
|
||||||
instance.setInitialData(serviceId, url, name);
|
instance.setInitialData(serviceId, url, name);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (useAsFrontPage && supportActionBar != null) {
|
if (useAsFrontPage && supportActionBar != null) {
|
||||||
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
} else {
|
} else {
|
||||||
@ -206,7 +206,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
private void openRssFeed() {
|
private void openRssFeed() {
|
||||||
final ChannelInfo info = currentInfo;
|
final ChannelInfo info = currentInfo;
|
||||||
if (info != null) {
|
if (info != null) {
|
||||||
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(info.getFeedUrl()));
|
final Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(info.getFeedUrl()));
|
||||||
startActivity(intent);
|
startActivity(intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -345,7 +345,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "No subscription to this channel!");
|
Log.d(TAG, "No subscription to this channel!");
|
||||||
}
|
}
|
||||||
SubscriptionEntity channel = new SubscriptionEntity();
|
final SubscriptionEntity channel = new SubscriptionEntity();
|
||||||
channel.setServiceId(info.getServiceId());
|
channel.setServiceId(info.getServiceId());
|
||||||
channel.setUrl(info.getUrl());
|
channel.setUrl(info.getUrl());
|
||||||
channel.setData(info.getName(),
|
channel.setData(info.getName(),
|
||||||
@ -371,16 +371,16 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
+ "isSubscribed = [" + isSubscribed + "]");
|
+ "isSubscribed = [" + isSubscribed + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean isButtonVisible = headerSubscribeButton.getVisibility() == View.VISIBLE;
|
final boolean isButtonVisible = headerSubscribeButton.getVisibility() == View.VISIBLE;
|
||||||
int backgroundDuration = isButtonVisible ? 300 : 0;
|
final int backgroundDuration = isButtonVisible ? 300 : 0;
|
||||||
int textDuration = isButtonVisible ? 200 : 0;
|
final int textDuration = isButtonVisible ? 200 : 0;
|
||||||
|
|
||||||
int subscribeBackground = ThemeHelper
|
final int subscribeBackground = ThemeHelper
|
||||||
.resolveColorFromAttr(activity, R.attr.colorPrimary);
|
.resolveColorFromAttr(activity, R.attr.colorPrimary);
|
||||||
int subscribeText = ContextCompat.getColor(activity, R.color.subscribe_text_color);
|
final int subscribeText = ContextCompat.getColor(activity, R.color.subscribe_text_color);
|
||||||
int subscribedBackground = ContextCompat
|
final int subscribedBackground = ContextCompat
|
||||||
.getColor(activity, R.color.subscribed_background_color);
|
.getColor(activity, R.color.subscribed_background_color);
|
||||||
int subscribedText = ContextCompat.getColor(activity, R.color.subscribed_text_color);
|
final int subscribedText = ContextCompat.getColor(activity, R.color.subscribed_text_color);
|
||||||
|
|
||||||
if (!isSubscribed) {
|
if (!isSubscribed) {
|
||||||
headerSubscribeButton.setText(R.string.subscribe_button_title);
|
headerSubscribeButton.setText(R.string.subscribe_button_title);
|
||||||
@ -426,10 +426,10 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
case R.id.sub_channel_title_view:
|
case R.id.sub_channel_title_view:
|
||||||
if (!TextUtils.isEmpty(currentInfo.getParentChannelUrl())) {
|
if (!TextUtils.isEmpty(currentInfo.getParentChannelUrl())) {
|
||||||
try {
|
try {
|
||||||
NavigationHelper.openChannelFragment(getFragmentManager(),
|
NavigationHelper.openChannelFragment(getFM(), currentInfo.getServiceId(),
|
||||||
currentInfo.getServiceId(), currentInfo.getParentChannelUrl(),
|
currentInfo.getParentChannelUrl(),
|
||||||
currentInfo.getParentChannelName());
|
currentInfo.getParentChannelName());
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||||
}
|
}
|
||||||
} else if (DEBUG) {
|
} else if (DEBUG) {
|
||||||
@ -490,13 +490,13 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
|
|
||||||
playlistCtrl.setVisibility(View.VISIBLE);
|
playlistCtrl.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
List<Throwable> errors = new ArrayList<>(result.getErrors());
|
final List<Throwable> errors = new ArrayList<>(result.getErrors());
|
||||||
if (!errors.isEmpty()) {
|
if (!errors.isEmpty()) {
|
||||||
|
|
||||||
// handling ContentNotSupportedException not to show the error but an appropriate string
|
// handling ContentNotSupportedException not to show the error but an appropriate string
|
||||||
// so that crashes won't be sent uselessly and the user will understand what happened
|
// so that crashes won't be sent uselessly and the user will understand what happened
|
||||||
for (Iterator<Throwable> it = errors.iterator(); it.hasNext();) {
|
for (Iterator<Throwable> it = errors.iterator(); it.hasNext();) {
|
||||||
Throwable throwable = it.next();
|
final Throwable throwable = it.next();
|
||||||
if (throwable instanceof ContentNotSupportedException) {
|
if (throwable instanceof ContentNotSupportedException) {
|
||||||
showContentNotSupported();
|
showContentNotSupported();
|
||||||
it.remove();
|
it.remove();
|
||||||
@ -549,7 +549,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
|
|
||||||
private PlayQueue getPlayQueue(final int index) {
|
private PlayQueue getPlayQueue(final int index) {
|
||||||
final List<StreamInfoItem> streamItems = new ArrayList<>();
|
final List<StreamInfoItem> streamItems = new ArrayList<>();
|
||||||
for (InfoItem i : infoListAdapter.getItemsList()) {
|
for (final InfoItem i : infoListAdapter.getItemsList()) {
|
||||||
if (i instanceof StreamInfoItem) {
|
if (i instanceof StreamInfoItem) {
|
||||||
streamItems.add((StreamInfoItem) i);
|
streamItems.add((StreamInfoItem) i);
|
||||||
}
|
}
|
||||||
@ -581,7 +581,7 @@ public class ChannelFragment extends BaseListInfoFragment<ChannelInfo>
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int errorId = exception instanceof ExtractionException
|
final int errorId = exception instanceof ExtractionException
|
||||||
? R.string.parsing_error : R.string.general_error;
|
? R.string.parsing_error : R.string.general_error;
|
||||||
|
|
||||||
onUnrecoverableError(exception, UserAction.REQUESTED_CHANNEL,
|
onUnrecoverableError(exception, UserAction.REQUESTED_CHANNEL,
|
||||||
|
@ -30,7 +30,7 @@ public class CommentsFragment extends BaseListInfoFragment<CommentsInfo> {
|
|||||||
|
|
||||||
public static CommentsFragment getInstance(final int serviceId, final String url,
|
public static CommentsFragment getInstance(final int serviceId, final String url,
|
||||||
final String name) {
|
final String name) {
|
||||||
CommentsFragment instance = new CommentsFragment();
|
final CommentsFragment instance = new CommentsFragment();
|
||||||
instance.setInitialData(serviceId, url, name);
|
instance.setInitialData(serviceId, url, name);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ public class DefaultKioskFragment extends KioskFragment {
|
|||||||
|
|
||||||
currentInfo = null;
|
currentInfo = null;
|
||||||
currentNextPage = null;
|
currentNextPage = null;
|
||||||
} catch (ExtractionException e) {
|
} catch (final ExtractionException e) {
|
||||||
onUnrecoverableError(e, UserAction.REQUESTED_KIOSK, "none",
|
onUnrecoverableError(e, UserAction.REQUESTED_KIOSK, "none",
|
||||||
"Loading default kiosk from selected service", 0);
|
"Loading default kiosk from selected service", 0);
|
||||||
}
|
}
|
||||||
|
@ -72,9 +72,9 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
|||||||
|
|
||||||
public static KioskFragment getInstance(final int serviceId, final String kioskId)
|
public static KioskFragment getInstance(final int serviceId, final String kioskId)
|
||||||
throws ExtractionException {
|
throws ExtractionException {
|
||||||
KioskFragment instance = new KioskFragment();
|
final KioskFragment instance = new KioskFragment();
|
||||||
StreamingService service = NewPipe.getService(serviceId);
|
final StreamingService service = NewPipe.getService(serviceId);
|
||||||
ListLinkHandlerFactory kioskLinkHandlerFactory = service.getKioskList()
|
final ListLinkHandlerFactory kioskLinkHandlerFactory = service.getKioskList()
|
||||||
.getListLinkHandlerFactoryByType(kioskId);
|
.getListLinkHandlerFactoryByType(kioskId);
|
||||||
instance.setInitialData(serviceId,
|
instance.setInitialData(serviceId,
|
||||||
kioskLinkHandlerFactory.fromId(kioskId).getUrl(), kioskId);
|
kioskLinkHandlerFactory.fromId(kioskId).getUrl(), kioskId);
|
||||||
@ -101,7 +101,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
|||||||
if (useAsFrontPage && isVisibleToUser && activity != null) {
|
if (useAsFrontPage && isVisibleToUser && activity != null) {
|
||||||
try {
|
try {
|
||||||
setTitle(kioskTranslatedName);
|
setTitle(kioskTranslatedName);
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
onUnrecoverableError(e, UserAction.UI_ERROR,
|
onUnrecoverableError(e, UserAction.UI_ERROR,
|
||||||
"none",
|
"none",
|
||||||
"none", R.string.app_ui_crash);
|
"none", R.string.app_ui_crash);
|
||||||
@ -132,7 +132,7 @@ public class KioskFragment extends BaseListInfoFragment<KioskInfo> {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (supportActionBar != null && useAsFrontPage) {
|
if (supportActionBar != null && useAsFrontPage) {
|
||||||
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
supportActionBar.setDisplayHomeAsUpEnabled(false);
|
||||||
}
|
}
|
||||||
|
@ -85,7 +85,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
|
|
||||||
public static PlaylistFragment getInstance(final int serviceId, final String url,
|
public static PlaylistFragment getInstance(final int serviceId, final String url,
|
||||||
final String name) {
|
final String name) {
|
||||||
PlaylistFragment instance = new PlaylistFragment();
|
final PlaylistFragment instance = new PlaylistFragment();
|
||||||
instance.setInitialData(serviceId, url, name);
|
instance.setInitialData(serviceId, url, name);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -286,11 +286,9 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
if (!TextUtils.isEmpty(result.getUploaderUrl())) {
|
if (!TextUtils.isEmpty(result.getUploaderUrl())) {
|
||||||
headerUploaderLayout.setOnClickListener(v -> {
|
headerUploaderLayout.setOnClickListener(v -> {
|
||||||
try {
|
try {
|
||||||
NavigationHelper.openChannelFragment(getFragmentManager(),
|
NavigationHelper.openChannelFragment(getFM(), result.getServiceId(),
|
||||||
result.getServiceId(),
|
result.getUploaderUrl(), result.getUploaderName());
|
||||||
result.getUploaderUrl(),
|
} catch (final Exception e) {
|
||||||
result.getUploaderName());
|
|
||||||
} catch (Exception e) {
|
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) getActivity(), e);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -341,7 +339,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
|
|
||||||
private PlayQueue getPlayQueue(final int index) {
|
private PlayQueue getPlayQueue(final int index) {
|
||||||
final List<StreamInfoItem> infoItems = new ArrayList<>();
|
final List<StreamInfoItem> infoItems = new ArrayList<>();
|
||||||
for (InfoItem i : infoListAdapter.getItemsList()) {
|
for (final InfoItem i : infoListAdapter.getItemsList()) {
|
||||||
if (i instanceof StreamInfoItem) {
|
if (i instanceof StreamInfoItem) {
|
||||||
infoItems.add((StreamInfoItem) i);
|
infoItems.add((StreamInfoItem) i);
|
||||||
}
|
}
|
||||||
@ -375,7 +373,7 @@ public class PlaylistFragment extends BaseListInfoFragment<PlaylistInfo> {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int errorId = exception instanceof ExtractionException
|
final int errorId = exception instanceof ExtractionException
|
||||||
? R.string.parsing_error : R.string.general_error;
|
? R.string.parsing_error : R.string.general_error;
|
||||||
onUnrecoverableError(exception, UserAction.REQUESTED_PLAYLIST,
|
onUnrecoverableError(exception, UserAction.REQUESTED_PLAYLIST,
|
||||||
NewPipe.getNameOfService(serviceId), url, errorId);
|
NewPipe.getNameOfService(serviceId), url, errorId);
|
||||||
|
@ -161,7 +161,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
private TextWatcher textWatcher;
|
private TextWatcher textWatcher;
|
||||||
|
|
||||||
public static SearchFragment getInstance(final int serviceId, final String searchString) {
|
public static SearchFragment getInstance(final int serviceId, final String searchString) {
|
||||||
SearchFragment searchFragment = new SearchFragment();
|
final SearchFragment searchFragment = new SearchFragment();
|
||||||
searchFragment.setQuery(serviceId, searchString, new String[0], "");
|
searchFragment.setQuery(serviceId, searchString, new String[0], "");
|
||||||
|
|
||||||
if (!TextUtils.isEmpty(searchString)) {
|
if (!TextUtils.isEmpty(searchString)) {
|
||||||
@ -187,8 +187,9 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
super.onAttach(context);
|
super.onAttach(context);
|
||||||
|
|
||||||
suggestionListAdapter = new SuggestionListAdapter(activity);
|
suggestionListAdapter = new SuggestionListAdapter(activity);
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
final SharedPreferences preferences
|
||||||
boolean isSearchHistoryEnabled = preferences
|
= PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
|
final boolean isSearchHistoryEnabled = preferences
|
||||||
.getBoolean(getString(R.string.enable_search_history_key), true);
|
.getBoolean(getString(R.string.enable_search_history_key), true);
|
||||||
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
|
suggestionListAdapter.setShowSuggestionHistory(isSearchHistoryEnabled);
|
||||||
|
|
||||||
@ -199,7 +200,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
public void onCreate(final Bundle savedInstanceState) {
|
public void onCreate(final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(activity);
|
final SharedPreferences preferences
|
||||||
|
= PreferenceManager.getDefaultSharedPreferences(activity);
|
||||||
isSuggestionsEnabled = preferences
|
isSuggestionsEnabled = preferences
|
||||||
.getBoolean(getString(R.string.show_search_suggestions_key), true);
|
.getBoolean(getString(R.string.show_search_suggestions_key), true);
|
||||||
contentCountry = preferences.getString(getString(R.string.content_country_key),
|
contentCountry = preferences.getString(getString(R.string.content_country_key),
|
||||||
@ -246,7 +248,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
service = NewPipe.getService(serviceId);
|
service = NewPipe.getService(serviceId);
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportError(getActivity(), e, getActivity().getClass(),
|
ErrorActivity.reportError(getActivity(), e, getActivity().getClass(),
|
||||||
getActivity().findViewById(android.R.id.content),
|
getActivity().findViewById(android.R.id.content),
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
ErrorActivity.ErrorInfo.make(UserAction.UI_ERROR,
|
||||||
@ -413,7 +415,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
public void onCreateOptionsMenu(final Menu menu, final MenuInflater inflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater);
|
super.onCreateOptionsMenu(menu, inflater);
|
||||||
|
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (supportActionBar != null) {
|
if (supportActionBar != null) {
|
||||||
supportActionBar.setDisplayShowTitleEnabled(false);
|
supportActionBar.setDisplayShowTitleEnabled(false);
|
||||||
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
supportActionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
@ -424,16 +426,16 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
int itemId = 0;
|
int itemId = 0;
|
||||||
boolean isFirstItem = true;
|
boolean isFirstItem = true;
|
||||||
final Context c = getContext();
|
final Context c = getContext();
|
||||||
for (String filter : service.getSearchQHFactory().getAvailableContentFilter()) {
|
for (final String filter : service.getSearchQHFactory().getAvailableContentFilter()) {
|
||||||
if (filter.equals("music_songs")) {
|
if (filter.equals("music_songs")) {
|
||||||
MenuItem musicItem = menu.add(2,
|
final MenuItem musicItem = menu.add(2,
|
||||||
itemId++,
|
itemId++,
|
||||||
0,
|
0,
|
||||||
"YouTube Music");
|
"YouTube Music");
|
||||||
musicItem.setEnabled(false);
|
musicItem.setEnabled(false);
|
||||||
}
|
}
|
||||||
menuItemToFilterName.put(itemId, filter);
|
menuItemToFilterName.put(itemId, filter);
|
||||||
MenuItem item = menu.add(1,
|
final MenuItem item = menu.add(1,
|
||||||
itemId++,
|
itemId++,
|
||||||
0,
|
0,
|
||||||
ServiceHelper.getTranslatedFilterString(filter, c));
|
ServiceHelper.getTranslatedFilterString(filter, c));
|
||||||
@ -449,7 +451,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
List<String> cf = new ArrayList<>(1);
|
final List<String> cf = new ArrayList<>(1);
|
||||||
cf.add(menuItemToFilterName.get(item.getItemId()));
|
cf.add(menuItemToFilterName.get(item.getItemId()));
|
||||||
changeContentFilter(item, cf);
|
changeContentFilter(item, cf);
|
||||||
|
|
||||||
@ -458,7 +460,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|
|
||||||
private void restoreFilterChecked(final Menu menu, final int itemId) {
|
private void restoreFilterChecked(final Menu menu, final int itemId) {
|
||||||
if (itemId != -1) {
|
if (itemId != -1) {
|
||||||
MenuItem item = menu.findItem(itemId);
|
final MenuItem item = menu.findItem(itemId);
|
||||||
if (item == null) {
|
if (item == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -505,7 +507,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
Log.d(TAG, "onClick() called with: v = [" + v + "]");
|
||||||
}
|
}
|
||||||
if (TextUtils.isEmpty(searchEditText.getText())) {
|
if (TextUtils.isEmpty(searchEditText.getText())) {
|
||||||
NavigationHelper.gotoMainFragment(getFragmentManager());
|
NavigationHelper.gotoMainFragment(getFM());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -578,7 +580,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterTextChanged(final Editable s) {
|
public void afterTextChanged(final Editable s) {
|
||||||
String newText = searchEditText.getText().toString();
|
final String newText = searchEditText.getText().toString();
|
||||||
suggestionPublisher.onNext(newText);
|
suggestionPublisher.onNext(newText);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -644,7 +646,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (searchEditText.requestFocus()) {
|
if (searchEditText.requestFocus()) {
|
||||||
InputMethodManager imm = (InputMethodManager) activity.getSystemService(
|
final InputMethodManager imm = (InputMethodManager) activity.getSystemService(
|
||||||
Context.INPUT_METHOD_SERVICE);
|
Context.INPUT_METHOD_SERVICE);
|
||||||
imm.showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED);
|
imm.showSoftInput(searchEditText, InputMethodManager.SHOW_FORCED);
|
||||||
}
|
}
|
||||||
@ -658,7 +660,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
InputMethodManager imm = (InputMethodManager) activity
|
final InputMethodManager imm = (InputMethodManager) activity
|
||||||
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
.getSystemService(Context.INPUT_METHOD_SERVICE);
|
||||||
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(),
|
imm.hideSoftInputFromWindow(searchEditText.getWindowToken(),
|
||||||
InputMethodManager.RESULT_UNCHANGED_SHOWN);
|
InputMethodManager.RESULT_UNCHANGED_SHOWN);
|
||||||
@ -725,8 +727,8 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
.getRelatedSearches(query, 3, 25);
|
.getRelatedSearches(query, 3, 25);
|
||||||
final Observable<List<SuggestionItem>> local = flowable.toObservable()
|
final Observable<List<SuggestionItem>> local = flowable.toObservable()
|
||||||
.map(searchHistoryEntries -> {
|
.map(searchHistoryEntries -> {
|
||||||
List<SuggestionItem> result = new ArrayList<>();
|
final List<SuggestionItem> result = new ArrayList<>();
|
||||||
for (SearchHistoryEntry entry : searchHistoryEntries) {
|
for (final SearchHistoryEntry entry : searchHistoryEntries) {
|
||||||
result.add(new SuggestionItem(true, entry.getSearch()));
|
result.add(new SuggestionItem(true, entry.getSearch()));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
@ -742,15 +744,15 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
.suggestionsFor(serviceId, query)
|
.suggestionsFor(serviceId, query)
|
||||||
.toObservable()
|
.toObservable()
|
||||||
.map(strings -> {
|
.map(strings -> {
|
||||||
List<SuggestionItem> result = new ArrayList<>();
|
final List<SuggestionItem> result = new ArrayList<>();
|
||||||
for (String entry : strings) {
|
for (final String entry : strings) {
|
||||||
result.add(new SuggestionItem(false, entry));
|
result.add(new SuggestionItem(false, entry));
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
return Observable.zip(local, network, (localResult, networkResult) -> {
|
return Observable.zip(local, network, (localResult, networkResult) -> {
|
||||||
List<SuggestionItem> result = new ArrayList<>();
|
final List<SuggestionItem> result = new ArrayList<>();
|
||||||
if (localResult.size() > 0) {
|
if (localResult.size() > 0) {
|
||||||
result.addAll(localResult);
|
result.addAll(localResult);
|
||||||
}
|
}
|
||||||
@ -759,7 +761,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
final Iterator<SuggestionItem> iterator = networkResult.iterator();
|
final Iterator<SuggestionItem> iterator = networkResult.iterator();
|
||||||
while (iterator.hasNext() && localResult.size() > 0) {
|
while (iterator.hasNext() && localResult.size() > 0) {
|
||||||
final SuggestionItem next = iterator.next();
|
final SuggestionItem next = iterator.next();
|
||||||
for (SuggestionItem item : localResult) {
|
for (final SuggestionItem item : localResult) {
|
||||||
if (item.query.equals(next.query)) {
|
if (item.query.equals(next.query)) {
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
break;
|
break;
|
||||||
@ -807,13 +809,13 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe(intent -> {
|
.subscribe(intent -> {
|
||||||
getFragmentManager().popBackStackImmediate();
|
getFM().popBackStackImmediate();
|
||||||
activity.startActivity(intent);
|
activity.startActivity(intent);
|
||||||
}, throwable ->
|
}, throwable ->
|
||||||
showError(getString(R.string.url_not_supported_toast), false)));
|
showError(getString(R.string.url_not_supported_toast), false)));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
// Exception occurred, it's not a url
|
// Exception occurred, it's not a url
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -935,7 +937,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int errorId = exception instanceof ParsingException
|
final int errorId = exception instanceof ParsingException
|
||||||
? R.string.parsing_error
|
? R.string.parsing_error
|
||||||
: R.string.general_error;
|
: R.string.general_error;
|
||||||
onUnrecoverableError(exception, UserAction.GET_SUGGESTIONS,
|
onUnrecoverableError(exception, UserAction.GET_SUGGESTIONS,
|
||||||
@ -1051,7 +1053,7 @@ public class SearchFragment extends BaseListFragment<SearchInfo, ListExtractor.I
|
|||||||
infoListAdapter.clearStreamItemList();
|
infoListAdapter.clearStreamItemList();
|
||||||
showEmptyState();
|
showEmptyState();
|
||||||
} else {
|
} else {
|
||||||
int errorId = exception instanceof ParsingException
|
final int errorId = exception instanceof ParsingException
|
||||||
? R.string.parsing_error
|
? R.string.parsing_error
|
||||||
: R.string.general_error;
|
: R.string.general_error;
|
||||||
onUnrecoverableError(exception, UserAction.SEARCHED,
|
onUnrecoverableError(exception, UserAction.SEARCHED,
|
||||||
|
@ -33,7 +33,7 @@ public class SuggestionListAdapter
|
|||||||
this.items.addAll(items);
|
this.items.addAll(items);
|
||||||
} else {
|
} else {
|
||||||
// remove history items if history is disabled
|
// remove history items if history is disabled
|
||||||
for (SuggestionItem item : items) {
|
for (final SuggestionItem item : items) {
|
||||||
if (!item.fromHistory) {
|
if (!item.fromHistory) {
|
||||||
this.items.add(item);
|
this.items.add(item);
|
||||||
}
|
}
|
||||||
@ -123,8 +123,8 @@ public class SuggestionListAdapter
|
|||||||
|
|
||||||
private static int resolveResourceIdFromAttr(final Context context,
|
private static int resolveResourceIdFromAttr(final Context context,
|
||||||
@AttrRes final int attr) {
|
@AttrRes final int attr) {
|
||||||
TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr});
|
final TypedArray a = context.getTheme().obtainStyledAttributes(new int[]{attr});
|
||||||
int attributeResourceId = a.getResourceId(0, 0);
|
final int attributeResourceId = a.getResourceId(0, 0);
|
||||||
a.recycle();
|
a.recycle();
|
||||||
return attributeResourceId;
|
return attributeResourceId;
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
|||||||
private Switch autoplaySwitch;
|
private Switch autoplaySwitch;
|
||||||
|
|
||||||
public static RelatedVideosFragment getInstance(final StreamInfo info) {
|
public static RelatedVideosFragment getInstance(final StreamInfo info) {
|
||||||
RelatedVideosFragment instance = new RelatedVideosFragment();
|
final RelatedVideosFragment instance = new RelatedVideosFragment();
|
||||||
instance.setInitialData(info);
|
instance.setInitialData(info);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
|||||||
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
|
protected void onRestoreInstanceState(@NonNull final Bundle savedState) {
|
||||||
super.onRestoreInstanceState(savedState);
|
super.onRestoreInstanceState(savedState);
|
||||||
if (savedState != null) {
|
if (savedState != null) {
|
||||||
Serializable serializable = savedState.getSerializable(INFO_KEY);
|
final Serializable serializable = savedState.getSerializable(INFO_KEY);
|
||||||
if (serializable instanceof RelatedStreamInfo) {
|
if (serializable instanceof RelatedStreamInfo) {
|
||||||
this.relatedStreamInfo = (RelatedStreamInfo) serializable;
|
this.relatedStreamInfo = (RelatedStreamInfo) serializable;
|
||||||
}
|
}
|
||||||
@ -201,8 +201,8 @@ public class RelatedVideosFragment extends BaseListInfoFragment<RelatedStreamInf
|
|||||||
@Override
|
@Override
|
||||||
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
|
public void onSharedPreferenceChanged(final SharedPreferences sharedPreferences,
|
||||||
final String s) {
|
final String s) {
|
||||||
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
final SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false);
|
final boolean autoplay = pref.getBoolean(getString(R.string.auto_queue_key), false);
|
||||||
if (autoplaySwitch != null) {
|
if (autoplaySwitch != null) {
|
||||||
autoplaySwitch.setChecked(autoplay);
|
autoplaySwitch.setChecked(autoplay);
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,8 @@ public class InfoItemBuilder {
|
|||||||
public View buildView(@NonNull final ViewGroup parent, @NonNull final InfoItem infoItem,
|
public View buildView(@NonNull final ViewGroup parent, @NonNull final InfoItem infoItem,
|
||||||
final HistoryRecordManager historyRecordManager,
|
final HistoryRecordManager historyRecordManager,
|
||||||
final boolean useMiniVariant) {
|
final boolean useMiniVariant) {
|
||||||
InfoItemHolder holder = holderFromInfoType(parent, infoItem.getInfoType(), useMiniVariant);
|
final InfoItemHolder holder
|
||||||
|
= holderFromInfoType(parent, infoItem.getInfoType(), useMiniVariant);
|
||||||
holder.updateFromItem(infoItem, historyRecordManager);
|
holder.updateFromItem(infoItem, historyRecordManager);
|
||||||
return holder.itemView;
|
return holder.itemView;
|
||||||
}
|
}
|
||||||
|
@ -31,10 +31,10 @@ public class InfoItemDialog {
|
|||||||
final View bannerView = View.inflate(activity, R.layout.dialog_title, null);
|
final View bannerView = View.inflate(activity, R.layout.dialog_title, null);
|
||||||
bannerView.setSelected(true);
|
bannerView.setSelected(true);
|
||||||
|
|
||||||
TextView titleView = bannerView.findViewById(R.id.itemTitleView);
|
final TextView titleView = bannerView.findViewById(R.id.itemTitleView);
|
||||||
titleView.setText(title);
|
titleView.setText(title);
|
||||||
|
|
||||||
TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails);
|
final TextView detailsView = bannerView.findViewById(R.id.itemAdditionalDetails);
|
||||||
if (additionalDetail != null) {
|
if (additionalDetail != null) {
|
||||||
detailsView.setText(additionalDetail);
|
detailsView.setText(additionalDetail);
|
||||||
detailsView.setVisibility(View.VISIBLE);
|
detailsView.setVisibility(View.VISIBLE);
|
||||||
|
@ -123,7 +123,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
+ infoItemList.size() + ", data.size() = " + data.size());
|
+ infoItemList.size() + ", data.size() = " + data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int offsetStart = sizeConsideringHeaderOffset();
|
final int offsetStart = sizeConsideringHeaderOffset();
|
||||||
infoItemList.addAll(data);
|
infoItemList.addAll(data);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -135,7 +135,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
notifyItemRangeInserted(offsetStart, data.size());
|
notifyItemRangeInserted(offsetStart, data.size());
|
||||||
|
|
||||||
if (footer != null && showFooter) {
|
if (footer != null && showFooter) {
|
||||||
int footerNow = sizeConsideringHeaderOffset();
|
final int footerNow = sizeConsideringHeaderOffset();
|
||||||
notifyItemMoved(offsetStart, footerNow);
|
notifyItemMoved(offsetStart, footerNow);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -160,7 +160,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
+ infoItemList.size() + ", thread = " + Thread.currentThread());
|
+ infoItemList.size() + ", thread = " + Thread.currentThread());
|
||||||
}
|
}
|
||||||
|
|
||||||
int positionInserted = sizeConsideringHeaderOffset();
|
final int positionInserted = sizeConsideringHeaderOffset();
|
||||||
infoItemList.add(data);
|
infoItemList.add(data);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -172,7 +172,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
notifyItemInserted(positionInserted);
|
notifyItemInserted(positionInserted);
|
||||||
|
|
||||||
if (footer != null && showFooter) {
|
if (footer != null && showFooter) {
|
||||||
int footerNow = sizeConsideringHeaderOffset();
|
final int footerNow = sizeConsideringHeaderOffset();
|
||||||
notifyItemMoved(positionInserted, footerNow);
|
notifyItemMoved(positionInserted, footerNow);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -191,7 +191,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setHeader(final View header) {
|
public void setHeader(final View header) {
|
||||||
boolean changed = header != this.header;
|
final boolean changed = header != this.header;
|
||||||
this.header = header;
|
this.header = header;
|
||||||
if (changed) {
|
if (changed) {
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
@ -219,7 +219,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int sizeConsideringHeaderOffset() {
|
private int sizeConsideringHeaderOffset() {
|
||||||
int i = infoItemList.size() + (header != null ? 1 : 0);
|
final int i = infoItemList.size() + (header != null ? 1 : 0);
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "sizeConsideringHeaderOffset() called → " + i);
|
Log.d(TAG, "sizeConsideringHeaderOffset() called → " + i);
|
||||||
}
|
}
|
||||||
@ -347,7 +347,7 @@ public class InfoListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolde
|
|||||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position,
|
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position,
|
||||||
@NonNull final List<Object> payloads) {
|
@NonNull final List<Object> payloads) {
|
||||||
if (!payloads.isEmpty() && holder instanceof InfoItemHolder) {
|
if (!payloads.isEmpty() && holder instanceof InfoItemHolder) {
|
||||||
for (Object payload : payloads) {
|
for (final Object payload : payloads) {
|
||||||
if (payload instanceof StreamStateEntity) {
|
if (payload instanceof StreamStateEntity) {
|
||||||
((InfoItemHolder) holder).updateState(infoItemList
|
((InfoItemHolder) holder).updateState(infoItemList
|
||||||
.get(header == null ? position : position - 1), recordManager);
|
.get(header == null ? position : position - 1), recordManager);
|
||||||
|
@ -56,8 +56,8 @@ public class ChannelInfoItemHolder extends ChannelMiniInfoItemHolder {
|
|||||||
String details = super.getDetailLine(item);
|
String details = super.getDetailLine(item);
|
||||||
|
|
||||||
if (item.getStreamCount() >= 0) {
|
if (item.getStreamCount() >= 0) {
|
||||||
String formattedVideoAmount = Localization.localizeStreamCount(itemBuilder.getContext(),
|
final String formattedVideoAmount = Localization.localizeStreamCount(
|
||||||
item.getStreamCount());
|
itemBuilder.getContext(), item.getStreamCount());
|
||||||
|
|
||||||
if (!details.isEmpty()) {
|
if (!details.isEmpty()) {
|
||||||
details += " • " + formattedVideoAmount;
|
details += " • " + formattedVideoAmount;
|
||||||
|
@ -45,9 +45,9 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
@Override
|
@Override
|
||||||
public String transformUrl(final Matcher match, final String url) {
|
public String transformUrl(final Matcher match, final String url) {
|
||||||
int timestamp = 0;
|
int timestamp = 0;
|
||||||
String hours = match.group(1);
|
final String hours = match.group(1);
|
||||||
String minutes = match.group(2);
|
final String minutes = match.group(2);
|
||||||
String seconds = match.group(3);
|
final String seconds = match.group(3);
|
||||||
if (hours != null) {
|
if (hours != null) {
|
||||||
timestamp += (Integer.parseInt(hours.replace(":", "")) * 3600);
|
timestamp += (Integer.parseInt(hours.replace(":", "")) * 3600);
|
||||||
}
|
}
|
||||||
@ -146,7 +146,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
item.getServiceId(),
|
item.getServiceId(),
|
||||||
item.getUploaderUrl(),
|
item.getUploaderUrl(),
|
||||||
item.getUploaderName());
|
item.getUploaderName());
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
|
ErrorActivity.reportUiError((AppCompatActivity) itemBuilder.getContext(), e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -164,7 +164,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
URLSpan[] urls = itemContentView.getUrls();
|
final URLSpan[] urls = itemContentView.getUrls();
|
||||||
|
|
||||||
return urls != null && urls.length != 0;
|
return urls != null && urls.length != 0;
|
||||||
}
|
}
|
||||||
@ -181,12 +181,13 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
boolean hasEllipsis = false;
|
boolean hasEllipsis = false;
|
||||||
|
|
||||||
if (itemContentView.getLineCount() > COMMENT_DEFAULT_LINES) {
|
if (itemContentView.getLineCount() > COMMENT_DEFAULT_LINES) {
|
||||||
int endOfLastLine = itemContentView.getLayout().getLineEnd(COMMENT_DEFAULT_LINES - 1);
|
final int endOfLastLine
|
||||||
|
= itemContentView.getLayout().getLineEnd(COMMENT_DEFAULT_LINES - 1);
|
||||||
int end = itemContentView.getText().toString().lastIndexOf(' ', endOfLastLine - 2);
|
int end = itemContentView.getText().toString().lastIndexOf(' ', endOfLastLine - 2);
|
||||||
if (end == -1) {
|
if (end == -1) {
|
||||||
end = Math.max(endOfLastLine - 2, 0);
|
end = Math.max(endOfLastLine - 2, 0);
|
||||||
}
|
}
|
||||||
String newVal = itemContentView.getText().subSequence(0, end) + " …";
|
final String newVal = itemContentView.getText().subSequence(0, end) + " …";
|
||||||
itemContentView.setText(newVal);
|
itemContentView.setText(newVal);
|
||||||
hasEllipsis = true;
|
hasEllipsis = true;
|
||||||
}
|
}
|
||||||
|
@ -60,7 +60,7 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
R.color.duration_background_color));
|
R.color.duration_background_color));
|
||||||
itemDurationView.setVisibility(View.VISIBLE);
|
itemDurationView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
StreamStateEntity state2 = historyRecordManager.loadStreamState(infoItem)
|
final StreamStateEntity state2 = historyRecordManager.loadStreamState(infoItem)
|
||||||
.blockingGet()[0];
|
.blockingGet()[0];
|
||||||
if (state2 != null) {
|
if (state2 != null) {
|
||||||
itemProgressView.setVisibility(View.VISIBLE);
|
itemProgressView.setVisibility(View.VISIBLE);
|
||||||
@ -113,7 +113,8 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
|
|||||||
final HistoryRecordManager historyRecordManager) {
|
final HistoryRecordManager historyRecordManager) {
|
||||||
final StreamInfoItem item = (StreamInfoItem) infoItem;
|
final StreamInfoItem item = (StreamInfoItem) infoItem;
|
||||||
|
|
||||||
StreamStateEntity state = historyRecordManager.loadStreamState(infoItem).blockingGet()[0];
|
final StreamStateEntity state
|
||||||
|
= historyRecordManager.loadStreamState(infoItem).blockingGet()[0];
|
||||||
if (state != null && item.getDuration() > 0
|
if (state != null && item.getDuration() > 0
|
||||||
&& item.getStreamType() != StreamType.LIVE_STREAM) {
|
&& item.getStreamType() != StreamType.LIVE_STREAM) {
|
||||||
itemProgressView.setMax((int) item.getDuration());
|
itemProgressView.setMax((int) item.getDuration());
|
||||||
|
@ -101,7 +101,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
+ localItems.size() + ", data.size() = " + data.size());
|
+ localItems.size() + ", data.size() = " + data.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
int offsetStart = sizeConsideringHeader();
|
final int offsetStart = sizeConsideringHeader();
|
||||||
localItems.addAll(data);
|
localItems.addAll(data);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -113,7 +113,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
notifyItemRangeInserted(offsetStart, data.size());
|
notifyItemRangeInserted(offsetStart, data.size());
|
||||||
|
|
||||||
if (footer != null && showFooter) {
|
if (footer != null && showFooter) {
|
||||||
int footerNow = sizeConsideringHeader();
|
final int footerNow = sizeConsideringHeader();
|
||||||
notifyItemMoved(offsetStart, footerNow);
|
notifyItemMoved(offsetStart, footerNow);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -158,7 +158,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void setHeader(final View header) {
|
public void setHeader(final View header) {
|
||||||
boolean changed = header != this.header;
|
final boolean changed = header != this.header;
|
||||||
this.header = header;
|
this.header = header;
|
||||||
if (changed) {
|
if (changed) {
|
||||||
notifyDataSetChanged();
|
notifyDataSetChanged();
|
||||||
@ -316,7 +316,7 @@ public class LocalItemListAdapter extends RecyclerView.Adapter<RecyclerView.View
|
|||||||
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position,
|
public void onBindViewHolder(@NonNull final RecyclerView.ViewHolder holder, final int position,
|
||||||
@NonNull final List<Object> payloads) {
|
@NonNull final List<Object> payloads) {
|
||||||
if (!payloads.isEmpty() && holder instanceof LocalItemHolder) {
|
if (!payloads.isEmpty() && holder instanceof LocalItemHolder) {
|
||||||
for (Object payload : payloads) {
|
for (final Object payload : payloads) {
|
||||||
if (payload instanceof StreamStateEntity) {
|
if (payload instanceof StreamStateEntity) {
|
||||||
((LocalItemHolder) holder).updateState(localItems
|
((LocalItemHolder) holder).updateState(localItems
|
||||||
.get(header == null ? position : position - 1), recordManager);
|
.get(header == null ? position : position - 1), recordManager);
|
||||||
|
@ -265,11 +265,11 @@ public final class BookmarkFragment extends BaseLocalListFragment<List<PlaylistL
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void showLocalDialog(final PlaylistMetadataEntry selectedItem) {
|
private void showLocalDialog(final PlaylistMetadataEntry selectedItem) {
|
||||||
View dialogView = View.inflate(getContext(), R.layout.dialog_bookmark, null);
|
final View dialogView = View.inflate(getContext(), R.layout.dialog_bookmark, null);
|
||||||
EditText editText = dialogView.findViewById(R.id.playlist_name_edit_text);
|
final EditText editText = dialogView.findViewById(R.id.playlist_name_edit_text);
|
||||||
editText.setText(selectedItem.name);
|
editText.setText(selectedItem.name);
|
||||||
|
|
||||||
Builder builder = new AlertDialog.Builder(activity);
|
final Builder builder = new AlertDialog.Builder(activity);
|
||||||
builder.setView(dialogView)
|
builder.setView(dialogView)
|
||||||
.setPositiveButton(R.string.rename_playlist, (dialog, which) -> {
|
.setPositiveButton(R.string.rename_playlist, (dialog, which) -> {
|
||||||
changeLocalPlaylistName(selectedItem.uid, editText.getText().toString());
|
changeLocalPlaylistName(selectedItem.uid, editText.getText().toString());
|
||||||
|
@ -39,14 +39,14 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
|||||||
private CompositeDisposable playlistDisposables = new CompositeDisposable();
|
private CompositeDisposable playlistDisposables = new CompositeDisposable();
|
||||||
|
|
||||||
public static PlaylistAppendDialog fromStreamInfo(final StreamInfo info) {
|
public static PlaylistAppendDialog fromStreamInfo(final StreamInfo info) {
|
||||||
PlaylistAppendDialog dialog = new PlaylistAppendDialog();
|
final PlaylistAppendDialog dialog = new PlaylistAppendDialog();
|
||||||
dialog.setInfo(Collections.singletonList(new StreamEntity(info)));
|
dialog.setInfo(Collections.singletonList(new StreamEntity(info)));
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static PlaylistAppendDialog fromStreamInfoItems(final List<StreamInfoItem> items) {
|
public static PlaylistAppendDialog fromStreamInfoItems(final List<StreamInfoItem> items) {
|
||||||
PlaylistAppendDialog dialog = new PlaylistAppendDialog();
|
final PlaylistAppendDialog dialog = new PlaylistAppendDialog();
|
||||||
List<StreamEntity> entities = new ArrayList<>(items.size());
|
final List<StreamEntity> entities = new ArrayList<>(items.size());
|
||||||
for (final StreamInfoItem item : items) {
|
for (final StreamInfoItem item : items) {
|
||||||
entities.add(new StreamEntity(item));
|
entities.add(new StreamEntity(item));
|
||||||
}
|
}
|
||||||
@ -55,8 +55,8 @@ public final class PlaylistAppendDialog extends PlaylistDialog {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static PlaylistAppendDialog fromPlayQueueItems(final List<PlayQueueItem> items) {
|
public static PlaylistAppendDialog fromPlayQueueItems(final List<PlayQueueItem> items) {
|
||||||
PlaylistAppendDialog dialog = new PlaylistAppendDialog();
|
final PlaylistAppendDialog dialog = new PlaylistAppendDialog();
|
||||||
List<StreamEntity> entities = new ArrayList<>(items.size());
|
final List<StreamEntity> entities = new ArrayList<>(items.size());
|
||||||
for (final PlayQueueItem item : items) {
|
for (final PlayQueueItem item : items) {
|
||||||
entities.add(new StreamEntity(item));
|
entities.add(new StreamEntity(item));
|
||||||
}
|
}
|
||||||
|
@ -21,7 +21,7 @@ import io.reactivex.android.schedulers.AndroidSchedulers;
|
|||||||
|
|
||||||
public final class PlaylistCreationDialog extends PlaylistDialog {
|
public final class PlaylistCreationDialog extends PlaylistDialog {
|
||||||
public static PlaylistCreationDialog newInstance(final List<StreamEntity> streams) {
|
public static PlaylistCreationDialog newInstance(final List<StreamEntity> streams) {
|
||||||
PlaylistCreationDialog dialog = new PlaylistCreationDialog();
|
final PlaylistCreationDialog dialog = new PlaylistCreationDialog();
|
||||||
dialog.setInfo(streams);
|
dialog.setInfo(streams);
|
||||||
return dialog;
|
return dialog;
|
||||||
}
|
}
|
||||||
@ -37,8 +37,8 @@ public final class PlaylistCreationDialog extends PlaylistDialog {
|
|||||||
return super.onCreateDialog(savedInstanceState);
|
return super.onCreateDialog(savedInstanceState);
|
||||||
}
|
}
|
||||||
|
|
||||||
View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null);
|
final View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null);
|
||||||
EditText nameInput = dialogView.findViewById(R.id.playlist_name);
|
final EditText nameInput = dialogView.findViewById(R.id.playlist_name);
|
||||||
|
|
||||||
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext())
|
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(getContext())
|
||||||
.setTitle(R.string.create_playlist)
|
.setTitle(R.string.create_playlist)
|
||||||
|
@ -88,7 +88,7 @@ public class HistoryRecordManager {
|
|||||||
final Date currentTime = new Date();
|
final Date currentTime = new Date();
|
||||||
return Maybe.fromCallable(() -> database.runInTransaction(() -> {
|
return Maybe.fromCallable(() -> database.runInTransaction(() -> {
|
||||||
final long streamId = streamTable.upsert(new StreamEntity(info));
|
final long streamId = streamTable.upsert(new StreamEntity(info));
|
||||||
StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(streamId);
|
final StreamHistoryEntity latestEntry = streamHistoryTable.getLatestEntry(streamId);
|
||||||
|
|
||||||
if (latestEntry != null) {
|
if (latestEntry != null) {
|
||||||
streamHistoryTable.delete(latestEntry);
|
streamHistoryTable.delete(latestEntry);
|
||||||
@ -129,7 +129,7 @@ public class HistoryRecordManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Single<List<Long>> insertStreamHistory(final Collection<StreamHistoryEntry> entries) {
|
public Single<List<Long>> insertStreamHistory(final Collection<StreamHistoryEntry> entries) {
|
||||||
List<StreamHistoryEntity> entities = new ArrayList<>(entries.size());
|
final List<StreamHistoryEntity> entities = new ArrayList<>(entries.size());
|
||||||
for (final StreamHistoryEntry entry : entries) {
|
for (final StreamHistoryEntry entry : entries) {
|
||||||
entities.add(entry.toStreamHistoryEntity());
|
entities.add(entry.toStreamHistoryEntity());
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ public class HistoryRecordManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Single<Integer> deleteStreamHistory(final Collection<StreamHistoryEntry> entries) {
|
public Single<Integer> deleteStreamHistory(final Collection<StreamHistoryEntry> entries) {
|
||||||
List<StreamHistoryEntity> entities = new ArrayList<>(entries.size());
|
final List<StreamHistoryEntity> entities = new ArrayList<>(entries.size());
|
||||||
for (final StreamHistoryEntry entry : entries) {
|
for (final StreamHistoryEntry entry : entries) {
|
||||||
entities.add(entry.toStreamHistoryEntity());
|
entities.add(entry.toStreamHistoryEntity());
|
||||||
}
|
}
|
||||||
@ -163,7 +163,7 @@ public class HistoryRecordManager {
|
|||||||
final SearchHistoryEntry newEntry = new SearchHistoryEntry(currentTime, serviceId, search);
|
final SearchHistoryEntry newEntry = new SearchHistoryEntry(currentTime, serviceId, search);
|
||||||
|
|
||||||
return Maybe.fromCallable(() -> database.runInTransaction(() -> {
|
return Maybe.fromCallable(() -> database.runInTransaction(() -> {
|
||||||
SearchHistoryEntry latestEntry = searchHistoryTable.getLatestEntry();
|
final SearchHistoryEntry latestEntry = searchHistoryTable.getLatestEntry();
|
||||||
if (latestEntry != null && latestEntry.hasEqualValues(newEntry)) {
|
if (latestEntry != null && latestEntry.hasEqualValues(newEntry)) {
|
||||||
latestEntry.setCreationDate(currentTime);
|
latestEntry.setCreationDate(currentTime);
|
||||||
return (long) searchHistoryTable.update(latestEntry);
|
return (long) searchHistoryTable.update(latestEntry);
|
||||||
@ -256,7 +256,7 @@ public class HistoryRecordManager {
|
|||||||
public Single<List<StreamStateEntity>> loadStreamStateBatch(final List<InfoItem> infos) {
|
public Single<List<StreamStateEntity>> loadStreamStateBatch(final List<InfoItem> infos) {
|
||||||
return Single.fromCallable(() -> {
|
return Single.fromCallable(() -> {
|
||||||
final List<StreamStateEntity> result = new ArrayList<>(infos.size());
|
final List<StreamStateEntity> result = new ArrayList<>(infos.size());
|
||||||
for (InfoItem info : infos) {
|
for (final InfoItem info : infos) {
|
||||||
final List<StreamEntity> entities = streamTable
|
final List<StreamEntity> entities = streamTable
|
||||||
.getStream(info.getServiceId(), info.getUrl()).blockingFirst();
|
.getStream(info.getServiceId(), info.getUrl()).blockingFirst();
|
||||||
if (entities.isEmpty()) {
|
if (entities.isEmpty()) {
|
||||||
@ -279,8 +279,8 @@ public class HistoryRecordManager {
|
|||||||
final List<? extends LocalItem> items) {
|
final List<? extends LocalItem> items) {
|
||||||
return Single.fromCallable(() -> {
|
return Single.fromCallable(() -> {
|
||||||
final List<StreamStateEntity> result = new ArrayList<>(items.size());
|
final List<StreamStateEntity> result = new ArrayList<>(items.size());
|
||||||
for (LocalItem item : items) {
|
for (final LocalItem item : items) {
|
||||||
long streamId;
|
final long streamId;
|
||||||
if (item instanceof StreamStatisticsEntry) {
|
if (item instanceof StreamStatisticsEntry) {
|
||||||
streamId = ((StreamStatisticsEntry) item).getStreamId();
|
streamId = ((StreamStatisticsEntry) item).getStreamId();
|
||||||
} else if (item instanceof PlaylistStreamEntity) {
|
} else if (item instanceof PlaylistStreamEntity) {
|
||||||
|
@ -455,7 +455,7 @@ public class StatisticsPlaylistFragment
|
|||||||
}
|
}
|
||||||
|
|
||||||
final List<LocalItem> infoItems = itemListAdapter.getItemsList();
|
final List<LocalItem> infoItems = itemListAdapter.getItemsList();
|
||||||
List<StreamInfoItem> streamInfoItems = new ArrayList<>(infoItems.size());
|
final List<StreamInfoItem> streamInfoItems = new ArrayList<>(infoItems.size());
|
||||||
for (final LocalItem item : infoItems) {
|
for (final LocalItem item : infoItems) {
|
||||||
if (item instanceof StreamStatisticsEntry) {
|
if (item instanceof StreamStatisticsEntry) {
|
||||||
streamInfoItems.add(((StreamStatisticsEntry) item).toStreamInfoItem());
|
streamInfoItems.add(((StreamStatisticsEntry) item).toStreamInfoItem());
|
||||||
|
@ -70,7 +70,7 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
|
|||||||
R.color.duration_background_color));
|
R.color.duration_background_color));
|
||||||
itemDurationView.setVisibility(View.VISIBLE);
|
itemDurationView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
StreamStateEntity state = historyRecordManager
|
final StreamStateEntity state = historyRecordManager
|
||||||
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
||||||
add(localItem);
|
add(localItem);
|
||||||
}}).blockingGet().get(0);
|
}}).blockingGet().get(0);
|
||||||
@ -116,7 +116,7 @@ public class LocalPlaylistStreamItemHolder extends LocalItemHolder {
|
|||||||
}
|
}
|
||||||
final PlaylistStreamEntry item = (PlaylistStreamEntry) localItem;
|
final PlaylistStreamEntry item = (PlaylistStreamEntry) localItem;
|
||||||
|
|
||||||
StreamStateEntity state = historyRecordManager
|
final StreamStateEntity state = historyRecordManager
|
||||||
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
||||||
add(localItem);
|
add(localItem);
|
||||||
}}).blockingGet().get(0);
|
}}).blockingGet().get(0);
|
||||||
|
@ -98,7 +98,7 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
|
|||||||
R.color.duration_background_color));
|
R.color.duration_background_color));
|
||||||
itemDurationView.setVisibility(View.VISIBLE);
|
itemDurationView.setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
StreamStateEntity state = historyRecordManager
|
final StreamStateEntity state = historyRecordManager
|
||||||
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
||||||
add(localItem);
|
add(localItem);
|
||||||
}}).blockingGet().get(0);
|
}}).blockingGet().get(0);
|
||||||
@ -146,7 +146,7 @@ public class LocalStatisticStreamItemHolder extends LocalItemHolder {
|
|||||||
}
|
}
|
||||||
final StreamStatisticsEntry item = (StreamStatisticsEntry) localItem;
|
final StreamStatisticsEntry item = (StreamStatisticsEntry) localItem;
|
||||||
|
|
||||||
StreamStateEntity state = historyRecordManager
|
final StreamStateEntity state = historyRecordManager
|
||||||
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
.loadLocalStreamStateBatch(new ArrayList<LocalItem>() {{
|
||||||
add(localItem);
|
add(localItem);
|
||||||
}}).blockingGet().get(0);
|
}}).blockingGet().get(0);
|
||||||
|
@ -98,7 +98,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
private boolean isRemovingWatched = false;
|
private boolean isRemovingWatched = false;
|
||||||
|
|
||||||
public static LocalPlaylistFragment getInstance(final long playlistId, final String name) {
|
public static LocalPlaylistFragment getInstance(final long playlistId, final String name) {
|
||||||
LocalPlaylistFragment instance = new LocalPlaylistFragment();
|
final LocalPlaylistFragment instance = new LocalPlaylistFragment();
|
||||||
instance.setInitialData(playlistId, name);
|
instance.setInitialData(playlistId, name);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
public void selected(final LocalItem selectedItem) {
|
public void selected(final LocalItem selectedItem) {
|
||||||
if (selectedItem instanceof PlaylistStreamEntry) {
|
if (selectedItem instanceof PlaylistStreamEntry) {
|
||||||
final PlaylistStreamEntry item = (PlaylistStreamEntry) selectedItem;
|
final PlaylistStreamEntry item = (PlaylistStreamEntry) selectedItem;
|
||||||
NavigationHelper.openVideoDetailFragment(getFragmentManager(),
|
NavigationHelper.openVideoDetailFragment(getFM(),
|
||||||
item.getStreamEntity().getServiceId(), item.getStreamEntity().getUrl(),
|
item.getStreamEntity().getServiceId(), item.getStreamEntity().getUrl(),
|
||||||
item.getStreamEntity().getTitle());
|
item.getStreamEntity().getTitle());
|
||||||
}
|
}
|
||||||
@ -411,7 +411,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
if (removePartiallyWatched) {
|
if (removePartiallyWatched) {
|
||||||
while (playlistIter.hasNext()) {
|
while (playlistIter.hasNext()) {
|
||||||
final PlaylistStreamEntry playlistItem = playlistIter.next();
|
final PlaylistStreamEntry playlistItem = playlistIter.next();
|
||||||
int indexInHistory = Collections.binarySearch(historyStreamIds,
|
final int indexInHistory = Collections.binarySearch(historyStreamIds,
|
||||||
playlistItem.getStreamId());
|
playlistItem.getStreamId());
|
||||||
|
|
||||||
if (indexInHistory < 0) {
|
if (indexInHistory < 0) {
|
||||||
@ -427,7 +427,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
.loadLocalStreamStateBatch(playlist).blockingGet().iterator();
|
.loadLocalStreamStateBatch(playlist).blockingGet().iterator();
|
||||||
|
|
||||||
while (playlistIter.hasNext()) {
|
while (playlistIter.hasNext()) {
|
||||||
PlaylistStreamEntry playlistItem = playlistIter.next();
|
final PlaylistStreamEntry playlistItem = playlistIter.next();
|
||||||
final int indexInHistory = Collections.binarySearch(historyStreamIds,
|
final int indexInHistory = Collections.binarySearch(historyStreamIds,
|
||||||
playlistItem.getStreamId());
|
playlistItem.getStreamId());
|
||||||
|
|
||||||
@ -544,7 +544,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
final View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null);
|
final View dialogView = View.inflate(getContext(), R.layout.dialog_playlist_name, null);
|
||||||
EditText nameEdit = dialogView.findViewById(R.id.playlist_name);
|
final EditText nameEdit = dialogView.findViewById(R.id.playlist_name);
|
||||||
nameEdit.setText(name);
|
nameEdit.setText(name);
|
||||||
nameEdit.setSelection(nameEdit.getText().length());
|
nameEdit.setSelection(nameEdit.getText().length());
|
||||||
|
|
||||||
@ -601,7 +601,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void updateThumbnailUrl() {
|
private void updateThumbnailUrl() {
|
||||||
String newThumbnailUrl;
|
final String newThumbnailUrl;
|
||||||
|
|
||||||
if (!itemListAdapter.getItemsList().isEmpty()) {
|
if (!itemListAdapter.getItemsList().isEmpty()) {
|
||||||
newThumbnailUrl = ((PlaylistStreamEntry) itemListAdapter.getItemsList().get(0))
|
newThumbnailUrl = ((PlaylistStreamEntry) itemListAdapter.getItemsList().get(0))
|
||||||
@ -662,7 +662,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
final List<LocalItem> items = itemListAdapter.getItemsList();
|
final List<LocalItem> items = itemListAdapter.getItemsList();
|
||||||
List<Long> streamIds = new ArrayList<>(items.size());
|
final List<Long> streamIds = new ArrayList<>(items.size());
|
||||||
for (final LocalItem item : items) {
|
for (final LocalItem item : items) {
|
||||||
if (item instanceof PlaylistStreamEntry) {
|
if (item instanceof PlaylistStreamEntry) {
|
||||||
streamIds.add(((PlaylistStreamEntry) item).getStreamId());
|
streamIds.add(((PlaylistStreamEntry) item).getStreamId());
|
||||||
@ -815,7 +815,7 @@ public class LocalPlaylistFragment extends BaseLocalListFragment<List<PlaylistSt
|
|||||||
}
|
}
|
||||||
|
|
||||||
final List<LocalItem> infoItems = itemListAdapter.getItemsList();
|
final List<LocalItem> infoItems = itemListAdapter.getItemsList();
|
||||||
List<StreamInfoItem> streamInfoItems = new ArrayList<>(infoItems.size());
|
final List<StreamInfoItem> streamInfoItems = new ArrayList<>(infoItems.size());
|
||||||
for (final LocalItem item : infoItems) {
|
for (final LocalItem item : infoItems) {
|
||||||
if (item instanceof PlaylistStreamEntry) {
|
if (item instanceof PlaylistStreamEntry) {
|
||||||
streamInfoItems.add(((PlaylistStreamEntry) item).toStreamInfoItem());
|
streamInfoItems.add(((PlaylistStreamEntry) item).toStreamInfoItem());
|
||||||
|
@ -61,7 +61,7 @@ public class LocalPlaylistManager {
|
|||||||
final List<StreamEntity> streams,
|
final List<StreamEntity> streams,
|
||||||
final int indexOffset) {
|
final int indexOffset) {
|
||||||
|
|
||||||
List<PlaylistStreamEntity> joinEntities = new ArrayList<>(streams.size());
|
final List<PlaylistStreamEntity> joinEntities = new ArrayList<>(streams.size());
|
||||||
final List<Long> streamIds = streamTable.upsertAll(streams);
|
final List<Long> streamIds = streamTable.upsertAll(streams);
|
||||||
for (int index = 0; index < streamIds.size(); index++) {
|
for (int index = 0; index < streamIds.size(); index++) {
|
||||||
joinEntities.add(new PlaylistStreamEntity(playlistId, streamIds.get(index),
|
joinEntities.add(new PlaylistStreamEntity(playlistId, streamIds.get(index),
|
||||||
@ -71,7 +71,7 @@ public class LocalPlaylistManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Completable updateJoin(final long playlistId, final List<Long> streamIds) {
|
public Completable updateJoin(final long playlistId, final List<Long> streamIds) {
|
||||||
List<PlaylistStreamEntity> joinEntities = new ArrayList<>(streamIds.size());
|
final List<PlaylistStreamEntity> joinEntities = new ArrayList<>(streamIds.size());
|
||||||
for (int i = 0; i < streamIds.size(); i++) {
|
for (int i = 0; i < streamIds.size(); i++) {
|
||||||
joinEntities.add(new PlaylistStreamEntity(playlistId, streamIds.get(i), i));
|
joinEntities.add(new PlaylistStreamEntity(playlistId, streamIds.get(i), i));
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ public class LocalPlaylistManager {
|
|||||||
.firstElement()
|
.firstElement()
|
||||||
.filter(playlistEntities -> !playlistEntities.isEmpty())
|
.filter(playlistEntities -> !playlistEntities.isEmpty())
|
||||||
.map(playlistEntities -> {
|
.map(playlistEntities -> {
|
||||||
PlaylistEntity playlist = playlistEntities.get(0);
|
final PlaylistEntity playlist = playlistEntities.get(0);
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
playlist.setName(name);
|
playlist.setName(name);
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public class RemotePlaylistManager {
|
|||||||
|
|
||||||
public Single<Integer> onUpdate(final long playlistId, final PlaylistInfo playlistInfo) {
|
public Single<Integer> onUpdate(final long playlistId, final PlaylistInfo playlistInfo) {
|
||||||
return Single.fromCallable(() -> {
|
return Single.fromCallable(() -> {
|
||||||
PlaylistRemoteEntity playlist = new PlaylistRemoteEntity(playlistInfo);
|
final PlaylistRemoteEntity playlist = new PlaylistRemoteEntity(playlistInfo);
|
||||||
playlist.setUid(playlistId);
|
playlist.setUid(playlistId);
|
||||||
return playlistRemoteTable.update(playlist);
|
return playlistRemoteTable.update(playlist);
|
||||||
}).subscribeOn(Schedulers.io());
|
}).subscribeOn(Schedulers.io());
|
||||||
|
@ -64,7 +64,7 @@ public class SubscriptionsImportFragment extends BaseFragment {
|
|||||||
private Button inputButton;
|
private Button inputButton;
|
||||||
|
|
||||||
public static SubscriptionsImportFragment getInstance(final int serviceId) {
|
public static SubscriptionsImportFragment getInstance(final int serviceId) {
|
||||||
SubscriptionsImportFragment instance = new SubscriptionsImportFragment();
|
final SubscriptionsImportFragment instance = new SubscriptionsImportFragment();
|
||||||
instance.setInitialData(serviceId);
|
instance.setInitialData(serviceId);
|
||||||
return instance;
|
return instance;
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ public class SubscriptionsImportFragment extends BaseFragment {
|
|||||||
setInfoText("");
|
setInfoText("");
|
||||||
}
|
}
|
||||||
|
|
||||||
ActionBar supportActionBar = activity.getSupportActionBar();
|
final ActionBar supportActionBar = activity.getSupportActionBar();
|
||||||
if (supportActionBar != null) {
|
if (supportActionBar != null) {
|
||||||
supportActionBar.setDisplayShowTitleEnabled(true);
|
supportActionBar.setDisplayShowTitleEnabled(true);
|
||||||
setTitle(getString(R.string.import_title));
|
setTitle(getString(R.string.import_title));
|
||||||
@ -206,7 +206,7 @@ public class SubscriptionsImportFragment extends BaseFragment {
|
|||||||
relatedUrl = extractor.getRelatedUrl();
|
relatedUrl = extractor.getRelatedUrl();
|
||||||
instructionsString = ServiceHelper.getImportInstructions(currentServiceId);
|
instructionsString = ServiceHelper.getImportInstructions(currentServiceId);
|
||||||
return;
|
return;
|
||||||
} catch (ExtractionException ignored) {
|
} catch (final ExtractionException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,12 +86,12 @@ public final class ImportExportJsonHelper {
|
|||||||
eventListener.onSizeReceived(channelsArray.size());
|
eventListener.onSizeReceived(channelsArray.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Object o : channelsArray) {
|
for (final Object o : channelsArray) {
|
||||||
if (o instanceof JsonObject) {
|
if (o instanceof JsonObject) {
|
||||||
JsonObject itemObject = (JsonObject) o;
|
final JsonObject itemObject = (JsonObject) o;
|
||||||
int serviceId = itemObject.getInt(JSON_SERVICE_ID_KEY, 0);
|
final int serviceId = itemObject.getInt(JSON_SERVICE_ID_KEY, 0);
|
||||||
String url = itemObject.getString(JSON_URL_KEY);
|
final String url = itemObject.getString(JSON_URL_KEY);
|
||||||
String name = itemObject.getString(JSON_NAME_KEY);
|
final String name = itemObject.getString(JSON_NAME_KEY);
|
||||||
|
|
||||||
if (url != null && name != null && !url.isEmpty() && !name.isEmpty()) {
|
if (url != null && name != null && !url.isEmpty() && !name.isEmpty()) {
|
||||||
channels.add(new SubscriptionItem(serviceId, url, name));
|
channels.add(new SubscriptionItem(serviceId, url, name));
|
||||||
@ -101,7 +101,7 @@ public final class ImportExportJsonHelper {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (Throwable e) {
|
} catch (final Throwable e) {
|
||||||
throw new InvalidSourceException("Couldn't parse json", e);
|
throw new InvalidSourceException("Couldn't parse json", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,7 +117,7 @@ public final class ImportExportJsonHelper {
|
|||||||
*/
|
*/
|
||||||
public static void writeTo(final List<SubscriptionItem> items, final OutputStream out,
|
public static void writeTo(final List<SubscriptionItem> items, final OutputStream out,
|
||||||
@Nullable final ImportExportEventListener eventListener) {
|
@Nullable final ImportExportEventListener eventListener) {
|
||||||
JsonAppendableWriter writer = JsonWriter.on(out);
|
final JsonAppendableWriter writer = JsonWriter.on(out);
|
||||||
writeTo(items, writer, eventListener);
|
writeTo(items, writer, eventListener);
|
||||||
writer.done();
|
writer.done();
|
||||||
}
|
}
|
||||||
@ -140,7 +140,7 @@ public final class ImportExportJsonHelper {
|
|||||||
writer.value(JSON_APP_VERSION_INT_KEY, BuildConfig.VERSION_CODE);
|
writer.value(JSON_APP_VERSION_INT_KEY, BuildConfig.VERSION_CODE);
|
||||||
|
|
||||||
writer.array(JSON_SUBSCRIPTIONS_ARRAY_KEY);
|
writer.array(JSON_SUBSCRIPTIONS_ARRAY_KEY);
|
||||||
for (SubscriptionItem item : items) {
|
for (final SubscriptionItem item : items) {
|
||||||
writer.object();
|
writer.object();
|
||||||
writer.value(JSON_SERVICE_ID_KEY, item.getServiceId());
|
writer.value(JSON_SERVICE_ID_KEY, item.getServiceId());
|
||||||
writer.value(JSON_URL_KEY, item.getUrl());
|
writer.value(JSON_URL_KEY, item.getUrl());
|
||||||
|
@ -74,7 +74,7 @@ public class SubscriptionsExportService extends BaseImportExportService {
|
|||||||
try {
|
try {
|
||||||
outFile = new File(path);
|
outFile = new File(path);
|
||||||
outputStream = new FileOutputStream(outFile);
|
outputStream = new FileOutputStream(outFile);
|
||||||
} catch (FileNotFoundException e) {
|
} catch (final FileNotFoundException e) {
|
||||||
handleError(e);
|
handleError(e);
|
||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
@ -109,7 +109,7 @@ public class SubscriptionsExportService extends BaseImportExportService {
|
|||||||
.map(subscriptionEntities -> {
|
.map(subscriptionEntities -> {
|
||||||
final List<SubscriptionItem> result
|
final List<SubscriptionItem> result
|
||||||
= new ArrayList<>(subscriptionEntities.size());
|
= new ArrayList<>(subscriptionEntities.size());
|
||||||
for (SubscriptionEntity entity : subscriptionEntities) {
|
for (final SubscriptionEntity entity : subscriptionEntities) {
|
||||||
result.add(new SubscriptionItem(entity.getServiceId(), entity.getUrl(),
|
result.add(new SubscriptionItem(entity.getServiceId(), entity.getUrl(),
|
||||||
entity.getName()));
|
entity.getName()));
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
inputStream = new FileInputStream(new File(filePath));
|
inputStream = new FileInputStream(new File(filePath));
|
||||||
} catch (FileNotFoundException e) {
|
} catch (final FileNotFoundException e) {
|
||||||
handleError(e);
|
handleError(e);
|
||||||
return START_NOT_STICKY;
|
return START_NOT_STICKY;
|
||||||
}
|
}
|
||||||
@ -187,7 +187,7 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
|||||||
.getChannelInfo(subscriptionItem.getServiceId(),
|
.getChannelInfo(subscriptionItem.getServiceId(),
|
||||||
subscriptionItem.getUrl(), true)
|
subscriptionItem.getUrl(), true)
|
||||||
.blockingGet());
|
.blockingGet());
|
||||||
} catch (Throwable e) {
|
} catch (final Throwable e) {
|
||||||
return Notification.createOnError(e);
|
return Notification.createOnError(e);
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -239,7 +239,7 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
|||||||
private Consumer<Notification<ChannelInfo>> getNotificationsConsumer() {
|
private Consumer<Notification<ChannelInfo>> getNotificationsConsumer() {
|
||||||
return notification -> {
|
return notification -> {
|
||||||
if (notification.isOnNext()) {
|
if (notification.isOnNext()) {
|
||||||
String name = notification.getValue().getName();
|
final String name = notification.getValue().getName();
|
||||||
eventListener.onItemCompleted(!TextUtils.isEmpty(name) ? name : "");
|
eventListener.onItemCompleted(!TextUtils.isEmpty(name) ? name : "");
|
||||||
} else if (notification.isOnError()) {
|
} else if (notification.isOnError()) {
|
||||||
final Throwable error = notification.getError();
|
final Throwable error = notification.getError();
|
||||||
@ -260,7 +260,7 @@ public class SubscriptionsImportService extends BaseImportExportService {
|
|||||||
private Function<List<Notification<ChannelInfo>>, List<SubscriptionEntity>> upsertBatch() {
|
private Function<List<Notification<ChannelInfo>>, List<SubscriptionEntity>> upsertBatch() {
|
||||||
return notificationList -> {
|
return notificationList -> {
|
||||||
final List<ChannelInfo> infoList = new ArrayList<>(notificationList.size());
|
final List<ChannelInfo> infoList = new ArrayList<>(notificationList.size());
|
||||||
for (Notification<ChannelInfo> n : notificationList) {
|
for (final Notification<ChannelInfo> n : notificationList) {
|
||||||
if (n.isOnNext()) {
|
if (n.isOnNext()) {
|
||||||
infoList.add(n.getValue());
|
infoList.add(n.getValue());
|
||||||
}
|
}
|
||||||
|
@ -54,9 +54,8 @@ import com.nostra13.universalimageloader.core.ImageLoader;
|
|||||||
import com.nostra13.universalimageloader.core.assist.FailReason;
|
import com.nostra13.universalimageloader.core.assist.FailReason;
|
||||||
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
import com.nostra13.universalimageloader.core.listener.ImageLoadingListener;
|
||||||
|
|
||||||
import io.reactivex.android.schedulers.AndroidSchedulers;
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
|
||||||
import org.schabi.newpipe.DownloaderImpl;
|
import org.schabi.newpipe.DownloaderImpl;
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
import org.schabi.newpipe.local.history.HistoryRecordManager;
|
||||||
@ -79,6 +78,7 @@ import org.schabi.newpipe.util.SerializedCache;
|
|||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
import io.reactivex.Observable;
|
import io.reactivex.Observable;
|
||||||
|
import io.reactivex.android.schedulers.AndroidSchedulers;
|
||||||
import io.reactivex.disposables.CompositeDisposable;
|
import io.reactivex.disposables.CompositeDisposable;
|
||||||
import io.reactivex.disposables.Disposable;
|
import io.reactivex.disposables.Disposable;
|
||||||
import io.reactivex.disposables.SerialDisposable;
|
import io.reactivex.disposables.SerialDisposable;
|
||||||
@ -98,7 +98,7 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
|
|||||||
@SuppressWarnings({"WeakerAccess"})
|
@SuppressWarnings({"WeakerAccess"})
|
||||||
public abstract class BasePlayer implements
|
public abstract class BasePlayer implements
|
||||||
Player.EventListener, PlaybackListener, ImageLoadingListener {
|
Player.EventListener, PlaybackListener, ImageLoadingListener {
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
public static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
@NonNull
|
@NonNull
|
||||||
public static final String TAG = "BasePlayer";
|
public static final String TAG = "BasePlayer";
|
||||||
|
|
||||||
@ -283,7 +283,7 @@ public abstract class BasePlayer implements
|
|||||||
|
|
||||||
// Resolve append intents
|
// Resolve append intents
|
||||||
if (intent.getBooleanExtra(APPEND_ONLY, false) && playQueue != null) {
|
if (intent.getBooleanExtra(APPEND_ONLY, false) && playQueue != null) {
|
||||||
int sizeBeforeAppend = playQueue.size();
|
final int sizeBeforeAppend = playQueue.size();
|
||||||
playQueue.append(queue.getStreams());
|
playQueue.append(queue.getStreams());
|
||||||
|
|
||||||
if ((intent.getBooleanExtra(SELECT_ON_APPEND, false)
|
if ((intent.getBooleanExtra(SELECT_ON_APPEND, false)
|
||||||
@ -883,7 +883,6 @@ public abstract class BasePlayer implements
|
|||||||
}
|
}
|
||||||
setRecovery();
|
setRecovery();
|
||||||
|
|
||||||
final Throwable cause = error.getCause();
|
|
||||||
if (error instanceof BehindLiveWindowException) {
|
if (error instanceof BehindLiveWindowException) {
|
||||||
reload();
|
reload();
|
||||||
} else {
|
} else {
|
||||||
@ -1071,14 +1070,6 @@ public abstract class BasePlayer implements
|
|||||||
registerView();
|
registerView();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onPlaybackShutdown() {
|
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "Shutting down...");
|
|
||||||
}
|
|
||||||
destroy();
|
|
||||||
}
|
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
// General Player
|
// General Player
|
||||||
//////////////////////////////////////////////////////////////////////////*/
|
//////////////////////////////////////////////////////////////////////////*/
|
||||||
@ -1463,7 +1454,7 @@ public abstract class BasePlayer implements
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Timeline.Window timelineWindow = new Timeline.Window();
|
final Timeline.Window timelineWindow = new Timeline.Window();
|
||||||
currentTimeline.getWindow(currentWindowIndex, timelineWindow);
|
currentTimeline.getWindow(currentWindowIndex, timelineWindow);
|
||||||
return timelineWindow.getDefaultPositionMs() <= simpleExoPlayer.getCurrentPosition();
|
return timelineWindow.getDefaultPositionMs() <= simpleExoPlayer.getCurrentPosition();
|
||||||
}
|
}
|
||||||
@ -1474,7 +1465,7 @@ public abstract class BasePlayer implements
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
return simpleExoPlayer.isCurrentWindowDynamic();
|
return simpleExoPlayer.isCurrentWindowDynamic();
|
||||||
} catch (@NonNull IndexOutOfBoundsException e) {
|
} catch (@NonNull final IndexOutOfBoundsException e) {
|
||||||
// Why would this even happen =(
|
// Why would this even happen =(
|
||||||
// But lets log it anyway. Save is save
|
// But lets log it anyway. Save is save
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
|
@ -580,7 +580,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
private void shareUrl(final String subject, final String url) {
|
private void shareUrl(final String subject, final String url) {
|
||||||
Intent intent = new Intent(Intent.ACTION_SEND);
|
final Intent intent = new Intent(Intent.ACTION_SEND);
|
||||||
intent.setType("text/plain");
|
intent.setType("text/plain");
|
||||||
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
intent.putExtra(Intent.EXTRA_SUBJECT, subject);
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, url);
|
intent.putExtra(Intent.EXTRA_TEXT, url);
|
||||||
@ -734,7 +734,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
|||||||
|
|
||||||
private void onMaybeMuteChanged() {
|
private void onMaybeMuteChanged() {
|
||||||
if (menu != null && player != null) {
|
if (menu != null && player != null) {
|
||||||
MenuItem item = menu.findItem(R.id.action_mute);
|
final MenuItem item = menu.findItem(R.id.action_mute);
|
||||||
|
|
||||||
//Change the mute-button item in ActionBar
|
//Change the mute-button item in ActionBar
|
||||||
//1) Text change:
|
//1) Text change:
|
||||||
|
@ -167,7 +167,7 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
|
|
||||||
// workaround to match normalized captions like english to English or deutsch to Deutsch
|
// workaround to match normalized captions like english to English or deutsch to Deutsch
|
||||||
private static boolean containsCaseInsensitive(final List<String> list, final String toFind) {
|
private static boolean containsCaseInsensitive(final List<String> list, final String toFind) {
|
||||||
for (String i : list) {
|
for (final String i : list) {
|
||||||
if (i.equalsIgnoreCase(toFind)) {
|
if (i.equalsIgnoreCase(toFind)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -279,7 +279,7 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
|
|
||||||
qualityPopupMenu.getMenu().removeGroup(qualityPopupMenuGroupId);
|
qualityPopupMenu.getMenu().removeGroup(qualityPopupMenuGroupId);
|
||||||
for (int i = 0; i < availableStreams.size(); i++) {
|
for (int i = 0; i < availableStreams.size(); i++) {
|
||||||
VideoStream videoStream = availableStreams.get(i);
|
final VideoStream videoStream = availableStreams.get(i);
|
||||||
qualityPopupMenu.getMenu().add(qualityPopupMenuGroupId, i, Menu.NONE, MediaFormat
|
qualityPopupMenu.getMenu().add(qualityPopupMenuGroupId, i, Menu.NONE, MediaFormat
|
||||||
.getNameById(videoStream.getFormatId()) + " " + videoStream.resolution);
|
.getNameById(videoStream.getFormatId()) + " " + videoStream.resolution);
|
||||||
}
|
}
|
||||||
@ -311,7 +311,7 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
}
|
}
|
||||||
captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId);
|
captionPopupMenu.getMenu().removeGroup(captionPopupMenuGroupId);
|
||||||
|
|
||||||
String userPreferredLanguage = PreferenceManager.getDefaultSharedPreferences(context)
|
final String userPreferredLanguage = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
.getString(context.getString(R.string.caption_user_set_key), null);
|
.getString(context.getString(R.string.caption_user_set_key), null);
|
||||||
/*
|
/*
|
||||||
* only search for autogenerated cc as fallback
|
* only search for autogenerated cc as fallback
|
||||||
@ -323,7 +323,7 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
&& !userPreferredLanguage.contains("(");
|
&& !userPreferredLanguage.contains("(");
|
||||||
|
|
||||||
// Add option for turning off caption
|
// Add option for turning off caption
|
||||||
MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId,
|
final MenuItem captionOffItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId,
|
||||||
0, Menu.NONE, R.string.caption_none);
|
0, Menu.NONE, R.string.caption_none);
|
||||||
captionOffItem.setOnMenuItemClickListener(menuItem -> {
|
captionOffItem.setOnMenuItemClickListener(menuItem -> {
|
||||||
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
@ -339,7 +339,7 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
// Add all available captions
|
// Add all available captions
|
||||||
for (int i = 0; i < availableLanguages.size(); i++) {
|
for (int i = 0; i < availableLanguages.size(); i++) {
|
||||||
final String captionLanguage = availableLanguages.get(i);
|
final String captionLanguage = availableLanguages.get(i);
|
||||||
MenuItem captionItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId,
|
final MenuItem captionItem = captionPopupMenu.getMenu().add(captionPopupMenuGroupId,
|
||||||
i + 1, Menu.NONE, captionLanguage);
|
i + 1, Menu.NONE, captionLanguage);
|
||||||
captionItem.setOnMenuItemClickListener(menuItem -> {
|
captionItem.setOnMenuItemClickListener(menuItem -> {
|
||||||
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
final int textRendererIndex = getRendererIndex(C.TRACK_TYPE_TEXT);
|
||||||
@ -579,7 +579,7 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
.getTrackGroups(textRenderer);
|
.getTrackGroups(textRenderer);
|
||||||
|
|
||||||
// Extract all loaded languages
|
// Extract all loaded languages
|
||||||
List<String> availableLanguages = new ArrayList<>(textTracks.length);
|
final List<String> availableLanguages = new ArrayList<>(textTracks.length);
|
||||||
for (int i = 0; i < textTracks.length; i++) {
|
for (int i = 0; i < textTracks.length; i++) {
|
||||||
final TrackGroup textTrack = textTracks.get(i);
|
final TrackGroup textTrack = textTracks.get(i);
|
||||||
if (textTrack.length > 0 && textTrack.getFormat(0) != null) {
|
if (textTrack.length > 0 && textTrack.getFormat(0) != null) {
|
||||||
@ -729,8 +729,8 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
qualityTextView.setText(menuItem.getTitle());
|
qualityTextView.setText(menuItem.getTitle());
|
||||||
return true;
|
return true;
|
||||||
} else if (playbackSpeedPopupMenuGroupId == menuItem.getGroupId()) {
|
} else if (playbackSpeedPopupMenuGroupId == menuItem.getGroupId()) {
|
||||||
int speedIndex = menuItem.getItemId();
|
final int speedIndex = menuItem.getItemId();
|
||||||
float speed = PLAYBACK_SPEEDS[speedIndex];
|
final float speed = PLAYBACK_SPEEDS[speedIndex];
|
||||||
|
|
||||||
setPlaybackSpeed(speed);
|
setPlaybackSpeed(speed);
|
||||||
playbackSpeedTextView.setText(formatSpeed(speed));
|
playbackSpeedTextView.setText(formatSpeed(speed));
|
||||||
@ -921,10 +921,10 @@ public abstract class VideoPlayer extends BasePlayer
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
float scaleFrom = goneOnEnd ? 1f : 1f;
|
final float scaleFrom = goneOnEnd ? 1f : 1f;
|
||||||
float scaleTo = goneOnEnd ? 1.8f : 1.4f;
|
final float scaleTo = goneOnEnd ? 1.8f : 1.4f;
|
||||||
float alphaFrom = goneOnEnd ? 1f : 0f;
|
final float alphaFrom = goneOnEnd ? 1f : 0f;
|
||||||
float alphaTo = goneOnEnd ? 0f : 1f;
|
final float alphaTo = goneOnEnd ? 0f : 1f;
|
||||||
|
|
||||||
|
|
||||||
controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(controlAnimationView,
|
controlViewAnimator = ObjectAnimator.ofPropertyValuesHolder(controlAnimationView,
|
||||||
|
@ -318,19 +318,17 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
final float captionScale,
|
final float captionScale,
|
||||||
@NonNull final CaptionStyleCompat captionStyle) {
|
@NonNull final CaptionStyleCompat captionStyle) {
|
||||||
if (popupPlayerSelected()) {
|
if (popupPlayerSelected()) {
|
||||||
float captionRatio = (captionScale - 1.0f) / 5.0f + 1.0f;
|
final float captionRatio = (captionScale - 1.0f) / 5.0f + 1.0f;
|
||||||
view.setFractionalTextSize(SubtitleView.DEFAULT_TEXT_SIZE_FRACTION * captionRatio);
|
view.setFractionalTextSize(SubtitleView.DEFAULT_TEXT_SIZE_FRACTION * captionRatio);
|
||||||
view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT));
|
|
||||||
view.setStyle(captionStyle);
|
|
||||||
} else {
|
} else {
|
||||||
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||||
final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels);
|
final int minimumLength = Math.min(metrics.heightPixels, metrics.widthPixels);
|
||||||
final float captionRatioInverse = 20f + 4f * (1.0f - captionScale);
|
final float captionRatioInverse = 20f + 4f * (1.0f - captionScale);
|
||||||
view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX,
|
view.setFixedTextSize(TypedValue.COMPLEX_UNIT_PX,
|
||||||
(float) minimumLength / captionRatioInverse);
|
(float) minimumLength / captionRatioInverse);
|
||||||
view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT));
|
|
||||||
view.setStyle(captionStyle);
|
|
||||||
}
|
}
|
||||||
|
view.setApplyEmbeddedStyles(captionStyle.equals(CaptionStyleCompat.DEFAULT));
|
||||||
|
view.setStyle(captionStyle);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -622,7 +620,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "onPlaybackShutdown() called");
|
Log.d(TAG, "onPlaybackShutdown() called");
|
||||||
}
|
}
|
||||||
// Override it because we don't want playerImpl destroyed
|
service.onDestroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -693,7 +691,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
if (popupPlayerSelected()) {
|
if (popupPlayerSelected()) {
|
||||||
setRecovery();
|
setRecovery();
|
||||||
service.removeViewFromParent();
|
service.removeViewFromParent();
|
||||||
Intent intent = NavigationHelper.getPlayerIntent(
|
final Intent intent = NavigationHelper.getPlayerIntent(
|
||||||
service,
|
service,
|
||||||
MainActivity.class,
|
MainActivity.class,
|
||||||
this.getPlayQueue(),
|
this.getPlayQueue(),
|
||||||
@ -856,9 +854,11 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
|
|
||||||
private void onShareClicked() {
|
private void onShareClicked() {
|
||||||
// share video at the current time (youtube.com/watch?v=ID&t=SECONDS)
|
// share video at the current time (youtube.com/watch?v=ID&t=SECONDS)
|
||||||
|
// Timestamp doesn't make sense in a live stream so drop it
|
||||||
|
final String ts = isLive() ? "" : ("&t=" + (getPlaybackSeekBar().getProgress() / 1000));
|
||||||
ShareUtils.shareUrl(service,
|
ShareUtils.shareUrl(service,
|
||||||
getVideoTitle(),
|
getVideoTitle(),
|
||||||
getVideoUrl() + "&t=" + getPlaybackSeekBar().getProgress() / 1000);
|
getVideoUrl() + ts);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void onPlayWithKodiClicked() {
|
private void onPlayWithKodiClicked() {
|
||||||
@ -868,7 +868,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
onPause();
|
onPause();
|
||||||
try {
|
try {
|
||||||
NavigationHelper.playWithKore(getParentActivity(), Uri.parse(getVideoUrl()));
|
NavigationHelper.playWithKore(getParentActivity(), Uri.parse(getVideoUrl()));
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.i(TAG, "Failed to start kore", e);
|
Log.i(TAG, "Failed to start kore", e);
|
||||||
}
|
}
|
||||||
@ -953,9 +953,9 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
if (l != ol || t != ot || r != or || b != ob) {
|
if (l != ol || t != ot || r != or || b != ob) {
|
||||||
// Use smaller value to be consistent between screen orientations
|
// Use smaller value to be consistent between screen orientations
|
||||||
// (and to make usage easier)
|
// (and to make usage easier)
|
||||||
int width = r - l;
|
final int width = r - l;
|
||||||
int height = b - t;
|
final int height = b - t;
|
||||||
int min = Math.min(width, height);
|
final int min = Math.min(width, height);
|
||||||
maxGestureLength = (int) (min * MAX_GESTURE_LENGTH);
|
maxGestureLength = (int) (min * MAX_GESTURE_LENGTH);
|
||||||
|
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
@ -969,7 +969,7 @@ public class VideoPlayerImpl extends VideoPlayer
|
|||||||
queueLayout.getLayoutParams().height = height - queueLayout.getTop();
|
queueLayout.getLayoutParams().height = height - queueLayout.getTop();
|
||||||
|
|
||||||
if (popupPlayerSelected()) {
|
if (popupPlayerSelected()) {
|
||||||
float widthDp = Math.abs(r - l) / service.getResources()
|
final float widthDp = Math.abs(r - l) / service.getResources()
|
||||||
.getDisplayMetrics().density;
|
.getDisplayMetrics().density;
|
||||||
final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP
|
final int visibility = widthDp > MINIMUM_SHOW_EXTRA_WIDTH_DP
|
||||||
? View.VISIBLE
|
? View.VISIBLE
|
||||||
|
@ -4,6 +4,7 @@ import android.content.Context;
|
|||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
import android.view.MotionEvent;
|
import android.view.MotionEvent;
|
||||||
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
@ -25,7 +26,7 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
|
|||||||
private boolean skippingInterception = false;
|
private boolean skippingInterception = false;
|
||||||
private final List<Integer> skipInterceptionOfElements = Arrays.asList(
|
private final List<Integer> skipInterceptionOfElements = Arrays.asList(
|
||||||
R.id.detail_content_root_layout, R.id.relatedStreamsLayout,
|
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
|
@Override
|
||||||
public boolean onInterceptTouchEvent(@NonNull final CoordinatorLayout parent,
|
public boolean onInterceptTouchEvent(@NonNull final CoordinatorLayout parent,
|
||||||
@ -51,6 +52,13 @@ public class CustomBottomSheetBehavior extends BottomSheetBehavior<FrameLayout>
|
|||||||
visible = viewGroup.getGlobalVisibleRect(globalRect);
|
visible = viewGroup.getGlobalVisibleRect(globalRect);
|
||||||
if (visible
|
if (visible
|
||||||
&& globalRect.contains((int) event.getRawX(), (int) event.getRawY())) {
|
&& 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;
|
skippingInterception = true;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -227,8 +227,8 @@ public class PlayerGestureListener
|
|||||||
|
|
||||||
isMovingInMain = true;
|
isMovingInMain = true;
|
||||||
|
|
||||||
boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
|
final boolean acceptAnyArea = isVolumeGestureEnabled != isBrightnessGestureEnabled;
|
||||||
boolean acceptVolumeArea = acceptAnyArea
|
final boolean acceptVolumeArea = acceptAnyArea
|
||||||
|| initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0;
|
|| initialEvent.getX() > playerImpl.getRootView().getWidth() / 2.0;
|
||||||
|
|
||||||
if (isVolumeGestureEnabled && acceptVolumeArea) {
|
if (isVolumeGestureEnabled && acceptVolumeArea) {
|
||||||
@ -563,13 +563,13 @@ public class PlayerGestureListener
|
|||||||
private boolean handleMultiDrag(final MotionEvent event) {
|
private boolean handleMultiDrag(final MotionEvent event) {
|
||||||
if (initPointerDistance != -1 && event.getPointerCount() == 2) {
|
if (initPointerDistance != -1 && event.getPointerCount() == 2) {
|
||||||
// get the movements of the fingers
|
// get the movements of the fingers
|
||||||
double firstPointerMove = Math.hypot(event.getX(0) - initFirstPointerX,
|
final double firstPointerMove = Math.hypot(event.getX(0) - initFirstPointerX,
|
||||||
event.getY(0) - initFirstPointerY);
|
event.getY(0) - initFirstPointerY);
|
||||||
double secPointerMove = Math.hypot(event.getX(1) - initSecPointerX,
|
final double secPointerMove = Math.hypot(event.getX(1) - initSecPointerX,
|
||||||
event.getY(1) - initSecPointerY);
|
event.getY(1) - initSecPointerY);
|
||||||
|
|
||||||
// minimum threshold beyond which pinch gesture will work
|
// minimum threshold beyond which pinch gesture will work
|
||||||
int minimumMove = ViewConfiguration.get(service).getScaledTouchSlop();
|
final int minimumMove = ViewConfiguration.get(service).getScaledTouchSlop();
|
||||||
|
|
||||||
if (Math.max(firstPointerMove, secPointerMove) > minimumMove) {
|
if (Math.max(firstPointerMove, secPointerMove) > minimumMove) {
|
||||||
// calculate current distance between the pointers
|
// calculate current distance between the pointers
|
||||||
@ -577,9 +577,9 @@ public class PlayerGestureListener
|
|||||||
Math.hypot(event.getX(0) - event.getX(1),
|
Math.hypot(event.getX(0) - event.getX(1),
|
||||||
event.getY(0) - event.getY(1));
|
event.getY(0) - event.getY(1));
|
||||||
|
|
||||||
double popupWidth = playerImpl.getPopupWidth();
|
final double popupWidth = playerImpl.getPopupWidth();
|
||||||
// change co-ordinates of popup so the center stays at the same position
|
// change co-ordinates of popup so the center stays at the same position
|
||||||
double newWidth = (popupWidth * currentPointerDistance / initPointerDistance);
|
final double newWidth = (popupWidth * currentPointerDistance / initPointerDistance);
|
||||||
initPointerDistance = currentPointerDistance;
|
initPointerDistance = currentPointerDistance;
|
||||||
playerImpl.getPopupLayoutParams().x += (popupWidth - newWidth) / 2;
|
playerImpl.getPopupLayoutParams().x += (popupWidth - newWidth) / 2;
|
||||||
|
|
||||||
@ -601,7 +601,7 @@ public class PlayerGestureListener
|
|||||||
* */
|
* */
|
||||||
|
|
||||||
private int getNavigationBarHeight(final Context context) {
|
private int getNavigationBarHeight(final Context context) {
|
||||||
int resId = context.getResources()
|
final int resId = context.getResources()
|
||||||
.getIdentifier("navigation_bar_height", "dimen", "android");
|
.getIdentifier("navigation_bar_height", "dimen", "android");
|
||||||
if (resId > 0) {
|
if (resId > 0) {
|
||||||
return context.getResources().getDimensionPixelSize(resId);
|
return context.getResources().getDimensionPixelSize(resId);
|
||||||
@ -610,7 +610,7 @@ public class PlayerGestureListener
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int getStatusBarHeight(final Context context) {
|
private int getStatusBarHeight(final Context context) {
|
||||||
int resId = context.getResources()
|
final int resId = context.getResources()
|
||||||
.getIdentifier("status_bar_height", "dimen", "android");
|
.getIdentifier("status_bar_height", "dimen", "android");
|
||||||
if (resId > 0) {
|
if (resId > 0) {
|
||||||
return context.getResources().getDimensionPixelSize(resId);
|
return context.getResources().getDimensionPixelSize(resId);
|
||||||
|
@ -133,7 +133,7 @@ public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, An
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void animateAudio(final float from, final float to) {
|
private void animateAudio(final float from, final float to) {
|
||||||
ValueAnimator valueAnimator = new ValueAnimator();
|
final ValueAnimator valueAnimator = new ValueAnimator();
|
||||||
valueAnimator.setFloatValues(from, to);
|
valueAnimator.setFloatValues(from, to);
|
||||||
valueAnimator.setDuration(AudioReactor.DUCK_DURATION);
|
valueAnimator.setDuration(AudioReactor.DUCK_DURATION);
|
||||||
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
||||||
|
@ -80,13 +80,13 @@ import java.io.File;
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (File file : cacheDir.listFiles()) {
|
for (final File file : cacheDir.listFiles()) {
|
||||||
final String filePath = file.getAbsolutePath();
|
final String filePath = file.getAbsolutePath();
|
||||||
final boolean deleteSuccessful = file.delete();
|
final boolean deleteSuccessful = file.delete();
|
||||||
|
|
||||||
Log.d(TAG, "tryDeleteCacheFiles: " + filePath + " deleted = " + deleteSuccessful);
|
Log.d(TAG, "tryDeleteCacheFiles: " + filePath + " deleted = " + deleteSuccessful);
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
Log.e(TAG, "Failed to delete file.", ignored);
|
Log.e(TAG, "Failed to delete file.", ignored);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ public class LoadController implements LoadControl {
|
|||||||
final int optimalPlaybackBufferMs) {
|
final int optimalPlaybackBufferMs) {
|
||||||
this.initialPlaybackBufferUs = initialPlaybackBufferMs * 1000;
|
this.initialPlaybackBufferUs = initialPlaybackBufferMs * 1000;
|
||||||
|
|
||||||
DefaultLoadControl.Builder builder = new DefaultLoadControl.Builder();
|
final DefaultLoadControl.Builder builder = new DefaultLoadControl.Builder();
|
||||||
builder.setBufferDurationsMs(minimumPlaybackbufferMs, optimalPlaybackBufferMs,
|
builder.setBufferDurationsMs(minimumPlaybackbufferMs, optimalPlaybackBufferMs,
|
||||||
initialPlaybackBufferMs, initialPlaybackBufferMs);
|
initialPlaybackBufferMs, initialPlaybackBufferMs);
|
||||||
internalLoadControl = builder.createDefaultLoadControl();
|
internalLoadControl = builder.createDefaultLoadControl();
|
||||||
|
@ -94,7 +94,7 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
final double playbackPitch,
|
final double playbackPitch,
|
||||||
final boolean playbackSkipSilence,
|
final boolean playbackSkipSilence,
|
||||||
final Callback callback) {
|
final Callback callback) {
|
||||||
PlaybackParameterDialog dialog = new PlaybackParameterDialog();
|
final PlaybackParameterDialog dialog = new PlaybackParameterDialog();
|
||||||
dialog.callback = callback;
|
dialog.callback = callback;
|
||||||
dialog.initialTempo = playbackTempo;
|
dialog.initialTempo = playbackTempo;
|
||||||
dialog.initialPitch = playbackPitch;
|
dialog.initialPitch = playbackPitch;
|
||||||
@ -187,8 +187,8 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
|
|
||||||
private void setupTempoControl(@NonNull final View rootView) {
|
private void setupTempoControl(@NonNull final View rootView) {
|
||||||
tempoSlider = rootView.findViewById(R.id.tempoSeekbar);
|
tempoSlider = rootView.findViewById(R.id.tempoSeekbar);
|
||||||
TextView tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText);
|
final TextView tempoMinimumText = rootView.findViewById(R.id.tempoMinimumText);
|
||||||
TextView tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText);
|
final TextView tempoMaximumText = rootView.findViewById(R.id.tempoMaximumText);
|
||||||
tempoCurrentText = rootView.findViewById(R.id.tempoCurrentText);
|
tempoCurrentText = rootView.findViewById(R.id.tempoCurrentText);
|
||||||
tempoStepUpText = rootView.findViewById(R.id.tempoStepUp);
|
tempoStepUpText = rootView.findViewById(R.id.tempoStepUp);
|
||||||
tempoStepDownText = rootView.findViewById(R.id.tempoStepDown);
|
tempoStepDownText = rootView.findViewById(R.id.tempoStepDown);
|
||||||
@ -212,8 +212,8 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
|
|
||||||
private void setupPitchControl(@NonNull final View rootView) {
|
private void setupPitchControl(@NonNull final View rootView) {
|
||||||
pitchSlider = rootView.findViewById(R.id.pitchSeekbar);
|
pitchSlider = rootView.findViewById(R.id.pitchSeekbar);
|
||||||
TextView pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText);
|
final TextView pitchMinimumText = rootView.findViewById(R.id.pitchMinimumText);
|
||||||
TextView pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText);
|
final TextView pitchMaximumText = rootView.findViewById(R.id.pitchMaximumText);
|
||||||
pitchCurrentText = rootView.findViewById(R.id.pitchCurrentText);
|
pitchCurrentText = rootView.findViewById(R.id.pitchCurrentText);
|
||||||
pitchStepDownText = rootView.findViewById(R.id.pitchStepDown);
|
pitchStepDownText = rootView.findViewById(R.id.pitchStepDown);
|
||||||
pitchStepUpText = rootView.findViewById(R.id.pitchStepUp);
|
pitchStepUpText = rootView.findViewById(R.id.pitchStepUp);
|
||||||
@ -269,12 +269,12 @@ public class PlaybackParameterDialog extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void setupStepSizeSelector(@NonNull final View rootView) {
|
private void setupStepSizeSelector(@NonNull final View rootView) {
|
||||||
TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
|
final TextView stepSizeOnePercentText = rootView.findViewById(R.id.stepSizeOnePercent);
|
||||||
TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
|
final TextView stepSizeFivePercentText = rootView.findViewById(R.id.stepSizeFivePercent);
|
||||||
TextView stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent);
|
final TextView stepSizeTenPercentText = rootView.findViewById(R.id.stepSizeTenPercent);
|
||||||
TextView stepSizeTwentyFivePercentText = rootView
|
final TextView stepSizeTwentyFivePercentText = rootView
|
||||||
.findViewById(R.id.stepSizeTwentyFivePercent);
|
.findViewById(R.id.stepSizeTwentyFivePercent);
|
||||||
TextView stepSizeOneHundredPercentText = rootView
|
final TextView stepSizeOneHundredPercentText = rootView
|
||||||
.findViewById(R.id.stepSizeOneHundredPercent);
|
.findViewById(R.id.stepSizeOneHundredPercent);
|
||||||
|
|
||||||
if (stepSizeOnePercentText != null) {
|
if (stepSizeOnePercentText != null) {
|
||||||
|
@ -76,10 +76,10 @@ public final class PlayerHelper {
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
public static String getTimeString(final int milliSeconds) {
|
public static String getTimeString(final int milliSeconds) {
|
||||||
int seconds = (milliSeconds % 60000) / 1000;
|
final int seconds = (milliSeconds % 60000) / 1000;
|
||||||
int minutes = (milliSeconds % 3600000) / 60000;
|
final int minutes = (milliSeconds % 3600000) / 60000;
|
||||||
int hours = (milliSeconds % 86400000) / 3600000;
|
final int hours = (milliSeconds % 86400000) / 3600000;
|
||||||
int days = (milliSeconds % (86400000 * 7)) / 86400000;
|
final int days = (milliSeconds % (86400000 * 7)) / 86400000;
|
||||||
|
|
||||||
STRING_BUILDER.setLength(0);
|
STRING_BUILDER.setLength(0);
|
||||||
return days > 0
|
return days > 0
|
||||||
@ -405,7 +405,7 @@ public final class PlayerHelper {
|
|||||||
|
|
||||||
private static void setScreenBrightness(@NonNull final Context context,
|
private static void setScreenBrightness(@NonNull final Context context,
|
||||||
final float screenBrightness, final long timestamp) {
|
final float screenBrightness, final long timestamp) {
|
||||||
SharedPreferences.Editor editor = getPreferences(context).edit();
|
final SharedPreferences.Editor editor = getPreferences(context).edit();
|
||||||
editor.putFloat(context.getString(R.string.screen_brightness_key), screenBrightness);
|
editor.putFloat(context.getString(R.string.screen_brightness_key), screenBrightness);
|
||||||
editor.putLong(context.getString(R.string.screen_brightness_timestamp_key), timestamp);
|
editor.putLong(context.getString(R.string.screen_brightness_timestamp_key), timestamp);
|
||||||
editor.apply();
|
editor.apply();
|
||||||
@ -413,8 +413,8 @@ public final class PlayerHelper {
|
|||||||
|
|
||||||
private static float getScreenBrightness(@NonNull final Context context,
|
private static float getScreenBrightness(@NonNull final Context context,
|
||||||
final float screenBrightness) {
|
final float screenBrightness) {
|
||||||
SharedPreferences sp = getPreferences(context);
|
final SharedPreferences sp = getPreferences(context);
|
||||||
long timestamp = sp
|
final long timestamp = sp
|
||||||
.getLong(context.getString(R.string.screen_brightness_timestamp_key), 0);
|
.getLong(context.getString(R.string.screen_brightness_timestamp_key), 0);
|
||||||
// Hypothesis: 4h covers a viewing block, e.g. evening.
|
// Hypothesis: 4h covers a viewing block, e.g. evening.
|
||||||
// External lightning conditions will change in the next
|
// External lightning conditions will change in the next
|
||||||
@ -441,7 +441,7 @@ public final class PlayerHelper {
|
|||||||
|
|
||||||
private static SinglePlayQueue getAutoQueuedSinglePlayQueue(
|
private static SinglePlayQueue getAutoQueuedSinglePlayQueue(
|
||||||
final StreamInfoItem streamInfoItem) {
|
final StreamInfoItem streamInfoItem) {
|
||||||
SinglePlayQueue singlePlayQueue = new SinglePlayQueue(streamInfoItem);
|
final SinglePlayQueue singlePlayQueue = new SinglePlayQueue(streamInfoItem);
|
||||||
singlePlayQueue.getItem().setAutoQueued(true);
|
singlePlayQueue.getItem().setAutoQueued(true);
|
||||||
return singlePlayQueue;
|
return singlePlayQueue;
|
||||||
}
|
}
|
||||||
|
@ -87,13 +87,13 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Yes this is almost a copypasta, got a problem with that? =\
|
// Yes this is almost a copypasta, got a problem with that? =\
|
||||||
int windowCount = callback.getQueueSize();
|
final int windowCount = callback.getQueueSize();
|
||||||
int currentWindowIndex = callback.getCurrentPlayingIndex();
|
final int currentWindowIndex = callback.getCurrentPlayingIndex();
|
||||||
int queueSize = Math.min(maxQueueSize, windowCount);
|
final int queueSize = Math.min(maxQueueSize, windowCount);
|
||||||
int startIndex = Util.constrainValue(currentWindowIndex - ((queueSize - 1) / 2), 0,
|
final int startIndex = Util.constrainValue(currentWindowIndex - ((queueSize - 1) / 2), 0,
|
||||||
windowCount - queueSize);
|
windowCount - queueSize);
|
||||||
|
|
||||||
List<MediaSessionCompat.QueueItem> queue = new ArrayList<>();
|
final List<MediaSessionCompat.QueueItem> queue = new ArrayList<>();
|
||||||
for (int i = startIndex; i < startIndex + queueSize; i++) {
|
for (int i = startIndex; i < startIndex + queueSize; i++) {
|
||||||
queue.add(new MediaSessionCompat.QueueItem(callback.getQueueMetadata(i), i));
|
queue.add(new MediaSessionCompat.QueueItem(callback.getQueueMetadata(i), i));
|
||||||
}
|
}
|
||||||
|
@ -57,13 +57,14 @@ public class BasePlayerMediaSession implements MediaSessionCallback {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final PlayQueueItem item = player.getPlayQueue().getItem(index);
|
final PlayQueueItem item = player.getPlayQueue().getItem(index);
|
||||||
MediaDescriptionCompat.Builder descriptionBuilder = new MediaDescriptionCompat.Builder()
|
final MediaDescriptionCompat.Builder descriptionBuilder
|
||||||
|
= new MediaDescriptionCompat.Builder()
|
||||||
.setMediaId(String.valueOf(index))
|
.setMediaId(String.valueOf(index))
|
||||||
.setTitle(item.getTitle())
|
.setTitle(item.getTitle())
|
||||||
.setSubtitle(item.getUploader());
|
.setSubtitle(item.getUploader());
|
||||||
|
|
||||||
// set additional metadata for A2DP/AVRCP
|
// set additional metadata for A2DP/AVRCP
|
||||||
Bundle additionalMetadata = new Bundle();
|
final Bundle additionalMetadata = new Bundle();
|
||||||
additionalMetadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, item.getTitle());
|
additionalMetadata.putString(MediaMetadataCompat.METADATA_KEY_TITLE, item.getTitle());
|
||||||
additionalMetadata.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, item.getUploader());
|
additionalMetadata.putString(MediaMetadataCompat.METADATA_KEY_ARTIST, item.getUploader());
|
||||||
additionalMetadata
|
additionalMetadata
|
||||||
|
@ -60,14 +60,14 @@ public class CustomTrackSelector extends DefaultTrackSelector {
|
|||||||
TextTrackScore selectedTrackScore = null;
|
TextTrackScore selectedTrackScore = null;
|
||||||
|
|
||||||
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
for (int groupIndex = 0; groupIndex < groups.length; groupIndex++) {
|
||||||
TrackGroup trackGroup = groups.get(groupIndex);
|
final TrackGroup trackGroup = groups.get(groupIndex);
|
||||||
@Capabilities int[] trackFormatSupport = formatSupport[groupIndex];
|
@Capabilities final int[] trackFormatSupport = formatSupport[groupIndex];
|
||||||
|
|
||||||
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
for (int trackIndex = 0; trackIndex < trackGroup.length; trackIndex++) {
|
||||||
if (isSupported(trackFormatSupport[trackIndex],
|
if (isSupported(trackFormatSupport[trackIndex],
|
||||||
params.exceedRendererCapabilitiesIfNecessary)) {
|
params.exceedRendererCapabilitiesIfNecessary)) {
|
||||||
Format format = trackGroup.getFormat(trackIndex);
|
final Format format = trackGroup.getFormat(trackIndex);
|
||||||
TextTrackScore trackScore = new TextTrackScore(format, params,
|
final TextTrackScore trackScore = new TextTrackScore(format, params,
|
||||||
trackFormatSupport[trackIndex], selectedAudioLanguage);
|
trackFormatSupport[trackIndex], selectedAudioLanguage);
|
||||||
|
|
||||||
if (formatHasLanguage(format, preferredTextLanguage)) {
|
if (formatHasLanguage(format, preferredTextLanguage)) {
|
||||||
|
@ -129,7 +129,7 @@ abstract class AbstractInfoPlayQueue<T extends ListInfo, U extends InfoItem> ext
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static List<PlayQueueItem> extractListItems(final List<StreamInfoItem> infos) {
|
private static List<PlayQueueItem> extractListItems(final List<StreamInfoItem> infos) {
|
||||||
List<PlayQueueItem> result = new ArrayList<>();
|
final List<PlayQueueItem> result = new ArrayList<>();
|
||||||
for (final InfoItem stream : infos) {
|
for (final InfoItem stream : infos) {
|
||||||
if (stream instanceof StreamInfoItem) {
|
if (stream instanceof StreamInfoItem) {
|
||||||
result.add(new PlayQueueItem((StreamInfoItem) stream));
|
result.add(new PlayQueueItem((StreamInfoItem) stream));
|
||||||
|
@ -7,7 +7,7 @@ import androidx.annotation.Nullable;
|
|||||||
|
|
||||||
import org.reactivestreams.Subscriber;
|
import org.reactivestreams.Subscriber;
|
||||||
import org.reactivestreams.Subscription;
|
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.AppendEvent;
|
||||||
import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
|
import org.schabi.newpipe.player.playqueue.events.ErrorEvent;
|
||||||
import org.schabi.newpipe.player.playqueue.events.InitEvent;
|
import org.schabi.newpipe.player.playqueue.events.InitEvent;
|
||||||
@ -44,7 +44,7 @@ import io.reactivex.subjects.BehaviorSubject;
|
|||||||
*/
|
*/
|
||||||
public abstract class PlayQueue implements Serializable {
|
public abstract class PlayQueue implements Serializable {
|
||||||
private final String TAG = "PlayQueue@" + Integer.toHexString(hashCode());
|
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> backup;
|
||||||
private ArrayList<PlayQueueItem> streams;
|
private ArrayList<PlayQueueItem> streams;
|
||||||
|
@ -26,7 +26,7 @@ public final class SinglePlayQueue extends PlayQueue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static List<PlayQueueItem> playQueueItemsOf(final List<StreamInfoItem> items) {
|
private static List<PlayQueueItem> playQueueItemsOf(final List<StreamInfoItem> items) {
|
||||||
List<PlayQueueItem> playQueueItems = new ArrayList<>(items.size());
|
final List<PlayQueueItem> playQueueItems = new ArrayList<>(items.size());
|
||||||
for (final StreamInfoItem item : items) {
|
for (final StreamInfoItem item : items) {
|
||||||
playQueueItems.add(new PlayQueueItem(item));
|
playQueueItems.add(new PlayQueueItem(item));
|
||||||
}
|
}
|
||||||
|
@ -52,7 +52,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
|
|||||||
return liveSource;
|
return liveSource;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MediaSource> mediaSources = new ArrayList<>();
|
final List<MediaSource> mediaSources = new ArrayList<>();
|
||||||
|
|
||||||
// Create video stream source
|
// Create video stream source
|
||||||
final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context,
|
final List<VideoStream> videos = ListHelper.getSortedStreamVideosList(context,
|
||||||
@ -106,7 +106,7 @@ public class VideoPlaybackResolver implements PlaybackResolver {
|
|||||||
SELECTION_FLAG_AUTOSELECT,
|
SELECTION_FLAG_AUTOSELECT,
|
||||||
PlayerHelper.captionLanguageOf(context, subtitle));
|
PlayerHelper.captionLanguageOf(context, subtitle));
|
||||||
final MediaSource textSource = dataSource.getSampleMediaSourceFactory()
|
final MediaSource textSource = dataSource.getSampleMediaSourceFactory()
|
||||||
.createMediaSource(Uri.parse(subtitle.getURL()), textFormat, TIME_UNSET);
|
.createMediaSource(Uri.parse(subtitle.getUrl()), textFormat, TIME_UNSET);
|
||||||
mediaSources.add(textSource);
|
mediaSources.add(textSource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,9 +112,9 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private static void startErrorActivity(final Class returnActivity, final Context context,
|
private static void startErrorActivity(final Class returnActivity, final Context context,
|
||||||
final ErrorInfo errorInfo, final List<Throwable> el) {
|
final ErrorInfo errorInfo, final List<Throwable> el) {
|
||||||
ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
|
final ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
|
||||||
ac.setReturnActivity(returnActivity);
|
ac.setReturnActivity(returnActivity);
|
||||||
Intent intent = new Intent(context, ErrorActivity.class);
|
final Intent intent = new Intent(context, ErrorActivity.class);
|
||||||
intent.putExtra(ERROR_INFO, errorInfo);
|
intent.putExtra(ERROR_INFO, errorInfo);
|
||||||
intent.putExtra(ERROR_LIST, elToSl(el));
|
intent.putExtra(ERROR_LIST, elToSl(el));
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
@ -154,9 +154,9 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
public static void reportError(final Context context, final CrashReportData report,
|
public static void reportError(final Context context, final CrashReportData report,
|
||||||
final ErrorInfo errorInfo) {
|
final ErrorInfo errorInfo) {
|
||||||
String[] el = new String[]{report.getString(ReportField.STACK_TRACE)};
|
final String[] el = new String[]{report.getString(ReportField.STACK_TRACE)};
|
||||||
|
|
||||||
Intent intent = new Intent(context, ErrorActivity.class);
|
final Intent intent = new Intent(context, ErrorActivity.class);
|
||||||
intent.putExtra(ERROR_INFO, errorInfo);
|
intent.putExtra(ERROR_INFO, errorInfo);
|
||||||
intent.putExtra(ERROR_LIST, el);
|
intent.putExtra(ERROR_LIST, el);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
||||||
@ -172,7 +172,7 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
// errorList to StringList
|
// errorList to StringList
|
||||||
private static String[] elToSl(final List<Throwable> stackTraces) {
|
private static String[] elToSl(final List<Throwable> stackTraces) {
|
||||||
String[] out = new String[stackTraces.size()];
|
final String[] out = new String[stackTraces.size()];
|
||||||
for (int i = 0; i < stackTraces.size(); i++) {
|
for (int i = 0; i < stackTraces.size(); i++) {
|
||||||
out[i] = getStackTrace(stackTraces.get(i));
|
out[i] = getStackTrace(stackTraces.get(i));
|
||||||
}
|
}
|
||||||
@ -186,12 +186,12 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
ThemeHelper.setTheme(this);
|
ThemeHelper.setTheme(this);
|
||||||
setContentView(R.layout.activity_error);
|
setContentView(R.layout.activity_error);
|
||||||
|
|
||||||
Intent intent = getIntent();
|
final Intent intent = getIntent();
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
ActionBar actionBar = getSupportActionBar();
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
actionBar.setTitle(R.string.error_report_title);
|
actionBar.setTitle(R.string.error_report_title);
|
||||||
@ -203,11 +203,11 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
final Button reportGithubButton = findViewById(R.id.errorReportGitHubButton);
|
final Button reportGithubButton = findViewById(R.id.errorReportGitHubButton);
|
||||||
|
|
||||||
userCommentBox = findViewById(R.id.errorCommentBox);
|
userCommentBox = findViewById(R.id.errorCommentBox);
|
||||||
TextView errorView = findViewById(R.id.errorView);
|
final TextView errorView = findViewById(R.id.errorView);
|
||||||
TextView infoView = findViewById(R.id.errorInfosView);
|
final TextView infoView = findViewById(R.id.errorInfosView);
|
||||||
TextView errorMessageView = findViewById(R.id.errorMessageView);
|
final TextView errorMessageView = findViewById(R.id.errorMessageView);
|
||||||
|
|
||||||
ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
|
final ActivityCommunicator ac = ActivityCommunicator.getCommunicator();
|
||||||
returnActivity = ac.getReturnActivity();
|
returnActivity = ac.getReturnActivity();
|
||||||
errorInfo = intent.getParcelableExtra(ERROR_INFO);
|
errorInfo = intent.getParcelableExtra(ERROR_INFO);
|
||||||
errorList = intent.getStringArrayExtra(ERROR_LIST);
|
errorList = intent.getStringArrayExtra(ERROR_LIST);
|
||||||
@ -242,27 +242,27 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
errorView.setText(formErrorText(errorList));
|
errorView.setText(formErrorText(errorList));
|
||||||
|
|
||||||
// print stack trace once again for debugging:
|
// print stack trace once again for debugging:
|
||||||
for (String e : errorList) {
|
for (final String e : errorList) {
|
||||||
Log.e(TAG, e);
|
Log.e(TAG, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||||
MenuInflater inflater = getMenuInflater();
|
final MenuInflater inflater = getMenuInflater();
|
||||||
inflater.inflate(R.menu.error_menu, menu);
|
inflater.inflate(R.menu.error_menu, menu);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case android.R.id.home:
|
case android.R.id.home:
|
||||||
goToReturnActivity();
|
goToReturnActivity();
|
||||||
break;
|
break;
|
||||||
case R.id.menu_item_share_error:
|
case R.id.menu_item_share_error:
|
||||||
Intent intent = new Intent();
|
final Intent intent = new Intent();
|
||||||
intent.setAction(Intent.ACTION_SEND);
|
intent.setAction(Intent.ACTION_SEND);
|
||||||
intent.putExtra(Intent.EXTRA_TEXT, buildJson());
|
intent.putExtra(Intent.EXTRA_TEXT, buildJson());
|
||||||
intent.setType("text/plain");
|
intent.setType("text/plain");
|
||||||
@ -304,9 +304,9 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String formErrorText(final String[] el) {
|
private String formErrorText(final String[] el) {
|
||||||
StringBuilder text = new StringBuilder();
|
final StringBuilder text = new StringBuilder();
|
||||||
if (el != null) {
|
if (el != null) {
|
||||||
for (String e : el) {
|
for (final String e : el) {
|
||||||
text.append("-------------------------------------\n").append(e);
|
text.append("-------------------------------------\n").append(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -334,19 +334,19 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void goToReturnActivity() {
|
private void goToReturnActivity() {
|
||||||
Class<? extends Activity> checkedReturnActivity = getReturnActivity(returnActivity);
|
final Class<? extends Activity> checkedReturnActivity = getReturnActivity(returnActivity);
|
||||||
if (checkedReturnActivity == null) {
|
if (checkedReturnActivity == null) {
|
||||||
super.onBackPressed();
|
super.onBackPressed();
|
||||||
} else {
|
} else {
|
||||||
Intent intent = new Intent(this, checkedReturnActivity);
|
final Intent intent = new Intent(this, checkedReturnActivity);
|
||||||
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
|
||||||
NavUtils.navigateUpTo(this, intent);
|
NavUtils.navigateUpTo(this, intent);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void buildInfo(final ErrorInfo info) {
|
private void buildInfo(final ErrorInfo info) {
|
||||||
TextView infoLabelView = findViewById(R.id.errorInfoLabelsView);
|
final TextView infoLabelView = findViewById(R.id.errorInfoLabelsView);
|
||||||
TextView infoView = findViewById(R.id.errorInfosView);
|
final TextView infoView = findViewById(R.id.errorInfosView);
|
||||||
String text = "";
|
String text = "";
|
||||||
|
|
||||||
infoLabelView.setText(getString(R.string.info_labels).replace("\\n", "\n"));
|
infoLabelView.setText(getString(R.string.info_labels).replace("\\n", "\n"));
|
||||||
@ -383,7 +383,7 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
.value("user_comment", userCommentBox.getText().toString())
|
.value("user_comment", userCommentBox.getText().toString())
|
||||||
.end()
|
.end()
|
||||||
.done();
|
.done();
|
||||||
} catch (Throwable e) {
|
} catch (final Throwable e) {
|
||||||
Log.e(TAG, "Error while erroring: Could not build json");
|
Log.e(TAG, "Error while erroring: Could not build json");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
@ -441,7 +441,7 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
htmlErrorReport.append("<hr>\n");
|
htmlErrorReport.append("<hr>\n");
|
||||||
return htmlErrorReport.toString();
|
return htmlErrorReport.toString();
|
||||||
} catch (Throwable e) {
|
} catch (final Throwable e) {
|
||||||
Log.e(TAG, "Error while erroring: Could not build markdown");
|
Log.e(TAG, "Error while erroring: Could not build markdown");
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
return "";
|
return "";
|
||||||
@ -478,7 +478,7 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
|
|
||||||
private void addGuruMeditation() {
|
private void addGuruMeditation() {
|
||||||
//just an easter egg
|
//just an easter egg
|
||||||
TextView sorryView = findViewById(R.id.errorSorryView);
|
final TextView sorryView = findViewById(R.id.errorSorryView);
|
||||||
String text = sorryView.getText().toString();
|
String text = sorryView.getText().toString();
|
||||||
text += "\n" + getString(R.string.guru_meditation);
|
text += "\n" + getString(R.string.guru_meditation);
|
||||||
sorryView.setText(text);
|
sorryView.setText(text);
|
||||||
@ -491,7 +491,7 @@ public class ErrorActivity extends AppCompatActivity {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public String getCurrentTimeStamp() {
|
public String getCurrentTimeStamp() {
|
||||||
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
final SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm");
|
||||||
df.setTimeZone(TimeZone.getTimeZone("GMT"));
|
df.setTimeZone(TimeZone.getTimeZone("GMT"));
|
||||||
return df.format(new Date());
|
return df.format(new Date());
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
String themeKey = getString(R.string.theme_key);
|
final String themeKey = getString(R.string.theme_key);
|
||||||
startThemeKey = defaultPreferences
|
startThemeKey = defaultPreferences
|
||||||
.getString(themeKey, getString(R.string.default_theme_value));
|
.getString(themeKey, getString(R.string.default_theme_value));
|
||||||
findPreference(themeKey).setOnPreferenceChangeListener(themePreferenceChange);
|
findPreference(themeKey).setOnPreferenceChangeListener(themePreferenceChange);
|
||||||
@ -64,7 +64,7 @@ public class AppearanceSettingsFragment extends BasePreferenceFragment {
|
|||||||
if (preference.getKey().equals(captionSettingsKey) && CAPTIONING_SETTINGS_ACCESSIBLE) {
|
if (preference.getKey().equals(captionSettingsKey) && CAPTIONING_SETTINGS_ACCESSIBLE) {
|
||||||
try {
|
try {
|
||||||
startActivity(new Intent(Settings.ACTION_CAPTIONING_SETTINGS));
|
startActivity(new Intent(Settings.ACTION_CAPTIONING_SETTINGS));
|
||||||
} catch (ActivityNotFoundException e) {
|
} catch (final ActivityNotFoundException e) {
|
||||||
Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
|
Toast.makeText(getActivity(), R.string.general_error, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -39,7 +39,7 @@ public abstract class BasePreferenceFragment extends PreferenceFragmentCompat {
|
|||||||
|
|
||||||
private void updateTitle() {
|
private void updateTitle() {
|
||||||
if (getActivity() instanceof AppCompatActivity) {
|
if (getActivity() instanceof AppCompatActivity) {
|
||||||
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setTitle(getPreferenceScreen().getTitle());
|
actionBar.setTitle(getPreferenceScreen().getTitle());
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,6 @@ import org.schabi.newpipe.util.ZipHelper;
|
|||||||
import java.io.BufferedOutputStream;
|
import java.io.BufferedOutputStream;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileInputStream;
|
import java.io.FileInputStream;
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.ObjectInputStream;
|
import java.io.ObjectInputStream;
|
||||||
@ -91,7 +90,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (preference.getKey().equals(youtubeRestrictedModeEnabledKey)) {
|
if (preference.getKey().equals(youtubeRestrictedModeEnabledKey)) {
|
||||||
Context context = getContext();
|
final Context context = getContext();
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
DownloaderImpl.getInstance().updateYoutubeRestrictedModeCookies(context);
|
DownloaderImpl.getInstance().updateYoutubeRestrictedModeCookies(context);
|
||||||
} else {
|
} else {
|
||||||
@ -105,7 +104,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||||
|
|
||||||
String homeDir = getActivity().getApplicationInfo().dataDir;
|
final String homeDir = getActivity().getApplicationInfo().dataDir;
|
||||||
databasesDir = new File(homeDir + "/databases");
|
databasesDir = new File(homeDir + "/databases");
|
||||||
newpipeDb = new File(homeDir + "/databases/newpipe.db");
|
newpipeDb = new File(homeDir + "/databases/newpipe.db");
|
||||||
newpipeDbJournal = new File(homeDir + "/databases/newpipe.db-journal");
|
newpipeDbJournal = new File(homeDir + "/databases/newpipe.db-journal");
|
||||||
@ -117,9 +116,9 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
|
|
||||||
addPreferencesFromResource(R.xml.content_settings);
|
addPreferencesFromResource(R.xml.content_settings);
|
||||||
|
|
||||||
Preference importDataPreference = findPreference(getString(R.string.import_data));
|
final Preference importDataPreference = findPreference(getString(R.string.import_data));
|
||||||
importDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
importDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
||||||
Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
final Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
||||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, false)
|
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, false)
|
||||||
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
|
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
|
||||||
@ -128,9 +127,9 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
return true;
|
return true;
|
||||||
});
|
});
|
||||||
|
|
||||||
Preference exportDataPreference = findPreference(getString(R.string.export_data));
|
final Preference exportDataPreference = findPreference(getString(R.string.export_data));
|
||||||
exportDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
exportDataPreference.setOnPreferenceClickListener((Preference p) -> {
|
||||||
Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
final Intent i = new Intent(getActivity(), FilePickerActivityHelper.class)
|
||||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_MULTIPLE, false)
|
||||||
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
|
.putExtra(FilePickerActivityHelper.EXTRA_ALLOW_CREATE_DIR, true)
|
||||||
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
|
.putExtra(FilePickerActivityHelper.EXTRA_MODE,
|
||||||
@ -175,12 +174,12 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
|
|
||||||
if ((requestCode == REQUEST_IMPORT_PATH || requestCode == REQUEST_EXPORT_PATH)
|
if ((requestCode == REQUEST_IMPORT_PATH || requestCode == REQUEST_EXPORT_PATH)
|
||||||
&& resultCode == Activity.RESULT_OK && data.getData() != null) {
|
&& resultCode == Activity.RESULT_OK && data.getData() != null) {
|
||||||
String path = Utils.getFileForUri(data.getData()).getAbsolutePath();
|
final String path = Utils.getFileForUri(data.getData()).getAbsolutePath();
|
||||||
if (requestCode == REQUEST_EXPORT_PATH) {
|
if (requestCode == REQUEST_EXPORT_PATH) {
|
||||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
|
final SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd_HHmmss", Locale.US);
|
||||||
exportDatabase(path + "/NewPipeData-" + sdf.format(new Date()) + ".zip");
|
exportDatabase(path + "/NewPipeData-" + sdf.format(new Date()) + ".zip");
|
||||||
} else {
|
} else {
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
final AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
|
||||||
builder.setMessage(R.string.override_current_data)
|
builder.setMessage(R.string.override_current_data)
|
||||||
.setPositiveButton(getString(R.string.finish),
|
.setPositiveButton(getString(R.string.finish),
|
||||||
(DialogInterface d, int id) -> importDatabase(path))
|
(DialogInterface d, int id) -> importDatabase(path))
|
||||||
@ -196,7 +195,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
//checkpoint before export
|
//checkpoint before export
|
||||||
NewPipeDatabase.checkpoint();
|
NewPipeDatabase.checkpoint();
|
||||||
|
|
||||||
ZipOutputStream outZip = new ZipOutputStream(
|
final ZipOutputStream outZip = new ZipOutputStream(
|
||||||
new BufferedOutputStream(
|
new BufferedOutputStream(
|
||||||
new FileOutputStream(path)));
|
new FileOutputStream(path)));
|
||||||
ZipHelper.addFileToZip(outZip, newpipeDb.getPath(), "newpipe.db");
|
ZipHelper.addFileToZip(outZip, newpipeDb.getPath(), "newpipe.db");
|
||||||
@ -208,7 +207,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
|
|
||||||
Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT)
|
Toast.makeText(getContext(), R.string.export_complete_toast, Toast.LENGTH_SHORT)
|
||||||
.show();
|
.show();
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
onError(e);
|
onError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -217,12 +216,11 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
ObjectOutputStream output = null;
|
ObjectOutputStream output = null;
|
||||||
try {
|
try {
|
||||||
output = new ObjectOutputStream(new FileOutputStream(dst));
|
output = new ObjectOutputStream(new FileOutputStream(dst));
|
||||||
SharedPreferences pref = PreferenceManager.getDefaultSharedPreferences(getContext());
|
final SharedPreferences pref
|
||||||
|
= PreferenceManager.getDefaultSharedPreferences(getContext());
|
||||||
output.writeObject(pref.getAll());
|
output.writeObject(pref.getAll());
|
||||||
|
|
||||||
} catch (FileNotFoundException e) {
|
} catch (final IOException e) {
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
@ -230,7 +228,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
output.flush();
|
output.flush();
|
||||||
output.close();
|
output.close();
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (final IOException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,14 +239,14 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
ZipFile zipFile = null;
|
ZipFile zipFile = null;
|
||||||
try {
|
try {
|
||||||
zipFile = new ZipFile(filePath);
|
zipFile = new ZipFile(filePath);
|
||||||
} catch (IOException ioe) {
|
} catch (final IOException ioe) {
|
||||||
Toast.makeText(getContext(), R.string.no_valid_zip_file, Toast.LENGTH_SHORT)
|
Toast.makeText(getContext(), R.string.no_valid_zip_file, Toast.LENGTH_SHORT)
|
||||||
.show();
|
.show();
|
||||||
return;
|
return;
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
zipFile.close();
|
zipFile.close();
|
||||||
} catch (Exception ignored) {
|
} catch (final Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -272,7 +270,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
//If settings file exist, ask if it should be imported.
|
//If settings file exist, ask if it should be imported.
|
||||||
if (ZipHelper.extractFileFromZip(filePath, newpipeSettings.getPath(),
|
if (ZipHelper.extractFileFromZip(filePath, newpipeSettings.getPath(),
|
||||||
"newpipe.settings")) {
|
"newpipe.settings")) {
|
||||||
AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
final AlertDialog.Builder alert = new AlertDialog.Builder(getContext());
|
||||||
alert.setTitle(R.string.import_settings);
|
alert.setTitle(R.string.import_settings);
|
||||||
|
|
||||||
alert.setNegativeButton(android.R.string.no, (dialog, which) -> {
|
alert.setNegativeButton(android.R.string.no, (dialog, which) -> {
|
||||||
@ -291,7 +289,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
// restart app to properly load db
|
// restart app to properly load db
|
||||||
System.exit(0);
|
System.exit(0);
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
onError(e);
|
onError(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -300,13 +298,13 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
ObjectInputStream input = null;
|
ObjectInputStream input = null;
|
||||||
try {
|
try {
|
||||||
input = new ObjectInputStream(new FileInputStream(src));
|
input = new ObjectInputStream(new FileInputStream(src));
|
||||||
SharedPreferences.Editor prefEdit = PreferenceManager
|
final SharedPreferences.Editor prefEdit = PreferenceManager
|
||||||
.getDefaultSharedPreferences(getContext()).edit();
|
.getDefaultSharedPreferences(getContext()).edit();
|
||||||
prefEdit.clear();
|
prefEdit.clear();
|
||||||
Map<String, ?> entries = (Map<String, ?>) input.readObject();
|
final Map<String, ?> entries = (Map<String, ?>) input.readObject();
|
||||||
for (Map.Entry<String, ?> entry : entries.entrySet()) {
|
for (final Map.Entry<String, ?> entry : entries.entrySet()) {
|
||||||
Object v = entry.getValue();
|
final Object v = entry.getValue();
|
||||||
String key = entry.getKey();
|
final String key = entry.getKey();
|
||||||
|
|
||||||
if (v instanceof Boolean) {
|
if (v instanceof Boolean) {
|
||||||
prefEdit.putBoolean(key, (Boolean) v);
|
prefEdit.putBoolean(key, (Boolean) v);
|
||||||
@ -321,18 +319,14 @@ public class ContentSettingsFragment extends BasePreferenceFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
prefEdit.commit();
|
prefEdit.commit();
|
||||||
} catch (FileNotFoundException e) {
|
} catch (final IOException | ClassNotFoundException e) {
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (ClassNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if (input != null) {
|
if (input != null) {
|
||||||
input.close();
|
input.close();
|
||||||
}
|
}
|
||||||
} catch (IOException ex) {
|
} catch (final IOException ex) {
|
||||||
ex.printStackTrace();
|
ex.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -120,7 +120,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
rawUri = URLDecoder.decode(rawUri, StandardCharsets.UTF_8.name());
|
rawUri = URLDecoder.decode(rawUri, StandardCharsets.UTF_8.name());
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (final UnsupportedEncodingException e) {
|
||||||
// nothing to do
|
// nothing to do
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean hasInvalidPath(final String prefKey) {
|
private boolean hasInvalidPath(final String prefKey) {
|
||||||
String value = defaultPreferences.getString(prefKey, null);
|
final String value = defaultPreferences.getString(prefKey, null);
|
||||||
return value == null || value.isEmpty();
|
return value == null || value.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,20 +152,20 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Uri uri = Uri.parse(oldPath);
|
final Uri uri = Uri.parse(oldPath);
|
||||||
|
|
||||||
context.getContentResolver()
|
context.getContentResolver()
|
||||||
.releasePersistableUriPermission(uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
.releasePersistableUriPermission(uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||||
context.revokeUriPermission(uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
context.revokeUriPermission(uri, StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||||
|
|
||||||
Log.i(TAG, "Revoke old path permissions success on " + oldPath);
|
Log.i(TAG, "Revoke old path permissions success on " + oldPath);
|
||||||
} catch (Exception err) {
|
} catch (final Exception err) {
|
||||||
Log.e(TAG, "Error revoking old path permissions on " + oldPath, err);
|
Log.e(TAG, "Error revoking old path permissions on " + oldPath, err);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showMessageDialog(@StringRes final int title, @StringRes final int message) {
|
private void showMessageDialog(@StringRes final int title, @StringRes final int message) {
|
||||||
AlertDialog.Builder msg = new AlertDialog.Builder(ctx);
|
final AlertDialog.Builder msg = new AlertDialog.Builder(ctx);
|
||||||
msg.setTitle(title);
|
msg.setTitle(title);
|
||||||
msg.setMessage(message);
|
msg.setMessage(message);
|
||||||
msg.setPositiveButton(getString(R.string.finish), null);
|
msg.setPositiveButton(getString(R.string.finish), null);
|
||||||
@ -179,8 +179,8 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||||||
+ "preference = [" + preference + "]");
|
+ "preference = [" + preference + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
String key = preference.getKey();
|
final String key = preference.getKey();
|
||||||
int request;
|
final int request;
|
||||||
|
|
||||||
if (key.equals(storageUseSafPreference)) {
|
if (key.equals(storageUseSafPreference)) {
|
||||||
Toast.makeText(getContext(), R.string.download_choose_new_path,
|
Toast.makeText(getContext(), R.string.download_choose_new_path,
|
||||||
@ -194,7 +194,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||||||
return super.onPreferenceTreeClick(preference);
|
return super.onPreferenceTreeClick(preference);
|
||||||
}
|
}
|
||||||
|
|
||||||
Intent i;
|
final Intent i;
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||||
&& NewPipeSettings.useStorageAccessFramework(ctx)) {
|
&& NewPipeSettings.useStorageAccessFramework(ctx)) {
|
||||||
i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
i = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)
|
||||||
@ -229,7 +229,7 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
String key;
|
final String key;
|
||||||
if (requestCode == REQUEST_DOWNLOAD_VIDEO_PATH) {
|
if (requestCode == REQUEST_DOWNLOAD_VIDEO_PATH) {
|
||||||
key = downloadPathVideoPreference;
|
key = downloadPathVideoPreference;
|
||||||
} else if (requestCode == REQUEST_DOWNLOAD_AUDIO_PATH) {
|
} else if (requestCode == REQUEST_DOWNLOAD_AUDIO_PATH) {
|
||||||
@ -262,19 +262,20 @@ public class DownloadSettingsFragment extends BasePreferenceFragment {
|
|||||||
context.grantUriPermission(context.getPackageName(), uri,
|
context.grantUriPermission(context.getPackageName(), uri,
|
||||||
StoredDirectoryHelper.PERMISSION_FLAGS);
|
StoredDirectoryHelper.PERMISSION_FLAGS);
|
||||||
|
|
||||||
StoredDirectoryHelper mainStorage = new StoredDirectoryHelper(context, uri, null);
|
final StoredDirectoryHelper mainStorage
|
||||||
|
= new StoredDirectoryHelper(context, uri, null);
|
||||||
Log.i(TAG, "Acquiring tree success from " + uri.toString());
|
Log.i(TAG, "Acquiring tree success from " + uri.toString());
|
||||||
|
|
||||||
if (!mainStorage.canWrite()) {
|
if (!mainStorage.canWrite()) {
|
||||||
throw new IOException("No write permissions on " + uri.toString());
|
throw new IOException("No write permissions on " + uri.toString());
|
||||||
}
|
}
|
||||||
} catch (IOException err) {
|
} catch (final IOException err) {
|
||||||
Log.e(TAG, "Error acquiring tree from " + uri.toString(), err);
|
Log.e(TAG, "Error acquiring tree from " + uri.toString(), err);
|
||||||
showMessageDialog(R.string.general_error, R.string.no_available_dir);
|
showMessageDialog(R.string.general_error, R.string.no_available_dir);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
File target = Utils.getFileForUri(uri);
|
final File target = Utils.getFileForUri(uri);
|
||||||
if (!target.canWrite()) {
|
if (!target.canWrite()) {
|
||||||
showMessageDialog(R.string.download_to_sdcard_error_title,
|
showMessageDialog(R.string.download_to_sdcard_error_title,
|
||||||
R.string.download_to_sdcard_error_message);
|
R.string.download_to_sdcard_error_message);
|
||||||
|
@ -4,12 +4,12 @@ import android.os.Bundle;
|
|||||||
|
|
||||||
import androidx.preference.Preference;
|
import androidx.preference.Preference;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
|
||||||
import org.schabi.newpipe.CheckForNewAppVersionTask;
|
import org.schabi.newpipe.CheckForNewAppVersionTask;
|
||||||
|
import org.schabi.newpipe.MainActivity;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
|
||||||
public class MainSettingsFragment extends BasePreferenceFragment {
|
public class MainSettingsFragment extends BasePreferenceFragment {
|
||||||
public static final boolean DEBUG = !BuildConfig.BUILD_TYPE.equals("release");
|
public static final boolean DEBUG = MainActivity.DEBUG;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) {
|
||||||
|
@ -60,14 +60,14 @@ public final class NewPipeSettings {
|
|||||||
|
|
||||||
private static void getDir(final Context context, final int keyID,
|
private static void getDir(final Context context, final int keyID,
|
||||||
final String defaultDirectoryName) {
|
final String defaultDirectoryName) {
|
||||||
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
final String key = context.getString(keyID);
|
final String key = context.getString(keyID);
|
||||||
String downloadPath = prefs.getString(key, null);
|
final String downloadPath = prefs.getString(key, null);
|
||||||
if ((downloadPath != null) && (!downloadPath.isEmpty())) {
|
if ((downloadPath != null) && (!downloadPath.isEmpty())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
SharedPreferences.Editor spEditor = prefs.edit();
|
final SharedPreferences.Editor spEditor = prefs.edit();
|
||||||
spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName)));
|
spEditor.putString(key, getNewPipeChildFolderPathForDir(getDir(defaultDirectoryName)));
|
||||||
spEditor.apply();
|
spEditor.apply();
|
||||||
}
|
}
|
||||||
|
@ -96,16 +96,16 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void initViews(@NonNull final View rootView) {
|
private void initViews(@NonNull final View rootView) {
|
||||||
TextView instanceHelpTV = rootView.findViewById(R.id.instanceHelpTV);
|
final TextView instanceHelpTV = rootView.findViewById(R.id.instanceHelpTV);
|
||||||
instanceHelpTV.setText(getString(R.string.peertube_instance_url_help,
|
instanceHelpTV.setText(getString(R.string.peertube_instance_url_help,
|
||||||
getString(R.string.peertube_instance_list_url)));
|
getString(R.string.peertube_instance_list_url)));
|
||||||
|
|
||||||
initButton(rootView);
|
initButton(rootView);
|
||||||
|
|
||||||
RecyclerView listInstances = rootView.findViewById(R.id.instances);
|
final RecyclerView listInstances = rootView.findViewById(R.id.instances);
|
||||||
listInstances.setLayoutManager(new LinearLayoutManager(requireContext()));
|
listInstances.setLayoutManager(new LinearLayoutManager(requireContext()));
|
||||||
|
|
||||||
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
final ItemTouchHelper itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
||||||
itemTouchHelper.attachToRecyclerView(listInstances);
|
itemTouchHelper.attachToRecyclerView(listInstances);
|
||||||
|
|
||||||
instanceListAdapter = new InstanceListAdapter(requireContext(), itemTouchHelper);
|
instanceListAdapter = new InstanceListAdapter(requireContext(), itemTouchHelper);
|
||||||
@ -178,7 +178,7 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
|
|
||||||
private void updateTitle() {
|
private void updateTitle() {
|
||||||
if (getActivity() instanceof AppCompatActivity) {
|
if (getActivity() instanceof AppCompatActivity) {
|
||||||
ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
final ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setTitle(R.string.peertube_instance_url_title);
|
actionBar.setTitle(R.string.peertube_instance_url_title);
|
||||||
}
|
}
|
||||||
@ -186,14 +186,14 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void saveChanges() {
|
private void saveChanges() {
|
||||||
JsonStringWriter jsonWriter = JsonWriter.string().object().array("instances");
|
final JsonStringWriter jsonWriter = JsonWriter.string().object().array("instances");
|
||||||
for (PeertubeInstance instance : instanceList) {
|
for (final PeertubeInstance instance : instanceList) {
|
||||||
jsonWriter.object();
|
jsonWriter.object();
|
||||||
jsonWriter.value("name", instance.getName());
|
jsonWriter.value("name", instance.getName());
|
||||||
jsonWriter.value("url", instance.getUrl());
|
jsonWriter.value("url", instance.getUrl());
|
||||||
jsonWriter.end();
|
jsonWriter.end();
|
||||||
}
|
}
|
||||||
String jsonToSave = jsonWriter.end().end().done();
|
final String jsonToSave = jsonWriter.end().end().done();
|
||||||
sharedPreferences.edit().putString(savedInstanceListKey, jsonToSave).apply();
|
sharedPreferences.edit().putString(savedInstanceListKey, jsonToSave).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -222,12 +222,12 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
final EditText urlET = new EditText(c);
|
final EditText urlET = new EditText(c);
|
||||||
urlET.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
|
urlET.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_VARIATION_URI);
|
||||||
urlET.setHint(R.string.peertube_instance_add_help);
|
urlET.setHint(R.string.peertube_instance_add_help);
|
||||||
AlertDialog dialog = new AlertDialog.Builder(c)
|
final AlertDialog dialog = new AlertDialog.Builder(c)
|
||||||
.setTitle(R.string.peertube_instance_add_title)
|
.setTitle(R.string.peertube_instance_add_title)
|
||||||
.setIcon(R.drawable.place_holder_peertube)
|
.setIcon(R.drawable.place_holder_peertube)
|
||||||
.setNegativeButton(R.string.cancel, null)
|
.setNegativeButton(R.string.cancel, null)
|
||||||
.setPositiveButton(R.string.finish, (dialog1, which) -> {
|
.setPositiveButton(R.string.finish, (dialog1, which) -> {
|
||||||
String url = urlET.getText().toString();
|
final String url = urlET.getText().toString();
|
||||||
addInstance(url);
|
addInstance(url);
|
||||||
})
|
})
|
||||||
.create();
|
.create();
|
||||||
@ -236,13 +236,13 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void addInstance(final String url) {
|
private void addInstance(final String url) {
|
||||||
String cleanUrl = cleanUrl(url);
|
final String cleanUrl = cleanUrl(url);
|
||||||
if (cleanUrl == null) {
|
if (cleanUrl == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
progressBar.setVisibility(View.VISIBLE);
|
||||||
Disposable disposable = Single.fromCallable(() -> {
|
final Disposable disposable = Single.fromCallable(() -> {
|
||||||
PeertubeInstance instance = new PeertubeInstance(cleanUrl);
|
final PeertubeInstance instance = new PeertubeInstance(cleanUrl);
|
||||||
instance.fetchInstanceMetaData();
|
instance.fetchInstanceMetaData();
|
||||||
return instance;
|
return instance;
|
||||||
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread())
|
||||||
@ -273,7 +273,7 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
// only allow if not already exists
|
// only allow if not already exists
|
||||||
for (PeertubeInstance instance : instanceList) {
|
for (final PeertubeInstance instance : instanceList) {
|
||||||
if (instance.getUrl().equals(cleanUrl)) {
|
if (instance.getUrl().equals(cleanUrl)) {
|
||||||
Toast.makeText(getActivity(), R.string.peertube_instance_add_exists,
|
Toast.makeText(getActivity(), R.string.peertube_instance_add_exists,
|
||||||
Toast.LENGTH_SHORT).show();
|
Toast.LENGTH_SHORT).show();
|
||||||
@ -331,7 +331,7 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int swipeDir) {
|
public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int swipeDir) {
|
||||||
int position = viewHolder.getAdapterPosition();
|
final int position = viewHolder.getAdapterPosition();
|
||||||
// do not allow swiping the selected instance
|
// do not allow swiping the selected instance
|
||||||
if (instanceList.get(position).getUrl().equals(selectedInstance.getUrl())) {
|
if (instanceList.get(position).getUrl().equals(selectedInstance.getUrl())) {
|
||||||
instanceListAdapter.notifyItemChanged(position);
|
instanceListAdapter.notifyItemChanged(position);
|
||||||
@ -372,7 +372,7 @@ public class PeertubeInstanceListFragment extends Fragment {
|
|||||||
@Override
|
@Override
|
||||||
public InstanceListAdapter.TabViewHolder onCreateViewHolder(@NonNull final ViewGroup parent,
|
public InstanceListAdapter.TabViewHolder onCreateViewHolder(@NonNull final ViewGroup parent,
|
||||||
final int viewType) {
|
final int viewType) {
|
||||||
View view = inflater.inflate(R.layout.item_instance, parent, false);
|
final View view = inflater.inflate(R.layout.item_instance, parent, false);
|
||||||
return new InstanceListAdapter.TabViewHolder(view);
|
return new InstanceListAdapter.TabViewHolder(view);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,10 +94,10 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
|
public View onCreateView(@NonNull final LayoutInflater inflater, final ViewGroup container,
|
||||||
final Bundle savedInstanceState) {
|
final Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.select_channel_fragment, container, false);
|
final View v = inflater.inflate(R.layout.select_channel_fragment, container, false);
|
||||||
recyclerView = v.findViewById(R.id.items_list);
|
recyclerView = v.findViewById(R.id.items_list);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
SelectChannelAdapter channelAdapter = new SelectChannelAdapter();
|
final SelectChannelAdapter channelAdapter = new SelectChannelAdapter();
|
||||||
recyclerView.setAdapter(channelAdapter);
|
recyclerView.setAdapter(channelAdapter);
|
||||||
|
|
||||||
progressBar = v.findViewById(R.id.progressBar);
|
progressBar = v.findViewById(R.id.progressBar);
|
||||||
@ -107,7 +107,7 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
emptyView.setVisibility(View.GONE);
|
emptyView.setVisibility(View.GONE);
|
||||||
|
|
||||||
|
|
||||||
SubscriptionManager subscriptionManager = new SubscriptionManager(getContext());
|
final SubscriptionManager subscriptionManager = new SubscriptionManager(getContext());
|
||||||
subscriptionManager.subscriptions().toObservable()
|
subscriptionManager.subscriptions().toObservable()
|
||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
@ -130,7 +130,7 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
|
|
||||||
private void clickedItem(final int position) {
|
private void clickedItem(final int position) {
|
||||||
if (onSelectedListener != null) {
|
if (onSelectedListener != null) {
|
||||||
SubscriptionEntity entry = subscriptions.get(position);
|
final SubscriptionEntity entry = subscriptions.get(position);
|
||||||
onSelectedListener
|
onSelectedListener
|
||||||
.onChannelSelected(entry.getServiceId(), entry.getUrl(), entry.getName());
|
.onChannelSelected(entry.getServiceId(), entry.getUrl(), entry.getName());
|
||||||
}
|
}
|
||||||
@ -199,14 +199,14 @@ public class SelectChannelFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public SelectChannelItemHolder onCreateViewHolder(final ViewGroup parent,
|
public SelectChannelItemHolder onCreateViewHolder(final ViewGroup parent,
|
||||||
final int viewType) {
|
final int viewType) {
|
||||||
View item = LayoutInflater.from(parent.getContext())
|
final View item = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.select_channel_item, parent, false);
|
.inflate(R.layout.select_channel_item, parent, false);
|
||||||
return new SelectChannelItemHolder(item);
|
return new SelectChannelItemHolder(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onBindViewHolder(final SelectChannelItemHolder holder, final int position) {
|
public void onBindViewHolder(final SelectChannelItemHolder holder, final int position) {
|
||||||
SubscriptionEntity entry = subscriptions.get(position);
|
final SubscriptionEntity entry = subscriptions.get(position);
|
||||||
holder.titleView.setText(entry.getName());
|
holder.titleView.setText(entry.getName());
|
||||||
holder.view.setOnClickListener(new View.OnClickListener() {
|
holder.view.setOnClickListener(new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -76,12 +76,12 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
@Override
|
@Override
|
||||||
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
|
public View onCreateView(final LayoutInflater inflater, final ViewGroup container,
|
||||||
final Bundle savedInstanceState) {
|
final Bundle savedInstanceState) {
|
||||||
View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false);
|
final View v = inflater.inflate(R.layout.select_kiosk_fragment, container, false);
|
||||||
recyclerView = v.findViewById(R.id.items_list);
|
recyclerView = v.findViewById(R.id.items_list);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
try {
|
try {
|
||||||
selectKioskAdapter = new SelectKioskAdapter();
|
selectKioskAdapter = new SelectKioskAdapter();
|
||||||
} catch (Exception e) {
|
} catch (final Exception e) {
|
||||||
onError(e);
|
onError(e);
|
||||||
}
|
}
|
||||||
recyclerView.setAdapter(selectKioskAdapter);
|
recyclerView.setAdapter(selectKioskAdapter);
|
||||||
@ -135,9 +135,9 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
private final List<Entry> kioskList = new Vector<>();
|
private final List<Entry> kioskList = new Vector<>();
|
||||||
|
|
||||||
SelectKioskAdapter() throws Exception {
|
SelectKioskAdapter() throws Exception {
|
||||||
for (StreamingService service : NewPipe.getServices()) {
|
for (final StreamingService service : NewPipe.getServices()) {
|
||||||
for (String kioskId : service.getKioskList().getAvailableKiosks()) {
|
for (final String kioskId : service.getKioskList().getAvailableKiosks()) {
|
||||||
String name = String.format(getString(R.string.service_kiosk_string),
|
final String name = String.format(getString(R.string.service_kiosk_string),
|
||||||
service.getServiceInfo().getName(),
|
service.getServiceInfo().getName(),
|
||||||
KioskTranslator.getTranslatedKioskName(kioskId, getContext()));
|
KioskTranslator.getTranslatedKioskName(kioskId, getContext()));
|
||||||
kioskList.add(new Entry(ServiceHelper.getIcon(service.getServiceId()),
|
kioskList.add(new Entry(ServiceHelper.getIcon(service.getServiceId()),
|
||||||
@ -151,7 +151,7 @@ public class SelectKioskFragment extends DialogFragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public SelectKioskItemHolder onCreateViewHolder(final ViewGroup parent, final int type) {
|
public SelectKioskItemHolder onCreateViewHolder(final ViewGroup parent, final int type) {
|
||||||
View item = LayoutInflater.from(parent.getContext())
|
final View item = LayoutInflater.from(parent.getContext())
|
||||||
.inflate(R.layout.select_kiosk_item, parent, false);
|
.inflate(R.layout.select_kiosk_item, parent, false);
|
||||||
return new SelectKioskItemHolder(item);
|
return new SelectKioskItemHolder(item);
|
||||||
}
|
}
|
||||||
|
@ -74,7 +74,7 @@ public class SelectPlaylistFragment extends DialogFragment {
|
|||||||
inflater.inflate(R.layout.select_playlist_fragment, container, false);
|
inflater.inflate(R.layout.select_playlist_fragment, container, false);
|
||||||
recyclerView = v.findViewById(R.id.items_list);
|
recyclerView = v.findViewById(R.id.items_list);
|
||||||
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
|
||||||
SelectPlaylistAdapter playlistAdapter = new SelectPlaylistAdapter();
|
final SelectPlaylistAdapter playlistAdapter = new SelectPlaylistAdapter();
|
||||||
recyclerView.setAdapter(playlistAdapter);
|
recyclerView.setAdapter(playlistAdapter);
|
||||||
|
|
||||||
progressBar = v.findViewById(R.id.progressBar);
|
progressBar = v.findViewById(R.id.progressBar);
|
||||||
|
@ -53,7 +53,7 @@ public class SettingsActivity extends AppCompatActivity
|
|||||||
super.onCreate(savedInstanceBundle);
|
super.onCreate(savedInstanceBundle);
|
||||||
setContentView(R.layout.settings_layout);
|
setContentView(R.layout.settings_layout);
|
||||||
|
|
||||||
Toolbar toolbar = findViewById(R.id.toolbar);
|
final Toolbar toolbar = findViewById(R.id.toolbar);
|
||||||
setSupportActionBar(toolbar);
|
setSupportActionBar(toolbar);
|
||||||
|
|
||||||
if (savedInstanceBundle == null) {
|
if (savedInstanceBundle == null) {
|
||||||
@ -69,7 +69,7 @@ public class SettingsActivity extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onCreateOptionsMenu(final Menu menu) {
|
public boolean onCreateOptionsMenu(final Menu menu) {
|
||||||
ActionBar actionBar = getSupportActionBar();
|
final ActionBar actionBar = getSupportActionBar();
|
||||||
if (actionBar != null) {
|
if (actionBar != null) {
|
||||||
actionBar.setDisplayHomeAsUpEnabled(true);
|
actionBar.setDisplayHomeAsUpEnabled(true);
|
||||||
actionBar.setDisplayShowTitleEnabled(true);
|
actionBar.setDisplayShowTitleEnabled(true);
|
||||||
@ -80,7 +80,7 @@ public class SettingsActivity extends AppCompatActivity
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onOptionsItemSelected(final MenuItem item) {
|
public boolean onOptionsItemSelected(final MenuItem item) {
|
||||||
int id = item.getItemId();
|
final int id = item.getItemId();
|
||||||
if (id == android.R.id.home) {
|
if (id == android.R.id.home) {
|
||||||
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
|
if (getSupportFragmentManager().getBackStackEntryCount() == 0) {
|
||||||
finish();
|
finish();
|
||||||
@ -95,7 +95,7 @@ public class SettingsActivity extends AppCompatActivity
|
|||||||
@Override
|
@Override
|
||||||
public boolean onPreferenceStartFragment(final PreferenceFragmentCompat caller,
|
public boolean onPreferenceStartFragment(final PreferenceFragmentCompat caller,
|
||||||
final Preference preference) {
|
final Preference preference) {
|
||||||
Fragment fragment = Fragment
|
final Fragment fragment = Fragment
|
||||||
.instantiate(this, preference.getFragment(), preference.getExtras());
|
.instantiate(this, preference.getFragment(), preference.getExtras());
|
||||||
getSupportFragmentManager().beginTransaction()
|
getSupportFragmentManager().beginTransaction()
|
||||||
.setCustomAnimations(R.animator.custom_fade_in, R.animator.custom_fade_out,
|
.setCustomAnimations(R.animator.custom_fade_in, R.animator.custom_fade_out,
|
||||||
|
@ -19,7 +19,7 @@ public class UpdateSettingsFragment extends BasePreferenceFragment {
|
|||||||
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
public void onCreate(@Nullable final Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
String updateToggleKey = getString(R.string.update_app_key);
|
final String updateToggleKey = getString(R.string.update_app_key);
|
||||||
findPreference(updateToggleKey).setOnPreferenceChangeListener(updatePreferenceChange);
|
findPreference(updateToggleKey).setOnPreferenceChangeListener(updatePreferenceChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
|
|||||||
// show a snackbar to let the user give permission
|
// show a snackbar to let the user give permission
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
|
||||||
&& s.equals(getString(R.string.minimize_on_exit_key))) {
|
&& s.equals(getString(R.string.minimize_on_exit_key))) {
|
||||||
String newSetting = sharedPreferences.getString(s, null);
|
final String newSetting = sharedPreferences.getString(s, null);
|
||||||
if (newSetting != null
|
if (newSetting != null
|
||||||
&& newSetting.equals(getString(R.string.minimize_on_exit_popup_key))
|
&& newSetting.equals(getString(R.string.minimize_on_exit_popup_key))
|
||||||
&& !Settings.canDrawOverlays(getContext())) {
|
&& !Settings.canDrawOverlays(getContext())) {
|
||||||
@ -68,7 +68,7 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
|
|||||||
final boolean inexactSeek = getPreferenceManager().getSharedPreferences()
|
final boolean inexactSeek = getPreferenceManager().getSharedPreferences()
|
||||||
.getBoolean(res.getString(R.string.use_inexact_seek_key), false);
|
.getBoolean(res.getString(R.string.use_inexact_seek_key), false);
|
||||||
|
|
||||||
for (String durationsValue : durationsValues) {
|
for (final String durationsValue : durationsValues) {
|
||||||
currentDurationValue =
|
currentDurationValue =
|
||||||
Integer.parseInt(durationsValue) / (int) DateUtils.SECOND_IN_MILLIS;
|
Integer.parseInt(durationsValue) / (int) DateUtils.SECOND_IN_MILLIS;
|
||||||
if (inexactSeek && currentDurationValue % 10 == 5) {
|
if (inexactSeek && currentDurationValue % 10 == 5) {
|
||||||
@ -81,7 +81,7 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
|
|||||||
res.getQuantityString(R.plurals.seconds,
|
res.getQuantityString(R.plurals.seconds,
|
||||||
currentDurationValue),
|
currentDurationValue),
|
||||||
currentDurationValue));
|
currentDurationValue));
|
||||||
} catch (Resources.NotFoundException ignored) {
|
} catch (final Resources.NotFoundException ignored) {
|
||||||
// if this happens, the translation is missing,
|
// if this happens, the translation is missing,
|
||||||
// and the english string will be displayed instead
|
// and the english string will be displayed instead
|
||||||
}
|
}
|
||||||
@ -96,7 +96,7 @@ public class VideoAudioSettingsFragment extends BasePreferenceFragment {
|
|||||||
final int newDuration = selectedDuration / (int) DateUtils.SECOND_IN_MILLIS + 5;
|
final int newDuration = selectedDuration / (int) DateUtils.SECOND_IN_MILLIS + 5;
|
||||||
durations.setValue(Integer.toString(newDuration * (int) DateUtils.SECOND_IN_MILLIS));
|
durations.setValue(Integer.toString(newDuration * (int) DateUtils.SECOND_IN_MILLIS));
|
||||||
|
|
||||||
Toast toast = Toast
|
final Toast toast = Toast
|
||||||
.makeText(getContext(),
|
.makeText(getContext(),
|
||||||
getString(R.string.new_seek_duration_toast, newDuration),
|
getString(R.string.new_seek_duration_toast, newDuration),
|
||||||
Toast.LENGTH_LONG);
|
Toast.LENGTH_LONG);
|
||||||
|
@ -173,7 +173,7 @@ public class ChooseTabsFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Dialog.OnClickListener actionListener = (dialog, which) -> {
|
final Dialog.OnClickListener actionListener = (dialog, which) -> {
|
||||||
final ChooseTabListItem selected = availableTabs[which];
|
final ChooseTabListItem selected = availableTabs[which];
|
||||||
addTab(selected.tabId);
|
addTab(selected.tabId);
|
||||||
};
|
};
|
||||||
@ -201,19 +201,19 @@ public class ChooseTabsFragment extends Fragment {
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case KIOSK:
|
case KIOSK:
|
||||||
SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
|
final SelectKioskFragment selectKioskFragment = new SelectKioskFragment();
|
||||||
selectKioskFragment.setOnSelectedListener((serviceId, kioskId, kioskName) ->
|
selectKioskFragment.setOnSelectedListener((serviceId, kioskId, kioskName) ->
|
||||||
addTab(new Tab.KioskTab(serviceId, kioskId)));
|
addTab(new Tab.KioskTab(serviceId, kioskId)));
|
||||||
selectKioskFragment.show(requireFragmentManager(), "select_kiosk");
|
selectKioskFragment.show(requireFragmentManager(), "select_kiosk");
|
||||||
return;
|
return;
|
||||||
case CHANNEL:
|
case CHANNEL:
|
||||||
SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
|
final SelectChannelFragment selectChannelFragment = new SelectChannelFragment();
|
||||||
selectChannelFragment.setOnSelectedListener((serviceId, url, name) ->
|
selectChannelFragment.setOnSelectedListener((serviceId, url, name) ->
|
||||||
addTab(new Tab.ChannelTab(serviceId, url, name)));
|
addTab(new Tab.ChannelTab(serviceId, url, name)));
|
||||||
selectChannelFragment.show(requireFragmentManager(), "select_channel");
|
selectChannelFragment.show(requireFragmentManager(), "select_channel");
|
||||||
return;
|
return;
|
||||||
case PLAYLIST:
|
case PLAYLIST:
|
||||||
SelectPlaylistFragment selectPlaylistFragment = new SelectPlaylistFragment();
|
final SelectPlaylistFragment selectPlaylistFragment = new SelectPlaylistFragment();
|
||||||
selectPlaylistFragment.setOnSelectedListener(
|
selectPlaylistFragment.setOnSelectedListener(
|
||||||
new SelectPlaylistFragment.OnSelectedListener() {
|
new SelectPlaylistFragment.OnSelectedListener() {
|
||||||
@Override
|
@Override
|
||||||
@ -238,7 +238,7 @@ public class ChooseTabsFragment extends Fragment {
|
|||||||
private ChooseTabListItem[] getAvailableTabs(final Context context) {
|
private ChooseTabListItem[] getAvailableTabs(final Context context) {
|
||||||
final ArrayList<ChooseTabListItem> returnList = new ArrayList<>();
|
final ArrayList<ChooseTabListItem> returnList = new ArrayList<>();
|
||||||
|
|
||||||
for (Tab.Type type : Tab.Type.values()) {
|
for (final Tab.Type type : Tab.Type.values()) {
|
||||||
final Tab tab = type.getTab();
|
final Tab tab = type.getTab();
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case BLANK:
|
case BLANK:
|
||||||
@ -329,7 +329,7 @@ public class ChooseTabsFragment extends Fragment {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int swipeDir) {
|
public void onSwiped(final RecyclerView.ViewHolder viewHolder, final int swipeDir) {
|
||||||
int position = viewHolder.getAdapterPosition();
|
final int position = viewHolder.getAdapterPosition();
|
||||||
tabList.remove(position);
|
tabList.remove(position);
|
||||||
selectedTabsAdapter.notifyItemRemoved(position);
|
selectedTabsAdapter.notifyItemRemoved(position);
|
||||||
|
|
||||||
|
@ -65,7 +65,7 @@ public abstract class Tab {
|
|||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Type typeFrom(final int tabId) {
|
public static Type typeFrom(final int tabId) {
|
||||||
for (Type available : Type.values()) {
|
for (final Type available : Type.values()) {
|
||||||
if (available.getTabId() == tabId) {
|
if (available.getTabId() == tabId) {
|
||||||
return available;
|
return available;
|
||||||
}
|
}
|
||||||
@ -481,7 +481,7 @@ public abstract class Tab {
|
|||||||
try {
|
try {
|
||||||
final StreamingService service = NewPipe.getService(kioskServiceId);
|
final StreamingService service = NewPipe.getService(kioskServiceId);
|
||||||
kioskId = service.getKioskList().getDefaultKioskId();
|
kioskId = service.getKioskList().getDefaultKioskId();
|
||||||
} catch (ExtractionException e) {
|
} catch (final ExtractionException e) {
|
||||||
ErrorActivity.reportError(context, e, null, null,
|
ErrorActivity.reportError(context, e, null, null,
|
||||||
ErrorActivity.ErrorInfo.make(UserAction.REQUESTED_KIOSK, "none",
|
ErrorActivity.ErrorInfo.make(UserAction.REQUESTED_KIOSK, "none",
|
||||||
"Loading default kiosk from selected service", 0));
|
"Loading default kiosk from selected service", 0));
|
||||||
|
@ -59,7 +59,7 @@ public final class TabsJsonHelper {
|
|||||||
|
|
||||||
final JsonArray tabsArray = outerJsonObject.getArray(JSON_TABS_ARRAY_KEY);
|
final JsonArray tabsArray = outerJsonObject.getArray(JSON_TABS_ARRAY_KEY);
|
||||||
|
|
||||||
for (Object o : tabsArray) {
|
for (final Object o : tabsArray) {
|
||||||
if (!(o instanceof JsonObject)) {
|
if (!(o instanceof JsonObject)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ public final class TabsJsonHelper {
|
|||||||
returnTabs.add(tab);
|
returnTabs.add(tab);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (JsonParserException e) {
|
} catch (final JsonParserException e) {
|
||||||
throw new InvalidJsonException(e);
|
throw new InvalidJsonException(e);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -93,7 +93,7 @@ public final class TabsJsonHelper {
|
|||||||
|
|
||||||
jsonWriter.array(JSON_TABS_ARRAY_KEY);
|
jsonWriter.array(JSON_TABS_ARRAY_KEY);
|
||||||
if (tabList != null) {
|
if (tabList != null) {
|
||||||
for (Tab tab : tabList) {
|
for (final Tab tab : tabList) {
|
||||||
tab.writeJsonOn(jsonWriter);
|
tab.writeJsonOn(jsonWriter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ public final class TabsManager {
|
|||||||
final String savedJson = sharedPreferences.getString(savedTabsKey, null);
|
final String savedJson = sharedPreferences.getString(savedTabsKey, null);
|
||||||
try {
|
try {
|
||||||
return TabsJsonHelper.getTabsFromJson(savedJson);
|
return TabsJsonHelper.getTabsFromJson(savedJson);
|
||||||
} catch (TabsJsonHelper.InvalidJsonException e) {
|
} catch (final TabsJsonHelper.InvalidJsonException e) {
|
||||||
Toast.makeText(context, R.string.saved_tabs_invalid_json, Toast.LENGTH_SHORT).show();
|
Toast.makeText(context, R.string.saved_tabs_invalid_json, Toast.LENGTH_SHORT).show();
|
||||||
return getDefaultTabs();
|
return getDefaultTabs();
|
||||||
}
|
}
|
||||||
|
@ -70,7 +70,7 @@ public class DataReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public long readUnsignedInt() throws IOException {
|
public long readUnsignedInt() throws IOException {
|
||||||
long value = readInt();
|
final long value = readInt();
|
||||||
return value & 0xffffffffL;
|
return value & 0xffffffffL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -82,8 +82,9 @@ public class DataReader {
|
|||||||
|
|
||||||
public long readLong() throws IOException {
|
public long readLong() throws IOException {
|
||||||
primitiveRead(LONG_SIZE);
|
primitiveRead(LONG_SIZE);
|
||||||
long high = primitive[0] << 24 | primitive[1] << 16 | primitive[2] << 8 | primitive[3];
|
final long high
|
||||||
long low = primitive[4] << 24 | primitive[5] << 16 | primitive[6] << 8 | primitive[7];
|
= primitive[0] << 24 | primitive[1] << 16 | primitive[2] << 8 | primitive[3];
|
||||||
|
final long low = primitive[4] << 24 | primitive[5] << 16 | primitive[6] << 8 | primitive[7];
|
||||||
return high << 32 | low;
|
return high << 32 | low;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -114,7 +115,7 @@ public class DataReader {
|
|||||||
total += Math.max(stream.read(buffer, offset, count), 0);
|
total += Math.max(stream.read(buffer, offset, count), 0);
|
||||||
} else {
|
} else {
|
||||||
while (count > 0 && !fillBuffer()) {
|
while (count > 0 && !fillBuffer()) {
|
||||||
int read = Math.min(readCount, count);
|
final int read = Math.min(readCount, count);
|
||||||
System.arraycopy(readBuffer, readOffset, buffer, offset, read);
|
System.arraycopy(readBuffer, readOffset, buffer, offset, read);
|
||||||
|
|
||||||
readOffset += read;
|
readOffset += read;
|
||||||
@ -169,7 +170,7 @@ public class DataReader {
|
|||||||
if (viewSize < 1) {
|
if (viewSize < 1) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
int res = DataReader.this.read();
|
final int res = DataReader.this.read();
|
||||||
if (res > 0) {
|
if (res > 0) {
|
||||||
viewSize--;
|
viewSize--;
|
||||||
}
|
}
|
||||||
@ -188,7 +189,7 @@ public class DataReader {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int res = DataReader.this.read(buffer, offset, Math.min(viewSize, count));
|
final int res = DataReader.this.read(buffer, offset, Math.min(viewSize, count));
|
||||||
viewSize -= res;
|
viewSize -= res;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -199,7 +200,7 @@ public class DataReader {
|
|||||||
if (viewSize < 1) {
|
if (viewSize < 1) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int res = (int) DataReader.this.skipBytes(Math.min(amount, viewSize));
|
final int res = (int) DataReader.this.skipBytes(Math.min(amount, viewSize));
|
||||||
viewSize -= res;
|
viewSize -= res;
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
@ -230,8 +231,8 @@ public class DataReader {
|
|||||||
private final short[] primitive = new short[LONG_SIZE];
|
private final short[] primitive = new short[LONG_SIZE];
|
||||||
|
|
||||||
private void primitiveRead(final int amount) throws IOException {
|
private void primitiveRead(final int amount) throws IOException {
|
||||||
byte[] buffer = new byte[amount];
|
final byte[] buffer = new byte[amount];
|
||||||
int read = read(buffer, 0, amount);
|
final int read = read(buffer, 0, amount);
|
||||||
|
|
||||||
if (read != amount) {
|
if (read != amount) {
|
||||||
throw new EOFException("Truncated stream, missing "
|
throw new EOFException("Truncated stream, missing "
|
||||||
|
@ -116,7 +116,7 @@ public class Mp4DashReader {
|
|||||||
tracks[i].trak = moov.trak[i];
|
tracks[i].trak = moov.trak[i];
|
||||||
|
|
||||||
if (moov.mvexTrex != null) {
|
if (moov.mvexTrex != null) {
|
||||||
for (Trex mvexTrex : moov.mvexTrex) {
|
for (final Trex mvexTrex : moov.mvexTrex) {
|
||||||
if (tracks[i].trak.tkhd.trackId == mvexTrex.trackId) {
|
if (tracks[i].trak.tkhd.trackId == mvexTrex.trackId) {
|
||||||
tracks[i].trex = mvexTrex;
|
tracks[i].trex = mvexTrex;
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public Mp4DashChunk getNextChunk(final boolean infoOnly) throws IOException {
|
public Mp4DashChunk getNextChunk(final boolean infoOnly) throws IOException {
|
||||||
Mp4Track track = tracks[selectedTrack];
|
final Mp4Track track = tracks[selectedTrack];
|
||||||
|
|
||||||
while (stream.available()) {
|
while (stream.available()) {
|
||||||
|
|
||||||
@ -233,7 +233,7 @@ public class Mp4DashReader {
|
|||||||
continue; // find another chunk
|
continue; // find another chunk
|
||||||
}
|
}
|
||||||
|
|
||||||
Mp4DashChunk chunk = new Mp4DashChunk();
|
final Mp4DashChunk chunk = new Mp4DashChunk();
|
||||||
chunk.moof = moof;
|
chunk.moof = moof;
|
||||||
if (!infoOnly) {
|
if (!infoOnly) {
|
||||||
chunk.data = stream.getView(moof.traf.trun.chunkSize);
|
chunk.data = stream.getView(moof.traf.trun.chunkSize);
|
||||||
@ -261,13 +261,13 @@ public class Mp4DashReader {
|
|||||||
private String boxName(final int type) {
|
private String boxName(final int type) {
|
||||||
try {
|
try {
|
||||||
return new String(ByteBuffer.allocate(4).putInt(type).array(), "UTF-8");
|
return new String(ByteBuffer.allocate(4).putInt(type).array(), "UTF-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (final UnsupportedEncodingException e) {
|
||||||
return "0x" + Integer.toHexString(type);
|
return "0x" + Integer.toHexString(type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private Box readBox() throws IOException {
|
private Box readBox() throws IOException {
|
||||||
Box b = new Box();
|
final Box b = new Box();
|
||||||
b.offset = stream.position();
|
b.offset = stream.position();
|
||||||
b.size = stream.readUnsignedInt();
|
b.size = stream.readUnsignedInt();
|
||||||
b.type = stream.readInt();
|
b.type = stream.readInt();
|
||||||
@ -280,7 +280,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Box readBox(final int expected) throws IOException {
|
private Box readBox(final int expected) throws IOException {
|
||||||
Box b = readBox();
|
final Box b = readBox();
|
||||||
if (b.type != expected) {
|
if (b.type != expected) {
|
||||||
throw new NoSuchElementException("expected " + boxName(expected)
|
throw new NoSuchElementException("expected " + boxName(expected)
|
||||||
+ " found " + boxName(b));
|
+ " found " + boxName(b));
|
||||||
@ -290,13 +290,13 @@ public class Mp4DashReader {
|
|||||||
|
|
||||||
private byte[] readFullBox(final Box ref) throws IOException {
|
private byte[] readFullBox(final Box ref) throws IOException {
|
||||||
// full box reading is limited to 2 GiB, and should be enough
|
// full box reading is limited to 2 GiB, and should be enough
|
||||||
int size = (int) ref.size;
|
final int size = (int) ref.size;
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
final ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||||
buffer.putInt(size);
|
buffer.putInt(size);
|
||||||
buffer.putInt(ref.type);
|
buffer.putInt(ref.type);
|
||||||
|
|
||||||
int read = size - 8;
|
final int read = size - 8;
|
||||||
|
|
||||||
if (stream.read(buffer.array(), 8, read) != read) {
|
if (stream.read(buffer.array(), 8, read) != read) {
|
||||||
throw new EOFException(String.format("EOF reached in box: type=%s offset=%s size=%s",
|
throw new EOFException(String.format("EOF reached in box: type=%s offset=%s size=%s",
|
||||||
@ -307,7 +307,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void ensure(final Box ref) throws IOException {
|
private void ensure(final Box ref) throws IOException {
|
||||||
long skip = ref.offset + ref.size - stream.position();
|
final long skip = ref.offset + ref.size - stream.position();
|
||||||
|
|
||||||
if (skip == 0) {
|
if (skip == 0) {
|
||||||
return;
|
return;
|
||||||
@ -325,7 +325,7 @@ public class Mp4DashReader {
|
|||||||
Box b;
|
Box b;
|
||||||
while (stream.position() < (ref.offset + ref.size)) {
|
while (stream.position() < (ref.offset + ref.size)) {
|
||||||
b = readBox();
|
b = readBox();
|
||||||
for (int type : expected) {
|
for (final int type : expected) {
|
||||||
if (b.type == type) {
|
if (b.type == type) {
|
||||||
return b;
|
return b;
|
||||||
}
|
}
|
||||||
@ -345,7 +345,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Moof parseMoof(final Box ref, final int trackId) throws IOException {
|
private Moof parseMoof(final Box ref, final int trackId) throws IOException {
|
||||||
Moof obj = new Moof();
|
final Moof obj = new Moof();
|
||||||
|
|
||||||
Box b = readBox(ATOM_MFHD);
|
Box b = readBox(ATOM_MFHD);
|
||||||
obj.mfhdSequenceNumber = parseMfhd();
|
obj.mfhdSequenceNumber = parseMfhd();
|
||||||
@ -372,7 +372,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Traf parseTraf(final Box ref, final int trackId) throws IOException {
|
private Traf parseTraf(final Box ref, final int trackId) throws IOException {
|
||||||
Traf traf = new Traf();
|
final Traf traf = new Traf();
|
||||||
|
|
||||||
Box b = readBox(ATOM_TFHD);
|
Box b = readBox(ATOM_TFHD);
|
||||||
traf.tfhd = parseTfhd(trackId);
|
traf.tfhd = parseTfhd(trackId);
|
||||||
@ -397,7 +397,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Tfhd parseTfhd(final int trackId) throws IOException {
|
private Tfhd parseTfhd(final int trackId) throws IOException {
|
||||||
Tfhd obj = new Tfhd();
|
final Tfhd obj = new Tfhd();
|
||||||
|
|
||||||
obj.bFlags = stream.readInt();
|
obj.bFlags = stream.readInt();
|
||||||
obj.trackId = stream.readInt();
|
obj.trackId = stream.readInt();
|
||||||
@ -426,13 +426,13 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private long parseTfdt() throws IOException {
|
private long parseTfdt() throws IOException {
|
||||||
int version = stream.read();
|
final int version = stream.read();
|
||||||
stream.skipBytes(3); // flags
|
stream.skipBytes(3); // flags
|
||||||
return version == 0 ? stream.readUnsignedInt() : stream.readLong();
|
return version == 0 ? stream.readUnsignedInt() : stream.readLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Trun parseTrun() throws IOException {
|
private Trun parseTrun() throws IOException {
|
||||||
Trun obj = new Trun();
|
final Trun obj = new Trun();
|
||||||
obj.bFlags = stream.readInt();
|
obj.bFlags = stream.readInt();
|
||||||
obj.entryCount = stream.readInt(); // unsigned int
|
obj.entryCount = stream.readInt(); // unsigned int
|
||||||
|
|
||||||
@ -461,7 +461,7 @@ public class Mp4DashReader {
|
|||||||
stream.read(obj.bEntries);
|
stream.read(obj.bEntries);
|
||||||
|
|
||||||
for (int i = 0; i < obj.entryCount; i++) {
|
for (int i = 0; i < obj.entryCount; i++) {
|
||||||
TrunEntry entry = obj.getEntry(i);
|
final TrunEntry entry = obj.getEntry(i);
|
||||||
if (hasFlag(obj.bFlags, 0x0100)) {
|
if (hasFlag(obj.bFlags, 0x0100)) {
|
||||||
obj.chunkDuration += entry.sampleDuration;
|
obj.chunkDuration += entry.sampleDuration;
|
||||||
}
|
}
|
||||||
@ -480,7 +480,7 @@ public class Mp4DashReader {
|
|||||||
|
|
||||||
private int[] parseFtyp(final Box ref) throws IOException {
|
private int[] parseFtyp(final Box ref) throws IOException {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
int[] list = new int[(int) ((ref.offset + ref.size - stream.position() - 4) / 4)];
|
final int[] list = new int[(int) ((ref.offset + ref.size - stream.position() - 4) / 4)];
|
||||||
|
|
||||||
list[i++] = stream.readInt(); // major brand
|
list[i++] = stream.readInt(); // major brand
|
||||||
|
|
||||||
@ -494,14 +494,14 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Mvhd parseMvhd() throws IOException {
|
private Mvhd parseMvhd() throws IOException {
|
||||||
int version = stream.read();
|
final int version = stream.read();
|
||||||
stream.skipBytes(3); // flags
|
stream.skipBytes(3); // flags
|
||||||
|
|
||||||
// creation entries_time
|
// creation entries_time
|
||||||
// modification entries_time
|
// modification entries_time
|
||||||
stream.skipBytes(2 * (version == 0 ? 4 : 8));
|
stream.skipBytes(2 * (version == 0 ? 4 : 8));
|
||||||
|
|
||||||
Mvhd obj = new Mvhd();
|
final Mvhd obj = new Mvhd();
|
||||||
obj.timeScale = stream.readUnsignedInt();
|
obj.timeScale = stream.readUnsignedInt();
|
||||||
|
|
||||||
// chunkDuration
|
// chunkDuration
|
||||||
@ -520,9 +520,9 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Tkhd parseTkhd() throws IOException {
|
private Tkhd parseTkhd() throws IOException {
|
||||||
int version = stream.read();
|
final int version = stream.read();
|
||||||
|
|
||||||
Tkhd obj = new Tkhd();
|
final Tkhd obj = new Tkhd();
|
||||||
|
|
||||||
// flags
|
// flags
|
||||||
// creation entries_time
|
// creation entries_time
|
||||||
@ -553,7 +553,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Trak parseTrak(final Box ref) throws IOException {
|
private Trak parseTrak(final Box ref) throws IOException {
|
||||||
Trak trak = new Trak();
|
final Trak trak = new Trak();
|
||||||
|
|
||||||
Box b = readBox(ATOM_TKHD);
|
Box b = readBox(ATOM_TKHD);
|
||||||
trak.tkhd = parseTkhd();
|
trak.tkhd = parseTkhd();
|
||||||
@ -576,7 +576,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Mdia parseMdia(final Box ref) throws IOException {
|
private Mdia parseMdia(final Box ref) throws IOException {
|
||||||
Mdia obj = new Mdia();
|
final Mdia obj = new Mdia();
|
||||||
|
|
||||||
Box b;
|
Box b;
|
||||||
while ((b = untilBox(ref, ATOM_MDHD, ATOM_HDLR, ATOM_MINF)) != null) {
|
while ((b = untilBox(ref, ATOM_MDHD, ATOM_HDLR, ATOM_MINF)) != null) {
|
||||||
@ -585,8 +585,8 @@ public class Mp4DashReader {
|
|||||||
obj.mdhd = readFullBox(b);
|
obj.mdhd = readFullBox(b);
|
||||||
|
|
||||||
// read time scale
|
// read time scale
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(obj.mdhd);
|
final ByteBuffer buffer = ByteBuffer.wrap(obj.mdhd);
|
||||||
byte version = buffer.get(8);
|
final byte version = buffer.get(8);
|
||||||
buffer.position(12 + ((version == 0 ? 4 : 8) * 2));
|
buffer.position(12 + ((version == 0 ? 4 : 8) * 2));
|
||||||
obj.mdhdTimeScale = buffer.getInt();
|
obj.mdhdTimeScale = buffer.getInt();
|
||||||
break;
|
break;
|
||||||
@ -608,7 +608,7 @@ public class Mp4DashReader {
|
|||||||
// flags
|
// flags
|
||||||
stream.skipBytes(4);
|
stream.skipBytes(4);
|
||||||
|
|
||||||
Hdlr obj = new Hdlr();
|
final Hdlr obj = new Hdlr();
|
||||||
obj.bReserved = new byte[12];
|
obj.bReserved = new byte[12];
|
||||||
|
|
||||||
obj.type = stream.readInt();
|
obj.type = stream.readInt();
|
||||||
@ -623,11 +623,11 @@ public class Mp4DashReader {
|
|||||||
|
|
||||||
private Moov parseMoov(final Box ref) throws IOException {
|
private Moov parseMoov(final Box ref) throws IOException {
|
||||||
Box b = readBox(ATOM_MVHD);
|
Box b = readBox(ATOM_MVHD);
|
||||||
Moov moov = new Moov();
|
final Moov moov = new Moov();
|
||||||
moov.mvhd = parseMvhd();
|
moov.mvhd = parseMvhd();
|
||||||
ensure(b);
|
ensure(b);
|
||||||
|
|
||||||
ArrayList<Trak> tmp = new ArrayList<>((int) moov.mvhd.nextTrackId);
|
final ArrayList<Trak> tmp = new ArrayList<>((int) moov.mvhd.nextTrackId);
|
||||||
while ((b = untilBox(ref, ATOM_TRAK, ATOM_MVEX)) != null) {
|
while ((b = untilBox(ref, ATOM_TRAK, ATOM_MVEX)) != null) {
|
||||||
|
|
||||||
switch (b.type) {
|
switch (b.type) {
|
||||||
@ -648,7 +648,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Trex[] parseMvex(final Box ref, final int possibleTrackCount) throws IOException {
|
private Trex[] parseMvex(final Box ref, final int possibleTrackCount) throws IOException {
|
||||||
ArrayList<Trex> tmp = new ArrayList<>(possibleTrackCount);
|
final ArrayList<Trex> tmp = new ArrayList<>(possibleTrackCount);
|
||||||
|
|
||||||
Box b;
|
Box b;
|
||||||
while ((b = untilBox(ref, ATOM_TREX)) != null) {
|
while ((b = untilBox(ref, ATOM_TREX)) != null) {
|
||||||
@ -664,7 +664,7 @@ public class Mp4DashReader {
|
|||||||
// flags
|
// flags
|
||||||
stream.skipBytes(4);
|
stream.skipBytes(4);
|
||||||
|
|
||||||
Trex obj = new Trex();
|
final Trex obj = new Trex();
|
||||||
obj.trackId = stream.readInt();
|
obj.trackId = stream.readInt();
|
||||||
obj.defaultSampleDescriptionIndex = stream.readInt();
|
obj.defaultSampleDescriptionIndex = stream.readInt();
|
||||||
obj.defaultSampleDuration = stream.readInt();
|
obj.defaultSampleDuration = stream.readInt();
|
||||||
@ -675,17 +675,17 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Elst parseEdts(final Box ref) throws IOException {
|
private Elst parseEdts(final Box ref) throws IOException {
|
||||||
Box b = untilBox(ref, ATOM_ELST);
|
final Box b = untilBox(ref, ATOM_ELST);
|
||||||
if (b == null) {
|
if (b == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Elst obj = new Elst();
|
final Elst obj = new Elst();
|
||||||
|
|
||||||
boolean v1 = stream.read() == 1;
|
final boolean v1 = stream.read() == 1;
|
||||||
stream.skipBytes(3); // flags
|
stream.skipBytes(3); // flags
|
||||||
|
|
||||||
int entryCount = stream.readInt();
|
final int entryCount = stream.readInt();
|
||||||
if (entryCount < 1) {
|
if (entryCount < 1) {
|
||||||
obj.bMediaRate = 0x00010000; // default media rate (1.0)
|
obj.bMediaRate = 0x00010000; // default media rate (1.0)
|
||||||
return obj;
|
return obj;
|
||||||
@ -707,7 +707,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private Minf parseMinf(final Box ref) throws IOException {
|
private Minf parseMinf(final Box ref) throws IOException {
|
||||||
Minf obj = new Minf();
|
final Minf obj = new Minf();
|
||||||
|
|
||||||
Box b;
|
Box b;
|
||||||
while ((b = untilAnyBox(ref)) != null) {
|
while ((b = untilAnyBox(ref)) != null) {
|
||||||
@ -738,7 +738,7 @@ public class Mp4DashReader {
|
|||||||
* @return stsd box inside
|
* @return stsd box inside
|
||||||
*/
|
*/
|
||||||
private byte[] parseStbl(final Box ref) throws IOException {
|
private byte[] parseStbl(final Box ref) throws IOException {
|
||||||
Box b = untilBox(ref, ATOM_STSD);
|
final Box b = untilBox(ref, ATOM_STSD);
|
||||||
|
|
||||||
if (b == null) {
|
if (b == null) {
|
||||||
return new byte[0]; // this never should happens (missing codec startup data)
|
return new byte[0]; // this never should happens (missing codec startup data)
|
||||||
@ -796,8 +796,8 @@ public class Mp4DashReader {
|
|||||||
int entriesRowSize;
|
int entriesRowSize;
|
||||||
|
|
||||||
public TrunEntry getEntry(final int i) {
|
public TrunEntry getEntry(final int i) {
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(bEntries, i * entriesRowSize, entriesRowSize);
|
final ByteBuffer buffer = ByteBuffer.wrap(bEntries, i * entriesRowSize, entriesRowSize);
|
||||||
TrunEntry entry = new TrunEntry();
|
final TrunEntry entry = new TrunEntry();
|
||||||
|
|
||||||
if (hasFlag(bFlags, 0x0100)) {
|
if (hasFlag(bFlags, 0x0100)) {
|
||||||
entry.sampleDuration = buffer.getInt();
|
entry.sampleDuration = buffer.getInt();
|
||||||
@ -819,7 +819,7 @@ public class Mp4DashReader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public TrunEntry getAbsoluteEntry(final int i, final Tfhd header) {
|
public TrunEntry getAbsoluteEntry(final int i, final Tfhd header) {
|
||||||
TrunEntry entry = getEntry(i);
|
final TrunEntry entry = getEntry(i);
|
||||||
|
|
||||||
if (!hasFlag(bFlags, 0x0100) && hasFlag(header.bFlags, 0x20)) {
|
if (!hasFlag(bFlags, 0x0100) && hasFlag(header.bFlags, 0x20)) {
|
||||||
entry.sampleFlags = header.defaultSampleFlags;
|
entry.sampleFlags = header.defaultSampleFlags;
|
||||||
@ -928,7 +928,7 @@ public class Mp4DashReader {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
Mp4DashSample sample = new Mp4DashSample();
|
final Mp4DashSample sample = new Mp4DashSample();
|
||||||
sample.info = moof.traf.trun.getAbsoluteEntry(i++, moof.traf.tfhd);
|
sample.info = moof.traf.trun.getAbsoluteEntry(i++, moof.traf.tfhd);
|
||||||
sample.data = new byte[sample.info.sampleSize];
|
sample.data = new byte[sample.info.sampleSize];
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ public class Mp4FromDashWriter {
|
|||||||
private final ArrayList<Integer> compatibleBrands = new ArrayList<>(5);
|
private final ArrayList<Integer> compatibleBrands = new ArrayList<>(5);
|
||||||
|
|
||||||
public Mp4FromDashWriter(final SharpStream... sources) throws IOException {
|
public Mp4FromDashWriter(final SharpStream... sources) throws IOException {
|
||||||
for (SharpStream src : sources) {
|
for (final SharpStream src : sources) {
|
||||||
if (!src.canRewind() && !src.canRead()) {
|
if (!src.canRewind() && !src.canRead()) {
|
||||||
throw new IOException("All sources must be readable and allow rewind");
|
throw new IOException("All sources must be readable and allow rewind");
|
||||||
}
|
}
|
||||||
@ -128,7 +128,7 @@ public class Mp4FromDashWriter {
|
|||||||
done = true;
|
done = true;
|
||||||
parsed = true;
|
parsed = true;
|
||||||
|
|
||||||
for (SharpStream src : sourceTracks) {
|
for (final SharpStream src : sourceTracks) {
|
||||||
src.close();
|
src.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -157,17 +157,17 @@ public class Mp4FromDashWriter {
|
|||||||
outStream = output;
|
outStream = output;
|
||||||
long read = 8; // mdat box header size
|
long read = 8; // mdat box header size
|
||||||
long totalSampleSize = 0;
|
long totalSampleSize = 0;
|
||||||
int[] sampleExtra = new int[readers.length];
|
final int[] sampleExtra = new int[readers.length];
|
||||||
int[] defaultMediaTime = new int[readers.length];
|
final int[] defaultMediaTime = new int[readers.length];
|
||||||
int[] defaultSampleDuration = new int[readers.length];
|
final int[] defaultSampleDuration = new int[readers.length];
|
||||||
int[] sampleCount = new int[readers.length];
|
final int[] sampleCount = new int[readers.length];
|
||||||
|
|
||||||
TablesInfo[] tablesInfo = new TablesInfo[tracks.length];
|
final TablesInfo[] tablesInfo = new TablesInfo[tracks.length];
|
||||||
for (int i = 0; i < tablesInfo.length; i++) {
|
for (int i = 0; i < tablesInfo.length; i++) {
|
||||||
tablesInfo[i] = new TablesInfo();
|
tablesInfo[i] = new TablesInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
int singleSampleBuffer;
|
final int singleSampleBuffer;
|
||||||
if (tracks.length == 1 && tracks[0].kind == TrackKind.Audio) {
|
if (tracks.length == 1 && tracks[0].kind == TrackKind.Audio) {
|
||||||
// near 1 second of audio data per chunk, avoid split the audio stream in large chunks
|
// near 1 second of audio data per chunk, avoid split the audio stream in large chunks
|
||||||
singleSampleBuffer = tracks[0].trak.mdia.mdhdTimeScale / 1000;
|
singleSampleBuffer = tracks[0].trak.mdia.mdhdTimeScale / 1000;
|
||||||
@ -250,10 +250,10 @@ public class Mp4FromDashWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
boolean is64 = read > THRESHOLD_FOR_CO64;
|
final boolean is64 = read > THRESHOLD_FOR_CO64;
|
||||||
|
|
||||||
// calculate the moov size
|
// calculate the moov size
|
||||||
int auxSize = makeMoov(defaultMediaTime, tablesInfo, is64);
|
final int auxSize = makeMoov(defaultMediaTime, tablesInfo, is64);
|
||||||
|
|
||||||
if (auxSize < THRESHOLD_MOOV_LENGTH) {
|
if (auxSize < THRESHOLD_MOOV_LENGTH) {
|
||||||
auxBuffer = ByteBuffer.allocate(auxSize); // cache moov in the memory
|
auxBuffer = ByteBuffer.allocate(auxSize); // cache moov in the memory
|
||||||
@ -267,9 +267,9 @@ public class Mp4FromDashWriter {
|
|||||||
// reserve moov space in the output stream
|
// reserve moov space in the output stream
|
||||||
if (auxSize > 0) {
|
if (auxSize > 0) {
|
||||||
int length = auxSize;
|
int length = auxSize;
|
||||||
byte[] buffer = new byte[64 * 1024]; // 64 KiB
|
final byte[] buffer = new byte[64 * 1024]; // 64 KiB
|
||||||
while (length > 0) {
|
while (length > 0) {
|
||||||
int count = Math.min(length, buffer.length);
|
final int count = Math.min(length, buffer.length);
|
||||||
outWrite(buffer, count);
|
outWrite(buffer, count);
|
||||||
length -= count;
|
length -= count;
|
||||||
}
|
}
|
||||||
@ -305,9 +305,10 @@ public class Mp4FromDashWriter {
|
|||||||
|
|
||||||
outWrite(makeMdat(totalSampleSize, is64));
|
outWrite(makeMdat(totalSampleSize, is64));
|
||||||
|
|
||||||
int[] sampleIndex = new int[readers.length];
|
final int[] sampleIndex = new int[readers.length];
|
||||||
int[] sizes = new int[singleSampleBuffer > 0 ? singleSampleBuffer : SAMPLES_PER_CHUNK];
|
final int[] sizes
|
||||||
int[] sync = new int[singleSampleBuffer > 0 ? singleSampleBuffer : SAMPLES_PER_CHUNK];
|
= new int[singleSampleBuffer > 0 ? singleSampleBuffer : SAMPLES_PER_CHUNK];
|
||||||
|
final int[] sync = new int[singleSampleBuffer > 0 ? singleSampleBuffer : SAMPLES_PER_CHUNK];
|
||||||
|
|
||||||
int written = readers.length;
|
int written = readers.length;
|
||||||
while (written > 0) {
|
while (written > 0) {
|
||||||
@ -318,9 +319,9 @@ public class Mp4FromDashWriter {
|
|||||||
continue; // track is done
|
continue; // track is done
|
||||||
}
|
}
|
||||||
|
|
||||||
long chunkOffset = writeOffset;
|
final long chunkOffset = writeOffset;
|
||||||
int syncCount = 0;
|
int syncCount = 0;
|
||||||
int limit;
|
final int limit;
|
||||||
if (singleSampleBuffer > 0) {
|
if (singleSampleBuffer > 0) {
|
||||||
limit = singleSampleBuffer;
|
limit = singleSampleBuffer;
|
||||||
} else {
|
} else {
|
||||||
@ -329,7 +330,7 @@ public class Mp4FromDashWriter {
|
|||||||
|
|
||||||
int j = 0;
|
int j = 0;
|
||||||
for (; j < limit; j++) {
|
for (; j < limit; j++) {
|
||||||
Mp4DashSample sample = getNextSample(i);
|
final Mp4DashSample sample = getNextSample(i);
|
||||||
|
|
||||||
if (sample == null) {
|
if (sample == null) {
|
||||||
if (tablesInfo[i].ctts > 0 && sampleExtra[i] >= 0) {
|
if (tablesInfo[i].ctts > 0 && sampleExtra[i] >= 0) {
|
||||||
@ -409,7 +410,7 @@ public class Mp4FromDashWriter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Mp4DashSample sample = readersChunks[track].getNextSample();
|
final Mp4DashSample sample = readersChunks[track].getNextSample();
|
||||||
if (sample == null) {
|
if (sample == null) {
|
||||||
readersChunks[track] = null;
|
readersChunks[track] = null;
|
||||||
return getNextSample(track);
|
return getNextSample(track);
|
||||||
@ -434,8 +435,8 @@ public class Mp4FromDashWriter {
|
|||||||
|
|
||||||
auxSeek(offset);
|
auxSeek(offset);
|
||||||
|
|
||||||
int size = count * 4;
|
final int size = count * 4;
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
final ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||||
|
|
||||||
for (int i = 0; i < count; i++) {
|
for (int i = 0; i < count; i++) {
|
||||||
buffer.putInt(values[i]);
|
buffer.putInt(values[i]);
|
||||||
@ -466,10 +467,10 @@ public class Mp4FromDashWriter {
|
|||||||
private void initChunkTables(final TablesInfo tables, final int firstCount,
|
private void initChunkTables(final TablesInfo tables, final int firstCount,
|
||||||
final int successiveCount) {
|
final int successiveCount) {
|
||||||
// tables.stsz holds amount of samples of the track (total)
|
// tables.stsz holds amount of samples of the track (total)
|
||||||
int totalSamples = (tables.stsz - firstCount);
|
final int totalSamples = (tables.stsz - firstCount);
|
||||||
float chunkAmount = totalSamples / (float) successiveCount;
|
final float chunkAmount = totalSamples / (float) successiveCount;
|
||||||
int remainChunkOffset = (int) Math.ceil(chunkAmount);
|
final int remainChunkOffset = (int) Math.ceil(chunkAmount);
|
||||||
boolean remain = remainChunkOffset != (int) chunkAmount;
|
final boolean remain = remainChunkOffset != (int) chunkAmount;
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
tables.stsc = 1;
|
tables.stsc = 1;
|
||||||
@ -529,7 +530,7 @@ public class Mp4FromDashWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int lengthFor(final int offset) throws IOException {
|
private int lengthFor(final int offset) throws IOException {
|
||||||
int size = auxOffset() - offset;
|
final int size = auxOffset() - offset;
|
||||||
|
|
||||||
if (moovSimulation) {
|
if (moovSimulation) {
|
||||||
return size;
|
return size;
|
||||||
@ -545,7 +546,7 @@ public class Mp4FromDashWriter {
|
|||||||
private int make(final int type, final int extra, final int columns, final int rows)
|
private int make(final int type, final int extra, final int columns, final int rows)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final byte base = 16;
|
final byte base = 16;
|
||||||
int size = columns * rows * 4;
|
final int size = columns * rows * 4;
|
||||||
int total = size + base;
|
int total = size + base;
|
||||||
int offset = auxOffset();
|
int offset = auxOffset();
|
||||||
|
|
||||||
@ -618,7 +619,7 @@ public class Mp4FromDashWriter {
|
|||||||
size += 4;
|
size += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(size);
|
final ByteBuffer buffer = ByteBuffer.allocate(size);
|
||||||
buffer.putInt(size);
|
buffer.putInt(size);
|
||||||
buffer.putInt(0x66747970); // "ftyp"
|
buffer.putInt(0x66747970); // "ftyp"
|
||||||
|
|
||||||
@ -631,7 +632,7 @@ public class Mp4FromDashWriter {
|
|||||||
buffer.putInt(0x6D703432); // "mp42" compatible brand
|
buffer.putInt(0x6D703432); // "mp42" compatible brand
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Integer brand : compatibleBrands) {
|
for (final Integer brand : compatibleBrands) {
|
||||||
buffer.putInt(brand); // compatible brand
|
buffer.putInt(brand); // compatible brand
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -648,7 +649,7 @@ public class Mp4FromDashWriter {
|
|||||||
size += 8;
|
size += 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(is64 ? 16 : 8)
|
final ByteBuffer buffer = ByteBuffer.allocate(is64 ? 16 : 8)
|
||||||
.putInt(is64 ? 0x01 : (int) size)
|
.putInt(is64 ? 0x01 : (int) size)
|
||||||
.putInt(0x6D646174); // mdat
|
.putInt(0x6D646174); // mdat
|
||||||
|
|
||||||
@ -689,14 +690,14 @@ public class Mp4FromDashWriter {
|
|||||||
|
|
||||||
private int makeMoov(final int[] defaultMediaTime, final TablesInfo[] tablesInfo,
|
private int makeMoov(final int[] defaultMediaTime, final TablesInfo[] tablesInfo,
|
||||||
final boolean is64) throws RuntimeException, IOException {
|
final boolean is64) throws RuntimeException, IOException {
|
||||||
int start = auxOffset();
|
final int start = auxOffset();
|
||||||
|
|
||||||
auxWrite(new byte[]{
|
auxWrite(new byte[]{
|
||||||
0x00, 0x00, 0x00, 0x00, 0x6D, 0x6F, 0x6F, 0x76
|
0x00, 0x00, 0x00, 0x00, 0x6D, 0x6F, 0x6F, 0x76
|
||||||
});
|
});
|
||||||
|
|
||||||
long longestTrack = 0;
|
long longestTrack = 0;
|
||||||
long[] durations = new long[tracks.length];
|
final long[] durations = new long[tracks.length];
|
||||||
|
|
||||||
for (int i = 0; i < durations.length; i++) {
|
for (int i = 0; i < durations.length; i++) {
|
||||||
durations[i] = (long) Math.ceil(
|
durations[i] = (long) Math.ceil(
|
||||||
@ -723,7 +724,7 @@ public class Mp4FromDashWriter {
|
|||||||
|
|
||||||
private void makeTrak(final int index, final long duration, final int defaultMediaTime,
|
private void makeTrak(final int index, final long duration, final int defaultMediaTime,
|
||||||
final TablesInfo tables, final boolean is64) throws IOException {
|
final TablesInfo tables, final boolean is64) throws IOException {
|
||||||
int start = auxOffset();
|
final int start = auxOffset();
|
||||||
|
|
||||||
auxWrite(new byte[]{
|
auxWrite(new byte[]{
|
||||||
// trak header
|
// trak header
|
||||||
@ -732,7 +733,7 @@ public class Mp4FromDashWriter {
|
|||||||
0x00, 0x00, 0x00, 0x68, 0x74, 0x6B, 0x68, 0x64, 0x01, 0x00, 0x00, 0x03
|
0x00, 0x00, 0x00, 0x68, 0x74, 0x6B, 0x68, 0x64, 0x01, 0x00, 0x00, 0x03
|
||||||
});
|
});
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.allocate(48);
|
final ByteBuffer buffer = ByteBuffer.allocate(48);
|
||||||
buffer.putLong(time);
|
buffer.putLong(time);
|
||||||
buffer.putLong(time);
|
buffer.putLong(time);
|
||||||
buffer.putInt(index + 1);
|
buffer.putInt(index + 1);
|
||||||
@ -757,8 +758,8 @@ public class Mp4FromDashWriter {
|
|||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 // elst header
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 // elst header
|
||||||
});
|
});
|
||||||
|
|
||||||
int bMediaRate;
|
final int bMediaRate;
|
||||||
int mediaTime;
|
final int mediaTime;
|
||||||
|
|
||||||
if (tracks[index].trak.edstElst == null) {
|
if (tracks[index].trak.edstElst == null) {
|
||||||
// is a audio track ¿is edst/elst optional for audio tracks?
|
// is a audio track ¿is edst/elst optional for audio tracks?
|
||||||
@ -784,17 +785,17 @@ public class Mp4FromDashWriter {
|
|||||||
|
|
||||||
private void makeMdia(final Mdia mdia, final TablesInfo tablesInfo, final boolean is64,
|
private void makeMdia(final Mdia mdia, final TablesInfo tablesInfo, final boolean is64,
|
||||||
final boolean isAudio) throws IOException {
|
final boolean isAudio) throws IOException {
|
||||||
int startMdia = auxOffset();
|
final int startMdia = auxOffset();
|
||||||
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x6D, 0x64, 0x69, 0x61}); // mdia
|
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x6D, 0x64, 0x69, 0x61}); // mdia
|
||||||
auxWrite(mdia.mdhd);
|
auxWrite(mdia.mdhd);
|
||||||
auxWrite(makeHdlr(mdia.hdlr));
|
auxWrite(makeHdlr(mdia.hdlr));
|
||||||
|
|
||||||
int startMinf = auxOffset();
|
final int startMinf = auxOffset();
|
||||||
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x6D, 0x69, 0x6E, 0x66}); // minf
|
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x6D, 0x69, 0x6E, 0x66}); // minf
|
||||||
auxWrite(mdia.minf.mhd);
|
auxWrite(mdia.minf.mhd);
|
||||||
auxWrite(mdia.minf.dinf);
|
auxWrite(mdia.minf.dinf);
|
||||||
|
|
||||||
int startStbl = auxOffset();
|
final int startStbl = auxOffset();
|
||||||
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x62, 0x6C}); // stbl
|
auxWrite(new byte[]{0x00, 0x00, 0x00, 0x00, 0x73, 0x74, 0x62, 0x6C}); // stbl
|
||||||
auxWrite(mdia.minf.stblStsd);
|
auxWrite(mdia.minf.stblStsd);
|
||||||
|
|
||||||
@ -838,7 +839,7 @@ public class Mp4FromDashWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private byte[] makeHdlr(final Hdlr hdlr) {
|
private byte[] makeHdlr(final Hdlr hdlr) {
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(new byte[]{
|
final ByteBuffer buffer = ByteBuffer.wrap(new byte[]{
|
||||||
0x00, 0x00, 0x00, 0x21, 0x68, 0x64, 0x6C, 0x72, // hdlr
|
0x00, 0x00, 0x00, 0x21, 0x68, 0x64, 0x6C, 0x72, // hdlr
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
@ -854,7 +855,7 @@ public class Mp4FromDashWriter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private int makeSbgp() throws IOException {
|
private int makeSbgp() throws IOException {
|
||||||
int offset = auxOffset();
|
final int offset = auxOffset();
|
||||||
|
|
||||||
auxWrite(new byte[] {
|
auxWrite(new byte[] {
|
||||||
0x00, 0x00, 0x00, 0x1C, // box size
|
0x00, 0x00, 0x00, 0x1C, // box size
|
||||||
@ -883,7 +884,7 @@ public class Mp4FromDashWriter {
|
|||||||
* most of m4a encoders and ffmpeg uses this box with dummy values (same values)
|
* most of m4a encoders and ffmpeg uses this box with dummy values (same values)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(new byte[] {
|
final ByteBuffer buffer = ByteBuffer.wrap(new byte[] {
|
||||||
0x00, 0x00, 0x00, 0x1A, // box size
|
0x00, 0x00, 0x00, 0x1A, // box size
|
||||||
0x73, 0x67, 0x70, 0x64, // "sgpd"
|
0x73, 0x67, 0x70, 0x64, // "sgpd"
|
||||||
0x01, 0x00, 0x00, 0x00, // box flags (unknown flag sets)
|
0x01, 0x00, 0x00, 0x00, // box flags (unknown flag sets)
|
||||||
|
@ -145,10 +145,10 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void build() throws IOException {
|
public void build() throws IOException {
|
||||||
float resolution;
|
final float resolution;
|
||||||
SimpleBlock bloq;
|
SimpleBlock bloq;
|
||||||
ByteBuffer header = ByteBuffer.allocate(27 + (255 * 255));
|
final ByteBuffer header = ByteBuffer.allocate(27 + (255 * 255));
|
||||||
ByteBuffer page = ByteBuffer.allocate(64 * 1024);
|
final ByteBuffer page = ByteBuffer.allocate(64 * 1024);
|
||||||
|
|
||||||
header.order(ByteOrder.LITTLE_ENDIAN);
|
header.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
|
|
||||||
@ -181,7 +181,7 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* step 3: create packet with metadata */
|
/* step 3: create packet with metadata */
|
||||||
byte[] buffer = makeMetadata();
|
final byte[] buffer = makeMetadata();
|
||||||
if (buffer != null) {
|
if (buffer != null) {
|
||||||
addPacketSegment(buffer.length);
|
addPacketSegment(buffer.length);
|
||||||
makePacketheader(0x00, header, buffer);
|
makePacketheader(0x00, header, buffer);
|
||||||
@ -194,7 +194,7 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
bloq = getNextBlock();
|
bloq = getNextBlock();
|
||||||
|
|
||||||
if (bloq != null && addPacketSegment(bloq)) {
|
if (bloq != null && addPacketSegment(bloq)) {
|
||||||
int pos = page.position();
|
final int pos = page.position();
|
||||||
//noinspection ResultOfMethodCallIgnored
|
//noinspection ResultOfMethodCallIgnored
|
||||||
bloq.data.read(page.array(), pos, bloq.dataSize);
|
bloq.data.read(page.array(), pos, bloq.dataSize);
|
||||||
page.position(pos + bloq.dataSize);
|
page.position(pos + bloq.dataSize);
|
||||||
@ -334,10 +334,10 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
|
|
||||||
private float getSampleFrequencyFromTrack(final byte[] bMetadata) {
|
private float getSampleFrequencyFromTrack(final byte[] bMetadata) {
|
||||||
// hardcoded way
|
// hardcoded way
|
||||||
ByteBuffer buffer = ByteBuffer.wrap(bMetadata);
|
final ByteBuffer buffer = ByteBuffer.wrap(bMetadata);
|
||||||
|
|
||||||
while (buffer.remaining() >= 6) {
|
while (buffer.remaining() >= 6) {
|
||||||
int id = buffer.getShort() & 0xFFFF;
|
final int id = buffer.getShort() & 0xFFFF;
|
||||||
if (id == 0x0000B584) {
|
if (id == 0x0000B584) {
|
||||||
return buffer.getFloat();
|
return buffer.getFloat();
|
||||||
}
|
}
|
||||||
@ -353,7 +353,7 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private boolean addPacketSegment(final SimpleBlock block) {
|
private boolean addPacketSegment(final SimpleBlock block) {
|
||||||
long timestamp = block.absoluteTimeCodeNs + webmTrack.codecDelay;
|
final long timestamp = block.absoluteTimeCodeNs + webmTrack.codecDelay;
|
||||||
|
|
||||||
if (timestamp >= segmentTableNextTimestamp) {
|
if (timestamp >= segmentTableNextTimestamp) {
|
||||||
return false;
|
return false;
|
||||||
@ -368,7 +368,7 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int available = (segmentTable.length - segmentTableSize) * 255;
|
int available = (segmentTable.length - segmentTableSize) * 255;
|
||||||
boolean extra = (size % 255) == 0;
|
final boolean extra = (size % 255) == 0;
|
||||||
|
|
||||||
if (extra) {
|
if (extra) {
|
||||||
// add a zero byte entry in the table
|
// add a zero byte entry in the table
|
||||||
@ -396,7 +396,7 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
for (int i = 0; i < 0x100; i++) {
|
for (int i = 0; i < 0x100; i++) {
|
||||||
int crc = i << 24;
|
int crc = i << 24;
|
||||||
for (int j = 0; j < 8; j++) {
|
for (int j = 0; j < 8; j++) {
|
||||||
long b = crc >>> 31;
|
final long b = crc >>> 31;
|
||||||
crc <<= 1;
|
crc <<= 1;
|
||||||
crc ^= (int) (0x100000000L - b) & 0x04c11db7;
|
crc ^= (int) (0x100000000L - b) & 0x04c11db7;
|
||||||
}
|
}
|
||||||
@ -407,7 +407,7 @@ public class OggFromWebMWriter implements Closeable {
|
|||||||
private int calcCrc32(final int initialCrc, final byte[] buffer, final int size) {
|
private int calcCrc32(final int initialCrc, final byte[] buffer, final int size) {
|
||||||
int crc = initialCrc;
|
int crc = initialCrc;
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i < size; i++) {
|
||||||
int reg = (crc >>> 24) & 0xff;
|
final int reg = (crc >>> 24) & 0xff;
|
||||||
crc = (crc << 8) ^ crc32Table[reg ^ (buffer[i] & 0xff)];
|
crc = (crc << 8) ^ crc32Table[reg ^ (buffer[i] & 0xff)];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,23 +65,23 @@ public class SrtFromTtmlWriter {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// parse XML
|
// parse XML
|
||||||
byte[] buffer = new byte[(int) ttml.available()];
|
final byte[] buffer = new byte[(int) ttml.available()];
|
||||||
ttml.read(buffer);
|
ttml.read(buffer);
|
||||||
Document doc = Jsoup.parse(new ByteArrayInputStream(buffer), "UTF-8", "",
|
final Document doc = Jsoup.parse(new ByteArrayInputStream(buffer), "UTF-8", "",
|
||||||
Parser.xmlParser());
|
Parser.xmlParser());
|
||||||
|
|
||||||
StringBuilder text = new StringBuilder(128);
|
final StringBuilder text = new StringBuilder(128);
|
||||||
Elements paragraphList = doc.select("body > div > p");
|
final Elements paragraphList = doc.select("body > div > p");
|
||||||
|
|
||||||
// check if has frames
|
// check if has frames
|
||||||
if (paragraphList.size() < 1) {
|
if (paragraphList.size() < 1) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (Element paragraph : paragraphList) {
|
for (final Element paragraph : paragraphList) {
|
||||||
text.setLength(0);
|
text.setLength(0);
|
||||||
|
|
||||||
for (Node children : paragraph.childNodes()) {
|
for (final Node children : paragraph.childNodes()) {
|
||||||
if (children instanceof TextNode) {
|
if (children instanceof TextNode) {
|
||||||
text.append(((TextNode) children).text());
|
text.append(((TextNode) children).text());
|
||||||
} else if (children instanceof Element
|
} else if (children instanceof Element
|
||||||
@ -94,8 +94,8 @@ public class SrtFromTtmlWriter {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
String begin = getTimestamp(paragraph, "begin");
|
final String begin = getTimestamp(paragraph, "begin");
|
||||||
String end = getTimestamp(paragraph, "end");
|
final String end = getTimestamp(paragraph, "end");
|
||||||
|
|
||||||
writeFrame(begin, end, text);
|
writeFrame(begin, end, text);
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user