From 8a7c99124dbad3e8bd89e62b6226e8f760bf8dbb Mon Sep 17 00:00:00 2001 From: shalva97 Date: Wed, 27 Sep 2023 23:49:54 +0400 Subject: [PATCH 1/4] Rename .java to .kt --- .../gifencoder/{OctTreeQuantizer.java => OctTreeQuantizer.kt} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/main/java/com/squareup/gifencoder/{OctTreeQuantizer.java => OctTreeQuantizer.kt} (100%) diff --git a/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.java b/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt similarity index 100% rename from src/main/java/com/squareup/gifencoder/OctTreeQuantizer.java rename to src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt From fa706ea11d124f6110304aca587335f3ce71d9fb Mon Sep 17 00:00:00 2001 From: shalva97 Date: Wed, 27 Sep 2023 23:49:54 +0400 Subject: [PATCH 2/4] remove Java --- .../squareup/gifencoder/OctTreeQuantizer.kt | 226 +++++++++--------- 1 file changed, 113 insertions(+), 113 deletions(-) diff --git a/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt b/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt index c2559af..ec0f8bd 100644 --- a/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt +++ b/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt @@ -13,157 +13,157 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.squareup.gifencoder; - -import java.util.HashSet; -import java.util.Set; +package com.squareup.gifencoder /** * Implements qct-tree quantization. - *

+ * + * * The principle of algorithm: http://www.microsoft.com/msj/archive/S3F1.aspx - *

+ * */ -public final class OctTreeQuantizer implements ColorQuantizer { - public static final OctTreeQuantizer INSTANCE = new OctTreeQuantizer(); - - private static final char[] mask = new char[]{0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; - private int leafCount; - private int inIndex; - - private final Node[] nodeList = new Node[8]; - - private OctTreeQuantizer() { - } - - @Override - public Set quantize(Multiset originalColors, int maxColorCount) { - Node node = createNode(0); - Set distinctElements = originalColors.getDistinctElements(); - for (Color color : distinctElements) { - addColor(node, color, 0); +public class OctTreeQuantizer private constructor() : ColorQuantizer { + private var leafCount = 0 + private var inIndex = 0 + private val nodeList = arrayOfNulls(8) + override fun quantize(originalColors: Multiset, maxColorCount: Int): Set { + val node = createNode(0) + val distinctElements = originalColors.distinctElements + for (color in distinctElements) { + addColor(node, color, 0) while (leafCount > maxColorCount) { - reduceTree(); + reduceTree() } } - HashSet colors = new HashSet<>(); - getColorPalette(node, colors); - - leafCount = 0; - inIndex = 0; - for (int i = 0; i < 8; i++) { - nodeList[i] = null; + val colors = HashSet() + getColorPalette(node, colors) + leafCount = 0 + inIndex = 0 + for (i in 0..7) { + nodeList[i] = null } - - return colors; + return colors } - private boolean addColor(Node node, Color color, int inLevel) { - int nIndex, shift; - + private fun addColor(node: Node?, color: Color, inLevel: Int): Boolean { + var node = node + val nIndex: Int + val shift: Int if (node == null) { - node = createNode(inLevel); + node = createNode(inLevel) } - - int red = (int) (color.getComponent(0) * 255); - int green = (int) (color.getComponent(1) * 255); - int blue = (int) (color.getComponent(2) * 255); - + val red = (color.getComponent(0) * 255).toInt() + val green = (color.getComponent(1) * 255).toInt() + val blue = (color.getComponent(2) * 255).toInt() if (node.isLeaf) { - node.pixelCount++; - node.redSum += red; - node.greenSum += green; - node.blueSum += blue; + node.pixelCount++ + node.redSum += red + node.greenSum += green + node.blueSum += blue } else { - shift = 7 - inLevel; - nIndex = (((red & mask[inLevel]) >> shift) << 2) - | (((green & mask[inLevel]) >> shift) << 1) - | ((blue & mask[inLevel]) >> shift); - Node tmpNode = node.child[nIndex]; + shift = 7 - inLevel + nIndex = (red and mask[inLevel].code shr shift shl 2 + or (green and mask[inLevel].code shr shift shl 1) + or (blue and mask[inLevel].code shr shift)) + var tmpNode = node.child[nIndex] if (tmpNode == null) { - tmpNode = createNode(inLevel + 1); + tmpNode = createNode(inLevel + 1) } - node.child[nIndex] = tmpNode; - return addColor(node.child[nIndex], color, inLevel + 1); + node.child[nIndex] = tmpNode + return addColor(node.child[nIndex], color, inLevel + 1) } - return true; + return true } - private Node createNode(int level) { - Node node = new Node(); - node.level = level; - node.isLeaf = (level == 8); + private fun createNode(level: Int): Node { + val node = Node() + node.level = level + node.isLeaf = level == 8 if (node.isLeaf) { - leafCount++; + leafCount++ } else { - node.next = nodeList[level]; - nodeList[level] = node; + node.next = nodeList[level] + nodeList[level] = node } - return node; + return node } - private void reduceTree() { - int i; - int redSum = 0, greenSum = 0, blueSum = 0, count = 0; - - for (i = 7; i > 0; i--) { - if (nodeList[i] != null) break; + private fun reduceTree() { + var redSum = 0 + var greenSum = 0 + var blueSum = 0 + var count = 0 + var i = 7 + while (i > 0) { + if (nodeList[i] != null) break + i-- } - - Node tmpNode = nodeList[i]; - nodeList[i] = tmpNode.next; - - for (i = 0; i < 8; i++) { + val tmpNode = nodeList[i] + nodeList[i] = tmpNode!!.next + i = 0 + while (i < 8) { if (tmpNode.child[i] != null) { - redSum += tmpNode.child[i].redSum; - greenSum += tmpNode.child[i].greenSum; - blueSum += tmpNode.child[i].blueSum; - count += tmpNode.child[i].pixelCount; - tmpNode.child[i] = null; - leafCount--; + redSum += tmpNode.child[i]!!.redSum + greenSum += tmpNode.child[i]!!.greenSum + blueSum += tmpNode.child[i]!!.blueSum + count += tmpNode.child[i]!!.pixelCount + tmpNode.child[i] = null + leafCount-- } + i++ } - tmpNode.isLeaf = true; - tmpNode.redSum = redSum; - tmpNode.greenSum = greenSum; - tmpNode.blueSum = blueSum; - tmpNode.pixelCount = count; - - leafCount++; + tmpNode.isLeaf = true + tmpNode.redSum = redSum + tmpNode.greenSum = greenSum + tmpNode.blueSum = blueSum + tmpNode.pixelCount = count + leafCount++ } - private void getColorPalette(Node node, Set colors) { - if (node.isLeaf) { - node.colorIndex = inIndex; - node.redSum = node.redSum / node.pixelCount; - node.greenSum = node.greenSum / node.pixelCount; - node.blueSum = node.blueSum / node.pixelCount; - node.pixelCount = 1; - inIndex++; - double red = (double) node.redSum / 255; - double green = (double) node.greenSum / 255; - double blue = (double) node.blueSum / 255; - colors.add(new Color(red, green, blue)); + private fun getColorPalette(node: Node?, colors: MutableSet) { + if (node!!.isLeaf) { + node.colorIndex = inIndex + node.redSum /= node.pixelCount + node.greenSum /= node.pixelCount + node.blueSum /= node.pixelCount + node.pixelCount = 1 + inIndex++ + val red = node.redSum.toDouble() / 255 + val green = node.greenSum.toDouble() / 255 + val blue = node.blueSum.toDouble() / 255 + colors.add(Color(red, green, blue)) } else { - for (int i = 0; i < 8; i++) { + for (i in 0..7) { if (node.child[i] != null) { - getColorPalette(node.child[i], colors); + getColorPalette(node.child[i], colors) } } } } - private static final class Node { - boolean isLeaf; - int level; - int colorIndex; - - int redSum; - int greenSum; - int blueSum; - int pixelCount; + private class Node { + var isLeaf = false + var level = 0 + var colorIndex = 0 + var redSum = 0 + var greenSum = 0 + var blueSum = 0 + var pixelCount = 0 + var child = arrayOfNulls(8) + var next: Node? = null + } - Node[] child = new Node[8]; - Node next; + public companion object { + public val INSTANCE: OctTreeQuantizer = OctTreeQuantizer() + private val mask = charArrayOf( + 0x80.toChar(), + 0x40.toChar(), + 0x20.toChar(), + 0x10.toChar(), + 0x08.toChar(), + 0x04.toChar(), + 0x02.toChar(), + 0x01.toChar() + ) } } \ No newline at end of file From 56385a4b368a3d86c8ac22724d00db2b28314237 Mon Sep 17 00:00:00 2001 From: shalva97 Date: Thu, 28 Sep 2023 12:34:03 +0400 Subject: [PATCH 3/4] update file location --- .../pixiv}/gifencoder/OctTreeQuantizer.kt | 6 +++++- .../pixiv/tool/PixivUgoiraEncoderTest.kt | 20 +++++++++++-------- 2 files changed, 17 insertions(+), 9 deletions(-) rename src/main/{java/com/squareup => kotlin/xyz/cssxsh/pixiv}/gifencoder/OctTreeQuantizer.kt (97%) diff --git a/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/gifencoder/OctTreeQuantizer.kt similarity index 97% rename from src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt rename to src/main/kotlin/xyz/cssxsh/pixiv/gifencoder/OctTreeQuantizer.kt index ec0f8bd..ee8ee3e 100644 --- a/src/main/java/com/squareup/gifencoder/OctTreeQuantizer.kt +++ b/src/main/kotlin/xyz/cssxsh/pixiv/gifencoder/OctTreeQuantizer.kt @@ -13,7 +13,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.squareup.gifencoder +package xyz.cssxsh.pixiv.gifencoder + +import com.squareup.gifencoder.Color +import com.squareup.gifencoder.ColorQuantizer +import com.squareup.gifencoder.Multiset /** * Implements qct-tree quantization. diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt b/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt index 9b709b6..f5e048b 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt +++ b/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt @@ -2,14 +2,18 @@ package xyz.cssxsh.pixiv.tool import com.squareup.gifencoder.* import io.ktor.http.* -import kotlinx.coroutines.* -import kotlinx.serialization.* -import org.junit.jupiter.api.* -import org.junit.jupiter.api.Assertions.* -import xyz.cssxsh.pixiv.* -import xyz.cssxsh.pixiv.apps.* -import java.io.* -import kotlin.system.* +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeAll +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import xyz.cssxsh.pixiv.PixivJson +import xyz.cssxsh.pixiv.SummaryTest +import xyz.cssxsh.pixiv.apps.IllustInfo +import xyz.cssxsh.pixiv.apps.UgoiraMetadata +import xyz.cssxsh.pixiv.gifencoder.OctTreeQuantizer +import java.io.File +import kotlin.system.measureTimeMillis @TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class PixivUgoiraEncoderTest : SummaryTest() { From 5307599d8e15555893623bfe1099dc79e96d6c5f Mon Sep 17 00:00:00 2001 From: George Shalvashvili Date: Thu, 5 Oct 2023 00:47:19 +0400 Subject: [PATCH 4/4] Refactoring (#1) added native targets --- .gitignore | 4 +- build.gradle.kts | 99 +++++----- example/99565513.json | 62 ++++++- example/99565513.ugoira.json | 72 +++++++- local.properties | 0 pixiv_auth.py | 114 ++++++++++++ .../kotlin/xyz/cssxsh/pixiv/OtherAuth.kt | 36 +--- .../kotlin/xyz/cssxsh/pixiv/PixivAppClient.kt | 0 .../xyz/cssxsh/pixiv/PixivAuthClient.kt | 59 +++--- .../kotlin/xyz/cssxsh/pixiv/PixivConfig.kt | 9 - .../kotlin/xyz/cssxsh/pixiv/PixivUtils.kt | 36 ++-- .../kotlin/xyz/cssxsh/pixiv/PixivWebClient.kt | 0 .../xyz/cssxsh/pixiv/SimplePixivClient.kt | 0 .../kotlin/xyz/cssxsh/pixiv/UseConfig.kt | 0 .../kotlin/xyz/cssxsh/pixiv/UseHttpClient.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/AppApi.kt | 0 .../xyz/cssxsh/pixiv/apps/ApplicationData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/Blacklist.kt | 0 .../xyz/cssxsh/pixiv/apps/BookmarkDetail.kt | 0 .../cssxsh/pixiv/apps/BookmarkDetailSingle.kt | 0 .../cssxsh/pixiv/apps/BookmarkRangeData.kt | 0 .../xyz/cssxsh/pixiv/apps/BookmarkTagData.kt | 0 .../xyz/cssxsh/pixiv/apps/CommentData.kt | 0 .../xyz/cssxsh/pixiv/apps/CommentInfo.kt | 8 +- .../xyz/cssxsh/pixiv/apps/CommentStamp.kt | 0 .../cssxsh/pixiv/apps/EmojiDefinitionData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/Illust.kt | 7 +- .../xyz/cssxsh/pixiv/apps/IllustData.kt | 0 .../xyz/cssxsh/pixiv/apps/IllustInfo.kt | 8 +- .../xyz/cssxsh/pixiv/apps/IllustSingle.kt | 0 .../xyz/cssxsh/pixiv/apps/KeywordsData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/Novel.kt | 12 +- .../kotlin/xyz/cssxsh/pixiv/apps/NovelData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt | 12 +- .../kotlin/xyz/cssxsh/pixiv/apps/Other.kt | 0 .../xyz/cssxsh/pixiv/apps/PreviewData.kt | 0 .../xyz/cssxsh/pixiv/apps/RecommendedData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/Search.kt | 11 +- .../xyz/cssxsh/pixiv/apps/SeriesInfo.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/Spotlight.kt | 0 .../xyz/cssxsh/pixiv/apps/SpotlightArticle.kt | 9 +- .../cssxsh/pixiv/apps/SpotlightArticleData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/StampData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/TagData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/TagInfo.kt | 0 .../xyz/cssxsh/pixiv/apps/TrendIllust.kt | 0 .../xyz/cssxsh/pixiv/apps/TrendIllustData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/Trending.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/Ugoira.kt | 0 .../xyz/cssxsh/pixiv/apps/UgoiraFrame.kt | 0 .../xyz/cssxsh/pixiv/apps/UgoiraInfo.kt | 0 .../xyz/cssxsh/pixiv/apps/UgoiraMetadata.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/User.kt | 0 .../xyz/cssxsh/pixiv/apps/UserDetail.kt | 0 .../xyz/cssxsh/pixiv/apps/UserIllustData.kt | 0 .../kotlin/xyz/cssxsh/pixiv/apps/UserInfo.kt | 0 .../xyz/cssxsh/pixiv/apps/UserPreview.kt | 0 .../xyz/cssxsh/pixiv/auth/AuthResult.kt | 0 .../xyz/cssxsh/pixiv/auth/HtmlAccount.kt | 5 +- .../kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt | 16 +- .../xyz/cssxsh/pixiv/auth/WebLoginResult.kt | 0 .../xyz/cssxsh/pixiv/auth/WeiboQrcode.kt | 0 .../cssxsh/pixiv/auth/WeiboQrcodeStatus.kt | 0 .../xyz/cssxsh/pixiv/exception/AppApiError.kt | 0 .../cssxsh/pixiv/exception/AppApiException.kt | 0 .../xyz/cssxsh/pixiv/exception/AuthError.kt | 0 .../cssxsh/pixiv/exception/AuthException.kt | 0 .../exception/MatchContentLengthException.kt | 8 +- .../pixiv/exception/NoCacheException.kt | 0 .../pixiv/exception/OtherClientException.kt | 0 .../cssxsh/pixiv/exception/ProxyException.kt | 0 .../pixiv/exception/RestrictException.kt | 0 .../exception/TransferExceptionHandler.kt | 0 .../cssxsh/pixiv/exception/WebApiException.kt | 0 .../xyz/cssxsh/pixiv/fanbox/CommentInfo.kt | 9 +- .../xyz/cssxsh/pixiv/fanbox/CommentList.kt | 0 .../xyz/cssxsh/pixiv/fanbox/CreatorActive.kt | 0 .../xyz/cssxsh/pixiv/fanbox/CreatorDetail.kt | 0 .../xyz/cssxsh/pixiv/fanbox/CreatorInfo.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt | 9 +- .../xyz/cssxsh/pixiv/fanbox/FanBoxBell.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxCreator.kt | 0 .../cssxsh/pixiv/fanbox/FanBoxNewsLetter.kt | 0 .../cssxsh/pixiv/fanbox/FanBoxNotification.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxPayment.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxPlan.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxPost.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxTag.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxUser.kt | 0 .../xyz/cssxsh/pixiv/fanbox/FanBoxUtils.kt | 0 .../xyz/cssxsh/pixiv/fanbox/ItemList.kt | 0 .../xyz/cssxsh/pixiv/fanbox/MetaData.kt | 0 .../xyz/cssxsh/pixiv/fanbox/Notification.kt | 0 .../xyz/cssxsh/pixiv/fanbox/PaidRecord.kt | 9 +- .../xyz/cssxsh/pixiv/fanbox/PlanInfo.kt | 0 .../xyz/cssxsh/pixiv/fanbox/PostDetail.kt | 49 ++--- .../xyz/cssxsh/pixiv/fanbox/PostInfo.kt | 9 +- .../xyz/cssxsh/pixiv/fanbox/PostList.kt | 0 .../xyz/cssxsh/pixiv/fanbox/TagFeature.kt | 0 .../cssxsh/pixiv/fanbox/TwitterAccountInfo.kt | 0 .../xyz/cssxsh/pixiv/fanbox/UserSetting.kt | 0 .../xyz/cssxsh/pixiv/fanbox/UserUpdate.kt | 0 .../xyz/cssxsh/pixiv/tool/CaptchaHandler.kt | 0 .../xyz/cssxsh/pixiv/tool/PixivDownloader.kt | 29 +-- .../cssxsh/pixiv/tool/TwoCaptchaHandler.kt | 4 +- .../cssxsh/pixiv/tool/YesCaptchaHandler.kt | 4 +- .../xyz/cssxsh/pixiv/web/ActivityApi.kt | 0 .../xyz/cssxsh/pixiv/web/BookmarkCount.kt | 0 .../kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt | 8 +- .../xyz/cssxsh/pixiv/web/MangaSeries.kt | 12 +- .../xyz/cssxsh/pixiv/web/NovelSeries.kt | 11 +- .../kotlin/xyz/cssxsh/pixiv/web/UserApi.kt | 25 +-- .../xyz/cssxsh/pixiv/web/UserBookmarks.kt | 0 .../xyz/cssxsh/pixiv/web/UserFollowing.kt | 0 .../xyz/cssxsh/pixiv/web/UserPickupInfo.kt | 0 .../xyz/cssxsh/pixiv/web/UserProfileAll.kt | 0 .../cssxsh/pixiv/web/UserProfileIllusts.kt | 0 .../xyz/cssxsh/pixiv/web/UserProfileTop.kt | 0 .../xyz/cssxsh/pixiv/web/UserRequestInfo.kt | 0 .../xyz/cssxsh/pixiv/web/UserWebPreview.kt | 0 .../kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt | 20 +- .../kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt | 18 +- .../xyz/cssxsh/pixiv/web/WebTitleCaption.kt | 0 .../kotlin/xyz/cssxsh/pixiv/web/WebUtils.kt | 0 .../xyz/cssxsh/pixiv/web/WebWorkInfo.kt | 0 .../kotlin/xyz/cssxsh/pixiv/EditThisCookie.kt | 0 .../xyz/cssxsh/pixiv/OtherAuthKtTest.kt | 13 +- .../cssxsh/pixiv/PixivEnumSerializerTest.kt | 7 +- .../kotlin/xyz/cssxsh/pixiv/WebTest.kt | 34 ++-- .../xyz/cssxsh/pixiv/apps/AppApiKtTest.kt | 14 +- .../xyz/cssxsh/pixiv/apps/IllustKtTest.kt | 21 ++- .../xyz/cssxsh/pixiv/apps/SearchKtTest.kt | 8 +- .../xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt | 8 +- .../xyz/cssxsh/pixiv/apps/TrendingKtTest.kt | 8 +- .../xyz/cssxsh/pixiv/apps/UserKtTest.kt | 15 +- .../cssxsh/pixiv/tool/PixivDownloaderTest.kt | 38 ++-- .../xyz/cssxsh/pixiv/web/UserApiKtTest.kt | 6 +- .../xyz/cssxsh/pixiv/PixivAuthClient.jvm.kt | 6 + .../cssxsh/pixiv/JapanDateTimeSerializer.kt | 8 - .../cssxsh/pixiv/OffsetDateTimeSerializer.kt | 21 --- .../pixiv/gifencoder/OctTreeQuantizer.kt | 173 ------------------ .../xyz/cssxsh/pixiv/tool/AtkinsonDitherer.kt | 20 -- .../xyz/cssxsh/pixiv/tool/JJNDitherer.kt | 26 --- .../xyz/cssxsh/pixiv/tool/OpenCVQuantizer.kt | 77 -------- .../xyz/cssxsh/pixiv/tool/PixivGifEncoder.kt | 62 ------- .../cssxsh/pixiv/tool/PixivUgoiraEncoder.kt | 48 ----- .../kotlin/xyz/cssxsh/pixiv/tool/RubyDns.kt | 61 ------ .../cssxsh/pixiv/tool/RubySSLSocketFactory.kt | 40 ---- .../cssxsh/pixiv/tool/RubyX509TrustManager.kt | 20 -- .../cssxsh/pixiv/tool/SierraLiteDitherer.kt | 16 -- .../xyz/cssxsh/pixiv/tool/StuckiDitherer.kt | 26 --- .../cssxsh/pixiv/tool/UniversalDitherer.kt | 36 ---- .../cssxsh/pixiv/PixivAuthClient.native.kt | 6 + .../kotlin/xyz/cssxsh/pixiv/SummaryTest.kt | 26 --- .../pixiv/tool/PixivUgoiraEncoderTest.kt | 101 ---------- 155 files changed, 598 insertions(+), 1150 deletions(-) delete mode 100644 local.properties create mode 100755 pixiv_auth.py rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/OtherAuth.kt (87%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/PixivAppClient.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.kt (78%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/PixivConfig.kt (59%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/PixivUtils.kt (90%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/PixivWebClient.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/SimplePixivClient.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/UseConfig.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/UseHttpClient.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/AppApi.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/ApplicationData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Blacklist.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetail.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetailSingle.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/BookmarkRangeData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/BookmarkTagData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/CommentData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/CommentInfo.kt (77%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/CommentStamp.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/EmojiDefinitionData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Illust.kt (96%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/IllustData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/IllustInfo.kt (95%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/IllustSingle.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/KeywordsData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Novel.kt (94%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/NovelData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt (86%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Other.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/PreviewData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/RecommendedData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Search.kt (89%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/SeriesInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Spotlight.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticle.kt (81%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticleData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/StampData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/TagData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/TagInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/TrendIllust.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/TrendIllustData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Trending.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/Ugoira.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/UgoiraFrame.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/UgoiraInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/UgoiraMetadata.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/User.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/UserDetail.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/UserIllustData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/UserInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/apps/UserPreview.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/auth/AuthResult.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/auth/HtmlAccount.kt (89%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt (88%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/auth/WebLoginResult.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcode.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcodeStatus.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/AppApiError.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/AppApiException.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/AuthError.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/AuthException.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/MatchContentLengthException.kt (69%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/NoCacheException.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/OtherClientException.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/ProxyException.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/RestrictException.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/TransferExceptionHandler.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/exception/WebApiException.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/CommentInfo.kt (83%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/CommentList.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorActive.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorDetail.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt (86%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxBell.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxCreator.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNewsLetter.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNotification.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPayment.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPlan.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPost.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxTag.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUser.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUtils.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/ItemList.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/MetaData.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/Notification.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/PaidRecord.kt (73%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/PlanInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/PostDetail.kt (94%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/PostInfo.kt (83%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/PostList.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/TagFeature.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/TwitterAccountInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/UserSetting.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/fanbox/UserUpdate.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/tool/CaptchaHandler.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloader.kt (89%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/tool/TwoCaptchaHandler.kt (96%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/tool/YesCaptchaHandler.kt (97%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/ActivityApi.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/BookmarkCount.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt (82%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/MangaSeries.kt (85%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/NovelSeries.kt (92%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserApi.kt (83%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserBookmarks.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserFollowing.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserPickupInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserProfileAll.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserProfileIllusts.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserProfileTop.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserRequestInfo.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/UserWebPreview.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt (81%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt (83%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/WebTitleCaption.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/WebUtils.kt (100%) rename src/{main => commonMain}/kotlin/xyz/cssxsh/pixiv/web/WebWorkInfo.kt (100%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/EditThisCookie.kt (100%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/OtherAuthKtTest.kt (85%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/PixivEnumSerializerTest.kt (82%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/WebTest.kt (65%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/apps/AppApiKtTest.kt (51%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/apps/IllustKtTest.kt (88%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/apps/SearchKtTest.kt (84%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt (68%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/apps/TrendingKtTest.kt (71%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/apps/UserKtTest.kt (90%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloaderTest.kt (76%) rename src/{test => commonTest}/kotlin/xyz/cssxsh/pixiv/web/UserApiKtTest.kt (86%) create mode 100644 src/jvmMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.jvm.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/JapanDateTimeSerializer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/OffsetDateTimeSerializer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/gifencoder/OctTreeQuantizer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/AtkinsonDitherer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/JJNDitherer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/OpenCVQuantizer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivGifEncoder.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoder.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyDns.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/RubySSLSocketFactory.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyX509TrustManager.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/SierraLiteDitherer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/StuckiDitherer.kt delete mode 100644 src/main/kotlin/xyz/cssxsh/pixiv/tool/UniversalDitherer.kt create mode 100644 src/nativeMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.native.kt delete mode 100644 src/test/kotlin/xyz/cssxsh/pixiv/SummaryTest.kt delete mode 100644 src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt diff --git a/.gitignore b/.gitignore index 8e6fc32..094dcf3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,4 +9,6 @@ /run *.html -*.cookies \ No newline at end of file +*.cookies + +local.properties \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index f510d61..014880d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,65 +1,76 @@ +@file:Suppress("OPT_IN_USAGE") + +import java.util.* + plugins { - kotlin("jvm") version "1.8.22" - kotlin("plugin.serialization") version "1.8.22" - id("me.him188.maven-central-publish") version "1.0.0-dev-3" + kotlin("multiplatform") version "1.9.10" + kotlin("plugin.serialization") version "1.9.10" + id("com.github.gmazzo.buildconfig") version "3.1.0" } group = "xyz.cssxsh.pixiv" version = "1.3.1" -mavenCentralPublish { - useCentralS01() - singleDevGithubProject("cssxsh", "pixiv-client") - licenseFromGitHubProject("AGPL-3.0") - workingDir = System.getenv("PUBLICATION_TEMP")?.let { file(it).resolve(projectName) } - ?: buildDir.resolve("publishing-tmp") -} - repositories { mavenLocal() mavenCentral() } -dependencies { - api("com.squareup:gifencoder:0.10.1") - compileOnly("org.openpnp:opencv:4.6.0-0") - compileOnly("org.seleniumhq.selenium:selenium-java:4.10.0") - testImplementation(kotlin("test")) - testImplementation("org.openpnp:opencv:4.6.0-0") - testImplementation("org.seleniumhq.selenium:selenium-java:4.10.0") - // - api(platform("io.ktor:ktor-bom:2.3.3")) - api("io.ktor:ktor-client-auth") - api("io.ktor:ktor-client-encoding") - api("io.ktor:ktor-client-okhttp") - api("io.ktor:ktor-client-content-negotiation") - api("io.ktor:ktor-serialization-kotlinx-json") - // - api(platform("com.squareup.okhttp3:okhttp-bom:4.11.0")) - api("com.squareup.okhttp3:okhttp-dnsoverhttps") - // - implementation(platform("org.slf4j:slf4j-parent:2.0.7")) - testImplementation("org.slf4j:slf4j-simple") -} - kotlin { explicitApi() - target.compilations { - all { - kotlinOptions { - jvmTarget = "11" + jvmToolchain(17) + targetHierarchy.default() + jvm() + macosX64() + linuxX64() + + sourceSets { + val commonMain by getting { + dependencies { + api(platform("io.ktor:ktor-bom:2.3.3")) + api("io.ktor:ktor-client-auth") + api("io.ktor:ktor-client-encoding") + api("io.ktor:ktor-client-cio") + api("io.ktor:ktor-client-content-negotiation") + api("io.ktor:ktor-serialization-kotlinx-json") +// api(platform("com.squareup.okhttp3:okhttp-bom:4.11.0")) + implementation("com.squareup.okio:okio:3.5.0") + implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1") + + implementation(platform("org.kotlincrypto.hash:bom:0.3.0")) + implementation("org.kotlincrypto.hash:sha2") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3") + } + } + commonTest.configure { + dependencies { + implementation(kotlin("test")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3") + } + } + + val jvmMain by getting { + dependencies { + implementation("io.ktor:ktor-client-okhttp") + } + } + + val nativeMain by getting { + dependencies { + implementation("io.ktor:ktor-client-curl") } } } } -java { - sourceCompatibility = JavaVersion.VERSION_11 - targetCompatibility = JavaVersion.VERSION_11 +val properties = Properties().apply { + try { + load(rootProject.file("local.properties").reader()) + } catch (e: Exception) { + println("local.properties file not found, you won't be able to run tests") + } } -tasks { - test { - useJUnitPlatform() - } +buildConfig { + buildConfigField("String", "REFRESH_TOKEN", provider { "\"${properties["refresh_token"]}\"" }) } \ No newline at end of file diff --git a/example/99565513.json b/example/99565513.json index 636b6b1..e04c3fb 100644 --- a/example/99565513.json +++ b/example/99565513.json @@ -1 +1,61 @@ -{"caption":"now loadingシリーズのケーちゃんです(*‘ω‘ *)","create_date":"2022-07-07T20:21:24+09:00","width":560,"height":315,"id":99565513,"image_urls":{"square_medium":"https://i.pximg.net/c/540x540_10_webp/img-master/img/2022/07/07/20/21/24/99565513_square1200.jpg","medium":"https://i.pximg.net/c/540x540_70/img-master/img/2022/07/07/20/21/24/99565513_master1200.jpg","large":"https://i.pximg.net/c/600x1200_90_webp/img-master/img/2022/07/07/20/21/24/99565513_master1200.jpg"},"is_bookmarked":false,"is_muted":false,"meta_pages":[],"meta_single_page":{"original_image_url":"https://i.pximg.net/img-original/img/2022/07/07/20/21/24/99565513_ugoira0.jpg"},"page_count":1,"restrict":0,"sanity_level":2,"series":null,"tags":[{"name":"うごイラ","translated_name":"动图"},{"name":"アークナイツ","translated_name":"明日方舟"},{"name":"明日方舟","translated_name":"Arknights"},{"name":"Arknights","translated_name":"明日方舟"},{"name":"ケオベ(アークナイツ)","translated_name":"刻俄柏(明日方舟)"}],"title":"ふりふりケーちゃん","tools":[],"total_bookmarks":347,"total_comments":12,"total_view":2626,"type":"ugoira","user":{"account":"sukoru_pisu","id":72778,"is_followed":false,"name":"Ca","profile_image_urls":{"medium":"https://i.pximg.net/user-profile/img/2020/02/29/06/21/21/18012369_ac14844d6d07b1df5f6a12d415d0acfb_170.jpg"}},"visible":true,"x_restrict":0} \ No newline at end of file +{ + "caption": "now loadingシリーズのケーちゃんです(*‘ω‘ *)", + "create_date": "2022-07-07T20:21:24+09:00", + "width": 560, + "height": 315, + "id": 99565513, + "image_urls": { + "square_medium": "https://i.pximg.net/c/540x540_10_webp/img-master/img/2022/07/07/20/21/24/99565513_square1200.jpg", + "medium": "https://i.pximg.net/c/540x540_70/img-master/img/2022/07/07/20/21/24/99565513_master1200.jpg", + "large": "https://i.pximg.net/c/600x1200_90_webp/img-master/img/2022/07/07/20/21/24/99565513_master1200.jpg" + }, + "is_bookmarked": false, + "is_muted": false, + "meta_pages": [], + "meta_single_page": { + "original_image_url": "https://i.pximg.net/img-original/img/2022/07/07/20/21/24/99565513_ugoira0.jpg" + }, + "page_count": 1, + "restrict": 0, + "sanity_level": 2, + "series": null, + "tags": [ + { + "name": "うごイラ", + "translated_name": "动图" + }, + { + "name": "アークナイツ", + "translated_name": "明日方舟" + }, + { + "name": "明日方舟", + "translated_name": "Arknights" + }, + { + "name": "Arknights", + "translated_name": "明日方舟" + }, + { + "name": "ケオベ(アークナイツ)", + "translated_name": "刻俄柏(明日方舟)" + } + ], + "title": "ふりふりケーちゃん", + "tools": [], + "total_bookmarks": 347, + "total_comments": 12, + "total_view": 2626, + "type": "ugoira", + "user": { + "account": "sukoru_pisu", + "id": 72778, + "is_followed": false, + "name": "Ca", + "profile_image_urls": { + "medium": "https://i.pximg.net/user-profile/img/2020/02/29/06/21/21/18012369_ac14844d6d07b1df5f6a12d415d0acfb_170.jpg" + } + }, + "visible": true, + "x_restrict": 0 +} \ No newline at end of file diff --git a/example/99565513.ugoira.json b/example/99565513.ugoira.json index 52e4b7c..9d94b3b 100644 --- a/example/99565513.ugoira.json +++ b/example/99565513.ugoira.json @@ -1 +1,71 @@ -{"frames":[{"delay":30,"file":"000000.jpg"},{"delay":30,"file":"000001.jpg"},{"delay":40,"file":"000002.jpg"},{"delay":30,"file":"000003.jpg"},{"delay":30,"file":"000004.jpg"},{"delay":40,"file":"000005.jpg"},{"delay":30,"file":"000006.jpg"},{"delay":30,"file":"000007.jpg"},{"delay":40,"file":"000008.jpg"},{"delay":30,"file":"000009.jpg"},{"delay":30,"file":"000010.jpg"},{"delay":40,"file":"000011.jpg"},{"delay":30,"file":"000012.jpg"},{"delay":30,"file":"000013.jpg"},{"delay":40,"file":"000014.jpg"},{"delay":30,"file":"000015.jpg"}],"zip_urls":{"medium":"https://i.pximg.net/img-zip-ugoira/img/2022/07/07/20/21/24/99565513_ugoira600x600.zip"}} \ No newline at end of file +{ + "frames": [ + { + "delay": 30, + "file": "000000.jpg" + }, + { + "delay": 30, + "file": "000001.jpg" + }, + { + "delay": 40, + "file": "000002.jpg" + }, + { + "delay": 30, + "file": "000003.jpg" + }, + { + "delay": 30, + "file": "000004.jpg" + }, + { + "delay": 40, + "file": "000005.jpg" + }, + { + "delay": 30, + "file": "000006.jpg" + }, + { + "delay": 30, + "file": "000007.jpg" + }, + { + "delay": 40, + "file": "000008.jpg" + }, + { + "delay": 30, + "file": "000009.jpg" + }, + { + "delay": 30, + "file": "000010.jpg" + }, + { + "delay": 40, + "file": "000011.jpg" + }, + { + "delay": 30, + "file": "000012.jpg" + }, + { + "delay": 30, + "file": "000013.jpg" + }, + { + "delay": 40, + "file": "000014.jpg" + }, + { + "delay": 30, + "file": "000015.jpg" + } + ], + "zip_urls": { + "medium": "https://i.pximg.net/img-zip-ugoira/img/2022/07/07/20/21/24/99565513_ugoira600x600.zip" + } +} \ No newline at end of file diff --git a/local.properties b/local.properties deleted file mode 100644 index e69de29..0000000 diff --git a/pixiv_auth.py b/pixiv_auth.py new file mode 100755 index 0000000..e0a27a9 --- /dev/null +++ b/pixiv_auth.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 + +import requests +from argparse import ArgumentParser +from base64 import urlsafe_b64encode +from hashlib import sha256 +from pprint import pprint +from secrets import token_urlsafe +from sys import exit +from urllib.parse import urlencode +from webbrowser import open as open_url + +# Latest app version can be found using GET /v1/application-info/android +USER_AGENT = "PixivAndroidApp/5.0.234 (Android 11; Pixel 5)" +REDIRECT_URI = "https://app-api.pixiv.net/web/v1/users/auth/pixiv/callback" +LOGIN_URL = "https://app-api.pixiv.net/web/v1/login" +AUTH_TOKEN_URL = "https://oauth.secure.pixiv.net/auth/token" +CLIENT_ID = "MOBrBDS8blbauoSck0ZfDbtuzpyT" +CLIENT_SECRET = "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj" + + +def s256(data): + """S256 transformation method.""" + + return urlsafe_b64encode(sha256(data).digest()).rstrip(b"=").decode("ascii") + + +def oauth_pkce(transform): + """Proof Key for Code Exchange by OAuth Public Clients (RFC7636).""" + + code_verifier = token_urlsafe(32) + code_challenge = transform(code_verifier.encode("ascii")) + + return code_verifier, code_challenge + + +def print_auth_token_response(response): + data = response.json() + + try: + access_token = data["access_token"] + refresh_token = data["refresh_token"] + except KeyError: + print("error:") + pprint(data) + exit(1) + + print("access_token:", access_token) + print("refresh_token:", refresh_token) + print("expires_in:", data.get("expires_in", 0)) + + +def login(): + code_verifier, code_challenge = oauth_pkce(s256) + login_params = { + "code_challenge": code_challenge, + "code_challenge_method": "S256", + "client": "pixiv-android", + } + + open_url(f"{LOGIN_URL}?{urlencode(login_params)}") + + try: + code = input("code: ").strip() + except (EOFError, KeyboardInterrupt): + return + + response = requests.post( + AUTH_TOKEN_URL, + data={ + "client_id": CLIENT_ID, + "client_secret": CLIENT_SECRET, + "code": code, + "code_verifier": code_verifier, + "grant_type": "authorization_code", + "include_policy": "true", + "redirect_uri": REDIRECT_URI, + }, + headers={"User-Agent": USER_AGENT}, + ) + + print_auth_token_response(response) + + +def refresh(refresh_token): + response = requests.post( + AUTH_TOKEN_URL, + data={ + "client_id": CLIENT_ID, + "client_secret": CLIENT_SECRET, + "grant_type": "refresh_token", + "include_policy": "true", + "refresh_token": refresh_token, + }, + headers={"User-Agent": USER_AGENT}, + ) + print_auth_token_response(response) + + +def main(): + parser = ArgumentParser() + subparsers = parser.add_subparsers() + parser.set_defaults(func=lambda _: parser.print_usage()) + login_parser = subparsers.add_parser("login") + login_parser.set_defaults(func=lambda _: login()) + refresh_parser = subparsers.add_parser("refresh") + refresh_parser.add_argument("refresh_token") + refresh_parser.set_defaults(func=lambda ns: refresh(ns.refresh_token)) + args = parser.parse_args() + args.func(args) + + +if __name__ == "__main__": + main() diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/OtherAuth.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/OtherAuth.kt similarity index 87% rename from src/main/kotlin/xyz/cssxsh/pixiv/OtherAuth.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/OtherAuth.kt index 483a8c8..ad726d1 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/OtherAuth.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/OtherAuth.kt @@ -8,11 +8,8 @@ import io.ktor.client.request.forms.* import io.ktor.client.statement.* import io.ktor.http.* import kotlinx.coroutines.* -import org.openqa.selenium.WebDriverException -import org.openqa.selenium.logging.* -import org.openqa.selenium.remote.* import xyz.cssxsh.pixiv.auth.* -import xyz.cssxsh.pixiv.tool.* +import xyz.cssxsh.pixiv.tool.CaptchaHandler public const val WEIBO_QRCODE_GENERATE: String = "https://api.weibo.com/oauth2/qrcode_authorize/generate" @@ -96,13 +93,6 @@ private suspend fun PixivAuthClient.redirect(link: Url): String { } } - code.contentType()?.let { type -> - java.io.File("pixiv.login.error.${type.contentSubtype}") - .writeBytes(code.body()) - java.io.File("pixiv.login.cookies") - .writeText(storage.get(authorize).joinToString("\n", transform = ::renderCookieHeader)) - } - val scheme = requireNotNull(code.location()) { "跳转到 pixiv://... 失败" } /** @@ -294,27 +284,3 @@ public suspend fun PixivAuthClient.password(id: String, pwd: String, handler: Ca redirect(link = link) } - -/** - * 登录,通过 selenium 调用浏览器 - * @param driver 浏览器驱动器 - */ -public suspend fun PixivAuthClient.selenium(driver: RemoteWebDriver, timeout: Long): AuthResult = login { redirect -> - try { - driver.get(redirect.toString()) - } catch (_: WebDriverException) { - // - } - withTimeout(timeout) { - while (driver.currentUrl.orEmpty().startsWith(POST_REDIRECT_URL).not()) { - delay(10_000) - } - } - // XXX: 通过错误日志获取 跳转URL - val log = driver.manage().logs().get(LogType.BROWSER) - .findLast { log -> "pixiv://account/login" in log.message.orEmpty() } - ?: throw NoSuchElementException("No Found pixiv://account/login") - val url = Url(log.message.substringAfter("'").substringBefore("'")) - - url.parameters["code"] ?: throw NoSuchElementException("code, ${log.message}") -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/PixivAppClient.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivAppClient.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/PixivAppClient.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivAppClient.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.kt similarity index 78% rename from src/main/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.kt index fbf013d..b916025 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.kt @@ -1,7 +1,7 @@ package xyz.cssxsh.pixiv import io.ktor.client.* -import io.ktor.client.engine.okhttp.* +import io.ktor.client.engine.* import io.ktor.client.plugins.* import io.ktor.client.plugins.auth.* import io.ktor.client.plugins.compression.* @@ -10,20 +10,23 @@ import io.ktor.client.plugins.cookies.* import io.ktor.client.request.* import io.ktor.http.* import io.ktor.http.auth.* -import io.ktor.utils.io.core.* import io.ktor.serialization.kotlinx.json.* -import kotlinx.coroutines.* -import kotlinx.coroutines.sync.* +import io.ktor.utils.io.core.* +import kotlinx.coroutines.isActive +import kotlinx.coroutines.supervisorScope +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import kotlinx.datetime.Clock import xyz.cssxsh.pixiv.auth.* -import xyz.cssxsh.pixiv.exception.* -import xyz.cssxsh.pixiv.tool.* -import java.time.* +import xyz.cssxsh.pixiv.exception.TransferExceptionHandler + +internal expect val httpClient: HttpClientEngineFactory<*> public abstract class PixivAuthClient : PixivAppClient, Closeable { protected open var auth: AuthResult? = null - protected open var expires: OffsetDateTime = OffsetDateTime.MIN + protected open var expiresSeconds: Long = 0L protected abstract val ignore: suspend (Throwable) -> Boolean @@ -34,7 +37,7 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { protected open val timeout: Long = 30_000L - protected open fun client(): HttpClient = HttpClient(OkHttp) { + protected open fun client(): HttpClient = HttpClient(httpClient) { install(ContentNegotiation) { json(json = PixivJson) } @@ -55,7 +58,9 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { header(HttpHeaders.CacheControl, "no-cache") header(HttpHeaders.Connection, "keep-alive") header(HttpHeaders.Pragma, "no-cache") - config.headers.forEach(::header) + config.headers.forEach { + header(it.key, it.value) + } url("https://www.pixiv.net") } Auth { @@ -71,8 +76,8 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { override suspend fun addRequestHeaders(request: HttpRequestBuilder, authHeader: HttpAuthHeader?) { val info = mutex.withLock { - auth?.takeIf { expires > OffsetDateTime.now() } ?: useHttpClient { client -> - val start = OffsetDateTime.now() + auth?.takeIf { expiresSeconds > Clock.System.now().epochSeconds } ?: useHttpClient { client -> + val start = Clock.System.now().epochSeconds client.refresh(refreshToken).save(start = start) } } @@ -94,21 +99,7 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { } }) } - engine { - config { - with(config) { - if (proxy.isNotBlank()) { - proxy(Url(proxy).toProxy()) - } else if (config.sni) { - sslSocketFactory(RubySSLSocketFactory, RubyX509TrustManager) - hostnameVerifier { _, _ -> true } - } - dns(RubyDns(dns, host)) - } - // StreamResetException: stream was reset: REFUSED_STREAM - // protocols(listOf(Protocol.HTTP_1_1)) - } - } + // TODO set proxy, dns and SSL based on config } protected open val clients: MutableList by lazy { MutableList(3) { client() } } @@ -129,7 +120,7 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { } } } - throw CancellationException() + throw kotlin.coroutines.cancellation.CancellationException() } protected open val mutex: Mutex = Mutex() @@ -160,8 +151,8 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { * 认证信息 */ override suspend fun info(): AuthResult = mutex.withLock { - val start = OffsetDateTime.now() - auth?.takeIf { expires > OffsetDateTime.now() } ?: useHttpClient { client -> + val start = Clock.System.now().epochSeconds + auth?.takeIf { expiresSeconds > Clock.System.now().epochSeconds } ?: useHttpClient { client -> client.refresh(token = refreshToken).save(start = start) } } @@ -174,7 +165,7 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { * @see authorize */ override suspend fun login(block: suspend (redirect: Url) -> String): AuthResult = mutex.withLock { - val start = OffsetDateTime.now() + val start = Clock.System.now().epochSeconds val (verifier, parameters) = verifier(time = start) val code = block(URLBuilder(REDIRECT_LOGIN_URL).apply { this.parameters.appendAll(parameters) }.build()) useHttpClient { client -> @@ -187,14 +178,14 @@ public abstract class PixivAuthClient : PixivAppClient, Closeable { * @see refreshToken */ override suspend fun refresh(): AuthResult = mutex.withLock { - val start = OffsetDateTime.now() + val start = Clock.System.now().epochSeconds useHttpClient { client -> client.refresh(token = refreshToken).save(start = start) } } - protected open suspend fun AuthResult.save(start: OffsetDateTime): AuthResult = also { result -> - expires = start.withNano(0).plusSeconds(result.expiresIn) + protected open suspend fun AuthResult.save(start: Long): AuthResult = also { result -> + expiresSeconds = start + result.expiresIn auth = result.copy(deviceToken = storage.get(Url(REDIRECT_LOGIN_URL))["device_token"]?.value) config { refreshToken = result.refreshToken diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/PixivConfig.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivConfig.kt similarity index 59% rename from src/main/kotlin/xyz/cssxsh/pixiv/PixivConfig.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivConfig.kt index f748cdb..d490304 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/PixivConfig.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivConfig.kt @@ -1,19 +1,10 @@ package xyz.cssxsh.pixiv -import kotlinx.serialization.* - -@Serializable public data class PixivConfig( - @SerialName("headers") var headers: HeadersMap = ANDROID_HEADERS, - @SerialName("proxy") var proxy: String = "", - @SerialName("dns") var dns: String = JAPAN_DNS, - @SerialName("host") var host: Map> = DEFAULT_PIXIV_HOST, - @SerialName("sni") var sni: Boolean = true, - @SerialName("refresh_token") var refreshToken: String? = null, ) \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/PixivUtils.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivUtils.kt similarity index 90% rename from src/main/kotlin/xyz/cssxsh/pixiv/PixivUtils.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivUtils.kt index ef5aa36..0f1b635 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/PixivUtils.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivUtils.kt @@ -2,26 +2,23 @@ package xyz.cssxsh.pixiv import io.ktor.client.plugins.auth.providers.* import io.ktor.http.* -import kotlinx.serialization.* -import kotlinx.serialization.descriptors.* -import kotlinx.serialization.encoding.* -import kotlinx.serialization.json.* -import kotlinx.serialization.modules.* -import xyz.cssxsh.pixiv.auth.* -import xyz.cssxsh.pixiv.exception.* -import java.net.* -import java.util.* +import kotlinx.serialization.KSerializer +import kotlinx.serialization.Serializable +import kotlinx.serialization.descriptors.PrimitiveKind +import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor +import kotlinx.serialization.descriptors.SerialDescriptor +import kotlinx.serialization.encoding.Decoder +import kotlinx.serialization.encoding.Encoder +import kotlinx.serialization.json.Json +import xyz.cssxsh.pixiv.auth.AuthResult public typealias HeadersMap = Map public typealias FileUrls = Map public val PixivJson: Json = Json { - ignoreUnknownKeys = System.getProperty("xyz.cssxsh.pixiv.json.ignore", "true").toBoolean() + ignoreUnknownKeys = true allowSpecialFloatingPointValues = true - serializersModule += SerializersModule { - contextual(JapanDateTimeSerializer) - } } public const val HTTP_KILO: Int = 1022 @@ -31,7 +28,7 @@ public const val IOS_CLIENT_ID: String = "KzEZED7aC0vird8jWyHM38mXjNTY" public const val IOS_CLIENT_SECRET: String = "W9JZoJe00qPvJsiyCGT3CCtC6ZUtdpKpzMbNlUGP" public val IOS_HEADERS: HeadersMap = mapOf( - HttpHeaders.AcceptLanguage to Locale.CHINA.language, + HttpHeaders.AcceptLanguage to "zh", HttpHeaders.UserAgent to "PixivIOSApp/7.13.3 (iOS 14.6; iPhone13,2)", "App-OS-Version" to "14.6", "App-OS" to "ios" @@ -42,7 +39,7 @@ public const val ANDROID_CLIENT_ID: String = "MOBrBDS8blbauoSck0ZfDbtuzpyT" public const val ANDROID_CLIENT_SECRET: String = "lsACyCD94FhDUtGTXi3QzcFE2uU1hqtDaKeqrdwj" public val ANDROID_HEADERS: HeadersMap = mapOf( - HttpHeaders.AcceptLanguage to Locale.CHINA.language, + HttpHeaders.AcceptLanguage to "zh", HttpHeaders.UserAgent to "PixivAndroidApp/6.45.0 (Android 8.0)", "App-OS-Version" to "8.0", "App-OS" to "android" @@ -67,15 +64,6 @@ public const val LIMIT_UNKNOWN_IMAGE: String = "https://s.pximg.net/common/image public const val LIMIT_MYPIXIV_IMAGE: String = "https://s.pximg.net/common/images/limit_mypixiv_360.png" -internal fun Url.toProxy(): Proxy { - val type = when (protocol) { - URLProtocol.SOCKS -> Proxy.Type.SOCKS - URLProtocol.HTTP -> Proxy.Type.HTTP - else -> throw ProxyException(this) - } - return Proxy(type, InetSocketAddress(host, port)) -} - internal fun AuthResult.toBearerTokens(): BearerTokens = BearerTokens(accessToken, refreshToken) @Suppress("FunctionName") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/PixivWebClient.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivWebClient.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/PixivWebClient.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/PixivWebClient.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/SimplePixivClient.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/SimplePixivClient.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/SimplePixivClient.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/SimplePixivClient.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/UseConfig.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/UseConfig.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/UseConfig.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/UseConfig.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/UseHttpClient.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/UseHttpClient.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/UseHttpClient.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/UseHttpClient.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/AppApi.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/AppApi.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/AppApi.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/AppApi.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/ApplicationData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/ApplicationData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/ApplicationData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/ApplicationData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Blacklist.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Blacklist.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Blacklist.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Blacklist.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetail.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetail.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetail.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetail.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetailSingle.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetailSingle.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetailSingle.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkDetailSingle.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkRangeData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkRangeData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkRangeData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkRangeData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkTagData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkTagData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/BookmarkTagData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/BookmarkTagData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/CommentData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/CommentData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/CommentData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/CommentData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/CommentInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/CommentInfo.kt similarity index 77% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/CommentInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/CommentInfo.kt index 056c8fb..19c9b12 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/apps/CommentInfo.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/CommentInfo.kt @@ -1,15 +1,15 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.serialization.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + @Serializable public data class CommentInfo( @SerialName("comment") val comment: String, @SerialName("date") - @Contextual - val date: OffsetDateTime, + val date: String, @SerialName("has_replies") val hasReplies: Boolean, @SerialName("id") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/CommentStamp.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/CommentStamp.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/CommentStamp.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/CommentStamp.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/EmojiDefinitionData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/EmojiDefinitionData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/EmojiDefinitionData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/EmojiDefinitionData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Illust.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Illust.kt similarity index 96% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Illust.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Illust.kt index da20a9a..e8e9114 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Illust.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Illust.kt @@ -4,10 +4,9 @@ import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.http.* -import kotlinx.serialization.json.* +import kotlinx.datetime.LocalDate +import kotlinx.serialization.json.JsonElement import xyz.cssxsh.pixiv.* -import java.time.* -import java.time.format.* public suspend fun PixivAppClient.illustBookmarkAdd( pid: Long, @@ -103,7 +102,7 @@ public suspend fun PixivAppClient.illustRanking( url: String = ILLUST_RANKING, ): IllustData = useHttpClient { client -> client.get(url) { - parameter("date", date?.format(DateTimeFormatter.ISO_DATE)) + parameter("date", date?.toString()) parameter("mode", mode) parameter("filter", filter) parameter("offset", offset) diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/IllustData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/IllustData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/IllustData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/IllustData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/IllustInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/IllustInfo.kt similarity index 95% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/IllustInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/IllustInfo.kt index 1b06a2a..ec4743b 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/apps/IllustInfo.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/IllustInfo.kt @@ -1,17 +1,17 @@ package xyz.cssxsh.pixiv.apps import io.ktor.http.* -import kotlinx.serialization.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable import xyz.cssxsh.pixiv.* -import java.time.* + @Serializable public data class IllustInfo( @SerialName("caption") val caption: String, @SerialName("create_date") - @Contextual - val createAt: OffsetDateTime, + val createAt: String, @SerialName("width") val width: Int, @SerialName("height") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/IllustSingle.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/IllustSingle.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/IllustSingle.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/IllustSingle.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/KeywordsData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/KeywordsData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/KeywordsData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/KeywordsData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Novel.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Novel.kt similarity index 94% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Novel.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Novel.kt index 32eeacc..425c9ee 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Novel.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Novel.kt @@ -4,10 +4,12 @@ import io.ktor.client.call.* import io.ktor.client.request.* import io.ktor.client.request.forms.* import io.ktor.http.* -import kotlinx.serialization.json.* -import xyz.cssxsh.pixiv.* -import java.time.* -import java.time.format.* +import kotlinx.datetime.LocalDate +import kotlinx.serialization.json.JsonElement +import xyz.cssxsh.pixiv.FilterType +import xyz.cssxsh.pixiv.PixivAppClient +import xyz.cssxsh.pixiv.PublicityType +import xyz.cssxsh.pixiv.RankMode public suspend fun PixivAppClient.novelBookmarkAdd( pid: Long, @@ -124,7 +126,7 @@ public suspend fun PixivAppClient.novelRanking( offset: Long = 0, url: String = NOVEL_RANKING, ): NovelData = novelRanking( - date = date.format(DateTimeFormatter.ISO_DATE), + date = date.toString(), mode = mode, filter = filter, offset = offset, diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/NovelData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/NovelData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/NovelData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/NovelData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt similarity index 86% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt index 312155c..c441015 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/NovelInfo.kt @@ -1,16 +1,18 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.serialization.* -import xyz.cssxsh.pixiv.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import xyz.cssxsh.pixiv.AgeLimit +import xyz.cssxsh.pixiv.FileUrls +import xyz.cssxsh.pixiv.PublicityType + @Serializable public data class NovelInfo( @SerialName("caption") val caption: String, @SerialName("create_date") - @Contextual - val createAt: OffsetDateTime, + val createAt: String, @SerialName("text_length") val textLength: Long, @SerialName("id") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Other.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Other.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Other.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Other.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/PreviewData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/PreviewData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/PreviewData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/PreviewData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/RecommendedData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/RecommendedData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/RecommendedData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/RecommendedData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Search.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Search.kt similarity index 89% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Search.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Search.kt index 0802a73..ae7c23c 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Search.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Search.kt @@ -2,9 +2,8 @@ package xyz.cssxsh.pixiv.apps import io.ktor.client.call.* import io.ktor.client.request.* +import kotlinx.datetime.LocalDate import xyz.cssxsh.pixiv.* -import java.time.* -import java.time.format.* public suspend fun PixivAppClient.searchAutoCompleteOld( word: String, @@ -40,8 +39,8 @@ public suspend fun PixivAppClient.searchBookmarkRangesIllust( client.get(url) { parameter("word", word) parameter("search_target", target) - parameter("start_date", start?.format(DateTimeFormatter.ISO_DATE)) - parameter("end_date", end?.format(DateTimeFormatter.ISO_DATE)) + parameter("start_date", start?.toString()) + parameter("end_date", end?.toString()) parameter("include_translated_tag_results", translated) parameter("merge_plain_keyword_results", merge) parameter("offset", offset) @@ -74,8 +73,8 @@ public suspend fun PixivAppClient.searchIllust( parameter("duration", duration) parameter("bookmark_num_min", min) parameter("bookmark_num_max", max) - parameter("start_date", start?.format(DateTimeFormatter.ISO_DATE)) - parameter("end_date", end?.format(DateTimeFormatter.ISO_DATE)) + parameter("start_date", start?.toString()) + parameter("end_date", end?.toString()) parameter("include_translated_tag_results", translated) parameter("merge_plain_keyword_results", merge) parameter("offset", offset) diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/SeriesInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/SeriesInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/SeriesInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/SeriesInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Spotlight.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Spotlight.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Spotlight.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Spotlight.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticle.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticle.kt similarity index 81% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticle.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticle.kt index 17a4180..1082e8d 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticle.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticle.kt @@ -1,7 +1,8 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.serialization.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + @Serializable public data class SpotlightArticle( @@ -12,8 +13,8 @@ public data class SpotlightArticle( @SerialName("id") val aid: Long, @SerialName("publish_date") - @Contextual - val publish: OffsetDateTime, + + val publish: String, @SerialName("pure_title") val pureTitle: String, @SerialName("subcategory_label") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticleData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticleData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticleData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/SpotlightArticleData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/StampData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/StampData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/StampData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/StampData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/TagData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TagData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/TagData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TagData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/TagInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TagInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/TagInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TagInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/TrendIllust.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TrendIllust.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/TrendIllust.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TrendIllust.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/TrendIllustData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TrendIllustData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/TrendIllustData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/TrendIllustData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Trending.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Trending.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Trending.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Trending.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/Ugoira.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Ugoira.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/Ugoira.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/Ugoira.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/UgoiraFrame.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UgoiraFrame.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/UgoiraFrame.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UgoiraFrame.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/UgoiraInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UgoiraInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/UgoiraInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UgoiraInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/UgoiraMetadata.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UgoiraMetadata.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/UgoiraMetadata.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UgoiraMetadata.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/User.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/User.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/User.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/User.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/UserDetail.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserDetail.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/UserDetail.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserDetail.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/UserIllustData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserIllustData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/UserIllustData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserIllustData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/UserInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/UserInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/apps/UserPreview.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserPreview.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/apps/UserPreview.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/apps/UserPreview.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/auth/AuthResult.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/AuthResult.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/auth/AuthResult.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/AuthResult.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/auth/HtmlAccount.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/HtmlAccount.kt similarity index 89% rename from src/main/kotlin/xyz/cssxsh/pixiv/auth/HtmlAccount.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/HtmlAccount.kt index d32f38b..b7d5806 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/auth/HtmlAccount.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/HtmlAccount.kt @@ -1,6 +1,7 @@ package xyz.cssxsh.pixiv.auth -import kotlinx.serialization.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable /** * * `https://accounts.pixiv.net/` @@ -15,7 +16,7 @@ public data class HtmlAccount( @SerialName("pixivAccount.tt") val token: String = "", @SerialName("pixivAccount.userId") - val uid: Long? = null, + val uid: Boolean? = null, @SerialName("pixivAccount.ref") val ref: String = "", @SerialName("pixivAccount.recaptchaEnterpriseScoreSiteKey") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt similarity index 88% rename from src/main/kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt index 3a9a14c..87825bc 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/OauthApi.kt @@ -5,9 +5,11 @@ import io.ktor.client.call.* import io.ktor.client.request.forms.* import io.ktor.http.* import io.ktor.util.* -import xyz.cssxsh.pixiv.* -import java.security.* -import java.time.* +import io.ktor.utils.io.charsets.* +import io.ktor.utils.io.core.* +import org.kotlincrypto.hash.sha2.SHA256 +import xyz.cssxsh.pixiv.ANDROID_CLIENT_ID +import xyz.cssxsh.pixiv.ANDROID_CLIENT_SECRET import kotlin.random.Random public const val OAUTH_TOKEN_URL: String = "https://oauth.secure.pixiv.net/auth/token" @@ -35,16 +37,16 @@ public const val GIGYA_AUTH_URL: String = "https://accounts.pixiv.net/gigya-auth public const val SOCIALIZE_LOGIN_URL: String = "https://socialize.gigya.com/socialize.login" private fun String.sha256(): ByteArray { - return MessageDigest.getInstance("SHA-256") - .digest(toByteArray(Charsets.US_ASCII)) + val digest = SHA256() + return digest.digest(toByteArray(Charsets.UTF_8)) } private const val VERIFIER_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" private const val VERIFIER_LENGTH = 128 -internal fun verifier(time: OffsetDateTime): Pair { - val random = Random(time.toEpochSecond()) +internal fun verifier(time: Long): Pair { + val random = Random(time) val origin = buildString(VERIFIER_LENGTH) { repeat(VERIFIER_LENGTH) { append(VERIFIER_CHARS[random.nextInt(VERIFIER_CHARS.length)]) diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/auth/WebLoginResult.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/WebLoginResult.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/auth/WebLoginResult.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/WebLoginResult.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcode.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcode.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcode.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcode.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcodeStatus.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcodeStatus.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcodeStatus.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/auth/WeiboQrcodeStatus.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/AppApiError.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AppApiError.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/AppApiError.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AppApiError.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/AppApiException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AppApiException.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/AppApiException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AppApiException.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/AuthError.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AuthError.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/AuthError.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AuthError.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/AuthException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AuthException.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/AuthException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/AuthException.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/MatchContentLengthException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/MatchContentLengthException.kt similarity index 69% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/MatchContentLengthException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/MatchContentLengthException.kt index 6c8a1f8..9d8e59a 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/exception/MatchContentLengthException.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/MatchContentLengthException.kt @@ -5,11 +5,13 @@ import io.ktor.client.statement.* import io.ktor.util.* import kotlinx.coroutines.* -public class MatchContentLengthException(response: HttpResponse) : - ResponseException(response, "") { +public class MatchContentLengthException( + response: HttpResponse +) : ResponseException(response, "") { + init { response.call.cancel(super.message!!) } override val message: String = "Not Match ContentLength $response ${response.headers.toMap()}" -} \ No newline at end of file +} diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/NoCacheException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/NoCacheException.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/NoCacheException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/NoCacheException.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/OtherClientException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/OtherClientException.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/OtherClientException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/OtherClientException.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/ProxyException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/ProxyException.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/ProxyException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/ProxyException.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/RestrictException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/RestrictException.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/RestrictException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/RestrictException.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/TransferExceptionHandler.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/TransferExceptionHandler.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/TransferExceptionHandler.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/TransferExceptionHandler.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/exception/WebApiException.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/WebApiException.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/exception/WebApiException.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/exception/WebApiException.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CommentInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CommentInfo.kt similarity index 83% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CommentInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CommentInfo.kt index 50ca3da..5fa3a49 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CommentInfo.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CommentInfo.kt @@ -1,15 +1,16 @@ package xyz.cssxsh.pixiv.fanbox -import kotlinx.serialization.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + @Serializable public data class CommentInfo( @SerialName("body") val body: String, - @Contextual + @SerialName("createdDatetime") - val createdDatetime: OffsetDateTime, + val createdDatetime: String, @SerialName("id") val id: Long, @SerialName("isLiked") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CommentList.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CommentList.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CommentList.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CommentList.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorActive.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorActive.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorActive.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorActive.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorDetail.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorDetail.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorDetail.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorDetail.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/CreatorInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt similarity index 86% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt index 1879619..e81cf29 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxApi.kt @@ -4,13 +4,14 @@ import io.ktor.client.call.* import io.ktor.client.plugins.cookies.* import io.ktor.client.request.* import io.ktor.http.* -import kotlinx.coroutines.sync.* -import xyz.cssxsh.pixiv.* -import java.util.* +import kotlinx.coroutines.sync.Mutex +import kotlinx.coroutines.sync.withLock +import xyz.cssxsh.pixiv.PixivJson +import xyz.cssxsh.pixiv.PixivWebClient public abstract class FanBoxApi { public companion object { - internal val contexts = WeakHashMap() + internal val contexts = HashMap() internal val mutex = Mutex() } diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxBell.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxBell.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxBell.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxBell.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxCreator.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxCreator.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxCreator.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxCreator.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNewsLetter.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNewsLetter.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNewsLetter.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNewsLetter.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNotification.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNotification.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNotification.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxNotification.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPayment.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPayment.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPayment.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPayment.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPlan.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPlan.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPlan.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPlan.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPost.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPost.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPost.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxPost.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxTag.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxTag.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxTag.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxTag.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUser.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUser.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUser.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUser.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUtils.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUtils.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUtils.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/FanBoxUtils.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/ItemList.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/ItemList.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/ItemList.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/ItemList.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/MetaData.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/MetaData.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/MetaData.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/MetaData.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/Notification.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/Notification.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/Notification.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/Notification.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PaidRecord.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PaidRecord.kt similarity index 73% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PaidRecord.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PaidRecord.kt index 973ba20..7c2a442 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PaidRecord.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PaidRecord.kt @@ -1,7 +1,8 @@ package xyz.cssxsh.pixiv.fanbox -import kotlinx.serialization.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + @Serializable public data class PaidRecord( @@ -11,9 +12,9 @@ public data class PaidRecord( val id: Long, @SerialName("paidAmount") val paidAmount: Int, - @Contextual + @SerialName("paymentDatetime") - val paymentDatetime: OffsetDateTime, + val paymentDatetime: String, @SerialName("paymentMethod") val paymentMethod: String ) diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PlanInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PlanInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PlanInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PlanInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostDetail.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostDetail.kt similarity index 94% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostDetail.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostDetail.kt index b2831be..58be8f0 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostDetail.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostDetail.kt @@ -1,7 +1,8 @@ package xyz.cssxsh.pixiv.fanbox -import kotlinx.serialization.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + @Serializable public sealed class PostDetail { @@ -20,11 +21,11 @@ public sealed class PostDetail { public abstract val likeCount: Int public abstract val nextPost: Link? public abstract val prevPost: Link? - public abstract val publishedDatetime: OffsetDateTime + public abstract val publishedDatetime: String public abstract val restrictedFor: Int? public abstract val tags: List public abstract val title: String - public abstract val updatedDatetime: OffsetDateTime + public abstract val updatedDatetime: String public abstract val user: CreatorInfo @Serializable @@ -60,18 +61,18 @@ public sealed class PostDetail { override val nextPost: Link? = null, @SerialName("prevPost") override val prevPost: Link? = null, - @Contextual + @SerialName("publishedDatetime") - override val publishedDatetime: OffsetDateTime, + override val publishedDatetime: String, @SerialName("restrictedFor") override val restrictedFor: Int?, @SerialName("tags") override val tags: List, @SerialName("title") override val title: String, - @Contextual + @SerialName("updatedDatetime") - override val updatedDatetime: OffsetDateTime, + override val updatedDatetime: String, @SerialName("user") override val user: CreatorInfo ) : PostDetail() @@ -109,18 +110,18 @@ public sealed class PostDetail { override val nextPost: Link? = null, @SerialName("prevPost") override val prevPost: Link? = null, - @Contextual + @SerialName("publishedDatetime") - override val publishedDatetime: OffsetDateTime, + override val publishedDatetime: String, @SerialName("restrictedFor") override val restrictedFor: Int?, @SerialName("tags") override val tags: List, @SerialName("title") override val title: String, - @Contextual + @SerialName("updatedDatetime") - override val updatedDatetime: OffsetDateTime, + override val updatedDatetime: String, @SerialName("user") override val user: CreatorInfo ) : PostDetail() @@ -158,18 +159,18 @@ public sealed class PostDetail { override val nextPost: Link? = null, @SerialName("prevPost") override val prevPost: Link? = null, - @Contextual + @SerialName("publishedDatetime") - override val publishedDatetime: OffsetDateTime, + override val publishedDatetime: String, @SerialName("restrictedFor") override val restrictedFor: Int?, @SerialName("tags") override val tags: List, @SerialName("title") override val title: String, - @Contextual + @SerialName("updatedDatetime") - override val updatedDatetime: OffsetDateTime, + override val updatedDatetime: String, @SerialName("user") override val user: CreatorInfo ) : PostDetail() @@ -207,18 +208,18 @@ public sealed class PostDetail { override val nextPost: Link? = null, @SerialName("prevPost") override val prevPost: Link? = null, - @Contextual + @SerialName("publishedDatetime") - override val publishedDatetime: OffsetDateTime, + override val publishedDatetime: String, @SerialName("restrictedFor") override val restrictedFor: Int?, @SerialName("tags") override val tags: List, @SerialName("title") override val title: String, - @Contextual + @SerialName("updatedDatetime") - override val updatedDatetime: OffsetDateTime, + override val updatedDatetime: String, @SerialName("user") override val user: CreatorInfo ) : PostDetail() @@ -256,18 +257,18 @@ public sealed class PostDetail { override val nextPost: Link? = null, @SerialName("prevPost") override val prevPost: Link? = null, - @Contextual + @SerialName("publishedDatetime") - override val publishedDatetime: OffsetDateTime, + override val publishedDatetime: String, @SerialName("restrictedFor") override val restrictedFor: Int?, @SerialName("tags") override val tags: List, @SerialName("title") override val title: String, - @Contextual + @SerialName("updatedDatetime") - override val updatedDatetime: OffsetDateTime, + override val updatedDatetime: String, @SerialName("user") override val user: CreatorInfo ) : PostDetail() diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostInfo.kt similarity index 83% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostInfo.kt index 41edb38..8c6fcdc 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostInfo.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostInfo.kt @@ -1,7 +1,8 @@ package xyz.cssxsh.pixiv.fanbox -import kotlinx.serialization.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + @Serializable public data class PostInfo( @@ -19,9 +20,9 @@ public data class PostInfo( val id: Long, @SerialName("imageForShare") val imageForShare: String? = null, - @Contextual + @SerialName("publishedDatetime") - val publishedDatetime: OffsetDateTime, + val publishedDatetime: String, @SerialName("title") val title: String, @SerialName("user") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostList.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostList.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/PostList.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/PostList.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/TagFeature.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/TagFeature.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/TagFeature.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/TagFeature.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/TwitterAccountInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/TwitterAccountInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/TwitterAccountInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/TwitterAccountInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/UserSetting.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/UserSetting.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/UserSetting.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/UserSetting.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/fanbox/UserUpdate.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/UserUpdate.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/fanbox/UserUpdate.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/fanbox/UserUpdate.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/CaptchaHandler.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/CaptchaHandler.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/tool/CaptchaHandler.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/CaptchaHandler.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloader.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloader.kt similarity index 89% rename from src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloader.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloader.kt index 71190cf..397b178 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloader.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloader.kt @@ -1,7 +1,7 @@ package xyz.cssxsh.pixiv.tool import io.ktor.client.* -import io.ktor.client.engine.okhttp.* +import io.ktor.client.engine.cio.* import io.ktor.client.plugins.* import io.ktor.client.plugins.compression.* import io.ktor.client.request.* @@ -9,28 +9,25 @@ import io.ktor.client.statement.* import io.ktor.http.* import io.ktor.utils.io.errors.* import kotlinx.coroutines.* -import kotlinx.coroutines.channels.* -import okhttp3.ConnectionPool -import xyz.cssxsh.pixiv.* -import xyz.cssxsh.pixiv.exception.* -import java.net.* -import java.util.concurrent.* +import kotlinx.coroutines.channels.Channel +import xyz.cssxsh.pixiv.DEFAULT_PIXIV_HOST +import xyz.cssxsh.pixiv.HTTP_KILO +import xyz.cssxsh.pixiv.JAPAN_DNS +import xyz.cssxsh.pixiv.exception.MatchContentLengthException +import xyz.cssxsh.pixiv.exception.NoCacheException public open class PixivDownloader( async: Int = 32, protected open val blockSize: Int = 512 * HTTP_KILO, // HTTP use 1022 no 1024, - protected open val proxy: Proxy? = null, protected open val doh: String = JAPAN_DNS, protected open val host: Map> = DEFAULT_PIXIV_HOST, ) { protected open val timeout: Long = 10 * 1000L - protected open val ignore: suspend (Throwable) -> Boolean = { it is IOException } - protected open val channel: Channel = Channel(async) - protected open fun client(): HttpClient = HttpClient(OkHttp) { + protected open fun client(): HttpClient = HttpClient(CIO) { ContentEncoding() install(HttpTimeout) { socketTimeoutMillis = timeout @@ -43,15 +40,7 @@ public open class PixivDownloader( header(HttpHeaders.Pragma, "no-cache") } expectSuccess = true - engine { - config { - connectionPool(ConnectionPool(5, 10, TimeUnit.MINUTES)) - sslSocketFactory(RubySSLSocketFactory, RubyX509TrustManager) - hostnameVerifier { _, _ -> true } - proxy(this@PixivDownloader.proxy) - dns(RubyDns(doh, host)) - } - } + // TODO configure engine with DNS and SSL } protected open val clients: MutableList by lazy { MutableList(8) { client() } } diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/TwoCaptchaHandler.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/TwoCaptchaHandler.kt similarity index 96% rename from src/main/kotlin/xyz/cssxsh/pixiv/tool/TwoCaptchaHandler.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/TwoCaptchaHandler.kt index a93a5c3..2a5d4ea 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/TwoCaptchaHandler.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/TwoCaptchaHandler.kt @@ -2,7 +2,7 @@ package xyz.cssxsh.pixiv.tool import io.ktor.client.* import io.ktor.client.call.* -import io.ktor.client.engine.okhttp.* +import io.ktor.client.engine.cio.* import io.ktor.client.plugins.compression.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.request.* @@ -15,7 +15,7 @@ import xyz.cssxsh.pixiv.* * [2captcha-api](https://2captcha.com/2captcha-api#solving_recaptchav2_new) */ public class TwoCaptchaHandler(private val clientKey: String) : CaptchaHandler { - private val client = HttpClient(OkHttp) { + private val client = HttpClient(CIO) { install(ContentNegotiation) { json(PixivJson) } diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/YesCaptchaHandler.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/YesCaptchaHandler.kt similarity index 97% rename from src/main/kotlin/xyz/cssxsh/pixiv/tool/YesCaptchaHandler.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/YesCaptchaHandler.kt index 3fd98cc..9565625 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/YesCaptchaHandler.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/tool/YesCaptchaHandler.kt @@ -2,7 +2,7 @@ package xyz.cssxsh.pixiv.tool import io.ktor.client.* import io.ktor.client.call.* -import io.ktor.client.engine.okhttp.* +import io.ktor.client.engine.cio.* import io.ktor.client.network.sockets.* import io.ktor.client.plugins.* import io.ktor.client.plugins.contentnegotiation.* @@ -20,7 +20,7 @@ import xyz.cssxsh.pixiv.* */ public class YesCaptchaHandler(private val clientKey: String, public val host: String = "api.yescaptcha.com") : CaptchaHandler { - private val client = HttpClient(OkHttp) { + private val client = HttpClient(CIO) { install(ContentNegotiation) { json(PixivJson) } diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/ActivityApi.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/ActivityApi.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/ActivityApi.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/ActivityApi.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/BookmarkCount.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/BookmarkCount.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/BookmarkCount.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/BookmarkCount.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt similarity index 82% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt index 9e210bd..f0a57af 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/IllustApi.kt @@ -2,8 +2,8 @@ package xyz.cssxsh.pixiv.web import io.ktor.client.request.* import io.ktor.http.* -import xyz.cssxsh.pixiv.* -import java.util.* +import xyz.cssxsh.pixiv.FollowType +import xyz.cssxsh.pixiv.PixivWebClient private fun referer(pid: Long) = "https://www.pixiv.net/artwork/${pid}" @@ -15,7 +15,7 @@ public suspend fun PixivWebClient.ajaxIllust( limit: Int, rest: FollowType = FollowType.SHOW, tag: String = "", - locale: Locale = Locale.CHINA, + locale: String = "zh", ): UserFollowing = ajax(illust(pid = pid)) { header(HttpHeaders.Referrer, referer(pid = pid)) @@ -23,5 +23,5 @@ public suspend fun PixivWebClient.ajaxIllust( parameter("limit", limit) parameter("rest", rest) parameter("tag", tag) - parameter("lang", locale.language) + parameter("lang", locale) } \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/MangaSeries.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/MangaSeries.kt similarity index 85% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/MangaSeries.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/MangaSeries.kt index 87e96c1..aa6ee7d 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/web/MangaSeries.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/MangaSeries.kt @@ -1,7 +1,8 @@ package xyz.cssxsh.pixiv.web -import kotlinx.serialization.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + @Serializable public data class MangaSeries( @@ -12,8 +13,7 @@ public data class MangaSeries( @SerialName("coverImageSl") val coverImageSl: Int, @SerialName("createDate") - @Contextual - val createAt: OffsetDateTime, + val createAt: String, @SerialName("description") val description: String, @SerialName("firstIllustId") @@ -31,8 +31,8 @@ public data class MangaSeries( @SerialName("total") val total: Int, @SerialName("updateDate") - @Contextual - val updateAt: OffsetDateTime, + + val updateAt: String, @SerialName("url") val url: String, @SerialName("userId") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/NovelSeries.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/NovelSeries.kt similarity index 92% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/NovelSeries.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/NovelSeries.kt index d53fe79..96c067b 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/web/NovelSeries.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/NovelSeries.kt @@ -1,8 +1,9 @@ package xyz.cssxsh.pixiv.web -import kotlinx.serialization.* -import xyz.cssxsh.pixiv.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import xyz.cssxsh.pixiv.AgeLimit + @Serializable public data class NovelSeries( @@ -47,8 +48,8 @@ public data class NovelSeries( @SerialName("total") val total: Int, @SerialName("updateDate") - @Contextual - val updateAt: OffsetDateTime, + + val updateAt: String, @SerialName("updatedTimestamp") val updatedTimestamp: Long, @SerialName("userId") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserApi.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserApi.kt similarity index 83% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserApi.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserApi.kt index d2c8fd2..40b158c 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserApi.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserApi.kt @@ -2,8 +2,9 @@ package xyz.cssxsh.pixiv.web import io.ktor.client.request.* import io.ktor.http.* -import xyz.cssxsh.pixiv.* -import java.util.* +import xyz.cssxsh.pixiv.CategoryType +import xyz.cssxsh.pixiv.FollowType +import xyz.cssxsh.pixiv.PixivWebClient private fun referer(uid: Long) = "https://www.pixiv.net/users/${uid}" @@ -11,27 +12,27 @@ private fun profile(uid: Long, type: String) = "https://www.pixiv.net/ajax/user/ public suspend fun PixivWebClient.ajaxProfileAll( uid: Long, - locale: Locale = Locale.CHINA, + locale: String = "zh", ): UserProfileAll = ajax(profile(uid = uid, type = "all")) { header(HttpHeaders.Referrer, referer(uid = uid)) - parameter("lang", locale.language) + parameter("lang", locale) } public suspend fun PixivWebClient.ajaxProfileTop( uid: Long, - locale: Locale = Locale.CHINA, + locale: String = "zh", ): UserProfileTop = ajax(profile(uid = uid, type = "top")) { header(HttpHeaders.Referrer, referer(uid = uid)) - parameter("lang", locale.language) + parameter("lang", locale) } public suspend fun PixivWebClient.ajaxProfileIllusts( uid: Long, ids: Set, category: CategoryType, - locale: Locale = Locale.CHINA, + locale: String = "zh", ): UserProfileIllusts = ajax(profile(uid = uid, type = "illusts")) { header(HttpHeaders.Referrer, referer(uid = uid)) @@ -40,7 +41,7 @@ public suspend fun PixivWebClient.ajaxProfileIllusts( } parameter("work_category", category) parameter("is_first_page", 1) - parameter("lang", locale.language) + parameter("lang", locale) } private fun following(uid: Long) = "https://www.pixiv.net/ajax/user/${uid}/following" @@ -51,7 +52,7 @@ public suspend fun PixivWebClient.ajaxFollowing( limit: Int, rest: FollowType = FollowType.SHOW, tag: String = "", - locale: Locale = Locale.CHINA, + locale: String = "zh", ): UserFollowing = ajax(following(uid = uid)) { header(HttpHeaders.Referrer, referer(uid = uid)) @@ -59,7 +60,7 @@ public suspend fun PixivWebClient.ajaxFollowing( parameter("limit", limit) parameter("rest", rest) parameter("tag", tag) - parameter("lang", locale.language) + parameter("lang", locale) } private fun bookmarks(uid: Long, type: String) = "https://www.pixiv.net/ajax/user/${uid}/${type}/bookmarks" @@ -70,7 +71,7 @@ public suspend fun PixivWebClient.ajaxBookmarks( limit: Int, rest: FollowType = FollowType.SHOW, tag: String = "", - locale: Locale = Locale.CHINA, + locale: String = "zh", ): UserBookmarks = ajax(bookmarks(uid = uid, type = "illust")) { header(HttpHeaders.Referrer, referer(uid = uid)) @@ -78,7 +79,7 @@ public suspend fun PixivWebClient.ajaxBookmarks( parameter("limit", limit) parameter("rest", rest) parameter("tag", tag) - parameter("lang", locale.language) + parameter("lang", locale) } // https://www.pixiv.net/ajax/user/478993/illusts/bookmark/tags?lang=zh \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserBookmarks.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserBookmarks.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserBookmarks.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserBookmarks.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserFollowing.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserFollowing.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserFollowing.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserFollowing.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserPickupInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserPickupInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserPickupInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserPickupInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserProfileAll.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserProfileAll.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserProfileAll.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserProfileAll.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserProfileIllusts.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserProfileIllusts.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserProfileIllusts.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserProfileIllusts.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserProfileTop.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserProfileTop.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserProfileTop.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserProfileTop.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserRequestInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserRequestInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserRequestInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserRequestInfo.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/UserWebPreview.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserWebPreview.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/UserWebPreview.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/UserWebPreview.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt similarity index 81% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt index d6e56fe..d00a25b 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebIllust.kt @@ -1,9 +1,13 @@ package xyz.cssxsh.pixiv.web -import kotlinx.serialization.* -import kotlinx.serialization.json.* -import xyz.cssxsh.pixiv.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement +import xyz.cssxsh.pixiv.AgeLimit +import xyz.cssxsh.pixiv.PublicityType +import xyz.cssxsh.pixiv.SanityLevel +import xyz.cssxsh.pixiv.WorkContentType + @Serializable public data class WebIllust( @@ -12,8 +16,8 @@ public data class WebIllust( @SerialName("bookmarkData") val bookmarkData: JsonElement,// TODO @SerialName("createDate") - @Contextual - val createAt: OffsetDateTime, + + val createAt: String, @SerialName("description") val description: String, @SerialName("width") @@ -47,8 +51,8 @@ public data class WebIllust( @SerialName("titleCaptionTranslation") val caption: WebTitleCaption, @SerialName("updateDate") - @Contextual - val updateAt: OffsetDateTime, + + val updateAt: String, @SerialName("url") val url: String, @SerialName("userId") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt similarity index 83% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt index 88f9dd4..12b772e 100644 --- a/src/main/kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt +++ b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebNovel.kt @@ -1,9 +1,11 @@ package xyz.cssxsh.pixiv.web -import kotlinx.serialization.* -import kotlinx.serialization.json.* -import xyz.cssxsh.pixiv.* -import java.time.* +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.JsonElement +import xyz.cssxsh.pixiv.AgeLimit +import xyz.cssxsh.pixiv.PublicityType + @Serializable public data class WebNovel( @@ -12,8 +14,8 @@ public data class WebNovel( @SerialName("bookmarkData") val bookmarkData: JsonElement,// TODO @SerialName("createDate") - @Contextual - val createAt: OffsetDateTime, + + val createAt: String, @SerialName("description") val description: String, @SerialName("id") @@ -42,8 +44,8 @@ public data class WebNovel( @SerialName("titleCaptionTranslation") val caption: WebTitleCaption, @SerialName("updateDate") - @Contextual - val updateAt: OffsetDateTime, + + val updateAt: String, @SerialName("url") val url: String, @SerialName("userId") diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/WebTitleCaption.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebTitleCaption.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/WebTitleCaption.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebTitleCaption.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/WebUtils.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebUtils.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/WebUtils.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebUtils.kt diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/web/WebWorkInfo.kt b/src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebWorkInfo.kt similarity index 100% rename from src/main/kotlin/xyz/cssxsh/pixiv/web/WebWorkInfo.kt rename to src/commonMain/kotlin/xyz/cssxsh/pixiv/web/WebWorkInfo.kt diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/EditThisCookie.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/EditThisCookie.kt similarity index 100% rename from src/test/kotlin/xyz/cssxsh/pixiv/EditThisCookie.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/EditThisCookie.kt diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/OtherAuthKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/OtherAuthKtTest.kt similarity index 85% rename from src/test/kotlin/xyz/cssxsh/pixiv/OtherAuthKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/OtherAuthKtTest.kt index d470e07..0b0afbb 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/OtherAuthKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/OtherAuthKtTest.kt @@ -2,16 +2,17 @@ package xyz.cssxsh.pixiv import io.ktor.http.* import io.ktor.util.date.* -import kotlinx.coroutines.* -import kotlinx.serialization.* -import org.junit.jupiter.api.* +import kotlinx.coroutines.runBlocking +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import okio.FileSystem +import okio.Path.Companion.toPath +import kotlin.test.Test internal class OtherAuthKtTest { private val client = SimplePixivClient(config = PixivConfig()) - private val work = java.io.File("./run") - @Serializable data class EditThisCookie( @SerialName("domain") @@ -64,7 +65,7 @@ internal class OtherAuthKtTest { fun cookie(): Unit = runBlocking { val result = client.cookie { PixivJson.decodeFromString>( - work.resolve("cookie.json").readText() + FileSystem.SYSTEM.read(".run/cookie.json".toPath()) { readUtf8() } ).map { it.toCookie() } } println(result) diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/PixivEnumSerializerTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/PixivEnumSerializerTest.kt similarity index 82% rename from src/test/kotlin/xyz/cssxsh/pixiv/PixivEnumSerializerTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/PixivEnumSerializerTest.kt index 34334b2..bac47f9 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/PixivEnumSerializerTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/PixivEnumSerializerTest.kt @@ -1,8 +1,9 @@ package xyz.cssxsh.pixiv -import kotlinx.serialization.* -import kotlinx.serialization.json.* -import org.junit.jupiter.api.* +import kotlinx.serialization.InternalSerializationApi +import kotlinx.serialization.Serializable +import kotlinx.serialization.json.Json +import kotlin.test.Test @InternalSerializationApi internal class PixivEnumSerializerTest { diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/WebTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/WebTest.kt similarity index 65% rename from src/test/kotlin/xyz/cssxsh/pixiv/WebTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/WebTest.kt index 1410e08..e1b0282 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/WebTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/WebTest.kt @@ -1,17 +1,15 @@ package xyz.cssxsh.pixiv import io.ktor.client.* -import io.ktor.client.engine.okhttp.* +import io.ktor.client.engine.cio.* import io.ktor.client.plugins.* import io.ktor.client.plugins.compression.* import io.ktor.client.plugins.contentnegotiation.* import io.ktor.client.plugins.cookies.* -import io.ktor.http.* import io.ktor.serialization.kotlinx.json.* -import org.junit.jupiter.api.Test -import xyz.cssxsh.pixiv.exception.* -import xyz.cssxsh.pixiv.tool.* -import javax.net.ssl.SSLSocket +import io.ktor.utils.io.core.* +import xyz.cssxsh.pixiv.exception.TransferExceptionHandler +import kotlin.use abstract class WebTest { @@ -23,7 +21,7 @@ abstract class WebTest { override val storage get() = this@WebTest.storage - private fun client(): HttpClient = HttpClient(OkHttp) { + private fun client(): HttpClient = HttpClient(CIO) { install(ContentNegotiation) { json(json = PixivJson) } @@ -40,12 +38,7 @@ abstract class WebTest { handleResponseExceptionWithRequest(block = TransferExceptionHandler) } - engine { - config { - sslSocketFactory(RubySSLSocketFactory, RubyX509TrustManager) - hostnameVerifier { _, _ -> true } - } - } + // TODO set up SSL } override suspend fun useHttpClient(block: suspend (HttpClient) -> R): R = client().use { block(it) } @@ -56,11 +49,12 @@ abstract class WebTest { } } - @Test - fun sos() { - (RubySSLSocketFactory.createSocket("d1ctzrip8l97jt.cloudfront.net", URLProtocol.HTTPS.defaultPort) as SSLSocket).use { - it.startHandshake() - println(it.session.cipherSuite) - } - } + // TODO fix below test +// @Test +// fun sos() { +// (RubySSLSocketFactory.createSocket("d1ctzrip8l97jt.cloudfront.net", URLProtocol.HTTPS.defaultPort) as SSLSocket).use { +// it.startHandshake() +// println(it.session.cipherSuite) +// } +// } } \ No newline at end of file diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/apps/AppApiKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/AppApiKtTest.kt similarity index 51% rename from src/test/kotlin/xyz/cssxsh/pixiv/apps/AppApiKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/AppApiKtTest.kt index c0fe11d..f0e9354 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/apps/AppApiKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/AppApiKtTest.kt @@ -1,18 +1,14 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -import xyz.cssxsh.pixiv.* +import xyz.cssxsh.pixiv.PixivAuthClient +import xyz.cssxsh.pixiv.PixivConfig +import xyz.cssxsh.pixiv.SimplePixivClient +import xyz.cssxsh.pixiv.pixiv_client.BuildConfig -@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal abstract class AppApiKtTest { - init { - System.setProperty("xyz.cssxsh.pixiv.json.ignore", "false") - } - protected val client: PixivAuthClient = object : SimplePixivClient( - config = PixivConfig(refreshToken = System.getenv("PIXIV_TOKEN")) + config = PixivConfig(refreshToken = BuildConfig.REFRESH_TOKEN) ) { override val ignore: suspend (Throwable) -> Boolean = { cause -> cause.printStackTrace() diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/apps/IllustKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/IllustKtTest.kt similarity index 88% rename from src/test/kotlin/xyz/cssxsh/pixiv/apps/IllustKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/IllustKtTest.kt index 2cff079..cbeebf9 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/apps/IllustKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/IllustKtTest.kt @@ -1,12 +1,13 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -import org.junit.jupiter.api.Assertions.* -import xyz.cssxsh.pixiv.* -import java.time.* +import kotlinx.coroutines.runBlocking +import kotlinx.datetime.LocalDate +import xyz.cssxsh.pixiv.RankMode +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertTrue -@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class IllustKtTest : AppApiKtTest() { @Test @@ -72,7 +73,7 @@ internal class IllustKtTest : AppApiKtTest() { client.illustRanking().let { (illusts) -> assertFalse(illusts.isEmpty()) } - val date = LocalDate.of(2020, 8, 20) + val date = LocalDate(2020, 8, 20) client.illustRanking(mode = RankMode.WEEK, date = date, offset = PAGE_SIZE).let { (illusts) -> assertFalse(illusts.isEmpty()) } @@ -95,4 +96,10 @@ internal class IllustKtTest : AppApiKtTest() { assertEquals(PAGE_SIZE, illusts.size.toLong()) } } + + @Test + fun timeanddate() = runBlocking { + println("Hello world") + } + } \ No newline at end of file diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/apps/SearchKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/SearchKtTest.kt similarity index 84% rename from src/test/kotlin/xyz/cssxsh/pixiv/apps/SearchKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/SearchKtTest.kt index b11bc3e..12c62c4 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/apps/SearchKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/SearchKtTest.kt @@ -1,10 +1,10 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -import org.junit.jupiter.api.Assertions.* +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertFalse + -@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class SearchKtTest : AppApiKtTest() { @Test diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt similarity index 68% rename from src/test/kotlin/xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt index 38d3b70..369c9f8 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/SpotlightKtTest.kt @@ -1,10 +1,10 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -import org.junit.jupiter.api.Assertions.* +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse -@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class SpotlightKtTest: AppApiKtTest() { @Test diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/apps/TrendingKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/TrendingKtTest.kt similarity index 71% rename from src/test/kotlin/xyz/cssxsh/pixiv/apps/TrendingKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/TrendingKtTest.kt index f6b3406..6a58e81 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/apps/TrendingKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/TrendingKtTest.kt @@ -1,10 +1,10 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -import org.junit.jupiter.api.Assertions.* +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertFalse +import kotlin.test.assertTrue -@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class TrendingKtTest : AppApiKtTest() { @Test diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/apps/UserKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/UserKtTest.kt similarity index 90% rename from src/test/kotlin/xyz/cssxsh/pixiv/apps/UserKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/UserKtTest.kt index c5393b1..56e8d73 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/apps/UserKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/apps/UserKtTest.kt @@ -1,10 +1,11 @@ package xyz.cssxsh.pixiv.apps -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -import org.junit.jupiter.api.Assertions.* +import kotlinx.coroutines.runBlocking +import kotlin.test.Test +import kotlin.test.assertEquals +import kotlin.test.assertFalse +import kotlin.test.assertNotEquals -@TestInstance(TestInstance.Lifecycle.PER_CLASS) internal class UserKtTest : AppApiKtTest() { @Test @@ -14,7 +15,6 @@ internal class UserKtTest : AppApiKtTest() { } } - @Disabled fun blacklist(): Unit = runBlocking { client.userBlacklist(uid = 3410615L).let { (users) -> assertFalse(users.isEmpty()) @@ -43,7 +43,6 @@ internal class UserKtTest : AppApiKtTest() { } } - @Disabled fun following(): Unit = runBlocking { val uid = 11L client.userFollowDelete(uid = uid) @@ -57,8 +56,6 @@ internal class UserKtTest : AppApiKtTest() { } } - - @Disabled fun follower(): Unit = runBlocking { val uid = 4102577L client.userFollower(uid = uid).let { (previews) -> @@ -66,8 +63,6 @@ internal class UserKtTest : AppApiKtTest() { } } - - @Disabled fun friend(): Unit = runBlocking { val uid = 4102577L client.userMyPixiv(uid = uid).let { (previews) -> diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloaderTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloaderTest.kt similarity index 76% rename from src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloaderTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloaderTest.kt index 878c5e2..de9831f 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloaderTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/tool/PixivDownloaderTest.kt @@ -2,14 +2,12 @@ package xyz.cssxsh.pixiv.tool import io.ktor.http.* import kotlinx.coroutines.* -import kotlinx.coroutines.channels.* -import org.junit.jupiter.api.* -import xyz.cssxsh.pixiv.* -import java.io.* -import kotlin.system.* +import kotlinx.coroutines.channels.Channel +import xyz.cssxsh.pixiv.HTTP_KILO +import kotlin.test.Test +import kotlin.time.Duration.Companion.milliseconds -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -internal class PixivDownloaderTest : SummaryTest() { +internal class PixivDownloaderTest { private val artworks = listOf( // https://www.pixiv.net/artworks/104820728 @@ -62,18 +60,19 @@ internal class PixivDownloaderTest : SummaryTest() { supervisorScope { async { val bytes: ByteArray - val millis = measureTimeMillis { - bytes = deferred.await() - } - val (pid, index) = regex.find(url.encodedPath)!!.destructured - val page = """${pid}#${index.toInt().plus(1)}""" - println("| [$page](https://www.pixiv.net/artworks/${page}) | ${bytes.length} | ${java.time.Duration.ofMillis(millis)} |") + // TODO fix measureTimeMillis not found +// val millis = measureTimeMillis { +// bytes = deferred.await() +// } +// val (pid, index) = regex.find(url.encodedPath)!!.destructured +// val page = """${pid}#${index.toInt().plus(1)}""" +// println("| [$page](https://www.pixiv.net/artworks/${page}) | ${bytes.length} | ${millis.milliseconds} |") } } } } - @Test +// @Test fun async(): Unit = runBlocking { println("# Async Test") val durations = jobs.associateWith { async -> @@ -82,11 +81,12 @@ internal class PixivDownloaderTest : SummaryTest() { println("## Async Number $async") println("| IMAGE | SIZE | DURATION |") println("|:-----:|:----:|:--------:|") - val millis = measureTimeMillis { - artworks.flatMap { artwork -> download(target = artwork) } - .awaitAll() - } - java.time.Duration.ofMillis(millis) + // TODO fix test +// val millis = measureTimeMillis { +// artworks.flatMap { artwork -> download(target = artwork) } +// .awaitAll() +// } +// millis.milliseconds } println("## Async Duration") println("| ASYNC | DURATION |") diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/web/UserApiKtTest.kt b/src/commonTest/kotlin/xyz/cssxsh/pixiv/web/UserApiKtTest.kt similarity index 86% rename from src/test/kotlin/xyz/cssxsh/pixiv/web/UserApiKtTest.kt rename to src/commonTest/kotlin/xyz/cssxsh/pixiv/web/UserApiKtTest.kt index 30474c6..35c4934 100644 --- a/src/test/kotlin/xyz/cssxsh/pixiv/web/UserApiKtTest.kt +++ b/src/commonTest/kotlin/xyz/cssxsh/pixiv/web/UserApiKtTest.kt @@ -1,8 +1,8 @@ package xyz.cssxsh.pixiv.web -import kotlinx.coroutines.* -import org.junit.jupiter.api.* -import xyz.cssxsh.pixiv.* +import kotlinx.coroutines.runBlocking +import xyz.cssxsh.pixiv.WebTest +import kotlin.test.Test internal class UserApiKtTest : WebTest() { diff --git a/src/jvmMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.jvm.kt b/src/jvmMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.jvm.kt new file mode 100644 index 0000000..affc2b9 --- /dev/null +++ b/src/jvmMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.jvm.kt @@ -0,0 +1,6 @@ +package xyz.cssxsh.pixiv + +import io.ktor.client.engine.* +import io.ktor.client.engine.okhttp.* + +internal actual val httpClient: HttpClientEngineFactory<*> = OkHttp \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/JapanDateTimeSerializer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/JapanDateTimeSerializer.kt deleted file mode 100644 index 54cd0b9..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/JapanDateTimeSerializer.kt +++ /dev/null @@ -1,8 +0,0 @@ -package xyz.cssxsh.pixiv - -import java.time.format.* -import java.util.* - -public object JapanDateTimeSerializer : OffsetDateTimeSerializer { - override val formatter: DateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.JAPAN) -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/OffsetDateTimeSerializer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/OffsetDateTimeSerializer.kt deleted file mode 100644 index 21f9f15..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/OffsetDateTimeSerializer.kt +++ /dev/null @@ -1,21 +0,0 @@ -package xyz.cssxsh.pixiv - -import kotlinx.serialization.* -import kotlinx.serialization.descriptors.* -import kotlinx.serialization.encoding.* -import java.time.* -import java.time.format.* - -public interface OffsetDateTimeSerializer : KSerializer { - - public val formatter: DateTimeFormatter - - override val descriptor: SerialDescriptor - get() = PrimitiveSerialDescriptor(OffsetDateTime::class.qualifiedName!!, PrimitiveKind.STRING) - - override fun serialize(encoder: Encoder, value: OffsetDateTime): Unit = - encoder.encodeString(value.format(formatter)) - - override fun deserialize(decoder: Decoder): OffsetDateTime = - OffsetDateTime.parse(decoder.decodeString(), formatter) -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/gifencoder/OctTreeQuantizer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/gifencoder/OctTreeQuantizer.kt deleted file mode 100644 index ee8ee3e..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/gifencoder/OctTreeQuantizer.kt +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2015 Square, Inc. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package xyz.cssxsh.pixiv.gifencoder - -import com.squareup.gifencoder.Color -import com.squareup.gifencoder.ColorQuantizer -import com.squareup.gifencoder.Multiset - -/** - * Implements qct-tree quantization. - * - * - * The principle of algorithm: http://www.microsoft.com/msj/archive/S3F1.aspx - * - */ -public class OctTreeQuantizer private constructor() : ColorQuantizer { - private var leafCount = 0 - private var inIndex = 0 - private val nodeList = arrayOfNulls(8) - override fun quantize(originalColors: Multiset, maxColorCount: Int): Set { - val node = createNode(0) - val distinctElements = originalColors.distinctElements - for (color in distinctElements) { - addColor(node, color, 0) - while (leafCount > maxColorCount) { - reduceTree() - } - } - val colors = HashSet() - getColorPalette(node, colors) - leafCount = 0 - inIndex = 0 - for (i in 0..7) { - nodeList[i] = null - } - return colors - } - - private fun addColor(node: Node?, color: Color, inLevel: Int): Boolean { - var node = node - val nIndex: Int - val shift: Int - if (node == null) { - node = createNode(inLevel) - } - val red = (color.getComponent(0) * 255).toInt() - val green = (color.getComponent(1) * 255).toInt() - val blue = (color.getComponent(2) * 255).toInt() - if (node.isLeaf) { - node.pixelCount++ - node.redSum += red - node.greenSum += green - node.blueSum += blue - } else { - shift = 7 - inLevel - nIndex = (red and mask[inLevel].code shr shift shl 2 - or (green and mask[inLevel].code shr shift shl 1) - or (blue and mask[inLevel].code shr shift)) - var tmpNode = node.child[nIndex] - if (tmpNode == null) { - tmpNode = createNode(inLevel + 1) - } - node.child[nIndex] = tmpNode - return addColor(node.child[nIndex], color, inLevel + 1) - } - return true - } - - private fun createNode(level: Int): Node { - val node = Node() - node.level = level - node.isLeaf = level == 8 - if (node.isLeaf) { - leafCount++ - } else { - node.next = nodeList[level] - nodeList[level] = node - } - return node - } - - private fun reduceTree() { - var redSum = 0 - var greenSum = 0 - var blueSum = 0 - var count = 0 - var i = 7 - while (i > 0) { - if (nodeList[i] != null) break - i-- - } - val tmpNode = nodeList[i] - nodeList[i] = tmpNode!!.next - i = 0 - while (i < 8) { - if (tmpNode.child[i] != null) { - redSum += tmpNode.child[i]!!.redSum - greenSum += tmpNode.child[i]!!.greenSum - blueSum += tmpNode.child[i]!!.blueSum - count += tmpNode.child[i]!!.pixelCount - tmpNode.child[i] = null - leafCount-- - } - i++ - } - tmpNode.isLeaf = true - tmpNode.redSum = redSum - tmpNode.greenSum = greenSum - tmpNode.blueSum = blueSum - tmpNode.pixelCount = count - leafCount++ - } - - private fun getColorPalette(node: Node?, colors: MutableSet) { - if (node!!.isLeaf) { - node.colorIndex = inIndex - node.redSum /= node.pixelCount - node.greenSum /= node.pixelCount - node.blueSum /= node.pixelCount - node.pixelCount = 1 - inIndex++ - val red = node.redSum.toDouble() / 255 - val green = node.greenSum.toDouble() / 255 - val blue = node.blueSum.toDouble() / 255 - colors.add(Color(red, green, blue)) - } else { - for (i in 0..7) { - if (node.child[i] != null) { - getColorPalette(node.child[i], colors) - } - } - } - } - - private class Node { - var isLeaf = false - var level = 0 - var colorIndex = 0 - var redSum = 0 - var greenSum = 0 - var blueSum = 0 - var pixelCount = 0 - var child = arrayOfNulls(8) - var next: Node? = null - } - - public companion object { - public val INSTANCE: OctTreeQuantizer = OctTreeQuantizer() - private val mask = charArrayOf( - 0x80.toChar(), - 0x40.toChar(), - 0x20.toChar(), - 0x10.toChar(), - 0x08.toChar(), - 0x04.toChar(), - 0x02.toChar(), - 0x01.toChar() - ) - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/AtkinsonDitherer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/AtkinsonDitherer.kt deleted file mode 100644 index 3692494..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/AtkinsonDitherer.kt +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -public class AtkinsonDitherer private constructor() : UniversalDitherer(DISTRIBUTION) { - public companion object { - @JvmStatic - public val DISTRIBUTION: List = listOf( - ErrorComponent(1, 0, 1 / 8.0), - ErrorComponent(2, 0, 1 / 8.0), - - ErrorComponent(-1, 1, 1 / 8.0), - ErrorComponent(0, 1, 1 / 8.0), - ErrorComponent(1, 1, 1 / 8.0), - - ErrorComponent(0, 2, 1 / 8.0), - ) - - @JvmStatic - public val INSTANCE: AtkinsonDitherer = AtkinsonDitherer() - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/JJNDitherer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/JJNDitherer.kt deleted file mode 100644 index 67eb613..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/JJNDitherer.kt +++ /dev/null @@ -1,26 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -public class JJNDitherer private constructor() : UniversalDitherer(DISTRIBUTION) { - public companion object { - @JvmStatic - public val DISTRIBUTION: List = listOf( - ErrorComponent(1, 0, 7 / 48.0), - ErrorComponent(2, 0, 5 / 48.0), - - ErrorComponent(-2, 1, 3 / 48.0), - ErrorComponent(-1, 1, 5 / 48.0), - ErrorComponent(0, 1, 7 / 48.0), - ErrorComponent(1, 1, 5 / 48.0), - ErrorComponent(2, 1, 3 / 48.0), - - ErrorComponent(-2, 2, 1 / 48.0), - ErrorComponent(-1, 2, 3 / 48.0), - ErrorComponent(0, 2, 5 / 48.0), - ErrorComponent(1, 2, 3 / 48.0), - ErrorComponent(2, 2, 1 / 48.0), - ) - - @JvmStatic - public val INSTANCE: JJNDitherer = JJNDitherer() - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/OpenCVQuantizer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/OpenCVQuantizer.kt deleted file mode 100644 index 0443bd7..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/OpenCVQuantizer.kt +++ /dev/null @@ -1,77 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import com.squareup.gifencoder.Color -import com.squareup.gifencoder.ColorQuantizer -import com.squareup.gifencoder.Multiset -import nu.pattern.OpenCV -import org.opencv.core.Core -import org.opencv.core.CvType -import org.opencv.core.Mat -import org.opencv.core.TermCriteria - -public class OpenCVQuantizer private constructor() : ColorQuantizer { - public companion object { - init { - OpenCV.loadLocally() - } - - @JvmStatic - public val INSTANCE: OpenCVQuantizer = OpenCVQuantizer() - - internal const val MAX_COUNT = "xyz.cssxsh.pixiv.tool.quantizer.max_count" - } - - private var last: Mat? = null - - public fun reset() { - last = null - } - - private val maxCount by lazy { - System.getProperty(MAX_COUNT, "32").toInt() - } - - override fun quantize(originalColors: Multiset, maxColorCount: Int): MutableSet { - val original = Mat(originalColors.size, 1, CvType.CV_64FC3).apply { - // val buffer = createBuffer() - for ((row, color) in originalColors.withIndex()) { - put( - row, 0, - color.getComponent(0), - color.getComponent(1), - color.getComponent(2) - ) - } - } - val src = Mat().apply { original.convertTo(this, CvType.CV_32F) } - - val flags = - if (last == null) Core.KMEANS_PP_CENTERS else Core.KMEANS_USE_INITIAL_LABELS + Core.KMEANS_PP_CENTERS - val labels = last ?: Mat() - val criteria = TermCriteria(TermCriteria.EPS + TermCriteria.MAX_ITER, maxCount, 1.0 / 64.0) - val centers = Mat() - - Core.kmeans( - src, - maxColorCount, - labels, - criteria, - 1, - flags, - centers - ) - - last = labels - - val colors = mutableSetOf() - val temp = Mat().apply { centers.convertTo(this, CvType.CV_64F) } - for (x in 0 until centers.rows()) { - val r = temp[x, 0][0] - val g = temp[x, 1][0] - val b = temp[x, 2][0] - colors.add(Color(r, g, b)) - } - - return colors - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivGifEncoder.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivGifEncoder.kt deleted file mode 100644 index c2ea291..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivGifEncoder.kt +++ /dev/null @@ -1,62 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import com.squareup.gifencoder.* -import xyz.cssxsh.pixiv.apps.* -import java.awt.image.* -import java.io.* -import java.util.concurrent.* - -public open class PixivGifEncoder(override val downloader: PixivDownloader = PixivDownloader()) : PixivUgoiraEncoder() { - protected open val quantizer: ColorQuantizer = MedianCutQuantizer.INSTANCE - - protected open val ditherer: Ditherer = FloydSteinbergDitherer.INSTANCE - - protected open val disposalMethod: DisposalMethod = DisposalMethod.UNSPECIFIED - - protected open val bufferSize: Int = 1 shl 22 - - protected fun BufferedImage.readRGBs(): Array = Array(height) { y -> IntArray(width) { x -> getRGB(x, y) } } - - protected fun UgoiraFrame.toImageOptions(): ImageOptions = ImageOptions().apply { - setColorQuantizer(quantizer) - setDitherer(ditherer) - setDisposalMethod(disposalMethod) - setDelay(delay, TimeUnit.MILLISECONDS) - } - - @Suppress("UNCHECKED_CAST") - protected fun instance(name: String): T { - val clazz = Class.forName(name, true, PixivGifEncoder::class.java.classLoader) - return try { - clazz.getField("INSTANCE").get(null) - } catch (_: Throwable) { - clazz.getConstructor().newInstance() - } as T - } - - @Suppress("BlockingMethodInNonBlockingContext") - override suspend fun encode(illust: IllustInfo, metadata: UgoiraMetadata, loop: Int): File { - val temp = cache.resolve("${illust.pid}.temp") - val output = temp.outputStream().buffered(bufferSize) - var width = illust.width - var height = illust.height - val encoder by lazy { GifEncoder(output, width, height, loop) } - - metadata.frame { frame, image -> - width = image.width - height = image.height - encoder.addImage(image.readRGBs(), frame.toImageOptions()) - } - (quantizer as? OpenCVQuantizer)?.reset() - - encoder.finishEncoding() - output.close() - - return cache.resolve("${illust.pid}.gif").apply { - if (exists()) { - renameTo(cache.resolve("${illust.pid}.${lastModified()}.gif")) - } - temp.renameTo(this) - } - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoder.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoder.kt deleted file mode 100644 index 82aea50..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoder.kt +++ /dev/null @@ -1,48 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import io.ktor.http.* -import kotlinx.coroutines.* -import xyz.cssxsh.pixiv.apps.* -import java.awt.image.* -import java.io.* -import java.util.zip.* -import javax.imageio.* - -public abstract class PixivUgoiraEncoder { - protected open val cache: File = File(".") - - protected open val downloader: PixivDownloader = PixivDownloader() - - // origin not found in app api - protected val UgoiraMetadata.original: Url get() = Url(zipUrls.values.first().replace("600x600", "1920x1080")) - - protected open suspend fun download(url: Url, filename: String): File = cache.resolve(filename).apply { - if (exists().not()) { - writeBytes(downloader.download(url)) - } - } - - protected open suspend fun UgoiraMetadata.download(): File { - return download(original, original.encodedPath.substringAfterLast('/')) - } - - protected infix fun UgoiraFrame.with(zip: ZipFile): BufferedImage = with(zip) { - getInputStream(getEntry(file)).use { ImageIO.read(it) } - } - - protected suspend fun UgoiraMetadata.frame(block: (UgoiraFrame, BufferedImage) -> T): List { - val file = download() - return withContext(Dispatchers.IO) { - ZipFile(file).use { zip -> - frames.map { frame -> - block(frame, frame with zip) - } - } - } - } - - /** - * write to [PixivUgoiraEncoder.cache] with pid of [illust] as filename - */ - public abstract suspend fun encode(illust: IllustInfo, metadata: UgoiraMetadata, loop: Int = 0): File -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyDns.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyDns.kt deleted file mode 100644 index 538e0ad..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyDns.kt +++ /dev/null @@ -1,61 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import okhttp3.* -import okhttp3.HttpUrl.Companion.toHttpUrl -import okhttp3.dnsoverhttps.* -import okhttp3.internal.* -import java.net.* - -public class RubyDns(doh: String, private val hosts: Map>) : Dns { - private val dns: Dns = (if (doh.isNotBlank()) DnsOverHttps(doh) else Dns.SYSTEM) - - private fun DnsOverHttps(url: String): DnsOverHttps { - return DnsOverHttps.Builder() - .client(OkHttpClient()) - .url(url.toHttpUrl()) - .post(true) - .resolvePrivateAddresses(false) - .resolvePublicAddresses(true) - .build() - } - - private val lookup: (String) -> List = { - if (it.canParseAsIpAddress()) InetAddress.getAllByName(it).asList() else dns.lookup(it) - } - - override fun lookup(hostname: String): List { - - val result = mutableListOf() - val other = hosts[hostname] ?: hosts.firstNotNullOfOrNull { (host, cname) -> - cname.takeIf { hostname.endsWith(host.removePrefix("*.")) } - } - - for (item in other.orEmpty()) try { - result.addAll(item.let(lookup)) - } catch (_: Throwable) { - // - } - - result.shuffle() - - if (result.isEmpty()) try { - result.addAll(hostname.let(lookup)) - } catch (_: Throwable) { - // - } - - if (result.isEmpty()) try { - result.addAll(InetAddress.getAllByName(hostname)) - } catch (_: Throwable) { - // - } - - return result.apply { - if (isEmpty()) throw UnknownHostException("$hostname and CNAME${other} ") - } - } - - override fun toString(): String { - return "RubyDns(doh=${(dns as? DnsOverHttps)?.url}, hosts=${hosts})" - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubySSLSocketFactory.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubySSLSocketFactory.kt deleted file mode 100644 index 518a026..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubySSLSocketFactory.kt +++ /dev/null @@ -1,40 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import java.net.* -import javax.net.ssl.* - -public object RubySSLSocketFactory : SSLSocketFactory() { - - internal val regexes = mutableListOf("""(pixiv|pximg)\.net""".toRegex()) - - private fun Socket.setServerNames(): Socket = apply { - if (this !is SSLSocket) return@apply - sslParameters = sslParameters.apply { - serverNames = serverNames?.filter { name -> - if (name !is SNIHostName) return@filter false - regexes.none { it in name.asciiName } - } - } - } - - private val default: SSLSocketFactory = SSLContext.getDefault().socketFactory - - override fun createSocket(socket: Socket?, host: String?, port: Int, autoClose: Boolean): Socket? = - default.createSocket(socket, host, port, autoClose)?.setServerNames() - - override fun createSocket(host: String?, port: Int): Socket? = - default.createSocket(host, port)?.setServerNames() - - override fun createSocket(host: String?, port: Int, localHost: InetAddress?, localPort: Int): Socket? = - default.createSocket(host, port, localHost, localPort)?.setServerNames() - - override fun createSocket(host: InetAddress?, port: Int): Socket? = - default.createSocket(host, port)?.setServerNames() - - override fun createSocket(address: InetAddress?, port: Int, localAddress: InetAddress?, localPort: Int): Socket? = - default.createSocket(address, port, localAddress, localPort)?.setServerNames() - - override fun getDefaultCipherSuites(): Array = default.defaultCipherSuites - - override fun getSupportedCipherSuites(): Array = default.supportedCipherSuites -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyX509TrustManager.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyX509TrustManager.kt deleted file mode 100644 index 6fda48e..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/RubyX509TrustManager.kt +++ /dev/null @@ -1,20 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import java.security.* -import java.security.cert.* -import javax.net.ssl.* - -public object RubyX509TrustManager : X509TrustManager { - - private val delegate: X509TrustManager by lazy { - val factory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()) - factory.init(null as KeyStore?) - factory.trustManagers.filterIsInstance().first() - } - - override fun checkClientTrusted(chain: Array?, authType: String?) {} - - override fun checkServerTrusted(chain: Array?, authType: String?) {} - - override fun getAcceptedIssuers(): Array = delegate.acceptedIssuers -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/SierraLiteDitherer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/SierraLiteDitherer.kt deleted file mode 100644 index 29c25c0..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/SierraLiteDitherer.kt +++ /dev/null @@ -1,16 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -public class SierraLiteDitherer private constructor() : UniversalDitherer(DISTRIBUTION) { - public companion object { - @JvmStatic - public val DISTRIBUTION: List = listOf( - ErrorComponent(1, 0, 2 / 4.0), - - ErrorComponent(-1, 1, 1 / 4.0), - ErrorComponent(0, 1, 1 / 4.0), - ) - - @JvmStatic - public val INSTANCE: SierraLiteDitherer = SierraLiteDitherer() - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/StuckiDitherer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/StuckiDitherer.kt deleted file mode 100644 index 6cfb978..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/StuckiDitherer.kt +++ /dev/null @@ -1,26 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -public class StuckiDitherer private constructor() : UniversalDitherer(DISTRIBUTION) { - public companion object { - @JvmStatic - public val DISTRIBUTION: List = listOf( - ErrorComponent(1, 0, 8 / 48.0), - ErrorComponent(2, 0, 4 / 48.0), - - ErrorComponent(-2, 1, 2 / 48.0), - ErrorComponent(-1, 1, 4 / 48.0), - ErrorComponent(0, 1, 8 / 48.0), - ErrorComponent(1, 1, 4 / 48.0), - ErrorComponent(2, 1, 2 / 48.0), - - ErrorComponent(-2, 2, 1 / 48.0), - ErrorComponent(-1, 2, 2 / 48.0), - ErrorComponent(0, 2, 4 / 48.0), - ErrorComponent(1, 2, 2 / 48.0), - ErrorComponent(2, 2, 1 / 48.0), - ) - - @JvmStatic - public val INSTANCE: StuckiDitherer = StuckiDitherer() - } -} \ No newline at end of file diff --git a/src/main/kotlin/xyz/cssxsh/pixiv/tool/UniversalDitherer.kt b/src/main/kotlin/xyz/cssxsh/pixiv/tool/UniversalDitherer.kt deleted file mode 100644 index 7364a3c..0000000 --- a/src/main/kotlin/xyz/cssxsh/pixiv/tool/UniversalDitherer.kt +++ /dev/null @@ -1,36 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import com.squareup.gifencoder.* - -public open class UniversalDitherer(private val distribution: List) : Ditherer { - override fun dither(image: Image, newColors: MutableSet): Image { - val width = image.width - val height = image.height - val colors = Array(height) { y -> Array(width) { x -> image.getColor(x, y) } } - - for (y in 0 until height) { - for (x in 0 until width) { - val original = colors[y][x] - val replacement = original.getNearestColor(newColors) - colors[y][x] = replacement - val error = original.minus(replacement) - for (component in distribution) { - val siblingX = x + component.deltaX - val siblingY = y + component.deltaY - if (siblingX in 0 until width && siblingY in 0 until height) { - val offset = error.scaled(component.power) - colors[siblingY][siblingX] = colors[siblingY][siblingX].plus(offset) - } - } - } - } - - return Image.fromColors(colors) - } - - public data class ErrorComponent( - val deltaX: Int, - val deltaY: Int, - val power: Double - ) -} \ No newline at end of file diff --git a/src/nativeMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.native.kt b/src/nativeMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.native.kt new file mode 100644 index 0000000..e495f8b --- /dev/null +++ b/src/nativeMain/kotlin/xyz/cssxsh/pixiv/PixivAuthClient.native.kt @@ -0,0 +1,6 @@ +package xyz.cssxsh.pixiv + +import io.ktor.client.engine.* +import io.ktor.client.engine.curl.* + +internal actual val httpClient: HttpClientEngineFactory<*> = Curl diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/SummaryTest.kt b/src/test/kotlin/xyz/cssxsh/pixiv/SummaryTest.kt deleted file mode 100644 index 3769a1a..0000000 --- a/src/test/kotlin/xyz/cssxsh/pixiv/SummaryTest.kt +++ /dev/null @@ -1,26 +0,0 @@ -package xyz.cssxsh.pixiv - -import org.junit.jupiter.api.* -import java.io.* - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -internal abstract class SummaryTest { - - private var stdout: PrintStream? = null - - @BeforeAll - open fun init() { - val markdown = File(System.getenv("GITHUB_STEP_SUMMARY") ?: "run/summary.md") - if (markdown.exists()) { - stdout = System.out - System.setOut(PrintStream(markdown)) - } - } - - @AfterAll - open fun redirect() { - if (stdout != null) { - System.setOut(stdout) - } - } -} \ No newline at end of file diff --git a/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt b/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt deleted file mode 100644 index f5e048b..0000000 --- a/src/test/kotlin/xyz/cssxsh/pixiv/tool/PixivUgoiraEncoderTest.kt +++ /dev/null @@ -1,101 +0,0 @@ -package xyz.cssxsh.pixiv.tool - -import com.squareup.gifencoder.* -import io.ktor.http.* -import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.assertTrue -import org.junit.jupiter.api.BeforeAll -import org.junit.jupiter.api.Test -import org.junit.jupiter.api.TestInstance -import xyz.cssxsh.pixiv.PixivJson -import xyz.cssxsh.pixiv.SummaryTest -import xyz.cssxsh.pixiv.apps.IllustInfo -import xyz.cssxsh.pixiv.apps.UgoiraMetadata -import xyz.cssxsh.pixiv.gifencoder.OctTreeQuantizer -import java.io.File -import kotlin.system.measureTimeMillis - -@TestInstance(TestInstance.Lifecycle.PER_CLASS) -internal class PixivUgoiraEncoderTest : SummaryTest() { - - private val exampleDir = File("example") - - private val workDir = File("run") - - private val downloader: PixivDownloader = PixivDownloader() - - private val mediancut = object : PixivGifEncoder(downloader) { - override val cache: File get() = workDir - override val quantizer: ColorQuantizer = MedianCutQuantizer.INSTANCE - override val ditherer: Ditherer = FloydSteinbergDitherer.INSTANCE - override val disposalMethod: DisposalMethod = DisposalMethod.UNSPECIFIED - } - - private val octtree = object : PixivGifEncoder(downloader) { - override val cache: File get() = workDir - override val quantizer: ColorQuantizer = OctTreeQuantizer.INSTANCE - override val ditherer: Ditherer = FloydSteinbergDitherer.INSTANCE - override val disposalMethod: DisposalMethod = DisposalMethod.UNSPECIFIED - } - - private val opencv = object : PixivGifEncoder(downloader) { - override val cache: File get() = workDir - override val quantizer: ColorQuantizer = OpenCVQuantizer.INSTANCE - override val ditherer: Ditherer = FloydSteinbergDitherer.INSTANCE - override val disposalMethod: DisposalMethod = DisposalMethod.UNSPECIFIED - } - - private val illust = PixivJson.decodeFromString(exampleDir.resolve("99565513.json").readText()) - - private val ugoira = PixivJson.decodeFromString(exampleDir.resolve("99565513.ugoira.json").readText()) - - @BeforeAll - override fun init() { - super.init() - - val original = Url(ugoira.zipUrls.values.first().replace("600x600", "1920x1080")) - workDir.resolve(original.encodedPath.substringAfterLast('/')).apply { - if (exists().not()) { - parentFile.mkdirs() - runBlocking { - writeBytes(downloader.download(original)) - } - } - } - - println("# Ugoira Encoder Test") - println("| QUANTIZER | SIZE | DURATION |") - println("|:---------:|:----:|:--------:|") - } - - @Test - fun mediancut(): Unit = runBlocking { - val file: File - val millis = measureTimeMillis { - file = mediancut.encode(illust = illust, metadata = ugoira) - } - assertTrue(file.exists()) - println("| MedianCut | ${file.length() shr 10}KB | ${java.time.Duration.ofMillis(millis)} |") - } - - @Test - fun octtree(): Unit = runBlocking { - val file: File - val millis = measureTimeMillis { - file = octtree.encode(illust = illust, metadata = ugoira) - } - assertTrue(file.exists()) - println("| OctTree | ${file.length() shr 10}KB | ${java.time.Duration.ofMillis(millis)} |") - } - - @Test - fun opencv(): Unit = runBlocking { - val file: File - val millis = measureTimeMillis { - file = opencv.encode(illust = illust, metadata = ugoira) - } - - assertTrue(file.exists()) - println("| OpenCV | ${file.length() shr 10}KB | ${java.time.Duration.ofMillis(millis)} |") - } -} \ No newline at end of file