From 178400d8e7cf3ca93db210f161005f20852c77cb Mon Sep 17 00:00:00 2001 From: kl3jvi Date: Mon, 17 Jan 2022 02:18:54 +0100 Subject: [PATCH] finally getting m3u8 url ( it's fixed) ^^ --- .idea/deploymentTargetDropDown.xml | 17 ++++++ app/build.gradle | 17 ++++-- .../animity/data/paging/SearchPagingSource.kt | 43 ++++++++++++++ .../data/repository/PlayerRepositoryImpl.kt | 15 +++-- .../data/repository/SearchRepositoryImpl.kt | 33 ++++++----- .../domain/repositories/PlayerRepository.kt | 2 +- .../domain/repositories/SearchRepository.kt | 8 +-- .../domain/use_cases/GetEpisodeInfoUseCase.kt | 21 ++++++- .../use_cases/GetSearchResultUseCase.kt | 43 ++++---------- .../ui/activities/player/PlayerActivity.kt | 10 ++-- .../ui/activities/player/PlayerViewModel.kt | 25 ++++---- .../ui/adapters/CustomSearchAdapter.kt | 18 +++--- .../ui/fragments/search/SearchFragment.kt | 47 +++++++-------- .../ui/fragments/search/SearchViewModel.kt | 25 ++++---- .../com/kl3jvi/animity/utils/Constants.kt | 6 ++ .../com/kl3jvi/animity/utils/ViewUtils.kt | 15 +++++ .../kl3jvi/animity/utils/parser/HtmlParser.kt | 59 +++++-------------- app/src/main/res/layout/fragment_search.xml | 4 +- 18 files changed, 232 insertions(+), 176 deletions(-) create mode 100644 .idea/deploymentTargetDropDown.xml create mode 100644 app/src/main/java/com/kl3jvi/animity/data/paging/SearchPagingSource.kt create mode 100644 app/src/main/java/com/kl3jvi/animity/utils/ViewUtils.kt diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml new file mode 100644 index 00000000..2df534e0 --- /dev/null +++ b/.idea/deploymentTargetDropDown.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle index 874ee6dc..3d454560 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -93,14 +93,14 @@ dependencies { // Coroutine Lifecycle Scopes implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.4.0' implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.4.0" - implementation 'com.google.firebase:firebase-analytics-ktx:20.0.0' - implementation 'com.google.firebase:firebase-crashlytics-ktx:18.2.5' + implementation 'com.google.firebase:firebase-analytics-ktx:20.0.2' + implementation 'com.google.firebase:firebase-crashlytics-ktx:18.2.6' implementation 'androidx.test.ext:junit-ktx:1.1.3' androidTestImplementation 'junit:junit:4.13.2' //dependency injection kapt "com.google.dagger:hilt-android-compiler:2.38.1" - implementation "com.google.dagger:hilt-android:2.40" + implementation "com.google.dagger:hilt-android:2.40.5" // Retrofit implementation 'com.squareup.retrofit2:retrofit:2.9.0' @@ -113,7 +113,7 @@ dependencies { implementation 'androidx.legacy:legacy-support-v4:1.0.0' //Room Library - def room_version = '2.4.0-beta02' + def room_version = '2.4.1' implementation "androidx.room:room-ktx:$room_version" kapt "androidx.room:room-compiler:$room_version" @@ -128,7 +128,7 @@ dependencies { implementation 'com.ms-square:expandableTextView:0.1.4' //animation lib - def lottieVersion = '4.1.0' + def lottieVersion = '4.2.2' implementation "com.airbnb.android:lottie:$lottieVersion" // image library @@ -138,7 +138,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" //splash screen - implementation "androidx.core:core-splashscreen:1.0.0-alpha02" + implementation "androidx.core:core-splashscreen:1.0.0-beta01" implementation 'com.onesignal:OneSignal:4.6.2' @@ -147,4 +147,9 @@ dependencies { implementation 'org.apache.commons:commons-text:1.7' + def paginationVersion = "3.1.0" + implementation "androidx.paging:paging-runtime-ktx:$paginationVersion" + implementation 'com.maxkeppeler.sheets:options:2.2.6' + + } diff --git a/app/src/main/java/com/kl3jvi/animity/data/paging/SearchPagingSource.kt b/app/src/main/java/com/kl3jvi/animity/data/paging/SearchPagingSource.kt new file mode 100644 index 00000000..2a8ee476 --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/data/paging/SearchPagingSource.kt @@ -0,0 +1,43 @@ +package com.kl3jvi.animity.data.paging + +import androidx.paging.PagingSource +import androidx.paging.PagingState +import com.kl3jvi.animity.data.model.AnimeMetaModel +import com.kl3jvi.animity.data.network.AnimeApiClient +import com.kl3jvi.animity.utils.Constants +import com.kl3jvi.animity.utils.Constants.Companion.STARTING_PAGE_INDEX +import com.kl3jvi.animity.utils.Constants.Companion.getHeader +import com.kl3jvi.animity.utils.parser.HtmlParser + +class SearchPagingSource( + private val animeService: AnimeApiClient, + private val query: String +) : PagingSource() { + override fun getRefreshKey(state: PagingState): Int? { + return state.anchorPosition?.let { anchorPosition -> + state.closestPageToPosition(anchorPosition)?.prevKey + } + } + + override suspend fun load(params: LoadParams): LoadResult { + val page = params.key ?: STARTING_PAGE_INDEX + return try { + val searchList = HtmlParser.parseMovie( + animeService.fetchSearchData( + header = getHeader(), + keyword = query, + page = page + ).string(), + Constants.TYPE_SEARCH + ) + LoadResult.Page( + data = searchList, + prevKey = if (page == STARTING_PAGE_INDEX) null else page - 1, + nextKey = if (searchList.isNullOrEmpty()) null else page + 1 + ) + } catch (exception: Exception) { + exception.printStackTrace() + LoadResult.Error(exception) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/data/repository/PlayerRepositoryImpl.kt b/app/src/main/java/com/kl3jvi/animity/data/repository/PlayerRepositoryImpl.kt index 75eadd43..f24f64b4 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/repository/PlayerRepositoryImpl.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/repository/PlayerRepositoryImpl.kt @@ -3,6 +3,7 @@ package com.kl3jvi.animity.data.repository import com.kl3jvi.animity.data.model.EpisodeInfo import com.kl3jvi.animity.data.network.AnimeApiClient import com.kl3jvi.animity.domain.repositories.PlayerRepository +import com.kl3jvi.animity.utils.Constants.Companion.REFERER import com.kl3jvi.animity.utils.parser.HtmlParser import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.withContext @@ -25,18 +26,22 @@ class PlayerRepositoryImpl @Inject constructor( parser.parseMediaUrl(apiClient.fetchEpisodeMediaUrl(header = header, url = url).string()) } - - override suspend fun fetchM3u8Url(header: Map, url: String): String = + override suspend fun fetchM3u8Url( + header: Map, + url: String + ): Pair, ArrayList> = withContext(ioDispatcher) { - parser.parseEncryptAjax(apiClient.fetchM3u8Url(header = header, url = url).string()) ?: "" + parser.parseEncryptedUrls(apiClient.fetchM3u8PreProcessor(header = header, url = url).string()) } override suspend fun fetchEncryptedAjaxUrl(header: Map, url: String): String = withContext(ioDispatcher) { parser.parseEncryptAjax( - apiClient.fetchM3u8PreProcessor(header = header, url = url).string() + apiClient.fetchM3u8Url( + header = header, + url = url + ).string() ) } - } diff --git a/app/src/main/java/com/kl3jvi/animity/data/repository/SearchRepositoryImpl.kt b/app/src/main/java/com/kl3jvi/animity/data/repository/SearchRepositoryImpl.kt index 7e72b796..5381a14c 100644 --- a/app/src/main/java/com/kl3jvi/animity/data/repository/SearchRepositoryImpl.kt +++ b/app/src/main/java/com/kl3jvi/animity/data/repository/SearchRepositoryImpl.kt @@ -1,12 +1,15 @@ package com.kl3jvi.animity.data.repository +import androidx.paging.Pager +import androidx.paging.PagingConfig +import androidx.paging.PagingData +import com.kl3jvi.animity.data.paging.SearchPagingSource import com.kl3jvi.animity.data.model.AnimeMetaModel import com.kl3jvi.animity.data.network.AnimeApiClient import com.kl3jvi.animity.domain.repositories.SearchRepository -import com.kl3jvi.animity.utils.Constants.Companion.TYPE_SEARCH -import com.kl3jvi.animity.utils.parser.HtmlParser import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.withContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.flowOn import javax.inject.Inject import javax.inject.Singleton @@ -16,21 +19,19 @@ class SearchRepositoryImpl @Inject constructor( private val apiClient: AnimeApiClient, private val ioDispatcher: CoroutineDispatcher ) : SearchRepository { - override val parser: HtmlParser - get() = HtmlParser - override suspend fun fetchSearchData( + override fun fetchSearchData( header: Map, keyword: String, - page: Int - ): List = withContext(ioDispatcher) { - parser.parseMovie( - apiClient.fetchSearchData( - header = header, - keyword = keyword, - page = page - ).string(), - TYPE_SEARCH - ) + ): Flow> { + return Pager( + config = PagingConfig(enablePlaceholders = false, pageSize = NETWORK_PAGE_SIZE), + pagingSourceFactory = { SearchPagingSource(apiClient, keyword) } + ).flow.flowOn(ioDispatcher) } + + companion object { + const val NETWORK_PAGE_SIZE = 20 + } + } diff --git a/app/src/main/java/com/kl3jvi/animity/domain/repositories/PlayerRepository.kt b/app/src/main/java/com/kl3jvi/animity/domain/repositories/PlayerRepository.kt index 9f83ad30..5f3eb47e 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/repositories/PlayerRepository.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/repositories/PlayerRepository.kt @@ -6,6 +6,6 @@ import com.kl3jvi.animity.utils.parser.HtmlParser interface PlayerRepository { val parser: HtmlParser suspend fun fetchEpisodeMediaUrl(header: Map, url: String): EpisodeInfo - suspend fun fetchM3u8Url(header: Map, url: String):String + suspend fun fetchM3u8Url(header: Map, url: String):Pair,ArrayList> suspend fun fetchEncryptedAjaxUrl(header: Map, url: String):String } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/domain/repositories/SearchRepository.kt b/app/src/main/java/com/kl3jvi/animity/domain/repositories/SearchRepository.kt index 8b9d70cb..b30f1b7f 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/repositories/SearchRepository.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/repositories/SearchRepository.kt @@ -1,13 +1,13 @@ package com.kl3jvi.animity.domain.repositories +import androidx.paging.PagingData import com.kl3jvi.animity.data.model.AnimeMetaModel import com.kl3jvi.animity.utils.parser.HtmlParser +import kotlinx.coroutines.flow.Flow interface SearchRepository { - val parser: HtmlParser - suspend fun fetchSearchData( + fun fetchSearchData( header: Map, keyword: String, - page: Int - ): List + ): Flow> } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt index acb66c83..6c6f4e31 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetEpisodeInfoUseCase.kt @@ -1,7 +1,10 @@ package com.kl3jvi.animity.domain.use_cases +import android.util.Log import com.kl3jvi.animity.data.repository.PlayerRepositoryImpl import com.kl3jvi.animity.utils.Constants +import com.kl3jvi.animity.utils.Constants.Companion.REFERER +import com.kl3jvi.animity.utils.Constants.Companion.getNetworkHeader import com.kl3jvi.animity.utils.Resource import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.flow @@ -25,12 +28,28 @@ class GetEpisodeInfoUseCase @Inject constructor( }.flowOn(ioDispatcher) fun fetchM3U8(url: String?) = flow { + emit(Resource.Loading()) + try { + val response = playerRepository.fetchM3u8Url(getNetworkHeader(), url ?: "") + Log.e("respons'ua", response.toString()) + emit(Resource.Success(data = response.first.first())) + } catch (e: Exception) { + e.printStackTrace() + emit(Resource.Error("Couldn't find a Stream for this Anime")) + } + }.flowOn(ioDispatcher) + + fun fetchEncryptedAjaxUrl(url: String?) = flow { emit(Resource.Loading()) try { val response = playerRepository.fetchEncryptedAjaxUrl(Constants.getHeader(), url ?: "") - emit(Resource.Success(data = response)) + val streamUrl = "${REFERER}encrypt-ajax.php?${response}" + Log.e("Stream Url", streamUrl) + emit(Resource.Success(data = streamUrl)) } catch (e: Exception) { + e.printStackTrace() emit(Resource.Error("Couldn't find a Stream for this Anime")) } }.flowOn(ioDispatcher) + } diff --git a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetSearchResultUseCase.kt b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetSearchResultUseCase.kt index 22674369..0e8510db 100644 --- a/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetSearchResultUseCase.kt +++ b/app/src/main/java/com/kl3jvi/animity/domain/use_cases/GetSearchResultUseCase.kt @@ -1,13 +1,16 @@ package com.kl3jvi.animity.domain.use_cases +import androidx.paging.PagingData import com.kl3jvi.animity.data.model.AnimeMetaModel import com.kl3jvi.animity.data.repository.SearchRepositoryImpl +import com.kl3jvi.animity.domain.repositories.SearchRepository import com.kl3jvi.animity.utils.Constants import com.kl3jvi.animity.utils.Resource import kotlinx.coroutines.CoroutineDispatcher import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.flow import kotlinx.coroutines.flow.flowOn +import kotlinx.coroutines.flow.toList import retrofit2.HttpException import java.io.IOException import javax.inject.Inject @@ -15,38 +18,12 @@ import javax.inject.Singleton @Singleton class GetSearchResultUseCase @Inject constructor( - private val searchRepository: SearchRepositoryImpl, - private val ioDispatcher: CoroutineDispatcher + private val searchRepository: SearchRepositoryImpl ) { - operator fun invoke(searchQuery: String): Flow>> = - flow { - try { - emit(Resource.Loading()) - val response = searchRepository.fetchSearchData( - Constants.getHeader(), - searchQuery, - 1 - ).toList() - emit( - Resource.Success( - data = response - ) - ) - } catch (e: HttpException) { - emit( - Resource.Error( - message = e.localizedMessage ?: "An unexpected error occurred", - ) - ) - } catch (e: IOException) { - emit( - Resource.Error( - e.localizedMessage - ?: "Couldn't reach server. Check your internet connection.", - - ) - ) - } - }.flowOn(ioDispatcher) - + operator fun invoke(searchQuery: String): Flow>{ + return searchRepository.fetchSearchData( + Constants.getHeader(), + searchQuery + ) + } } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerActivity.kt b/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerActivity.kt index 809f7319..f920c2c4 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerActivity.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerActivity.kt @@ -21,7 +21,6 @@ import com.google.android.exoplayer2.trackselection.MappingTrackSelector import com.google.android.exoplayer2.ui.AspectRatioFrameLayout import com.google.android.exoplayer2.ui.TrackSelectionDialogBuilder import com.google.android.exoplayer2.upstream.DataSource -import com.google.android.exoplayer2.util.MimeTypes import com.google.android.exoplayer2.util.Util import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.ktx.analytics @@ -291,13 +290,12 @@ class PlayerActivity : AppCompatActivity() { e.printStackTrace() } viewBinding.loadingOverlay.visibility = View.GONE - - } - is Resource.Error -> { - } is Resource.Loading -> { - + viewBinding.loadingOverlay.visibility = View.VISIBLE + } + is Resource.Error -> { + showSnack(viewBinding.root, res.message) } } } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt index 20c8d975..06de1296 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/activities/player/PlayerViewModel.kt @@ -7,8 +7,7 @@ import com.google.android.exoplayer2.ExoPlayer import com.kl3jvi.animity.data.model.Content import com.kl3jvi.animity.domain.use_cases.GetEpisodeInfoUseCase import com.kl3jvi.animity.persistence.EpisodeDao -import com.kl3jvi.animity.utils.Constants -import com.kl3jvi.animity.utils.Constants.Companion.REFERER +import com.kl3jvi.animity.utils.parser.HtmlParser import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.ExperimentalCoroutinesApi @@ -20,24 +19,17 @@ import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel +@ExperimentalCoroutinesApi class PlayerViewModel @Inject constructor( private val getEpisodeInfoUseCase: GetEpisodeInfoUseCase, private val episodeDao: EpisodeDao, ) : ViewModel() { - private var _vidUrl = MutableLiveData() + private var _episodeUrl = MutableLiveData() private var _playBackPosition = MutableLiveData() fun updateEpisodeUrl(vidUrl: String) { - _vidUrl.value = vidUrl - Log.e("videoUrl",vidUrl) - } - - @ExperimentalCoroutinesApi - val videoUrlLiveData = Transformations.switchMap(_vidUrl) { url -> - getEpisodeInfoUseCase(url).flatMapLatest { episodeInfo -> - getEpisodeInfoUseCase.fetchM3U8("${REFERER}/encrypt-ajax.php?${episodeInfo.data?.vidCdnUrl}") - }.asLiveData() + _episodeUrl.value = vidUrl } fun audioProgress(exoPlayer: ExoPlayer?) = flow { @@ -49,6 +41,15 @@ class PlayerViewModel @Inject constructor( } }.flowOn(Dispatchers.Main).asLiveData(Dispatchers.IO + viewModelScope.coroutineContext) + val videoUrlLiveData = Transformations.switchMap(_episodeUrl) { url -> + getEpisodeInfoUseCase(url).flatMapLatest { episodeInfo -> + getEpisodeInfoUseCase.fetchEncryptedAjaxUrl(episodeInfo.data?.vidCdnUrl) + }.flatMapLatest { + Log.e("parsed url ->" , it.data.toString()) + getEpisodeInfoUseCase.fetchM3U8(it.data) + }.asLiveData() + } + fun insertOrUpdate(content: Content) { viewModelScope.launch { if (episodeDao.isEpisodeOnDatabase(content.episodeUrl) && content.watchedDuration > 0) { diff --git a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomSearchAdapter.kt b/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomSearchAdapter.kt index 68f4ffca..89f67782 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomSearchAdapter.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/adapters/CustomSearchAdapter.kt @@ -4,16 +4,14 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.navigation.findNavController +import androidx.paging.PagingDataAdapter import androidx.recyclerview.widget.DiffUtil -import androidx.recyclerview.widget.ListAdapter import androidx.recyclerview.widget.RecyclerView -import com.kl3jvi.animity.databinding.SearchLayoutBinding import com.kl3jvi.animity.data.model.AnimeMetaModel +import com.kl3jvi.animity.databinding.SearchLayoutBinding import com.kl3jvi.animity.ui.fragments.search.SearchFragmentDirections -class CustomSearchAdapter( - -) : ListAdapter( +class CustomSearchAdapter : PagingDataAdapter( AnimeDiffCallback() ) { @@ -51,10 +49,12 @@ class CustomSearchAdapter( return ViewHolder(binding) } - override fun onBindViewHolder(holder: ViewHolder, position: Int) = - holder.bindAnimeInfo(getItem(position)) - - override fun getItemCount(): Int = currentList.size + override fun onBindViewHolder(holder: ViewHolder, position: Int) { + val animeInfo = getItem(position) + if (animeInfo != null) { + holder.bindAnimeInfo(animeInfo) + } + } private class AnimeDiffCallback : DiffUtil.ItemCallback() { diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt index e3fd0769..4621eacf 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchFragment.kt @@ -6,6 +6,7 @@ import android.view.View import android.view.ViewGroup import androidx.appcompat.widget.SearchView import androidx.fragment.app.viewModels +import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.LinearLayoutManager import com.google.firebase.analytics.FirebaseAnalytics import com.google.firebase.analytics.ktx.analytics @@ -14,9 +15,12 @@ import com.kl3jvi.animity.databinding.FragmentSearchBinding import com.kl3jvi.animity.ui.activities.main.MainActivity import com.kl3jvi.animity.ui.adapters.CustomSearchAdapter import com.kl3jvi.animity.ui.base.BaseFragment -import com.kl3jvi.animity.utils.Constants.Companion.showSnack -import com.kl3jvi.animity.utils.Resource +import com.kl3jvi.animity.utils.ViewUtils.hide +import com.kl3jvi.animity.utils.ViewUtils.show import dagger.hilt.android.AndroidEntryPoint +import kotlinx.coroutines.Job +import kotlinx.coroutines.flow.collectLatest +import kotlinx.coroutines.launch @AndroidEntryPoint class SearchFragment : BaseFragment() { @@ -25,6 +29,7 @@ class SearchFragment : BaseFragment() { override val viewModel: SearchViewModel by viewModels() private lateinit var searchAdapter: CustomSearchAdapter private lateinit var firebaseAnalytics: FirebaseAnalytics + private var searchJob: Job? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -39,9 +44,7 @@ class SearchFragment : BaseFragment() { return binding.root } - override fun observeViewModel() { - getSearchData() - } + override fun observeViewModel() {} override fun initViews() { binding.apply { @@ -57,33 +60,13 @@ class SearchFragment : BaseFragment() { } override fun onQueryTextSubmit(query: String): Boolean { - viewModel.passQuery(query) + search(query) return false } }) } } - private fun getSearchData() { - viewModel.searchResult.observe(viewLifecycleOwner) { res -> - when (res) { - is Resource.Success -> { - binding.searchLoadingBar.visibility = View.GONE - binding.noSearchResult.visibility = View.GONE - binding.searchRecycler.visibility = View.VISIBLE - res.data?.let { searchAdapter.submitList(it) } - } - is Resource.Loading -> { - binding.searchRecycler.visibility = View.GONE - binding.searchLoadingBar.visibility = View.VISIBLE - binding.noSearchResult.visibility = View.VISIBLE - } - is Resource.Error -> { - showSnack(binding.root, res.message) - } - } - } - } override fun onResume() { super.onResume() @@ -95,4 +78,16 @@ class SearchFragment : BaseFragment() { override fun getViewBinding(): FragmentSearchBinding = FragmentSearchBinding.inflate(layoutInflater) + private fun search(query: String) { + // Make sure we cancel the previous job before creating a new one + searchJob?.cancel() + searchJob = lifecycleScope.launch { + viewModel.searchAnimes(query).collectLatest { animeData -> + binding.searchRecycler.show() + searchAdapter.submitData(animeData) + binding.noSearchResult.hide() + } + } + } + } diff --git a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt index ec70e74b..7596dff8 100644 --- a/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt +++ b/app/src/main/java/com/kl3jvi/animity/ui/fragments/search/SearchViewModel.kt @@ -1,13 +1,14 @@ package com.kl3jvi.animity.ui.fragments.search import androidx.lifecycle.* -import com.kl3jvi.animity.domain.use_cases.GetAnimeDetailsUseCase +import androidx.paging.PagingData +import androidx.paging.cachedIn +import com.kl3jvi.animity.data.model.AnimeMetaModel import com.kl3jvi.animity.domain.use_cases.GetSearchResultUseCase import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.CoroutineDispatcher -import kotlinx.coroutines.flow.flatMapConcat -import kotlinx.coroutines.flow.flatMapLatest -import kotlinx.coroutines.flow.onEach +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel @@ -16,14 +17,14 @@ class SearchViewModel @Inject constructor( private val ioDispatcher: CoroutineDispatcher ) : ViewModel() { - private val _query = MutableLiveData() - val searchResult = Transformations.switchMap(_query) { query -> - getSearchResultUseCase(query).asLiveData(ioDispatcher + viewModelScope.coroutineContext) - } - - + private var currentQueryValue: String? = null + private var currentSearchResult: Flow>? = null - fun passQuery(query: String) { - _query.value = query + fun searchAnimes(queryString: String): Flow> { + currentQueryValue = queryString + val newResult: Flow> = + getSearchResultUseCase(queryString).cachedIn(viewModelScope) + currentSearchResult = newResult + return newResult } } \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt b/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt index 50f5b39f..5f460493 100644 --- a/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt +++ b/app/src/main/java/com/kl3jvi/animity/utils/Constants.kt @@ -15,6 +15,7 @@ class Constants { const val EPISODE_DETAILS: String = "episodeInfo" const val DATABASE_NAME = "anime_database" const val SAVE_DIRECTORY = "Animity" + const val STARTING_PAGE_INDEX =1 // Base URLS var BASE_URL = "https://gogoanime.film" @@ -91,5 +92,10 @@ class Constants { snack.show() } } + + + fun getNetworkHeader(): Map{ + return mapOf("referer" to REFERER, "origin" to ORIGIN, "user-agent" to USER_AGENT) + } } } diff --git a/app/src/main/java/com/kl3jvi/animity/utils/ViewUtils.kt b/app/src/main/java/com/kl3jvi/animity/utils/ViewUtils.kt new file mode 100644 index 00000000..0949bd36 --- /dev/null +++ b/app/src/main/java/com/kl3jvi/animity/utils/ViewUtils.kt @@ -0,0 +1,15 @@ +package com.kl3jvi.animity.utils + +import android.view.View + +object ViewUtils { + + fun View.hide() { + visibility = View.GONE + } + + fun View.show() { + visibility = View.VISIBLE + } + +} \ No newline at end of file diff --git a/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt b/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt index a15f4ccd..aef771ef 100644 --- a/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt +++ b/app/src/main/java/com/kl3jvi/animity/utils/parser/HtmlParser.kt @@ -3,14 +3,12 @@ package com.kl3jvi.animity.utils.parser import android.os.Build import android.util.Log import com.kl3jvi.animity.data.model.* -import com.kl3jvi.animity.utils.Constants -import com.kl3jvi.animity.utils.Constants.Companion.M3U8_REGEX_PATTERN import org.apache.commons.lang3.RandomStringUtils +import org.json.JSONObject import org.jsoup.Jsoup import org.jsoup.select.Elements import java.net.URLDecoder import java.util.* -import java.util.regex.Pattern import javax.crypto.Cipher import javax.crypto.spec.IvParameterSpec import javax.crypto.spec.SecretKeySpec @@ -296,48 +294,23 @@ object HtmlParser { ) } - fun parseMirrorLink(response: String): String? { - var m3u8Url: String? = "" - val document = Jsoup.parse(response) - val info = document?.getElementsByClass("mirror_link") - val pattern = Pattern.compile(M3U8_REGEX_PATTERN) - val matcher = pattern.matcher(info.toString()) - return try { - while (matcher.find()) { - if (matcher.group(0)!!.contains("mp4")) { - m3u8Url = matcher.group(0) - } - break - } - m3u8Url - } catch (npe: NullPointerException) { - m3u8Url - } - } - - - fun parseM3U8Url(response: String): String? { - Log.e("Response e downloadit", response) - var m3u8Url: String? = "" - val document = Jsoup.parse(response) - val info = document?.getElementsByClass("videocontent") - val pattern = Pattern.compile(M3U8_REGEX_PATTERN) - val matcher = pattern.matcher(info.toString()) + fun parseEncryptedUrls(response: String): Pair, ArrayList> { + val urls: ArrayList = ArrayList() + val qualities: ArrayList = ArrayList() + var i = 0 + val res = JSONObject(response).getJSONArray("source") + Log.e("resu,", res.toString()) return try { - while (matcher.find()) { - if (matcher.group(0)!!.contains("m3u8") || matcher.group(0)!! - .contains("googlevideo") - ) { - m3u8Url = matcher.group(0) - break - } + while (i != res.length() && res.getJSONObject(i).getString("label") != "Auto") { + urls.add(res.getJSONObject(i).getString("file")) + qualities.add( + res.getJSONObject(i).getString("label").lowercase(Locale.getDefault()) + .filterNot { it.isWhitespace() }) + i++ } - Log.e("url", m3u8Url.toString()) - m3u8Url - } catch (npe: NullPointerException) { - Log.e("url", m3u8Url.toString()) - npe.printStackTrace() - m3u8Url + Pair(urls, qualities) + } catch (exp: java.lang.NullPointerException) { + Pair(urls, qualities) } } } diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index 13b99388..7818dd6e 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -63,14 +63,14 @@ android:paddingStart="10dp" android:paddingEnd="10dp" android:paddingBottom="5dp" - android:visibility="gone" + android:visibility="visible" tools:listitem="@layout/search_layout" />