Extract Uploader's Avatar on YouTube.
This commit is contained in:
parent
68f1fa994a
commit
b9fad4fcc8
|
@ -79,6 +79,12 @@ public class BandcampRadioInfoItemExtractor implements StreamInfoItemExtractor {
|
|||
return "";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return false;
|
||||
|
|
|
@ -4,6 +4,8 @@ import com.grack.nanojson.JsonObject;
|
|||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampExtractorHelper;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BandcampDiscographStreamInfoItemExtractor extends BandcampStreamInfoItemExtractor {
|
||||
|
||||
private final JsonObject discograph;
|
||||
|
@ -18,6 +20,12 @@ public class BandcampDiscographStreamInfoItemExtractor extends BandcampStreamInf
|
|||
return discograph.getString("band_name");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return discograph.getString("title");
|
||||
|
|
|
@ -8,6 +8,7 @@ import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
|
@ -53,6 +54,12 @@ public class BandcampPlaylistStreamInfoItemExtractor extends BandcampStreamInfoI
|
|||
return "";
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Each track can have its own cover art. Therefore, unless a substitute is provided,
|
||||
* the thumbnail is extracted using a stream extractor.
|
||||
|
|
|
@ -3,6 +3,8 @@ package org.schabi.newpipe.extractor.services.bandcamp.extractors.streaminfoitem
|
|||
import org.jsoup.nodes.Element;
|
||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class BandcampSearchStreamInfoItemExtractor extends BandcampStreamInfoItemExtractor {
|
||||
|
||||
private final Element resultInfo, searchResult;
|
||||
|
@ -24,6 +26,12 @@ public class BandcampSearchStreamInfoItemExtractor extends BandcampStreamInfoIte
|
|||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() throws ParsingException {
|
||||
return resultInfo.getElementsByClass("heading").text();
|
||||
|
|
|
@ -73,6 +73,12 @@ public class MediaCCCLiveStreamKioskExtractor implements StreamInfoItemExtractor
|
|||
return "https://media.ccc.de/c/" + conferenceInfo.getString("slug");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return false;
|
||||
|
|
|
@ -68,6 +68,12 @@ public class MediaCCCRecentKioskExtractor implements StreamInfoItemExtractor {
|
|||
.getUrl(); // web URL
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return false;
|
||||
|
|
|
@ -46,6 +46,12 @@ public class MediaCCCStreamInfoItemExtractor implements StreamInfoItemExtractor
|
|||
return event.getString("conference_url");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return false;
|
||||
|
|
|
@ -9,6 +9,8 @@ import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
|||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||
|
||||
protected final JsonObject item;
|
||||
|
@ -54,6 +56,12 @@ public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor
|
|||
.fromId("accounts/" + name + "@" + host, baseUrl).getUrl();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return false;
|
||||
|
|
|
@ -7,6 +7,8 @@ import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudParsingHelper;
|
|||
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.EMPTY_STRING;
|
||||
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
||||
|
||||
|
@ -43,6 +45,12 @@ public class SoundcloudStreamInfoItemExtractor implements StreamInfoItemExtracto
|
|||
return replaceHttpWithHttps(itemObject.getObject("user").getString("permalink_url"));
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return itemObject.getObject("user").getBoolean("verified");
|
||||
|
|
|
@ -50,6 +50,12 @@ public class YoutubeFeedInfoItemExtractor implements StreamInfoItemExtractor {
|
|||
return entryElement.select("author > uri").first().text();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return false;
|
||||
|
|
|
@ -9,6 +9,7 @@ import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
|||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||
import org.schabi.newpipe.extractor.utils.Utils;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -40,7 +41,7 @@ import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
|||
*/
|
||||
|
||||
public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||
private JsonObject videoInfo;
|
||||
private final JsonObject videoInfo;
|
||||
private final TimeAgoParser timeAgoParser;
|
||||
private StreamType cachedStreamType;
|
||||
|
||||
|
@ -162,6 +163,17 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
|||
return url;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public String getUploaderAvatarUrl() throws ParsingException {
|
||||
|
||||
if(videoInfo.has("channelThumbnailSupportedRenderers")) {
|
||||
return JsonUtils.getArray(videoInfo, "channelThumbnailSupportedRenderers.channelThumbnailWithLinkRenderer.thumbnail.thumbnails").getObject(0).getString("url");
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUploaderVerified() throws ParsingException {
|
||||
return YoutubeParsingHelper.isVerified(videoInfo.getArray("ownerBadges"));
|
||||
|
|
|
@ -39,6 +39,7 @@ public class StreamInfoItem extends InfoItem {
|
|||
private long duration = -1;
|
||||
|
||||
private String uploaderUrl = null;
|
||||
private String uploaderAvatarUrl = null;
|
||||
private boolean uploaderVerified = false;
|
||||
|
||||
public StreamInfoItem(int serviceId, String url, String name, StreamType streamType) {
|
||||
|
@ -82,6 +83,15 @@ public class StreamInfoItem extends InfoItem {
|
|||
this.uploaderUrl = uploaderUrl;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getUploaderAvatarUrl() {
|
||||
return uploaderAvatarUrl;
|
||||
}
|
||||
|
||||
public void setUploaderAvatarUrl(String uploaderAvatarUrl) {
|
||||
this.uploaderAvatarUrl = uploaderAvatarUrl;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public String getTextualUploadDate() {
|
||||
return textualUploadDate;
|
||||
|
|
|
@ -71,6 +71,15 @@ public interface StreamInfoItemExtractor extends InfoItemExtractor {
|
|||
|
||||
String getUploaderUrl() throws ParsingException;
|
||||
|
||||
/**
|
||||
* Get the uploader's avatar
|
||||
*
|
||||
* @return The uploader's avatar url or {@code null} if not provided by the service.
|
||||
* @throws ParsingException if there is an error in the extraction
|
||||
*/
|
||||
@Nullable
|
||||
String getUploaderAvatarUrl() throws ParsingException;
|
||||
|
||||
/**
|
||||
* Whether the uploader has been verified by the service's provider.
|
||||
* If there is no verification implemented, return <code>false</code>.
|
||||
|
|
|
@ -91,6 +91,11 @@ public class StreamInfoItemsCollector extends InfoItemsCollector<StreamInfoItem,
|
|||
} catch (Exception e) {
|
||||
addError(e);
|
||||
}
|
||||
try {
|
||||
resultItem.setUploaderAvatarUrl(extractor.getUploaderAvatarUrl());
|
||||
} catch (Exception e) {
|
||||
addError(e);
|
||||
}
|
||||
try {
|
||||
resultItem.setUploaderVerified(extractor.isUploaderVerified());
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -1,24 +1,18 @@
|
|||
package org.schabi.newpipe.extractor.services.youtube.search;
|
||||
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Ignore;
|
||||
import org.junit.Test;
|
||||
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||
import org.schabi.newpipe.extractor.InfoItem;
|
||||
import org.schabi.newpipe.extractor.ListExtractor;
|
||||
import org.schabi.newpipe.extractor.MetaInfo;
|
||||
import org.schabi.newpipe.extractor.NewPipe;
|
||||
import org.schabi.newpipe.extractor.StreamingService;
|
||||
import org.schabi.newpipe.extractor.*;
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||
import org.schabi.newpipe.extractor.services.DefaultSearchExtractorTest;
|
||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||
import org.schabi.newpipe.extractor.stream.Description;
|
||||
|
||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.MalformedURLException;
|
||||
import java.net.URL;
|
||||
|
@ -29,14 +23,11 @@ import java.util.Random;
|
|||
|
||||
import static java.util.Collections.singletonList;
|
||||
import static junit.framework.TestCase.assertFalse;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertEmptyErrors;
|
||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoDuplicatedItems;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.CHANNELS;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.PLAYLISTS;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.VIDEOS;
|
||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.*;
|
||||
|
||||
public class YoutubeSearchExtractorTest {
|
||||
|
||||
|
@ -320,4 +311,36 @@ public class YoutubeSearchExtractorTest {
|
|||
assertTrue(verified);
|
||||
}
|
||||
}
|
||||
|
||||
public static class VideoUploaderAvatar extends DefaultSearchExtractorTest {
|
||||
private static SearchExtractor extractor;
|
||||
private static final String QUERY = "sidemen";
|
||||
|
||||
@BeforeClass
|
||||
public static void setUp() throws Exception {
|
||||
YoutubeParsingHelper.resetClientVersionAndKey();
|
||||
YoutubeParsingHelper.setNumberGenerator(new Random(1));
|
||||
NewPipe.init(new DownloaderFactory().getDownloader(RESOURCE_PATH + "video_uploader_avatar"));
|
||||
extractor = YouTube.getSearchExtractor(QUERY, singletonList(VIDEOS), "");
|
||||
extractor.fetchPage();
|
||||
}
|
||||
|
||||
@Override public SearchExtractor extractor() { return extractor; }
|
||||
@Override public StreamingService expectedService() { return YouTube; }
|
||||
@Override public String expectedName() { return QUERY; }
|
||||
@Override public String expectedId() { return QUERY; }
|
||||
@Override public String expectedUrlContains() { return "youtube.com/results?search_query=" + QUERY; }
|
||||
@Override public String expectedOriginalUrlContains() { return "youtube.com/results?search_query=" + QUERY; }
|
||||
@Override public String expectedSearchString() { return QUERY; }
|
||||
@Nullable @Override public String expectedSearchSuggestion() { return null; }
|
||||
@Override public InfoItem.InfoType expectedInfoItemType() { return InfoItem.InfoType.STREAM; }
|
||||
|
||||
@Test
|
||||
public void testUploaderAvatar() throws IOException, ExtractionException {
|
||||
final List<InfoItem> items = extractor.getInitialPage().getItems();
|
||||
for (InfoItem item : items) {
|
||||
assertNotNull(((StreamInfoItem) item).getUploaderAvatarUrl());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue