Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions app/src/main/java/moe/apex/breadboard/image/Image.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import moe.apex.breadboard.preferences.ImageSource
import moe.apex.breadboard.tag.TagCategory
import moe.apex.breadboard.tag.TagGroup
import moe.apex.breadboard.util.MigrationOnlyField
import moe.apex.breadboard.util.PixivArtwork


@Serializable
Expand All @@ -21,7 +22,8 @@ data class ImageMetadata(
val uncategorisedTags: List<String>? = null,
val groupedTags: List<TagGroup> = emptyList(),
val rating: ImageRating,
val pixivId: Int? = null,
@SerialName("pixivId")
private val pixivArtworkId: Int? = null,
@MigrationOnlyField
@SerialName("artist")
@Deprecated(
Expand All @@ -36,8 +38,18 @@ data class ImageMetadata(
val tags: List<String>
get() = groupedTags.fold(emptyList()) { acc, tagGroup -> acc + tagGroup.tags }

val pixivId: Int?
get() = pixivArtworkId ?: pixivArtwork?.id

val pixivArtwork: PixivArtwork?
get() = PixivArtwork.fromUrl(source) ?: pixivArtworkId?.let { PixivArtwork(it, 0) }

val pixivUrl: String?
get() = pixivId?.let { "https://www.pixiv.net/en/artworks/$it" }
get() = pixivArtwork?.let {
val id = if (it.index == 0) it.id.toString()
else "${it.id}#${it.index}"
"https://www.pixiv.net/artworks/$id"
}

}

Expand Down
7 changes: 1 addition & 6 deletions app/src/main/java/moe/apex/breadboard/image/ImageBoard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ import moe.apex.breadboard.tag.TagCategory
import moe.apex.breadboard.tag.TagGroup
import moe.apex.breadboard.tag.TagSuggestion
import moe.apex.breadboard.util.decodeHtml
import moe.apex.breadboard.util.extractPixivId
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
Expand Down Expand Up @@ -195,15 +194,13 @@ interface GelbooruBasedImageBoard : ImageBoard {
}

val metaRating = getRatingFromString(e.getString("rating"))
val metaPixivId = extractPixivId(metaSource)
val metadata = ImageMetadata(
parentId = metaParentId,
hasChildren = null, // Not available for Gelbooru-based image boards
artists = metaArtists,
source = metaSource,
groupedTags = metaGroupedTags,
rating = metaRating,
pixivId = metaPixivId,
)

return Image(id, fileName, fileFormat, previewUrl, fileUrl, sampleUrl, imageSource, aspectRatio, metadata)
Expand Down Expand Up @@ -459,7 +456,7 @@ object Danbooru : ImageBoard {
source = metaSource,
groupedTags = metaGroupedTags,
rating = metaRating,
pixivId = metaPixivId,
pixivArtworkId = metaPixivId,
)

return Image(id, fileName, fileFormat, previewUrl, fileUrl, sampleUrl, ImageSource.DANBOORU, aspectRatio, metadata)
Expand Down Expand Up @@ -543,14 +540,12 @@ object Yandere : ImageBoard {
TagCategory.GENERAL.group(e.getString("tags").decodeHtml().split(" ")),
)
val metaRating = getRatingFromString(e.getString("rating"))
val metaPixivId = extractPixivId(metaSource)
val metadata = ImageMetadata(
parentId = metaParentId,
hasChildren = metaHasChildren,
source = metaSource,
groupedTags = metaGroupedTags,
rating = metaRating,
pixivId = metaPixivId,
)

return Image(id, fileName, fileFormat, previewUrl, fileUrl, sampleUrl, ImageSource.YANDERE, aspectRatio, metadata)
Expand Down
4 changes: 2 additions & 2 deletions app/src/main/java/moe/apex/breadboard/preferences/Pref.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ import moe.apex.breadboard.image.AI_TAG_NAMES
import moe.apex.breadboard.tag.TagCategory
import moe.apex.breadboard.util.AgeVerification
import moe.apex.breadboard.util.MigrationOnlyField
import moe.apex.breadboard.util.PixivArtwork
import moe.apex.breadboard.util.SecretsManager
import moe.apex.breadboard.util.availableRatingsForSource
import moe.apex.breadboard.util.extractPixivId
import moe.apex.breadboard.util.decodeHtml
import java.io.IOException

Expand Down Expand Up @@ -404,7 +404,7 @@ class UserPreferencesRepository(private val dataStore: DataStore<Preferences>) {
uncategorisedTags = null,
groupedTags = if (!image.metadata.uncategorisedTags.isNullOrEmpty()) listOf(TagCategory.GENERAL.group(image.metadata.tags))
else emptyList(),
pixivId = image.metadata.pixivId ?: extractPixivId(image.metadata.source)
pixivArtworkId = image.metadata.pixivId ?: PixivArtwork.fromUrl(image.metadata.source)?.id
)
)
)
Expand Down
30 changes: 26 additions & 4 deletions app/src/main/java/moe/apex/breadboard/util/Links.kt
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,35 @@ private val links = mapOf(
fun fixLink(link: String): String {
val uri = link.toUri()
for ((originalHost, fixedHost) in links) {
if (uri.host == originalHost) {
return uri.buildUpon().authority(fixedHost).build().toString()
val newHost = if (uri.host == originalHost) {
fixedHost
} else if (uri.host!!.endsWith(".$originalHost")) {
val subdomain = uri.host!!.substringBeforeLast(".$originalHost")
val newHost = "$subdomain.$fixedHost"
return uri.buildUpon().authority(newHost).build().toString()
"$subdomain.$fixedHost"
} else {
continue
}

var newPath: String? = null
var newFragment: String? = null

/* The phixiv fixer cannot take the official pixiv image index syntax into account since
URI fragments are client-sided, so we have to use its own path syntax for indexed images. */
if (fixedHost == "phixiv.net" && "/artworks/\\d+$".toRegex().containsMatchIn(uri.path ?: "")) {
val index = uri.fragment?.toIntOrNull().takeIf { it != 0 }
if (index != null) {
newPath = "${uri.path}/${index + 1}"
newFragment = ""
}
}

return uri
.buildUpon()
.authority(newHost)
.path(newPath ?: uri.path)
.fragment(newFragment ?: uri.fragment)
.build()
.toString()
}
return link
}
Expand Down
29 changes: 17 additions & 12 deletions app/src/main/java/moe/apex/breadboard/util/Pixiv.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,34 +4,39 @@ package moe.apex.breadboard.util
private val PIXIV_CURRENT_RX =
// https://i.pximg.net/img-original/img/2022/11/27/21/27/08/103150283_p0.jpg (Safebooru #6517847)
// https://i.pximg.net/img-master/img/2019/07/09/08/27/59/75629295_p0_master1200.jpg (Safebooru #3567627)
"""https?://i\.pximg\.net/img-(?:original|master)/img/\d+/\d+/\d+/\d+/\d+/\d+/(\d+)_p\d+(_master1200)?\.(png|jpg|jpeg|gif)""".toRegex()
"""https?://i\.pximg\.net/img-(original|master)/img/\d+/\d+/\d+/\d+/\d+/\d+/(?<id>\d+)_p(?<index>\d+)(_master1200)?\.(png|jpg|jpeg|gif)""".toRegex()

// 2012-2016 pixiv direct image URLs
private val PIXIV_2012_TO_2016_RX = listOf(
// https://i1.pixiv.net/img-original/img/2016/10/02/16/47/39/59270556_p0.jpg (Safebooru #1843535)
// No source, but I'd assume an `img-master` version exists too on this old subdomain
"""https?://i\d+\.pixiv\.net/img-(?:original|master)/img/\d+/\d+/\d+/\d+/\d+/\d+/(\d+)_p\d+(_master1200)?\.(png|jpg|jpeg|gif)""".toRegex(),
"""https?://i\d+\.pixiv\.net/img-(original|master)/img/\d+/\d+/\d+/\d+/\d+/\d+/(?<id>\d+)_p(?<index>\d+)(_master1200)?\.(png|jpg|jpeg|gif)""".toRegex(),

// https://i1.pixiv.net/img47/img/l3lc201/34464791.png (Safebooru #1000441)
// https://i1.pixiv.net/img21/img/togainuakira/34478247_big_p8.jpg (Safebooru #1000649)
"""https?://i\d+\.pixiv\.net/img\d+/img/.+/(\d+)(_big_p\d+)?\.(png|jpg|jpeg|gif)""".toRegex()
"""https?://i\d+\.pixiv\.net/img\d+/img/.+/(?<id>\d+)(_big_p(?<index>\d+))?\.(png|jpg|jpeg|gif)""".toRegex()
)

// Pre-2012 pixiv direct image URLs
private val PIXIV_PRE_2012_RX =
// https://img13.pixiv.net/img/tubasarei/4894590.jpg (Safebooru #166629)
"""https?://img\d+\.pixiv\.net/img/.+/(\d+)\.(png|jpg|jpeg|gif)""".toRegex()
"""https?://img\d+\.pixiv\.net/img/.+/(?<id>\d+)\.(png|jpg|jpeg|gif)""".toRegex()

private val PIXIV_RX = listOf(PIXIV_CURRENT_RX) + PIXIV_2012_TO_2016_RX + PIXIV_PRE_2012_RX

fun extractPixivId(url: String?): Int? {
if (url == null) return null
data class PixivArtwork(val id: Int, val index: Int) {
companion object {
fun fromUrl(url: String?): PixivArtwork? {
if (url == null) return null

for (regex in PIXIV_RX) {
val match = regex.find(url)
val id = match?.groupValues?.get(1)?.toInt()?.takeIf { it != 0 }
if (id != null) return id
}
for (regex in PIXIV_RX) {
val match = regex.find(url) ?: continue
val id = match.groups["id"]?.value?.toIntOrNull().takeIf { it != 0 } ?: continue
val index = match.groups["index"]?.value?.toIntOrNull() ?: 0
return PixivArtwork(id, index)
}

return null
return null
}
}
}
Loading