Support obtaining multiple images from the extractor
This commit is contained in:
parent
e2de83188a
commit
af2375948d
30 changed files with 190 additions and 77 deletions
|
@ -197,7 +197,7 @@ dependencies {
|
||||||
// name and the commit hash with the commit hash of the (pushed) commit you want to test
|
// name and the commit hash with the commit hash of the (pushed) commit you want to test
|
||||||
// This works thanks to JitPack: https://jitpack.io/
|
// This works thanks to JitPack: https://jitpack.io/
|
||||||
implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751'
|
implementation 'com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751'
|
||||||
implementation 'com.github.TeamNewPipe:NewPipeExtractor:95a3cc0a173bba28c179f9f9503b1010ec6bff21'
|
implementation 'com.github.TeamNewPipe:NewPipeExtractor:3be76a6406d59f1fd8eedf5fab6552e6c2a3da76'
|
||||||
implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'
|
implementation 'com.github.TeamNewPipe:NoNonsense-FilePicker:5.0.0'
|
||||||
|
|
||||||
/** Checkstyle **/
|
/** Checkstyle **/
|
||||||
|
|
|
@ -75,7 +75,7 @@ public final class QueueItemMenuUtil {
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_item_share:
|
case R.id.menu_item_share:
|
||||||
shareText(context, item.getTitle(), item.getUrl(),
|
shareText(context, item.getTitle(), item.getUrl(),
|
||||||
item.getThumbnailUrl());
|
item.getThumbnails());
|
||||||
return true;
|
return true;
|
||||||
case R.id.menu_item_download:
|
case R.id.menu_item_download:
|
||||||
fetchStreamInfoAndSaveToDatabase(context, item.getServiceId(), item.getUrl(),
|
fetchStreamInfoAndSaveToDatabase(context, item.getServiceId(), item.getUrl(),
|
||||||
|
|
|
@ -7,6 +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.StreamEntity
|
||||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity
|
import org.schabi.newpipe.database.stream.model.StreamStateEntity
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper
|
||||||
|
|
||||||
data class PlaylistStreamEntry(
|
data class PlaylistStreamEntry(
|
||||||
@Embedded
|
@Embedded
|
||||||
|
@ -28,7 +29,7 @@ data class PlaylistStreamEntry(
|
||||||
item.duration = streamEntity.duration
|
item.duration = streamEntity.duration
|
||||||
item.uploaderName = streamEntity.uploader
|
item.uploaderName = streamEntity.uploader
|
||||||
item.uploaderUrl = streamEntity.uploaderUrl
|
item.uploaderUrl = streamEntity.uploaderUrl
|
||||||
item.thumbnailUrl = streamEntity.thumbnailUrl
|
item.thumbnails = PicassoHelper.urlToImageList(streamEntity.thumbnailUrl)
|
||||||
|
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ import androidx.room.PrimaryKey;
|
||||||
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
import org.schabi.newpipe.database.playlist.PlaylistLocalItem;
|
||||||
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
import org.schabi.newpipe.extractor.playlist.PlaylistInfo;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
|
import static org.schabi.newpipe.database.LocalItem.LocalItemType.PLAYLIST_REMOTE_ITEM;
|
||||||
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME;
|
import static org.schabi.newpipe.database.playlist.model.PlaylistRemoteEntity.REMOTE_PLAYLIST_NAME;
|
||||||
|
@ -69,8 +70,7 @@ public class PlaylistRemoteEntity implements PlaylistLocalItem {
|
||||||
@Ignore
|
@Ignore
|
||||||
public PlaylistRemoteEntity(final PlaylistInfo info) {
|
public PlaylistRemoteEntity(final PlaylistInfo info) {
|
||||||
this(info.getServiceId(), info.getName(), info.getUrl(),
|
this(info.getServiceId(), info.getName(), info.getUrl(),
|
||||||
info.getThumbnailUrl() == null
|
PicassoHelper.choosePreferredImage(info.getThumbnails()),
|
||||||
? info.getUploaderAvatarUrl() : info.getThumbnailUrl(),
|
|
||||||
info.getUploaderName(), info.getStreamCount());
|
info.getUploaderName(), info.getStreamCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +84,8 @@ public class PlaylistRemoteEntity implements PlaylistLocalItem {
|
||||||
&& getStreamCount() == info.getStreamCount()
|
&& getStreamCount() == info.getStreamCount()
|
||||||
&& TextUtils.equals(getName(), info.getName())
|
&& TextUtils.equals(getName(), info.getName())
|
||||||
&& TextUtils.equals(getUrl(), info.getUrl())
|
&& TextUtils.equals(getUrl(), info.getUrl())
|
||||||
&& TextUtils.equals(getThumbnailUrl(), info.getThumbnailUrl())
|
&& TextUtils.equals(getThumbnailUrl(),
|
||||||
|
PicassoHelper.choosePreferredImage(info.getThumbnails()))
|
||||||
&& TextUtils.equals(getUploader(), info.getUploaderName());
|
&& TextUtils.equals(getUploader(), info.getUploaderName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -7,6 +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.StreamEntity
|
||||||
import org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS
|
import org.schabi.newpipe.database.stream.model.StreamStateEntity.STREAM_PROGRESS_MILLIS
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
class StreamStatisticsEntry(
|
class StreamStatisticsEntry(
|
||||||
|
@ -30,7 +31,7 @@ class StreamStatisticsEntry(
|
||||||
item.duration = streamEntity.duration
|
item.duration = streamEntity.duration
|
||||||
item.uploaderName = streamEntity.uploader
|
item.uploaderName = streamEntity.uploader
|
||||||
item.uploaderUrl = streamEntity.uploaderUrl
|
item.uploaderUrl = streamEntity.uploaderUrl
|
||||||
item.thumbnailUrl = streamEntity.thumbnailUrl
|
item.thumbnails = PicassoHelper.urlToImageList(streamEntity.thumbnailUrl)
|
||||||
|
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType
|
import org.schabi.newpipe.extractor.stream.StreamType
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.time.OffsetDateTime
|
import java.time.OffsetDateTime
|
||||||
|
|
||||||
|
@ -67,7 +68,7 @@ data class StreamEntity(
|
||||||
constructor(item: StreamInfoItem) : this(
|
constructor(item: StreamInfoItem) : this(
|
||||||
serviceId = item.serviceId, url = item.url, title = item.name,
|
serviceId = item.serviceId, url = item.url, title = item.name,
|
||||||
streamType = item.streamType, duration = item.duration, uploader = item.uploaderName,
|
streamType = item.streamType, duration = item.duration, uploader = item.uploaderName,
|
||||||
uploaderUrl = item.uploaderUrl, thumbnailUrl = item.thumbnailUrl, viewCount = item.viewCount,
|
uploaderUrl = item.uploaderUrl, thumbnailUrl = PicassoHelper.choosePreferredImage(item.thumbnails), viewCount = item.viewCount,
|
||||||
textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(),
|
textualUploadDate = item.textualUploadDate, uploadDate = item.uploadDate?.offsetDateTime(),
|
||||||
isUploadDateApproximation = item.uploadDate?.isApproximation
|
isUploadDateApproximation = item.uploadDate?.isApproximation
|
||||||
)
|
)
|
||||||
|
@ -76,7 +77,7 @@ data class StreamEntity(
|
||||||
constructor(info: StreamInfo) : this(
|
constructor(info: StreamInfo) : this(
|
||||||
serviceId = info.serviceId, url = info.url, title = info.name,
|
serviceId = info.serviceId, url = info.url, title = info.name,
|
||||||
streamType = info.streamType, duration = info.duration, uploader = info.uploaderName,
|
streamType = info.streamType, duration = info.duration, uploader = info.uploaderName,
|
||||||
uploaderUrl = info.uploaderUrl, thumbnailUrl = info.thumbnailUrl, viewCount = info.viewCount,
|
uploaderUrl = info.uploaderUrl, thumbnailUrl = PicassoHelper.choosePreferredImage(info.thumbnails), viewCount = info.viewCount,
|
||||||
textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(),
|
textualUploadDate = info.textualUploadDate, uploadDate = info.uploadDate?.offsetDateTime(),
|
||||||
isUploadDateApproximation = info.uploadDate?.isApproximation
|
isUploadDateApproximation = info.uploadDate?.isApproximation
|
||||||
)
|
)
|
||||||
|
@ -85,7 +86,8 @@ data class StreamEntity(
|
||||||
constructor(item: PlayQueueItem) : this(
|
constructor(item: PlayQueueItem) : this(
|
||||||
serviceId = item.serviceId, url = item.url, title = item.title,
|
serviceId = item.serviceId, url = item.url, title = item.title,
|
||||||
streamType = item.streamType, duration = item.duration, uploader = item.uploader,
|
streamType = item.streamType, duration = item.duration, uploader = item.uploader,
|
||||||
uploaderUrl = item.uploaderUrl, thumbnailUrl = item.thumbnailUrl
|
uploaderUrl = item.uploaderUrl,
|
||||||
|
thumbnailUrl = PicassoHelper.choosePreferredImage(item.thumbnails)
|
||||||
)
|
)
|
||||||
|
|
||||||
fun toStreamInfoItem(): StreamInfoItem {
|
fun toStreamInfoItem(): StreamInfoItem {
|
||||||
|
@ -93,7 +95,7 @@ data class StreamEntity(
|
||||||
item.duration = duration
|
item.duration = duration
|
||||||
item.uploaderName = uploader
|
item.uploaderName = uploader
|
||||||
item.uploaderUrl = uploaderUrl
|
item.uploaderUrl = uploaderUrl
|
||||||
item.thumbnailUrl = thumbnailUrl
|
item.thumbnails = PicassoHelper.urlToImageList(thumbnailUrl)
|
||||||
|
|
||||||
if (viewCount != null) item.viewCount = viewCount as Long
|
if (viewCount != null) item.viewCount = viewCount as Long
|
||||||
item.textualUploadDate = textualUploadDate
|
item.textualUploadDate = textualUploadDate
|
||||||
|
|
|
@ -10,6 +10,7 @@ import androidx.room.PrimaryKey;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
import org.schabi.newpipe.extractor.channel.ChannelInfo;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.util.Constants;
|
import org.schabi.newpipe.util.Constants;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
|
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_SERVICE_ID;
|
||||||
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
|
import static org.schabi.newpipe.database.subscription.SubscriptionEntity.SUBSCRIPTION_TABLE;
|
||||||
|
@ -57,8 +58,8 @@ public class SubscriptionEntity {
|
||||||
final 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(), PicassoHelper.choosePreferredImage(info.getAvatars()),
|
||||||
info.getSubscriberCount());
|
info.getDescription(), info.getSubscriberCount());
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -138,7 +139,7 @@ public class SubscriptionEntity {
|
||||||
@Ignore
|
@Ignore
|
||||||
public ChannelInfoItem toChannelInfoItem() {
|
public ChannelInfoItem toChannelInfoItem() {
|
||||||
final ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
final ChannelInfoItem item = new ChannelInfoItem(getServiceId(), getUrl(), getName());
|
||||||
item.setThumbnailUrl(getAvatarUrl());
|
item.setThumbnails(PicassoHelper.urlToImageList(getAvatarUrl()));
|
||||||
item.setSubscriberCount(getSubscriberCount());
|
item.setSubscriberCount(getSubscriberCount());
|
||||||
item.setDescription(getDescription());
|
item.setDescription(getDescription());
|
||||||
return item;
|
return item;
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import icepick.State;
|
import icepick.State;
|
||||||
|
|
||||||
|
@ -113,7 +114,7 @@ public class DescriptionFragment extends BaseDescriptionFragment {
|
||||||
addMetadataItem(inflater, layout, true, R.string.metadata_host,
|
addMetadataItem(inflater, layout, true, R.string.metadata_host,
|
||||||
streamInfo.getHost());
|
streamInfo.getHost());
|
||||||
addMetadataItem(inflater, layout, true, R.string.metadata_thumbnail_url,
|
addMetadataItem(inflater, layout, true, R.string.metadata_thumbnail_url,
|
||||||
streamInfo.getThumbnailUrl());
|
PicassoHelper.choosePreferredImage(streamInfo.getThumbnails()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addPrivacyMetadataItem(final LayoutInflater inflater, final LinearLayout layout) {
|
private void addPrivacyMetadataItem(final LayoutInflater inflater, final LinearLayout layout) {
|
||||||
|
|
|
@ -71,6 +71,7 @@ import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
import org.schabi.newpipe.error.ReCaptchaActivity;
|
import org.schabi.newpipe.error.ReCaptchaActivity;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
|
import org.schabi.newpipe.extractor.Image;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.InfoItem;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
import org.schabi.newpipe.extractor.NewPipe;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
import org.schabi.newpipe.extractor.exceptions.ContentNotSupportedException;
|
||||||
|
@ -483,7 +484,7 @@ public final class VideoDetailFragment
|
||||||
});
|
});
|
||||||
binding.detailControlsShare.setOnClickListener(makeOnClickListener(info ->
|
binding.detailControlsShare.setOnClickListener(makeOnClickListener(info ->
|
||||||
ShareUtils.shareText(requireContext(), info.getName(), info.getUrl(),
|
ShareUtils.shareText(requireContext(), info.getName(), info.getUrl(),
|
||||||
info.getThumbnailUrl())));
|
info.getThumbnails())));
|
||||||
binding.detailControlsOpenInBrowser.setOnClickListener(makeOnClickListener(info ->
|
binding.detailControlsOpenInBrowser.setOnClickListener(makeOnClickListener(info ->
|
||||||
ShareUtils.openUrlInBrowser(requireContext(), info.getUrl())));
|
ShareUtils.openUrlInBrowser(requireContext(), info.getUrl())));
|
||||||
binding.detailControlsPlayWithKodi.setOnClickListener(makeOnClickListener(info ->
|
binding.detailControlsPlayWithKodi.setOnClickListener(makeOnClickListener(info ->
|
||||||
|
@ -723,7 +724,7 @@ public final class VideoDetailFragment
|
||||||
final boolean isPlayerStopped = !isPlayerAvailable() || player.isStopped();
|
final boolean isPlayerStopped = !isPlayerAvailable() || player.isStopped();
|
||||||
if (playQueueItem != null && isPlayerStopped) {
|
if (playQueueItem != null && isPlayerStopped) {
|
||||||
updateOverlayData(playQueueItem.getTitle(),
|
updateOverlayData(playQueueItem.getTitle(),
|
||||||
playQueueItem.getUploader(), playQueueItem.getThumbnailUrl());
|
playQueueItem.getUploader(), playQueueItem.getThumbnails());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1536,13 +1537,13 @@ public final class VideoDetailFragment
|
||||||
binding.detailSecondaryControlPanel.setVisibility(View.GONE);
|
binding.detailSecondaryControlPanel.setVisibility(View.GONE);
|
||||||
|
|
||||||
checkUpdateProgressInfo(info);
|
checkUpdateProgressInfo(info);
|
||||||
PicassoHelper.loadDetailsThumbnail(info.getThumbnailUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
PicassoHelper.loadDetailsThumbnail(info.getThumbnails()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||||
.into(binding.detailThumbnailImageView);
|
.into(binding.detailThumbnailImageView);
|
||||||
showMetaInfoInTextView(info.getMetaInfo(), binding.detailMetaInfoTextView,
|
showMetaInfoInTextView(info.getMetaInfo(), binding.detailMetaInfoTextView,
|
||||||
binding.detailMetaInfoSeparator, disposables);
|
binding.detailMetaInfoSeparator, disposables);
|
||||||
|
|
||||||
if (!isPlayerAvailable() || player.isStopped()) {
|
if (!isPlayerAvailable() || player.isStopped()) {
|
||||||
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnails());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!info.getErrors().isEmpty()) {
|
if (!info.getErrors().isEmpty()) {
|
||||||
|
@ -1587,7 +1588,7 @@ public final class VideoDetailFragment
|
||||||
binding.detailUploaderTextView.setVisibility(View.GONE);
|
binding.detailUploaderTextView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
PicassoHelper.loadAvatar(info.getUploaderAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
PicassoHelper.loadAvatar(info.getUploaderAvatars()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||||
.into(binding.detailSubChannelThumbnailView);
|
.into(binding.detailSubChannelThumbnailView);
|
||||||
binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE);
|
binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE);
|
||||||
binding.detailUploaderThumbnailView.setVisibility(View.GONE);
|
binding.detailUploaderThumbnailView.setVisibility(View.GONE);
|
||||||
|
@ -1619,10 +1620,10 @@ public final class VideoDetailFragment
|
||||||
binding.detailUploaderTextView.setVisibility(View.GONE);
|
binding.detailUploaderTextView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
PicassoHelper.loadAvatar(info.getSubChannelAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
PicassoHelper.loadAvatar(info.getSubChannelAvatars()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||||
.into(binding.detailSubChannelThumbnailView);
|
.into(binding.detailSubChannelThumbnailView);
|
||||||
binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE);
|
binding.detailSubChannelThumbnailView.setVisibility(View.VISIBLE);
|
||||||
PicassoHelper.loadAvatar(info.getUploaderAvatarUrl()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
PicassoHelper.loadAvatar(info.getUploaderAvatars()).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||||
.into(binding.detailUploaderThumbnailView);
|
.into(binding.detailUploaderThumbnailView);
|
||||||
binding.detailUploaderThumbnailView.setVisibility(View.VISIBLE);
|
binding.detailUploaderThumbnailView.setVisibility(View.VISIBLE);
|
||||||
}
|
}
|
||||||
|
@ -1797,7 +1798,7 @@ public final class VideoDetailFragment
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnailUrl());
|
updateOverlayData(info.getName(), info.getUploaderName(), info.getThumbnails());
|
||||||
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) {
|
if (currentInfo != null && info.getUrl().equals(currentInfo.getUrl())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1826,7 +1827,7 @@ public final class VideoDetailFragment
|
||||||
if (currentInfo != null) {
|
if (currentInfo != null) {
|
||||||
updateOverlayData(currentInfo.getName(),
|
updateOverlayData(currentInfo.getName(),
|
||||||
currentInfo.getUploaderName(),
|
currentInfo.getUploaderName(),
|
||||||
currentInfo.getThumbnailUrl());
|
currentInfo.getThumbnails());
|
||||||
}
|
}
|
||||||
updateOverlayPlayQueueButtonVisibility();
|
updateOverlayPlayQueueButtonVisibility();
|
||||||
}
|
}
|
||||||
|
@ -2191,7 +2192,7 @@ public final class VideoDetailFragment
|
||||||
playerHolder.stopService();
|
playerHolder.stopService();
|
||||||
setInitialData(0, null, "", null);
|
setInitialData(0, null, "", null);
|
||||||
currentInfo = null;
|
currentInfo = null;
|
||||||
updateOverlayData(null, null, null);
|
updateOverlayData(null, null, List.of());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*//////////////////////////////////////////////////////////////////////////
|
/*//////////////////////////////////////////////////////////////////////////
|
||||||
|
@ -2373,11 +2374,11 @@ public final class VideoDetailFragment
|
||||||
|
|
||||||
private void updateOverlayData(@Nullable final String overlayTitle,
|
private void updateOverlayData(@Nullable final String overlayTitle,
|
||||||
@Nullable final String uploader,
|
@Nullable final String uploader,
|
||||||
@Nullable final String thumbnailUrl) {
|
@NonNull final List<Image> thumbnails) {
|
||||||
binding.overlayTitleTextView.setText(isEmpty(overlayTitle) ? "" : overlayTitle);
|
binding.overlayTitleTextView.setText(isEmpty(overlayTitle) ? "" : overlayTitle);
|
||||||
binding.overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
|
binding.overlayChannelTextView.setText(isEmpty(uploader) ? "" : uploader);
|
||||||
binding.overlayThumbnail.setImageDrawable(null);
|
binding.overlayThumbnail.setImageDrawable(null);
|
||||||
PicassoHelper.loadDetailsThumbnail(thumbnailUrl).tag(PICASSO_VIDEO_DETAILS_TAG)
|
PicassoHelper.loadDetailsThumbnail(thumbnails).tag(PICASSO_VIDEO_DETAILS_TAG)
|
||||||
.into(binding.overlayThumbnail);
|
.into(binding.overlayThumbnail);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.schabi.newpipe.extractor.stream.Description;
|
||||||
import org.schabi.newpipe.fragments.detail.BaseDescriptionFragment;
|
import org.schabi.newpipe.fragments.detail.BaseDescriptionFragment;
|
||||||
import org.schabi.newpipe.util.DeviceUtils;
|
import org.schabi.newpipe.util.DeviceUtils;
|
||||||
import org.schabi.newpipe.util.Localization;
|
import org.schabi.newpipe.util.Localization;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -100,8 +101,8 @@ public class ChannelAboutFragment extends BaseDescriptionFragment {
|
||||||
}
|
}
|
||||||
|
|
||||||
addMetadataItem(inflater, layout, true, R.string.metadata_avatar_url,
|
addMetadataItem(inflater, layout, true, R.string.metadata_avatar_url,
|
||||||
channelInfo.getAvatarUrl());
|
PicassoHelper.choosePreferredImage(channelInfo.getAvatars()));
|
||||||
addMetadataItem(inflater, layout, true, R.string.metadata_banner_url,
|
addMetadataItem(inflater, layout, true, R.string.metadata_banner_url,
|
||||||
channelInfo.getBannerUrl());
|
PicassoHelper.choosePreferredImage(channelInfo.getBanners()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
package org.schabi.newpipe.fragments.list.channel;
|
package org.schabi.newpipe.fragments.list.channel;
|
||||||
|
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
|
||||||
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
|
import static org.schabi.newpipe.ktx.TextViewUtils.animateTextColor;
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
import static org.schabi.newpipe.ktx.ViewUtils.animate;
|
||||||
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
|
import static org.schabi.newpipe.ktx.ViewUtils.animateBackgroundColor;
|
||||||
|
@ -234,7 +233,7 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
||||||
case R.id.menu_item_share:
|
case R.id.menu_item_share:
|
||||||
if (currentInfo != null) {
|
if (currentInfo != null) {
|
||||||
ShareUtils.shareText(requireContext(), name, currentInfo.getOriginalUrl(),
|
ShareUtils.shareText(requireContext(), name, currentInfo.getOriginalUrl(),
|
||||||
currentInfo.getAvatarUrl());
|
currentInfo.getAvatars());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -355,7 +354,7 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
||||||
channel.setServiceId(info.getServiceId());
|
channel.setServiceId(info.getServiceId());
|
||||||
channel.setUrl(info.getUrl());
|
channel.setUrl(info.getUrl());
|
||||||
channel.setData(info.getName(),
|
channel.setData(info.getName(),
|
||||||
info.getAvatarUrl(),
|
PicassoHelper.choosePreferredImage(info.getAvatars()),
|
||||||
info.getDescription(),
|
info.getDescription(),
|
||||||
info.getSubscriberCount());
|
info.getSubscriberCount());
|
||||||
channelSubscription = null;
|
channelSubscription = null;
|
||||||
|
@ -579,17 +578,17 @@ public class ChannelFragment extends BaseStateFragment<ChannelInfo>
|
||||||
currentInfo = result;
|
currentInfo = result;
|
||||||
setInitialData(result.getServiceId(), result.getOriginalUrl(), result.getName());
|
setInitialData(result.getServiceId(), result.getOriginalUrl(), result.getName());
|
||||||
|
|
||||||
if (PicassoHelper.getShouldLoadImages() && !isBlank(result.getBannerUrl())) {
|
if (PicassoHelper.getShouldLoadImages() && !result.getBanners().isEmpty()) {
|
||||||
PicassoHelper.loadBanner(result.getBannerUrl()).tag(PICASSO_CHANNEL_TAG)
|
PicassoHelper.loadBanner(result.getBanners()).tag(PICASSO_CHANNEL_TAG)
|
||||||
.into(binding.channelBannerImage);
|
.into(binding.channelBannerImage);
|
||||||
} else {
|
} else {
|
||||||
// do not waste space for the banner, if the user disabled images or there is not one
|
// do not waste space for the banner, if the user disabled images or there is not one
|
||||||
binding.channelBannerImage.setImageDrawable(null);
|
binding.channelBannerImage.setImageDrawable(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
PicassoHelper.loadAvatar(result.getAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
|
PicassoHelper.loadAvatar(result.getAvatars()).tag(PICASSO_CHANNEL_TAG)
|
||||||
.into(binding.channelAvatarView);
|
.into(binding.channelAvatarView);
|
||||||
PicassoHelper.loadAvatar(result.getParentChannelAvatarUrl()).tag(PICASSO_CHANNEL_TAG)
|
PicassoHelper.loadAvatar(result.getParentChannelAvatars()).tag(PICASSO_CHANNEL_TAG)
|
||||||
.into(binding.subChannelAvatarView);
|
.into(binding.subChannelAvatarView);
|
||||||
|
|
||||||
binding.channelTitleView.setText(result.getName());
|
binding.channelTitleView.setText(result.getName());
|
||||||
|
|
|
@ -234,7 +234,7 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||||
break;
|
break;
|
||||||
case R.id.menu_item_share:
|
case R.id.menu_item_share:
|
||||||
ShareUtils.shareText(requireContext(), name, url,
|
ShareUtils.shareText(requireContext(), name, url,
|
||||||
currentInfo == null ? null : currentInfo.getThumbnailUrl());
|
currentInfo == null ? List.of() : currentInfo.getThumbnails());
|
||||||
break;
|
break;
|
||||||
case R.id.menu_item_bookmark:
|
case R.id.menu_item_bookmark:
|
||||||
onBookmarkClicked();
|
onBookmarkClicked();
|
||||||
|
@ -299,7 +299,6 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||||
|
|
||||||
playlistControlBinding.getRoot().setVisibility(View.VISIBLE);
|
playlistControlBinding.getRoot().setVisibility(View.VISIBLE);
|
||||||
|
|
||||||
final String avatarUrl = result.getUploaderAvatarUrl();
|
|
||||||
if (result.getServiceId() == ServiceList.YouTube.getServiceId()
|
if (result.getServiceId() == ServiceList.YouTube.getServiceId()
|
||||||
&& (YoutubeParsingHelper.isYoutubeMixId(result.getId())
|
&& (YoutubeParsingHelper.isYoutubeMixId(result.getId())
|
||||||
|| YoutubeParsingHelper.isYoutubeMusicMixId(result.getId()))) {
|
|| YoutubeParsingHelper.isYoutubeMusicMixId(result.getId()))) {
|
||||||
|
@ -315,7 +314,7 @@ public class PlaylistFragment extends BaseListInfoFragment<StreamInfoItem, Playl
|
||||||
R.drawable.ic_radio)
|
R.drawable.ic_radio)
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
PicassoHelper.loadAvatar(avatarUrl).tag(PICASSO_PLAYLIST_TAG)
|
PicassoHelper.loadAvatar(result.getUploaderAvatars()).tag(PICASSO_PLAYLIST_TAG)
|
||||||
.into(headerBinding.uploaderAvatarView);
|
.into(headerBinding.uploaderAvatarView);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,7 +104,7 @@ public enum StreamDialogDefaultEntry {
|
||||||
|
|
||||||
SHARE(R.string.share, (fragment, item) ->
|
SHARE(R.string.share, (fragment, item) ->
|
||||||
ShareUtils.shareText(fragment.requireContext(), item.getName(), item.getUrl(),
|
ShareUtils.shareText(fragment.requireContext(), item.getName(), item.getUrl(),
|
||||||
item.getThumbnailUrl())),
|
item.getThumbnails())),
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Opens a {@link DownloadDialog} after fetching some stream info.
|
* Opens a {@link DownloadDialog} after fetching some stream info.
|
||||||
|
|
|
@ -56,7 +56,7 @@ public class ChannelMiniInfoItemHolder extends InfoItemHolder {
|
||||||
itemAdditionalDetailView.setText(getDetailLine(item));
|
itemAdditionalDetailView.setText(getDetailLine(item));
|
||||||
}
|
}
|
||||||
|
|
||||||
PicassoHelper.loadAvatar(item.getThumbnailUrl()).into(itemThumbnailView);
|
PicassoHelper.loadAvatar(item.getThumbnails()).into(itemThumbnailView);
|
||||||
|
|
||||||
itemView.setOnClickListener(view -> {
|
itemView.setOnClickListener(view -> {
|
||||||
if (itemBuilder.getOnChannelSelectedListener() != null) {
|
if (itemBuilder.getOnChannelSelectedListener() != null) {
|
||||||
|
|
|
@ -97,7 +97,7 @@ public class CommentsMiniInfoItemHolder extends InfoItemHolder {
|
||||||
}
|
}
|
||||||
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
final CommentsInfoItem item = (CommentsInfoItem) infoItem;
|
||||||
|
|
||||||
PicassoHelper.loadAvatar(item.getUploaderAvatarUrl()).into(itemThumbnailView);
|
PicassoHelper.loadAvatar(item.getUploaderAvatars()).into(itemThumbnailView);
|
||||||
if (PicassoHelper.getShouldLoadImages()) {
|
if (PicassoHelper.getShouldLoadImages()) {
|
||||||
itemThumbnailView.setVisibility(View.VISIBLE);
|
itemThumbnailView.setVisibility(View.VISIBLE);
|
||||||
itemRoot.setPadding(commentVerticalPadding, commentVerticalPadding,
|
itemRoot.setPadding(commentVerticalPadding, commentVerticalPadding,
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class PlaylistMiniInfoItemHolder extends InfoItemHolder {
|
||||||
.localizeStreamCountMini(itemStreamCountView.getContext(), item.getStreamCount()));
|
.localizeStreamCountMini(itemStreamCountView.getContext(), item.getStreamCount()));
|
||||||
itemUploaderView.setText(item.getUploaderName());
|
itemUploaderView.setText(item.getUploaderName());
|
||||||
|
|
||||||
PicassoHelper.loadPlaylistThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
|
PicassoHelper.loadPlaylistThumbnail(item.getThumbnails()).into(itemThumbnailView);
|
||||||
|
|
||||||
itemView.setOnClickListener(view -> {
|
itemView.setOnClickListener(view -> {
|
||||||
if (itemBuilder.getOnPlaylistSelectedListener() != null) {
|
if (itemBuilder.getOnPlaylistSelectedListener() != null) {
|
||||||
|
|
|
@ -87,7 +87,7 @@ public class StreamMiniInfoItemHolder extends InfoItemHolder {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Default thumbnail is shown on error, while loading and if the url is empty
|
// Default thumbnail is shown on error, while loading and if the url is empty
|
||||||
PicassoHelper.loadThumbnail(item.getThumbnailUrl()).into(itemThumbnailView);
|
PicassoHelper.loadThumbnail(item.getThumbnails()).into(itemThumbnailView);
|
||||||
|
|
||||||
itemView.setOnClickListener(view -> {
|
itemView.setOnClickListener(view -> {
|
||||||
if (itemBuilder.getOnStreamSelectedListener() != null) {
|
if (itemBuilder.getOnStreamSelectedListener() != null) {
|
||||||
|
|
|
@ -58,6 +58,7 @@ import org.schabi.newpipe.streams.io.NoFileManagerSafeGuard
|
||||||
import org.schabi.newpipe.streams.io.StoredFileHelper
|
import org.schabi.newpipe.streams.io.StoredFileHelper
|
||||||
import org.schabi.newpipe.util.NavigationHelper
|
import org.schabi.newpipe.util.NavigationHelper
|
||||||
import org.schabi.newpipe.util.OnClickGesture
|
import org.schabi.newpipe.util.OnClickGesture
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper
|
||||||
import org.schabi.newpipe.util.ServiceHelper
|
import org.schabi.newpipe.util.ServiceHelper
|
||||||
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountChannels
|
import org.schabi.newpipe.util.ThemeHelper.getGridSpanCountChannels
|
||||||
import org.schabi.newpipe.util.external_communication.ShareUtils
|
import org.schabi.newpipe.util.external_communication.ShareUtils
|
||||||
|
@ -342,7 +343,7 @@ class SubscriptionFragment : BaseStateFragment<SubscriptionState>() {
|
||||||
when (i) {
|
when (i) {
|
||||||
0 -> ShareUtils.shareText(
|
0 -> ShareUtils.shareText(
|
||||||
requireContext(), selectedItem.name, selectedItem.url,
|
requireContext(), selectedItem.name, selectedItem.url,
|
||||||
selectedItem.thumbnailUrl
|
PicassoHelper.choosePreferredImage(selectedItem.thumbnails)
|
||||||
)
|
)
|
||||||
1 -> ShareUtils.openUrlInBrowser(requireContext(), selectedItem.url)
|
1 -> ShareUtils.openUrlInBrowser(requireContext(), selectedItem.url)
|
||||||
2 -> deleteChannel(selectedItem)
|
2 -> deleteChannel(selectedItem)
|
||||||
|
|
|
@ -19,6 +19,7 @@ import org.schabi.newpipe.extractor.feed.FeedInfo
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem
|
||||||
import org.schabi.newpipe.local.feed.FeedDatabaseManager
|
import org.schabi.newpipe.local.feed.FeedDatabaseManager
|
||||||
import org.schabi.newpipe.util.ExtractorHelper
|
import org.schabi.newpipe.util.ExtractorHelper
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper
|
||||||
|
|
||||||
class SubscriptionManager(context: Context) {
|
class SubscriptionManager(context: Context) {
|
||||||
private val database = NewPipeDatabase.getInstance(context)
|
private val database = NewPipeDatabase.getInstance(context)
|
||||||
|
@ -71,7 +72,12 @@ class SubscriptionManager(context: Context) {
|
||||||
subscriptionTable.getSubscription(info.serviceId, info.url)
|
subscriptionTable.getSubscription(info.serviceId, info.url)
|
||||||
.flatMapCompletable {
|
.flatMapCompletable {
|
||||||
Completable.fromRunnable {
|
Completable.fromRunnable {
|
||||||
it.setData(info.name, info.avatarUrl, info.description, info.subscriberCount)
|
it.setData(
|
||||||
|
info.name,
|
||||||
|
PicassoHelper.choosePreferredImage(info.avatars),
|
||||||
|
info.description,
|
||||||
|
info.subscriberCount
|
||||||
|
)
|
||||||
subscriptionTable.update(it)
|
subscriptionTable.update(it)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -99,7 +105,7 @@ class SubscriptionManager(context: Context) {
|
||||||
} else if (info is ChannelInfo) {
|
} else if (info is ChannelInfo) {
|
||||||
subscriptionEntity.setData(
|
subscriptionEntity.setData(
|
||||||
info.name,
|
info.name,
|
||||||
info.avatarUrl,
|
PicassoHelper.choosePreferredImage(info.avatars),
|
||||||
info.description,
|
info.description,
|
||||||
info.subscriberCount
|
info.subscriberCount
|
||||||
)
|
)
|
||||||
|
|
|
@ -39,7 +39,7 @@ class ChannelItem(
|
||||||
itemChannelDescriptionView.text = infoItem.description
|
itemChannelDescriptionView.text = infoItem.description
|
||||||
}
|
}
|
||||||
|
|
||||||
PicassoHelper.loadAvatar(infoItem.thumbnailUrl).into(itemThumbnailView)
|
PicassoHelper.loadAvatar(infoItem.thumbnails).into(itemThumbnailView)
|
||||||
|
|
||||||
gesturesListener?.run {
|
gesturesListener?.run {
|
||||||
viewHolder.root.setOnClickListener { selected(infoItem) }
|
viewHolder.root.setOnClickListener { selected(infoItem) }
|
||||||
|
|
|
@ -87,6 +87,7 @@ import org.schabi.newpipe.error.ErrorInfo;
|
||||||
import org.schabi.newpipe.error.ErrorUtil;
|
import org.schabi.newpipe.error.ErrorUtil;
|
||||||
import org.schabi.newpipe.error.UserAction;
|
import org.schabi.newpipe.error.UserAction;
|
||||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||||
|
import org.schabi.newpipe.extractor.Image;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
|
@ -805,10 +806,10 @@ public final class Player implements PlaybackListener, Listener {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadCurrentThumbnail(final String url) {
|
private void loadCurrentThumbnail(final List<Image> thumbnails) {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Thumbnail - loadCurrentThumbnail() called with url = ["
|
Log.d(TAG, "Thumbnail - loadCurrentThumbnail() called with thumbnails = ["
|
||||||
+ (url == null ? "null" : url) + "]");
|
+ thumbnails.size() + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
// first cancel any previous loading
|
// first cancel any previous loading
|
||||||
|
@ -817,12 +818,12 @@ public final class Player implements PlaybackListener, Listener {
|
||||||
// Unset currentThumbnail, since it is now outdated. This ensures it is not used in media
|
// Unset currentThumbnail, since it is now outdated. This ensures it is not used in media
|
||||||
// session metadata while the new thumbnail is being loaded by Picasso.
|
// session metadata while the new thumbnail is being loaded by Picasso.
|
||||||
onThumbnailLoaded(null);
|
onThumbnailLoaded(null);
|
||||||
if (isNullOrEmpty(url)) {
|
if (thumbnails.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// scale down the notification thumbnail for performance
|
// scale down the notification thumbnail for performance
|
||||||
PicassoHelper.loadScaledDownThumbnail(context, url)
|
PicassoHelper.loadScaledDownThumbnail(context, thumbnails)
|
||||||
.tag(PICASSO_PLAYER_THUMBNAIL_TAG)
|
.tag(PICASSO_PLAYER_THUMBNAIL_TAG)
|
||||||
.into(currentThumbnailTarget);
|
.into(currentThumbnailTarget);
|
||||||
}
|
}
|
||||||
|
@ -1792,7 +1793,7 @@ public final class Player implements PlaybackListener, Listener {
|
||||||
|
|
||||||
maybeAutoQueueNextStream(info);
|
maybeAutoQueueNextStream(info);
|
||||||
|
|
||||||
loadCurrentThumbnail(info.getThumbnailUrl());
|
loadCurrentThumbnail(info.getThumbnails());
|
||||||
registerStreamViewed();
|
registerStreamViewed();
|
||||||
|
|
||||||
notifyMetadataUpdateToListeners();
|
notifyMetadataUpdateToListeners();
|
||||||
|
|
|
@ -3,6 +3,7 @@ package org.schabi.newpipe.player.mediaitem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -74,7 +75,7 @@ public final class ExceptionTag implements MediaItemTag {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getThumbnailUrl() {
|
public String getThumbnailUrl() {
|
||||||
return item.getThumbnailUrl();
|
return PicassoHelper.choosePreferredImage(item.getThumbnails());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,6 +6,7 @@ import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -95,7 +96,7 @@ public final class StreamInfoTag implements MediaItemTag {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getThumbnailUrl() {
|
public String getThumbnailUrl() {
|
||||||
return streamInfo.getThumbnailUrl();
|
return PicassoHelper.choosePreferredImage(streamInfo.getThumbnails());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -20,6 +20,7 @@ import com.google.android.exoplayer2.util.Util;
|
||||||
import org.schabi.newpipe.player.Player;
|
import org.schabi.newpipe.player.Player;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
import org.schabi.newpipe.player.playqueue.PlayQueue;
|
||||||
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
import org.schabi.newpipe.player.playqueue.PlayQueueItem;
|
||||||
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -137,7 +138,8 @@ public class PlayQueueNavigator implements MediaSessionConnector.QueueNavigator
|
||||||
.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, player.getPlayQueue().size());
|
.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, player.getPlayQueue().size());
|
||||||
descBuilder.setExtras(additionalMetadata);
|
descBuilder.setExtras(additionalMetadata);
|
||||||
|
|
||||||
final Uri thumbnailUri = Uri.parse(item.getThumbnailUrl());
|
final Uri thumbnailUri = Uri.parse(
|
||||||
|
PicassoHelper.choosePreferredImage(item.getThumbnails()));
|
||||||
if (thumbnailUri != null) {
|
if (thumbnailUri != null) {
|
||||||
descBuilder.setIconUri(thumbnailUri);
|
descBuilder.setIconUri(thumbnailUri);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,12 +3,14 @@ package org.schabi.newpipe.player.playqueue;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
|
|
||||||
|
import org.schabi.newpipe.extractor.Image;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
import org.schabi.newpipe.util.ExtractorHelper;
|
import org.schabi.newpipe.util.ExtractorHelper;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
import io.reactivex.rxjava3.core.Single;
|
import io.reactivex.rxjava3.core.Single;
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers;
|
import io.reactivex.rxjava3.schedulers.Schedulers;
|
||||||
|
@ -24,7 +26,7 @@ public class PlayQueueItem implements Serializable {
|
||||||
private final int serviceId;
|
private final int serviceId;
|
||||||
private final long duration;
|
private final long duration;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final String thumbnailUrl;
|
private final List<Image> thumbnails;
|
||||||
@NonNull
|
@NonNull
|
||||||
private final String uploader;
|
private final String uploader;
|
||||||
private final String uploaderUrl;
|
private final String uploaderUrl;
|
||||||
|
@ -38,7 +40,7 @@ public class PlayQueueItem implements Serializable {
|
||||||
|
|
||||||
PlayQueueItem(@NonNull final StreamInfo info) {
|
PlayQueueItem(@NonNull final StreamInfo info) {
|
||||||
this(info.getName(), info.getUrl(), info.getServiceId(), info.getDuration(),
|
this(info.getName(), info.getUrl(), info.getServiceId(), info.getDuration(),
|
||||||
info.getThumbnailUrl(), info.getUploaderName(),
|
info.getThumbnails(), info.getUploaderName(),
|
||||||
info.getUploaderUrl(), info.getStreamType());
|
info.getUploaderUrl(), info.getStreamType());
|
||||||
|
|
||||||
if (info.getStartPosition() > 0) {
|
if (info.getStartPosition() > 0) {
|
||||||
|
@ -48,20 +50,20 @@ public class PlayQueueItem implements Serializable {
|
||||||
|
|
||||||
PlayQueueItem(@NonNull final StreamInfoItem item) {
|
PlayQueueItem(@NonNull final StreamInfoItem item) {
|
||||||
this(item.getName(), item.getUrl(), item.getServiceId(), item.getDuration(),
|
this(item.getName(), item.getUrl(), item.getServiceId(), item.getDuration(),
|
||||||
item.getThumbnailUrl(), item.getUploaderName(),
|
item.getThumbnails(), item.getUploaderName(),
|
||||||
item.getUploaderUrl(), item.getStreamType());
|
item.getUploaderUrl(), item.getStreamType());
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("ParameterNumber")
|
@SuppressWarnings("ParameterNumber")
|
||||||
private PlayQueueItem(@Nullable final String name, @Nullable final String url,
|
private PlayQueueItem(@Nullable final String name, @Nullable final String url,
|
||||||
final int serviceId, final long duration,
|
final int serviceId, final long duration,
|
||||||
@Nullable final String thumbnailUrl, @Nullable final String uploader,
|
final List<Image> thumbnails, @Nullable final String uploader,
|
||||||
final String uploaderUrl, @NonNull final StreamType streamType) {
|
final String uploaderUrl, @NonNull final StreamType streamType) {
|
||||||
this.title = name != null ? name : EMPTY_STRING;
|
this.title = name != null ? name : EMPTY_STRING;
|
||||||
this.url = url != null ? url : EMPTY_STRING;
|
this.url = url != null ? url : EMPTY_STRING;
|
||||||
this.serviceId = serviceId;
|
this.serviceId = serviceId;
|
||||||
this.duration = duration;
|
this.duration = duration;
|
||||||
this.thumbnailUrl = thumbnailUrl != null ? thumbnailUrl : EMPTY_STRING;
|
this.thumbnails = thumbnails;
|
||||||
this.uploader = uploader != null ? uploader : EMPTY_STRING;
|
this.uploader = uploader != null ? uploader : EMPTY_STRING;
|
||||||
this.uploaderUrl = uploaderUrl;
|
this.uploaderUrl = uploaderUrl;
|
||||||
this.streamType = streamType;
|
this.streamType = streamType;
|
||||||
|
@ -88,8 +90,8 @@ public class PlayQueueItem implements Serializable {
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
public String getThumbnailUrl() {
|
public List<Image> getThumbnails() {
|
||||||
return thumbnailUrl;
|
return thumbnails;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class PlayQueueItemBuilder {
|
||||||
holder.itemDurationView.setVisibility(View.GONE);
|
holder.itemDurationView.setVisibility(View.GONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
PicassoHelper.loadThumbnail(item.getThumbnailUrl()).into(holder.itemThumbnailView);
|
PicassoHelper.loadThumbnail(item.getThumbnails()).into(holder.itemThumbnailView);
|
||||||
|
|
||||||
holder.itemRoot.setOnClickListener(view -> {
|
holder.itemRoot.setOnClickListener(view -> {
|
||||||
if (onItemClickListener != null) {
|
if (onItemClickListener != null) {
|
||||||
|
|
|
@ -740,7 +740,7 @@ public final class MainPlayerUi extends VideoPlayerUi implements View.OnLayoutCh
|
||||||
String videoUrl = player.getVideoUrl();
|
String videoUrl = player.getVideoUrl();
|
||||||
videoUrl += ("&t=" + seconds);
|
videoUrl += ("&t=" + seconds);
|
||||||
ShareUtils.shareText(context, currentItem.getTitle(),
|
ShareUtils.shareText(context, currentItem.getTitle(),
|
||||||
videoUrl, currentItem.getThumbnailUrl());
|
videoUrl, currentItem.getThumbnails());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -226,7 +226,7 @@ public abstract class VideoPlayerUi extends PlayerUi implements SeekBar.OnSeekBa
|
||||||
final PlayQueueItem currentItem = player.getCurrentItem();
|
final PlayQueueItem currentItem = player.getCurrentItem();
|
||||||
if (currentItem != null) {
|
if (currentItem != null) {
|
||||||
ShareUtils.shareText(context, currentItem.getTitle(),
|
ShareUtils.shareText(context, currentItem.getTitle(),
|
||||||
player.getVideoUrlAtCurrentTime(), currentItem.getThumbnailUrl());
|
player.getVideoUrlAtCurrentTime(), currentItem.getThumbnails());
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
binding.share.setOnLongClickListener(v -> {
|
binding.share.setOnLongClickListener(v -> {
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
package org.schabi.newpipe.util;
|
package org.schabi.newpipe.util;
|
||||||
|
|
||||||
import static org.schabi.newpipe.MainActivity.DEBUG;
|
import static org.schabi.newpipe.MainActivity.DEBUG;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.isBlank;
|
import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
|
|
||||||
import android.annotation.SuppressLint;
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.core.graphics.BitmapCompat;
|
import androidx.core.graphics.BitmapCompat;
|
||||||
|
|
||||||
|
@ -19,9 +20,13 @@ import com.squareup.picasso.RequestCreator;
|
||||||
import com.squareup.picasso.Transformation;
|
import com.squareup.picasso.Transformation;
|
||||||
|
|
||||||
import org.schabi.newpipe.R;
|
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.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
import okhttp3.OkHttpClient;
|
import okhttp3.OkHttpClient;
|
||||||
|
@ -42,6 +47,7 @@ public final class PicassoHelper {
|
||||||
private static Picasso picassoInstance;
|
private static Picasso picassoInstance;
|
||||||
|
|
||||||
private static boolean shouldLoadImages;
|
private static boolean shouldLoadImages;
|
||||||
|
private static ResolutionLevel preferredResolutionLevel = ResolutionLevel.HIGH;
|
||||||
|
|
||||||
public static void init(final Context context) {
|
public static void init(final Context context) {
|
||||||
picassoCache = new LruCache(10 * 1024 * 1024);
|
picassoCache = new LruCache(10 * 1024 * 1024);
|
||||||
|
@ -96,20 +102,33 @@ public final class PicassoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static RequestCreator loadAvatar(final List<Image> images) {
|
||||||
|
return loadImageDefault(images, R.drawable.placeholder_person);
|
||||||
|
}
|
||||||
|
|
||||||
public static RequestCreator loadAvatar(final String url) {
|
public static RequestCreator loadAvatar(final String url) {
|
||||||
return loadImageDefault(url, R.drawable.placeholder_person);
|
return loadImageDefault(url, R.drawable.placeholder_person);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static RequestCreator loadThumbnail(final List<Image> images) {
|
||||||
|
return loadImageDefault(images, R.drawable.placeholder_thumbnail_video);
|
||||||
|
}
|
||||||
|
|
||||||
public static RequestCreator loadThumbnail(final String url) {
|
public static RequestCreator loadThumbnail(final String url) {
|
||||||
return loadImageDefault(url, R.drawable.placeholder_thumbnail_video);
|
return loadImageDefault(url, R.drawable.placeholder_thumbnail_video);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RequestCreator loadDetailsThumbnail(final String url) {
|
public static RequestCreator loadDetailsThumbnail(final List<Image> images) {
|
||||||
return loadImageDefault(url, R.drawable.placeholder_thumbnail_video, false);
|
return loadImageDefault(choosePreferredImage(images),
|
||||||
|
R.drawable.placeholder_thumbnail_video, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RequestCreator loadBanner(final String url) {
|
public static RequestCreator loadBanner(final List<Image> images) {
|
||||||
return loadImageDefault(url, R.drawable.placeholder_channel_banner);
|
return loadImageDefault(images, R.drawable.placeholder_channel_banner);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static RequestCreator loadPlaylistThumbnail(final List<Image> images) {
|
||||||
|
return loadImageDefault(images, R.drawable.placeholder_thumbnail_playlist);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static RequestCreator loadPlaylistThumbnail(final String url) {
|
public static RequestCreator loadPlaylistThumbnail(final String url) {
|
||||||
|
@ -125,9 +144,10 @@ public final class PicassoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static RequestCreator loadScaledDownThumbnail(final Context context, final String url) {
|
public static RequestCreator loadScaledDownThumbnail(final Context context,
|
||||||
|
final List<Image> images) {
|
||||||
// scale down the notification thumbnail for performance
|
// scale down the notification thumbnail for performance
|
||||||
return PicassoHelper.loadThumbnail(url)
|
return PicassoHelper.loadThumbnail(images)
|
||||||
.transform(new Transformation() {
|
.transform(new Transformation() {
|
||||||
@Override
|
@Override
|
||||||
public Bitmap transform(final Bitmap source) {
|
public Bitmap transform(final Bitmap source) {
|
||||||
|
@ -180,13 +200,20 @@ public final class PicassoHelper {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static RequestCreator loadImageDefault(final String url, final int placeholderResId) {
|
private static RequestCreator loadImageDefault(final List<Image> images,
|
||||||
|
final int placeholderResId) {
|
||||||
|
return loadImageDefault(choosePreferredImage(images), placeholderResId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RequestCreator loadImageDefault(final String url,
|
||||||
|
final int placeholderResId) {
|
||||||
return loadImageDefault(url, placeholderResId, true);
|
return loadImageDefault(url, placeholderResId, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static RequestCreator loadImageDefault(final String url, final int placeholderResId,
|
private static RequestCreator loadImageDefault(@Nullable final String url,
|
||||||
|
final int placeholderResId,
|
||||||
final boolean showPlaceholderWhileLoading) {
|
final boolean showPlaceholderWhileLoading) {
|
||||||
if (!shouldLoadImages || isBlank(url)) {
|
if (isNullOrEmpty(url)) {
|
||||||
return picassoInstance
|
return picassoInstance
|
||||||
.load((String) null)
|
.load((String) null)
|
||||||
.placeholder(placeholderResId) // show placeholder when no image should load
|
.placeholder(placeholderResId) // show placeholder when no image should load
|
||||||
|
@ -201,4 +228,44 @@ public final class PicassoHelper {
|
||||||
return requestCreator;
|
return requestCreator;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public static String choosePreferredImage(final List<Image> images) {
|
||||||
|
if (!shouldLoadImages) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final Comparator<Image> comparator;
|
||||||
|
switch (preferredResolutionLevel) {
|
||||||
|
case HIGH:
|
||||||
|
comparator = Comparator.comparingInt(Image::getHeight).reversed();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
case UNKNOWN:
|
||||||
|
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<Image> urlToImageList(@Nullable final String url) {
|
||||||
|
if (url == null) {
|
||||||
|
return List.of();
|
||||||
|
} else {
|
||||||
|
return List.of(new Image(url, -1, -1, ResolutionLevel.UNKNOWN));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,12 @@ import androidx.core.content.FileProvider;
|
||||||
|
|
||||||
import org.schabi.newpipe.BuildConfig;
|
import org.schabi.newpipe.BuildConfig;
|
||||||
import org.schabi.newpipe.R;
|
import org.schabi.newpipe.R;
|
||||||
|
import org.schabi.newpipe.extractor.Image;
|
||||||
import org.schabi.newpipe.util.PicassoHelper;
|
import org.schabi.newpipe.util.PicassoHelper;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
public final class ShareUtils {
|
public final class ShareUtils {
|
||||||
private static final String TAG = ShareUtils.class.getSimpleName();
|
private static final String TAG = ShareUtils.class.getSimpleName();
|
||||||
|
@ -261,6 +263,29 @@ public final class ShareUtils {
|
||||||
openAppChooser(context, shareIntent, false);
|
openAppChooser(context, shareIntent, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open the android share sheet to share a content.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* For Android 10+ users, a content preview is shown, which includes the title of the shared
|
||||||
|
* content and an image preview the content, if its URL is not null or empty and its
|
||||||
|
* corresponding image is in the image cache.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param context the context to use
|
||||||
|
* @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
|
||||||
|
* 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<Image> images) {
|
||||||
|
shareText(context, title, content, PicassoHelper.choosePreferredImage(images));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open the android share sheet to share a content.
|
* Open the android share sheet to share a content.
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue