2 * Copyright 2006 the original author or authors.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package org.wamblee.mythtv;
20 import java.io.IOException;
21 import java.text.SimpleDateFormat;
22 import java.util.HashMap;
25 import org.apache.commons.logging.Log;
26 import org.apache.commons.logging.LogFactory;
27 import org.wamblee.io.SimpleProcess;
28 import org.wamblee.io.DirectoryMonitor.Listener;
33 * @author Erik Brakkee
35 public class LinkStructure implements Listener {
37 private static final Log LOG = LogFactory.getLog(LinkStructure.class);
39 private String _monitorDir;
41 private File _linkDir;
43 private RecordingDatabase _database;
45 private SimpleDateFormat _format;
47 private Map<File,Recording> _recordings;
49 public LinkStructure(String aMonitorDir, File aLinkDir,
50 RecordingDatabase aDatabase) {
51 _monitorDir = aMonitorDir + "/";
54 _database = aDatabase;
55 _format = new SimpleDateFormat("yyyy-MM-dd-HH:mm");
56 _recordings = new HashMap<File,Recording>();
59 private void deleteDir(File aFile) {
60 for (File file: aFile.listFiles()) {
61 if ( file.isDirectory()) {
64 LOG.info("File deleted " + file + ": " + file.delete());
71 * @see org.wamblee.io.DirectoryMonitor.Listener#fileChanged(java.io.File)
73 public void fileChanged(File aFile) {
74 LOG.debug("file changed " + aFile);
76 // Re-assess file type
77 Recording recording = _recordings.get(aFile);
78 LOG.info("Recording changed " + recording);
79 recording.setFilesize(aFile.length());
80 _database.update(recording);
81 String dir = getDirectory(recording);
82 FileType type = getFileType(aFile);
83 String path = dir + "/" + getFilename(recording, type);
85 if (exists(dir + "/" + getFilename(recording, type))) {
89 for (FileType t : FileType.values()) {
90 rmlink(dir + "/" + getFilename(recording, t));
92 createSymLink(_monitorDir + aFile.getName(), dir + "/"
93 + getFilename(recording, type));
100 * @see org.wamblee.io.DirectoryMonitor.Listener#fileCreated(java.io.File)
102 public void fileCreated(File aFile) {
103 LOG.debug("file created " + aFile);
104 Recording recording = _database.findRecording(aFile.getName());
105 if ( recording == null ) {
106 LOG.warn("Spurious recording which should not exist according to mythtv: " + aFile);
109 _recordings.put(aFile, recording);
110 LOG.info("New recording detected " + aFile + " "
113 recording.setFilesize(aFile.length());
114 _database.update(recording);
115 String dir = getDirectory(recording);
117 createSymLink(_monitorDir + aFile.getName(), dir + "/"
118 + getFilename(recording, getFileType(aFile)));
124 * @see org.wamblee.io.DirectoryMonitor.Listener#fileDeleted(java.io.File)
126 public void fileDeleted(File aFile) {
127 LOG.debug("file deleted " + aFile);
128 Recording recording = _recordings.get(aFile);
129 _recordings.remove(recording);
130 // mythtv will remove the recording from its database itself.
131 LOG.info("recording deleted " + recording);
132 String dir = getDirectory(recording);
133 for (FileType t: FileType.values()) {
134 rmlink(dir + "/" + getFilename(recording, t));
139 private String getDirectory(Recording aRecording) {
140 return aRecording.getTitle().replaceAll("/", "-");
143 private FileType getFileType(File aFile) {
144 SimpleProcess process = new SimpleProcess(new File(_monitorDir), new String[] {
145 "file", aFile.getName() });
148 if (process.getStdout().contains("RIFF")) {
153 } catch (IOException e) {
154 LOG.error("Determining filetype for " + aFile + " failed", e);
159 private String getFilename(Recording aRecording, FileType aType) {
160 return (_format.format(aRecording.getProgstart()) + "-"
161 + aRecording.getSubtitle() + "-"
162 + aRecording.getChannel().getName() + "."
163 + aType.toString().toLowerCase()).replaceAll("/", "-");
166 private boolean exists(String aPath) {
167 LOG.debug("exists " + aPath);
168 return new File(_linkDir, aPath).exists();
171 private void rmlink(String aPath) {
172 LOG.debug("rmlink " + aPath);
173 File link = new File(_linkDir, aPath);
174 //if ( !link.exists()) {
177 if (!link.delete()) {
178 LOG.warn("Delete failed: " + aPath);
180 LOG.info("Removed link " + link);
184 private void mkdir(String aDir) {
185 LOG.debug("mkdir " + aDir);
186 File dir = new File(_linkDir, aDir);
187 if ( dir.isDirectory()) {
191 LOG.warn("Could not create directory path: " + aDir);
193 LOG.info("Created directory " + dir);
197 private void rmdir(String aDir) {
198 LOG.debug("rmdir " + aDir);
199 File dir = new File(_linkDir, aDir);
201 LOG.warn("Directory not deleted (still recordings left): " + aDir);
203 LOG.info("Directory " + dir + " deleted.");
207 private void createSymLink(String aTarget, String aSource) {
209 SimpleProcess process = new SimpleProcess(_linkDir, new String[] {
210 "ln", "-s", aTarget, aSource });
212 LOG.info("Created symlink " + aSource + " -> " + aTarget);
213 } catch (IOException e) {
215 "Could not create symlink: " + aTarget + " <- " + aSource,