Skip to content

Commit

Permalink
NTV-465: Add audio parsing (#1584)
Browse files Browse the repository at this point in the history
  • Loading branch information
Arkariang committed Mar 29, 2022
1 parent aff05bf commit f4f4b59
Show file tree
Hide file tree
Showing 8 changed files with 172 additions and 19 deletions.
2 changes: 1 addition & 1 deletion app/build.gradle
Expand Up @@ -220,7 +220,7 @@ dependencies {
implementation "com.jakewharton.rxbinding:rxbinding:$rx_binding_version"
implementation "com.jakewharton.rxbinding:rxbinding-recyclerview-v7:$rx_binding_version"
implementation "com.jakewharton.rxbinding:rxbinding-support-v4:$rx_binding_version"
implementation "com.jakewharton.timber:timber:4.7.1"
implementation "com.jakewharton.timber:timber:5.0.1"
implementation 'com.optimizely.ab:android-sdk:3.11.1'
implementation "com.stripe:stripe-android:19.2.0"
final okhttp_version = "4.9.+"
Expand Down
Expand Up @@ -45,6 +45,14 @@ fun Element.isImageStructure(): Boolean {
return !isTemplateDiv.isNullOrEmpty()
}

fun Element.parseAudioElement(): AudioViewElement {
val url = this.children()
.firstOrNull { (it.attr("type") ?: "").contentEquals("audio/mp3") }
?.attr("src") ?: ""

return AudioViewElement(url)
}

fun Element.parseVideoElement(): String {
val sourceUrls = this.children().mapNotNull { it.attr("src") }
return sourceUrls.firstOrNull { it.contains("high") } ?: sourceUrls.first()
Expand Down
12 changes: 10 additions & 2 deletions app/src/main/java/com/kickstarter/libs/htmlparser/HTMLModels.kt
Expand Up @@ -5,12 +5,16 @@ import org.jsoup.nodes.Element
interface ViewElement

data class TextViewElement(var components: List<TextComponent>) : ViewElement

data class AudioViewElement(
val sourceUrl: String
) : ViewElement

data class VideoViewElement(
val sourceUrl: String,
val thumbnailUrl: String?,
val seekPosition: Long
) :
ViewElement
) : ViewElement

data class TextComponent(
var text: String,
Expand Down Expand Up @@ -63,6 +67,7 @@ enum class ViewElementType(val tag: String?) {
IMAGE("img"),
TEXT(null),
VIDEO("video"),
AUDIO("audio"),
EXTERNAL_SOURCES("iframe"),
UNKNOWN(null);

Expand All @@ -82,6 +87,9 @@ enum class ViewElementType(val tag: String?) {
tag == VIDEO.tag -> {
return VIDEO
}
tag == AUDIO.tag -> {
return AUDIO
}
}
return UNKNOWN
}
Expand Down
Expand Up @@ -39,6 +39,10 @@ class HTMLParser {
)
viewElements.add(videoViewElement)
}
ViewElementType.AUDIO -> {
val audioElement = element.parseAudioElement()
viewElements.add(audioElement)
}
ViewElementType.EXTERNAL_SOURCES -> {
viewElements.add(element.parseExternalElement())
}
Expand Down
Expand Up @@ -11,6 +11,7 @@ import com.kickstarter.ui.data.ProjectData
import com.kickstarter.ui.fragments.projectpage.ProjectOverviewFragment
import rx.Observable
import rx.subjects.BehaviorSubject
import timber.log.Timber

class ProjectCampaignViewModel {
interface Inputs {
Expand All @@ -24,11 +25,12 @@ class ProjectCampaignViewModel {
/** Emits in a list format the DOM elements */
fun storyViewElements(): Observable<List<ViewElement>>
fun onScrollToVideoPosition(): Observable<Int>
fun onOpenVideoInFullScreen(): Observable< Pair<String, Long>>
fun updateVideoCloseSeekPosition(): Observable< Pair<Int, Long>>
fun onOpenVideoInFullScreen(): Observable<Pair<String, Long>>
fun updateVideoCloseSeekPosition(): Observable<Pair<Int, Long>>
}

class ViewModel(@NonNull val environment: Environment) : FragmentViewModel<ProjectOverviewFragment>(environment), Inputs, Outputs {
class ViewModel(@NonNull val environment: Environment) :
FragmentViewModel<ProjectOverviewFragment>(environment), Inputs, Outputs {
val inputs: Inputs = this
val outputs: Outputs = this

Expand All @@ -39,8 +41,9 @@ class ProjectCampaignViewModel {
private val closeFullScreenVideo = BehaviorSubject.create<Long>()
private val openVideoInFullScreen = BehaviorSubject.create<Pair<Int, Pair<String, Long>>>()
private val onScrollToVideoPosition = BehaviorSubject.create<Int>()
private val onOpenVideoInFullScreen = BehaviorSubject.create< Pair<String, Long>>()
private val onOpenVideoInFullScreen = BehaviorSubject.create<Pair<String, Long>>()
private val updateVideoCloseSeekPosition = BehaviorSubject.create<Pair<Int, Long>>()

init {
val project = projectDataInput
.map { it.project() }
Expand All @@ -54,13 +57,14 @@ class ProjectCampaignViewModel {
.map { htmlParser.parse(it) }
.compose(bindToLifecycle())
.subscribe {

if (environment.build().isDebug) {
Timber.d("$this parsed list of ViewElements: ${it.map { item -> "$item \n" }}")
}
storyViewElementsList.onNext(it)
}

closeFullScreenVideo
.withLatestFrom(openVideoInFullScreen) {
closePosition, videoOpenPosition ->
.withLatestFrom(openVideoInFullScreen) { closePosition, videoOpenPosition ->
Pair(videoOpenPosition.first, closePosition)
}.withLatestFrom(storyViewElementsList) { pair, list ->
Pair(pair, list)
Expand All @@ -85,8 +89,7 @@ class ProjectCampaignViewModel {
}

closeFullScreenVideo
.withLatestFrom(openVideoInFullScreen) {
closePosition, videoOpenPosition ->
.withLatestFrom(openVideoInFullScreen) { closePosition, videoOpenPosition ->
Pair(videoOpenPosition.first, closePosition)
}
.compose(bindToLifecycle())
Expand All @@ -107,14 +110,17 @@ class ProjectCampaignViewModel {
// - Inputs
override fun configureWith(projectData: ProjectData) =
this.projectDataInput.onNext(projectData)

override fun closeFullScreenVideo(position: Long) = closeFullScreenVideo.onNext(position)
override fun openVideoInFullScreen(index: Int, source: String, seekPosition: Long) =
openVideoInFullScreen.onNext(Pair(index, Pair(source, seekPosition)))

override fun storyViewElements(): Observable<List<ViewElement>> = storyViewElementsList
override fun onScrollToVideoPosition(): Observable<Int> = onScrollToVideoPosition
override fun onOpenVideoInFullScreen(): Observable< Pair<String, Long>> = onOpenVideoInFullScreen
override fun updateVideoCloseSeekPosition(): Observable< Pair<Int, Long>> =
override fun onOpenVideoInFullScreen(): Observable<Pair<String, Long>> =
onOpenVideoInFullScreen

override fun updateVideoCloseSeekPosition(): Observable<Pair<Int, Long>> =
updateVideoCloseSeekPosition
}
}
@@ -1,6 +1,7 @@
package com.kickstarter.libs.htmlparser

import junit.framework.TestCase
import junit.framework.TestCase.assertEquals
import org.junit.Test
import java.net.URI

Expand Down Expand Up @@ -253,4 +254,47 @@ class HTMLParserTest {
TestCase.assertEquals(videoViewElement.sourceUrl, baseURL)
TestCase.assertEquals(videoViewElement.thumbnailUrl, thumbnailUrl)
}

@Test
fun parseAudioElementCorrectFormat() {
val baseUrl =
"https://dr0rfahizzuzj.cloudfront.net/assets/002/236/466/f17de99e2a9e76a4954418c16d963f9b_mp3.mp3?2015"
val html =
"<div class=\"template asset\" contenteditable=\"false\" data-id=\"2236466\">" +
"<figure>" +
"<audio controls=\"controls\" preload=\"none\">" +
" <source src=$baseUrl type=\"audio/mp3\"></source>" +
" <source src=\"https://dr0rfahizzuzj.cloudfront.net/assets/002/236/466/f17de99e2a9e76a4954418c16d963f9b_aac.aac?2015\" type=\"audio/aac\"></source>" +
" <source src=\"https://dr0rfahizzuzj.cloudfront.net/assets/002/236/466/f17de99e2a9e76a4954418c16d963f9b_ogg.ogg?2015\" type=\"audio/ogg\"></source>" +
" <source src=\"https://dr0rfahizzuzj.cloudfront.net/assets/002/236/466/f17de99e2a9e76a4954418c16d963f9b_webm.webm?2015\" type=\"audio/webm\"></source>" +
"</audio>" +
"</figure>" +
"</div>"

val listOfElements = HTMLParser().parse(html)
assert(listOfElements.size == 1)

val audioElement: AudioViewElement = listOfElements.last() as AudioViewElement
assertEquals(audioElement.sourceUrl, baseUrl)
}

@Test
fun parseAudioElementNoMP3Source() {
val html =
"<div class=\"template asset\" contenteditable=\"false\" data-id=\"2236466\">" +
"<figure>" +
"<audio controls=\"controls\" preload=\"none\">" +
" <source src=\"https://dr0rfahizzuzj.cloudfront.net/assets/002/236/466/f17de99e2a9e76a4954418c16d963f9b_aac.aac?2015\" type=\"audio/aac\"></source>" +
" <source src=\"https://dr0rfahizzuzj.cloudfront.net/assets/002/236/466/f17de99e2a9e76a4954418c16d963f9b_ogg.ogg?2015\" type=\"audio/ogg\"></source>" +
" <source src=\"https://dr0rfahizzuzj.cloudfront.net/assets/002/236/466/f17de99e2a9e76a4954418c16d963f9b_webm.webm?2015\" type=\"audio/webm\"></source>" +
"</audio>" +
"</figure>" +
"</div>"

val listOfElements = HTMLParser().parse(html)
assert(listOfElements.size == 1)

val audioElement: AudioViewElement = listOfElements.last() as AudioViewElement
assertEquals(audioElement.sourceUrl, "")
}
}

0 comments on commit f4f4b59

Please sign in to comment.