From 9ec8ab782400192b3e77efe09180c2509cf2b8b5 Mon Sep 17 00:00:00 2001 From: udhayarajan Date: Fri, 21 Jul 2023 14:14:18 +0530 Subject: [PATCH 1/2] fix(Facebook): story extraction logic, and added handling for --- build.gradle.kts | 2 +- .../mugames/vidsnapkit/extractor/Extractor.kt | 65 +++--- .../mugames/vidsnapkit/extractor/Facebook.kt | 217 ++++++++++++------ .../mugames/vidsnapkit/extractor/Instagram.kt | 2 +- .../vidsnapkit/network/HttpRequestHelper.kt | 41 +++- 5 files changed, 218 insertions(+), 109 deletions(-) diff --git a/build.gradle.kts b/build.gradle.kts index 5a5af455..abd8c203 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -28,7 +28,7 @@ plugins { } group = "io.github.udhayarajan" -version = "5.6.6" +version = "5.6.7" // Version Naming incremented if ".." // Priority on incrementing Feature > BugFix > Beta diff --git a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt index f0af1fd9..296d86eb 100644 --- a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt +++ b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt @@ -30,6 +30,7 @@ import io.ktor.client.plugins.* import kotlinx.coroutines.* import kotlinx.coroutines.future.future import org.slf4j.LoggerFactory +import java.net.SocketException import java.util.* import java.util.regex.Pattern import javax.net.ssl.SSLHandshakeException @@ -58,6 +59,22 @@ abstract class Extractor( fun findExtractor( url: String, ): Extractor? { + if (url.contains("facebook")) { + if (url.contains("instagram.com")) { + logger.info("Insta embedded FB post, redirecting to Instagram") + val instaURL = Pattern.compile("\\?.*?u=(.*?)(?:&|/|)\$").matcher(url).run { + if (find()) + Util.decodeHTML(group(1)) + else + null + } + return instaURL?.let { + Instagram( + it + ) + } + } + } return when { url.contains("facebook|fb\\.".toRegex()) -> Facebook(url) url.contains("instagram") -> Instagram(url) @@ -118,24 +135,6 @@ abstract class Extractor( private suspend fun safeAnalyze() { try { - if (inputUrl.contains("facebook")) { - if (inputUrl.contains("instagram.com")) { - logger.info("Insta embedded FB post, redirecting to Instagram") - val instaURL = Pattern.compile("\\?.*?u=(.*?)(?:&|/|)\$").matcher(inputUrl).run { - if (find()) - Util.decodeHTML(group(1)) - else - null - } - Instagram( - instaURL ?: run { - logger.error("Fail to match the regex url=$inputUrl") - internalError("unable to match the instagram url") - return - } - ) - } - } if (inputUrl.contains("instagram")) { inputUrl = if (cookies == null) { inputUrl.replace("/reels/", "/reel/") @@ -153,11 +152,11 @@ abstract class Extractor( } else clientRequestError() } catch (e: Exception) { if (e is SSLHandshakeException) - clientRequestError() - else if (e is ClientRequestException && inputUrl.contains("instagram")) + internalError("problem with SSL try again") + if (e is ClientRequestException && inputUrl.contains("instagram")) onProgress(Result.Failed(Error.Instagram404Error(cookies != null))) - else if (e is SocketTimeoutException) - onProgress(Result.Failed(Error.NonFatalError("socket can't connect please try again"))) + else if (e is SocketTimeoutException || e is SocketException) + internalError("socket can't connect please try again") else onProgress(Result.Failed(Error.InternalError("Error in SafeAnalyze", e))) } @@ -240,28 +239,32 @@ abstract class Extractor( onProgress(Result.Failed(Error.InternalError(msg, e))) } + protected fun missingLogic() { + onProgress(Result.Failed(Error.MethodMissingLogic)) + } + abstract suspend fun testWebpage(string: String) // list of ua supported by both fb & insta private fun getRandomInstagramUserAgent(): String { val userAgents = listOf( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) " + - "Chrome/74.0.3729.169 Safari/537.36", + "Chrome/74.0.3729.169 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + - "Mobile/15E148 Instagram 105.0.0.11.118 (iPhone11,8; iOS 12_3_1; en_US; en-US; scale=2.00; " + - "828x1792; 165586599)" + "Mobile/15E148 Instagram 105.0.0.11.118 (iPhone11,8; iOS 12_3_1; en_US; en-US; scale=2.00; " + + "828x1792; 165586599)" ) return userAgents.random() } diff --git a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt index 3411804e..6c26c5a7 100644 --- a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt +++ b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt @@ -46,6 +46,8 @@ class Facebook internal constructor(url: String) : Extractor(url) { Chrome/69.0.3497.122 Safari/537.36 """.trimIndent().replace("\n", "") + private var isBucket = false + private suspend fun isCookieValid(): Boolean { if (cookies.isNullOrEmpty()) return false val res = HttpRequest("https://www.facebook.com/", headers).getRawResponse(false) ?: return false @@ -226,7 +228,9 @@ class Facebook internal constructor(url: String) : Extractor(url) { default = "Facebook_Video" ) } - videoFormats.add(localFormats) + if (videoFormats.isEmpty()) { + videoFormats.add(localFormats) + } finalize() } ?: apply { onProgress(Result.Failed(Error.NonFatalError("This video can't be Downloaded"))) @@ -249,13 +253,16 @@ class Facebook internal constructor(url: String) : Extractor(url) { } private fun grabRelayPrefetchedDataSearchUrl(webpage: String): Any? { - fun parseAttachment(attachment: JSONObject?, key: String) { + fun parseAttachment(attachment: JSONObject?, key: String): Formats? { val media = attachment?.getNullableJSONObject(key) media?.let { if (it.getString("__typename") == "Video") { - parseGraphqlVideo(it) + return parseGraphqlVideo(it) + } else if (it.getString("__typename") == "Photo") { + return parseGraphqlImage(it) } } + return null } val data = @@ -264,6 +271,11 @@ class Facebook internal constructor(url: String) : Extractor(url) { var nodes = it.getNullableJSONArray("nodes") var node = it.getNullableJSONObject("node") + val bucket = data.getNullableJSONObject("bucket") + if (bucket != null) { + nodes = bucket.getJSONObject("unified_stories").getJSONArray("edges") + isBucket = true + } if (nodes == null && node != null) { nodes = JSONArray().apply { put(data) @@ -274,9 +286,9 @@ class Facebook internal constructor(url: String) : Extractor(url) { for (i in 0 until nodesIt.length()) { node = nodesIt.getNullableJSONObject(i)?.getNullableJSONObject("node") - val story = node!!.getJSONObject("comet_sections") - .getJSONObject("content") - .getJSONObject("story") + val story = node!!.getNullableJSONObject("comet_sections") + ?.getJSONObject("content") + ?.getJSONObject("story") ?: node!! val attachments = story.getNullableJSONObject("attached_story") ?.getNullableJSONArray("attachments") @@ -288,17 +300,21 @@ class Facebook internal constructor(url: String) : Extractor(url) { ?.run { getNullableJSONObject("style_type_renderer") ?: getNullableJSONObject("styles") } - ?.getNullableJSONObject("attachment") + ?.getNullableJSONObject("attachment") ?: attachments.getJSONObject(j) val ns = attachment?.getNullableJSONObject("all_subattachments") ?.getNullableJSONArray("nodes") ns?.let { nsIt -> for (l in 0 until nsIt.length()) { - parseAttachment(nsIt.getJSONObject(l), "media") + parseAttachment(nsIt.getJSONObject(l), "media")?.let { + videoFormats.add(it) + } } } - parseAttachment(attachment, "media") + parseAttachment(attachment, "media")?.let { + videoFormats.add(it) + } } } } @@ -310,7 +326,9 @@ class Facebook internal constructor(url: String) : Extractor(url) { if (edges != null) { for (j in 0 until edges.length()) { val edge = edges.getJSONObject(j) - parseAttachment(edge, "node") + parseAttachment(edge, "node")?.let { + videoFormats.add(it) + } } } @@ -324,15 +342,17 @@ class Facebook internal constructor(url: String) : Extractor(url) { if (attachments != null) { for (j in 0 until attachments.length()) { - parseAttachment(attachments.getJSONObject(j), "media") + parseAttachment(attachments.getJSONObject(j), "media")?.let { + videoFormats.add(it) + } } } else { - extractFromCreationStory(video) + videoFormats.add(extractFromCreationStory(video)) return SUCCESS } - if (localFormats.videoData.isEmpty()) parseGraphqlVideo(video) + if (videoFormats.isEmpty()) videoFormats.add(parseGraphqlVideo(video)) } - if (localFormats.videoData.isNotEmpty()) return SUCCESS + return SUCCESS } return null } @@ -385,26 +405,37 @@ class Facebook internal constructor(url: String) : Extractor(url) { return searchFromRequireArray(jsonString?.toJSONObjectOrNull()?.getJSONArray("require")) } - private fun parseGraphqlVideo(media: JSONObject, hasCreationStory: Boolean = true) { + private fun parseGraphqlVideo(media: JSONObject, hasCreationStory: Boolean = true): Formats { if (media.getNullableJSONObject("creation_story") != null && hasCreationStory) { - extractFromCreationStory(media) - return + return extractFromCreationStory(media) } + val scopedFormats = localFormats.copy( + title = "", + videoData = mutableListOf(), + audioData = mutableListOf(), + imageData = mutableListOf() + ) + val thumbnailUrl = media.getNullableJSONObject("thumbnailImage")?.getString("uri") ?: media.getNullableJSONObject("preferred_thumbnail") ?.getJSONObject("image") ?.getString("uri") ?: "" val thumbnailRes = Util.getResolutionFromUrl(thumbnailUrl) if (thumbnailUrl != "") - localFormats.imageData.add(ImageResource(resolution = thumbnailRes, url = thumbnailUrl)) - localFormats.title = media.getNullableString("name") + scopedFormats.imageData.add(ImageResource(resolution = thumbnailRes, url = thumbnailUrl)) + scopedFormats.title = media.getNullableString("name") ?: media.getNullableJSONObject("savable_description") ?.getNullableString("text") - ?: "Facebook_Video" + ?: media.getNullableJSONObject("title")?.getString("text")?.ifEmpty { + "Facebook_Video" + } + ?: "Facebook_Video" val dashXml = media.getNullableString("dash_manifest") dashXml?.let { - extractFromDash(it) + val dashFormats = extractFromDash(it) + scopedFormats.videoData.addAll(dashFormats.videoData) + scopedFormats.imageData.addAll(dashFormats.imageData) } fun getWidth() = media.getNullable("width") ?: media["original_width"].toString() @@ -415,7 +446,7 @@ class Facebook internal constructor(url: String) : Extractor(url) { for (suffix in arrayOf("", "_quality_hd")) { val playableUrl = media.getNullableString("playable_url$suffix") if (playableUrl == null || playableUrl == "null") continue - localFormats.videoData.add( + scopedFormats.videoData.add( VideoResource( playableUrl, MimeType.VIDEO_MP4, @@ -423,17 +454,52 @@ class Facebook internal constructor(url: String) : Extractor(url) { ) ) } + return scopedFormats } - private fun extractFromCreationStory(media: JSONObject) { + private fun parseGraphqlImage(media: JSONObject): Formats? { + val scopedFormats = localFormats.copy( + title = "", + videoData = mutableListOf(), + audioData = mutableListOf(), + imageData = mutableListOf() + ) + + val image = media.getJSONObject("image") + scopedFormats.imageData.add( + ImageResource( + image.getString("uri"), + resolution = "${image.get("width")}x${image.get("height")}" + ) + ) + + val blurredImage = media.getJSONObject("blurred_image") + scopedFormats.imageData.add( + ImageResource( + blurredImage.getString("uri"), + resolution = Util.getResolutionFromUrl(blurredImage.getString("uri")) + ) + ) + + val previewImage = media.getJSONObject("previewImage") + scopedFormats.imageData.add( + ImageResource( + previewImage.getString("uri"), + resolution = Util.getResolutionFromUrl(previewImage.getString("uri")) + ) + ) + return scopedFormats + } + + private fun extractFromCreationStory(media: JSONObject): Formats { val playbackVideo = media.getNullableJSONObject("creation_story")?.getNullableJSONObject("short_form_video_context") ?.getNullableJSONObject("playback_video") - if (playbackVideo != null) parseGraphqlVideo(playbackVideo) + return if (playbackVideo != null) parseGraphqlVideo(playbackVideo) else parseGraphqlVideo(media, false) } - private fun extractFromDash(xml: String) { + private fun extractFromDash(xml: String): Formats { fun getRepresentationArray(adaptionSet: JSONArray, index: Int) = with(adaptionSet.getJSONObject(index)) { "Representation".let { key -> getNullableJSONArray(key) ?: run { @@ -444,59 +510,73 @@ class Facebook internal constructor(url: String) : Extractor(url) { } } + val scopedFormats = localFormats.copy( + title = "", + videoData = mutableListOf(), + audioData = mutableListOf(), + imageData = mutableListOf() + ) + var xmlDecoded = xml.replace("x3C".toRegex(), "<") xmlDecoded = xmlDecoded.replace("\\\\\u003C".toRegex(), "<") var videos = JSONArray() var audios = JSONArray() - XMLParserFactory.createParserFactory().xmlToJsonObject(xmlDecoded).getJSONObject("MPD") - .getJSONObject("Period").run { - "AdaptationSet".let { adaptationSet -> - getNullableJSONArray(adaptationSet)?.let { - videos = getRepresentationArray(it, 0) - audios = getRepresentationArray(it, 1) - } ?: run { - videos = getJSONObject(adaptationSet).getNullableJSONArray("Representation") ?: run { - val arr = JSONArray() - arr.put(getJSONObject(adaptationSet).getJSONObject("Representation")) + try { + XMLParserFactory.createParserFactory().xmlToJsonObject(xmlDecoded).getJSONObject("MPD") + .getJSONObject("Period").run { + "AdaptationSet".let { adaptationSet -> + getNullableJSONArray(adaptationSet)?.let { + videos = getRepresentationArray(it, 0) + audios = getRepresentationArray(it, 1) + } ?: run { + videos = getJSONObject(adaptationSet).getNullableJSONArray("Representation") ?: run { + val arr = JSONArray() + arr.put(getJSONObject(adaptationSet).getJSONObject("Representation")) + } } } } - } - fun safeGet(jsonObject: JSONObject, key: String) = - jsonObject.getNullable("_$key") ?: jsonObject.getNullable(key) ?: "--NA--" - - fun addVideos() { - for (i in 0 until videos.length()) { - val video = videos.getJSONObject(i) - val videoUrl = video.getString("BaseURL") - val res: String = try { - "${safeGet(video, "FBQualityLabel")}(${safeGet(video, "FBQualityClass").uppercase()})" - } catch (e: JSONException) { - "${safeGet(video, "width")}x${safeGet(video, "height")}" - } - val videoMime = safeGet(video, "mimeType") - localFormats.videoData.add( - VideoResource( - videoUrl, - videoMime, - res, - hasAudio = false + + fun safeGet(jsonObject: JSONObject, key: String) = + jsonObject.getNullable("_$key") ?: jsonObject.getNullable(key) ?: "--NA--" + + fun addVideos() { + for (i in 0 until videos.length()) { + val video = videos.getJSONObject(i) + val videoUrl = video.getString("BaseURL") + val res: String = try { + "${safeGet(video, "FBQualityLabel")}(${safeGet(video, "FBQualityClass").uppercase()})" + } catch (e: JSONException) { + "${safeGet(video, "width")}x${safeGet(video, "height")}" + } + val videoMime = safeGet(video, "mimeType") + scopedFormats.videoData.add( + VideoResource( + videoUrl, + videoMime, + res, + hasAudio = false + ) ) - ) + } } - } - fun addAudios() { - for (i in 0 until audios.length()) { - val audio = audios.getJSONObject(i) - val audioUrl = safeGet(audio, "BaseURL") - val audioMime = safeGet(audio, "mimeType") - localFormats.audioData.add(AudioResource(audioUrl, audioMime)) + fun addAudios() { + for (i in 0 until audios.length()) { + val audio = audios.getJSONObject(i) + val audioUrl = safeGet(audio, "BaseURL") + val audioMime = safeGet(audio, "mimeType") + scopedFormats.audioData.add(AudioResource(audioUrl, audioMime)) + } } + addAudios() + addVideos() + } catch (e: JSONException) { + logger.error(e.message) + logger.info(xmlDecoded) } - addAudios() - addVideos() + return scopedFormats } private fun grabFromJSModsInstance(jsData: JSONObject): Any? { @@ -525,10 +605,10 @@ class Facebook internal constructor(url: String) : Extractor(url) { url, MimeType.VIDEO_MP4, videoData.get("original_width").toString() + "x" + - videoData.get("original_height") + "(" + - s.uppercase() + ")", + videoData.get("original_height") + "(" + + s.uppercase() + ")", - ) + ) ) } return SUCCESS @@ -546,6 +626,7 @@ class Facebook internal constructor(url: String) : Extractor(url) { companion object { const val TAG: String = Statics.TAG.plus(":Facebook") const val SUCCESS = -1 // Null if fails + const val FAILS = 1 // so don't send back the response val logger = LoggerFactory.getLogger(Facebook::class.java) var PAGELET_REGEX = "(?:pagelet_group_mall|permalink_video_pagelet|hyperfeed_story_id_[0-9a-f]+)".toRegex() diff --git a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Instagram.kt b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Instagram.kt index 822e0edf..75882117 100644 --- a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Instagram.kt +++ b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Instagram.kt @@ -45,7 +45,7 @@ class Instagram internal constructor(url: String) : Extractor(url) { const val NO_STATUS_AVAILABLE = "No stories Available to Download" const val HIGHLIGHTS_API = "https://www.instagram.com/api/v1/feed/reels_media/?reel_ids=highlight%s" const val GRAPHQL_URL = - "https://www.instagram.com/graphql/query/?query_hash=%s&variables={\"shortcode\":\"%s\"}" + "https://www.instagram.com/graphql/query/?query_hash=%s&variables={\"shortcode\":\"%s\"}&__a=1&__d=dis" const val DEFAULT_QUERY_HASH = "b3055c01b4b222b8a47dc12b090e4e64" private val logger = LoggerFactory.getLogger(Instagram::class.java) diff --git a/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt b/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt index beef9c4d..d749915e 100644 --- a/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt +++ b/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt @@ -25,9 +25,14 @@ import io.ktor.client.request.* import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.http.content.* +import kotlinx.coroutines.TimeoutCancellationException import org.slf4j.LoggerFactory +import java.net.SocketException import java.util.* +import java.util.concurrent.CancellationException import java.util.regex.Pattern +import javax.net.ssl.SSLHandshakeException +import kotlin.math.min /** * @author Udhaya @@ -138,6 +143,13 @@ class HttpInterfaceImpl( false } catch (e: SocketTimeoutException) { + logger.error("checkWebPage() url=$url header=$headers SocketTimeoutException ${e.message}") + throw e + } catch (e: SocketException) { + logger.error("checkWebPage() url=$url header=$headers SocketException ${e.message}") + throw e + } catch (e: SSLHandshakeException) { + logger.error("checkWebPage() url=$url header=$headers SLLHandShakeException ${e.message}") throw e } catch (e: Exception) { logger.error("checkWebPage() url=$url header=$headers GenericException:", e) @@ -171,30 +183,43 @@ class HttpInterfaceImpl( "{error:\"Invalid Cookies\"}" } else if (status == HttpStatusCode.TooManyRequests) { logger.warn("Unhandled in getData() TooManyRequest for url=$url with headers=$headers & response=${bodyAsText()}") - "429" } else { - logger.warn("Unhandled in getData() status code=$status for url=$url with headers=$headers &\n response=${bodyAsText()}") - + val body = bodyAsText() + logger.warn( + "Unhandled in getData() status code=$status for url=$url with headers=$headers &\n response=${ + body.substring( + min(body.length, 2000) + ) + }" + ) null } } } catch (e: ClientRequestException) { logger.error("getData() url=$url header=$headers ClientRequestException:", e) - null + } catch (e: SocketTimeoutException) { + logger.error("getData() url=$url header=$headers SocketTimeoutException ${e.message}") + throw e + } catch (e: SocketException) { + logger.error("getData() url=$url header=$headers SocketException ${e.message}") + throw e + } catch (e: SSLHandshakeException) { + logger.error("getData() url=$url header=$headers SLLHandShakeException ${e.message}") + throw e } catch (e: SendCountExceedException) { if (url.contains("instagram") && headers?.containsKey("Cookie") == true) { - "{error:\"Invalid Cookies\"}" } else { logger.error("getData() url=$url header=$headers SendCountExceedException:", e) - throw e } } catch (e: Exception) { - logger.error("getData() url=$url header=$headers Generic exception:", e) - + if (e is TimeoutCancellationException || e is CancellationException) + logger.error("getData() url=$url header=$headers Cancellation exception: ${e.message}") + else + logger.error("getData() url=$url header=$headers Generic exception:", e) throw e } } From 124746e2359b7858b8f820f0f5e04b9a13c40159 Mon Sep 17 00:00:00 2001 From: udhayarajan Date: Fri, 21 Jul 2023 14:22:27 +0530 Subject: [PATCH 2/2] lint fix --- .../mugames/vidsnapkit/extractor/Extractor.kt | 18 +++++++++--------- .../mugames/vidsnapkit/extractor/Facebook.kt | 11 +++++------ .../vidsnapkit/network/HttpRequestHelper.kt | 6 +++--- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt index 296d86eb..5aa90bd2 100644 --- a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt +++ b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Extractor.kt @@ -249,22 +249,22 @@ abstract class Extractor( private fun getRandomInstagramUserAgent(): String { val userAgents = listOf( "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.80 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_6) AppleWebKit/537.36 (KHTML, like Gecko) " + - "Chrome/74.0.3729.169 Safari/537.36", + "Chrome/74.0.3729.169 Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.131 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 " + - "Safari/537.36", + "Safari/537.36", "Mozilla/5.0 (iPhone; CPU iPhone OS 12_3_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) " + - "Mobile/15E148 Instagram 105.0.0.11.118 (iPhone11,8; iOS 12_3_1; en_US; en-US; scale=2.00; " + - "828x1792; 165586599)" + "Mobile/15E148 Instagram 105.0.0.11.118 (iPhone11,8; iOS 12_3_1; en_US; en-US; scale=2.00; " + + "828x1792; 165586599)" ) return userAgents.random() } diff --git a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt index 6c26c5a7..0e39ba8d 100644 --- a/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt +++ b/src/commonMain/kotlin/com/mugames/vidsnapkit/extractor/Facebook.kt @@ -426,10 +426,10 @@ class Facebook internal constructor(url: String) : Extractor(url) { scopedFormats.title = media.getNullableString("name") ?: media.getNullableJSONObject("savable_description") ?.getNullableString("text") - ?: media.getNullableJSONObject("title")?.getString("text")?.ifEmpty { + ?: media.getNullableJSONObject("title")?.getString("text")?.ifEmpty { "Facebook_Video" } - ?: "Facebook_Video" + ?: "Facebook_Video" val dashXml = media.getNullableString("dash_manifest") dashXml?.let { @@ -537,7 +537,6 @@ class Facebook internal constructor(url: String) : Extractor(url) { } } - fun safeGet(jsonObject: JSONObject, key: String) = jsonObject.getNullable("_$key") ?: jsonObject.getNullable(key) ?: "--NA--" @@ -605,10 +604,10 @@ class Facebook internal constructor(url: String) : Extractor(url) { url, MimeType.VIDEO_MP4, videoData.get("original_width").toString() + "x" + - videoData.get("original_height") + "(" + - s.uppercase() + ")", + videoData.get("original_height") + "(" + + s.uppercase() + ")", - ) + ) ) } return SUCCESS diff --git a/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt b/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt index d749915e..e3dd18e5 100644 --- a/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt +++ b/src/commonMain/kotlin/com/mugames/vidsnapkit/network/HttpRequestHelper.kt @@ -188,9 +188,9 @@ class HttpInterfaceImpl( val body = bodyAsText() logger.warn( "Unhandled in getData() status code=$status for url=$url with headers=$headers &\n response=${ - body.substring( - min(body.length, 2000) - ) + body.substring( + min(body.length, 2000) + ) }" ) null