From 35073c780d21cba874893b5f75d9e9d99236a1e8 Mon Sep 17 00:00:00 2001 From: Stypox Date: Tue, 2 May 2023 12:30:27 +0200 Subject: [PATCH] Implement better image selection strategy --- app/src/main/java/org/schabi/newpipe/App.java | 3 +- .../database/playlist/PlaylistStreamEntry.kt | 4 +- .../playlist/model/PlaylistRemoteEntity.java | 6 +- .../database/stream/StreamStatisticsEntry.kt | 4 +- .../database/stream/model/StreamEntity.kt | 10 +- .../subscription/SubscriptionEntity.java | 6 +- .../fragments/detail/DescriptionFragment.java | 4 +- .../list/channel/ChannelAboutFragment.java | 6 +- .../list/channel/ChannelFragment.java | 7 +- .../holder/CommentsMiniInfoItemHolder.java | 3 +- .../subscription/SubscriptionFragment.kt | 4 +- .../local/subscription/SubscriptionManager.kt | 6 +- .../player/mediaitem/ExceptionTag.java | 4 +- .../player/mediaitem/StreamInfoTag.java | 4 +- .../mediasession/PlayQueueNavigator.java | 4 +- .../settings/ContentSettingsFragment.java | 3 +- .../external_communication/ShareUtils.java | 7 +- .../newpipe/util/image/ImageStrategy.java | 115 ++++++++++++++++++ .../newpipe/util/image/PicassoHelper.java | 50 +------- 19 files changed, 161 insertions(+), 89 deletions(-) create mode 100644 app/src/main/java/org/schabi/newpipe/util/image/ImageStrategy.java diff --git a/app/src/main/java/org/schabi/newpipe/App.java b/app/src/main/java/org/schabi/newpipe/App.java index b394c7039..ee352ae4a 100644 --- a/app/src/main/java/org/schabi/newpipe/App.java +++ b/app/src/main/java/org/schabi/newpipe/App.java @@ -20,6 +20,7 @@ import org.schabi.newpipe.extractor.downloader.Downloader; import org.schabi.newpipe.ktx.ExceptionUtils; import org.schabi.newpipe.settings.NewPipeSettings; import org.schabi.newpipe.util.Localization; +import org.schabi.newpipe.util.image.ImageStrategy; import org.schabi.newpipe.util.image.PicassoHelper; import org.schabi.newpipe.util.ServiceHelper; import org.schabi.newpipe.util.StateSaver; @@ -100,7 +101,7 @@ public class App extends Application { // Initialize image loader final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); PicassoHelper.init(this); - PicassoHelper.setPreferredImageQuality(PreferredImageQuality.fromPreferenceKey(this, + ImageStrategy.setPreferredImageQuality(PreferredImageQuality.fromPreferenceKey(this, prefs.getString(getString(R.string.image_quality_key), getString(R.string.image_quality_default)))); PicassoHelper.setIndicatorsEnabled(MainActivity.DEBUG diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt index e7db1d603..47dc1d06a 100644 --- a/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt +++ b/app/src/main/java/org/schabi/newpipe/database/playlist/PlaylistStreamEntry.kt @@ -7,7 +7,7 @@ import org.schabi.newpipe.database.playlist.model.PlaylistStreamEntity import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamStateEntity import org.schabi.newpipe.extractor.stream.StreamInfoItem -import org.schabi.newpipe.util.image.PicassoHelper +import org.schabi.newpipe.util.image.ImageStrategy data class PlaylistStreamEntry( @Embedded @@ -29,7 +29,7 @@ data class PlaylistStreamEntry( item.duration = streamEntity.duration item.uploaderName = streamEntity.uploader item.uploaderUrl = streamEntity.uploaderUrl - item.thumbnails = PicassoHelper.urlToImageList(streamEntity.thumbnailUrl) + item.thumbnails = ImageStrategy.urlToImageList(streamEntity.thumbnailUrl) return item } diff --git a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.java b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.java index 569f6721c..5e8977821 100644 --- a/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.java +++ b/app/src/main/java/org/schabi/newpipe/database/playlist/model/PlaylistRemoteEntity.java @@ -11,7 +11,7 @@ import androidx.room.PrimaryKey; import org.schabi.newpipe.database.playlist.PlaylistLocalItem; import org.schabi.newpipe.extractor.playlist.PlaylistInfo; import org.schabi.newpipe.util.Constants; -import org.schabi.newpipe.util.image.PicassoHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM; import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME; @@ -70,7 +70,7 @@ public class PlaylistRemoteEntity implements PlaylistLocalItem { @Ignore public PlaylistRemoteEntity(final PlaylistInfo info) { this(info.getServiceId(), info.getName(), info.getUrl(), - PicassoHelper.choosePreferredImage(info.getThumbnails()), + ImageStrategy.choosePreferredImage(info.getThumbnails()), info.getUploaderName(), info.getStreamCount()); } @@ -85,7 +85,7 @@ public class PlaylistRemoteEntity implements PlaylistLocalItem { && TextUtils.equals(getName(), info.getName()) && TextUtils.equals(getUrl(), info.getUrl()) && TextUtils.equals(getThumbnailUrl(), - PicassoHelper.choosePreferredImage(info.getThumbnails())) + ImageStrategy.choosePreferredImage(info.getThumbnails())) && TextUtils.equals(getUploader(), info.getUploaderName()); } diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt b/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt index 6d005351d..81e17b720 100644 --- a/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt +++ b/app/src/main/java/org/schabi/newpipe/database/stream/StreamStatisticsEntry.kt @@ -7,7 +7,7 @@ import org.schabi.newpipe.database.history.model.StreamHistoryEntity import org.schabi.newpipe.database.stream.model.StreamEntity import org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS import org.schabi.newpipe.extractor.stream.StreamInfoItem -import org.schabi.newpipe.util.image.PicassoHelper +import org.schabi.newpipe.util.image.ImageStrategy import java.time.OffsetDateTime class StreamStatisticsEntry( @@ -31,7 +31,7 @@ class StreamStatisticsEntry( item.duration = streamEntity.duration item.uploaderName = streamEntity.uploader item.uploaderUrl = streamEntity.uploaderUrl - item.thumbnails = PicassoHelper.urlToImageList(streamEntity.thumbnailUrl) + item.thumbnails = ImageStrategy.urlToImageList(streamEntity.thumbnailUrl) return item } diff --git a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt index bb2c0e0d7..4eecc9373 100644 --- a/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt +++ b/app/src/main/java/org/schabi/newpipe/database/stream/model/StreamEntity.kt @@ -13,7 +13,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.extractor.stream.StreamType import org.schabi.newpipe.player.playqueue.PlayQueueItem -import org.schabi.newpipe.util.image.PicassoHelper +import org.schabi.newpipe.util.image.ImageStrategy import java.io.Serializable import java.time.OffsetDateTime @@ -68,7 +68,7 @@ data class StreamEntity( constructor(item: StreamInfoItem) : this( serviceId = item.serviceId, url = item.url, title = item.name, streamType = item.streamType, duration = item.duration, uploader = item.uploaderName, - uploaderUrl = item.uploaderUrl, thumbnailUrl = PicassoHelper.choosePreferredImage(item.thumbnails), viewCount = item.viewCount, + uploaderUrl = item.uploaderUrl, thumbnailUrl = ImageStrategy.choosePreferredImage(item.thumbnails), viewCount = item.viewCount, textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(), isUploadDateApproximation = item.uploadDate?.isApproximation ) @@ -77,7 +77,7 @@ data class StreamEntity( constructor(info: StreamInfo) : this( serviceId = info.serviceId, url = info.url, title = info.name, streamType = info.streamType, duration = info.duration, uploader = info.uploaderName, - uploaderUrl = info.uploaderUrl, thumbnailUrl = PicassoHelper.choosePreferredImage(info.thumbnails), viewCount = info.viewCount, + uploaderUrl = info.uploaderUrl, thumbnailUrl = ImageStrategy.choosePreferredImage(info.thumbnails), viewCount = info.viewCount, textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(), isUploadDateApproximation = info.uploadDate?.isApproximation ) @@ -87,7 +87,7 @@ data class StreamEntity( serviceId = item.serviceId, url = item.url, title = item.title, streamType = item.streamType, duration = item.duration, uploader = item.uploader, uploaderUrl = item.uploaderUrl, - thumbnailUrl = PicassoHelper.choosePreferredImage(item.thumbnails) + thumbnailUrl = ImageStrategy.choosePreferredImage(item.thumbnails) ) fun toStreamInfoItem(): StreamInfoItem { @@ -95,7 +95,7 @@ data class StreamEntity( item.duration = duration item.uploaderName = uploader item.uploaderUrl = uploaderUrl - item.thumbnails = PicassoHelper.urlToImageList(thumbnailUrl) + item.thumbnails = ImageStrategy.urlToImageList(thumbnailUrl) if (viewCount != null) item.viewCount = viewCount as Long item.textualUploadDate = textualUploadDate diff --git a/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.java b/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.java index 1f1722814..3fb474423 100644 --- a/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.java +++ b/app/src/main/java/org/schabi/newpipe/database/subscription/SubscriptionEntity.java @@ -10,7 +10,7 @@ import androidx.room.PrimaryKey; import org.schabi.newpipe.extractor.channel.ChannelInfo; import org.schabi.newpipe.extractor.channel.ChannelInfoItem; import org.schabi.newpipe.util.Constants; -import org.schabi.newpipe.util.image.PicassoHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID; import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE; @@ -58,7 +58,7 @@ public class SubscriptionEntity { final SubscriptionEntity result = new SubscriptionEntity(); result.setServiceId(info.getServiceId()); result.setUrl(info.getUrl()); - result.setData(info.getName(), PicassoHelper.choosePreferredImage(info.getAvatars()), + result.setData(info.getName(), ImageStrategy.choosePreferredImage(info.getAvatars()), info.getDescription(), info.getSubscriberCount()); return result; } @@ -139,7 +139,7 @@ public class SubscriptionEntity { @Ignore public ChannelInfoItem toChannelInfoItem() { final ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName()); - item.setThumbnails(PicassoHelper.urlToImageList(getAvatarUrl())); + item.setThumbnails(ImageStrategy.urlToImageList(getAvatarUrl())); item.setSubscriberCount(getSubscriberCount()); item.setDescription(getDescription()); return item; diff --git a/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java index ff1a01466..60a2a2ed3 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/detail/DescriptionFragment.java @@ -17,7 +17,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.util.Localization; import java.util.List; -import org.schabi.newpipe.util.image.PicassoHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import icepick.State; @@ -114,7 +114,7 @@ public class DescriptionFragment extends BaseDescriptionFragment { addMetadataItem(inflater, layout, true, R.string.metadata_host, streamInfo.getHost()); addMetadataItem(inflater, layout, true, R.string.metadata_thumbnail_url, - PicassoHelper.choosePreferredImage(streamInfo.getThumbnails())); + ImageStrategy.choosePreferredImage(streamInfo.getThumbnails())); } private void addPrivacyMetadataItem(final LayoutInflater inflater, final LinearLayout layout) { diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelAboutFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelAboutFragment.java index 5ea25bf15..9a035d0ab 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelAboutFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelAboutFragment.java @@ -17,7 +17,7 @@ import org.schabi.newpipe.extractor.stream.Description; import org.schabi.newpipe.fragments.detail.BaseDescriptionFragment; import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.Localization; -import org.schabi.newpipe.util.image.PicassoHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import java.util.List; @@ -101,8 +101,8 @@ public class ChannelAboutFragment extends BaseDescriptionFragment { } addMetadataItem(inflater, layout, true, R.string.metadata_avatar_url, - PicassoHelper.choosePreferredImage(channelInfo.getAvatars())); + ImageStrategy.choosePreferredImage(channelInfo.getAvatars())); addMetadataItem(inflater, layout, true, R.string.metadata_banner_url, - PicassoHelper.choosePreferredImage(channelInfo.getBanners())); + ImageStrategy.choosePreferredImage(channelInfo.getBanners())); } } diff --git a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java index 7436f50fd..3ece760ca 100644 --- a/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java +++ b/app/src/main/java/org/schabi/newpipe/fragments/list/channel/ChannelFragment.java @@ -49,6 +49,7 @@ import org.schabi.newpipe.util.ExtractorHelper; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; import org.schabi.newpipe.util.StateSaver; +import org.schabi.newpipe.util.image.ImageStrategy; import org.schabi.newpipe.util.image.PicassoHelper; import org.schabi.newpipe.util.ThemeHelper; import org.schabi.newpipe.util.external_communication.ShareUtils; @@ -147,7 +148,7 @@ public class ChannelFragment extends BaseStateFragment setTitle(name); binding.channelTitleView.setText(name); - if (!PicassoHelper.shouldLoadImages()) { + if (!ImageStrategy.shouldLoadImages()) { // do not waste space for the banner if it is not going to be loaded binding.channelBannerImage.setImageDrawable(null); } @@ -354,7 +355,7 @@ public class ChannelFragment extends BaseStateFragment channel.setServiceId(info.getServiceId()); channel.setUrl(info.getUrl()); channel.setData(info.getName(), - PicassoHelper.choosePreferredImage(info.getAvatars()), + ImageStrategy.choosePreferredImage(info.getAvatars()), info.getDescription(), info.getSubscriberCount()); channelSubscription = null; @@ -578,7 +579,7 @@ public class ChannelFragment extends BaseStateFragment currentInfo = result; setInitialData(result.getServiceId(), result.getOriginalUrl(), result.getName()); - if (PicassoHelper.shouldLoadImages() && !result.getBanners().isEmpty()) { + if (ImageStrategy.shouldLoadImages() && !result.getBanners().isEmpty()) { PicassoHelper.loadBanner(result.getBanners()).tag(PICASSO_CHANNEL_TAG) .into(binding.channelBannerImage); } else { diff --git a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java index 69e1bf5f6..d6a08e6cb 100644 --- a/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java +++ b/app/src/main/java/org/schabi/newpipe/info_list/holder/CommentsMiniInfoItemHolder.java @@ -31,6 +31,7 @@ import org.schabi.newpipe.local.history.HistoryRecordManager; import org.schabi.newpipe.util.DeviceUtils; import org.schabi.newpipe.util.Localization; import org.schabi.newpipe.util.NavigationHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import org.schabi.newpipe.util.image.PicassoHelper; import org.schabi.newpipe.util.external_communication.ShareUtils; import org.schabi.newpipe.util.text.CommentTextOnTouchListener; @@ -98,7 +99,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder { final CommentsInfoItem item = (CommentsInfoItem) infoItem; PicassoHelper.loadAvatar(item.getUploaderAvatars()).into(itemThumbnailView); - if (PicassoHelper.shouldLoadImages()) { + if (ImageStrategy.shouldLoadImages()) { itemThumbnailView.setVisibility(View.VISIBLE); itemRoot.setPadding(commentVerticalPadding, commentVerticalPadding, commentVerticalPadding, commentVerticalPadding); diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt index f84d9865f..ac82d5c91 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionFragment.kt @@ -61,7 +61,7 @@ import org.schabi.newpipe.util.OnClickGesture import org.schabi.newpipe.util.ServiceHelper import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountChannels import org.schabi.newpipe.util.external_communication.ShareUtils -import org.schabi.newpipe.util.image.PicassoHelper +import org.schabi.newpipe.util.image.ImageStrategy import java.text.SimpleDateFormat import java.util.Date import java.util.Locale @@ -343,7 +343,7 @@ class SubscriptionFragment : BaseStateFragment() { when (i) { 0 -> ShareUtils.shareText( requireContext(), selectedItem.name, selectedItem.url, - PicassoHelper.choosePreferredImage(selectedItem.thumbnails) + ImageStrategy.choosePreferredImage(selectedItem.thumbnails) ) 1 -> ShareUtils.openUrlInBrowser(requireContext(), selectedItem.url) 2 -> deleteChannel(selectedItem) diff --git a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt index 70bac6168..cfd5196be 100644 --- a/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt +++ b/app/src/main/java/org/schabi/newpipe/local/subscription/SubscriptionManager.kt @@ -19,7 +19,7 @@ import org.schabi.newpipe.extractor.feed.FeedInfo import org.schabi.newpipe.extractor.stream.StreamInfoItem import org.schabi.newpipe.local.feed.FeedDatabaseManager import org.schabi.newpipe.util.ExtractorHelper -import org.schabi.newpipe.util.image.PicassoHelper +import org.schabi.newpipe.util.image.ImageStrategy class SubscriptionManager(context: Context) { private val database = NewPipeDatabase.getInstance(context) @@ -74,7 +74,7 @@ class SubscriptionManager(context: Context) { Completable.fromRunnable { it.setData( info.name, - PicassoHelper.choosePreferredImage(info.avatars), + ImageStrategy.choosePreferredImage(info.avatars), info.description, info.subscriberCount ) @@ -105,7 +105,7 @@ class SubscriptionManager(context: Context) { } else if (info is ChannelInfo) { subscriptionEntity.setData( info.name, - PicassoHelper.choosePreferredImage(info.avatars), + ImageStrategy.choosePreferredImage(info.avatars), info.description, info.subscriberCount ) diff --git a/app/src/main/java/org/schabi/newpipe/player/mediaitem/ExceptionTag.java b/app/src/main/java/org/schabi/newpipe/player/mediaitem/ExceptionTag.java index 9ec6513dc..95a4f74af 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediaitem/ExceptionTag.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediaitem/ExceptionTag.java @@ -3,7 +3,7 @@ package org.schabi.newpipe.player.mediaitem; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.player.playqueue.PlayQueueItem; -import org.schabi.newpipe.util.image.PicassoHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import java.util.List; import java.util.Optional; @@ -75,7 +75,7 @@ public final class ExceptionTag implements MediaItemTag { @Override public String getThumbnailUrl() { - return PicassoHelper.choosePreferredImage(item.getThumbnails()); + return ImageStrategy.choosePreferredImage(item.getThumbnails()); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/player/mediaitem/StreamInfoTag.java b/app/src/main/java/org/schabi/newpipe/player/mediaitem/StreamInfoTag.java index a96f49f2f..e24a93615 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediaitem/StreamInfoTag.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediaitem/StreamInfoTag.java @@ -6,7 +6,7 @@ import org.schabi.newpipe.extractor.stream.AudioStream; import org.schabi.newpipe.extractor.stream.StreamInfo; import org.schabi.newpipe.extractor.stream.StreamType; import org.schabi.newpipe.extractor.stream.VideoStream; -import org.schabi.newpipe.util.image.PicassoHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import java.util.Collections; import java.util.List; @@ -96,7 +96,7 @@ public final class StreamInfoTag implements MediaItemTag { @Override public String getThumbnailUrl() { - return PicassoHelper.choosePreferredImage(streamInfo.getThumbnails()); + return ImageStrategy.choosePreferredImage(streamInfo.getThumbnails()); } @Override diff --git a/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java b/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java index 3e0736f82..f925bff16 100644 --- a/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java +++ b/app/src/main/java/org/schabi/newpipe/player/mediasession/PlayQueueNavigator.java @@ -20,7 +20,7 @@ import com.google.android.exoplayer2.util.Util; import org.schabi.newpipe.player.Player; import org.schabi.newpipe.player.playqueue.PlayQueue; import org.schabi.newpipe.player.playqueue.PlayQueueItem; -import org.schabi.newpipe.util.image.PicassoHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import java.util.ArrayList; import java.util.Collections; @@ -139,7 +139,7 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator descBuilder.setExtras(additionalMetadata); final Uri thumbnailUri = Uri.parse( - PicassoHelper.choosePreferredImage(item.getThumbnails())); + ImageStrategy.choosePreferredImage(item.getThumbnails())); if (thumbnailUri != null) { descBuilder.setIconUri(thumbnailUri); } diff --git a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java index 2297e3e93..c7d107acb 100644 --- a/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java +++ b/app/src/main/java/org/schabi/newpipe/settings/ContentSettingsFragment.java @@ -31,6 +31,7 @@ import org.schabi.newpipe.extractor.localization.Localization; import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard; import org.schabi.newpipe.streams.io.StoredFileHelper; import org.schabi.newpipe.util.NavigationHelper; +import org.schabi.newpipe.util.image.ImageStrategy; import org.schabi.newpipe.util.image.PicassoHelper; import org.schabi.newpipe.util.ZipHelper; import org.schabi.newpipe.util.image.PreferredImageQuality; @@ -109,7 +110,7 @@ public class ContentSettingsFragment extends BasePreferenceFragment { final Preference imageQualityPreference = requirePreference(R.string.image_quality_key); imageQualityPreference.setOnPreferenceChangeListener( (preference, newValue) -> { - PicassoHelper.setPreferredImageQuality(PreferredImageQuality + ImageStrategy.setPreferredImageQuality(PreferredImageQuality .fromPreferenceKey(requireContext(), (String) newValue)); try { PicassoHelper.clearCache(preference.getContext()); diff --git a/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java b/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java index 8150d4030..fc057de41 100644 --- a/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java +++ b/app/src/main/java/org/schabi/newpipe/util/external_communication/ShareUtils.java @@ -24,6 +24,7 @@ import androidx.core.content.FileProvider; import org.schabi.newpipe.BuildConfig; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.Image; +import org.schabi.newpipe.util.image.ImageStrategy; import org.schabi.newpipe.util.image.PicassoHelper; import java.io.File; @@ -251,7 +252,7 @@ public final class ShareUtils { // If loading of images has been disabled, don't try to generate a content preview if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !TextUtils.isEmpty(imagePreviewUrl) - && PicassoHelper.shouldLoadImages()) { + && ImageStrategy.shouldLoadImages()) { final ClipData clipData = generateClipDataForImagePreview(context, imagePreviewUrl); if (clipData != null) { @@ -276,14 +277,14 @@ public final class ShareUtils { * @param title the title of the content * @param content the content to share * @param images a set of possible {@link Image}s of the subject, among which to choose with - * {@link PicassoHelper#choosePreferredImage(List)} since that's likely to + * {@link ImageStrategy#choosePreferredImage(List)} since that's likely to * provide an image that is in Picasso's cache */ public static void shareText(@NonNull final Context context, @NonNull final String title, final String content, final List images) { - shareText(context, title, content, PicassoHelper.choosePreferredImage(images)); + shareText(context, title, content, ImageStrategy.choosePreferredImage(images)); } /** diff --git a/app/src/main/java/org/schabi/newpipe/util/image/ImageStrategy.java b/app/src/main/java/org/schabi/newpipe/util/image/ImageStrategy.java new file mode 100644 index 000000000..5de0b52f4 --- /dev/null +++ b/app/src/main/java/org/schabi/newpipe/util/image/ImageStrategy.java @@ -0,0 +1,115 @@ +package org.schabi.newpipe.util.image; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import org.schabi.newpipe.extractor.Image; + +import java.util.Comparator; +import java.util.List; + +public final class ImageStrategy { + + // the height thresholds also used by the extractor (TODO move them to the extractor) + private static final int LOW_MEDIUM = 175; + private static final int MEDIUM_HIGH = 720; + + private static PreferredImageQuality preferredImageQuality = PreferredImageQuality.MEDIUM; + + private ImageStrategy() { + } + + public static void setPreferredImageQuality(final PreferredImageQuality preferredImageQuality) { + ImageStrategy.preferredImageQuality = preferredImageQuality; + } + + public static boolean shouldLoadImages() { + return preferredImageQuality != PreferredImageQuality.NONE; + } + + + private static double estimatePixelCount(final Image image, + final double widthOverHeight, + final boolean unknownsLast) { + if (image.getHeight() == Image.HEIGHT_UNKNOWN) { + if (image.getWidth() == Image.WIDTH_UNKNOWN) { + switch (image.getEstimatedResolutionLevel()) { + case LOW: + return unknownsLast + ? (LOW_MEDIUM - 1) * (LOW_MEDIUM - 1) * widthOverHeight + : 0; + case MEDIUM: + return unknownsLast + ? (MEDIUM_HIGH - 1) * (MEDIUM_HIGH - 1) * widthOverHeight + : LOW_MEDIUM * LOW_MEDIUM * widthOverHeight; + case HIGH: + return unknownsLast + ? 1e20 // less than 1e21 to prefer over fully unknown image sizes + : MEDIUM_HIGH * MEDIUM_HIGH * widthOverHeight; + default: + case UNKNOWN: + // images whose size is completely unknown will be avoided when possible + return unknownsLast ? 1e21 : -1; + } + + } else { + return image.getWidth() * image.getWidth() / widthOverHeight; + } + + } else if (image.getWidth() == Image.WIDTH_UNKNOWN) { + return image.getHeight() * image.getHeight() * widthOverHeight; + + } else { + return image.getHeight() * image.getWidth(); + } + } + + @Nullable + public static String choosePreferredImage(@NonNull final List images) { + if (preferredImageQuality == PreferredImageQuality.NONE) { + return null; // do not load images + } + + final double widthOverHeight = images.stream() + .filter(image -> image.getHeight() != Image.HEIGHT_UNKNOWN + && image.getWidth() != Image.WIDTH_UNKNOWN) + .mapToDouble(image -> ((double) image.getWidth()) / image.getHeight()) + .findFirst() + .orElse(1.0); + + final Comparator comparator; + switch (preferredImageQuality) { + case LOW: + comparator = Comparator.comparingDouble( + image -> estimatePixelCount(image, widthOverHeight, true)); + break; + default: + case MEDIUM: + comparator = Comparator.comparingDouble(image -> { + final double pixelCount = estimatePixelCount(image, widthOverHeight, true); + final double mediumHeight = (LOW_MEDIUM + MEDIUM_HIGH) / 2.0; + return Math.abs(pixelCount - mediumHeight * mediumHeight * widthOverHeight); + }); + break; + case HIGH: + comparator = Comparator.comparingDouble( + image -> estimatePixelCount(image, widthOverHeight, false)) + .reversed(); + break; + } + + return images.stream() + .min(comparator) + .map(Image::getUrl) + .orElse(null); + } + + @NonNull + public static List urlToImageList(@Nullable final String url) { + if (url == null) { + return List.of(); + } else { + return List.of(new Image(url, -1, -1, Image.ResolutionLevel.UNKNOWN)); + } + } +} diff --git a/app/src/main/java/org/schabi/newpipe/util/image/PicassoHelper.java b/app/src/main/java/org/schabi/newpipe/util/image/PicassoHelper.java index 3177e83f4..ccf7c3737 100644 --- a/app/src/main/java/org/schabi/newpipe/util/image/PicassoHelper.java +++ b/app/src/main/java/org/schabi/newpipe/util/image/PicassoHelper.java @@ -2,13 +2,13 @@ package org.schabi.newpipe.util.image; import static org.schabi.newpipe.MainActivity.DEBUG; import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty; +import static org.schabi.newpipe.util.image.ImageStrategy.choosePreferredImage; import android.annotation.SuppressLint; import android.content.Context; import android.graphics.Bitmap; import android.util.Log; -import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.core.graphics.BitmapCompat; @@ -21,11 +21,9 @@ import com.squareup.picasso.Transformation; import org.schabi.newpipe.R; import org.schabi.newpipe.extractor.Image; -import org.schabi.newpipe.extractor.Image.ResolutionLevel; import java.io.File; import java.io.IOException; -import java.util.Comparator; import java.util.List; import java.util.concurrent.TimeUnit; @@ -46,7 +44,6 @@ public final class PicassoHelper { @SuppressLint("StaticFieldLeak") private static Picasso picassoInstance; - private static PreferredImageQuality preferredImageQuality = PreferredImageQuality.MEDIUM; public static void init(final Context context) { picassoCache = new LruCache(10 * 1024 * 1024); @@ -92,14 +89,6 @@ public final class PicassoHelper { picassoInstance.setIndicatorsEnabled(enabled); // useful for debugging } - public static void setPreferredImageQuality(final PreferredImageQuality preferredImageQuality) { - PicassoHelper.preferredImageQuality = preferredImageQuality; - } - - public static boolean shouldLoadImages() { - return preferredImageQuality != PreferredImageQuality.NONE; - } - public static RequestCreator loadAvatar(final List images) { return loadImageDefault(images, R.drawable.placeholder_person); @@ -227,41 +216,4 @@ public final class PicassoHelper { return requestCreator; } } - - @Nullable - public static String choosePreferredImage(final List images) { - final Comparator comparator; - switch (preferredImageQuality) { - case NONE: - return null; - case HIGH: - comparator = Comparator.comparingInt(Image::getHeight).reversed(); - break; - default: - case MEDIUM: - comparator = Comparator.comparingInt(image -> Math.abs(image.getHeight() - 450)); - break; - case LOW: - comparator = Comparator.comparingInt(Image::getHeight); - break; - } - - return images.stream() - .filter(image -> image.getEstimatedResolutionLevel() != ResolutionLevel.UNKNOWN) - .min(comparator) - .map(Image::getUrl) - .orElseGet(() -> images.stream() - .findAny() - .map(Image::getUrl) - .orElse(null)); - } - - @NonNull - public static List urlToImageList(@Nullable final String url) { - if (url == null) { - return List.of(); - } else { - return List.of(new Image(url, -1, -1, ResolutionLevel.UNKNOWN)); - } - } }