mirror of
https://github.com/ultrasonic/ultrasonic
synced 2025-02-11 01:00:58 +01:00
Move file methods to FileUtil.kt
This commit is contained in:
parent
c9e276dc76
commit
f73457298d
@ -21,7 +21,7 @@ import org.moire.ultrasonic.api.subsonic.throwOnFailure
|
||||
import org.moire.ultrasonic.api.subsonic.toStreamResponse
|
||||
import org.moire.ultrasonic.domain.MusicDirectory
|
||||
import org.moire.ultrasonic.util.FileUtil
|
||||
import org.moire.ultrasonic.util.Util
|
||||
import org.moire.ultrasonic.util.Util.safeClose
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
@ -185,10 +185,10 @@ class ImageLoader(
|
||||
outputStream = FileOutputStream(file)
|
||||
outputStream.write(bytes)
|
||||
} finally {
|
||||
Util.close(outputStream)
|
||||
outputStream.safeClose()
|
||||
}
|
||||
} finally {
|
||||
Util.close(inputStream)
|
||||
inputStream.safeClose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,6 @@ import java.text.SimpleDateFormat
|
||||
import java.util.Date
|
||||
import java.util.Locale
|
||||
import org.moire.ultrasonic.util.FileUtil
|
||||
import org.moire.ultrasonic.util.Util
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
@ -38,7 +37,7 @@ class FileLoggerTree : Timber.DebugTree() {
|
||||
// Using base class DebugTree here, we don't want to try to log this into file
|
||||
super.log(6, TAG, String.format("Failed to write log to %s", file), x)
|
||||
} finally {
|
||||
if (writer != null) Util.close(writer)
|
||||
writer.safeClose()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ import org.moire.ultrasonic.util.CancellableTask
|
||||
import org.moire.ultrasonic.util.FileUtil
|
||||
import org.moire.ultrasonic.util.Settings
|
||||
import org.moire.ultrasonic.util.Util
|
||||
import org.moire.ultrasonic.util.Util.safeClose
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
@ -135,9 +136,9 @@ class DownloadFile(
|
||||
|
||||
fun delete() {
|
||||
cancelDownload()
|
||||
Util.delete(partialFile)
|
||||
Util.delete(completeFile)
|
||||
Util.delete(saveFile)
|
||||
FileUtil.delete(partialFile)
|
||||
FileUtil.delete(completeFile)
|
||||
FileUtil.delete(saveFile)
|
||||
|
||||
Util.scanMedia(saveFile)
|
||||
}
|
||||
@ -156,11 +157,11 @@ class DownloadFile(
|
||||
fun cleanup(): Boolean {
|
||||
var ok = true
|
||||
if (completeFile.exists() || saveFile.exists()) {
|
||||
ok = Util.delete(partialFile)
|
||||
ok = FileUtil.delete(partialFile)
|
||||
}
|
||||
|
||||
if (saveFile.exists()) {
|
||||
ok = ok and Util.delete(completeFile)
|
||||
ok = ok and FileUtil.delete(completeFile)
|
||||
}
|
||||
|
||||
return ok
|
||||
@ -182,14 +183,14 @@ class DownloadFile(
|
||||
private fun doPendingRename() {
|
||||
try {
|
||||
if (saveWhenDone) {
|
||||
Util.renameFile(completeFile, saveFile)
|
||||
FileUtil.renameFile(completeFile, saveFile)
|
||||
saveWhenDone = false
|
||||
} else if (completeWhenDone) {
|
||||
if (save) {
|
||||
Util.renameFile(partialFile, saveFile)
|
||||
FileUtil.renameFile(partialFile, saveFile)
|
||||
Util.scanMedia(saveFile)
|
||||
} else {
|
||||
Util.renameFile(partialFile, completeFile)
|
||||
FileUtil.renameFile(partialFile, completeFile)
|
||||
}
|
||||
completeWhenDone = false
|
||||
}
|
||||
@ -221,7 +222,7 @@ class DownloadFile(
|
||||
if (isPlaying) {
|
||||
saveWhenDone = true
|
||||
} else {
|
||||
Util.renameFile(completeFile, saveFile)
|
||||
FileUtil.renameFile(completeFile, saveFile)
|
||||
}
|
||||
} else {
|
||||
Timber.i("%s already exists. Skipping.", completeFile)
|
||||
@ -291,16 +292,16 @@ class DownloadFile(
|
||||
completeWhenDone = true
|
||||
} else {
|
||||
if (save) {
|
||||
Util.renameFile(partialFile, saveFile)
|
||||
FileUtil.renameFile(partialFile, saveFile)
|
||||
Util.scanMedia(saveFile)
|
||||
} else {
|
||||
Util.renameFile(partialFile, completeFile)
|
||||
FileUtil.renameFile(partialFile, completeFile)
|
||||
}
|
||||
}
|
||||
} catch (all: Exception) {
|
||||
Util.close(outputStream)
|
||||
Util.delete(completeFile)
|
||||
Util.delete(saveFile)
|
||||
outputStream.safeClose()
|
||||
FileUtil.delete(completeFile)
|
||||
FileUtil.delete(saveFile)
|
||||
if (!isCancelled) {
|
||||
isFailed = true
|
||||
if (retryCount > 1) {
|
||||
@ -313,8 +314,8 @@ class DownloadFile(
|
||||
Timber.w(all, "Failed to download '%s'.", song)
|
||||
}
|
||||
} finally {
|
||||
Util.close(inputStream)
|
||||
Util.close(outputStream)
|
||||
inputStream.safeClose()
|
||||
outputStream.safeClose()
|
||||
CacheCleaner().cleanSpace()
|
||||
downloader.checkDownloads()
|
||||
}
|
||||
|
@ -41,7 +41,7 @@ import org.moire.ultrasonic.domain.Share
|
||||
import org.moire.ultrasonic.domain.UserInfo
|
||||
import org.moire.ultrasonic.util.Constants
|
||||
import org.moire.ultrasonic.util.FileUtil
|
||||
import org.moire.ultrasonic.util.Util
|
||||
import org.moire.ultrasonic.util.Util.safeClose
|
||||
import timber.log.Timber
|
||||
|
||||
// TODO: There are quite a number of deeply nested and complicated functions in this class..
|
||||
@ -213,8 +213,8 @@ class OfflineMusicService : MusicService, KoinComponent {
|
||||
}
|
||||
playlist
|
||||
} finally {
|
||||
Util.close(buffer)
|
||||
Util.close(reader)
|
||||
buffer.safeClose()
|
||||
reader.safeClose()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -27,8 +27,10 @@ import java.util.TreeSet
|
||||
import java.util.regex.Pattern
|
||||
import org.moire.ultrasonic.app.UApp
|
||||
import org.moire.ultrasonic.domain.MusicDirectory
|
||||
import org.moire.ultrasonic.util.Util.safeClose
|
||||
import timber.log.Timber
|
||||
|
||||
@Suppress("TooManyFunctions")
|
||||
object FileUtil {
|
||||
|
||||
private val FILE_SYSTEM_UNSAFE = arrayOf("/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|")
|
||||
@ -416,7 +418,7 @@ object FileUtil {
|
||||
Timber.w("Failed to serialize object to %s", file)
|
||||
false
|
||||
} finally {
|
||||
Util.close(out)
|
||||
out.safeClose()
|
||||
}
|
||||
}
|
||||
|
||||
@ -438,7 +440,7 @@ object FileUtil {
|
||||
Timber.w(all, "Failed to deserialize object from %s", file)
|
||||
null
|
||||
} finally {
|
||||
Util.close(inStream)
|
||||
inStream.safeClose()
|
||||
}
|
||||
}
|
||||
|
||||
@ -466,8 +468,55 @@ object FileUtil {
|
||||
Timber.w("Failed to save playlist: %s", name)
|
||||
throw e
|
||||
} finally {
|
||||
bw.close()
|
||||
fw.close()
|
||||
bw.safeClose()
|
||||
fw.safeClose()
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun atomicCopy(from: File, to: File) {
|
||||
val tmp = File(String.format(Locale.ROOT, "%s.tmp", to.path))
|
||||
val input = FileInputStream(from)
|
||||
val out = FileOutputStream(tmp)
|
||||
try {
|
||||
input.channel.transferTo(0, from.length(), out.channel)
|
||||
out.close()
|
||||
if (!tmp.renameTo(to)) {
|
||||
throw IOException(
|
||||
String.format(Locale.ROOT, "Failed to rename %s to %s", tmp, to)
|
||||
)
|
||||
}
|
||||
Timber.i("Copied %s to %s", from, to)
|
||||
} catch (x: IOException) {
|
||||
out.safeClose()
|
||||
delete(to)
|
||||
throw x
|
||||
} finally {
|
||||
input.safeClose()
|
||||
out.safeClose()
|
||||
delete(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun renameFile(from: File, to: File) {
|
||||
if (from.renameTo(to)) {
|
||||
Timber.i("Renamed %s to %s", from, to)
|
||||
} else {
|
||||
atomicCopy(from, to)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun delete(file: File?): Boolean {
|
||||
if (file != null && file.exists()) {
|
||||
if (!file.delete()) {
|
||||
Timber.w("Failed to delete file %s", file)
|
||||
return false
|
||||
}
|
||||
Timber.i("Deleted file %s", file)
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import android.content.Context
|
||||
import android.os.Build
|
||||
import java.io.File
|
||||
import java.io.PrintWriter
|
||||
import org.moire.ultrasonic.util.Util.safeClose
|
||||
import timber.log.Timber
|
||||
|
||||
/**
|
||||
@ -34,7 +35,7 @@ class SubsonicUncaughtExceptionHandler(
|
||||
} catch (x: Throwable) {
|
||||
Timber.e(x, "Failed to write stack trace to %s", file)
|
||||
} finally {
|
||||
Util.close(printWriter)
|
||||
printWriter.safeClose()
|
||||
defaultHandler?.uncaughtException(thread, throwable)
|
||||
}
|
||||
}
|
||||
|
@ -43,9 +43,6 @@ import androidx.annotation.AnyRes
|
||||
import androidx.media.utils.MediaConstants
|
||||
import java.io.Closeable
|
||||
import java.io.File
|
||||
import java.io.FileInputStream
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.UnsupportedEncodingException
|
||||
import java.security.MessageDigest
|
||||
import java.text.DecimalFormat
|
||||
@ -114,62 +111,6 @@ object Util {
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun atomicCopy(from: File, to: File) {
|
||||
val tmp = File(String.format(Locale.ROOT, "%s.tmp", to.path))
|
||||
val input = FileInputStream(from)
|
||||
val out = FileOutputStream(tmp)
|
||||
try {
|
||||
input.channel.transferTo(0, from.length(), out.channel)
|
||||
out.close()
|
||||
if (!tmp.renameTo(to)) {
|
||||
throw IOException(
|
||||
String.format(Locale.ROOT, "Failed to rename %s to %s", tmp, to)
|
||||
)
|
||||
}
|
||||
Timber.i("Copied %s to %s", from, to)
|
||||
} catch (x: IOException) {
|
||||
close(out)
|
||||
delete(to)
|
||||
throw x
|
||||
} finally {
|
||||
close(input)
|
||||
close(out)
|
||||
delete(tmp)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@Throws(IOException::class)
|
||||
fun renameFile(from: File, to: File) {
|
||||
if (from.renameTo(to)) {
|
||||
Timber.i("Renamed %s to %s", from, to)
|
||||
} else {
|
||||
atomicCopy(from, to)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun close(closeable: Closeable?) {
|
||||
try {
|
||||
closeable?.close()
|
||||
} catch (_: Throwable) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun delete(file: File?): Boolean {
|
||||
if (file != null && file.exists()) {
|
||||
if (!file.delete()) {
|
||||
Timber.w("Failed to delete file %s", file)
|
||||
return false
|
||||
}
|
||||
Timber.i("Deleted file %s", file)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
@JvmOverloads
|
||||
fun toast(context: Context?, messageId: Int, shortDuration: Boolean = true) {
|
||||
@ -957,8 +898,22 @@ object Util {
|
||||
return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||
}
|
||||
|
||||
/**
|
||||
* Small data class to store information about the current network
|
||||
**/
|
||||
data class NetworkInfo(
|
||||
var connected: Boolean = false,
|
||||
var unmetered: Boolean = false
|
||||
)
|
||||
|
||||
/**
|
||||
* Closes a Closeable while ignoring any errors.
|
||||
**/
|
||||
fun Closeable?.safeClose() {
|
||||
try {
|
||||
this?.close()
|
||||
} catch (_: Exception) {
|
||||
// Ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user