mirror of
https://gitlab.com/ultrasonic/ultrasonic.git
synced 2025-04-30 07:31:34 +03: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.api.subsonic.toStreamResponse
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory
|
import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
import org.moire.ultrasonic.util.FileUtil
|
import org.moire.ultrasonic.util.FileUtil
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util.safeClose
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -185,10 +185,10 @@ class ImageLoader(
|
|||||||
outputStream = FileOutputStream(file)
|
outputStream = FileOutputStream(file)
|
||||||
outputStream.write(bytes)
|
outputStream.write(bytes)
|
||||||
} finally {
|
} finally {
|
||||||
Util.close(outputStream)
|
outputStream.safeClose()
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Util.close(inputStream)
|
inputStream.safeClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ import java.text.SimpleDateFormat
|
|||||||
import java.util.Date
|
import java.util.Date
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import org.moire.ultrasonic.util.FileUtil
|
import org.moire.ultrasonic.util.FileUtil
|
||||||
import org.moire.ultrasonic.util.Util
|
|
||||||
import timber.log.Timber
|
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
|
// 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)
|
super.log(6, TAG, String.format("Failed to write log to %s", file), x)
|
||||||
} finally {
|
} 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.FileUtil
|
||||||
import org.moire.ultrasonic.util.Settings
|
import org.moire.ultrasonic.util.Settings
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util
|
||||||
|
import org.moire.ultrasonic.util.Util.safeClose
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -135,9 +136,9 @@ class DownloadFile(
|
|||||||
|
|
||||||
fun delete() {
|
fun delete() {
|
||||||
cancelDownload()
|
cancelDownload()
|
||||||
Util.delete(partialFile)
|
FileUtil.delete(partialFile)
|
||||||
Util.delete(completeFile)
|
FileUtil.delete(completeFile)
|
||||||
Util.delete(saveFile)
|
FileUtil.delete(saveFile)
|
||||||
|
|
||||||
Util.scanMedia(saveFile)
|
Util.scanMedia(saveFile)
|
||||||
}
|
}
|
||||||
@ -156,11 +157,11 @@ class DownloadFile(
|
|||||||
fun cleanup(): Boolean {
|
fun cleanup(): Boolean {
|
||||||
var ok = true
|
var ok = true
|
||||||
if (completeFile.exists() || saveFile.exists()) {
|
if (completeFile.exists() || saveFile.exists()) {
|
||||||
ok = Util.delete(partialFile)
|
ok = FileUtil.delete(partialFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saveFile.exists()) {
|
if (saveFile.exists()) {
|
||||||
ok = ok and Util.delete(completeFile)
|
ok = ok and FileUtil.delete(completeFile)
|
||||||
}
|
}
|
||||||
|
|
||||||
return ok
|
return ok
|
||||||
@ -182,14 +183,14 @@ class DownloadFile(
|
|||||||
private fun doPendingRename() {
|
private fun doPendingRename() {
|
||||||
try {
|
try {
|
||||||
if (saveWhenDone) {
|
if (saveWhenDone) {
|
||||||
Util.renameFile(completeFile, saveFile)
|
FileUtil.renameFile(completeFile, saveFile)
|
||||||
saveWhenDone = false
|
saveWhenDone = false
|
||||||
} else if (completeWhenDone) {
|
} else if (completeWhenDone) {
|
||||||
if (save) {
|
if (save) {
|
||||||
Util.renameFile(partialFile, saveFile)
|
FileUtil.renameFile(partialFile, saveFile)
|
||||||
Util.scanMedia(saveFile)
|
Util.scanMedia(saveFile)
|
||||||
} else {
|
} else {
|
||||||
Util.renameFile(partialFile, completeFile)
|
FileUtil.renameFile(partialFile, completeFile)
|
||||||
}
|
}
|
||||||
completeWhenDone = false
|
completeWhenDone = false
|
||||||
}
|
}
|
||||||
@ -221,7 +222,7 @@ class DownloadFile(
|
|||||||
if (isPlaying) {
|
if (isPlaying) {
|
||||||
saveWhenDone = true
|
saveWhenDone = true
|
||||||
} else {
|
} else {
|
||||||
Util.renameFile(completeFile, saveFile)
|
FileUtil.renameFile(completeFile, saveFile)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Timber.i("%s already exists. Skipping.", completeFile)
|
Timber.i("%s already exists. Skipping.", completeFile)
|
||||||
@ -291,16 +292,16 @@ class DownloadFile(
|
|||||||
completeWhenDone = true
|
completeWhenDone = true
|
||||||
} else {
|
} else {
|
||||||
if (save) {
|
if (save) {
|
||||||
Util.renameFile(partialFile, saveFile)
|
FileUtil.renameFile(partialFile, saveFile)
|
||||||
Util.scanMedia(saveFile)
|
Util.scanMedia(saveFile)
|
||||||
} else {
|
} else {
|
||||||
Util.renameFile(partialFile, completeFile)
|
FileUtil.renameFile(partialFile, completeFile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (all: Exception) {
|
} catch (all: Exception) {
|
||||||
Util.close(outputStream)
|
outputStream.safeClose()
|
||||||
Util.delete(completeFile)
|
FileUtil.delete(completeFile)
|
||||||
Util.delete(saveFile)
|
FileUtil.delete(saveFile)
|
||||||
if (!isCancelled) {
|
if (!isCancelled) {
|
||||||
isFailed = true
|
isFailed = true
|
||||||
if (retryCount > 1) {
|
if (retryCount > 1) {
|
||||||
@ -313,8 +314,8 @@ class DownloadFile(
|
|||||||
Timber.w(all, "Failed to download '%s'.", song)
|
Timber.w(all, "Failed to download '%s'.", song)
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Util.close(inputStream)
|
inputStream.safeClose()
|
||||||
Util.close(outputStream)
|
outputStream.safeClose()
|
||||||
CacheCleaner().cleanSpace()
|
CacheCleaner().cleanSpace()
|
||||||
downloader.checkDownloads()
|
downloader.checkDownloads()
|
||||||
}
|
}
|
||||||
|
@ -41,7 +41,7 @@ import org.moire.ultrasonic.domain.Share
|
|||||||
import org.moire.ultrasonic.domain.UserInfo
|
import org.moire.ultrasonic.domain.UserInfo
|
||||||
import org.moire.ultrasonic.util.Constants
|
import org.moire.ultrasonic.util.Constants
|
||||||
import org.moire.ultrasonic.util.FileUtil
|
import org.moire.ultrasonic.util.FileUtil
|
||||||
import org.moire.ultrasonic.util.Util
|
import org.moire.ultrasonic.util.Util.safeClose
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
// TODO: There are quite a number of deeply nested and complicated functions in this class..
|
// TODO: There are quite a number of deeply nested and complicated functions in this class..
|
||||||
@ -213,8 +213,8 @@ class OfflineMusicService : MusicService, KoinComponent {
|
|||||||
}
|
}
|
||||||
playlist
|
playlist
|
||||||
} finally {
|
} finally {
|
||||||
Util.close(buffer)
|
buffer.safeClose()
|
||||||
Util.close(reader)
|
reader.safeClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,8 +27,10 @@ import java.util.TreeSet
|
|||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
import org.moire.ultrasonic.app.UApp
|
import org.moire.ultrasonic.app.UApp
|
||||||
import org.moire.ultrasonic.domain.MusicDirectory
|
import org.moire.ultrasonic.domain.MusicDirectory
|
||||||
|
import org.moire.ultrasonic.util.Util.safeClose
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@Suppress("TooManyFunctions")
|
||||||
object FileUtil {
|
object FileUtil {
|
||||||
|
|
||||||
private val FILE_SYSTEM_UNSAFE = arrayOf("/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|")
|
private val FILE_SYSTEM_UNSAFE = arrayOf("/", "\\", "..", ":", "\"", "?", "*", "<", ">", "|")
|
||||||
@ -416,7 +418,7 @@ object FileUtil {
|
|||||||
Timber.w("Failed to serialize object to %s", file)
|
Timber.w("Failed to serialize object to %s", file)
|
||||||
false
|
false
|
||||||
} finally {
|
} finally {
|
||||||
Util.close(out)
|
out.safeClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -438,7 +440,7 @@ object FileUtil {
|
|||||||
Timber.w(all, "Failed to deserialize object from %s", file)
|
Timber.w(all, "Failed to deserialize object from %s", file)
|
||||||
null
|
null
|
||||||
} finally {
|
} finally {
|
||||||
Util.close(inStream)
|
inStream.safeClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -466,8 +468,55 @@ object FileUtil {
|
|||||||
Timber.w("Failed to save playlist: %s", name)
|
Timber.w("Failed to save playlist: %s", name)
|
||||||
throw e
|
throw e
|
||||||
} finally {
|
} finally {
|
||||||
bw.close()
|
bw.safeClose()
|
||||||
fw.close()
|
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 android.os.Build
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
|
import org.moire.ultrasonic.util.Util.safeClose
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,7 +35,7 @@ class SubsonicUncaughtExceptionHandler(
|
|||||||
} catch (x: Throwable) {
|
} catch (x: Throwable) {
|
||||||
Timber.e(x, "Failed to write stack trace to %s", file)
|
Timber.e(x, "Failed to write stack trace to %s", file)
|
||||||
} finally {
|
} finally {
|
||||||
Util.close(printWriter)
|
printWriter.safeClose()
|
||||||
defaultHandler?.uncaughtException(thread, throwable)
|
defaultHandler?.uncaughtException(thread, throwable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -43,9 +43,6 @@ import androidx.annotation.AnyRes
|
|||||||
import androidx.media.utils.MediaConstants
|
import androidx.media.utils.MediaConstants
|
||||||
import java.io.Closeable
|
import java.io.Closeable
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileInputStream
|
|
||||||
import java.io.FileOutputStream
|
|
||||||
import java.io.IOException
|
|
||||||
import java.io.UnsupportedEncodingException
|
import java.io.UnsupportedEncodingException
|
||||||
import java.security.MessageDigest
|
import java.security.MessageDigest
|
||||||
import java.text.DecimalFormat
|
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
|
@JvmStatic
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
fun toast(context: Context?, messageId: Int, shortDuration: Boolean = true) {
|
fun toast(context: Context?, messageId: Int, shortDuration: Boolean = true) {
|
||||||
@ -957,8 +898,22 @@ object Util {
|
|||||||
return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
return context.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Small data class to store information about the current network
|
||||||
|
**/
|
||||||
data class NetworkInfo(
|
data class NetworkInfo(
|
||||||
var connected: Boolean = false,
|
var connected: Boolean = false,
|
||||||
var unmetered: 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