Skip to content

Commit 6f7d1f0

Browse files
AudricVTheta-DevStypox
committed
[Bandcamp] Add tabs support for artists
Support of tracks and albums has been added for artists. Also use the singleton pattern and add the declaration of the UnsupportedOperationException exception to the service's LinkHandlers and improved some code in the files changed. Co-authored-by: ThetaDev <t.testboy@gmail.com> Co-authored-by: Stypox <stypox@pm.me>
1 parent 1e8474b commit 6f7d1f0

11 files changed

Lines changed: 404 additions & 63 deletions

extractor/src/main/java/org/schabi/newpipe/extractor/services/bandcamp/BandcampService.java

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,18 +12,21 @@
1212

1313
import org.schabi.newpipe.extractor.StreamingService;
1414
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
15+
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
1516
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
1617
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
1718
import org.schabi.newpipe.extractor.kiosk.KioskList;
1819
import org.schabi.newpipe.extractor.linkhandler.LinkHandler;
1920
import org.schabi.newpipe.extractor.linkhandler.LinkHandlerFactory;
2021
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
2122
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandlerFactory;
23+
import org.schabi.newpipe.extractor.linkhandler.ReadyChannelTabListLinkHandler;
2224
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandler;
2325
import org.schabi.newpipe.extractor.linkhandler.SearchQueryHandlerFactory;
2426
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
2527
import org.schabi.newpipe.extractor.search.SearchExtractor;
2628
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampChannelExtractor;
29+
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampChannelTabExtractor;
2730
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampCommentsExtractor;
2831
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampExtractorHelper;
2932
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampFeaturedExtractor;
@@ -34,6 +37,7 @@
3437
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampStreamExtractor;
3538
import org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampSuggestionExtractor;
3639
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampChannelLinkHandlerFactory;
40+
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampChannelTabLinkHandlerFactory;
3741
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampCommentsLinkHandlerFactory;
3842
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampFeaturedLinkHandlerFactory;
3943
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampPlaylistLinkHandlerFactory;
@@ -58,27 +62,32 @@ public String getBaseUrl() {
5862

5963
@Override
6064
public LinkHandlerFactory getStreamLHFactory() {
61-
return new BandcampStreamLinkHandlerFactory();
65+
return BandcampStreamLinkHandlerFactory.getInstance();
6266
}
6367

6468
@Override
6569
public ListLinkHandlerFactory getChannelLHFactory() {
66-
return new BandcampChannelLinkHandlerFactory();
70+
return BandcampChannelLinkHandlerFactory.getInstance();
71+
}
72+
73+
@Override
74+
public ListLinkHandlerFactory getChannelTabLHFactory() {
75+
return BandcampChannelTabLinkHandlerFactory.getInstance();
6776
}
6877

6978
@Override
7079
public ListLinkHandlerFactory getPlaylistLHFactory() {
71-
return new BandcampPlaylistLinkHandlerFactory();
80+
return BandcampPlaylistLinkHandlerFactory.getInstance();
7281
}
7382

7483
@Override
7584
public SearchQueryHandlerFactory getSearchQHFactory() {
76-
return new BandcampSearchQueryHandlerFactory();
85+
return BandcampSearchQueryHandlerFactory.getInstance();
7786
}
7887

7988
@Override
8089
public ListLinkHandlerFactory getCommentsLHFactory() {
81-
return new BandcampCommentsLinkHandlerFactory();
90+
return BandcampCommentsLinkHandlerFactory.getInstance();
8291
}
8392

8493
@Override
@@ -98,27 +107,27 @@ public SubscriptionExtractor getSubscriptionExtractor() {
98107

99108
@Override
100109
public KioskList getKioskList() throws ExtractionException {
101-
102110
final KioskList kioskList = new KioskList(this);
111+
final ListLinkHandlerFactory h = BandcampFeaturedLinkHandlerFactory.getInstance();
103112

104113
try {
105114
kioskList.addKioskEntry(
106115
(streamingService, url, kioskId) -> new BandcampFeaturedExtractor(
107116
BandcampService.this,
108-
new BandcampFeaturedLinkHandlerFactory().fromUrl(FEATURED_API_URL),
117+
h.fromUrl(FEATURED_API_URL),
109118
kioskId
110119
),
111-
new BandcampFeaturedLinkHandlerFactory(),
120+
h,
112121
KIOSK_FEATURED
113122
);
114123

115124
kioskList.addKioskEntry(
116125
(streamingService, url, kioskId) -> new BandcampRadioExtractor(
117126
BandcampService.this,
118-
new BandcampFeaturedLinkHandlerFactory().fromUrl(RADIO_API_URL),
127+
h.fromUrl(RADIO_API_URL),
119128
kioskId
120129
),
121-
new BandcampFeaturedLinkHandlerFactory(),
130+
h,
122131
KIOSK_RADIO
123132
);
124133

@@ -136,6 +145,15 @@ public ChannelExtractor getChannelExtractor(final ListLinkHandler linkHandler) {
136145
return new BandcampChannelExtractor(this, linkHandler);
137146
}
138147

148+
@Override
149+
public ChannelTabExtractor getChannelTabExtractor(final ListLinkHandler linkHandler) {
150+
if (linkHandler instanceof ReadyChannelTabListLinkHandler) {
151+
return ((ReadyChannelTabListLinkHandler) linkHandler).getChannelTabExtractor(this);
152+
} else {
153+
return new BandcampChannelTabExtractor(this, linkHandler);
154+
}
155+
}
156+
139157
@Override
140158
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) {
141159
return new BandcampPlaylistExtractor(this, linkHandler);
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package org.schabi.newpipe.extractor.services.bandcamp.extractors;
2+
3+
import com.grack.nanojson.JsonObject;
4+
import org.schabi.newpipe.extractor.ListExtractor;
5+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
6+
import org.schabi.newpipe.extractor.playlist.PlaylistInfoItemExtractor;
7+
8+
public class BandcampAlbumInfoItemExtractor implements PlaylistInfoItemExtractor {
9+
private final JsonObject albumInfoItem;
10+
private final String uploaderUrl;
11+
12+
public BandcampAlbumInfoItemExtractor(final JsonObject albumInfoItem,
13+
final String uploaderUrl) {
14+
this.albumInfoItem = albumInfoItem;
15+
this.uploaderUrl = uploaderUrl;
16+
}
17+
18+
@Override
19+
public String getName() throws ParsingException {
20+
return albumInfoItem.getString("title");
21+
}
22+
23+
@Override
24+
public String getUrl() throws ParsingException {
25+
return BandcampExtractorHelper.getStreamUrlFromIds(
26+
albumInfoItem.getLong("band_id"),
27+
albumInfoItem.getLong("item_id"),
28+
albumInfoItem.getString("item_type"));
29+
}
30+
31+
@Override
32+
public String getThumbnailUrl() throws ParsingException {
33+
return BandcampExtractorHelper.getImageUrl(albumInfoItem.getLong("art_id"), true);
34+
}
35+
36+
@Override
37+
public String getUploaderName() throws ParsingException {
38+
return albumInfoItem.getString("band_name");
39+
}
40+
41+
@Override
42+
public String getUploaderUrl() {
43+
return uploaderUrl;
44+
}
45+
46+
@Override
47+
public boolean isUploaderVerified() {
48+
return false;
49+
}
50+
51+
@Override
52+
public long getStreamCount() {
53+
return ListExtractor.ITEM_COUNT_UNKNOWN;
54+
}
55+
}

extractor/src/main/java/org/schabi/newpipe/extractor/services/bandcamp/extractors/BandcampChannelExtractor.java

Lines changed: 57 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,19 +8,22 @@
88
import com.grack.nanojson.JsonObject;
99

1010
import org.jsoup.Jsoup;
11-
import org.schabi.newpipe.extractor.Page;
1211
import org.schabi.newpipe.extractor.StreamingService;
1312
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
13+
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
1414
import org.schabi.newpipe.extractor.downloader.Downloader;
1515
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
1616
import org.schabi.newpipe.extractor.exceptions.ParsingException;
1717
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
18+
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
1819
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
19-
import org.schabi.newpipe.extractor.services.bandcamp.extractors.streaminfoitem.BandcampDiscographStreamInfoItemExtractor;
20-
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
21-
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;
20+
import org.schabi.newpipe.extractor.linkhandler.ReadyChannelTabListLinkHandler;
21+
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.BandcampChannelTabLinkHandlerFactory;
2222

2323
import java.io.IOException;
24+
import java.util.ArrayList;
25+
import java.util.Collections;
26+
import java.util.List;
2427
import java.util.Objects;
2528
import java.util.stream.Stream;
2629

@@ -52,8 +55,8 @@ public String getBannerUrl() throws ParsingException {
5255
*/
5356
try {
5457
final String html = getDownloader()
55-
.get(replaceHttpWithHttps(channelInfo.getString("bandcamp_url")))
56-
.responseBody();
58+
.get(replaceHttpWithHttps(channelInfo.getString("bandcamp_url")))
59+
.responseBody();
5760

5861
return Stream.of(Jsoup.parse(html).getElementById("customHeader"))
5962
.filter(Objects::nonNull)
@@ -107,29 +110,47 @@ public boolean isVerified() throws ParsingException {
107110

108111
@Nonnull
109112
@Override
110-
public InfoItemsPage<StreamInfoItem> getInitialPage() throws ParsingException {
113+
public List<ListLinkHandler> getTabs() throws ParsingException {
114+
final JsonArray discography = channelInfo.getArray("discography");
115+
final TabExtractorBuilder builder = new TabExtractorBuilder(discography);
111116

112-
final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());
117+
final List<ListLinkHandler> tabs = new ArrayList<>();
113118

114-
final JsonArray discography = channelInfo.getArray("discography");
119+
boolean foundTrackItem = false;
120+
boolean foundAlbumItem = false;
115121

116-
for (int i = 0; i < discography.size(); i++) {
117-
// A discograph is as an item appears in a discography
118-
final JsonObject discograph = discography.getObject(i);
122+
for (final Object discographyItem : discography) {
123+
if (foundTrackItem && foundAlbumItem) {
124+
break;
125+
}
119126

120-
if (!discograph.getString("item_type").equals("track")) {
127+
if (!(discographyItem instanceof JsonObject)) {
121128
continue;
122129
}
123130

124-
collector.commit(new BandcampDiscographStreamInfoItemExtractor(discograph, getUrl()));
125-
}
131+
final JsonObject discographyJsonItem = (JsonObject) discographyItem;
132+
final String itemType = discographyJsonItem.getString("item_type");
126133

127-
return new InfoItemsPage<>(collector, null);
128-
}
134+
if (!foundTrackItem && "track".equals(itemType)) {
135+
foundTrackItem = true;
136+
tabs.add(new ReadyChannelTabListLinkHandler(getUrl()
137+
+ BandcampChannelTabLinkHandlerFactory.getUrlSuffix(ChannelTabs.TRACKS),
138+
getId(),
139+
ChannelTabs.TRACKS,
140+
builder));
141+
}
129142

130-
@Override
131-
public InfoItemsPage<StreamInfoItem> getPage(final Page page) {
132-
return null;
143+
if (!foundAlbumItem && "album".equals(itemType)) {
144+
foundAlbumItem = true;
145+
tabs.add(new ReadyChannelTabListLinkHandler(getUrl()
146+
+ BandcampChannelTabLinkHandlerFactory.getUrlSuffix(ChannelTabs.ALBUMS),
147+
getId(),
148+
ChannelTabs.ALBUMS,
149+
builder));
150+
}
151+
}
152+
153+
return Collections.unmodifiableList(tabs);
133154
}
134155

135156
@Override
@@ -143,4 +164,20 @@ public void onFetchPage(@Nonnull final Downloader downloader)
143164
public String getName() {
144165
return channelInfo.getString("name");
145166
}
167+
168+
private static final class TabExtractorBuilder
169+
implements ReadyChannelTabListLinkHandler.ChannelTabExtractorBuilder {
170+
private final JsonArray discography;
171+
172+
TabExtractorBuilder(final JsonArray discography) {
173+
this.discography = discography;
174+
}
175+
176+
@Nonnull
177+
@Override
178+
public ChannelTabExtractor build(@Nonnull final StreamingService service,
179+
@Nonnull final ListLinkHandler linkHandler) {
180+
return BandcampChannelTabExtractor.fromDiscography(service, linkHandler, discography);
181+
}
182+
}
146183
}
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
package org.schabi.newpipe.extractor.services.bandcamp.extractors;
2+
3+
import com.grack.nanojson.JsonArray;
4+
import com.grack.nanojson.JsonObject;
5+
import org.schabi.newpipe.extractor.InfoItem;
6+
import org.schabi.newpipe.extractor.MultiInfoItemsCollector;
7+
import org.schabi.newpipe.extractor.Page;
8+
import org.schabi.newpipe.extractor.StreamingService;
9+
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabExtractor;
10+
import org.schabi.newpipe.extractor.channel.tabs.ChannelTabs;
11+
import org.schabi.newpipe.extractor.downloader.Downloader;
12+
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
13+
import org.schabi.newpipe.extractor.exceptions.ParsingException;
14+
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
15+
import org.schabi.newpipe.extractor.services.bandcamp.extractors.streaminfoitem.BandcampDiscographStreamInfoItemExtractor;
16+
17+
import javax.annotation.Nonnull;
18+
import java.io.IOException;
19+
20+
public class BandcampChannelTabExtractor extends ChannelTabExtractor {
21+
private JsonArray discography;
22+
private final String filter;
23+
24+
public BandcampChannelTabExtractor(final StreamingService service,
25+
final ListLinkHandler linkHandler) {
26+
super(service, linkHandler);
27+
28+
final String tab = linkHandler.getContentFilters().get(0);
29+
switch (tab) {
30+
case ChannelTabs.TRACKS:
31+
filter = "track";
32+
break;
33+
case ChannelTabs.ALBUMS:
34+
filter = "album";
35+
break;
36+
default:
37+
throw new IllegalArgumentException("Unsupported channel tab: " + tab);
38+
}
39+
}
40+
41+
public static BandcampChannelTabExtractor fromDiscography(final StreamingService service,
42+
final ListLinkHandler linkHandler,
43+
final JsonArray discography) {
44+
final BandcampChannelTabExtractor tabExtractor =
45+
new BandcampChannelTabExtractor(service, linkHandler);
46+
tabExtractor.discography = discography;
47+
return tabExtractor;
48+
}
49+
50+
@Override
51+
public void onFetchPage(@Nonnull final Downloader downloader) throws ParsingException {
52+
if (discography == null) {
53+
discography = BandcampExtractorHelper.getArtistDetails(getId())
54+
.getArray("discography");
55+
}
56+
}
57+
58+
@Nonnull
59+
@Override
60+
public InfoItemsPage<InfoItem> getInitialPage() throws IOException, ExtractionException {
61+
final MultiInfoItemsCollector collector = new MultiInfoItemsCollector(getServiceId());
62+
63+
for (final Object discograph : discography) {
64+
// A discograph is as an item appears in a discography
65+
if (!(discograph instanceof JsonObject)) {
66+
continue;
67+
}
68+
69+
final JsonObject discographJsonObject = (JsonObject) discograph;
70+
final String itemType = discographJsonObject.getString("item_type", "");
71+
72+
if (!itemType.equals(filter)) {
73+
continue;
74+
}
75+
76+
switch (itemType) {
77+
case "track":
78+
collector.commit(new BandcampDiscographStreamInfoItemExtractor(
79+
discographJsonObject, getUrl()));
80+
break;
81+
case "album":
82+
collector.commit(new BandcampAlbumInfoItemExtractor(
83+
discographJsonObject, getUrl()));
84+
break;
85+
}
86+
}
87+
88+
return new InfoItemsPage<>(collector, null);
89+
}
90+
91+
@Override
92+
public InfoItemsPage<InfoItem> getPage(final Page page) {
93+
return null;
94+
}
95+
}

0 commit comments

Comments
 (0)