Skip to content
Merged
Show file tree
Hide file tree
Changes from 86 commits
Commits
Show all changes
104 commits
Select commit Hold shift + click to select a range
a579337
Bandcamp service with support for streams and searches
fynngodau Dec 21, 2019
43dc3c3
Return empty kiosk list instead of null
fynngodau Dec 21, 2019
80d67e2
Return mp3-128 audio stream [experimental]
fynngodau Dec 21, 2019
c3d127c
Bandcamp audio stream test and fix
fynngodau Dec 21, 2019
5281456
Bandcamp channel link handler factory
fynngodau Dec 21, 2019
a42c774
Bandcamp channel extractor (ignoring everything but tracks)
fynngodau Dec 21, 2019
7730eb2
Bandcamp channel extractor: enforce https when getting banner url
fynngodau Dec 21, 2019
d5cdc20
Bandcmap channel extractor: fix getting banner url
fynngodau Dec 22, 2019
91c0ec7
Bandcamp stream extractor: catch NullPointerException
fynngodau Dec 22, 2019
794ca5e
Bandcamp channel extractor: handel nonexistent images better
fynngodau Dec 22, 2019
d05b14a
Add channels (artists) to search results
fynngodau Dec 22, 2019
ba700bf
Add bandcamp playlists (albums)
fynngodau Dec 22, 2019
655df35
Various improvements concerning bandcamp playlists
fynngodau Dec 22, 2019
e12ddae
Bandcamp playlist and search extractors: better and more tests
fynngodau Dec 22, 2019
ce2a88e
Add bandcamp search suggestion extractor
fynngodau Dec 22, 2019
9b16baf
Bandcamp search: multiple pages
fynngodau Dec 22, 2019
13e4908
Bandcamp search extractor: read track count from result page
fynngodau Dec 22, 2019
db02850
Bandcamp playlist extractor: support playlists with just one stream
fynngodau Dec 22, 2019
13ef11e
Bandcamp featured kiosk
fynngodau Dec 22, 2019
808c8aa
Add bandcamp weekly kiosk
fynngodau Dec 22, 2019
f0d36df
Bandcamp radio: proper name, date shortened
fynngodau Dec 22, 2019
46e1f39
Refuse to load bandcamp playlists without content
fynngodau Jan 3, 2020
ba967f1
Workaround enourmous load times for long bandcamp playlists
fynngodau Jan 3, 2020
7b5702b
Add bandcamp to list of supported services in README
fynngodau Jan 11, 2020
623e6a8
Merge branch 'dev' into dev
fynngodau Jan 17, 2020
36a316e
Merge branch 'dev' into dev
fynngodau Feb 8, 2020
b78f788
Merge branch 'dev' into dev
fynngodau Mar 17, 2020
a1523eb
Update Bandcamp service to latest interface changes
fynngodau Mar 17, 2020
5c0a033
Merge 'origin/dev' into dev
fynngodau Apr 19, 2020
9c23937
Change nanojson dependency to @wb9688's fork
fynngodau Apr 19, 2020
b100b98
Bandcmap: Use nanojson fork instead of org.json
fynngodau Mar 19, 2020
c133190
Bandcamp capitalization
fynngodau Apr 20, 2020
67de028
Bandcamp: Generate query JSON in a proper way
fynngodau Apr 20, 2020
433d72c
Depend on nanojson fork in timeago-parser
fynngodau Apr 20, 2020
00c0333
Bandcamp: Fetch channelInfo in onFetchPage
fynngodau Apr 20, 2020
8209959
Bandcamp: Move code from SearchExtractor to InfoItemExtractors
fynngodau Apr 20, 2020
965bce0
Bandcamp stream extractor: return NO_AGE_LIMIT
fynngodau Apr 20, 2020
9201e0d
Don't declare exceptions that can't actually be thrown
fynngodau Apr 20, 2020
10ae3db
Bandcamp javadoc: Replace br tags with p tags
fynngodau Apr 20, 2020
8c70dab
Bandcamp search query handler factory: inline variable
fynngodau Apr 20, 2020
b5e251c
Bandcamp channel extractor: package-private access for getImageUrl(…)
fynngodau Apr 20, 2020
5009d9f
Bandcamp tests: remove certain tests
fynngodau Apr 20, 2020
f71bd29
Bandcamp playlist extractor: add more tests
fynngodau Apr 20, 2020
9bc7a47
Replace fori with foreach loop
fynngodau Apr 26, 2020
a3e8e1c
Bandcamp: move own methods to helper class
fynngodau Apr 26, 2020
e7b046d
Merge remote-tracking branch 'origin/dev' into dev
fynngodau Apr 26, 2020
fff21ca
Fix Bandcamp no avatar test
fynngodau May 25, 2020
692b2d0
Bandcamp: read info item data in place and not in advance
fynngodau May 25, 2020
e08256e
Remove "url cleanup" in Bandcamp link handlers
fynngodau May 25, 2020
89b0639
New Bandcamp tests for channel extractor
fynngodau May 25, 2020
dd955c7
Merge branch 'origin/dev' into dev
fynngodau Jun 3, 2020
9fa9d92
Bandcamp: Implement new methods required due to interface changes
fynngodau Jun 3, 2020
3940138
Fix Bandcamp capitalization in one more spot
fynngodau Jun 3, 2020
de77656
Bandcamp: fix loading uploader from streams in search
fynngodau Jun 4, 2020
8f6c00f
Use default test in BandcampSearchExtractorTest
fynngodau Jun 4, 2020
e98bff8
Improved Bandcamp radio stream extractor tests
fynngodau Jun 4, 2020
6822fe3
Bandcamp: Get Stream upload date
fynngodau Jun 4, 2020
1be20ce
Bandcamp: parse date
fynngodau Jun 4, 2020
34b6928
Don't print stacktrace before throwing new exception
fynngodau Jun 4, 2020
ea49202
Don't display internal license id
fynngodau Jun 4, 2020
27e7aad
Bandcamp: Improve code style
fynngodau Jun 4, 2020
e6ecd91
Bandcamp: Test full date
fynngodau Jun 4, 2020
0950a95
Fix for testing wrong object for null or empty
fynngodau Jun 4, 2020
8fa8153
Better bandcamp stream extractor description test
fynngodau Jun 4, 2020
52103ac
Remove "useless" comments
fynngodau Jun 4, 2020
4dd9540
Bandcamp license switch order
fynngodau Jun 4, 2020
e13f341
Bandcamp stream extractor: test service id
fynngodau Jun 4, 2020
9a555d9
Remove useless bandcamp tests
fynngodau Jun 4, 2020
39b55b5
Bandcamp radio stream extractor: test uploader url
fynngodau Jun 4, 2020
96de834
Bandcamp: parse date from radio info item
fynngodau Jun 4, 2020
c12ef3a
Merge TNP/dev into fynngodau/dev
fynngodau Aug 2, 2020
932d094
Upgrade featured playlist urls to https
fynngodau Aug 2, 2020
cfe88a7
Throw ContentNotSupportedException when opening radio uploader channel
fynngodau Aug 9, 2020
81b5e7c
Fix extractor
fynngodau Oct 8, 2020
6bc7e34
Merge TNP/dev into fynngodau/dev
fynngodau Nov 19, 2020
186936d
Various changes regarding tests
fynngodau Nov 19, 2020
8c369b0
Rephrase link in javadoc
fynngodau Nov 24, 2020
99e7ef0
[Bandcamp] Apply small changes to code formatting and style
TobiGr Nov 24, 2020
c91e21b
[Bandcamp] Tests - Add finals and improve code formatting
TobiGr Nov 24, 2020
be562b8
Change tests
fynngodau Nov 27, 2020
04dd3d4
Rework link handlers to correctly accept external websites
fynngodau Dec 5, 2020
df16a86
[Bandcamp] Improve radio stream extractor test
TobiGr Dec 18, 2020
116e921
Merge remote-tracking branch 'origin/dev' into bandcamp
TobiGr Dec 18, 2020
74b46fe
[Bandcamp] Fix deprecation in parseDate helper function
TobiGr Dec 19, 2020
5090373
[Bandcamp] Fix accepting HTTP URLs
TobiGr Dec 22, 2020
c9e9953
[Bandcamp] Fix channel link handler factory
fynngodau Dec 22, 2020
78c2113
Merge remote-tracking branch 'origin/dev' into bandcamp
TobiGr Jan 15, 2021
0757055
Fix build and optimize imports
TobiGr Jan 15, 2021
e062c8c
Merge branch 'dev' into bandcamp
TobiGr Feb 15, 2021
5bf9fdd
Code improvements
TobiGr Feb 15, 2021
1697312
Use Collections.emptyList() instead of Collections.EMPTY_LIST or new …
TobiGr Feb 16, 2021
54b8e54
Fix potential NPE
TobiGr Feb 16, 2021
54aa5b3
Use propper structure in KioskExtractors
TobiGr Feb 16, 2021
98268e3
Move radio URL check into a function
TobiGr Feb 19, 2021
fa61b86
Code improvements
TobiGr Feb 19, 2021
91e9309
Merge remote-tracking branch 'origin/dev' into bandcamp
TobiGr Feb 19, 2021
02920fa
Add isUploaderVerified()
TobiGr Feb 19, 2021
ea120a4
remove print stacktrace
TobiGr Feb 19, 2021
adde433
Code improvements
TobiGr Feb 20, 2021
c07db80
Add BASE_URL and BASE_API_URL to BandcampExtractorHelper
TobiGr Feb 21, 2021
b9e8ee8
Rename BandcampExtractorHelper.smartConcatenate(String[], String) to …
TobiGr Feb 21, 2021
70814dc
Fix Utils.nonEmptyAndNullJoin
TobiGr Feb 21, 2021
a1688fe
Move BandcampExtractorHelper.getJsonData(String, String) to JsonUtils
TobiGr Feb 21, 2021
22fa131
Merge branch 'dev' into bandcamp
TobiGr Mar 5, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ The following sites are currently supported:
- SoundCloud
- media.ccc.de
- PeerTube (no P2P)
- Bandcamp

## License

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.schabi.newpipe.extractor;

import org.schabi.newpipe.extractor.services.bandcamp.BandcampService;
import org.schabi.newpipe.extractor.services.media_ccc.MediaCCCService;
import org.schabi.newpipe.extractor.services.peertube.PeertubeService;
import org.schabi.newpipe.extractor.services.soundcloud.SoundcloudService;
Expand Down Expand Up @@ -39,6 +40,7 @@ private ServiceList() {
public static final SoundcloudService SoundCloud;
public static final MediaCCCService MediaCCC;
public static final PeertubeService PeerTube;
public static final BandcampService Bandcamp;

/**
* When creating a new service, put this service in the end of this list,
Expand All @@ -49,7 +51,8 @@ private ServiceList() {
YouTube = new YoutubeService(0),
SoundCloud = new SoundcloudService(1),
MediaCCC = new MediaCCCService(2),
PeerTube = new PeertubeService(3)
PeerTube = new PeertubeService(3),
Bandcamp = new BandcampService(4)
));

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// Created by Fynn Godau 2019, licensed GNU GPL version 3 or later

package org.schabi.newpipe.extractor.services.bandcamp;

import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.comments.CommentsExtractor;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.kiosk.KioskList;
import org.schabi.newpipe.extractor.linkhandler.*;
import org.schabi.newpipe.extractor.playlist.PlaylistExtractor;
import org.schabi.newpipe.extractor.search.SearchExtractor;
import org.schabi.newpipe.extractor.services.bandcamp.extractors.*;
import org.schabi.newpipe.extractor.services.bandcamp.linkHandler.*;
import org.schabi.newpipe.extractor.stream.StreamExtractor;
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor;
import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor;

import java.util.Collections;

import static org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO;
import static org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampFeaturedExtractor.FEATURED_API_URL;
import static org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampFeaturedExtractor.KIOSK_FEATURED;
import static org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampRadioExtractor.KIOSK_RADIO;
import static org.schabi.newpipe.extractor.services.bandcamp.extractors.BandcampRadioExtractor.RADIO_API_URL;

public class BandcampService extends StreamingService {

public BandcampService(final int id) {
super(id, "Bandcamp", Collections.singletonList(AUDIO));
}

@Override
public String getBaseUrl() {
return "https://bandcamp.com";
}

@Override
public LinkHandlerFactory getStreamLHFactory() {
return new BandcampStreamLinkHandlerFactory();
}

@Override
public ListLinkHandlerFactory getChannelLHFactory() {
return new BandcampChannelLinkHandlerFactory();
}

@Override
public ListLinkHandlerFactory getPlaylistLHFactory() {
return new BandcampPlaylistLinkHandlerFactory();
}

@Override
public SearchQueryHandlerFactory getSearchQHFactory() {
return new BandcampSearchQueryHandlerFactory();
}

@Override
public ListLinkHandlerFactory getCommentsLHFactory() {
return null;
}

@Override
public SearchExtractor getSearchExtractor(final SearchQueryHandler queryHandler) {
return new BandcampSearchExtractor(this, queryHandler);
}

@Override
public SuggestionExtractor getSuggestionExtractor() {
return new BandcampSuggestionExtractor(this);
}

@Override
public SubscriptionExtractor getSubscriptionExtractor() {
return null;
}

@Override
public KioskList getKioskList() throws ExtractionException {

KioskList kioskList = new KioskList(this);

try {
kioskList.addKioskEntry((streamingService, url, kioskId) ->
new BandcampFeaturedExtractor(
BandcampService.this,
new BandcampFeaturedLinkHandlerFactory().fromUrl(FEATURED_API_URL), kioskId),
new BandcampFeaturedLinkHandlerFactory(), KIOSK_FEATURED);

kioskList.addKioskEntry((streamingService, url, kioskId) ->
new BandcampRadioExtractor(BandcampService.this,
new BandcampFeaturedLinkHandlerFactory().fromUrl(RADIO_API_URL), kioskId),
new BandcampFeaturedLinkHandlerFactory(), KIOSK_RADIO);

kioskList.setDefaultKiosk(KIOSK_FEATURED);

} catch (final Exception e) {
throw new ExtractionException(e);
}

return kioskList;
}

@Override
public ChannelExtractor getChannelExtractor(final ListLinkHandler linkHandler) {
return new BandcampChannelExtractor(this, linkHandler);
}

@Override
public PlaylistExtractor getPlaylistExtractor(final ListLinkHandler linkHandler) {
return new BandcampPlaylistExtractor(this, linkHandler);
}

@Override
public StreamExtractor getStreamExtractor(final LinkHandler linkHandler) {
if (linkHandler.getUrl().matches("https?://bandcamp\\.com/\\?show=\\d+"))
return new BandcampRadioStreamExtractor(this, linkHandler);
else
return new BandcampStreamExtractor(this, linkHandler);
}

@Override
public CommentsExtractor getCommentsExtractor(ListLinkHandler linkHandler) {
return null;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
// Created by Fynn Godau 2019, licensed GNU GPL version 3 or later

package org.schabi.newpipe.extractor.services.bandcamp.extractors;

import com.grack.nanojson.JsonArray;
import com.grack.nanojson.JsonObject;
import org.jsoup.Jsoup;
import org.schabi.newpipe.extractor.Page;
import org.schabi.newpipe.extractor.StreamingService;
import org.schabi.newpipe.extractor.channel.ChannelExtractor;
import org.schabi.newpipe.extractor.downloader.Downloader;
import org.schabi.newpipe.extractor.exceptions.ExtractionException;
import org.schabi.newpipe.extractor.exceptions.ParsingException;
import org.schabi.newpipe.extractor.exceptions.ReCaptchaException;
import org.schabi.newpipe.extractor.linkhandler.ListLinkHandler;
import org.schabi.newpipe.extractor.services.bandcamp.extractors.streaminfoitem.BandcampDiscographStreamInfoItemExtractor;
import org.schabi.newpipe.extractor.stream.StreamInfoItem;
import org.schabi.newpipe.extractor.stream.StreamInfoItemsCollector;

import javax.annotation.Nonnull;
import java.io.IOException;

public class BandcampChannelExtractor extends ChannelExtractor {

private JsonObject channelInfo;

public BandcampChannelExtractor(final StreamingService service, final ListLinkHandler linkHandler) {
super(service, linkHandler);
}

@Override
public String getAvatarUrl() {
if (channelInfo.getLong("bio_image_id") == 0) return "";

return BandcampExtractorHelper.getImageUrl(channelInfo.getLong("bio_image_id"), false);
}

@Override
public String getBannerUrl() throws ParsingException {
/*
* Why does the mobile endpoint not contain the header?? Or at least not the same one?
* Anyway we're back to querying websites
*/
try {
final String html = getDownloader()
.get(channelInfo.getString("bandcamp_url").replace("http://", "https://"))
.responseBody();

return Jsoup.parse(html)
.getElementById("customHeader")
.getElementsByTag("img")
.first()
.attr("src");

} catch (final IOException | ReCaptchaException e) {
throw new ParsingException("Could not download artist web site", e);
} catch (final NullPointerException e) {
// No banner available
return "";
}
}

/**
* bandcamp stopped providing RSS feeds when appending /feed to any URL
* because too few people used it.
*/
@Override
public String getFeedUrl() {
return null;
}

@Override
public long getSubscriberCount() {
return -1;
}

@Override
public String getDescription() {
return channelInfo.getString("bio");
}

@Override
public String getParentChannelName() {
return null;
}

@Override
public String getParentChannelUrl() {
return null;
}

@Override
public String getParentChannelAvatarUrl() {
return null;
}

@Nonnull
@Override
public InfoItemsPage<StreamInfoItem> getInitialPage() throws ParsingException {

final StreamInfoItemsCollector collector = new StreamInfoItemsCollector(getServiceId());

final JsonArray discography = channelInfo.getArray("discography");

for (int i = 0; i < discography.size(); i++) {
// I define discograph as an item that can appear in a discography
final JsonObject discograph = discography.getObject(i);

if (!discograph.getString("item_type").equals("track")) continue;

collector.commit(new BandcampDiscographStreamInfoItemExtractor(discograph, getUrl()));
}

return new InfoItemsPage<>(collector, null);
}

@Override
public InfoItemsPage<StreamInfoItem> getPage(Page page) {
return null;
}

@Override
public void onFetchPage(@Nonnull Downloader downloader) throws IOException, ExtractionException {
channelInfo = BandcampExtractorHelper.getArtistDetails(getId());
}

@Nonnull
@Override
public String getName() {
return channelInfo.getString("name");
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Created by Fynn Godau 2019, licensed GNU GPL version 3 or later

package org.schabi.newpipe.extractor.services.bandcamp.extractors;

import org.jsoup.nodes.Element;
import org.schabi.newpipe.extractor.channel.ChannelInfoItemExtractor;
import org.schabi.newpipe.extractor.exceptions.ParsingException;

public class BandcampChannelInfoItemExtractor implements ChannelInfoItemExtractor {

private final Element resultInfo, searchResult;

public BandcampChannelInfoItemExtractor(final Element searchResult) {
this.searchResult = searchResult;
resultInfo = searchResult.getElementsByClass("result-info").first();
}

@Override
public String getName() throws ParsingException {
return resultInfo.getElementsByClass("heading").text();
}

@Override
public String getUrl() throws ParsingException {
return resultInfo.getElementsByClass("itemurl").text();
}

@Override
public String getThumbnailUrl() throws ParsingException {
final Element img = searchResult.getElementsByClass("art").first()
.getElementsByTag("img").first();
if (img != null) {
return img.attr("src");
} else {
return null;
}
}

@Override
public String getDescription() {
return resultInfo.getElementsByClass("subhead").text();
}

@Override
public long getSubscriberCount() {
return -1;
}

@Override
public long getStreamCount() {
return -1;
}
}
Loading