/* This file is part of JFLICKS. JFLICKS is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. JFLICKS is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with JFLICKS. If not, see <http://www.gnu.org/licenses/>. */ package org.jflicks.tv.recorder.dvb; import java.io.File; import java.io.IOException; import java.util.HashMap; import org.jflicks.job.JobContainer; import org.jflicks.job.JobEvent; import org.jflicks.job.JobManager; import org.jflicks.job.SystemJob; import org.jflicks.tv.recorder.BaseDeviceJob; import org.jflicks.util.Util; /** * * @author Doug Barnum * @version 1.0 */ public class ScanJob extends BaseDeviceJob { private static final String SERVICE_LINE = "service is running"; private static final String CHANNEL_TEXT = "Channel number:"; private static final String NAME_TEXT = "Name: '"; private static final String VSB_BAD_TEXT = "VSB_8"; private static final String VSB_GOOD_TEXT = "8VSB"; private File file; private String[] args; private String fileText; private String dumpText; /** * Simple no argument constructor. */ public ScanJob() { } /** * Simple no argument constructor. * * @param args The arguments to use. */ public ScanJob(String[] args) { try { File f = File.createTempFile("wscan", ".dump"); fileText = null; dumpText = null; setFile(f); if (args != null) { String[] plus = new String[args.length + 2]; for (int i = 0; i < args.length; i++) { plus[i] = args[i]; } plus[args.length] = ">"; plus[args.length + 1] = f.getPath(); args = plus; } } catch (IOException ex) { } setArgs(args); } private File getFile() { return (file); } private void setFile(File f) { file = f; } private String getDumpText() { return (dumpText); } private void setDumpText(String s) { dumpText = s; } /** * Can't do much work with out arguments to run as a system job. * * @return An array of String instances. */ public String[] getArgs() { return (args); } private void setArgs(String[] array) { args = array; } private String ensurePrintable(String s) { String result = s; if (result != null) { result = result.trim(); char[] chars = result.toCharArray(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < chars.length; i++) { if ((Character.isLetterOrDigit(chars[i])) || (Character.isSpaceChar(chars[i])) || (chars[i] == '.') || (chars[i] == ':') || (chars[i] == '-') || (chars[i] == '_')) { if (chars[i] == ':') { sb.append("."); } else { sb.append(chars[i]); } } } result = sb.toString(); } return (result); } private String parseChannel(String s) { String result = null; if (s != null) { int index = s.indexOf(CHANNEL_TEXT); if (index != -1) { index += CHANNEL_TEXT.length(); int lastIndex = s.indexOf(".", index); if (lastIndex != -1) { result = s.substring(index, lastIndex); if (result != null) { result = ensurePrintable(result); } } } } return (result); } private String parseName(String s) { String result = null; if (s != null) { int index = s.indexOf(NAME_TEXT); if (index != -1) { index += NAME_TEXT.length(); int lastIndex = s.lastIndexOf("'"); if ((lastIndex != -1) && (lastIndex > index)) { result = s.substring(index, lastIndex); if (result != null) { result = ensurePrintable(result); } } else { // This is a hack as a name sometimes doesn't // have an ending tick. So just take the rest... result = ensurePrintable(s.substring(index + 1)); } } } return (result); } /** * Convenience method to parse out the output from the scan program * and format the text so it is proper for our use. * * @return Text usable to write channel config to a conf file. */ public String getFileText() { if (fileText == null) { String output = getDumpText(); if (output != null) { String[] array = output.split("\n"); if ((array != null) && (array.length > 0)) { HashMap<String, String> hm = new HashMap<String, String>(); for (int i = 0; i < array.length; i++) { // We are at the beginning and we look for // lines that "define" a channel number by // it's name - we need to substitute it later... if (array[i].indexOf(CHANNEL_TEXT) != -1) { String channel = parseChannel(array[i]); String name = parseName(array[i]); if ((channel != null) && (name != null)) { hm.put(name, channel); } } } // OK we have built a hash of channel names and // numbers. The next thing to do is load the // file output and replace the name with the proper // number. StringBuilder sb = new StringBuilder(); array = Util.readTextFile(getFile()); for (int i = 0; i < array.length; i++) { // First a hack to fix ATSC bad text. if (array[i].indexOf(VSB_BAD_TEXT) != -1) { array[i] = array[i].replaceAll(VSB_BAD_TEXT, VSB_GOOD_TEXT); } int index = array[i].indexOf(":"); if (index != -1) { String name = array[i].substring(0, index); name = ensurePrintable(name); String rest = array[i].substring(index); String channel = hm.get(name); if (channel != null) { sb.append(channel); sb.append(rest); sb.append("\n"); } } } // Now at this point we should have lines with // the channel numbers instead of the channel // names. if (sb.length() > 0) { fileText = sb.toString(); } } } } return (fileText); } /** * {@inheritDoc} */ public void start() { setTerminate(false); } /** * {@inheritDoc} */ public void run() { SystemJob job = null; String[] myargs = getArgs(); if ((myargs != null) && (args.length > 0)) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < myargs.length; i++) { if (i > 0) { sb.append(" "); } sb.append(args[i]); } job = SystemJob.getInstance(sb.toString()); fireJobEvent(JobEvent.UPDATE, "command:<" + job.getCommand() + ">"); setSystemJob(job); job.addJobListener(this); JobContainer jc = JobManager.getJobContainer(job); setJobContainer(jc); jc.start(); } else { setTerminate(true); } while (!isTerminate()) { JobManager.sleep(getSleepTime()); } fireJobEvent(JobEvent.COMPLETE); } /** * {@inheritDoc} */ public void stop() { setTerminate(true); JobContainer jc = getJobContainer(); if (jc != null) { jc.stop(); setJobContainer(null); } } /** * {@inheritDoc} */ public void jobUpdate(JobEvent event) { if (event.getType() == JobEvent.COMPLETE) { SystemJob job = getSystemJob(); if (job != null) { fireJobEvent(JobEvent.UPDATE, "ProgramJob: exit: " + job.getExitValue()); setDumpText(job.getOutputText()); getFileText(); stop(); } } else { fireJobEvent(JobEvent.UPDATE, event.getMessage()); } } }