| | |
| | | <selectionStates> |
| | | <SelectionState runConfigName="app"> |
| | | <option name="selectionMode" value="DROPDOWN" /> |
| | | <DropdownSelection timestamp="2024-11-27T11:37:15.668942400Z"> |
| | | <DropdownSelection timestamp="2024-12-09T08:10:34.232180Z"> |
| | | <Target type="DEFAULT_BOOT"> |
| | | <handle> |
| | | <DeviceId pluginId="Default" identifier="serial=127.0.0.1:5555;connection=03e18c1a" /> |
| | | <DeviceId pluginId="PhysicalDevice" identifier="serial=xg4hkjgmhexwdawg" /> |
| | | </handle> |
| | | </Target> |
| | | </DropdownSelection> |
| | |
| | | import android.util.Log |
| | | import android.webkit.CookieManager |
| | | import org.json.JSONObject |
| | | |
| | | |
| | | |
| | | object CookieHelper { |
| | | private const val PREF_NAME = "CookieHelper" |
| | | |
| | | |
| | | |
| | | fun saveSessionProfileUrlCookies(context: Context, sessionProfileId: String, url: String) { |
| | | try{ |
| | | val cookies = CookieManager.getInstance().getCookie(url) |
| | | if (cookies != null) { |
| | | println("这是cookie"+cookies) |
| | | val sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) |
| | | val sessionCookiesMap = sharedPreferences.getString(sessionProfileId, "{}") |
| | | val sessionCookies = JSONObject(sessionCookiesMap!!) |
| | |
| | | Log.e("CookieHelper", "Failed to get cookies: ", e) |
| | | } |
| | | } |
| | | |
| | | fun getAllSessionProfileCookies(context: Context, sessionProfileId: String): Map<String, String> { |
| | | val sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) |
| | | val sessionCookiesMap = sharedPreferences.getString(sessionProfileId, "{}") |
| | | val sessionCookies = JSONObject(sessionCookiesMap!!) |
| | | println("最终的sessioncookies是"+sessionCookies) |
| | | println("返回的结果是:"+sessionCookies.keys().asSequence().associateWith { sessionCookies.getString(it) }) |
| | | return sessionCookies.keys().asSequence().associateWith { sessionCookies.getString(it) } |
| | | } |
| | | private fun getBaseUrl(url: String): String { |
| | | val uri = Uri.parse(url) |
| | | println("最终路径:${uri.scheme}://${uri.host}/") |
| | | return "${uri.scheme}://${uri.host}/" |
| | | } |
| | | } |
| New file |
| | |
| | | import android.content.Context |
| | | import android.webkit.CookieManager |
| | | import com.shsening.autouploadvideos.AppConfig |
| | | import org.json.JSONObject |
| | | |
| | | object CookieHelper2 { |
| | | private const val PREF_NAME = "CookieHelper" |
| | | |
| | | fun saveSessionProfileUrlCookies(context: Context, sessionProfileId: String, url: String, cookies: String) { |
| | | println("进来了"+cookies) |
| | | val sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) |
| | | val sessionCookiesMap = sharedPreferences.getString(sessionProfileId, "{}") |
| | | val sessionCookies = JSONObject(sessionCookiesMap!!) |
| | | sessionCookies.put(url, cookies) |
| | | sharedPreferences.edit().putString(sessionProfileId, sessionCookies.toString()).apply() |
| | | println("结束了") |
| | | } |
| | | |
| | | fun getAllSessionProfileCookies(context: Context, sessionProfileId: String): Map<String, String> { |
| | | val sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) |
| | | val sessionCookiesMap = sharedPreferences.getString(sessionProfileId, "{}") |
| | | val sessionCookies = JSONObject(sessionCookiesMap!!) |
| | | return sessionCookies.keys().asSequence().associateWith { sessionCookies.getString(it) } |
| | | } |
| | | |
| | | fun removeCookiesForUrl(url: String) { |
| | | val cookieManager = CookieManager.getInstance() |
| | | val cookies = cookieManager.getCookie(url) // 获取特定 URL 的所有 Cookie |
| | | if (cookies != null) { |
| | | val cookieArray = cookies.split(";") // 按分号分隔多个 Cookie |
| | | for (cookie in cookieArray) { |
| | | val cookieParts = cookie.split("=") |
| | | if (cookieParts.size > 0) { |
| | | val cookieName = cookieParts[0].trim() |
| | | // 设置一个过期的 Cookie 覆盖原来的 |
| | | cookieManager.setCookie(url, "$cookieName=; Expires=Thu, 01 Jan 1970 00:00:00 GMT") |
| | | } |
| | | } |
| | | // 确保将更改同步到存储中 |
| | | cookieManager.flush() |
| | | } |
| | | } |
| | | |
| | | fun removeCookieForAllPlatform(){ |
| | | AppConfig.SESSION_PROFILE_PALTFORM_LISTS.forEach { item -> |
| | | removeCookiesForUrl(item.url) |
| | | } |
| | | } |
| | | |
| | | fun saveSessionCookies(context: Context,sessionProfileId:String) { |
| | | var cookieManager = CookieManager.getInstance() |
| | | AppConfig.SESSION_PROFILE_PALTFORM_LISTS.forEach { item -> |
| | | val cookies = cookieManager.getCookie(item.url) |
| | | if (cookies != null) { |
| | | saveSessionProfileUrlCookies( |
| | | context, |
| | | sessionProfileId, |
| | | item.url, |
| | | cookies |
| | | ) |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | package com.shsening.autouploadvideos |
| | | |
| | | import CookieHelper |
| | | import CookieHelper.saveSessionProfileUrlCookies |
| | | import Profile |
| | | import SessionProfile |
| | | import SessionProfileManager |
| | |
| | | super.onCreate(savedInstanceState) |
| | | setContentView(R.layout.activity_session_profile) |
| | | activityReference = this |
| | | |
| | | // 获取传入的 SessionProfile |
| | | sessionProfile = intent.getSerializableExtra("sessionProfile") as? SessionProfile |
| | | ?: SessionProfile( |
| | |
| | | lastUploadTime = "", |
| | | profiles = mutableListOf() |
| | | ) |
| | | |
| | | if (sessionProfile.id == ""){ |
| | | isNewSessionProfile = true |
| | | sessionProfile.id = UUID.randomUUID().toString().replace("-", "") |
| | |
| | | }else { |
| | | findViewById<TextView>(R.id.txt_session_id).text = sessionProfile.id |
| | | } |
| | | |
| | | editName = findViewById(R.id.edit_name) |
| | | findViewById<TextView>(R.id.edit_name).text = sessionProfile.name |
| | | |
| | |
| | | CookieManager.getInstance().removeAllCookies(null) |
| | | CookieManager.getInstance().flush() |
| | | val sessionCookies = CookieHelper.getAllSessionProfileCookies(context, sessionProfileId) |
| | | println("这是session cookie"+sessionCookies) |
| | | for ((url, cookies) in sessionCookies) { |
| | | splitCookieStringAndSetCookie(url,cookies) |
| | | } |
| | |
| | | import com.shsening.autouploadvideos.action.ActionDouyin |
| | | import com.shsening.autouploadvideos.action.ActionKuaishou |
| | | import com.shsening.autouploadvideos.action.ActionShipinhao |
| | | import com.shsening.autouploadvideos.action.ActionRedbook |
| | | import com.shsening.autouploadvideos.utils.Utils |
| | | import kotlinx.coroutines.launch |
| | | import kotlinx.coroutines.runBlocking |
| | |
| | | |
| | | } |
| | | AppConfig.UPLOADSERVERTYPE_XIAOHONGSHU -> { |
| | | val actionXiaohongshu = |
| | | ActionRedbook(this, requireContext(), threadHandler, currentUploadVideoInfo) |
| | | actionXiaohongshu.checkIfContentLoaded() |
| | | |
| | | } |
| | | |
| | |
| | | package com.shsening.autouploadvideos |
| | | |
| | | import CookieHelper |
| | | import Profile |
| | | import CookieHelper2 |
| | | import SessionProfile |
| | | import SessionProfileManager |
| | | import android.app.Activity |
| | | import android.content.Intent |
| | | import android.graphics.Bitmap |
| | | import android.net.Uri |
| | | import android.os.Bundle |
| | | import android.os.Handler |
| | |
| | | import android.webkit.WebChromeClient |
| | | import android.webkit.WebView |
| | | import android.webkit.WebViewClient |
| | | import android.widget.ArrayAdapter |
| | | import android.widget.Button |
| | | import android.widget.EditText |
| | | import android.widget.LinearLayout |
| | | import android.widget.ProgressBar |
| | | import android.widget.Spinner |
| | | import android.widget.Switch |
| | | import android.widget.TextView |
| | | import android.widget.Toast |
| | | import androidx.appcompat.app.AppCompatActivity |
| | |
| | | import com.shsening.autouploadvideos.AppConfig.Companion.SESSION_PROFILE_PALTFORM_LISTS |
| | | import com.shsening.autouploadvideos.action.ActionDouyin |
| | | import com.shsening.autouploadvideos.action.ActionKuaishou |
| | | import com.shsening.autouploadvideos.action.ActionRedbook |
| | | import com.shsening.autouploadvideos.action.ActionShipinhao |
| | | import com.shsening.autouploadvideos.utils.DownloadHelper |
| | | import com.shsening.autouploadvideos.utils.DownloadReceiver |
| | | import com.shsening.autouploadvideos.utils.Utils |
| | | import kotlinx.coroutines.CoroutineScope |
| | | import kotlinx.coroutines.Dispatchers |
| | | import kotlinx.coroutines.launch |
| | | import okhttp3.Call |
| | | import okhttp3.Callback |
| | | import okhttp3.OkHttpClient |
| | | import okhttp3.Request |
| | | import okhttp3.Response |
| | | import org.json.JSONArray |
| | | import java.io.File |
| | | import java.io.IOException |
| | | import java.util.LinkedList |
| | | import java.util.Queue |
| | | import java.util.UUID |
| | | |
| | | |
| | | class UploadSessionActivity : AppCompatActivity() { |
| | | |
| | | private var RedbooklUrl: String? = "https://creator.xiaohongshu.com/publish/publish?from=menu" |
| | | private var DingyuehaolUrl: String? = null |
| | | private lateinit var sessionProfileManager: SessionProfileManager |
| | | lateinit var sessionProfileWebView:SessionProfileWebView |
| | | |
| | |
| | | override fun onPageStarted( |
| | | view: WebView?, |
| | | url: String?, |
| | | favicon: android.graphics.Bitmap? |
| | | favicon: Bitmap? |
| | | ) { |
| | | super.onPageStarted(view, url, favicon) |
| | | } |
| | | override fun onPageFinished(view: WebView?, url: String?) { |
| | | println("这是其他页面"+url) |
| | | super.onPageFinished(view, url) |
| | | view?.requestFocus() // 确保 WebView 获取焦点 |
| | | //inject action |
| | |
| | | package com.shsening.autouploadvideos |
| | | package com.shsening.autouploadvideos.action |
| | | |
| | | |
| | | import android.app.Instrumentation |
| | |
| | | package com.shsening.autouploadvideos |
| | | package com.shsening.autouploadvideos.action |
| | | |
| | | |
| | | import android.app.Instrumentation |
| | |
| | | import android.os.Bundle |
| | | import android.os.Looper |
| | | import androidx.appcompat.app.AppCompatActivity |
| | | import com.shsening.autouploadvideos.UploadSessionActivity |
| | | import com.shsening.autouploadvideos.WebviewUtils |
| | | import com.shsening.autouploadvideos.action.PlatformActionInterface |
| | | import com.shsening.autouploadvideos.utils.Utils |
| | | |
| | |
| | | private fun updatePostDescription(){ |
| | | WebviewUtils.addValueToInput(webView,"#publish-container > div > div.body > div.content > div.input.titleInput > div.d-input-wrapper.d-inline-block.c-input_inner > div > input",videoInfo.title) |
| | | WebviewUtils.addValueToDiv(webView,"#quillEditor > div > p",videoInfo.description) |
| | | WebviewUtils.simpleElementClick(webView,"#topicBtn") |
| | | SystemClock.sleep(500) |
| | | WebviewUtils.simpleElementClick(webView,"#quill-mention-item-0") |
| | | WebviewUtils.simpleElementClick(webView,"#topicBtn") |
| | | SystemClock.sleep(500) |
| | | WebviewUtils.simpleElementClick(webView,"#quill-mention-item-1") |
| | | |
| | | // WebviewUtils.simpleElementClick(webView,"#el-id-3410-26 > label:nth-child(1)") |
| | | WebviewUtils.simpleElementClick(webView,"html > body > div:nth-of-type(1) > div > div:nth-of-type(2) > div > div:nth-of-type(2) > main > div:nth-of-type(3) > div > div > div:nth-of-type(1) > div > div > div > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(10) > div > div:nth-of-type(5) > div:nth-of-type(2) > label:nth-of-type(2)") |
| | | addValueToDatePickerInput(true,"html > body > div:nth-of-type(1) > div > div:nth-of-type(2) > div > div:nth-of-type(2) > main > div:nth-of-type(3) > div > div > div:nth-of-type(1) > div > div > div > div:nth-of-type(2) > div:nth-of-type(1) > div:nth-of-type(1) > div:nth-of-type(10) > div > div:nth-of-type(5) > div:nth-of-type(2) > div > div:nth-of-type(1) > div",videoInfo.datetime) |
| | | // 在主线程中设置延迟执行 |
| | |
| | | webView.evaluateJavascript(jsCode_CheckVideoUploadFinished) { result -> |
| | | if (result == "true") { |
| | | // 等待视频检测和生成封面 |
| | | // WebviewUtils.simpleElementClick(webView,"#web > div > div > div > div.upload-content > div.upload-wrapper > div > input") |
| | | println("33333333333333333333333333333333333333") |
| | | threadHandler.postDelayed({updatePostDescription()},3000) |
| | | |
| | | } else { |
| | | println("11111111111111111111111") |
| | | // 元素不存在,1秒后再次检查 |
| | | webView.postDelayed({ |
| | | checkVideoUploadFinished() |
| | |
| | | } |
| | | }, 1000) // 每秒检查一次 |
| | | } |
| | | |
| | | private fun checkVideoPublishFinished(){ |
| | | webView.postDelayed({ |
| | | webView.evaluateJavascript(jsCode_PublishVideo_Finished) { result -> |
| | |
| | | val displayMetrics = activity.resources.displayMetrics |
| | | val width = displayMetrics.widthPixels |
| | | val height = displayMetrics.heightPixels |
| | | |
| | | val startX = width.toFloat() * 0.9f // 从右侧滑动 |
| | | val endX = width.toFloat() * 0.1f // 滑动到左侧 |
| | | val y = height / 3f // Y 坐标在屏幕中间 |
| | | |
| | | Thread { |
| | | Utils.instrumentationSwipe(instrumentation, startX, y, endX, y) |
| | | SystemClock.sleep(500) |
| | |
| | | SystemClock.sleep(500) |
| | | Utils.instrumentationClick(instrumentation, width / 2f, height * 2 / 4f) |
| | | // back to main thread |
| | | |
| | | threadHandler.post { |
| | | checkVideoUploadFinished() |
| | | } |
| | |
| | | * Title,description(including # and @ ) publish datetime etc |
| | | */ |
| | | private fun updatePostDescription(){ |
| | | WebviewUtils.addValueToInput(webView,"#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div:nth-child(8) > div.form-item-body.short-title-wrap > div > div > span > input",videoInfo.title) |
| | | WebviewUtils.addValueToDiv( |
| | | webView, |
| | | "#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div:nth-child(2) > div.form-item-body > div > div.input-editor", |
| | |
| | | // publish later radiobox |
| | | WebviewUtils.simpleElementClick( |
| | | webView, |
| | | "#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div.post-time-wrap > div:nth-child(1) > div.form-item-body > div > label:nth-child(2)" |
| | | "#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div.post-time-wrap > div > div.form-item-body > div > label:nth-child(2)" |
| | | ) |
| | | |
| | | addValueToDatePickerInput(true,"#container-wrap > div.container-center > div > div > div.main-body-wrap.post-create > div.main-body > div > div.post-edit-wrap.material-edit-wrap > div.form > div.post-time-wrap > div:nth-child(2) > div.form-item-body > dl > dd",videoInfo.datetime) |
| | |
| | | |
| | | |
| | | private fun addValueToDatePickerInput(first:Boolean, jsPath: String, targetValue: String) { |
| | | println(targetValue+"这是时间///////////") |
| | | |
| | | var datetimes = Utils.validateAndReturnDateTime(targetValue) ?: return |
| | | |
| New file |
| | |
| | | xsecappid=ugc; |
| | | a1=1939a580098qal8prsprpx71cj9rygo65cs0ame6n30000165115; |
| | | webId=3fe950abc269d8ccc08d8ab1a513b51e; |
| | | gid=yjqj02Yyqf2Kyjqj02Y88S6djYA01YUFMUFUMKICWySVj8q8FvklK0888yK2yy288YqdW84f; |
| | | customer-sso-sid=68c517445160666216132753128a94cf26ffda46; |
| | | x-user-id-creator.xiaohongshu.com=66f9208b000000001d0307a5; |
| | | customerClientId=496382327268371; |
| | | access-token-creator.xiaohongshu.com=customer.creator.AT-68c517446276627574625368zz58vqokvj20qob0; |
| | | galaxy_creator_session_id=NrzaB1vOCZl5RrtKdOBmW7Glu0Z9uQAz6uWh; |
| | | galaxy.creator.beaker.session.id=1733721380817008025744; |
| | | acw_tc=0a4a9a7a17337344438126430e8b239cf9bb9e8ccd29cd7c5128375c1e1baa; |
| | | websectiga=29098a4cf41f76ee3f8db19051aaa60c0fc7c5e305572fec762da32d457d76ae; |
| | | sec_poison_id=fc7e7662-9729-4ea2-80fe-0d9f21445919 |
| | | |
| | | |
| | | |
| | | |
| | | |
| | | xsecappid=ugc; |
| | | acw_tc=0a4a1d1e17338016839177906e1b35470f735fdbfbd6b1e5910b33b5940d03; |
| | | websectiga=2a3d3ea002e7d92b5c9743590ebd24010cf3710ff3af8029153751e41a6af4a3; |
| | | sec_poison_id=4a974805-0f17-4f34-aace-af303de48018; |
| | | gid=yjq0d0J4yKF4yjq000280M1SS8fvd3hv1Fl8VCI6D343T828yhSY0h888q8qq2Y8d8y20JqS |