@ -41,7 +41,7 @@ object AoDParser {
private const val loginPath = " /users/sign_in "
private const val libraryPath = " /animes "
private const val userAgent = " Mozilla/5.0 (X11; Linux x86_64; rv:80.0) Gecko/20100101 Firefox/80 .0 "
private const val userAgent = " Mozilla/5.0 (X11; Linux x86_64; rv:84.0) Gecko/20100101 Firefox/84 .0 "
private var sessionCookies = mutableMapOf < String , String > ( )
private var csrfToken : String = " "
@ -53,10 +53,11 @@ object AoDParser {
val newEpisodesList = arrayListOf < ItemMedia > ( )
val newSimulcastsList = arrayListOf < ItemMedia > ( )
val newTitlesList = arrayListOf < ItemMedia > ( )
val topTenList = arrayListOf < ItemMedia > ( )
fun login ( ) : Boolean = runBlocking {
withContext ( Dispatchers . Default ) {
withContext ( Dispatchers . IO ) {
// get the authenticity token
val resAuth = Jsoup . connect ( baseUrl + loginPath )
. header ( " User-Agent " , userAgent )
@ -78,7 +79,7 @@ object AoDParser {
val resLogin = Jsoup . connect ( baseUrl + loginPath )
. method ( Connection . Method . POST )
. timeout ( 60000 ) // login can take some time
. timeout ( 60000 ) // login can take some time default is 60000 (60 sec)
. data ( data )
. postDataCharset ( " UTF-8 " )
. cookies ( authCookies )
@ -96,20 +97,11 @@ object AoDParser {
/ * *
* initially load all media and home screen data
* -> blocking
* /
fun initialLoading ( ) = runBlocking {
val loadHomeJob = GlobalScope . async {
loadHome ( )
}
val listJob = GlobalScope . async {
fun initialLoading ( ) = listOf (
loadHome ( ) ,
listAnimes ( )
}
loadHomeJob . await ( )
listJob . await ( )
}
)
/ * *
* get a media by it ' s ID ( int )
@ -134,7 +126,7 @@ object AoDParser {
}
// TODO don't use jsoup here
fun sendCallback ( callbackPath : String ) = GlobalScope . launch ( Dispatchers . IO ) {
private fun sendCallback ( callbackPath : String ) = GlobalScope . launch ( Dispatchers . IO ) {
val headers = mutableMapOf (
Pair ( " Accept " , " application/json, text/javascript, */*; q=0.01 " ) ,
Pair ( " Accept-Language " , " de,en-US;q=0.7,en;q=0.3 " ) ,
@ -158,112 +150,112 @@ object AoDParser {
/ * *
* load all media from aod into itemMediaList and mediaList
* /
private fun listAnimes ( ) = runBlocking {
if ( sessionCookies . isEmpty ( ) ) login ( )
withContext ( Dispatchers . Default ) {
val resAnimes = Jsoup . connect ( baseUrl + libraryPath )
. cookies ( sessionCookies )
. get ( )
//println(resAnimes)
itemMediaList . clear ( )
mediaList . clear ( )
resAnimes . select ( " div.animebox " ) . forEach {
val type = if ( it . select ( " p.animebox-link " ) . select ( " a " ) . text ( ) . toLowerCase ( Locale . ROOT ) == " zur serie " ) {
MediaType . TVSHOW
} else {
MediaType . MOVIE
}
val mediaTitle = it . select ( " h3.animebox-title " ) . text ( )
val mediaLink = it . select ( " p.animebox-link " ) . select ( " a " ) . attr ( " href " )
val mediaImage = it . select ( " p.animebox-image " ) . select ( " img " ) . attr ( " src " )
val mediaShortText = it . select ( " p.animebox-shorttext " ) . text ( )
val mediaId = mediaLink . substringAfterLast ( " / " ) . toInt ( )
itemMediaList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
mediaList . add ( Media ( mediaId , mediaLink , type ) . apply {
info . title = mediaTitle
info . posterUrl = mediaImage
info . shortDesc = mediaShortText
} )
private fun listAnimes ( ) = GlobalScope . launch ( Dispatchers . IO ) {
val resAnimes = Jsoup . connect ( baseUrl + libraryPath ) . get ( )
//println(resAnimes)
itemMediaList . clear ( )
mediaList . clear ( )
resAnimes . select ( " div.animebox " ) . forEach {
val type = if ( it . select ( " p.animebox-link " ) . select ( " a " ) . text ( ) . toLowerCase ( Locale . ROOT ) == " zur serie " ) {
MediaType . TVSHOW
} else {
MediaType . MOVIE
}
Log . i ( javaClass . name , " Total library size is: ${mediaList.size} " )
val mediaTitle = it . select ( " h3.animebox-title " ) . text ( )
val mediaLink = it . select ( " p.animebox-link " ) . select ( " a " ) . attr ( " href " )
val mediaImage = it . select ( " p.animebox-image " ) . select ( " img " ) . attr ( " src " )
val mediaShortText = it . select ( " p.animebox-shorttext " ) . text ( )
val mediaId = mediaLink . substringAfterLast ( " / " ) . toInt ( )
itemMediaList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
mediaList . add ( Media ( mediaId , mediaLink , type ) . apply {
info . title = mediaTitle
info . posterUrl = mediaImage
info . shortDesc = mediaShortText
} )
}
Log . i ( javaClass . name , " Total library size is: ${mediaList.size} " )
}
/ * *
* load new episodes , titles and highlights
* /
private fun loadHome ( ) = runBlocking {
if ( sessionCookies . isEmpty ( ) ) login ( )
private fun loadHome ( ) = GlobalScope . launch ( Dispatchers . IO ) {
val resHome = Jsoup . connect ( baseUrl ) . get ( )
// get highlights from AoD
highlightsList . clear ( )
resHome . select ( " #aod-highlights " ) . select ( " div.news-item " ) . forEach {
val mediaId = it . select ( " div.news-item-text " ) . select ( " a.serienlink " )
. attr ( " href " ) . substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaTitle = it . select ( " div.news-title " ) . select ( " h2 " ) . text ( )
val mediaImage = it . select ( " img " ) . attr ( " src " )
if ( mediaId != null ) {
highlightsList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
}
withContext ( Dispatchers . Default ) {
val resHome = Jsoup . connect ( baseUrl )
. cookies ( sessionCookies )
. get ( )
// get highlights from AoD
highlightsList . clear ( )
resHome . select ( " #aod-highlights " ) . select ( " div.news-item " ) . forEach {
val mediaId = it . select ( " div.news-item-text " ) . select ( " a.serienlink " )
. attr ( " href " ) . substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaTitle = it . select ( " div.news-title " ) . select ( " h2 " ) . text ( )
val mediaImage = it . select ( " img " ) . attr ( " src " )
if ( mediaId != null ) {
highlightsList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
// get all new episodes from AoD
newEpisodesList . clear ( )
resHome . select ( " h2:contains(Neue Episoden) " ) . next ( ) . select ( " li " ) . forEach {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = " ${it.select("a").text()} - ${it.select("span.neweps").text()} "
if ( mediaId != null ) {
newEpisodesList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
}
// get all new episode s from AoD
newEpisode sList . clear ( )
resHome . select ( " h2:contains(Neue Episoden ) " ) . next ( ) . select ( " li " ) . forEach {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = " ${it.select("a").text()} - ${it.select("span.neweps").text()} "
// get new simulcasts from AoD
newSimulcastsList . clear ( )
resHome . select ( " h2:contains(Neue Simulcasts) " ) . next ( ) . select ( " li " ) . forEach {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = it . select ( " a " ) . text ( )
if ( mediaId != null ) {
newEpisodesList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
if ( mediaId != null ) {
newSimulcastsList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
}
// get new simulcast s from AoD
newSimulcast sList . clear ( )
resHome . select ( " h2:contains(Neue Simulcasts ) " ) . next ( ) . select ( " li " ) . forEach {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = it . select ( " a " ) . text ( )
// get new title s from AoD
newTitle sList. clear ( )
resHome . select ( " h2:contains(Neue Anime-Titel ) " ) . next ( ) . select ( " li " ) . forEach {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = it . select ( " a " ) . text ( )
if ( mediaId != null ) {
newSimulcastsList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
if ( mediaId != null ) {
newTitlesList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
}
// get new titles from AoD
newTitles List . clear ( )
resHome . select ( " h2:contains(Neue Anime-Titel ) " ) . next ( ) . select ( " li " ) . forEach {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = it . select ( " a " ) . text ( )
// get top ten from AoD
topTen List. clear ( )
resHome . select ( " h2:contains(Anime Top 10 ) " ) . next ( ) . select ( " li " ) . forEach {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = it . select ( " a " ) . text ( )
if ( mediaId != null ) {
newTitlesList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
if ( mediaId != null ) {
topTenList . add ( ItemMedia ( mediaId , mediaTitle , mediaImage ) )
}
}
// if highlights is empty, add a random new title
if ( highlightsList . isEmpty ( ) ) {
if ( newTitlesList . isNotEmpty ( ) ) {
highlightsList . add ( newTitlesList [ Random . nextInt ( 0 , newTitlesList . size ) ] )
} else {
highlightsList . add ( ItemMedia ( 0 , " " , " " ) )
}
// if highlights is empty, add a random new title
if ( highlightsList . isEmpty ( ) ) {
if ( newTitlesList . isNotEmpty ( ) ) {
highlightsList . add ( newTitlesList [ Random . nextInt ( 0 , newTitlesList . size ) ] )
} else {
highlightsList . add ( ItemMedia ( 0 , " " , " " ) )
}
}
}
@ -272,7 +264,7 @@ object AoDParser {
* load streams for the media path , movies have one episode
* @param media is used as call ba reference
* /
private suspend fun loadStreams ( media : Media ) = GlobalScope . launch ( Dispatchers . IO ) {
private fun loadStreams ( media : Media ) = GlobalScope . launch ( Dispatchers . IO ) {
if ( sessionCookies . isEmpty ( ) ) login ( )
if ( ! loginSuccess ) {
@ -331,7 +323,7 @@ object AoDParser {
}
Log . i ( javaClass . name , " Loaded playlists successfully " )
// parse additional info from the media page
// additional info from the media page
res . select ( " table.vertical-table " ) . select ( " tr " ) . forEach { row ->
when ( row . select ( " th " ) . text ( ) . toLowerCase ( Locale . ROOT ) ) {
" produktionsjahr " -> media . info . year = row . select ( " td " ) . text ( ) . toInt ( )
@ -345,7 +337,21 @@ object AoDParser {
}
}
// parse additional information for tv shows the episode title (description) is loaded from the "api"
// similar titles from media page
media . info . similar = res . select ( " h2:contains(รhnliche Animes) " ) . next ( ) . select ( " li " ) . mapNotNull {
val mediaId = it . select ( " a.thumbs " ) . attr ( " href " )
. substringAfterLast ( " / " ) . toIntOrNull ( )
val mediaImage = it . select ( " a.thumbs > img " ) . attr ( " src " )
val mediaTitle = it . select ( " a " ) . text ( )
if ( mediaId != null ) {
ItemMedia ( mediaId , mediaTitle , mediaImage )
} else {
null
}
}
// additional information for tv shows the episode title (description) is loaded from the "api"
if ( media . type == MediaType . TVSHOW ) {
res . select ( " div.three-box-container > div.episodebox " ) . forEach { episodebox ->
// make sure the episode has a streaming link
@ -363,6 +369,7 @@ object AoDParser {
}
}
}
Log . i ( javaClass . name , " media loaded successfully " )
}
/ * *