Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
33 changes: 31 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,21 +1,39 @@
allprojects {
apply plugin: 'java-library'
apply plugin: 'kotlin'
apply plugin: 'maven'

sourceCompatibility = 1.7
targetCompatibility = 1.7

version 'v0.19.5'
//version 'v0.19.5'
version 'LOCAL_SNAPSHOT'
group 'com.github.TeamNewPipe'

repositories {
jcenter()
mavenCentral()
maven { url "https://jitpack.io" }
}

compileKotlin {
kotlinOptions {
jvmTarget = "1.6"
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = "1.6"
}
}

dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
}

dependencies {
implementation project(':extractor')
api project(':extractor')
implementation project(':timeago-parser')
}

Expand Down Expand Up @@ -55,3 +73,14 @@ task aggregatedJavadocs(type: Javadoc, group: 'Documentation') {
}
}
}

buildscript {
ext.kotlin_version = '1.3.72'
repositories {
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

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.bbc_sounds.BSService;
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 BSService BBC_SOUNDS;

/**
* 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),
BBC_SOUNDS = new BSService(4)
));

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.schabi.newpipe.extractor.services.bbc_sounds

import org.schabi.newpipe.extractor.MediaFormat
import org.schabi.newpipe.extractor.NewPipe
import org.schabi.newpipe.extractor.stream.AudioStream
import org.schabi.newpipe.extractor.stream.DashMpdParser
import org.schabi.newpipe.extractor.stream.DeliveryFormat
import org.w3c.dom.Element
import java.io.ByteArrayInputStream
import java.util.*
import javax.xml.parsers.DocumentBuilderFactory

internal object BSDashMpdParser : DashMpdParser() {

override fun getStreams(manifestUrl: String): Result {
val manifest = NewPipe.getDownloader().get(manifestUrl).responseBody()
val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
val dashDoc = builder.parse(ByteArrayInputStream(manifest.toByteArray()))
val representationList = dashDoc.getElementsByTagName("Representation")

val audioStreams: MutableList<AudioStream> = ArrayList()

for (i in 0 until representationList.length) {
val representation = representationList.item(i) as? Element
representation?.let {

val adaptationSet = representation.parentNode as Element
val mimeType = adaptationSet.getAttribute("mimeType")
val mediaFormat = MediaFormat.getFromMimeType(mimeType)
val abr = it.getAttribute("bandwidth").toInt()
val deliveryFormat = DeliveryFormat.manualDASH(manifestUrl, manualDashFromRepresentation(dashDoc, it))
val stream = AudioStream(deliveryFormat, mediaFormat, abr)
if (!AudioStream.containSimilarStream(stream, audioStreams)) {
audioStreams.add(stream)
}
}
}

return Result(emptyList(), emptyList(), audioStreams)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package org.schabi.newpipe.extractor.services.bbc_sounds

import org.schabi.newpipe.extractor.exceptions.ParsingException
import org.schabi.newpipe.extractor.utils.Parser
import org.schabi.newpipe.extractor.utils.Parser.RegexException
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.*

internal object BSParsingHelper {

@Throws(ParsingException::class)
fun parseDate(textualDate: String): Calendar {
return try {
SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")
.apply { timeZone = TimeZone.getTimeZone("GMT") }
.parse(textualDate).let { Calendar.getInstance().apply { time = it } }
} catch (e: ParseException) {
throw ParsingException("Could not parse date: $textualDate", e)
}
}

fun getNextPageUrl(prevPageUrl: String, limit: Int, total: Int): String {
val prevOffset = try {
Parser.matchGroup1("offset=(\\d*)", prevPageUrl)
} catch (e: RegexException) {
return ""
}
val nextOffset = prevOffset.toInt() + limit
return if (nextOffset < total) {
prevPageUrl.replace("offset=$prevOffset", "offset=$nextOffset")
} else {
""
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.schabi.newpipe.extractor.services.bbc_sounds

import org.schabi.newpipe.extractor.StreamingService
import org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.AUDIO
import org.schabi.newpipe.extractor.StreamingService.ServiceInfo.MediaCapability.LIVE
import org.schabi.newpipe.extractor.channel.ChannelExtractor
import org.schabi.newpipe.extractor.comments.CommentsExtractor
import org.schabi.newpipe.extractor.kiosk.KioskList
import org.schabi.newpipe.extractor.kiosk.KioskList.KioskExtractorFactory
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.bbc_sounds.extractors.BSExtractorHelper
import org.schabi.newpipe.extractor.services.bbc_sounds.extractors.BSKioskExtractor
import org.schabi.newpipe.extractor.services.bbc_sounds.extractors.BSSearchExtractor
import org.schabi.newpipe.extractor.services.bbc_sounds.linkHandler.BSChannelLinkHandlerFactory
import org.schabi.newpipe.extractor.services.bbc_sounds.linkHandler.BSKioskLinkHandlerFactory
import org.schabi.newpipe.extractor.services.bbc_sounds.linkHandler.BSSearchQueryHandlerFactory
import org.schabi.newpipe.extractor.services.bbc_sounds.linkHandler.BSStreamLinkHandlerFactory
import org.schabi.newpipe.extractor.stream.StreamExtractor
import org.schabi.newpipe.extractor.subscription.SubscriptionExtractor
import org.schabi.newpipe.extractor.suggestion.SuggestionExtractor

class BSService(id: Int) : StreamingService(id, "BBC Sounds", listOf(AUDIO, LIVE)) {
override fun getBaseUrl(): String {
return "https://bbc.co.uk/sounds"
}

override fun getStreamLHFactory(): LinkHandlerFactory {
return BSStreamLinkHandlerFactory
}

override fun getChannelLHFactory(): ListLinkHandlerFactory {
return BSChannelLinkHandlerFactory
}

override fun getPlaylistLHFactory(): ListLinkHandlerFactory? {
return null
}

override fun getSearchQHFactory(): SearchQueryHandlerFactory {
return BSSearchQueryHandlerFactory
}

override fun getCommentsLHFactory(): ListLinkHandlerFactory? {
return null
}

override fun getSearchExtractor(queryHandler: SearchQueryHandler): SearchExtractor {
// TODO fix this to return brands,series also
return BSSearchExtractor(this, queryHandler)
}

override fun getSuggestionExtractor(): SuggestionExtractor? {
return null
}

override fun getSubscriptionExtractor(): SubscriptionExtractor? {
return null
}

override fun getKioskList(): KioskList {
val kioskLHF = BSKioskLinkHandlerFactory

val kioskFactory = KioskExtractorFactory { service, _, id ->
BSKioskExtractor(service,
kioskLHF.fromId(id), id)
}

val list = KioskList(this)
BSKioskLinkHandlerFactory.kiosks.forEach {
list.addKioskEntry(kioskFactory, kioskLHF, it.key)
}
list.setDefaultKiosk(BSKioskLinkHandlerFactory.DEFAULT_KIOSK_ID)

return list
}

override fun getChannelExtractor(linkHandler: ListLinkHandler): ChannelExtractor {
return BSExtractorHelper.getChannelExtractor(this, linkHandler)
}

override fun getPlaylistExtractor(linkHandler: ListLinkHandler?): PlaylistExtractor? {
return null
}

override fun getStreamExtractor(linkHandler: LinkHandler): StreamExtractor {
return BSExtractorHelper.getStreamExtractor(this, linkHandler)
}

override fun getCommentsExtractor(linkHandler: ListLinkHandler?): CommentsExtractor? {
return null
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package org.schabi.newpipe.extractor.services.bbc_sounds.extractors

import com.grack.nanojson.JsonObject
import com.grack.nanojson.JsonParser
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.linkhandler.ListLinkHandler
import org.schabi.newpipe.extractor.services.bbc_sounds.linkHandler.BSChannelLinkHandlerFactory
import org.schabi.newpipe.extractor.stream.StreamInfoItem

class BSChannelExtractor(service: StreamingService, linkHandler: ListLinkHandler) : ChannelExtractor(service, linkHandler) {

private lateinit var initPage: InfoItemsPage<StreamInfoItem>
private var container: JsonObject? = null
private var network: JsonObject? = null

override fun onFetchPage(downloader: Downloader) {
initPage = getPage(url)
}

override fun getInitialPage(): InfoItemsPage<StreamInfoItem> {
super.fetchPage()
return initPage
}

override fun getNextPageUrl(): String {
super.fetchPage()
return initPage.nextPageUrl
}

override fun getPage(pageUrl: String): InfoItemsPage<StreamInfoItem> {
val response = JsonParser.`object`().from(downloader.get(pageUrl).responseBody())
if(network == null) {
network = response.getArray("data")?.get(0)?.let { it as? JsonObject }?.getObject("network")
}
if(container == null) {
container = response.getArray("data")?.get(0)?.let { it as? JsonObject }?.getObject("container")
}
return BSExtractorHelper.parsePage(this, pageUrl, response)
}

private fun getDescription(synopses: JsonObject): String {
synopses.getString("long")?.let { return it }
synopses.getString("medium")?.let { return it }
synopses.getString("short")?.let { return it }
return ""
}

override fun getSubscriberCount(): Long {
return -1
}

override fun getName(): String {
return container?.getString("title") ?: ""
}

override fun getAvatarUrl(): String {
return initPage.items?.get(0)?.thumbnailUrl ?: ""
}

override fun getBannerUrl(): String {
return ""
}

override fun getFeedUrl(): String {
return ""
}

override fun getDescription(): String {
return container?.getObject("synopses")?.let { getDescription(it) } ?: ""
}

override fun getParentChannelName(): String {
return network?.getString("short_title") ?: ""
}

override fun getParentChannelUrl(): String {
return network?.getString("id")?.let {
val id = BSChannelLinkHandlerFactory.NETWORK_ID_PREFIX + it
BSChannelLinkHandlerFactory.fromNetworkId(id).url
} ?: ""
}

override fun getParentChannelAvatarUrl(): String {
return network?.getString("logo_url")
?.replace("{type}", "colour")
?.replace("{size}", "default")
?.replace("{format}", "svg") ?: ""

}

override fun getOriginalUrl(): String {
return "${service.baseUrl}/brand/$id"
}
}
Loading