Skip to content

Commit

Permalink
Fix #4, add preload mechanics, fix #4 downloading/buffering progress …
Browse files Browse the repository at this point in the history
…bars of local tracks
  • Loading branch information
Tim-W committed Nov 19, 2020
1 parent 5ad28eb commit e98ab9e
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 38 deletions.
12 changes: 7 additions & 5 deletions common/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,13 @@ dependencies {
implementation 'com.mattskala:itemadapter:0.3'

// BitTorrent
api files('libs/jlibtorrent-1.2.10.0.jar')
api files('libs/jlibtorrent-android-arm64-1.2.10.0.jar')
api files('libs/jlibtorrent-android-arm-1.2.10.0.jar')
api files('libs/jlibtorrent-android-x86-1.2.10.0.jar')
api files('libs/jlibtorrent-android-x86_64-1.2.10.0.jar')
api files('libs/jlibtorrent-1.2.5.0.jar')
api files('libs/jlibtorrent-android-arm64-1.2.5.0.jar')
api files('libs/jlibtorrent-android-arm-1.2.5.0.jar')
api files('libs/jlibtorrent-android-x86-1.2.5.0.jar')
api files('libs/jlibtorrent-android-x86_64-1.2.5.0.jar')

// implementation 'com.github.TorrentStream:TorrentStream-Android:07f97b8'

//This AAR dependency also contains jlibtorrent
api files('libs/torrentstream-android.jar')
Expand Down
7 changes: 4 additions & 3 deletions musicdao/src/main/java/com/example/musicdao/MusicService.kt
Original file line number Diff line number Diff line change
Expand Up @@ -140,9 +140,10 @@ class MusicService : AppCompatActivity() {
* Show libtorrent connectivity stats
*/
fun getStatsOverview(): String {
val startingMessage = "Starting libtorrent session..."
if (!::torrentStream.isInitialized) return startingMessage
val sessionManager = torrentStream.sessionManager ?: return startingMessage
if (!::torrentStream.isInitialized) return "Starting up torrent client..."
if (torrentStream.sessionManager == null) return "Starting up torrent client..."
if (!torrentStream.sessionManager.isRunning) return "Starting up torrent client..."
val sessionManager = torrentStream.sessionManager
return "up: ${Util.readableBytes(sessionManager.uploadRate())}, down: ${
Util.readableBytes(
sessionManager.downloadRate()
Expand Down
11 changes: 7 additions & 4 deletions musicdao/src/main/java/com/example/musicdao/net/ContentSeeder.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.example.musicdao.net

import com.example.musicdao.util.Util
import com.frostwire.jlibtorrent.SessionManager
import com.frostwire.jlibtorrent.TorrentInfo
import org.apache.commons.io.FileUtils
Expand Down Expand Up @@ -32,9 +33,11 @@ class ContentSeeder(private val sessionManager: SessionManager, private val save
count += 1
// 'Downloading' the torrent file also starts seeding it after download has
// already been completed
// TODO enable seeding of all files that you have locally. Currently doing this
// clashes with the TorrentStreaming library somehow
// sessionManager.download(torrentInfo, saveDir)
// We only seed torrents that have previously already been fully downloaded,
// so that this does not clash with the TorrentStream library
if (Util.isTorrentCompleted(torrentInfo, saveDir)) {
sessionManager.download(torrentInfo, saveDir)
}
}
}
}
Expand All @@ -52,7 +55,7 @@ class ContentSeeder(private val sessionManager: SessionManager, private val save
}
// TODO enable seeding of all files that you have locally. Currently doing this
// clashes with the TorrentStreaming library somehow
// sessionManager.download(torrentInfo, saveDir)
sessionManager.download(torrentInfo, saveDir)
return true
}
return false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,14 +46,32 @@ class ReleaseFragment(
private var currentFileIndex = -1
private var prevFileIndex = -1
private var prevProgress = -1.0f
private var localTorrent: Torrent? = null
private var streamingTorrent: Torrent? = null
private var downloadedTorrent: TorrentInfo? = null

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
val torrentUrl = resolveTorrentUrl(magnet)
if ((activity as MusicService).torrentStream.isStreaming) {
(activity as MusicService).torrentStream.stopStream()
var torrentUrl = magnet
if (torrentInfoName != null) {
val torrentFileName =
"${context?.cacheDir}/$torrentInfoName.torrent"
val torrentFile = File(torrentFileName)
val saveDir = context?.cacheDir
if (torrentFile.isFile && TorrentInfo(torrentFile).isValid) {
// This means we have the torrent file already locally and we can skip the step of
// obtaining the TorrentInfo from magnet link
torrentUrl = torrentFile.toURI().toURL().toString()
if (saveDir != null &&
Util.isTorrentCompleted(TorrentInfo(torrentFile), saveDir)
) {
// All files are already downloaded so we do not need to use TorrentStream
val torrentInfo = TorrentInfo(torrentFile)
setMetadata(torrentInfo.files(), preloaded = true)
downloadedTorrent = torrentInfo
return
}
}
}
(activity as MusicService).torrentStream.addListener(this)
(activity as MusicService).torrentStream.startStream(torrentUrl)
Expand All @@ -79,16 +97,6 @@ class ReleaseFragment(
}
}

override fun onResume() {
super.onResume()

if (release_table_layout.childCount == 0) {
loadingTracks.visibility = View.VISIBLE
} else {
loadingTracks.visibility = View.GONE
}
}

override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
// Debug button is a simple toggle for a connectivity stats display
Expand All @@ -112,9 +120,6 @@ class ReleaseFragment(

override fun onDestroy() {
(activity as MusicService).torrentStream.removeListener(this)
if ((activity as MusicService).torrentStream.isStreaming) {
(activity as MusicService).torrentStream.stopStream()
}
super.onDestroy()
}

Expand Down Expand Up @@ -143,21 +148,26 @@ class ReleaseFragment(
* This sets the metadata of the TorrentInfo in the UI, it renders the file list and other
* metadata
*/
private fun setMetadata(metadata: FileStorage) {
loadingTracks.visibility = View.GONE
private fun setMetadata(metadata: FileStorage, preloaded: Boolean = false) {
loadingTracks?.visibility = View.GONE
this.metadata = metadata
val num = metadata.numFiles()
val filestorage = metadata

for (index in 0 until num) {
var fileName = filestorage.fileName(index)
fileName = Util.checkAndSanitizeTrackNames(fileName)
var progress: Int? = null
if (preloaded) {
progress = 100
}
if (fileName != null) {
val track = TrackFragment(
fileName,
index,
this,
Util.readableBytes(filestorage.fileSize(index))
Util.readableBytes(filestorage.fileSize(index)),
progress
)

// Add a table row (Track) to the table (Release)
Expand Down Expand Up @@ -187,7 +197,8 @@ class ReleaseFragment(
val audioPlayer = AudioPlayer.getInstance()
audioPlayer?.prepareNextTrack()

val tor = localTorrent
val tor = streamingTorrent
val localTorrent = downloadedTorrent
if (tor != null) {
(activity as MusicService).torrentStream.removeListener(this)
tor.setSelectedFileIndex(currentFileIndex)
Expand All @@ -201,6 +212,14 @@ class ReleaseFragment(
AudioPlayer.getInstance()
?.setTrackInfo("Buffering track: " + tor.videoFile.nameWithoutExtension)
}
} else if (localTorrent != null) {
val fileToPlay =
File("${context?.cacheDir}/${localTorrent.files().filePath(currentFileIndex)}")
// It is not a streaming torrent, and therefore we can conclude we already have
// it locally so we can just start playing it
if (fileToPlay.isFile && fileToPlay.length() > 1024 * 512) {
startPlaying(fileToPlay, currentFileIndex)
}
}
}

Expand All @@ -223,7 +242,9 @@ class ReleaseFragment(
private fun startPlaying(file: File, index: Int) {
val audioPlayer = AudioPlayer.getInstance()
audioPlayer?.setAudioResource(file, index)
audioPlayer?.setTrackInfo(file.nameWithoutExtension)
audioPlayer?.setTrackInfo(
Util.checkAndSanitizeTrackNames(file.name) ?: ""
)
}

fun resolveTorrentUrl(magnet: String): String {
Expand All @@ -232,7 +253,7 @@ class ReleaseFragment(
val torrentFileName =
"${context?.cacheDir}/$torrentInfoName.torrent"
val torrentFile = File(torrentFileName)
if (torrentFile.isFile) {
if (torrentFile.isFile && TorrentInfo(torrentFile).isValid) {
// This means we have the torrent file already locally and we can skip the step of
// obtaining the TorrentInfo from magnet link
torrentUrl = torrentFile.toURI().toURL().toString()
Expand All @@ -259,7 +280,7 @@ class ReleaseFragment(
override fun onStreamPrepared(torrent: Torrent?) {
val fileProgress = torrent?.torrentHandle?.fileProgress()
if (fileProgress != null) updateFileProgress(fileProgress)
localTorrent = torrent
streamingTorrent = torrent
if (torrent == null) return
torrent.setSelectedFileIndex(0)
torrent.startDownload()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,15 @@ class TrackFragment(
private val name: String,
private val index: Int,
private val release: ReleaseFragment,
private val size: String
private val size: String,
private val progress: Int?
) : Fragment(R.layout.track_table_row) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
trackTitle.text = name
trackArtist.text = size
trackId.text = "${index + 1}."
if (progress != null) progressBar.progress = progress

contentRow.setOnClickListener {
release.selectTrackAndPlay(index)
Expand Down
26 changes: 26 additions & 0 deletions musicdao/src/main/java/com/example/musicdao/util/Util.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package com.example.musicdao.util
import com.frostwire.jlibtorrent.Priority
import com.frostwire.jlibtorrent.TorrentInfo
import com.github.se_bastiaan.torrentstream.Torrent
import java.io.File


object Util {

Expand Down Expand Up @@ -80,4 +82,28 @@ object Util {
}
return null
}

/**
* Check if a torrent file has all its corresponding files downloaded
*/
fun isTorrentCompleted(torrentInfo: TorrentInfo, saveDirectory: File): Boolean {
val dir = File(saveDirectory.path + "/" + torrentInfo.name())
if (!dir.isDirectory) return false
if (folderSize(dir) != torrentInfo.totalSize()) return false
return true
}

private fun folderSize(dir: File): Long {
var length = 0.toLong()
if (!dir.isDirectory) return 0
val files = dir.listFiles() ?: return 0
for (file in files) {
length += if (file.isFile) {
file.length()
} else {
folderSize(file)
}
}
return length
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class ContentSeederTest {
val saveDir = File("./src/test/resources")
Assert.assertTrue(saveDir.isDirectory)
// Test whether it reads all local torrent files correctly
contentSeeder = ContentSeeder.getInstance(sessionManager, saveDir)
contentSeeder = ContentSeeder.getInstance(saveDir)
Assert.assertNotNull(contentSeeder)
}

Expand Down

0 comments on commit e98ab9e

Please sign in to comment.