Videos started to fail to download.

Attempt to get the video URL from the first response if the 'actual' url cannot be found within.

#14
This commit is contained in:
Gergely Hegedus 2023-12-14 23:20:45 +02:00
parent 2f3ecfd4f6
commit 78606df4dd
8 changed files with 44 additions and 17 deletions

View file

@ -9,12 +9,15 @@ import org.fnives.tiktokdownloader.data.model.VideoInSavingIntoFile
import org.fnives.tiktokdownloader.data.network.exceptions.CaptchaRequiredException
import org.fnives.tiktokdownloader.data.network.exceptions.NetworkException
import org.fnives.tiktokdownloader.data.network.exceptions.ParsingException
import org.fnives.tiktokdownloader.data.network.parsing.converter.VideoFileUrlConverter
import org.fnives.tiktokdownloader.data.network.parsing.response.VideoFileUrl
import org.fnives.tiktokdownloader.data.network.session.CookieStore
class TikTokDownloadRemoteSource(
private val delayBeforeRequest: Long,
private val service: TikTokRetrofitService,
private val cookieStore: CookieStore
private val cookieStore: CookieStore,
private val videoFileUrlConverter: VideoFileUrlConverter,
) {
@Throws(ParsingException::class, NetworkException::class, CaptchaRequiredException::class)
@ -23,9 +26,17 @@ class TikTokDownloadRemoteSource(
wrapIntoProperException {
delay(delayBeforeRequest) // added just so captcha trigger may not happen
val actualUrl = service.getContentActualUrlAndCookie(videoInPending.url)
Logger.logMessage("actualUrl found = ${actualUrl.url}")
delay(delayBeforeRequest) // added just so captcha trigger may not happen
val videoUrl = service.getVideoUrl(actualUrl.url)
val videoUrl: VideoFileUrl
if (actualUrl.url != null) {
Logger.logMessage("actualUrl found = ${actualUrl.url}")
delay(delayBeforeRequest) // added just so captcha trigger may not happen
videoUrl = service.getVideoUrl(actualUrl.url)
} else {
Logger.logMessage("actualUrl not found. Attempting to parse videoUrl")
videoUrl = videoFileUrlConverter.convertSafely(actualUrl.fullResponse)
}
Logger.logMessage("videoFileUrl found = ${videoUrl.videoFileUrl}")
delay(delayBeforeRequest) // added just so captcha trigger may not happen
val response = service.getVideo(videoUrl.videoFileUrl)

View file

@ -10,10 +10,18 @@ class ActualVideoPageUrlConverter(
) : ParsingExceptionThrowingConverter<ActualVideoPageUrl>() {
@Throws(IndexOutOfBoundsException::class, CaptchaRequiredException::class)
override fun convertSafely(responseBody: ResponseBody): ActualVideoPageUrl? =
responseBody.string()
.also(throwIfIsCaptchaResponse::invoke)
.split("rel=\"canonical\" href=\"")[1]
.split("\"")[0]
.let(::ActualVideoPageUrl)
override fun convertSafely(responseBody: ResponseBody): ActualVideoPageUrl? {
val responseBodyAsString =responseBody.string()
return try {
val actualVideoPageUrl = responseBodyAsString
.also(throwIfIsCaptchaResponse::invoke)
.split("rel=\"canonical\" href=\"")[1]
.split("\"")[0]
ActualVideoPageUrl(actualVideoPageUrl, responseBodyAsString)
} catch(_: Throwable) {
ActualVideoPageUrl(null, responseBodyAsString)
}
}
}

View file

@ -11,7 +11,12 @@ class VideoFileUrlConverter(
@Throws(IllegalArgumentException::class, IndexOutOfBoundsException::class, CaptchaRequiredException::class)
override fun convertSafely(responseBody: ResponseBody): VideoFileUrl? {
val html = responseBody.string().also(throwIfIsCaptchaResponse::invoke)
return convertSafely(responseBody.string())
}
@Throws(IllegalArgumentException::class, IndexOutOfBoundsException::class, CaptchaRequiredException::class)
fun convertSafely(responseBody: String): VideoFileUrl {
val html = responseBody.also(throwIfIsCaptchaResponse::invoke)
val url = tryToParseDownloadLink(html).also { Logger.logMessage("parsed download link = $it") }
?: tryToParseVideoSrc(html).also { Logger.logMessage("parsed video src = $it") }
?: throw IllegalArgumentException("Couldn't parse url from HTML: $html")

View file

@ -1,3 +1,3 @@
package org.fnives.tiktokdownloader.data.network.parsing.response
class ActualVideoPageUrl(val url: String)
class ActualVideoPageUrl(val url: String?, val fullResponse: String)

View file

@ -7,6 +7,7 @@ import org.fnives.tiktokdownloader.data.network.TikTokDownloadRemoteSource
import org.fnives.tiktokdownloader.data.network.TikTokRetrofitService
import org.fnives.tiktokdownloader.data.network.parsing.TikTokWebPageConverterFactory
import org.fnives.tiktokdownloader.data.network.parsing.converter.ThrowIfIsCaptchaResponse
import org.fnives.tiktokdownloader.data.network.parsing.converter.VideoFileUrlConverter
import org.fnives.tiktokdownloader.data.network.session.CookieSavingInterceptor
import org.fnives.tiktokdownloader.data.network.session.CookieStore
import retrofit2.Converter
@ -47,5 +48,5 @@ class NetworkModule(private val delayBeforeRequest: Long) {
get() = retrofit.create(TikTokRetrofitService::class.java)
val tikTokDownloadRemoteSource: TikTokDownloadRemoteSource
get() = TikTokDownloadRemoteSource(delayBeforeRequest, tikTokRetrofitService, cookieStore)
get() = TikTokDownloadRemoteSource(delayBeforeRequest, tikTokRetrofitService, cookieStore, VideoFileUrlConverter(throwIfIsCaptchaResponse))
}

View file

@ -8,7 +8,6 @@ import org.fnives.tiktokdownloader.di.module.NetworkModule
import org.fnives.tiktokdownloader.helper.getResourceFile
import org.junit.jupiter.api.Assertions
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Disabled
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.Timeout
import java.io.File
@ -38,7 +37,7 @@ class TikTokDownloadRemoteSourceUpToDateTest {
actualFile.delete()
actualFile.createNewFile()
actualFile.deleteOnExit()
val expectedFile = getResourceFile(EXPECTED_FILE_PATH)
val expectedFileOptions = EXPECTED_FILE_PATHS.map{getResourceFile(it)}
actualFile.writeText("")
runBlocking { sut.getVideo(parameter).byteStream }.use { inputStream ->
@ -46,12 +45,15 @@ class TikTokDownloadRemoteSourceUpToDateTest {
inputStream.copyTo(outputStream)
}
}
Assertions.assertTrue(FileUtils.contentEquals(expectedFile, actualFile), "The Downloaded file Is Not Matching the expected")
val doesAnyIsTheSameFile = expectedFileOptions.any { expectedFile->
FileUtils.contentEquals(expectedFile, actualFile)
}
Assertions.assertTrue(doesAnyIsTheSameFile, "The Downloaded file Is Not Matching the expected")
}
companion object {
private const val ACTUAL_FILE_PATH = "actual.mp4"
private const val EXPECTED_FILE_PATH = "video/expected.mp4"
private val EXPECTED_FILE_PATHS = listOf("video/expected_option_1.mp4","video/expected_option_2.mp4")
private const val SUBJECT_VIDEO_URL = "https://vm.tiktok.com/ZSQG7SMf/"
}
}

Binary file not shown.