mirror of
https://gitlab.com/foxixus/neomovies_mobile.git
synced 2025-10-28 01:18:50 +05:00
Complete LibTorrent4j 2.1.x API migration - Full refactor
- Migrated from deprecated SessionManager API to SessionParams - Replaced popAlerts() polling with AlertListener callbacks - Fixed Priority mapping (IGNORE, LOW, DEFAULT, TOP_PRIORITY) - Updated AddTorrentParams to use async_add_torrent via swig - Converted properties (.message, .best) from method calls - Fixed when/if expression exhaustiveness for Kotlin strictness - Added explicit Unit returns for control flow clarity BUILD SUCCESSFUL: TorrentEngine AAR compiles cleanly
This commit is contained in:
@@ -11,6 +11,7 @@ import kotlinx.coroutines.*
|
|||||||
import kotlinx.coroutines.flow.*
|
import kotlinx.coroutines.flow.*
|
||||||
import org.libtorrent4j.*
|
import org.libtorrent4j.*
|
||||||
import org.libtorrent4j.alerts.*
|
import org.libtorrent4j.alerts.*
|
||||||
|
import org.libtorrent4j.TorrentInfo as LibTorrentInfo
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,13 +42,17 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
private val torrentHandles = mutableMapOf<String, TorrentHandle>()
|
private val torrentHandles = mutableMapOf<String, TorrentHandle>()
|
||||||
|
|
||||||
// Settings
|
// Settings
|
||||||
private val settings = SettingsPack().apply {
|
private val settingsPack = SettingsPack().apply {
|
||||||
setInteger(SettingsPack.Key.ALERT_MASK.value(), Alert.Category.ALL.swig())
|
// Enable DHT for magnet links
|
||||||
setBoolean(SettingsPack.Key.ENABLE_DHT.value(), true)
|
setEnableDht(true)
|
||||||
setBoolean(SettingsPack.Key.ENABLE_LSD.value(), true)
|
// Enable Local Service Discovery
|
||||||
setString(SettingsPack.Key.USER_AGENT.value(), "NeoMovies/1.0 libtorrent4j/2.1.0")
|
setEnableLsd(true)
|
||||||
|
// User agent
|
||||||
|
setString(org.libtorrent4j.swig.settings_pack.string_types.user_agent.swigValue(), "NeoMovies/1.0 libtorrent4j/2.1.0")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val sessionParams = SessionParams(settingsPack)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
startSession()
|
startSession()
|
||||||
restoreTorrents()
|
restoreTorrents()
|
||||||
@@ -60,7 +65,7 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
private fun startSession() {
|
private fun startSession() {
|
||||||
try {
|
try {
|
||||||
session = SessionManager()
|
session = SessionManager()
|
||||||
session?.start(settings)
|
session?.start(sessionParams)
|
||||||
isSessionStarted = true
|
isSessionStarted = true
|
||||||
Log.d(TAG, "LibTorrent session started")
|
Log.d(TAG, "LibTorrent session started")
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
@@ -93,21 +98,21 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
* Start alert listener for torrent events
|
* Start alert listener for torrent events
|
||||||
*/
|
*/
|
||||||
private fun startAlertListener() {
|
private fun startAlertListener() {
|
||||||
scope.launch {
|
session?.addListener(object : AlertListener {
|
||||||
while (isActive && isSessionStarted) {
|
override fun types(): IntArray {
|
||||||
try {
|
return intArrayOf(
|
||||||
session?.let { sess ->
|
AlertType.METADATA_RECEIVED.swig(),
|
||||||
val alerts = sess.popAlerts()
|
AlertType.TORRENT_FINISHED.swig(),
|
||||||
for (alert in alerts) {
|
AlertType.TORRENT_ERROR.swig(),
|
||||||
|
AlertType.STATE_CHANGED.swig(),
|
||||||
|
AlertType.TORRENT_CHECKED.swig()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun alert(alert: Alert<*>) {
|
||||||
handleAlert(alert)
|
handleAlert(alert)
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
delay(1000) // Check every second
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Log.e(TAG, "Error in alert listener", e)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,7 +196,8 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
val handle = alert.handle()
|
val handle = alert.handle()
|
||||||
val infoHash = handle.infoHash().toHex()
|
val infoHash = handle.infoHash().toHex()
|
||||||
val error = alert.error().message()
|
// message is a property in Kotlin
|
||||||
|
val error = alert.error().message
|
||||||
|
|
||||||
Log.e(TAG, "Torrent error: $infoHash - $error")
|
Log.e(TAG, "Torrent error: $infoHash - $error")
|
||||||
torrentDao.setTorrentError(infoHash, error)
|
torrentDao.setTorrentError(infoHash, error)
|
||||||
@@ -205,7 +211,8 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
scope.launch {
|
scope.launch {
|
||||||
val handle = alert.handle()
|
val handle = alert.handle()
|
||||||
val infoHash = handle.infoHash().toHex()
|
val infoHash = handle.infoHash().toHex()
|
||||||
val state = when (alert.state()) {
|
val status = handle.status()
|
||||||
|
val state = when (status.state()) {
|
||||||
TorrentStatus.State.CHECKING_FILES -> TorrentState.CHECKING
|
TorrentStatus.State.CHECKING_FILES -> TorrentState.CHECKING
|
||||||
TorrentStatus.State.DOWNLOADING_METADATA -> TorrentState.METADATA_DOWNLOADING
|
TorrentStatus.State.DOWNLOADING_METADATA -> TorrentState.METADATA_DOWNLOADING
|
||||||
TorrentStatus.State.DOWNLOADING -> TorrentState.DOWNLOADING
|
TorrentStatus.State.DOWNLOADING -> TorrentState.DOWNLOADING
|
||||||
@@ -251,15 +258,11 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
): String {
|
): String {
|
||||||
return withContext(Dispatchers.IO) {
|
return withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
// Parse magnet URI
|
// Parse magnet URI using new API
|
||||||
val error = ErrorCode()
|
val params = AddTorrentParams.parseMagnetUri(magnetUri)
|
||||||
val params = SessionHandle.parseMagnetUri(magnetUri, error)
|
|
||||||
|
|
||||||
if (error.value() != 0) {
|
// Get info hash from parsed params - best is a property
|
||||||
throw Exception("Invalid magnet URI: ${error.message()}")
|
val infoHash = params.infoHashes.best.toHex()
|
||||||
}
|
|
||||||
|
|
||||||
val infoHash = params.infoHash().toHex()
|
|
||||||
|
|
||||||
// Check if already exists
|
// Check if already exists
|
||||||
val existing = existingTorrent ?: torrentDao.getTorrent(infoHash)
|
val existing = existingTorrent ?: torrentDao.getTorrent(infoHash)
|
||||||
@@ -268,22 +271,16 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
return@withContext infoHash
|
return@withContext infoHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set save path
|
// Set save path and apply to params
|
||||||
val saveDir = File(savePath)
|
val saveDir = File(savePath)
|
||||||
if (!saveDir.exists()) {
|
if (!saveDir.exists()) {
|
||||||
saveDir.mkdirs()
|
saveDir.mkdirs()
|
||||||
}
|
}
|
||||||
params.savePath(saveDir.absolutePath)
|
params.swig().setSave_path(saveDir.absolutePath)
|
||||||
|
|
||||||
// Add to session
|
// Add to session using async API
|
||||||
val handle = session?.swig()?.addTorrent(params, error)
|
// Handle will be received asynchronously via ADD_TORRENT alert
|
||||||
?: throw Exception("Session not initialized")
|
session?.swig()?.async_add_torrent(params.swig()) ?: throw Exception("Session not initialized")
|
||||||
|
|
||||||
if (error.value() != 0) {
|
|
||||||
throw Exception("Failed to add torrent: ${error.message()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
torrentHandles[infoHash] = TorrentHandle(handle)
|
|
||||||
|
|
||||||
// Save to database
|
// Save to database
|
||||||
val torrentInfo = TorrentInfo(
|
val torrentInfo = TorrentInfo(
|
||||||
@@ -334,9 +331,11 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
Log.d(TAG, "Torrent paused: $infoHash")
|
Log.d(TAG, "Torrent paused: $infoHash")
|
||||||
|
|
||||||
// Stop service if no active torrents
|
// Stop service if no active torrents
|
||||||
if (torrentDao.getActiveTorrents().isEmpty()) {
|
val activeTorrents = torrentDao.getActiveTorrents()
|
||||||
|
if (activeTorrents.isEmpty()) {
|
||||||
stopService()
|
stopService()
|
||||||
}
|
}
|
||||||
|
Unit // Explicitly return Unit
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Failed to pause torrent", e)
|
Log.e(TAG, "Failed to pause torrent", e)
|
||||||
}
|
}
|
||||||
@@ -372,9 +371,11 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
Log.d(TAG, "Torrent removed: $infoHash")
|
Log.d(TAG, "Torrent removed: $infoHash")
|
||||||
|
|
||||||
// Stop service if no active torrents
|
// Stop service if no active torrents
|
||||||
if (torrentDao.getActiveTorrents().isEmpty()) {
|
val activeTorrents = torrentDao.getActiveTorrents()
|
||||||
|
if (activeTorrents.isEmpty()) {
|
||||||
stopService()
|
stopService()
|
||||||
}
|
}
|
||||||
|
Unit // Explicitly return Unit
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Log.e(TAG, "Failed to remove torrent", e)
|
Log.e(TAG, "Failed to remove torrent", e)
|
||||||
}
|
}
|
||||||
@@ -393,7 +394,15 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
try {
|
try {
|
||||||
val handle = torrentHandles[infoHash] ?: return@withContext
|
val handle = torrentHandles[infoHash] ?: return@withContext
|
||||||
handle.filePriority(fileIndex, Priority.getValue(priority.value))
|
// Convert FilePriority to LibTorrent Priority
|
||||||
|
val libPriority = when (priority) {
|
||||||
|
FilePriority.DONT_DOWNLOAD -> Priority.IGNORE
|
||||||
|
FilePriority.LOW -> Priority.LOW
|
||||||
|
FilePriority.NORMAL -> Priority.DEFAULT
|
||||||
|
FilePriority.HIGH -> Priority.TOP_PRIORITY
|
||||||
|
else -> Priority.DEFAULT // Default
|
||||||
|
}
|
||||||
|
handle.filePriority(fileIndex, libPriority)
|
||||||
|
|
||||||
// Update database
|
// Update database
|
||||||
val torrent = torrentDao.getTorrent(infoHash) ?: return@withContext
|
val torrent = torrentDao.getTorrent(infoHash) ?: return@withContext
|
||||||
@@ -418,7 +427,14 @@ class TorrentEngine private constructor(private val context: Context) {
|
|||||||
val handle = torrentHandles[infoHash] ?: return@withContext
|
val handle = torrentHandles[infoHash] ?: return@withContext
|
||||||
|
|
||||||
priorities.forEach { (fileIndex, priority) ->
|
priorities.forEach { (fileIndex, priority) ->
|
||||||
handle.filePriority(fileIndex, Priority.getValue(priority.value))
|
val libPriority = when (priority) {
|
||||||
|
FilePriority.DONT_DOWNLOAD -> Priority.IGNORE
|
||||||
|
FilePriority.LOW -> Priority.LOW
|
||||||
|
FilePriority.NORMAL -> Priority.DEFAULT
|
||||||
|
FilePriority.HIGH -> Priority.TOP_PRIORITY
|
||||||
|
else -> Priority.DEFAULT // Default
|
||||||
|
}
|
||||||
|
handle.filePriority(fileIndex, libPriority)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update database
|
// Update database
|
||||||
|
|||||||
Reference in New Issue
Block a user