// Created by Fynn Godau 2019, licensed GNU GPL version 3 or later package org.schabi.newpipe.extractor.services.bandcamp.extractors; import com.grack.nanojson.JsonObject; import com.grack.nanojson.JsonParser; import com.grack.nanojson.JsonParserException; import com.grack.nanojson.JsonWriter; import org.jsoup.Jsoup; import org.jsoup.nodes.Document; import org.schabi.newpipe.extractor.NewPipe; import org.schabi.newpipe.extractor.exceptions.ParsingException; import org.schabi.newpipe.extractor.exceptions.ReCaptchaException; import org.schabi.newpipe.extractor.localization.DateWrapper; import org.schabi.newpipe.extractor.utils.Utils; import java.io.IOException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.*; public class BandcampExtractorHelper { /** *

Get an attribute of a web page as JSON * *

Originally a part of bandcampDirect.

* * @param html The HTML where the JSON we're looking for is stored inside a * variable inside some JavaScript block * @param variable Name of the variable * @return The JsonObject stored in the variable with this name */ public static JsonObject getJsonData(final String html, final String variable) throws JsonParserException, ArrayIndexOutOfBoundsException { final Document document = Jsoup.parse(html); final String json = document.getElementsByAttribute(variable).attr(variable); return JsonParser.object().from(json); } /** * Translate all these parameters together to the URL of the corresponding album or track * using the mobile api */ public static String getStreamUrlFromIds(final long bandId, final long itemId, final String itemType) throws ParsingException { try { final String jsonString = NewPipe.getDownloader().get( "https://bandcamp.com/api/mobile/22/tralbum_details?band_id=" + bandId + "&tralbum_id=" + itemId + "&tralbum_type=" + itemType.substring(0, 1)) .responseBody(); return JsonParser.object().from(jsonString).getString("bandcamp_url").replace("http://", "https://"); } catch (final JsonParserException | ReCaptchaException | IOException e) { throw new ParsingException("Ids could not be translated to URL", e); } } /** * Concatenate all non-null and non-empty strings together while separating them using * the comma parameter */ public static String smartConcatenate(final String[] strings, final String comma) { final StringBuilder result = new StringBuilder(); // Remove empty strings final ArrayList list = new ArrayList<>(Arrays.asList(strings)); for (int i = list.size() - 1; i >= 0; i--) { if (Utils.isNullOrEmpty(list.get(i)) || list.get(i).equals("null")) { list.remove(i); } } // Append remaining strings to result for (int i = 0; i < list.size(); i++) { result.append(list.get(i)); if (i != list.size() - 1) { // This is not the last iteration yet result.append(comma); } } return String.valueOf(result); } /** * Fetch artist details from mobile endpoint. * * More technical info. */ public static JsonObject getArtistDetails(String id) throws ParsingException { try { return JsonParser.object().from( NewPipe.getDownloader().post( "https://bandcamp.com/api/mobile/22/band_details", null, JsonWriter.string() .object() .value("band_id", id) .end() .done() .getBytes() ).responseBody() ); } catch (final IOException | ReCaptchaException | JsonParserException e) { throw new ParsingException("Could not download band details", e); } } /** * @param id The image ID * @param album Whether this is the cover of an album * @return Url of image with this ID in size 10 which is 1200x1200 (we could also choose size 0 * but we don't want something as large as 3460x3460 here, do we?) */ public static String getImageUrl(final long id, final boolean album) { return "https://f4.bcbits.com/img/" + (album ? 'a' : "") + id + "_10.jpg"; } /** * @return true if the given url looks like it comes from a bandcamp custom domain * or if it comes from bandcamp.com itself */ public static boolean isSupportedDomain(final String url) throws ParsingException { // Accept all bandcamp.com URLs if (url.toLowerCase().matches("https?://.+\\.bandcamp\\.com(/.*)?")) return true; try { // Accept all other URLs if they contain a tag that says they are generated by bandcamp return Jsoup.parse( NewPipe.getDownloader().get(url).responseBody() ) .getElementsByAttributeValue("name", "generator") .attr("content").equals("Bandcamp"); } catch (IOException | ReCaptchaException e) { throw new ParsingException("Could not determine whether URL is custom domain " + "(not available? network error?)"); } } static DateWrapper parseDate(final String textDate) throws ParsingException { try { final Date date = new SimpleDateFormat("dd MMM yyyy HH:mm:ss zzz", Locale.ENGLISH).parse(textDate); final Calendar calendar = Calendar.getInstance(); calendar.setTime(date); return new DateWrapper(calendar, false); } catch (final ParseException e) { throw new ParsingException("Could not extract date", e); } } }