1   package com.webstersmalley.iplayer.organiser;
2   
3   /**
4    *    Copyright 2009 Webster Smalley
5    *
6    *   Licensed under the Apache License, Version 2.0 (the "License");
7    *   you may not use this file except in compliance with the License.
8    *   You may obtain a copy of the License at
9    *
10   *       http://www.apache.org/licenses/LICENSE-2.0
11   *
12   *   Unless required by applicable law or agreed to in writing, software
13   *   distributed under the License is distributed on an "AS IS" BASIS,
14   *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   *   See the License for the specific language governing permissions and
16   *   limitations under the License.
17   *
18   */
19  
20  import java.io.File;
21  import java.io.FilenameFilter;
22  
23  import org.apache.log4j.Logger;
24  import org.blinkenlights.jid3.ID3Exception;
25  import org.blinkenlights.jid3.ID3Tag;
26  import org.blinkenlights.jid3.MP3File;
27  import org.blinkenlights.jid3.MediaFile;
28  import org.blinkenlights.jid3.v1.ID3V1_0Tag;
29  import org.blinkenlights.jid3.v1.ID3V1_1Tag;
30  import org.blinkenlights.jid3.v1.ID3V1Tag.Genre;
31  import org.blinkenlights.jid3.v2.ID3V2Tag;
32  import org.blinkenlights.jid3.v2.ID3V2_3_0Tag;
33  import org.springframework.context.ApplicationContext;
34  import org.springframework.context.support.ClassPathXmlApplicationContext;
35  
36  import com.webstersmalley.iplayer.mp3.MP3Utils;
37  
38  public class Retagger {
39  	protected class MP3FilenameFilter implements FilenameFilter {
40  
41  		public boolean accept(File dir, String name) {
42  			return name.toLowerCase().matches(".*\\.mp3");
43  		}
44  
45  	}
46  
47  	private Logger logger = Logger.getLogger(getClass());
48  
49  	private String inputFolder;
50  	private String outputFolder;
51  	private RadioProgramBeanFactory beanFactory;
52  
53  	public RadioProgramBeanFactory getBeanFactory() {
54  		return beanFactory;
55  	}
56  
57  	public void setBeanFactory(RadioProgramBeanFactory beanFactory) {
58  		this.beanFactory = beanFactory;
59  	}
60  
61  	public String getInputFolder() {
62  		return inputFolder;
63  	}
64  
65  	public void setInputFolder(String inputFolder) {
66  		this.inputFolder = inputFolder;
67  	}
68  
69  	public String getOutputFolder() {
70  		return outputFolder;
71  	}
72  
73  	public void setOutputFolder(String outputFolder) {
74  		this.outputFolder = outputFolder;
75  	}
76  
77  	private void rewriteID3Tags(File mp3file, RadioProgramBean bean) {
78  
79  		logger.info("Title: " + bean.getEpisodeTitle());
80  		logger.info("Info: " + bean);
81  		MediaFile mediaFile = new MP3File(mp3file);
82  		boolean tagsExist = false;
83  		try {
84  			ID3Tag[] tags = mediaFile.getTags();
85  			mediaFile.removeTags();
86  			for (ID3Tag tag : tags) {
87  				if (tag instanceof ID3V1_0Tag) {
88  					logger.info("Rewriting id3 1.0 tag");
89  					ID3V1_0Tag v10tag = (ID3V1_0Tag) tag;
90  					v10tag.setTitle(bean.getEpisodeTitle());
91  					v10tag.setGenre(Genre.Vocal);
92  					v10tag.setAlbum(bean.getSeriesTitle());
93  					v10tag.setArtist(bean.getArtist());
94  					mediaFile.setID3Tag(v10tag);
95  					tagsExist = true;
96  				} else if (tag instanceof ID3V1_1Tag) {
97  					logger.info("Rewriting id3 1.1 tag");
98  					ID3V1_1Tag v11tag = (ID3V1_1Tag) tag;
99  					v11tag.setTitle(bean.getEpisodeTitle());
100 					v11tag.setGenre(Genre.Vocal);
101 					v11tag.setAlbum(bean.getSeriesTitle());
102 					v11tag.setArtist(bean.getArtist());
103 					mediaFile.setID3Tag(v11tag);
104 					tagsExist = true;
105 				} else if (tag instanceof ID3V2Tag) {
106 					logger.info("Rewriting id3 2 tag");
107 					ID3V2Tag v2tag = (ID3V2Tag) tag;
108 					v2tag.setTitle(bean.getEpisodeTitle());
109 					v2tag.setGenre("Audio book/play");
110 					v2tag.setAlbum(bean.getSeriesTitle());
111 					v2tag.setArtist(bean.getArtist());
112 					mediaFile.setID3Tag(v2tag);
113 					tagsExist = true;
114 				} else if (tag instanceof ID3V2_3_0Tag) {
115 					logger.info("Rewriting id3 2.3.0 tag");
116 					ID3V2_3_0Tag v230tag = (ID3V2_3_0Tag) tag;
117 					v230tag.setTitle(bean.getEpisodeTitle());
118 					v230tag.setGenre("Audio book/play");
119 					v230tag.setAlbum(bean.getSeriesTitle());
120 					v230tag.setArtist(bean.getArtist());
121 					mediaFile.setID3Tag(v230tag);
122 					tagsExist = true;
123 				}
124 			}
125 			if (!tagsExist) {
126 				logger.info("Creating new tag");
127 				ID3V2_3_0Tag tag = new ID3V2_3_0Tag();
128 				tag.setTitle(bean.getEpisodeTitle());
129 				mediaFile.setID3Tag(tag);
130 			}
131 			mediaFile.sync();
132 		} catch (ID3Exception e) {
133 			logger.error("Error updating tags: ", e);
134 			throw new RuntimeException("Error updating tags: " + e.getMessage());
135 		}
136 	}
137 
138 	private void moveFile(File file, RadioProgramBean bean) {
139 		String folder = outputFolder + File.separator + bean.getFolder();
140 		String filename = folder + File.separator + bean.getFilename();
141 
142 		File folderFile = new File(folder);
143 		if (!folderFile.exists()) {
144 			if (!folderFile.mkdirs()) {
145 				throw new RuntimeException("Error creating folder: " + folder);
146 			}
147 		} else {
148 			if (!folderFile.isDirectory()) {
149 				throw new RuntimeException("Error creating folder: " + folder + " - it already exists but is not a directory...!");
150 			}
151 		}
152 		file.renameTo(new File(filename));
153 	}
154 
155 	private void processFile(File file) {
156 		RadioProgramBean bean = beanFactory.getBeanFromFile(file.getName());
157 		rewriteID3Tags(file, bean);
158 		moveFile(file, bean);
159 	}
160 
161 	public void go() {
162 		logger.info("Opening folder: " + inputFolder);
163 		File folder = new File(inputFolder);
164 		if (!folder.isDirectory()) {
165 			throw new RuntimeException("Given folder name is not a folder or does not exist");
166 		}
167 		File[] files = folder.listFiles(new MP3FilenameFilter());
168 
169 		for (File file : files) {
170 			processFile(file);
171 		}
172 	}
173 
174 	public static void main(String[] args) {
175 		ApplicationContext ac = new ClassPathXmlApplicationContext("beans-production.xml");
176 		Retagger retagger = (Retagger) ac.getBean("retagger");
177 		retagger.go();
178 	}
179 }