From b1fb07f1e68df8b1c9afea472da23868fa734581 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nguy=E1=BB=85n=20=C4=90=E1=BB=A9c=20Tu=E1=BA=A5n=20Minh?= Date: Thu, 7 Sep 2023 11:09:22 +0700 Subject: [PATCH] Check for update done --- .../data/repository/MainRepository.kt | 22 ++++++++- .../com/maxrave/simpmusic/ui/MainActivity.kt | 38 +++++++++++++-- .../ui/fragment/home/SettingsFragment.kt | 39 +++++++++++++++ .../simpmusic/viewModel/SettingsViewModel.kt | 24 ++++++++++ .../simpmusic/viewModel/SharedViewModel.kt | 22 +++++++++ app/src/main/res/layout/fragment_settings.xml | 27 +++++++++++ app/src/main/res/values/strings.xml | 5 ++ .../maxrave/kotlinytmusicscraper/YouTube.kt | 12 ++++- .../maxrave/kotlinytmusicscraper/Ytmusic.kt | 25 ++++++++++ .../models/simpmusic/Asset.kt | 35 ++++++++++++++ .../models/simpmusic/Author.kt | 45 ++++++++++++++++++ .../models/simpmusic/GithubResponse.kt | 47 +++++++++++++++++++ .../models/simpmusic/Reactions.kt | 29 ++++++++++++ .../models/simpmusic/Uploader.kt | 45 ++++++++++++++++++ .../models/sponsorblock/SkipSegments.kt | 25 ++++++++++ 15 files changed, 434 insertions(+), 6 deletions(-) create mode 100644 kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Asset.kt create mode 100644 kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Author.kt create mode 100644 kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/GithubResponse.kt create mode 100644 kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Reactions.kt create mode 100644 kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Uploader.kt create mode 100644 kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/sponsorblock/SkipSegments.kt diff --git a/app/src/main/java/com/maxrave/simpmusic/data/repository/MainRepository.kt b/app/src/main/java/com/maxrave/simpmusic/data/repository/MainRepository.kt index b09fe2f1..80abab90 100644 --- a/app/src/main/java/com/maxrave/simpmusic/data/repository/MainRepository.kt +++ b/app/src/main/java/com/maxrave/simpmusic/data/repository/MainRepository.kt @@ -5,6 +5,8 @@ import android.util.Log import com.maxrave.kotlinytmusicscraper.YouTube import com.maxrave.kotlinytmusicscraper.models.MusicShelfRenderer import com.maxrave.kotlinytmusicscraper.models.response.PipedResponse +import com.maxrave.kotlinytmusicscraper.models.simpmusic.GithubResponse +import com.maxrave.kotlinytmusicscraper.models.sponsorblock.SkipSegments import com.maxrave.simpmusic.data.dataStore.DataStoreManager import com.maxrave.simpmusic.data.db.LocalDataSource import com.maxrave.simpmusic.data.db.entities.AlbumEntity @@ -637,7 +639,7 @@ class MainRepository @Inject constructor(private val localDataSource: LocalDataS runCatching { val q = query.replace(Regex("\\([^)]*?(feat.|ft.|cùng với|con)[^)]*?\\)"), "").replace(" ", " ") Log.d("Lyrics", "query: $q") - YouTube.authencation().onSuccess {token -> + YouTube.authentication().onSuccess { token -> if (token.accessToken != null) { YouTube.getSongId(token.accessToken!!, q).onSuccess { spotifyResult -> Log.d("SongId", "id: ${spotifyResult.tracks?.items?.get(0)?.id}") @@ -675,7 +677,7 @@ class MainRepository @Inject constructor(private val localDataSource: LocalDataS suspend fun getStream(videoId: String, itag: Int): Flow = flow{ val instance = runBlocking { dataStoreManager.pipedInstance.first() } YouTube.player(videoId, instance).onSuccess { response -> - val format = response.streamingData?.formats?.find { it.itag == itag} + val format = response.streamingData?.formats?.find { it.itag == itag} runBlocking { insertFormat( FormatEntity( @@ -699,6 +701,13 @@ class MainRepository @Inject constructor(private val localDataSource: LocalDataS emit(null) } }.flowOn(Dispatchers.IO) + suspend fun getSkipSegments(videoId: String): Flow?> = flow { + YouTube.getSkipSegments(videoId).onSuccess { + emit(it) + }.onFailure { + emit(null) + } + }.flowOn(Dispatchers.IO) fun getSongFull(videoId: String): Flow = flow { val instance = runBlocking { dataStoreManager.pipedInstance.first() } @@ -706,4 +715,13 @@ class MainRepository @Inject constructor(private val localDataSource: LocalDataS emit(it) } }.flowOn(Dispatchers.IO) + + fun checkForUpdate(): Flow = flow { + YouTube.checkForUpdate().onSuccess { + emit(it) + } + .onFailure { + emit(null) + } + } } \ No newline at end of file diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt b/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt index 774692f9..4107f385 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/MainActivity.kt @@ -8,7 +8,7 @@ import android.graphics.drawable.GradientDrawable import android.net.Uri import android.os.Build import android.os.Bundle -import android.provider.ContactsContract.Data +import android.text.Html import android.util.Log import android.view.View import android.view.animation.AnimationUtils @@ -27,7 +27,6 @@ import androidx.lifecycle.repeatOnLifecycle import androidx.lifecycle.switchMap import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.offline.DownloadService -import androidx.navigation.NavController import androidx.navigation.fragment.findNavController import androidx.navigation.ui.setupWithNavController import androidx.palette.graphics.Palette @@ -36,6 +35,7 @@ import coil.request.ImageRequest import coil.size.Size import coil.transform.Transformation import com.daimajia.swipe.SwipeLayout +import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.maxrave.kotlinytmusicscraper.YouTube import com.maxrave.kotlinytmusicscraper.models.YouTubeLocale import com.maxrave.simpmusic.R @@ -50,7 +50,6 @@ import com.maxrave.simpmusic.data.dataStore.DataStoreManager.Settings.RESTORE_LA import com.maxrave.simpmusic.data.model.browse.album.Track import com.maxrave.simpmusic.data.queue.Queue import com.maxrave.simpmusic.databinding.ActivityMainBinding -import com.maxrave.simpmusic.extension.dataStore import com.maxrave.simpmusic.extension.isMyServiceRunning import com.maxrave.simpmusic.extension.toTrack import com.maxrave.simpmusic.service.SimpleMediaService @@ -65,6 +64,7 @@ import kotlinx.coroutines.flow.collectLatest import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import pub.devrel.easypermissions.EasyPermissions +import java.text.SimpleDateFormat import java.util.Locale import javax.inject.Inject @@ -473,9 +473,13 @@ class MainActivity : AppCompatActivity() { ) ) } + checkForUpdate() } } } + else { + checkForUpdate() + } } override fun onDestroy() { @@ -559,6 +563,34 @@ class MainActivity : AppCompatActivity() { binding.miniPlayerContainer.visibility = View.VISIBLE } + private fun checkForUpdate() { + viewModel.checkForUpdate() + viewModel.githubResponse.observe(this) {response -> + if (response != null) { + if (response.tagName != getString(R.string.version_name)) { + val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()) + val outputFormat = SimpleDateFormat("dd MMM yyyy HH:mm:ss", Locale.getDefault()) + val formatted = response.publishedAt?.let { input -> + inputFormat.parse(input) + ?.let { outputFormat.format(it) } + } + + MaterialAlertDialogBuilder(this) + .setTitle(getString(R.string.update_available)) + .setMessage(getString(R.string.update_message, response.tagName, formatted, Html.fromHtml(response.body, Html.FROM_HTML_MODE_COMPACT))) + .setPositiveButton(getString(R.string.download)) { _, _ -> + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(response.assets?.firstOrNull()?.browserDownloadUrl)) + startActivity(browserIntent) + } + .setNegativeButton(getString(R.string.cancel)) { dialog, _ -> + dialog.dismiss() + } + .show() + } + } + } + } + private fun putString(key: String, value: String) { viewModel.putString(key, value) } diff --git a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/home/SettingsFragment.kt b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/home/SettingsFragment.kt index 19d317e7..7e1ba9f2 100644 --- a/app/src/main/java/com/maxrave/simpmusic/ui/fragment/home/SettingsFragment.kt +++ b/app/src/main/java/com/maxrave/simpmusic/ui/fragment/home/SettingsFragment.kt @@ -4,6 +4,7 @@ import android.content.Intent import android.media.audiofx.AudioEffect import android.net.Uri import android.os.Bundle +import android.text.Html import android.util.Log import android.view.LayoutInflater import android.view.View @@ -30,8 +31,12 @@ import com.maxrave.simpmusic.databinding.FragmentSettingsBinding import com.maxrave.simpmusic.viewModel.SettingsViewModel import dagger.hilt.android.AndroidEntryPoint import dev.chrisbanes.insetter.applyInsetter +import java.text.SimpleDateFormat +import java.time.Instant import java.time.LocalDateTime +import java.time.ZoneId import java.time.format.DateTimeFormatter +import java.util.Locale import javax.inject.Inject @UnstableApi @@ -101,6 +106,7 @@ class SettingsFragment : Fragment() { viewModel.getSavedPlaybackState() viewModel.getPipedInstance() viewModel.getSaveRecentSongAndQueue() + viewModel.getLastCheckForUpdate() val diskCache = context?.imageLoader?.diskCache @@ -152,6 +158,39 @@ class SettingsFragment : Fragment() { viewModel.pipedInstance.observe(viewLifecycleOwner) { binding.tvPipedInstance.text = it } + viewModel.lastCheckForUpdate.observe(viewLifecycleOwner) { + binding.tvCheckForUpdate.text = getString(R.string.last_checked_at, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) + .format(Instant.ofEpochMilli(it.toLong()))) + } + binding.btCheckForUpdate.setOnClickListener { + binding.tvCheckForUpdate.text = getString(R.string.checking) + viewModel.checkForUpdate() + viewModel.githubResponse.observe(viewLifecycleOwner) {response -> + if (it != null) { + binding.tvCheckForUpdate.text = getString(R.string.last_checked_at, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss") + .withZone(ZoneId.systemDefault()) + .format(Instant.ofEpochMilli(System.currentTimeMillis()))) + val inputFormat = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.getDefault()) + val outputFormat = SimpleDateFormat("dd MMM yyyy HH:mm:ss", Locale.getDefault()) + val formatted = response.publishedAt?.let { input -> + inputFormat.parse(input) + ?.let { outputFormat.format(it) } + } + MaterialAlertDialogBuilder(requireContext()) + .setTitle(getString(R.string.update_available)) + .setMessage(getString(R.string.update_message, response.tagName, formatted, Html.fromHtml(response.body, Html.FROM_HTML_MODE_COMPACT))) + .setPositiveButton(getString(R.string.download)) { _, _ -> + val browserIntent = Intent(Intent.ACTION_VIEW, Uri.parse(response.assets?.firstOrNull()?.browserDownloadUrl)) + startActivity(browserIntent) + } + .setNegativeButton(getString(R.string.cancel)) { dialog, _ -> + dialog.dismiss() + } + .show() + } + } + } binding.btVersion.setOnClickListener { val urlIntent = Intent( diff --git a/app/src/main/java/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt b/app/src/main/java/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt index cb6dbaeb..cdea24df 100644 --- a/app/src/main/java/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt +++ b/app/src/main/java/com/maxrave/simpmusic/viewModel/SettingsViewModel.kt @@ -13,6 +13,7 @@ import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.cache.SimpleCache import com.maxrave.kotlinytmusicscraper.YouTube import com.maxrave.kotlinytmusicscraper.models.YouTubeLocale +import com.maxrave.kotlinytmusicscraper.models.simpmusic.GithubResponse import com.maxrave.simpmusic.R import com.maxrave.simpmusic.common.DB_NAME import com.maxrave.simpmusic.common.DownloadState @@ -31,6 +32,7 @@ import com.maxrave.simpmusic.service.SimpleMediaServiceHandler import com.maxrave.simpmusic.ui.MainActivity import dagger.hilt.android.lifecycle.HiltViewModel import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.flow.first import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withContext @@ -70,6 +72,19 @@ class SettingsViewModel @Inject constructor( val savedPlaybackState: LiveData = _savedPlaybackState private var _saveRecentSongAndQueue: MutableLiveData = MutableLiveData() val saveRecentSongAndQueue: LiveData = _saveRecentSongAndQueue + private var _lastCheckForUpdate: MutableLiveData = MutableLiveData() + val lastCheckForUpdate: LiveData = _lastCheckForUpdate + private var _githubResponse = MutableLiveData() + val githubResponse: LiveData = _githubResponse + + fun checkForUpdate() { + viewModelScope.launch { + mainRepository.checkForUpdate().collect {response -> + dataStoreManager.putString("CheckForUpdateAt", System.currentTimeMillis().toString()) + _githubResponse.postValue(response) + } + } + } fun getLocation() { viewModelScope.launch { @@ -108,6 +123,15 @@ class SettingsViewModel @Inject constructor( } } } + fun getLastCheckForUpdate() { + viewModelScope.launch { + withContext(Dispatchers.Main) { + dataStoreManager.getString("CheckForUpdateAt").first().let { lastCheckForUpdate -> + _lastCheckForUpdate.postValue(lastCheckForUpdate) + } + } + } + } private var _quality: MutableLiveData = MutableLiveData() val quality: LiveData = _quality diff --git a/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt b/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt index c35332e9..4b4d5e14 100644 --- a/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt +++ b/app/src/main/java/com/maxrave/simpmusic/viewModel/SharedViewModel.kt @@ -18,6 +18,7 @@ import androidx.media3.datasource.cache.SimpleCache import androidx.media3.exoplayer.offline.Download import com.maxrave.kotlinytmusicscraper.YouTube import com.maxrave.kotlinytmusicscraper.models.response.PipedResponse +import com.maxrave.kotlinytmusicscraper.models.simpmusic.GithubResponse import com.maxrave.simpmusic.R import com.maxrave.simpmusic.common.Config import com.maxrave.simpmusic.common.DownloadState @@ -206,6 +207,7 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor simpleMediaServiceHandler.nowPlaying.collectLatest { nowPlaying -> if (nowPlaying != null && getCurrentMediaItemIndex() > 0) { _nowPlayingMediaItem.postValue(nowPlaying) + getSkipSegments(nowPlaying.mediaId) var downloaded = false val tempSong = musicSource.catalogMetadata[getCurrentMediaItemIndex()] Log.d("Check tempSong", tempSong.toString()) @@ -371,6 +373,15 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor mainRepository.insertLyrics(lyrics) } } + fun getSkipSegments(videoId: String) { + viewModelScope.launch { + mainRepository.getSkipSegments(videoId).collect { segments -> + if (segments != null) { + Log.w("Check segments ${videoId}", segments.toString()) + } + } + } + } fun getSavedLyrics(videoId: String, query: String) { viewModelScope.launch { resetLyrics() @@ -900,6 +911,17 @@ class SharedViewModel @Inject constructor(private var dataStoreManager: DataStor mainRepository.removeQueue() } } + private var _githubResponse = MutableLiveData() + val githubResponse: LiveData = _githubResponse + + fun checkForUpdate() { + viewModelScope.launch { + mainRepository.checkForUpdate().collect {response -> + dataStoreManager.putString("CheckForUpdateAt", System.currentTimeMillis().toString()) + _githubResponse.postValue(response) + } + } + } } sealed class UIEvent { data object PlayPause : UIEvent() diff --git a/app/src/main/res/layout/fragment_settings.xml b/app/src/main/res/layout/fragment_settings.xml index 8f4c9ff3..b50cf797 100644 --- a/app/src/main/res/layout/fragment_settings.xml +++ b/app/src/main/res/layout/fragment_settings.xml @@ -595,6 +595,33 @@ + + + + + + + + Time out, check internet connection or change Piped instance in Settings Save Last Played Save last played track and queue + New update available + "Version %1$s available\nRelease: %2$s\nChange logs:\n%3$s " + Check for update + Last checked at %1$s + Checking %d song %d songs diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/YouTube.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/YouTube.kt index a69246e7..ee6d0ef9 100644 --- a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/YouTube.kt +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/YouTube.kt @@ -26,7 +26,9 @@ import com.maxrave.kotlinytmusicscraper.models.response.NextResponse import com.maxrave.kotlinytmusicscraper.models.response.PipedResponse import com.maxrave.kotlinytmusicscraper.models.response.PlayerResponse import com.maxrave.kotlinytmusicscraper.models.response.SearchResponse +import com.maxrave.kotlinytmusicscraper.models.simpmusic.GithubResponse import com.maxrave.kotlinytmusicscraper.models.splitBySeparator +import com.maxrave.kotlinytmusicscraper.models.sponsorblock.SkipSegments import com.maxrave.kotlinytmusicscraper.models.spotify.SpotifyResult import com.maxrave.kotlinytmusicscraper.models.spotify.Token import com.maxrave.kotlinytmusicscraper.pages.AlbumPage @@ -225,7 +227,7 @@ object YouTube { suspend fun getLyrics(songId: String) = runCatching { ytMusic.getLyrics(songId).body() } - suspend fun authencation() = runCatching { + suspend fun authentication() = runCatching { ytMusic.authorizationSpotify().body() } suspend fun getSongId(authorization: String, query: String) = runCatching { @@ -246,6 +248,14 @@ object YouTube { return@runCatching listSuggest } + suspend fun getSkipSegments(videoId: String) = runCatching { + ytMusic.getSkipSegments(videoId).body>() + } + + suspend fun checkForUpdate() = runCatching { + ytMusic.checkForUpdate().body() + } + suspend fun explore(): Result = runCatching { val response = ytMusic.browse(WEB_REMIX, browseId = "FEmusic_explore").body() ExplorePage( diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/Ytmusic.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/Ytmusic.kt index 9e27b704..76ad02ca 100644 --- a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/Ytmusic.kt +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/Ytmusic.kt @@ -192,6 +192,31 @@ class Ytmusic { parameter("q", query) } + /*** + * SponsorBlock testing + * @author maxrave-dev + */ + + suspend fun getSkipSegments(videoId: String) = + httpClient.get("https://sponsor.ajay.app/api/skipSegments/") { + contentType(ContentType.Application.Json) + parameter("videoID", videoId) + parameter("category", "sponsor") + parameter("category", "selfpromo") + parameter("category", "interaction") + parameter("category", "intro") + parameter("category", "outro") + parameter("category", "preview") + parameter("category", "music_offtopic") + parameter("category", "poi_highlight") + parameter("category", "filler") + parameter("service", "YouTube") + } + + suspend fun checkForUpdate() = httpClient.get("https://api.github.com/repos/maxrave-dev/SimpMusic/releases/latest") { + contentType(ContentType.Application.Json) + } + suspend fun browse( client: YouTubeClient, browseId: String? = null, diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Asset.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Asset.kt new file mode 100644 index 00000000..81a4c266 --- /dev/null +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Asset.kt @@ -0,0 +1,35 @@ +package com.maxrave.kotlinytmusicscraper.models.simpmusic + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Asset( + @SerialName("browser_download_url") + val browserDownloadUrl: String?, + @SerialName("content_type") + val contentType: String?, + @SerialName("created_at") + val createdAt: String?, + @SerialName("download_count") + val downloadCount: Int?, + @SerialName("id") + val id: Int?, + @SerialName("label") + val label: String?, + @SerialName("name") + val name: String?, + @SerialName("node_id") + val nodeId: String?, + @SerialName("size") + val size: Int?, + @SerialName("state") + val state: String?, + @SerialName("updated_at") + val updatedAt: String?, + @SerialName("uploader") + val uploader: Uploader?, + @SerialName("url") + val url: String? +) \ No newline at end of file diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Author.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Author.kt new file mode 100644 index 00000000..219c46c9 --- /dev/null +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Author.kt @@ -0,0 +1,45 @@ +package com.maxrave.kotlinytmusicscraper.models.simpmusic + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Author( + @SerialName("avatar_url") + val avatarUrl: String?, + @SerialName("events_url") + val eventsUrl: String?, + @SerialName("followers_url") + val followersUrl: String?, + @SerialName("following_url") + val followingUrl: String?, + @SerialName("gists_url") + val gistsUrl: String?, + @SerialName("gravatar_id") + val gravatarId: String?, + @SerialName("html_url") + val htmlUrl: String?, + @SerialName("id") + val id: Int?, + @SerialName("login") + val login: String?, + @SerialName("node_id") + val nodeId: String?, + @SerialName("organizations_url") + val organizationsUrl: String?, + @SerialName("received_events_url") + val receivedEventsUrl: String?, + @SerialName("repos_url") + val reposUrl: String?, + @SerialName("site_admin") + val siteAdmin: Boolean?, + @SerialName("starred_url") + val starredUrl: String?, + @SerialName("subscriptions_url") + val subscriptionsUrl: String?, + @SerialName("type") + val type: String?, + @SerialName("url") + val url: String? +) \ No newline at end of file diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/GithubResponse.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/GithubResponse.kt new file mode 100644 index 00000000..730aeb2f --- /dev/null +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/GithubResponse.kt @@ -0,0 +1,47 @@ +package com.maxrave.kotlinytmusicscraper.models.simpmusic + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class GithubResponse( + @SerialName("assets") + val assets: List?, + @SerialName("assets_url") + val assetsUrl: String?, + @SerialName("author") + val author: Author?, + @SerialName("body") + val body: String?, + @SerialName("created_at") + val createdAt: String?, + @SerialName("draft") + val draft: Boolean?, + @SerialName("html_url") + val htmlUrl: String?, + @SerialName("id") + val id: Int?, + @SerialName("name") + val name: String?, + @SerialName("node_id") + val nodeId: String?, + @SerialName("prerelease") + val prerelease: Boolean?, + @SerialName("published_at") + val publishedAt: String?, + @SerialName("reactions") + val reactions: Reactions?, + @SerialName("tag_name") + val tagName: String?, + @SerialName("tarball_url") + val tarballUrl: String?, + @SerialName("target_commitish") + val targetCommitish: String?, + @SerialName("upload_url") + val uploadUrl: String?, + @SerialName("url") + val url: String?, + @SerialName("zipball_url") + val zipballUrl: String? +) \ No newline at end of file diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Reactions.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Reactions.kt new file mode 100644 index 00000000..a156e8d8 --- /dev/null +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Reactions.kt @@ -0,0 +1,29 @@ +package com.maxrave.kotlinytmusicscraper.models.simpmusic + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Reactions( + @SerialName("confused") + val confused: Int?, + @SerialName("eyes") + val eyes: Int?, + @SerialName("heart") + val heart: Int?, + @SerialName("hooray") + val hooray: Int?, + @SerialName("laugh") + val laugh: Int?, + @SerialName("rocket") + val rocket: Int?, + @SerialName("total_count") + val totalCount: Int?, + @SerialName("url") + val url: String?, + @SerialName("+1") + val x1: Int?, + @SerialName("-1") + val x2: Int? +) \ No newline at end of file diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Uploader.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Uploader.kt new file mode 100644 index 00000000..01ac2dca --- /dev/null +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/simpmusic/Uploader.kt @@ -0,0 +1,45 @@ +package com.maxrave.kotlinytmusicscraper.models.simpmusic + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class Uploader( + @SerialName("avatar_url") + val avatarUrl: String?, + @SerialName("events_url") + val eventsUrl: String?, + @SerialName("followers_url") + val followersUrl: String?, + @SerialName("following_url") + val followingUrl: String?, + @SerialName("gists_url") + val gistsUrl: String?, + @SerialName("gravatar_id") + val gravatarId: String?, + @SerialName("html_url") + val htmlUrl: String?, + @SerialName("id") + val id: Int?, + @SerialName("login") + val login: String?, + @SerialName("node_id") + val nodeId: String?, + @SerialName("organizations_url") + val organizationsUrl: String?, + @SerialName("received_events_url") + val receivedEventsUrl: String?, + @SerialName("repos_url") + val reposUrl: String?, + @SerialName("site_admin") + val siteAdmin: Boolean?, + @SerialName("starred_url") + val starredUrl: String?, + @SerialName("subscriptions_url") + val subscriptionsUrl: String?, + @SerialName("type") + val type: String?, + @SerialName("url") + val url: String? +) \ No newline at end of file diff --git a/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/sponsorblock/SkipSegments.kt b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/sponsorblock/SkipSegments.kt new file mode 100644 index 00000000..7be116dc --- /dev/null +++ b/kotlinYtmusicScraper/src/main/java/com/maxrave/kotlinytmusicscraper/models/sponsorblock/SkipSegments.kt @@ -0,0 +1,25 @@ +package com.maxrave.kotlinytmusicscraper.models.sponsorblock + + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable + +@Serializable +data class SkipSegments( + @SerialName("actionType") + val actionType: String, + @SerialName("category") + val category: String, + @SerialName("description") + val description: String, + @SerialName("locked") + val locked: Int, + @SerialName("segment") + val segment: List, + @SerialName("UUID") + val uUID: String, + @SerialName("videoDuration") + val videoDuration: Double, + @SerialName("votes") + val votes: Int +) \ No newline at end of file