
Sometimes I write a small program to deal with a minor inconvenience. This is one of those programs.
Spotify for Android decided to start doing something annoying recently. For several years it has been happily connecting to my car's bluetooth, auto playing, and then auto stopping when the car is turned off. That last part is what stopped working. Now when I turn off my car Spotify continues playing through the phone speaker. Literally no one would ever want things to work this way. I went through every setting in Spotify and on my phone twice. I read all the usual support articles. Most of them blame Android Auto which I don't have enabled. I quit.
Then I remembered my car has a couple USB ports that can play mp3s. It's pretty low tech, a $10 mp3 player has more features. I don't need much though. I just want it to play a random assortment of songs like how shuffle works on Spotify. Well, except for "Smart" Shuffle. Any time I accidentally click that it ruins my entire day.
So here's what I need a program to do:
Of course this will all work with any file type, I only care about copying mp3s in a random order today. For example this code could copy a random list of PDFs to a book reader. I will probably even do that with it one day. It would also work for an offline digital photo frame to shuffle the pictures every few months.
The first part to write is code to rename files. There are a couple reasons this is needed:
And the code goes like...
public static String buildUUIDName(File f,boolean preserveExtension){
String currentFileName=f.getName();
String newFileName=UUID.randomUUID().toString().replace("-","");
if(preserveExtension){
newFileName=newFileName+getExtension(currentFileName);
}
return(newFileName);
}
There are many other perfectly good ways to solve this problem. Like simply renaming the files "000001.mp3" and so on.
Now the code to copy the files... after some notes about the parameters and return type:
public static Map<String,String> shuffleCopy(List<String> sourceFileList,String destinationPath,boolean uuidRename,long maxBytesKillswitch){
Map<String,String> copyMap=new HashMap<String,String>();
if(sourceFileList==null){
return(copyMap);
}
if(!destinationPath.endsWith(File.separator)){
destinationPath=destinationPath+File.separator;
}
File destinationRoot=new File(destinationPath);
if(!destinationRoot.exists()){
return(copyMap);
}
int filesRemaining=sourceFileList.size();
Random r=new Random();
while((filesRemaining>0)&&(maxBytesKillswitch>0)){
int index=r.nextInt(filesRemaining);
String filePath=sourceFileList.remove(index);
filesRemaining--;
//is there room for this file?
File source=new File(filePath);
long sourceSize=source.length();
long usableSpace=destinationRoot.getUsableSpace();//yes, need to check this each time in case on concurrent operations
if(sourceSize<usableSpace){
try{
String fileName;
if(uuidRename){
fileName=buildUUIDName(source,true);
}else{
fileName=source.getName();
}
File destination=new File(destinationPath+File.separator+fileName);
Files.copy(source.toPath(),destination.toPath(),StandardCopyOption.COPY_ATTRIBUTES);
copyMap.put(filePath,destination.getPath());
maxBytesKillswitch-=sourceSize;
}catch(IOException iox){
if(iox.getMessage().toLowerCase().contains("no space left on device")){
filesRemaining=-1;
}
}
}
}
return(copyMap);
}
It's pretty simple really. Some notes about it:
Here's a main class to call this code and display the results:
import java.io.IOException;
import java.util.ArrayList;
import java.util.Map;
import com.huguesjohnson.dubbel.file.FileUtils;
public class SDCardRandomFill{
public static void main(String[] args){
String destinationPath="[path to where you want to copy files]";
//build the list of files
ArrayList<String> filePathList=[whatever you want to do to build a list of file paths];
//try copying
long maxBytesKillswitch=Long.MAX_VALUE; //or something like 32*1024*1024*1024 if you prefer;
Map<String,String> copyMap=FileUtils.shuffleCopy(filePathList,destinationPath,true,maxBytesKillswitch);
for(String key:copyMap.keySet()){
String value=copyMap.get(key);
System.out.println(key+"|"+value);
}
}
}
Alright, this was fun and something I will use often.
Related