Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix progress bar #85

Merged
merged 1 commit into from
Feb 11, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions src/main/java/listfix/io/BufferedProgressReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package listfix.io;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;

public class BufferedProgressReader extends BufferedReader
{

// Used to keep track how much of the file we've read.
private long charsRead = 0;

public BufferedProgressReader(Reader in, int sz)
{
super(in, sz);
}

public BufferedProgressReader(Reader in)
{
super(in);
}

// Custom readLine implementation that appends to the internal cache so we know how much of the file we've read.
@Override
public String readLine() throws IOException
{
String line = super.readLine();
if (line != null)
{
// Not the End-Of-File yet, count bytes
charsRead += line.length() + 1;
}
return line;
}

/**
* @return Number of characters read
*/
public long getCharactersRead() {
return this.charsRead;
}
}
26 changes: 23 additions & 3 deletions src/main/java/listfix/io/playlists/PlaylistReader.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package listfix.io.playlists;

import listfix.io.BufferedProgressReader;
import listfix.io.Constants;
import listfix.io.IPlaylistOptions;
import listfix.model.playlists.FilePlaylistEntry;
Expand All @@ -8,13 +9,16 @@
import listfix.util.ArrayFunctions;
import listfix.util.OperatingSystem;
import listfix.view.GUIScreen;
import org.apache.commons.io.ByteOrderMark;
import org.apache.commons.io.input.BOMInputStream;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.File;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.List;
import java.util.StringTokenizer;
Expand All @@ -25,7 +29,7 @@ public abstract class PlaylistReader implements IPlaylistReader
protected final Path playlistPath;
protected Charset encoding;

private final Logger _logger = LogManager.getLogger(GUIScreen.class);
private final Logger logger = LogManager.getLogger(GUIScreen.class);

public PlaylistReader(IPlaylistOptions playListOptions, Path playlistPath) {
this.playListOptions = playListOptions;
Expand All @@ -43,6 +47,22 @@ public Charset getEncoding()
return this.encoding;
}

public BufferedProgressReader openBufferedReader(Path textFile) throws IOException
{
final BOMInputStream bomInputStream = new BOMInputStream(new FileInputStream(textFile.toFile()),
ByteOrderMark.UTF_8,
ByteOrderMark.UTF_16BE,
ByteOrderMark.UTF_16LE,
ByteOrderMark.UTF_32BE,
ByteOrderMark.UTF_32LE
);
final String charsetName = bomInputStream.getBOMCharsetName();
this.encoding = charsetName == null ? StandardCharsets.UTF_8 : Charset.forName(charsetName);

this.logger.info(String.format("Detected playlist file encoding for \"%s\": %s", textFile.getFileName().toString(), this.encoding.name()));
return new BufferedProgressReader(new InputStreamReader(bomInputStream, this.encoding));
}

protected void processEntry(List<PlaylistEntry> results, String L2, String cid, String tid)
{
StringTokenizer pathTokenizer = null;
Expand Down Expand Up @@ -156,7 +176,7 @@ else if (L2.startsWith("\\\\") && pathTokenizer.countTokens() >= 1
}
catch (URISyntaxException e)
{
this._logger.warn("While adding URI entry to playlist", e);
this.logger.warn("While adding URI entry to playlist", e);
throw new RuntimeException(e);
}
}
Expand Down
191 changes: 78 additions & 113 deletions src/main/java/listfix/io/playlists/m3u/M3UReader.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,50 +20,32 @@

package listfix.io.playlists.m3u;

import listfix.io.BufferedProgressReader;
import listfix.io.IPlaylistOptions;
import listfix.io.UnicodeInputStream;
import listfix.io.playlists.PlaylistReader;
import listfix.model.enums.PlaylistType;
import listfix.model.playlists.PlaylistEntry;
import listfix.view.support.IProgressObserver;
import listfix.view.support.ProgressAdapter;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.*;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

/**
* Reads in a M3U/M3U8 file and returns a List containing PlaylistEntries that represent the files & URIs in the playlist.
*
* @author jcaron
*/
public class M3UReader extends PlaylistReader
{
private final BufferedReader buffer;
private final List<PlaylistEntry> results = new ArrayList<>();
private final long fileLength;
private static final PlaylistType type = PlaylistType.M3U;
private static final Logger _logger = LogManager.getLogger(M3UReader.class);

private StringBuilder _cache;

public M3UReader(IPlaylistOptions playListOptions, Path m3uPath) throws FileNotFoundException
public M3UReader(IPlaylistOptions playListOptions, Path m3uPath) throws IOException
{
super(playListOptions, m3uPath);

File m3uFile = m3uPath.toFile();

// encoding = UnicodeUtils.getEncoding(m3uFile);
UnicodeInputStream unicodeInputStream = new UnicodeInputStream(new FileInputStream(m3uFile), StandardCharsets.UTF_8);
this.encoding = Charset.forName(unicodeInputStream.getEncoding());
_logger.info(String.format("Detected M3U encoding for \"%s\": %s", m3uPath.getFileName().toString(), this.encoding.name()));
buffer = new BufferedReader(new InputStreamReader(unicodeInputStream, this.encoding));
fileLength = m3uFile.length();
}

@Override
Expand All @@ -81,114 +63,107 @@ public PlaylistType getPlaylistType()
@Override
public List<PlaylistEntry> readPlaylist(IProgressObserver<String> observer) throws IOException
{
// See http://gonze.com/playlists/playlist-format-survey.html#M3U for the format of an M3U file.
// Line1 holds the metadata about the file that we just hang on to, line2 represents the file reference.

//Initialize the progress adapter if we're given an observer.
ProgressAdapter<String> progress = ProgressAdapter.wrap(observer);
long fileLength = Files.size(this.playlistPath);

_cache = new StringBuilder();
String line1 = readLine();
String line2;
if (line1 != null)
try (BufferedProgressReader buffer = openBufferedReader(this.playlistPath))
{
// Ignore the standard M3U header and random mediamonkey crap.
while (line1.contains("#EXTM3U") || line1.startsWith("#EXTINFUTF8") || line1.isEmpty())
{
line1 = readLine();
if (line1 == null)
{
// needed to handle empty playlists
return results;
}
}
// See http://gonze.com/playlists/playlist-format-survey.html#M3U for the format of an M3U file.
// Line1 holds the metadata about the file that we just hang on to, line2 represents the file reference.

// If after skipping that line the line doesn't start w/ a #, then we already have the file reference. Stuff that into line2.
if (!line1.startsWith("#"))
{
line2 = line1;
line1 = "";
}
else
{
// Otherwise, read in the next line which should be our file reference.
line2 = readLine();
while (line2.startsWith("#"))
{
// throw away non-standard metadata added by mediamonkey...
line2 = readLine();
}
}

// Declare this variable outside the loop so we don't do it over and over.
int cacheSize;
//Initialize the progress adapter if we're given an observer.
ProgressAdapter<String> progress = ProgressAdapter.wrap(observer);
progress.setTotal(fileLength);

while (line1 != null)
String line1 = buffer.readLine();
String line2;
if (line1 != null)
{
// If we have an observer and the user cancelled, bail out.
if (observer != null)
// Ignore the standard M3U header and random mediamonkey crap.
while (line1.contains("#EXTM3U") || line1.startsWith("#EXTINFUTF8") || line1.isEmpty())
{
if (observer.getCancelled())
line1 = buffer.readLine();
if (line1 == null)
{
return null;
// needed to handle empty playlists
return results;
}
}

// Process the two strings we have into a playlist entry
processEntry(line2, line1);

// We just processed an entry, update the progress bar w/ the % of the file we've read if we have an observer.
cacheSize = _cache.toString().getBytes().length;
if (cacheSize < fileLength)
// If after skipping that line the line doesn't start w/ a #, then we already have the file reference. Stuff that into line2.
if (!line1.startsWith("#"))
{
progress.setCompleted(cacheSize);
line2 = line1;
line1 = "";
}

// Start processing the next entry.
line1 = readLine();
if (line1 != null)
else
{
// WMP produces M3Us with spaces between entries... have to read in an extra line to avoid this if line1 is empty.
// Let's also handle an arbitrary number of spaces between the entries while we're at it.
while (line1.isEmpty())
// Otherwise, read in the next line which should be our file reference.
line2 = buffer.readLine();
while (line2.startsWith("#"))
{
line1 = readLine();
// throw away non-standard metadata added by mediamonkey...
line2 = buffer.readLine();
}
}

// And of course WMP ends the file w/ several blank lines, so if we find a null here return what we have...
if (line1 == null)
while (line1 != null)
{
// If we have an observer and the user cancelled, bail out.
if (observer != null)
{
if (observer.getCancelled())
{
// Fill the progress bar
progress.setCompleted((int) fileLength);

return results;
return null;
}
}

if (!line1.startsWith("#"))
{
line2 = line1;
line1 = "";
}
else
// Process the two strings we have into a playlist entry
processEntry(line2, line1);

// We just processed an entry, update the progress bar w/ the % of the file we've read if we have an observer.
long bytesRead = Math.min(fileLength, buffer.getCharactersRead());
progress.setCompleted((int) bytesRead);

// Start processing the next entry.
line1 = buffer.readLine();
if (line1 != null)
{
line2 = readLine();
while (line2.startsWith("#"))
// WMP produces M3Us with spaces between entries... have to read in an extra line to avoid this if line1 is empty.
// Let's also handle an arbitrary number of spaces between the entries while we're at it.
while (line1.isEmpty())
{
line1 = buffer.readLine();

// And of course WMP ends the file w/ several blank lines, so if we find a null here return what we have...
if (line1 == null)
{
// Fill the progress bar
progress.setCompleted(fileLength);

return results;
}
}

if (!line1.startsWith("#"))
{
// throw away non-standard metadata added by mediamonkey...
line2 = readLine();
line2 = line1;
line1 = "";
}
else
{
line2 = buffer.readLine();
while (line2.startsWith("#"))
{
// throw away non-standard metadata added by mediamonkey...
line2 = buffer.readLine();
}
}
}
}
}
progress.setCompleted((int) fileLength);
return results;
}

// Close the reader
buffer.close();

// Fill the progress bar
progress.setCompleted((int) fileLength);

return results;
}

@Override
Expand All @@ -198,16 +173,6 @@ public List<PlaylistEntry> readPlaylist() throws IOException
return results;
}

// Custom readLine implementation that appends to the internal cache so we know how much of the file we've read.
private String readLine() throws IOException
{
String line = buffer.readLine();
if (_cache != null)
{
_cache.append(line);
}
return line;
}

private void processEntry(String L2, String extInf)
{
Expand Down
Loading