Skip to content

Commit

Permalink
feat(src/ru): New source: Animelib (#3138)
Browse files Browse the repository at this point in the history
  • Loading branch information
danya140 authored Apr 9, 2024
1 parent 060f3c0 commit 095f005
Show file tree
Hide file tree
Showing 9 changed files with 878 additions and 0 deletions.
12 changes: 12 additions & 0 deletions src/ru/animelib/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
ext {
extName = 'Animelib'
extClass = '.Animelib'
extVersionCode = 1
isNsfw = true
}

apply from: "$rootDir/common.gradle"

dependencies {
implementation project(':lib:playlist-utils')
}
Binary file added src/ru/animelib/res/mipmap-hdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/ru/animelib/res/mipmap-mdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/ru/animelib/res/mipmap-xhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/ru/animelib/res/mipmap-xxhdpi/ic_launcher.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
package eu.kanade.tachiyomi.animeextension.ru.animelib

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class AnimeStatus(
val id: Int,
)

@Serializable
data class CoverInfo(
val thumbnail: String,
)

@Serializable
data class GenreInfo(
val id: Int,
val name: String,
)

@Serializable
data class PublisherInfo(
val id: Int,
val name: String,
)

@Serializable
data class AuthorInfo(
val id: Int,
val name: String,
)

@Serializable
data class AnimeData(
val id: Int,
@SerialName("rus_name") val rusName: String,
@SerialName("slug_url") val href: String,
@SerialName("status") val animeStatus: AnimeStatus,
val cover: CoverInfo,

// Optional
@SerialName("is_licensed") val licensed: Boolean? = null,
val summary: String? = null,
val genres: List<GenreInfo>? = null,
val publisher: List<PublisherInfo>? = null,
val authors: List<AuthorInfo>? = null,
)

@Serializable
data class PageMetaData(
val next: String? = null,
)

@Serializable
data class AnimeList(
val data: List<AnimeData>,
val links: PageMetaData? = null,
)

@Serializable
data class AnimeInfo(
val data: AnimeData,
)

// ============================== Episode ==============================
@Serializable
data class TeamInfo(
val id: Int,
val name: String,
)

@Serializable
data class VideoQuality(
val href: String,
val quality: Int,
)

@Serializable
data class VideoMetaData(
val id: Int,
val quality: List<VideoQuality>,
)

@Serializable
data class TranslationInfo(
val id: Int,
)

@Serializable
data class SubtitleInfo(
val id: Int,
val format: String,
val src: String,
)

@Serializable
data class VideoInfo(
val id: Int,
val player: String,
val team: TeamInfo,

@SerialName("translation_type") val translationInfo: TranslationInfo,

// Kodik player
val src: String? = null,

// Animelib player
val video: VideoMetaData? = null,
val subtitles: List<SubtitleInfo>? = null,
)

@Serializable
data class EpisodeInfo(
val id: Int,
@SerialName("name") val episodeName: String,
val number: String,
val season: String,
@SerialName("created_at") val date: String,

// Optional
val players: List<VideoInfo>? = null,
)

@Serializable
data class EpisodeVideoData(
val data: EpisodeInfo,
)

@Serializable
data class EpisodeList(
val data: List<EpisodeInfo>,
)

// ============================== VideoServer ==============================
@Serializable
data class VideoServerInfo(
val id: String,
val label: String,
val url: String,
)

@Serializable
data class VideoServers(
val videoServers: List<VideoServerInfo>,
)

@Serializable
data class VideoServerData(
val data: VideoServers,
)

// ============================== Kodik ==============================
@Serializable
data class KodikForm(
val d: String = "",
@SerialName("d_sign") val dSign: String = "",
val pd: String = "",
@SerialName("pd_sign") val pdSign: String = "",
val ref: String = "",
@SerialName("ref_sign") val refSign: String = "",
)

@Serializable
data class KodikVideoInfo(
val src: String,
)

@Serializable
data class KodikVideoQuality(
@SerialName("480") val bad: List<KodikVideoInfo>,
@SerialName("720") val good: List<KodikVideoInfo>,
@SerialName("360") val ugly: List<KodikVideoInfo>,
)

@Serializable
data class KodikData(
val links: KodikVideoQuality,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,192 @@
package eu.kanade.tachiyomi.animeextension.ru.animelib

import eu.kanade.tachiyomi.animesource.model.AnimeFilter
import eu.kanade.tachiyomi.animesource.model.AnimeFilterList

object AnimelibFilters {

open class TriStateFilterList(name: String, values: List<AnimeFilter.TriState>) : AnimeFilter.Group<AnimeFilter.TriState>(name, values)
class TriFilterVal(name: String) : AnimeFilter.TriState(name)

class GenresFilter : TriStateFilterList("Жанр", AnimelibFiltersData.GENRES.map { TriFilterVal(it.first) })

private inline fun <reified R> AnimeFilterList.getFirst(): R = first { it is R } as R

private inline fun <reified R> AnimeFilterList.parseTriFilter(options: Array<Pair<String, String>>): IncludeExcludeParams {
return (getFirst<R>() as TriStateFilterList).state
.filterNot { it.isIgnored() }
.map { filter -> filter.state to options.find { it.first == filter.name }!!.second }
.groupBy { it.first }
.let { dict ->
val included = dict[AnimeFilter.TriState.STATE_INCLUDE]?.map { it.second }.orEmpty()
val excluded = dict[AnimeFilter.TriState.STATE_EXCLUDE]?.map { it.second }.orEmpty()
IncludeExcludeParams(included, excluded)
}
}

open class CheckBoxFilterList(name: String, values: List<CheckBox>) : AnimeFilter.Group<AnimeFilter.CheckBox>(name, values)
class CheckBoxVal(name: String, state: Boolean = false) : AnimeFilter.CheckBox(name, state)

class FormatFilter : CheckBoxFilterList("Формат", AnimelibFiltersData.FORMATS.map { CheckBoxVal(it.first) })
class PegiFilter : CheckBoxFilterList("Возрастной рейтинг", AnimelibFiltersData.PEGI.map { CheckBoxVal(it.first) })
class OngoingFilter : CheckBoxFilterList("Статус тайтла", AnimelibFiltersData.ONGOING_STATUS.map { CheckBoxVal(it.first) })

private inline fun <reified R> AnimeFilterList.parseCheckbox(options: Array<Pair<String, String>>): List<String> {
return (getFirst<R>() as CheckBoxFilterList).state
.asSequence()
.filter { it.state }
.map { checkbox -> options.find { it.first == checkbox.name }!!.second }
.toList()
}

class SortFilter : AnimeFilter.Sort(
"Сортировать по",
AnimelibFiltersData.ORDERS.map { it.first }.toTypedArray(),
Selection(0, false),
)

val FILTER_LIST get() = AnimeFilterList(
GenresFilter(),

PegiFilter(),
FormatFilter(),
OngoingFilter(),

SortFilter(),
)

data class IncludeExcludeParams(
val include: List<String> = emptyList(),
var exclude: List<String> = emptyList(),
)

data class FilterSearchParams(
val genres: IncludeExcludeParams = IncludeExcludeParams(),
val format: List<String> = emptyList(),
val pegi: List<String> = emptyList(),
val ongoingStatus: List<String> = emptyList(),

val sortOrder: String = AnimelibFiltersData.ORDERS[0].second,
val sortDirection: String = "",
)

internal fun getSearchParameters(filters: AnimeFilterList): FilterSearchParams {
if (filters.isEmpty()) return FilterSearchParams()

val sortDirection = filters.getFirst<SortFilter>().state?.let {
if (it.ascending) "asc" else ""
} ?: ""

val sortOrder = filters.getFirst<SortFilter>().state?.let {
AnimelibFiltersData.ORDERS[it.index].second
} ?: ""

return FilterSearchParams(
filters.parseTriFilter<GenresFilter>(AnimelibFiltersData.GENRES),
filters.parseCheckbox<FormatFilter>(AnimelibFiltersData.FORMATS),
filters.parseCheckbox<PegiFilter>(AnimelibFiltersData.PEGI),
filters.parseCheckbox<OngoingFilter>(AnimelibFiltersData.ONGOING_STATUS),
sortOrder,
sortDirection,
)
}

private object AnimelibFiltersData {
val FORMATS = arrayOf(
Pair("TV сериалы", "16"),
Pair("Фильмы", "17"),
Pair("Короткометражное", "18"),
Pair("Спешл", "19"),
Pair("OVA", "20"),
Pair("ONA", "21"),
Pair("Клип", "22"),
)

val GENRES = arrayOf(
Pair("Арт", "32"),
Pair("Безумие", "91"),
Pair("Боевик", "34"),
Pair("Боевые искусства", "35"),
Pair("Вампиры", "36"),
Pair("Военное", "89"),
Pair("Гарем", "37"),
Pair("Гендерная интрига", "38"),
Pair("Героическое фэнтези", "39"),
Pair("Демоны", "81"),
Pair("Детектив", "40"),
Pair("Детское", "88"),
Pair("Дзёсэй", "41"),
Pair("Драма", "43"),
Pair("Игра", "44"),
Pair("Исекай", "79"),
Pair("История", "45"),
Pair("Киберпанк", "46"),
Pair("Кодомо", "76"),
Pair("Комедия", "47"),
Pair("Космос", "83"),
Pair("Магия", "85"),
Pair("Махо-сёдзё", "48"),
Pair("Машины", "90"),
Pair("Меха", "49"),
Pair("Мистика", "50"),
Pair("Музыка", "80"),
Pair("Научная фантастика", "51"),
Pair("Омегаверс", "77"),
Pair("Пародия", "86"),
Pair("Повседневность", "52"),
Pair("Полиция", "82"),
Pair("Постапокалиптика", "53"),
Pair("Приключения", "54"),
Pair("Психология", "55"),
Pair("Романтика", "56"),
Pair("Самурайский боевик", "57"),
Pair("Сверхъестественное", "58"),
Pair("Сёдзё", "59"),
Pair("Сёдзё-ай", "60"),
Pair("Сёнэн", "61"),
Pair("Сёнэн-ай", "62"),
Pair("Спорт", "63"),
Pair("Супер сила", "87"),
Pair("Сэйнэн", "64"),
Pair("Трагедия", "65"),
Pair("Триллер", "66"),
Pair("Ужасы", "67"),
Pair("Фантастика", "68"),
Pair("Фэнтези", "69"),
Pair("Хентай", "84"),
Pair("Школа", "70"),
Pair("Эротика", "71"),
Pair("Этти", "72"),
Pair("Юри", "73"),
Pair("Яой", "74"),
)

val PEGI = arrayOf(
Pair("Нет", "0"),
Pair("6+", "1"),
Pair("12+", "2"),
Pair("16+", "3"),
Pair("18+", "4"),
Pair("18+ (RX)", "5"),
)

val ONGOING_STATUS = arrayOf(
Pair("Онгоинг", "1"),
Pair("Завершён", "2"),
Pair("Анонс", "3"),
Pair("Приостановлен", "4"),
Pair("Выпуск прекращён", "5"),
)

val ORDERS = arrayOf(
Pair("Популярности", "rating_score"),
Pair("Рейтингу", "rate_avg"),
Pair("Просмотрам", "views"),
Pair("Количеству эпизодов", "episodes_count"),
Pair("Дате обновления", "last_episode_at"),
Pair("Дате добавления", "created_at"),
Pair("Названию (A-Z)", "name"),
Pair("Названию (А-Я)", "rus_name"),
)
}
}

0 comments on commit 095f005

Please sign in to comment.