diff --git a/.idea/deploymentTargetDropDown.xml b/.idea/deploymentTargetDropDown.xml
index 12b9340..5380a26 100644
--- a/.idea/deploymentTargetDropDown.xml
+++ b/.idea/deploymentTargetDropDown.xml
@@ -1,17 +1,17 @@
-
+
-
+
-
-
+
+
-
-
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
index 94a25f7..a854d63 100644
--- a/.idea/vcs.xml
+++ b/.idea/vcs.xml
@@ -2,5 +2,6 @@
+
\ No newline at end of file
diff --git a/app/build.gradle b/app/build.gradle
index 7d86d07..d5bf187 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -87,8 +87,8 @@ dependencies {
//YoutubeDl
- implementation 'com.github.yausername.youtubedl-android:library:-SNAPSHOT'
- implementation 'com.github.yausername.youtubedl-android:ffmpeg:-SNAPSHOT' // Optional
+ implementation "com.github.yausername.youtubedl-android:library:3a0252d88b4ae573068c63c3d08fc52c66102d55"
+ implementation "com.github.yausername.youtubedl-android:ffmpeg:3a0252d88b4ae573068c63c3d08fc52c66102d55"
//Coroutines
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.6.4'
@@ -105,6 +105,8 @@ dependencies {
implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
implementation "androidx.navigation:navigation-dynamic-features-fragment:$nav_version"
+ implementation "io.coil-kt:coil:2.3.0"
+
}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/spotifydownloader/Application.kt b/app/src/main/java/com/example/spotifydownloader/Application.kt
index 8070ac6..fd70613 100644
--- a/app/src/main/java/com/example/spotifydownloader/Application.kt
+++ b/app/src/main/java/com/example/spotifydownloader/Application.kt
@@ -27,7 +27,13 @@ class SpotifyDownloaderApplication : Application(){
YoutubeDL.getInstance().updateYoutubeDL(applicationContext)
}
} catch (e: Exception) {
- Toast.makeText(applicationContext, "Download Library Initialization Failed", Toast.LENGTH_LONG).show()
+ withContext(Dispatchers.Main) {
+ Toast.makeText(
+ applicationContext,
+ "Download Library Initialization Failed",
+ Toast.LENGTH_LONG
+ ).show()
+ }
}
if (!Python.isStarted()) {
Python.start(AndroidPlatform(this@SpotifyDownloaderApplication))
diff --git a/app/src/main/java/com/example/spotifydownloader/MainActivity.kt b/app/src/main/java/com/example/spotifydownloader/MainActivity.kt
index ba22768..40187cd 100644
--- a/app/src/main/java/com/example/spotifydownloader/MainActivity.kt
+++ b/app/src/main/java/com/example/spotifydownloader/MainActivity.kt
@@ -93,6 +93,12 @@ class MainActivity : AppCompatActivity() {
}
+
+
+
+
+
+
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (toggle.onOptionsItemSelected(item)) {
return true
diff --git a/app/src/main/java/com/example/spotifydownloader/downloadFragment.kt b/app/src/main/java/com/example/spotifydownloader/downloadFragment.kt
index 11993b5..18fd342 100644
--- a/app/src/main/java/com/example/spotifydownloader/downloadFragment.kt
+++ b/app/src/main/java/com/example/spotifydownloader/downloadFragment.kt
@@ -17,17 +17,23 @@ import androidx.activity.OnBackPressedCallback
import androidx.core.view.forEach
import androidx.documentfile.provider.DocumentFile
import androidx.fragment.app.Fragment
+import androidx.lifecycle.lifecycleScope
import androidx.navigation.NavController
import androidx.navigation.Navigation
import androidx.navigation.fragment.navArgs
+import androidx.recyclerview.widget.LinearLayoutManager
import com.chaquo.python.PyObject
import com.chaquo.python.Python
import com.chaquo.python.android.AndroidPlatform
import com.example.spotifydownloader.databinding.FragmentDownloadBinding
+import com.example.spotifydownloader.model.recyclerViewAdaptor
+import com.example.spotifydownloader.model.songItemData
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.yausername.youtubedl_android.YoutubeDL
import com.yausername.youtubedl_android.YoutubeDLException
import com.yausername.youtubedl_android.YoutubeDLRequest
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.launch
import org.apache.commons.io.IOUtils
import java.io.File
import java.util.concurrent.Executors
@@ -41,7 +47,11 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
private val args by navArgs()
private lateinit var module:PyObject
private var stop = false
+ private var songItems = mutableListOf()
+ private var completed = 0
+ private var index = 0
+ private val adapter = recyclerViewAdaptor(songItems)
override fun onDestroy() {
super.onDestroy()
@@ -51,13 +61,17 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ Log.d(tag,completed.toString())
+ binding = FragmentDownloadBinding.bind(view)
if (! Python.isStarted()) {
Python.start( AndroidPlatform(context as Activity))
}
+ binding.recyclerView.adapter = adapter
+ binding.recyclerView.layoutManager = LinearLayoutManager(context)
+
- binding = FragmentDownloadBinding.bind(view)
navController =Navigation.findNavController(view)
val py = Python.getInstance()
module = py.getModule("main")
@@ -73,10 +87,15 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
}
- binding.cancelBtn.setOnClickListener {
+
+
+
+
+
+ binding.fabButton.setOnClickListener {
stop = true
Toast.makeText((context as Activity),"Stopping...",Toast.LENGTH_SHORT).show()
- binding.cancelBtn.isEnabled = false
+ binding.fabButton.isEnabled = false
}
@@ -93,9 +112,6 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
-
- binding.progressBar.progress = 0
-
if (isDeviceOnline(context as Activity)){
val concurrentThreads = args.Data.concurrentDownloads
@@ -103,7 +119,9 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
val songNamesSize = args.Data.songNames.size
- binding.progressBar.max = songNamesSize
+
+
+
for (i in args.Data.songNames as MutableList) {
@@ -119,8 +137,9 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
when (download(songName, args.Data.folderURI)) {
0 -> {
+ Log.d(tag,"$completed")
- if (songNamesSize == binding.progressBar.progress) {
+ if (songNamesSize == completed) {
runOnUiThread {
Toast.makeText(
context as Activity,
@@ -160,7 +179,8 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
}
}
2 -> {
- if (songNamesSize == binding.progressBar.progress) {
+ Log.d(tag,"Completed $completed")
+ if (songNamesSize == completed) {
runOnUiThread {
Toast.makeText(
context as Activity,
@@ -264,7 +284,22 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
val filename = videoInfo[0].toString()
val ytLInk = videoInfo[1].toString()
- val code = videoInfo[2].toInt()
+ val imgUrl = videoInfo[2].toString()
+ val code = videoInfo[3].toInt()
+ val artistName = videoInfo[4].toString()
+ val trackName = videoInfo[5].toString()
+
+ val songData = songItemData(imgUrl,trackName,artistName,0)
+ songItems.add(songData)
+ val position = index
+ runOnUiThread {
+ adapter.notifyItemInserted(index)
+ binding.recyclerView.scrollToPosition(position)
+ }
+ index += 1
+
+
+
if (code == 0) {
try {
@@ -283,11 +318,38 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
val documentFIle: DocumentFile =
DocumentFile.fromTreeUri((context as Activity), data!!)!!
val dc: DocumentFile? = documentFIle.findFile(filename)
+
+
+
+
+
+
+
+
+
if (isDeviceOnline(context as Activity) && dc?.exists() == null) {
try {
+
+
+
+
+
+
YoutubeDL.getInstance().execute(
request
- ) { _: Float, _: Long, _: String? -> }
+ ) { progress: Float, _: Long, _: String? ->
+ //Log.d(tag,"Progress is $progress and the song is $songName")
+ if (progress >0){
+ songItems[position].progress = progress.toInt()
+ runOnUiThread {
+ adapter.notifyItemChanged(position)
+ }
+
+ }
+
+
+
+ }
} catch (e: YoutubeDLException) {
Log.e(tag, e.message!!)
@@ -332,11 +394,18 @@ class downloadFragment : Fragment(R.layout.fragment_download) {
} else {
Log.d(tag, "Already exists skipping")
tmpFile.deleteRecursively()
- binding.progressBar.incrementProgressBy(1)
+ songItems[position].progress = 100
+ runOnUiThread {
+ adapter.notifyItemChanged(position)
+ }
+ //binding.progressBar.incrementProgressBy(1)
+ completed += 1
return 2
}
Log.d(tag, "No errors")
- binding.progressBar.incrementProgressBy(1)
+ //binding.progressBar.incrementProgressBy(1)
+ completed += 1
+
tmpFile.deleteRecursively()
return 0
} catch (e: java.lang.NullPointerException) {
diff --git a/app/src/main/java/com/example/spotifydownloader/model/recyclerViewAdaptor.kt b/app/src/main/java/com/example/spotifydownloader/model/recyclerViewAdaptor.kt
new file mode 100644
index 0000000..9d8d3bc
--- /dev/null
+++ b/app/src/main/java/com/example/spotifydownloader/model/recyclerViewAdaptor.kt
@@ -0,0 +1,56 @@
+package com.example.spotifydownloader.model
+
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.ProgressBar
+import android.widget.TextView
+import androidx.recyclerview.widget.RecyclerView
+import coil.load
+import com.example.spotifydownloader.R
+
+class recyclerViewAdaptor (private val songData: List)
+ :RecyclerView.Adapter() {
+
+
+
+
+ class ViewHolder(ItemView: View):RecyclerView.ViewHolder(ItemView){
+ val songCoverImage: ImageView = itemView.findViewById(R.id.songCoverImage)
+ val songTitle : TextView = itemView.findViewById(R.id.songTitle)
+ val artistName : TextView = itemView.findViewById(R.id.artistName)
+ val progressBar : ProgressBar = itemView.findViewById(R.id.progressBar)
+
+
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
+ val view = LayoutInflater.from(parent.context).inflate(R.layout.song_item,parent,false)
+ return ViewHolder(view)
+ }
+
+ override fun getItemCount(): Int {
+ return songData.size
+ }
+
+ override fun onBindViewHolder(holder: ViewHolder, position: Int) {
+ val recyclerViewAdaptor = songData[position]
+
+ holder.songCoverImage.load(recyclerViewAdaptor.imageUrl)
+
+
+ if (recyclerViewAdaptor.songName.length>19) {
+ holder.songTitle.text = recyclerViewAdaptor.songName.take(17).plus("...")
+ }
+ else{
+ holder.songTitle.text = recyclerViewAdaptor.songName
+ }
+ holder.artistName.text = recyclerViewAdaptor.artistName
+ holder.progressBar.progress = recyclerViewAdaptor.progress
+
+
+ }
+
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/example/spotifydownloader/model/songItemData.kt b/app/src/main/java/com/example/spotifydownloader/model/songItemData.kt
new file mode 100644
index 0000000..ecabb36
--- /dev/null
+++ b/app/src/main/java/com/example/spotifydownloader/model/songItemData.kt
@@ -0,0 +1,8 @@
+package com.example.spotifydownloader.model
+
+import android.graphics.Bitmap
+
+data class songItemData(val imageUrl : String,
+ val songName: String,
+ val artistName:String,
+ var progress:Int)
diff --git a/app/src/main/python/main.py b/app/src/main/python/main.py
index a9184b4..8cc1437 100644
--- a/app/src/main/python/main.py
+++ b/app/src/main/python/main.py
@@ -101,23 +101,34 @@ def songSearchSpotifyAlbum(albumLink):
def getDownloadPath(songs):
fileName = ""
songUrl=""
+ imgUrl=""
+ songName =""
+ artistName=""
+ albumUrl=""
+ songName=""
try:
+ tracks = sp.search(songs)
+ albumUrl = tracks['tracks']['items'][0]['album']['images'][1]['url']
songSearch = VideosSearch(songs, limit=1).result()
+ artistName = tracks['tracks']['items'][0]['artists'][0]['name']
+ songName = tracks['tracks']['items'][0]['name']
+
+
try:
songId = songSearch['result'][0]['id']
except(IndexError):
- return fileName,songUrl,2
+ return fileName,songUrl,albumUrl,2,artistName,songName
songUrl= "https://youtu.be/"+songId
songTitle = songSearch['result'][0]['title']
translation_table = str.maketrans('', '', string.punctuation)
safeString = songTitle.translate(translation_table)
fileName = safeString.replace(" ", "") + ".mp3"
except(httpx.ConnectError, ChunkedEncodingError, ReadError):
- return fileName,songUrl,1
- return fileName,songUrl,0
+ return fileName,songUrl,albumUrl,1,songName,artistName,songName
+ return fileName,songUrl,albumUrl,0,artistName,songName
def insertMetaData(songs,fileLocation):
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 6f4f1cc..e703154 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -14,15 +14,15 @@
diff --git a/app/src/main/res/layout/fragment_download.xml b/app/src/main/res/layout/fragment_download.xml
index e11805e..beb2006 100644
--- a/app/src/main/res/layout/fragment_download.xml
+++ b/app/src/main/res/layout/fragment_download.xml
@@ -7,22 +7,23 @@
tools:context=".downloadFragment">
-
-
+ android:text="Cancel"
+ app:layout_constraintBottom_toBottomOf="parent"
+ app:layout_constraintEnd_toEndOf="parent" />
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/song_item.xml b/app/src/main/res/layout/song_item.xml
new file mode 100644
index 0000000..86f465c
--- /dev/null
+++ b/app/src/main/res/layout/song_item.xml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/menu/bottom_nav_menu.xml b/app/src/main/res/menu/bottom_nav_menu.xml
index 032e48b..7eea45f 100644
--- a/app/src/main/res/menu/bottom_nav_menu.xml
+++ b/app/src/main/res/menu/bottom_nav_menu.xml
@@ -12,7 +12,7 @@
android:icon="@drawable/baseline_album_24"/>