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 "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -4,6 +4,8 @@ import com.grack.nanojson.JsonObject;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampExtractorHelper;
|
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampExtractorHelper;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class BandcampDiscographStreamInfoItemExtractor extends BandcampStreamInfoItemExtractor {
|
public class BandcampDiscographStreamInfoItemExtractor extends BandcampStreamInfoItemExtractor {
|
||||||
|
|
||||||
private final JsonObject discograph;
|
private final JsonObject discograph;
|
||||||
|
@ -18,6 +20,12 @@ public class BandcampDiscographStreamInfoItemExtractor extends BandcampStreamInf
|
||||||
return discograph.getString("band_name");
|
return discograph.getString("band_name");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return discograph.getString("title");
|
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.exceptions.ParsingException;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamExtractor;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,6 +54,12 @@ public class BandcampPlaylistStreamInfoItemExtractor extends BandcampStreamInfoI
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each track can have its own cover art. Therefore, unless a substitute is provided,
|
* Each track can have its own cover art. Therefore, unless a substitute is provided,
|
||||||
* the thumbnail is extracted using a stream extractor.
|
* 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.jsoup.nodes.Element;
|
||||||
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
import org.schabi.newpipe.extractor.exceptions.ParsingException;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class BandcampSearchStreamInfoItemExtractor extends BandcampStreamInfoItemExtractor {
|
public class BandcampSearchStreamInfoItemExtractor extends BandcampStreamInfoItemExtractor {
|
||||||
|
|
||||||
private final Element resultInfo, searchResult;
|
private final Element resultInfo, searchResult;
|
||||||
|
@ -24,6 +26,12 @@ public class BandcampSearchStreamInfoItemExtractor extends BandcampStreamInfoIte
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() throws ParsingException {
|
public String getName() throws ParsingException {
|
||||||
return resultInfo.getElementsByClass("heading").text();
|
return resultInfo.getElementsByClass("heading").text();
|
||||||
|
|
|
@ -73,6 +73,12 @@ public class MediaCCCLiveStreamKioskExtractor implements StreamInfoItemExtractor
|
||||||
return "https://media.ccc.de/c/" + conferenceInfo.getString("slug");
|
return "https://media.ccc.de/c/" + conferenceInfo.getString("slug");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -68,6 +68,12 @@ public class MediaCCCRecentKioskExtractor implements StreamInfoItemExtractor {
|
||||||
.getUrl(); // web URL
|
.getUrl(); // web URL
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -46,6 +46,12 @@ public class MediaCCCStreamInfoItemExtractor implements StreamInfoItemExtractor
|
||||||
return event.getString("conference_url");
|
return event.getString("conference_url");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return false;
|
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.stream.StreamType;
|
||||||
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||||
|
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
|
|
||||||
protected final JsonObject item;
|
protected final JsonObject item;
|
||||||
|
@ -54,6 +56,12 @@ public class PeertubeStreamInfoItemExtractor implements StreamInfoItemExtractor
|
||||||
.fromId("accounts/" + name + "@" + host, baseUrl).getUrl();
|
.fromId("accounts/" + name + "@" + host, baseUrl).getUrl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return false;
|
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.StreamInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
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.EMPTY_STRING;
|
||||||
import static org.schabi.newpipe.extractor.utils.Utils.replaceHttpWithHttps;
|
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"));
|
return replaceHttpWithHttps(itemObject.getObject("user").getString("permalink_url"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return itemObject.getObject("user").getBoolean("verified");
|
return itemObject.getObject("user").getBoolean("verified");
|
||||||
|
|
|
@ -50,6 +50,12 @@ public class YoutubeFeedInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
return entryElement.select("author > uri").first().text();
|
return entryElement.select("author > uri").first().text();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
public String getUploaderAvatarUrl() throws ParsingException {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return false;
|
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.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
import org.schabi.newpipe.extractor.stream.StreamInfoItemExtractor;
|
||||||
import org.schabi.newpipe.extractor.stream.StreamType;
|
import org.schabi.newpipe.extractor.stream.StreamType;
|
||||||
|
import org.schabi.newpipe.extractor.utils.JsonUtils;
|
||||||
import org.schabi.newpipe.extractor.utils.Utils;
|
import org.schabi.newpipe.extractor.utils.Utils;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -40,7 +41,7 @@ import static org.schabi.newpipe.extractor.utils.Utils.isNullOrEmpty;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
private JsonObject videoInfo;
|
private final JsonObject videoInfo;
|
||||||
private final TimeAgoParser timeAgoParser;
|
private final TimeAgoParser timeAgoParser;
|
||||||
private StreamType cachedStreamType;
|
private StreamType cachedStreamType;
|
||||||
|
|
||||||
|
@ -162,6 +163,17 @@ public class YoutubeStreamInfoItemExtractor implements StreamInfoItemExtractor {
|
||||||
return url;
|
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
|
@Override
|
||||||
public boolean isUploaderVerified() throws ParsingException {
|
public boolean isUploaderVerified() throws ParsingException {
|
||||||
return YoutubeParsingHelper.isVerified(videoInfo.getArray("ownerBadges"));
|
return YoutubeParsingHelper.isVerified(videoInfo.getArray("ownerBadges"));
|
||||||
|
|
|
@ -39,6 +39,7 @@ public class StreamInfoItem extends InfoItem {
|
||||||
private long duration = -1;
|
private long duration = -1;
|
||||||
|
|
||||||
private String uploaderUrl = null;
|
private String uploaderUrl = null;
|
||||||
|
private String uploaderAvatarUrl = null;
|
||||||
private boolean uploaderVerified = false;
|
private boolean uploaderVerified = false;
|
||||||
|
|
||||||
public StreamInfoItem(int serviceId, String url, String name, StreamType streamType) {
|
public StreamInfoItem(int serviceId, String url, String name, StreamType streamType) {
|
||||||
|
@ -82,6 +83,15 @@ public class StreamInfoItem extends InfoItem {
|
||||||
this.uploaderUrl = uploaderUrl;
|
this.uploaderUrl = uploaderUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
public String getUploaderAvatarUrl() {
|
||||||
|
return uploaderAvatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setUploaderAvatarUrl(String uploaderAvatarUrl) {
|
||||||
|
this.uploaderAvatarUrl = uploaderAvatarUrl;
|
||||||
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
public String getTextualUploadDate() {
|
public String getTextualUploadDate() {
|
||||||
return textualUploadDate;
|
return textualUploadDate;
|
||||||
|
|
|
@ -71,6 +71,15 @@ public interface StreamInfoItemExtractor extends InfoItemExtractor {
|
||||||
|
|
||||||
String getUploaderUrl() throws ParsingException;
|
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.
|
* Whether the uploader has been verified by the service's provider.
|
||||||
* If there is no verification implemented, return <code>false</code>.
|
* If there is no verification implemented, return <code>false</code>.
|
||||||
|
|
|
@ -91,6 +91,11 @@ public class StreamInfoItemsCollector extends InfoItemsCollector<StreamInfoItem,
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
addError(e);
|
addError(e);
|
||||||
}
|
}
|
||||||
|
try {
|
||||||
|
resultItem.setUploaderAvatarUrl(extractor.getUploaderAvatarUrl());
|
||||||
|
} catch (Exception e) {
|
||||||
|
addError(e);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
resultItem.setUploaderVerified(extractor.isUploaderVerified());
|
resultItem.setUploaderVerified(extractor.isUploaderVerified());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|
|
@ -1,24 +1,18 @@
|
||||||
package org.schabi.newpipe.extractor.services.youtube.search;
|
package org.schabi.newpipe.extractor.services.youtube.search;
|
||||||
|
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
import org.junit.Ignore;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.schabi.newpipe.downloader.DownloaderFactory;
|
import org.schabi.newpipe.downloader.DownloaderFactory;
|
||||||
import org.schabi.newpipe.extractor.InfoItem;
|
import org.schabi.newpipe.extractor.*;
|
||||||
import org.schabi.newpipe.extractor.ListExtractor;
|
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
||||||
import org.schabi.newpipe.extractor.MetaInfo;
|
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
||||||
import org.schabi.newpipe.extractor.NewPipe;
|
|
||||||
import org.schabi.newpipe.extractor.StreamingService;
|
|
||||||
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
import org.schabi.newpipe.extractor.search.SearchExtractor;
|
||||||
import org.schabi.newpipe.extractor.services.DefaultSearchExtractorTest;
|
import org.schabi.newpipe.extractor.services.DefaultSearchExtractorTest;
|
||||||
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
import org.schabi.newpipe.extractor.services.youtube.YoutubeParsingHelper;
|
||||||
import org.schabi.newpipe.extractor.stream.Description;
|
import org.schabi.newpipe.extractor.stream.Description;
|
||||||
|
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
|
||||||
import org.schabi.newpipe.extractor.channel.ChannelInfoItem;
|
|
||||||
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.MalformedURLException;
|
import java.net.MalformedURLException;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
|
@ -29,14 +23,11 @@ import java.util.Random;
|
||||||
|
|
||||||
import static java.util.Collections.singletonList;
|
import static java.util.Collections.singletonList;
|
||||||
import static junit.framework.TestCase.assertFalse;
|
import static junit.framework.TestCase.assertFalse;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertEmptyErrors;
|
import static org.schabi.newpipe.extractor.ExtractorAsserts.assertEmptyErrors;
|
||||||
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
import static org.schabi.newpipe.extractor.ServiceList.YouTube;
|
||||||
import static org.schabi.newpipe.extractor.services.DefaultTests.assertNoDuplicatedItems;
|
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.*;
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.PLAYLISTS;
|
|
||||||
import static org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeSearchQueryHandlerFactory.VIDEOS;
|
|
||||||
|
|
||||||
public class YoutubeSearchExtractorTest {
|
public class YoutubeSearchExtractorTest {
|
||||||
|
|
||||||
|
@ -320,4 +311,36 @@ public class YoutubeSearchExtractorTest {
|
||||||
assertTrue(verified);
|
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