Add extension: Animeunity (#1188)
Closes https://github.com/jmir1/aniyomi-extensions/issues/769
This commit is contained in:
2
src/it/animeunity/AndroidManifest.xml
Normal file
2
src/it/animeunity/AndroidManifest.xml
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest package="eu.kanade.tachiyomi.animeextension" />
|
13
src/it/animeunity/build.gradle
Normal file
13
src/it/animeunity/build.gradle
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
apply plugin: 'com.android.application'
|
||||||
|
apply plugin: 'kotlin-android'
|
||||||
|
apply plugin: 'kotlinx-serialization'
|
||||||
|
|
||||||
|
ext {
|
||||||
|
extName = 'AnimeUnity'
|
||||||
|
pkgNameSuffix = 'it.animeunity'
|
||||||
|
extClass = '.AnimeUnity'
|
||||||
|
extVersionCode = 1
|
||||||
|
libVersion = '13'
|
||||||
|
}
|
||||||
|
|
||||||
|
apply from: "$rootDir/common.gradle"
|
BIN
src/it/animeunity/res/mipmap-hdpi/ic_launcher.png
Normal file
BIN
src/it/animeunity/res/mipmap-hdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
BIN
src/it/animeunity/res/mipmap-mdpi/ic_launcher.png
Normal file
BIN
src/it/animeunity/res/mipmap-mdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.8 KiB |
BIN
src/it/animeunity/res/mipmap-xhdpi/ic_launcher.png
Normal file
BIN
src/it/animeunity/res/mipmap-xhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.4 KiB |
BIN
src/it/animeunity/res/mipmap-xxhdpi/ic_launcher.png
Normal file
BIN
src/it/animeunity/res/mipmap-xxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
BIN
src/it/animeunity/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
BIN
src/it/animeunity/res/mipmap-xxxhdpi/ic_launcher.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
src/it/animeunity/res/web_hi_res_512.png
Normal file
BIN
src/it/animeunity/res/web_hi_res_512.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
@ -0,0 +1,443 @@
|
|||||||
|
package eu.kanade.tachiyomi.animeextension.it.animeunity
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import androidx.preference.ListPreference
|
||||||
|
import androidx.preference.PreferenceScreen
|
||||||
|
import eu.kanade.tachiyomi.animesource.ConfigurableAnimeSource
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimesPage
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SAnime
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.SEpisode
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.Video
|
||||||
|
import eu.kanade.tachiyomi.animesource.online.AnimeHttpSource
|
||||||
|
import eu.kanade.tachiyomi.network.GET
|
||||||
|
import eu.kanade.tachiyomi.network.POST
|
||||||
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
|
import kotlinx.serialization.decodeFromString
|
||||||
|
import kotlinx.serialization.encodeToString
|
||||||
|
import kotlinx.serialization.json.Json
|
||||||
|
import okhttp3.Headers
|
||||||
|
import okhttp3.MediaType.Companion.toMediaType
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
|
import okhttp3.Response
|
||||||
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.lang.Exception
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
|
||||||
|
class AnimeUnity : ConfigurableAnimeSource, AnimeHttpSource() {
|
||||||
|
|
||||||
|
override val name = "AnimeUnity"
|
||||||
|
|
||||||
|
override val baseUrl = "https://www.animeunity.tv"
|
||||||
|
|
||||||
|
private val workerUrl = "https://scws.work"
|
||||||
|
|
||||||
|
override val lang = "it"
|
||||||
|
|
||||||
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
private val json: Json by injectLazy()
|
||||||
|
|
||||||
|
override val client: OkHttpClient = network.cloudflareClient
|
||||||
|
|
||||||
|
private val preferences: SharedPreferences by lazy {
|
||||||
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================== Popular ===============================
|
||||||
|
|
||||||
|
override fun popularAnimeParse(response: Response): AnimesPage {
|
||||||
|
val parsed = json.decodeFromString<AnimeResponse>(
|
||||||
|
response.body!!.string().substringAfter("top-anime animes=\"").substringBefore("\"></top-anime>").replace(""", "\"")
|
||||||
|
)
|
||||||
|
|
||||||
|
val animeList = parsed.data.map { ani ->
|
||||||
|
SAnime.create().apply {
|
||||||
|
title = ani.title_eng
|
||||||
|
url = "${ani.id}-${ani.slug}"
|
||||||
|
thumbnail_url = ani.imageurl ?: ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return AnimesPage(animeList, parsed.current_page < parsed.last_page)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun popularAnimeRequest(page: Int): Request = GET("$baseUrl/top-anime?popular=true&page=$page", headers = headers)
|
||||||
|
|
||||||
|
// =============================== Latest ===============================
|
||||||
|
|
||||||
|
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/?anime=$page", headers = headers)
|
||||||
|
|
||||||
|
override fun latestUpdatesParse(response: Response): AnimesPage {
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
val animeList = document.select("div.home-wrapper-body > div.row > div.latest-anime-container").map {
|
||||||
|
SAnime.create().apply {
|
||||||
|
title = it.select("a > strong").text()
|
||||||
|
url = it.selectFirst("a").attr("href").substringAfter("/anime/")
|
||||||
|
thumbnail_url = it.select("img").attr("src")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val hasNextPage = document.select("ul.pagination > li.active ~ li").first() != null
|
||||||
|
|
||||||
|
return AnimesPage(animeList, hasNextPage)
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================== Search ===============================
|
||||||
|
|
||||||
|
override fun fetchSearchAnime(page: Int, query: String, filters: AnimeFilterList): Observable<AnimesPage> {
|
||||||
|
val params = AnimeUnityFilters.getSearchParameters(filters)
|
||||||
|
return client.newCall(searchAnimeRequest(page, query, params))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
searchAnimeParse(response, page)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchAnimeRequest(page: Int, query: String, filters: AnimeFilterList): Request = throw Exception("Not used")
|
||||||
|
|
||||||
|
private fun searchAnimeRequest(page: Int, query: String, filters: AnimeUnityFilters.FilterSearchParams): Request {
|
||||||
|
val archivioResponse = client.newCall(
|
||||||
|
GET("$baseUrl/archivio", headers = headers)
|
||||||
|
).execute()
|
||||||
|
|
||||||
|
val document = archivioResponse.asJsoup()
|
||||||
|
|
||||||
|
val crsfToken = document.select("meta[name=csrf-token]").attr("content")
|
||||||
|
var newHeadersBuilder = headers.newBuilder()
|
||||||
|
for (cookie in archivioResponse.headers) {
|
||||||
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("XSRF-TOKEN")) {
|
||||||
|
newHeadersBuilder.add("X-XSRF-TOKEN", cookie.second.substringAfter("=").substringBefore(";").replace("%3D", "="))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("animeunity_session")) {
|
||||||
|
newHeadersBuilder.add("Cookie", cookie.second.substringBefore(";").replace("%3D", "="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newHeadersBuilder.add("X-CSRF-TOKEN", crsfToken)
|
||||||
|
.add("Accept-Language", "en-US,en;q=0.5")
|
||||||
|
.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0")
|
||||||
|
|
||||||
|
if (filters.top.isNotEmpty()) {
|
||||||
|
val topHeaders = newHeadersBuilder.add("X-CSRF-TOKEN", crsfToken)
|
||||||
|
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8")
|
||||||
|
.add("Referer", "$baseUrl/${filters.top}")
|
||||||
|
return GET("$baseUrl/${filters.top}", headers = topHeaders.build())
|
||||||
|
}
|
||||||
|
|
||||||
|
val searchHeaders = newHeadersBuilder
|
||||||
|
.add("Accept", "application/json, text/plain, */*")
|
||||||
|
.add("Content-Type", "application/json;charset=utf-8")
|
||||||
|
.add("Origin", baseUrl)
|
||||||
|
.add("Referer", archivioResponse.request.url.toString())
|
||||||
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
|
.build()
|
||||||
|
|
||||||
|
val body = """
|
||||||
|
{
|
||||||
|
"title": ${query.falseIfEmpty()},
|
||||||
|
"type": ${filters.type.falseIfEmpty()},
|
||||||
|
"year": ${filters.year.falseIfEmpty()},
|
||||||
|
"order": ${filters.order.falseIfEmpty()},
|
||||||
|
"status": ${filters.state.falseIfEmpty()},
|
||||||
|
"genres": ${filters.genre.ifEmpty { "false" }},
|
||||||
|
"offset": ${(page - 1) * 30},
|
||||||
|
"dubbed": ${if (filters.dub.isEmpty()) "false" else "true"},
|
||||||
|
"season": ${filters.season.falseIfEmpty()}
|
||||||
|
}
|
||||||
|
""".trimIndent().toRequestBody("application/json".toMediaType())
|
||||||
|
|
||||||
|
return POST("$baseUrl/archivio/get-animes", body = body, headers = searchHeaders)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun searchAnimeParse(response: Response): AnimesPage = throw Exception("Not used")
|
||||||
|
|
||||||
|
private fun searchAnimeParse(response: Response, page: Int): AnimesPage {
|
||||||
|
return if (response.request.method == "POST") {
|
||||||
|
val data = json.decodeFromString<SearchResponse>(
|
||||||
|
response.body!!.string()
|
||||||
|
)
|
||||||
|
|
||||||
|
val animeList = data.records.map {
|
||||||
|
SAnime.create().apply {
|
||||||
|
title = it.title_eng
|
||||||
|
thumbnail_url = it.imageurl
|
||||||
|
url = "${it.id}-${it.slug}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
AnimesPage(animeList, data.tot - page * 30 >= 30 && data.tot > 30)
|
||||||
|
} else {
|
||||||
|
popularAnimeParse(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getFilterList(): AnimeFilterList = AnimeUnityFilters.filterList
|
||||||
|
|
||||||
|
// =========================== Anime Details ============================
|
||||||
|
|
||||||
|
override fun animeDetailsRequest(anime: SAnime): Request {
|
||||||
|
return GET("$baseUrl/anime/${anime.url}")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun animeDetailsParse(response: Response): SAnime {
|
||||||
|
val anime = SAnime.create()
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
val videoPlayer = document.selectFirst("video-player[episodes_count]")
|
||||||
|
|
||||||
|
val animeDetails = json.decodeFromString<AnimeInfo>(
|
||||||
|
videoPlayer.attr("anime").replace(""", "\"")
|
||||||
|
)
|
||||||
|
|
||||||
|
anime.title = animeDetails.title_eng
|
||||||
|
anime.status = parseStatus(animeDetails.status)
|
||||||
|
anime.artist = animeDetails.studio
|
||||||
|
anime.genre = animeDetails.genres.joinToString(", ") { it.name }
|
||||||
|
|
||||||
|
var description = animeDetails.plot + "\n"
|
||||||
|
|
||||||
|
description += "\nTipo: ${animeDetails.type}"
|
||||||
|
description += "\nStagione: ${animeDetails.season} ${animeDetails.date}"
|
||||||
|
description += "\nValutazione: ★${animeDetails.score ?: "-"}"
|
||||||
|
|
||||||
|
anime.description = description
|
||||||
|
|
||||||
|
return anime
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================== Episodes ==============================
|
||||||
|
|
||||||
|
override fun episodeListRequest(anime: SAnime): Request {
|
||||||
|
return GET("$baseUrl/anime/${anime.url}", headers = headers)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun episodeListParse(response: Response): List<SEpisode> {
|
||||||
|
val episodeList = mutableListOf<SEpisode>()
|
||||||
|
val document = response.asJsoup()
|
||||||
|
|
||||||
|
val crsfToken = document.select("meta[name=csrf-token]").attr("content")
|
||||||
|
var newHeadersBuilder = headers.newBuilder()
|
||||||
|
for (cookie in response.headers) {
|
||||||
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("XSRF-TOKEN")) {
|
||||||
|
newHeadersBuilder.add("X-XSRF-TOKEN", cookie.second.substringAfter("=").substringBefore(";").replace("%3D", "="))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cookie.first == "set-cookie" && cookie.second.startsWith("animeunity_session")) {
|
||||||
|
newHeadersBuilder.add("Cookie", cookie.second.substringBefore(";").replace("%3D", "="))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
newHeadersBuilder.add("X-CSRF-TOKEN", crsfToken)
|
||||||
|
.add("Content-Type", "application/json")
|
||||||
|
.add("Referer", response.request.url.toString())
|
||||||
|
.add("Accept", "application/json, text/plain, */*")
|
||||||
|
.add("Accept-Language", "en-US,en;q=0.5")
|
||||||
|
.add("X-Requested-With", "XMLHttpRequest")
|
||||||
|
val newHeaders = newHeadersBuilder.build()
|
||||||
|
|
||||||
|
val videoPlayer = document.selectFirst("video-player[episodes_count]")
|
||||||
|
val episodeCount = videoPlayer.attr("episodes_count").toInt()
|
||||||
|
val animeId = response.request.url.toString().substringAfter("/anime/").substringBefore("-")
|
||||||
|
|
||||||
|
val episodes = json.decodeFromString<List<Episode>>(
|
||||||
|
videoPlayer.attr("episodes").replace(""", "\"")
|
||||||
|
)
|
||||||
|
|
||||||
|
episodeList.addAll(
|
||||||
|
episodes.filter {
|
||||||
|
it.scws_id != null && it.file_name != null
|
||||||
|
}.map {
|
||||||
|
SEpisode.create().apply {
|
||||||
|
name = "Episode ${it.number}"
|
||||||
|
url = LinkData(it.scws_id.toString(), it.file_name!!).toJsonString()
|
||||||
|
date_upload = parseDate(it.created_at)
|
||||||
|
episode_number = it.number.split("-")[0].toFloatOrNull() ?: 0F
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if (episodeCount > 120) {
|
||||||
|
var start = 121
|
||||||
|
var end = 240
|
||||||
|
|
||||||
|
while (end < episodeCount) {
|
||||||
|
episodeList.addAll(
|
||||||
|
addFromApi(start, end, animeId, newHeaders)
|
||||||
|
)
|
||||||
|
start += 120
|
||||||
|
end += 120
|
||||||
|
}
|
||||||
|
|
||||||
|
if (episodeCount >= start) {
|
||||||
|
episodeList.addAll(
|
||||||
|
addFromApi(start, episodeCount, animeId, newHeaders)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return episodeList.sortedBy { it.episode_number }.reversed()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ============================ Video Links =============================
|
||||||
|
|
||||||
|
override fun fetchVideoList(episode: SEpisode): Observable<List<Video>> {
|
||||||
|
val newHeaders = Headers.headersOf(
|
||||||
|
"Accept", "*/*",
|
||||||
|
"Accept-Language", "en-US,en;q=0.5",
|
||||||
|
"Host", "scws.work",
|
||||||
|
"Origin", baseUrl,
|
||||||
|
"Referer", "$baseUrl/",
|
||||||
|
"User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:101.0) Gecko/20100101 Firefox/101.0"
|
||||||
|
)
|
||||||
|
|
||||||
|
val mediaId = json.decodeFromString<LinkData>(episode.url)
|
||||||
|
val videoList = mutableListOf<Video>()
|
||||||
|
|
||||||
|
val serverJson = json.decodeFromString<ServerResponse>(
|
||||||
|
client.newCall(GET("https://scws.work/videos/${mediaId.id}", headers = newHeaders)).execute().body!!.string()
|
||||||
|
)
|
||||||
|
|
||||||
|
val appJs = client.newCall(GET("$baseUrl/js/app.js", headers = headers)).execute().body!!.string()
|
||||||
|
|
||||||
|
val tokenRegex = """(\d+),(?:\w+)\.client_ip,"(\w+)"""".toRegex()
|
||||||
|
val (multiplier, key) = tokenRegex.find(appJs)!!.destructured
|
||||||
|
|
||||||
|
val pKeyRegex = """(\d+),u,"(\w+)"""".toRegex()
|
||||||
|
val (pMultiplier, pKey) = pKeyRegex.find(appJs)!!.destructured
|
||||||
|
|
||||||
|
val playListToken = getToken(multiplier.toInt(), serverJson.client_ip, key)
|
||||||
|
val downloadToken = getToken(pMultiplier.toInt(), serverJson.client_ip, pKey)
|
||||||
|
|
||||||
|
val masterPlaylist = client.newCall(
|
||||||
|
GET("$workerUrl/master/${mediaId.id}?token=$playListToken", headers = headers)
|
||||||
|
).execute().body!!.string()
|
||||||
|
|
||||||
|
val qualities = mutableListOf<String>()
|
||||||
|
masterPlaylist.substringAfter("#EXT-X-STREAM-INF:").split("#EXT-X-STREAM-INF:").forEach {
|
||||||
|
qualities.add(
|
||||||
|
it.substringAfter("\n").substringBefore("\n").substringBefore("p/").substringAfterLast("/")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
qualities.forEach {
|
||||||
|
val url = "https://au-d1-0" +
|
||||||
|
serverJson.proxy_download +
|
||||||
|
".scws-content.net/download/" +
|
||||||
|
serverJson.storage_download.number +
|
||||||
|
"/" +
|
||||||
|
serverJson.folder_id +
|
||||||
|
"/" +
|
||||||
|
it +
|
||||||
|
"p.mp4?token=" +
|
||||||
|
downloadToken +
|
||||||
|
"&filename=" +
|
||||||
|
mediaId.file_name.replace("&", ".")
|
||||||
|
videoList.add(
|
||||||
|
Video(
|
||||||
|
"https://au-d1-0${serverJson.proxy_download}.scws-content.net",
|
||||||
|
"${it}p",
|
||||||
|
url,
|
||||||
|
headers = headers
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Observable.just(videoList.sort())
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun videoListRequest(episode: SEpisode): Request = throw Exception("Not used")
|
||||||
|
|
||||||
|
override fun videoListParse(response: Response): List<Video> = throw Exception("Not used")
|
||||||
|
|
||||||
|
// ============================= Utilities ==============================
|
||||||
|
|
||||||
|
private fun parseStatus(statusString: String): Int {
|
||||||
|
return when (statusString) {
|
||||||
|
"In Corso" -> SAnime.ONGOING
|
||||||
|
"Terminato" -> SAnime.COMPLETED
|
||||||
|
else -> SAnime.UNKNOWN
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun addFromApi(start: Int, end: Int, animeId: String, headers: Headers): List<SEpisode> {
|
||||||
|
val response = client.newCall(
|
||||||
|
GET("$baseUrl/info_api/$animeId/1?start_range=$start&end_range=$end", headers = headers)
|
||||||
|
).execute()
|
||||||
|
val json = json.decodeFromString<ApiResponse>(response.body!!.string())
|
||||||
|
return json.episodes.filter {
|
||||||
|
it.scws_id != null && it.file_name != null
|
||||||
|
}.map {
|
||||||
|
SEpisode.create().apply {
|
||||||
|
name = "Episode ${it.number}"
|
||||||
|
url = LinkData(it.scws_id.toString(), it.file_name!!).toJsonString()
|
||||||
|
date_upload = parseDate(it.created_at)
|
||||||
|
episode_number = it.number.split("-")[0].toFloatOrNull() ?: 0F
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.falseIfEmpty(): String {
|
||||||
|
return if (this.isEmpty()) {
|
||||||
|
"false"
|
||||||
|
} else {
|
||||||
|
"\"${this}\""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun LinkData.toJsonString(): String {
|
||||||
|
return json.encodeToString(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("SimpleDateFormat")
|
||||||
|
private fun parseDate(date: String): Long {
|
||||||
|
val knownPatterns: MutableList<SimpleDateFormat> = ArrayList()
|
||||||
|
knownPatterns.add(SimpleDateFormat("yyyy-MM-dd hh:mm:ss"))
|
||||||
|
|
||||||
|
for (pattern in knownPatterns) {
|
||||||
|
try {
|
||||||
|
// Take a try
|
||||||
|
return pattern.parse(date)!!.time
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
// Loop on
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return System.currentTimeMillis()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun List<Video>.sort(): List<Video> {
|
||||||
|
val quality = preferences.getString("preferred_quality", "1080")!!
|
||||||
|
|
||||||
|
return this.sortedWith(
|
||||||
|
compareBy { it.quality.contains(quality) }
|
||||||
|
).reversed()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
|
val videoQualityPref = ListPreference(screen.context).apply {
|
||||||
|
key = "preferred_quality"
|
||||||
|
title = "Preferred quality"
|
||||||
|
entries = arrayOf("1080p", "720p", "480p", "360p", "240p", "80p")
|
||||||
|
entryValues = arrayOf("1080", "720", "480", "360", "240", "80")
|
||||||
|
setDefaultValue("1080")
|
||||||
|
summary = "%s"
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val selected = newValue as String
|
||||||
|
val index = findIndexOfValue(selected)
|
||||||
|
val entry = entryValues[index] as String
|
||||||
|
preferences.edit().putString(key, entry).commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPreference(videoQualityPref)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,204 @@
|
|||||||
|
package eu.kanade.tachiyomi.animeextension.it.animeunity
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilter
|
||||||
|
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList
|
||||||
|
|
||||||
|
object AnimeUnityFilters {
|
||||||
|
|
||||||
|
open class QueryPartFilter(
|
||||||
|
displayName: String,
|
||||||
|
val vals: Array<Pair<String, String>>
|
||||||
|
) : AnimeFilter.Select<String>(
|
||||||
|
displayName,
|
||||||
|
vals.map { it.first }.toTypedArray()
|
||||||
|
) {
|
||||||
|
fun toQueryPart() = vals[state].second
|
||||||
|
}
|
||||||
|
|
||||||
|
open class CheckBoxFilterList(name: String, values: List<CheckBox>) : AnimeFilter.Group<AnimeFilter.CheckBox>(name, values)
|
||||||
|
private class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state)
|
||||||
|
|
||||||
|
private inline fun <reified R> AnimeFilterList.asQueryPart(): String {
|
||||||
|
return this.filterIsInstance<R>().joinToString("") {
|
||||||
|
(it as QueryPartFilter).toQueryPart()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TopFilter : QueryPartFilter("Top Anime", AnimeUnityFiltersData.top)
|
||||||
|
|
||||||
|
class GenreFilter : CheckBoxFilterList(
|
||||||
|
"Genere",
|
||||||
|
AnimeUnityFiltersData.genere.map { CheckBoxVal(it.first, false) }
|
||||||
|
)
|
||||||
|
|
||||||
|
class YearFilter : QueryPartFilter("Anno", AnimeUnityFiltersData.year)
|
||||||
|
|
||||||
|
class OrderFilter : QueryPartFilter("Ordina", AnimeUnityFiltersData.order)
|
||||||
|
|
||||||
|
class StateFilter : QueryPartFilter("Stato", AnimeUnityFiltersData.state)
|
||||||
|
|
||||||
|
class TypeFilter : QueryPartFilter("Tipo", AnimeUnityFiltersData.type)
|
||||||
|
|
||||||
|
class SeasonFilter : QueryPartFilter("Stagione", AnimeUnityFiltersData.season)
|
||||||
|
|
||||||
|
class DubFilter : QueryPartFilter("Dub ITA", AnimeUnityFiltersData.dub)
|
||||||
|
|
||||||
|
val filterList = AnimeFilterList(
|
||||||
|
AnimeFilter.Header("Le migliori pagine di anime"),
|
||||||
|
AnimeFilter.Header("Nota: ignora altri filtri"),
|
||||||
|
TopFilter(),
|
||||||
|
AnimeFilter.Separator(),
|
||||||
|
GenreFilter(),
|
||||||
|
YearFilter(),
|
||||||
|
OrderFilter(),
|
||||||
|
StateFilter(),
|
||||||
|
TypeFilter(),
|
||||||
|
SeasonFilter(),
|
||||||
|
DubFilter()
|
||||||
|
)
|
||||||
|
|
||||||
|
data class FilterSearchParams(
|
||||||
|
val top: String = "",
|
||||||
|
val genre: String = "",
|
||||||
|
val year: String = "",
|
||||||
|
val order: String = "",
|
||||||
|
val state: String = "",
|
||||||
|
val type: String = "",
|
||||||
|
val season: String = "",
|
||||||
|
val dub: String = ""
|
||||||
|
)
|
||||||
|
|
||||||
|
internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
|
||||||
|
if (filters.isEmpty()) return FilterSearchParams()
|
||||||
|
|
||||||
|
val genre: String = filters.filterIsInstance<GenreFilter>()
|
||||||
|
.first()
|
||||||
|
.state.mapNotNull { format ->
|
||||||
|
if (format.state) {
|
||||||
|
"{\"id\":" +
|
||||||
|
AnimeUnityFiltersData.genere.find { it.first == format.name }!!.second +
|
||||||
|
",\"name\":\"" +
|
||||||
|
AnimeUnityFiltersData.genere.find { it.first == format.name }!!.first +
|
||||||
|
"\"}"
|
||||||
|
} else { null }
|
||||||
|
}.joinToString(",")
|
||||||
|
|
||||||
|
return FilterSearchParams(
|
||||||
|
filters.asQueryPart<TopFilter>(),
|
||||||
|
if (genre.isEmpty()) "" else "[$genre]",
|
||||||
|
filters.asQueryPart<YearFilter>(),
|
||||||
|
filters.asQueryPart<OrderFilter>(),
|
||||||
|
filters.asQueryPart<StateFilter>(),
|
||||||
|
filters.asQueryPart<TypeFilter>(),
|
||||||
|
filters.asQueryPart<SeasonFilter>(),
|
||||||
|
filters.asQueryPart<DubFilter>(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private object AnimeUnityFiltersData {
|
||||||
|
val any = Pair("Any", "")
|
||||||
|
|
||||||
|
val top = arrayOf(
|
||||||
|
Pair("Nessuno", ""),
|
||||||
|
Pair("Tutto", "top-anime"),
|
||||||
|
Pair("In corso", "top-anime?status=In Corso"),
|
||||||
|
Pair("In arrivo", "top-anime?status=In uscita prossimamente"),
|
||||||
|
Pair("TV", "top-anime?type=TV"),
|
||||||
|
Pair("Movie", "top-anime?type=Movie"),
|
||||||
|
Pair("OVA", "top-anime?type=OVA"),
|
||||||
|
Pair("ONA", "top-anime?type=ONA"),
|
||||||
|
Pair("Special", "top-anime?type=Special"),
|
||||||
|
Pair("Popolari", "top-anime?popular=true"),
|
||||||
|
Pair("Preferiti", "top-anime?order=favorites"),
|
||||||
|
Pair("Più visti", "top-anime?order=most_viewed")
|
||||||
|
)
|
||||||
|
|
||||||
|
val genere = arrayOf(
|
||||||
|
Pair("Action", "51"),
|
||||||
|
Pair("Adventure", "21"),
|
||||||
|
Pair("Cars", "29"),
|
||||||
|
Pair("Comedy", "37"),
|
||||||
|
Pair("Dementia", "43"),
|
||||||
|
Pair("Demons", "13"),
|
||||||
|
Pair("Drama", "22"),
|
||||||
|
Pair("Ecchi", "5"),
|
||||||
|
Pair("Fantasy", "9"),
|
||||||
|
Pair("Game", "44"),
|
||||||
|
Pair("Harem", "15"),
|
||||||
|
Pair("Hentai", "4"),
|
||||||
|
Pair("Historical", "30"),
|
||||||
|
Pair("Horror", "3"),
|
||||||
|
Pair("Josei", "45"),
|
||||||
|
Pair("Kids", "14"),
|
||||||
|
Pair("Magic", "23"),
|
||||||
|
Pair("Martial Arts", "Martial 31"),
|
||||||
|
Pair("Mecha", "38"),
|
||||||
|
Pair("Military", "46"),
|
||||||
|
Pair("Music", "16"),
|
||||||
|
Pair("Mystery", "24"),
|
||||||
|
Pair("Parody", "32"),
|
||||||
|
Pair("Police", "39"),
|
||||||
|
Pair("Psychological", "47"),
|
||||||
|
Pair("Romance", "17"),
|
||||||
|
Pair("Samurai", "25"),
|
||||||
|
Pair("School", "33"),
|
||||||
|
Pair("Sci-fi", "Sci-40"),
|
||||||
|
Pair("Seinen", "49"),
|
||||||
|
Pair("Shoujo", "18"),
|
||||||
|
Pair("Shoujo Ai", "Shoujo 26"),
|
||||||
|
Pair("Shounen", "34"),
|
||||||
|
Pair("Shounen Ai", "Shounen 41"),
|
||||||
|
Pair("Slice of Life", "Slice of 50"),
|
||||||
|
Pair("Space", "19"),
|
||||||
|
Pair("Splatter", "52"),
|
||||||
|
Pair("Sports", "27"),
|
||||||
|
Pair("Super Power", "Super 35"),
|
||||||
|
Pair("Supernatural", "42"),
|
||||||
|
Pair("Thriller", "48"),
|
||||||
|
Pair("Vampire", "20"),
|
||||||
|
Pair("Yaoi", "28"),
|
||||||
|
Pair("Yuri", "36")
|
||||||
|
)
|
||||||
|
|
||||||
|
val order = arrayOf(
|
||||||
|
any,
|
||||||
|
Pair("Lista A-Z", "Lista A-Z"),
|
||||||
|
Pair("Lista Z-A", "Lista Z-A"),
|
||||||
|
Pair("Valutazione", "Valutazione"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val state = arrayOf(
|
||||||
|
any,
|
||||||
|
Pair("In Corso", "In Corso"),
|
||||||
|
Pair("Terminato", "Terminato"),
|
||||||
|
Pair("In Uscita", "In Uscita"),
|
||||||
|
Pair("Droppato", "Droppato"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val type = arrayOf(
|
||||||
|
any,
|
||||||
|
Pair("TV", "TV"),
|
||||||
|
Pair("OVA", "OVA"),
|
||||||
|
Pair("ONA", "ONA"),
|
||||||
|
Pair("Special", "Special"),
|
||||||
|
Pair("Movie", "Movie"),
|
||||||
|
)
|
||||||
|
|
||||||
|
val season = arrayOf(
|
||||||
|
any,
|
||||||
|
Pair("Inverno", "Inverno"),
|
||||||
|
Pair("Primavera", "Primavera"),
|
||||||
|
Pair("Estate", "Estate"),
|
||||||
|
Pair("Autunno", "Autunno")
|
||||||
|
)
|
||||||
|
|
||||||
|
val dub = arrayOf(
|
||||||
|
Pair("No", ""),
|
||||||
|
Pair("Sì", "true")
|
||||||
|
)
|
||||||
|
|
||||||
|
val year = arrayOf(any) + (1969..2024).map {
|
||||||
|
Pair(it.toString(), it.toString())
|
||||||
|
}.reversed().toTypedArray()
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,78 @@
|
|||||||
|
package eu.kanade.tachiyomi.animeextension.it.animeunity
|
||||||
|
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AnimeResponse(
|
||||||
|
val current_page: Int,
|
||||||
|
val last_page: Int,
|
||||||
|
val data: List<Anime>
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class Anime(
|
||||||
|
val id: Int,
|
||||||
|
val slug: String,
|
||||||
|
val title_eng: String,
|
||||||
|
val imageurl: String? = null,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class Episode(
|
||||||
|
val number: String,
|
||||||
|
val created_at: String,
|
||||||
|
val scws_id: Int? = null,
|
||||||
|
val file_name: String? = null,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ApiResponse(
|
||||||
|
val episodes: List<Episode>
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class ServerResponse(
|
||||||
|
val name: String,
|
||||||
|
val client_ip: String,
|
||||||
|
val folder_id: String,
|
||||||
|
val proxy_download: Int,
|
||||||
|
val storage_download: StorageDownload
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class StorageDownload(
|
||||||
|
val number: Int
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class LinkData(
|
||||||
|
val id: String,
|
||||||
|
val file_name: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class AnimeInfo(
|
||||||
|
val title_eng: String,
|
||||||
|
val imageurl: String,
|
||||||
|
val plot: String,
|
||||||
|
val date: String,
|
||||||
|
val season: String,
|
||||||
|
val slug: String,
|
||||||
|
val id: Int,
|
||||||
|
val type: String,
|
||||||
|
val status: String,
|
||||||
|
val studio: String,
|
||||||
|
val genres: List<Genre>,
|
||||||
|
val score: String? = null,
|
||||||
|
) {
|
||||||
|
@Serializable
|
||||||
|
data class Genre(
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
data class SearchResponse(
|
||||||
|
val records: List<AnimeInfo>,
|
||||||
|
val tot: Int
|
||||||
|
)
|
@ -0,0 +1,760 @@
|
|||||||
|
package eu.kanade.tachiyomi.animeextension.it.animeunity
|
||||||
|
|
||||||
|
import app.cash.quickjs.QuickJs
|
||||||
|
import kotlin.math.roundToLong
|
||||||
|
|
||||||
|
fun getToken(multiplier: Int, ipAdress: String, key: String): String {
|
||||||
|
val quickJs = QuickJs.create()
|
||||||
|
val expires = (System.currentTimeMillis() + 3600000 * multiplier / 1000.0).roundToLong().toString()
|
||||||
|
val r = "$expires$ipAdress $key"
|
||||||
|
val token = quickJs.evaluate(encodeString(r)).toString() + "&expires=" + expires
|
||||||
|
quickJs.close()
|
||||||
|
return token
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun encodeString(string: String) = """
|
||||||
|
/*
|
||||||
|
CryptoJS v3.1.2
|
||||||
|
code.google.com/p/crypto-js
|
||||||
|
(c) 2009-2013 by Jeff Mott. All rights reserved.
|
||||||
|
code.google.com/p/crypto-js/wiki/License
|
||||||
|
*/
|
||||||
|
var CryptoJS = CryptoJS || function(u, p) {
|
||||||
|
var d = {},
|
||||||
|
l = d.lib = {},
|
||||||
|
s = function() {},
|
||||||
|
t = l.Base = {
|
||||||
|
extend: function(a) {
|
||||||
|
s.prototype = this;
|
||||||
|
var c = new s;
|
||||||
|
a && c.mixIn(a);
|
||||||
|
c.hasOwnProperty("init") || (c.init = function() {
|
||||||
|
c.${'$'}super.init.apply(this, arguments)
|
||||||
|
});
|
||||||
|
c.init.prototype = c;
|
||||||
|
c.${'$'}super = this;
|
||||||
|
return c
|
||||||
|
},
|
||||||
|
create: function() {
|
||||||
|
var a = this.extend();
|
||||||
|
a.init.apply(a, arguments);
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
init: function() {},
|
||||||
|
mixIn: function(a) {
|
||||||
|
for (var c in a) a.hasOwnProperty(c) && (this[c] = a[c]);
|
||||||
|
a.hasOwnProperty("toString") && (this.toString = a.toString)
|
||||||
|
},
|
||||||
|
clone: function() {
|
||||||
|
return this.init.prototype.extend(this)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
r = l.WordArray = t.extend({
|
||||||
|
init: function(a, c) {
|
||||||
|
a = this.words = a || [];
|
||||||
|
this.sigBytes = c != p ? c : 4 * a.length
|
||||||
|
},
|
||||||
|
toString: function(a) {
|
||||||
|
return (a || v).stringify(this)
|
||||||
|
},
|
||||||
|
concat: function(a) {
|
||||||
|
var c = this.words,
|
||||||
|
e = a.words,
|
||||||
|
j = this.sigBytes;
|
||||||
|
a = a.sigBytes;
|
||||||
|
this.clamp();
|
||||||
|
if (j % 4)
|
||||||
|
for (var k = 0; k < a; k++) c[j + k >>> 2] |= (e[k >>> 2] >>> 24 - 8 * (k % 4) & 255) << 24 - 8 * ((j + k) % 4);
|
||||||
|
else if (65535 < e.length)
|
||||||
|
for (k = 0; k < a; k += 4) c[j + k >>> 2] = e[k >>> 2];
|
||||||
|
else c.push.apply(c, e);
|
||||||
|
this.sigBytes += a;
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
clamp: function() {
|
||||||
|
var a = this.words,
|
||||||
|
c = this.sigBytes;
|
||||||
|
a[c >>> 2] &= 4294967295 <<
|
||||||
|
32 - 8 * (c % 4);
|
||||||
|
a.length = u.ceil(c / 4)
|
||||||
|
},
|
||||||
|
clone: function() {
|
||||||
|
var a = t.clone.call(this);
|
||||||
|
a.words = this.words.slice(0);
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
random: function(a) {
|
||||||
|
for (var c = [], e = 0; e < a; e += 4) c.push(4294967296 * u.random() | 0);
|
||||||
|
return new r.init(c, a)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
w = d.enc = {},
|
||||||
|
v = w.Hex = {
|
||||||
|
stringify: function(a) {
|
||||||
|
var c = a.words;
|
||||||
|
a = a.sigBytes;
|
||||||
|
for (var e = [], j = 0; j < a; j++) {
|
||||||
|
var k = c[j >>> 2] >>> 24 - 8 * (j % 4) & 255;
|
||||||
|
e.push((k >>> 4).toString(16));
|
||||||
|
e.push((k & 15).toString(16))
|
||||||
|
}
|
||||||
|
return e.join("")
|
||||||
|
},
|
||||||
|
parse: function(a) {
|
||||||
|
for (var c = a.length, e = [], j = 0; j < c; j += 2) e[j >>> 3] |= parseInt(a.substr(j,
|
||||||
|
2), 16) << 24 - 4 * (j % 8);
|
||||||
|
return new r.init(e, c / 2)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
b = w.Latin1 = {
|
||||||
|
stringify: function(a) {
|
||||||
|
var c = a.words;
|
||||||
|
a = a.sigBytes;
|
||||||
|
for (var e = [], j = 0; j < a; j++) e.push(String.fromCharCode(c[j >>> 2] >>> 24 - 8 * (j % 4) & 255));
|
||||||
|
return e.join("")
|
||||||
|
},
|
||||||
|
parse: function(a) {
|
||||||
|
for (var c = a.length, e = [], j = 0; j < c; j++) e[j >>> 2] |= (a.charCodeAt(j) & 255) << 24 - 8 * (j % 4);
|
||||||
|
return new r.init(e, c)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
x = w.Utf8 = {
|
||||||
|
stringify: function(a) {
|
||||||
|
try {
|
||||||
|
return decodeURIComponent(escape(b.stringify(a)))
|
||||||
|
} catch (c) {
|
||||||
|
throw Error("Malformed UTF-8 data");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
parse: function(a) {
|
||||||
|
return b.parse(unescape(encodeURIComponent(a)))
|
||||||
|
}
|
||||||
|
},
|
||||||
|
q = l.BufferedBlockAlgorithm = t.extend({
|
||||||
|
reset: function() {
|
||||||
|
this._data = new r.init;
|
||||||
|
this._nDataBytes = 0
|
||||||
|
},
|
||||||
|
_append: function(a) {
|
||||||
|
"string" == typeof a && (a = x.parse(a));
|
||||||
|
this._data.concat(a);
|
||||||
|
this._nDataBytes += a.sigBytes
|
||||||
|
},
|
||||||
|
_process: function(a) {
|
||||||
|
var c = this._data,
|
||||||
|
e = c.words,
|
||||||
|
j = c.sigBytes,
|
||||||
|
k = this.blockSize,
|
||||||
|
b = j / (4 * k),
|
||||||
|
b = a ? u.ceil(b) : u.max((b | 0) - this._minBufferSize, 0);
|
||||||
|
a = b * k;
|
||||||
|
j = u.min(4 * a, j);
|
||||||
|
if (a) {
|
||||||
|
for (var q = 0; q < a; q += k) this._doProcessBlock(e, q);
|
||||||
|
q = e.splice(0, a);
|
||||||
|
c.sigBytes -= j
|
||||||
|
}
|
||||||
|
return new r.init(q, j)
|
||||||
|
},
|
||||||
|
clone: function() {
|
||||||
|
var a = t.clone.call(this);
|
||||||
|
a._data = this._data.clone();
|
||||||
|
return a
|
||||||
|
},
|
||||||
|
_minBufferSize: 0
|
||||||
|
});
|
||||||
|
l.Hasher = q.extend({
|
||||||
|
cfg: t.extend(),
|
||||||
|
init: function(a) {
|
||||||
|
this.cfg = this.cfg.extend(a);
|
||||||
|
this.reset()
|
||||||
|
},
|
||||||
|
reset: function() {
|
||||||
|
q.reset.call(this);
|
||||||
|
this._doReset()
|
||||||
|
},
|
||||||
|
update: function(a) {
|
||||||
|
this._append(a);
|
||||||
|
this._process();
|
||||||
|
return this
|
||||||
|
},
|
||||||
|
finalize: function(a) {
|
||||||
|
a && this._append(a);
|
||||||
|
return this._doFinalize()
|
||||||
|
},
|
||||||
|
blockSize: 16,
|
||||||
|
_createHelper: function(a) {
|
||||||
|
return function(b, e) {
|
||||||
|
return (new a.init(e)).finalize(b)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
_createHmacHelper: function(a) {
|
||||||
|
return function(b, e) {
|
||||||
|
return (new n.HMAC.init(a,
|
||||||
|
e)).finalize(b)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
var n = d.algo = {};
|
||||||
|
return d
|
||||||
|
}(Math);
|
||||||
|
(function() {
|
||||||
|
var u = CryptoJS,
|
||||||
|
p = u.lib.WordArray;
|
||||||
|
u.enc.Base64 = {
|
||||||
|
stringify: function(d) {
|
||||||
|
var l = d.words,
|
||||||
|
p = d.sigBytes,
|
||||||
|
t = this._map;
|
||||||
|
d.clamp();
|
||||||
|
d = [];
|
||||||
|
for (var r = 0; r < p; r += 3)
|
||||||
|
for (var w = (l[r >>> 2] >>> 24 - 8 * (r % 4) & 255) << 16 | (l[r + 1 >>> 2] >>> 24 - 8 * ((r + 1) % 4) & 255) << 8 | l[r + 2 >>> 2] >>> 24 - 8 * ((r + 2) % 4) & 255, v = 0; 4 > v && r + 0.75 * v < p; v++) d.push(t.charAt(w >>> 6 * (3 - v) & 63));
|
||||||
|
if (l = t.charAt(64))
|
||||||
|
for (; d.length % 4;) d.push(l);
|
||||||
|
return d.join("")
|
||||||
|
},
|
||||||
|
parse: function(d) {
|
||||||
|
var l = d.length,
|
||||||
|
s = this._map,
|
||||||
|
t = s.charAt(64);
|
||||||
|
t && (t = d.indexOf(t), -1 != t && (l = t));
|
||||||
|
for (var t = [], r = 0, w = 0; w <
|
||||||
|
l; w++)
|
||||||
|
if (w % 4) {
|
||||||
|
var v = s.indexOf(d.charAt(w - 1)) << 2 * (w % 4),
|
||||||
|
b = s.indexOf(d.charAt(w)) >>> 6 - 2 * (w % 4);
|
||||||
|
t[r >>> 2] |= (v | b) << 24 - 8 * (r % 4);
|
||||||
|
r++
|
||||||
|
} return p.create(t, r)
|
||||||
|
},
|
||||||
|
_map: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
(function(u) {
|
||||||
|
function p(b, n, a, c, e, j, k) {
|
||||||
|
b = b + (n & a | ~n & c) + e + k;
|
||||||
|
return (b << j | b >>> 32 - j) + n
|
||||||
|
}
|
||||||
|
|
||||||
|
function d(b, n, a, c, e, j, k) {
|
||||||
|
b = b + (n & c | a & ~c) + e + k;
|
||||||
|
return (b << j | b >>> 32 - j) + n
|
||||||
|
}
|
||||||
|
|
||||||
|
function l(b, n, a, c, e, j, k) {
|
||||||
|
b = b + (n ^ a ^ c) + e + k;
|
||||||
|
return (b << j | b >>> 32 - j) + n
|
||||||
|
}
|
||||||
|
|
||||||
|
function s(b, n, a, c, e, j, k) {
|
||||||
|
b = b + (a ^ (n | ~c)) + e + k;
|
||||||
|
return (b << j | b >>> 32 - j) + n
|
||||||
|
}
|
||||||
|
for (var t = CryptoJS, r = t.lib, w = r.WordArray, v = r.Hasher, r = t.algo, b = [], x = 0; 64 > x; x++) b[x] = 4294967296 * u.abs(u.sin(x + 1)) | 0;
|
||||||
|
r = r.MD5 = v.extend({
|
||||||
|
_doReset: function() {
|
||||||
|
this._hash = new w.init([1732584193, 4023233417, 2562383102, 271733878])
|
||||||
|
},
|
||||||
|
_doProcessBlock: function(q, n) {
|
||||||
|
for (var a = 0; 16 > a; a++) {
|
||||||
|
var c = n + a,
|
||||||
|
e = q[c];
|
||||||
|
q[c] = (e << 8 | e >>> 24) & 16711935 | (e << 24 | e >>> 8) & 4278255360
|
||||||
|
}
|
||||||
|
var a = this._hash.words,
|
||||||
|
c = q[n + 0],
|
||||||
|
e = q[n + 1],
|
||||||
|
j = q[n + 2],
|
||||||
|
k = q[n + 3],
|
||||||
|
z = q[n + 4],
|
||||||
|
r = q[n + 5],
|
||||||
|
t = q[n + 6],
|
||||||
|
w = q[n + 7],
|
||||||
|
v = q[n + 8],
|
||||||
|
A = q[n + 9],
|
||||||
|
B = q[n + 10],
|
||||||
|
C = q[n + 11],
|
||||||
|
u = q[n + 12],
|
||||||
|
D = q[n + 13],
|
||||||
|
E = q[n + 14],
|
||||||
|
x = q[n + 15],
|
||||||
|
f = a[0],
|
||||||
|
m = a[1],
|
||||||
|
g = a[2],
|
||||||
|
h = a[3],
|
||||||
|
f = p(f, m, g, h, c, 7, b[0]),
|
||||||
|
h = p(h, f, m, g, e, 12, b[1]),
|
||||||
|
g = p(g, h, f, m, j, 17, b[2]),
|
||||||
|
m = p(m, g, h, f, k, 22, b[3]),
|
||||||
|
f = p(f, m, g, h, z, 7, b[4]),
|
||||||
|
h = p(h, f, m, g, r, 12, b[5]),
|
||||||
|
g = p(g, h, f, m, t, 17, b[6]),
|
||||||
|
m = p(m, g, h, f, w, 22, b[7]),
|
||||||
|
f = p(f, m, g, h, v, 7, b[8]),
|
||||||
|
h = p(h, f, m, g, A, 12, b[9]),
|
||||||
|
g = p(g, h, f, m, B, 17, b[10]),
|
||||||
|
m = p(m, g, h, f, C, 22, b[11]),
|
||||||
|
f = p(f, m, g, h, u, 7, b[12]),
|
||||||
|
h = p(h, f, m, g, D, 12, b[13]),
|
||||||
|
g = p(g, h, f, m, E, 17, b[14]),
|
||||||
|
m = p(m, g, h, f, x, 22, b[15]),
|
||||||
|
f = d(f, m, g, h, e, 5, b[16]),
|
||||||
|
h = d(h, f, m, g, t, 9, b[17]),
|
||||||
|
g = d(g, h, f, m, C, 14, b[18]),
|
||||||
|
m = d(m, g, h, f, c, 20, b[19]),
|
||||||
|
f = d(f, m, g, h, r, 5, b[20]),
|
||||||
|
h = d(h, f, m, g, B, 9, b[21]),
|
||||||
|
g = d(g, h, f, m, x, 14, b[22]),
|
||||||
|
m = d(m, g, h, f, z, 20, b[23]),
|
||||||
|
f = d(f, m, g, h, A, 5, b[24]),
|
||||||
|
h = d(h, f, m, g, E, 9, b[25]),
|
||||||
|
g = d(g, h, f, m, k, 14, b[26]),
|
||||||
|
m = d(m, g, h, f, v, 20, b[27]),
|
||||||
|
f = d(f, m, g, h, D, 5, b[28]),
|
||||||
|
h = d(h, f,
|
||||||
|
m, g, j, 9, b[29]),
|
||||||
|
g = d(g, h, f, m, w, 14, b[30]),
|
||||||
|
m = d(m, g, h, f, u, 20, b[31]),
|
||||||
|
f = l(f, m, g, h, r, 4, b[32]),
|
||||||
|
h = l(h, f, m, g, v, 11, b[33]),
|
||||||
|
g = l(g, h, f, m, C, 16, b[34]),
|
||||||
|
m = l(m, g, h, f, E, 23, b[35]),
|
||||||
|
f = l(f, m, g, h, e, 4, b[36]),
|
||||||
|
h = l(h, f, m, g, z, 11, b[37]),
|
||||||
|
g = l(g, h, f, m, w, 16, b[38]),
|
||||||
|
m = l(m, g, h, f, B, 23, b[39]),
|
||||||
|
f = l(f, m, g, h, D, 4, b[40]),
|
||||||
|
h = l(h, f, m, g, c, 11, b[41]),
|
||||||
|
g = l(g, h, f, m, k, 16, b[42]),
|
||||||
|
m = l(m, g, h, f, t, 23, b[43]),
|
||||||
|
f = l(f, m, g, h, A, 4, b[44]),
|
||||||
|
h = l(h, f, m, g, u, 11, b[45]),
|
||||||
|
g = l(g, h, f, m, x, 16, b[46]),
|
||||||
|
m = l(m, g, h, f, j, 23, b[47]),
|
||||||
|
f = s(f, m, g, h, c, 6, b[48]),
|
||||||
|
h = s(h, f, m, g, w, 10, b[49]),
|
||||||
|
g = s(g, h, f, m,
|
||||||
|
E, 15, b[50]),
|
||||||
|
m = s(m, g, h, f, r, 21, b[51]),
|
||||||
|
f = s(f, m, g, h, u, 6, b[52]),
|
||||||
|
h = s(h, f, m, g, k, 10, b[53]),
|
||||||
|
g = s(g, h, f, m, B, 15, b[54]),
|
||||||
|
m = s(m, g, h, f, e, 21, b[55]),
|
||||||
|
f = s(f, m, g, h, v, 6, b[56]),
|
||||||
|
h = s(h, f, m, g, x, 10, b[57]),
|
||||||
|
g = s(g, h, f, m, t, 15, b[58]),
|
||||||
|
m = s(m, g, h, f, D, 21, b[59]),
|
||||||
|
f = s(f, m, g, h, z, 6, b[60]),
|
||||||
|
h = s(h, f, m, g, C, 10, b[61]),
|
||||||
|
g = s(g, h, f, m, j, 15, b[62]),
|
||||||
|
m = s(m, g, h, f, A, 21, b[63]);
|
||||||
|
a[0] = a[0] + f | 0;
|
||||||
|
a[1] = a[1] + m | 0;
|
||||||
|
a[2] = a[2] + g | 0;
|
||||||
|
a[3] = a[3] + h | 0
|
||||||
|
},
|
||||||
|
_doFinalize: function() {
|
||||||
|
var b = this._data,
|
||||||
|
n = b.words,
|
||||||
|
a = 8 * this._nDataBytes,
|
||||||
|
c = 8 * b.sigBytes;
|
||||||
|
n[c >>> 5] |= 128 << 24 - c % 32;
|
||||||
|
var e = u.floor(a /
|
||||||
|
4294967296);
|
||||||
|
n[(c + 64 >>> 9 << 4) + 15] = (e << 8 | e >>> 24) & 16711935 | (e << 24 | e >>> 8) & 4278255360;
|
||||||
|
n[(c + 64 >>> 9 << 4) + 14] = (a << 8 | a >>> 24) & 16711935 | (a << 24 | a >>> 8) & 4278255360;
|
||||||
|
b.sigBytes = 4 * (n.length + 1);
|
||||||
|
this._process();
|
||||||
|
b = this._hash;
|
||||||
|
n = b.words;
|
||||||
|
for (a = 0; 4 > a; a++) c = n[a], n[a] = (c << 8 | c >>> 24) & 16711935 | (c << 24 | c >>> 8) & 4278255360;
|
||||||
|
return b
|
||||||
|
},
|
||||||
|
clone: function() {
|
||||||
|
var b = v.clone.call(this);
|
||||||
|
b._hash = this._hash.clone();
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
});
|
||||||
|
t.MD5 = v._createHelper(r);
|
||||||
|
t.HmacMD5 = v._createHmacHelper(r)
|
||||||
|
})(Math);
|
||||||
|
(function() {
|
||||||
|
var u = CryptoJS,
|
||||||
|
p = u.lib,
|
||||||
|
d = p.Base,
|
||||||
|
l = p.WordArray,
|
||||||
|
p = u.algo,
|
||||||
|
s = p.EvpKDF = d.extend({
|
||||||
|
cfg: d.extend({
|
||||||
|
keySize: 4,
|
||||||
|
hasher: p.MD5,
|
||||||
|
iterations: 1
|
||||||
|
}),
|
||||||
|
init: function(d) {
|
||||||
|
this.cfg = this.cfg.extend(d)
|
||||||
|
},
|
||||||
|
compute: function(d, r) {
|
||||||
|
for (var p = this.cfg, s = p.hasher.create(), b = l.create(), u = b.words, q = p.keySize, p = p.iterations; u.length < q;) {
|
||||||
|
n && s.update(n);
|
||||||
|
var n = s.update(d).finalize(r);
|
||||||
|
s.reset();
|
||||||
|
for (var a = 1; a < p; a++) n = s.finalize(n), s.reset();
|
||||||
|
b.concat(n)
|
||||||
|
}
|
||||||
|
b.sigBytes = 4 * q;
|
||||||
|
return b
|
||||||
|
}
|
||||||
|
});
|
||||||
|
u.EvpKDF = function(d, l, p) {
|
||||||
|
return s.create(p).compute(d,
|
||||||
|
l)
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
CryptoJS.lib.Cipher || function(u) {
|
||||||
|
var p = CryptoJS,
|
||||||
|
d = p.lib,
|
||||||
|
l = d.Base,
|
||||||
|
s = d.WordArray,
|
||||||
|
t = d.BufferedBlockAlgorithm,
|
||||||
|
r = p.enc.Base64,
|
||||||
|
w = p.algo.EvpKDF,
|
||||||
|
v = d.Cipher = t.extend({
|
||||||
|
cfg: l.extend(),
|
||||||
|
createEncryptor: function(e, a) {
|
||||||
|
return this.create(this._ENC_XFORM_MODE, e, a)
|
||||||
|
},
|
||||||
|
createDecryptor: function(e, a) {
|
||||||
|
return this.create(this._DEC_XFORM_MODE, e, a)
|
||||||
|
},
|
||||||
|
init: function(e, a, b) {
|
||||||
|
this.cfg = this.cfg.extend(b);
|
||||||
|
this._xformMode = e;
|
||||||
|
this._key = a;
|
||||||
|
this.reset()
|
||||||
|
},
|
||||||
|
reset: function() {
|
||||||
|
t.reset.call(this);
|
||||||
|
this._doReset()
|
||||||
|
},
|
||||||
|
process: function(e) {
|
||||||
|
this._append(e);
|
||||||
|
return this._process()
|
||||||
|
},
|
||||||
|
finalize: function(e) {
|
||||||
|
e && this._append(e);
|
||||||
|
return this._doFinalize()
|
||||||
|
},
|
||||||
|
keySize: 4,
|
||||||
|
ivSize: 4,
|
||||||
|
_ENC_XFORM_MODE: 1,
|
||||||
|
_DEC_XFORM_MODE: 2,
|
||||||
|
_createHelper: function(e) {
|
||||||
|
return {
|
||||||
|
encrypt: function(b, k, d) {
|
||||||
|
return ("string" == typeof k ? c : a).encrypt(e, b, k, d)
|
||||||
|
},
|
||||||
|
decrypt: function(b, k, d) {
|
||||||
|
return ("string" == typeof k ? c : a).decrypt(e, b, k, d)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
d.StreamCipher = v.extend({
|
||||||
|
_doFinalize: function() {
|
||||||
|
return this._process(!0)
|
||||||
|
},
|
||||||
|
blockSize: 1
|
||||||
|
});
|
||||||
|
var b = p.mode = {},
|
||||||
|
x = function(e, a, b) {
|
||||||
|
var c = this._iv;
|
||||||
|
c ? this._iv = u : c = this._prevBlock;
|
||||||
|
for (var d = 0; d < b; d++) e[a + d] ^=
|
||||||
|
c[d]
|
||||||
|
},
|
||||||
|
q = (d.BlockCipherMode = l.extend({
|
||||||
|
createEncryptor: function(e, a) {
|
||||||
|
return this.Encryptor.create(e, a)
|
||||||
|
},
|
||||||
|
createDecryptor: function(e, a) {
|
||||||
|
return this.Decryptor.create(e, a)
|
||||||
|
},
|
||||||
|
init: function(e, a) {
|
||||||
|
this._cipher = e;
|
||||||
|
this._iv = a
|
||||||
|
}
|
||||||
|
})).extend();
|
||||||
|
q.Encryptor = q.extend({
|
||||||
|
processBlock: function(e, a) {
|
||||||
|
var b = this._cipher,
|
||||||
|
c = b.blockSize;
|
||||||
|
x.call(this, e, a, c);
|
||||||
|
b.encryptBlock(e, a);
|
||||||
|
this._prevBlock = e.slice(a, a + c)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
q.Decryptor = q.extend({
|
||||||
|
processBlock: function(e, a) {
|
||||||
|
var b = this._cipher,
|
||||||
|
c = b.blockSize,
|
||||||
|
d = e.slice(a, a + c);
|
||||||
|
b.decryptBlock(e, a);
|
||||||
|
x.call(this,
|
||||||
|
e, a, c);
|
||||||
|
this._prevBlock = d
|
||||||
|
}
|
||||||
|
});
|
||||||
|
b = b.CBC = q;
|
||||||
|
q = (p.pad = {}).Pkcs7 = {
|
||||||
|
pad: function(a, b) {
|
||||||
|
for (var c = 4 * b, c = c - a.sigBytes % c, d = c << 24 | c << 16 | c << 8 | c, l = [], n = 0; n < c; n += 4) l.push(d);
|
||||||
|
c = s.create(l, c);
|
||||||
|
a.concat(c)
|
||||||
|
},
|
||||||
|
unpad: function(a) {
|
||||||
|
a.sigBytes -= a.words[a.sigBytes - 1 >>> 2] & 255
|
||||||
|
}
|
||||||
|
};
|
||||||
|
d.BlockCipher = v.extend({
|
||||||
|
cfg: v.cfg.extend({
|
||||||
|
mode: b,
|
||||||
|
padding: q
|
||||||
|
}),
|
||||||
|
reset: function() {
|
||||||
|
v.reset.call(this);
|
||||||
|
var a = this.cfg,
|
||||||
|
b = a.iv,
|
||||||
|
a = a.mode;
|
||||||
|
if (this._xformMode == this._ENC_XFORM_MODE) var c = a.createEncryptor;
|
||||||
|
else c = a.createDecryptor, this._minBufferSize = 1;
|
||||||
|
this._mode = c.call(a,
|
||||||
|
this, b && b.words)
|
||||||
|
},
|
||||||
|
_doProcessBlock: function(a, b) {
|
||||||
|
this._mode.processBlock(a, b)
|
||||||
|
},
|
||||||
|
_doFinalize: function() {
|
||||||
|
var a = this.cfg.padding;
|
||||||
|
if (this._xformMode == this._ENC_XFORM_MODE) {
|
||||||
|
a.pad(this._data, this.blockSize);
|
||||||
|
var b = this._process(!0)
|
||||||
|
} else b = this._process(!0), a.unpad(b);
|
||||||
|
return b
|
||||||
|
},
|
||||||
|
blockSize: 4
|
||||||
|
});
|
||||||
|
var n = d.CipherParams = l.extend({
|
||||||
|
init: function(a) {
|
||||||
|
this.mixIn(a)
|
||||||
|
},
|
||||||
|
toString: function(a) {
|
||||||
|
return (a || this.formatter).stringify(this)
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
b = (p.format = {}).OpenSSL = {
|
||||||
|
stringify: function(a) {
|
||||||
|
var b = a.ciphertext;
|
||||||
|
a = a.salt;
|
||||||
|
return (a ? s.create([1398893684,
|
||||||
|
1701076831
|
||||||
|
]).concat(a).concat(b) : b).toString(r)
|
||||||
|
},
|
||||||
|
parse: function(a) {
|
||||||
|
a = r.parse(a);
|
||||||
|
var b = a.words;
|
||||||
|
if (1398893684 == b[0] && 1701076831 == b[1]) {
|
||||||
|
var c = s.create(b.slice(2, 4));
|
||||||
|
b.splice(0, 4);
|
||||||
|
a.sigBytes -= 16
|
||||||
|
}
|
||||||
|
return n.create({
|
||||||
|
ciphertext: a,
|
||||||
|
salt: c
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
a = d.SerializableCipher = l.extend({
|
||||||
|
cfg: l.extend({
|
||||||
|
format: b
|
||||||
|
}),
|
||||||
|
encrypt: function(a, b, c, d) {
|
||||||
|
d = this.cfg.extend(d);
|
||||||
|
var l = a.createEncryptor(c, d);
|
||||||
|
b = l.finalize(b);
|
||||||
|
l = l.cfg;
|
||||||
|
return n.create({
|
||||||
|
ciphertext: b,
|
||||||
|
key: c,
|
||||||
|
iv: l.iv,
|
||||||
|
algorithm: a,
|
||||||
|
mode: l.mode,
|
||||||
|
padding: l.padding,
|
||||||
|
blockSize: a.blockSize,
|
||||||
|
formatter: d.format
|
||||||
|
})
|
||||||
|
},
|
||||||
|
decrypt: function(a, b, c, d) {
|
||||||
|
d = this.cfg.extend(d);
|
||||||
|
b = this._parse(b, d.format);
|
||||||
|
return a.createDecryptor(c, d).finalize(b.ciphertext)
|
||||||
|
},
|
||||||
|
_parse: function(a, b) {
|
||||||
|
return "string" == typeof a ? b.parse(a, this) : a
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
p = (p.kdf = {}).OpenSSL = {
|
||||||
|
execute: function(a, b, c, d) {
|
||||||
|
d || (d = s.random(8));
|
||||||
|
a = w.create({
|
||||||
|
keySize: b + c
|
||||||
|
}).compute(a, d);
|
||||||
|
c = s.create(a.words.slice(b), 4 * c);
|
||||||
|
a.sigBytes = 4 * b;
|
||||||
|
return n.create({
|
||||||
|
key: a,
|
||||||
|
iv: c,
|
||||||
|
salt: d
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
c = d.PasswordBasedCipher = a.extend({
|
||||||
|
cfg: a.cfg.extend({
|
||||||
|
kdf: p
|
||||||
|
}),
|
||||||
|
encrypt: function(b, c, d, l) {
|
||||||
|
l = this.cfg.extend(l);
|
||||||
|
d = l.kdf.execute(d,
|
||||||
|
b.keySize, b.ivSize);
|
||||||
|
l.iv = d.iv;
|
||||||
|
b = a.encrypt.call(this, b, c, d.key, l);
|
||||||
|
b.mixIn(d);
|
||||||
|
return b
|
||||||
|
},
|
||||||
|
decrypt: function(b, c, d, l) {
|
||||||
|
l = this.cfg.extend(l);
|
||||||
|
c = this._parse(c, l.format);
|
||||||
|
d = l.kdf.execute(d, b.keySize, b.ivSize, c.salt);
|
||||||
|
l.iv = d.iv;
|
||||||
|
return a.decrypt.call(this, b, c, d.key, l)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}();
|
||||||
|
(function() {
|
||||||
|
for (var u = CryptoJS, p = u.lib.BlockCipher, d = u.algo, l = [], s = [], t = [], r = [], w = [], v = [], b = [], x = [], q = [], n = [], a = [], c = 0; 256 > c; c++) a[c] = 128 > c ? c << 1 : c << 1 ^ 283;
|
||||||
|
for (var e = 0, j = 0, c = 0; 256 > c; c++) {
|
||||||
|
var k = j ^ j << 1 ^ j << 2 ^ j << 3 ^ j << 4,
|
||||||
|
k = k >>> 8 ^ k & 255 ^ 99;
|
||||||
|
l[e] = k;
|
||||||
|
s[k] = e;
|
||||||
|
var z = a[e],
|
||||||
|
F = a[z],
|
||||||
|
G = a[F],
|
||||||
|
y = 257 * a[k] ^ 16843008 * k;
|
||||||
|
t[e] = y << 24 | y >>> 8;
|
||||||
|
r[e] = y << 16 | y >>> 16;
|
||||||
|
w[e] = y << 8 | y >>> 24;
|
||||||
|
v[e] = y;
|
||||||
|
y = 16843009 * G ^ 65537 * F ^ 257 * z ^ 16843008 * e;
|
||||||
|
b[k] = y << 24 | y >>> 8;
|
||||||
|
x[k] = y << 16 | y >>> 16;
|
||||||
|
q[k] = y << 8 | y >>> 24;
|
||||||
|
n[k] = y;
|
||||||
|
e ? (e = z ^ a[a[a[G ^ z]]], j ^= a[a[j]]) : e = j = 1
|
||||||
|
}
|
||||||
|
var H = [0, 1, 2, 4, 8,
|
||||||
|
16, 32, 64, 128, 27, 54
|
||||||
|
],
|
||||||
|
d = d.AES = p.extend({
|
||||||
|
_doReset: function() {
|
||||||
|
for (var a = this._key, c = a.words, d = a.sigBytes / 4, a = 4 * ((this._nRounds = d + 6) + 1), e = this._keySchedule = [], j = 0; j < a; j++)
|
||||||
|
if (j < d) e[j] = c[j];
|
||||||
|
else {
|
||||||
|
var k = e[j - 1];
|
||||||
|
j % d ? 6 < d && 4 == j % d && (k = l[k >>> 24] << 24 | l[k >>> 16 & 255] << 16 | l[k >>> 8 & 255] << 8 | l[k & 255]) : (k = k << 8 | k >>> 24, k = l[k >>> 24] << 24 | l[k >>> 16 & 255] << 16 | l[k >>> 8 & 255] << 8 | l[k & 255], k ^= H[j / d | 0] << 24);
|
||||||
|
e[j] = e[j - d] ^ k
|
||||||
|
} c = this._invKeySchedule = [];
|
||||||
|
for (d = 0; d < a; d++) j = a - d, k = d % 4 ? e[j] : e[j - 4], c[d] = 4 > d || 4 >= j ? k : b[l[k >>> 24]] ^ x[l[k >>> 16 & 255]] ^ q[l[k >>>
|
||||||
|
8 & 255]] ^ n[l[k & 255]]
|
||||||
|
},
|
||||||
|
encryptBlock: function(a, b) {
|
||||||
|
this._doCryptBlock(a, b, this._keySchedule, t, r, w, v, l)
|
||||||
|
},
|
||||||
|
decryptBlock: function(a, c) {
|
||||||
|
var d = a[c + 1];
|
||||||
|
a[c + 1] = a[c + 3];
|
||||||
|
a[c + 3] = d;
|
||||||
|
this._doCryptBlock(a, c, this._invKeySchedule, b, x, q, n, s);
|
||||||
|
d = a[c + 1];
|
||||||
|
a[c + 1] = a[c + 3];
|
||||||
|
a[c + 3] = d
|
||||||
|
},
|
||||||
|
_doCryptBlock: function(a, b, c, d, e, j, l, f) {
|
||||||
|
for (var m = this._nRounds, g = a[b] ^ c[0], h = a[b + 1] ^ c[1], k = a[b + 2] ^ c[2], n = a[b + 3] ^ c[3], p = 4, r = 1; r < m; r++) var q = d[g >>> 24] ^ e[h >>> 16 & 255] ^ j[k >>> 8 & 255] ^ l[n & 255] ^ c[p++],
|
||||||
|
s = d[h >>> 24] ^ e[k >>> 16 & 255] ^ j[n >>> 8 & 255] ^ l[g & 255] ^ c[p++],
|
||||||
|
t =
|
||||||
|
d[k >>> 24] ^ e[n >>> 16 & 255] ^ j[g >>> 8 & 255] ^ l[h & 255] ^ c[p++],
|
||||||
|
n = d[n >>> 24] ^ e[g >>> 16 & 255] ^ j[h >>> 8 & 255] ^ l[k & 255] ^ c[p++],
|
||||||
|
g = q,
|
||||||
|
h = s,
|
||||||
|
k = t;
|
||||||
|
q = (f[g >>> 24] << 24 | f[h >>> 16 & 255] << 16 | f[k >>> 8 & 255] << 8 | f[n & 255]) ^ c[p++];
|
||||||
|
s = (f[h >>> 24] << 24 | f[k >>> 16 & 255] << 16 | f[n >>> 8 & 255] << 8 | f[g & 255]) ^ c[p++];
|
||||||
|
t = (f[k >>> 24] << 24 | f[n >>> 16 & 255] << 16 | f[g >>> 8 & 255] << 8 | f[h & 255]) ^ c[p++];
|
||||||
|
n = (f[n >>> 24] << 24 | f[g >>> 16 & 255] << 16 | f[h >>> 8 & 255] << 8 | f[k & 255]) ^ c[p++];
|
||||||
|
a[b] = q;
|
||||||
|
a[b + 1] = s;
|
||||||
|
a[b + 2] = t;
|
||||||
|
a[b + 3] = n
|
||||||
|
},
|
||||||
|
keySize: 8
|
||||||
|
});
|
||||||
|
u.AES = p._createHelper(d)
|
||||||
|
})();
|
||||||
|
var CryptoJSAesJson = {
|
||||||
|
/**
|
||||||
|
* Encrypt any value
|
||||||
|
* @param {*} value
|
||||||
|
* @param {string} password
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
'encrypt': function (value, password) {
|
||||||
|
return CryptoJS.AES.encrypt(JSON.stringify(value), password, { format: CryptoJSAesJson }).toString()
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Decrypt a previously encrypted value
|
||||||
|
* @param {string} jsonStr
|
||||||
|
* @param {string} password
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
'decrypt': function (jsonStr, password) {
|
||||||
|
return JSON.parse(CryptoJS.AES.decrypt(jsonStr, password, { format: CryptoJSAesJson }).toString(CryptoJS.enc.Utf8))
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Stringify cryptojs data
|
||||||
|
* @param {Object} cipherParams
|
||||||
|
* @return {string}
|
||||||
|
*/
|
||||||
|
'stringify': function (cipherParams) {
|
||||||
|
var j = { ct: cipherParams.ciphertext.toString(CryptoJS.enc.Base64) }
|
||||||
|
if (cipherParams.iv) j.iv = cipherParams.iv.toString()
|
||||||
|
if (cipherParams.salt) j.s = cipherParams.salt.toString()
|
||||||
|
return JSON.stringify(j).replace(/\s/g, '')
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* Parse cryptojs data
|
||||||
|
* @param {string} jsonStr
|
||||||
|
* @return {*}
|
||||||
|
*/
|
||||||
|
'parse': function (jsonStr) {
|
||||||
|
var j = JSON.parse(jsonStr)
|
||||||
|
var cipherParams = CryptoJS.lib.CipherParams.create({ ciphertext: CryptoJS.enc.Base64.parse(j.ct) })
|
||||||
|
if (j.iv) cipherParams.iv = CryptoJS.enc.Hex.parse(j.iv)
|
||||||
|
if (j.s) cipherParams.salt = CryptoJS.enc.Hex.parse(j.s)
|
||||||
|
return cipherParams
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
CryptoJS.MD5('$string').toString(CryptoJS.enc.Base64).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_")
|
||||||
|
"""
|
Reference in New Issue
Block a user