package net.pms.util;
import java.io.File;
import java.util.Iterator;
import java.util.Map;
import net.pms.PMS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InfoDb implements DbHandler {
public static class InfoDbData {
public String imdb;
public String ep_name;
public String year;
public String season;
public String episode;
public String title;
}
private static final Logger LOGGER = LoggerFactory.getLogger(InfoDb.class);
private static final long REDO_PERIOD = 7 * 24 * 60 * 60 * 1000; // one week
private static final String LAST_INFO_REREAD_KEY = "lastInfoReread";
private FileDb db;
public InfoDb() {
db = new FileDb(this);
db.setMinCnt(6);
db.setUseNullObj(true);
db.init();
if (PMS.getKey(LAST_INFO_REREAD_KEY) == null) {
PMS.setKey(LAST_INFO_REREAD_KEY, "" + System.currentTimeMillis());
}
redoNulls();
}
private void askAndInsert(File f, String formattedName) {
synchronized (db) {
try {
String[] tmp = OpenSubtitle.getInfo(f, formattedName);
Object obj = db.nullObj();
if (tmp != null) {
obj = create(tmp, 0);
}
db.add(f.getAbsolutePath(), obj);
} catch (Exception e) {
LOGGER.error("Error while inserting in InfoDb: {}", e.getMessage());
LOGGER.trace("", e);
}
}
}
public void backgroundAdd(final File f, final String formattedName) {
synchronized (db) {
if (db.get(f.getAbsolutePath()) != null) {
// we need to use the raw get to see so it's
// truly null
// also see if we should redo
redoNulls();
return;
}
}
Runnable r = new Runnable() {
@Override
public void run() {
askAndInsert(f, formattedName);
}
};
new Thread(r).start();
}
public void moveInfo(File old_file, File new_file) {
synchronized (db) {
InfoDbData data = get(old_file);
if (data != null) {
db.removeNoSync(old_file.getAbsolutePath());
db.addNoSync(new_file.getAbsolutePath(), data);
db.sync();
}
}
}
public InfoDbData get(File f) {
return get(f.getAbsolutePath());
}
public InfoDbData get(String f) {
synchronized (db) {
Object obj = db.get(f);
return (InfoDbData) (db.isNull(obj) ? null : obj);
}
}
@Override
public Object create(String[] args) {
return create(args, 1);
}
public Object create(String[] args, int off) {
InfoDbData data = new InfoDbData();
data.imdb = FileDb.safeGetArg(args, off);
data.ep_name = FileDb.safeGetArg(args, off + 1);
data.title = FileDb.safeGetArg(args, off + 2);
data.season = FileDb.safeGetArg(args, off + 3);
data.episode = FileDb.safeGetArg(args, off + 4);
data.year = FileDb.safeGetArg(args, off + 5);
return data;
}
@Override
public String[] format(Object obj) {
InfoDbData data = (InfoDbData) obj;
return new String[]{
data.imdb,
data.ep_name,
data.title,
data.season,
data.episode,
data.year
};
}
@Override
public String name() {
return "InfoDb.db";
}
private boolean redo() {
long now = System.currentTimeMillis();
long last = now;
try {
last = Long.parseLong(PMS.getKey(LAST_INFO_REREAD_KEY));
} catch (NumberFormatException e) {
}
return (now - last) > REDO_PERIOD;
}
private void redoNulls() {
synchronized (db) {
// no nulls in db skip this
if (!db.hasNulls()) {
return;
}
if (!redo() || !PMS.getConfiguration().isInfoDbRetry()) {
// no redo
return;
}
}
// update this first to make redo() return false for other
PMS.setKey(LAST_INFO_REREAD_KEY, "" + System.currentTimeMillis());
Runnable r = new Runnable() {
@Override
public void run() {
synchronized (db) {
// this whole iterator stuff is to avoid
// CMEs
Iterator it = db.iterator();
boolean sync = false;
while (it.hasNext()) {
Map.Entry kv = (Map.Entry) it.next();
String key = (String) kv.getKey();
// nonNull -> no need to ask again
if (!db.isNull(kv.getValue())) {
continue;
}
File f = new File(key);
String name = f.getName();
try {
String[] tmp = OpenSubtitle.getInfo(f, name);
// if we still get nothing from opensubs
// we don't fiddle with the db
if (tmp != null) {
kv.setValue(create(tmp, 0));
sync = true;
}
} catch (Exception e) {
LOGGER.error("Exception in redoNulls: {}", e.getMessage());
LOGGER.trace("", e);
}
}
if (sync) {
// we need a manual sync here
db.sync();
}
}
}
};
new Thread(r).start();
}
}