package Ġtech . so it . quiet . repository . local Ċ Ċ import Ġandroid . os . Environment Ċ import Ġandroidx . annotation . Visible ForTesting Ċ import Ġandroidx . annotation . Worker Thread Ċ import Ġandroidx . lifecycle . Mutable LiveData Ċ import Ġkotlinx . coroutines . Cancellation Exception Ċ import Ġkotlinx . coroutines . Global Scope Ċ import Ġkotlinx . coroutines . isActive Ċ import Ġkotlinx . coroutines . launch Ċ import Ġtech . so it . quiet . model . vo . Music Ċ import Ġtech . so it . quiet . repository . db . dao . Local Music Dao Ċ import Ġtech . so it . quiet . utils . Music Converter Ċ import Ġtech . so it . quiet . utils . component . log Ċ import Ġtech . so it . quiet . utils . component . log Error Ċ import Ġtech . so it . quiet . utils . component . support . Resource Ċ import Ġtech . so it . quiet . utils . component . support . Status Ċ import Ġtech . so it . quiet . utils . get Storage Path Ċ import Ġjava . io . File Ċ import Ġkotlin . coroutines . coroutine Context Ċ Ċ /** Ċ Ġ* Ġretrieval Ġlocal Ġmusic Ġto Ġdatabase Ċ Ġ* Ċ Ġ* Ġ@ param Ġlocal Music Dao Ġlocal Ġmusic Ġdb Ċ Ġ*/ Ċ class ĠLocal Music Engine ( private Ġval Ġlocal Music Dao : ĠLocal Music Dao ) Ġ{ ĊĊĠĠĠ Ġcompanion Ġobject Ġ{ ĊĊĊĠĠĠĠĠĠĠ Ġ/** Ġinternal Ġand Ġexternal Ġstorage Ġdirectory Ġ*/ ĊĠĠĠĠĠĠĠ Ġprivate Ġval Ġdisks ĊĠĠĠĠĠĠĠĠĠĠĠ Ġget () Ġ= ĠlistOf NotNull ( ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ ĠEnvironment . get External Storage Directory (). path , ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġget Storage Path ( true )) ĊĊĊĠĠĠ Ġ} ĊĊĠĠĠ Ġval Ġstates Ġ= ĠMutable LiveData < Status >() ĊĊĠĠĠ Ġinit Ġ{ ĊĠĠĠĠĠĠĠ Ġstates . post Value ( null ) ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġval Ġnew Music Ġ= ĠMutable LiveData < Resource < Music >>() ĊĊĠĠĠ Ġ/** ĊĠĠĠĠ Ġ* Ġstart Ġscan ĊĠĠĠĠ Ġ*/ ĊĠĠĠ Ġfun Ġscan () Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ( states . value Ġ== ĠStatus . LOADING ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġstates . post Value ( Status . LOADING ) ĊĠĠĠĠĠĠĠ Ġ// do Ġscan Ġwork ĊĠĠĠĠĠĠĠ ĠGlobal Scope . launch Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġdisks . forEach Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtraversal Directory ( File ( it )) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ}. invoke On Completion Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( it Ġ!= Ġnull Ġ&& Ġit Ġ! is ĠC ancellation Exception ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġlog Error ( it ) ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstates . post Value ( Status . ERROR ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġstates . post Value ( Status . SUCCESS ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠ Ġ} ĊĊĊĠĠĠ Ġ@ Worker Thread ĊĠĠĠ Ġ@ Visible ForTesting ĊĠĠĠ Ġprivate Ġsuspend Ġfun Ġtraversal Directory ( file : ĠFile ): ĠUnit Ġ= Ġwith ( file ) Ġ{ ĊĠĠĠĠĠĠĠ Ġif Ġ(! coroutine Context . isActive ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ/* to Ġcheck Ġif Ġcanceled */ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ with ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ(! exists () Ġ|| Ġ! isDirectory ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn @ with ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ( path . startsWith (".") Ġ|| Ġname Ġ== Ġ" Android ") Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ// TODO Ġæĸĩä»¶ è¿ĩæ»¤ éħįç½® åĮĸ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġfiles Ġ= Ġlist Files () Ġ?: Ġreturn @ with ĊĠĠĠĠĠĠĠ Ġfiles . forEach Ġ{ Ġchild Ġ-> ĊĠĠĠĠĠĠĠĠĠĠĠ Ġif Ġ( child . isDirectory ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġtraversal Directory ( child ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} Ġelse Ġif Ġ( child . isFile Ġ&& Ġchild . exists ()) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠĠĠĠĠ Ġon File Emit ted ( child ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ ĠUnit ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġ/** Ġon Ġa Ġfile Ġhas Ġbeen Ġtra versed Ġ*/ ĊĠĠĠ Ġprivate Ġfun Ġon File Emit ted ( file : ĠFile ) Ġ{ ĊĠĠĠĠĠĠĠ Ġlog Ġ{ Ġ" sc anning Ġfile Ġ: Ġ${ file . path }" Ġ} ĊĠĠĠĠĠĠĠ Ġif Ġ(! isFile Accept ( file )) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġreturn ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠĠĠĠĠ Ġval Ġmusic Ġ= ĠMusic Converter . scan File To Music ( file ) ĊĠĠĠĠĠĠĠ Ġif Ġ( music Ġ!= Ġnull ) Ġ{ ĊĠĠĠĠĠĠĠĠĠĠĠ Ġlocal Music Dao . insert Music ( music ) ĊĠĠĠĠĠĠĠĠĠĠĠ Ġnew Music . post Value ( Resource . success ( music )) ĊĠĠĠĠĠĠĠ Ġ} ĊĠĠĠ Ġ} ĊĊĠĠĠ Ġprivate Ġfun Ġis File Accept ( file : ĠFile ): ĠBoolean Ġ{ ĊĠĠĠĠĠĠĠ Ġreturn Ġfile . path . endsWith (". mp 3 ", Ġtrue ) ĊĠĠĠ Ġ} ĊĊ Ċ }