private void cleanup(TvShow tvShow) { boolean dirty = false; if (!tvShow.isNewlyAdded()) { // check and delete all not found MediaFiles List<MediaFile> mediaFiles = new ArrayList<MediaFile>(tvShow.getMediaFiles()); for (MediaFile mf : mediaFiles) { if (!mf.getFile().exists()) { tvShow.removeFromMediaFiles(mf); dirty = true; } } List<TvShowEpisode> episodes = new ArrayList<TvShowEpisode>(tvShow.getEpisodes()); for (TvShowEpisode episode : episodes) { mediaFiles = new ArrayList<MediaFile>(episode.getMediaFiles()); for (MediaFile mf : mediaFiles) { if (!mf.getFile().exists()) { episode.removeFromMediaFiles(mf); dirty = true; } } // lets have a look if there is at least one video file for this episode List<MediaFile> mfs = episode.getMediaFiles(MediaFileType.VIDEO); if (mfs.size() == 0) { tvShow.removeEpisode(episode); dirty = true; } } } if (dirty) { tvShow.saveToDb(); } }
@Override public void mouseClicked(MouseEvent arg0) { int col = tableFiles.columnAtPoint(arg0.getPoint()); if (col == 0) { int row = tableFiles.rowAtPoint(arg0.getPoint()); row = tableFiles.convertRowIndexToModel(row); MediaFile mf = mediaFileEventList.get(row); // open the video file in the desired player if (mf.isVideo()) { try { TmmUIHelper.openFile(mf.getFile()); } catch (Exception e) { LOGGER.error("open file", e); MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, mf, "message.erroropenfile", new String[] {":", e.getLocalizedMessage()})); } } // open the graphic in the lightbox if (mf.isGraphic()) { MainWindow.getActiveInstance() .createLightbox(mf.getPath() + File.separator + mf.getFilename(), ""); } } }
/* * update a single TV show */ private void updateTvShows() { // one thread here - more threads killed the UI initThreadPool(1, "update"); for (File tvShowFolder : tvShowFolders) { // check if the tv show dir is accessible File[] filesInDatasourceRoot = tvShowFolder.getParentFile().listFiles(); if (filesInDatasourceRoot == null || filesInDatasourceRoot.length == 0) { LOGGER.warn("TvShow folder not available/empty " + tvShowFolder); MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, "update.datasource", "update.datasource.unavailable", new String[] {tvShowFolder.getParent()})); continue; } if (tvShowFolder.isDirectory()) { submitTask(new FindTvShowTask(tvShowFolder, tvShowFolder.getParent())); } } waitForCompletionOrCancel(); // cleanup setTaskName(BUNDLE.getString("update.cleanup")); setTaskDescription(null); setProgressDone(0); setWorkUnits(0); publishState(); LOGGER.info("removing orphaned movies/files..."); for (int i = tvShowList.getTvShows().size() - 1; i >= 0; i--) { if (cancel) { break; } TvShow tvShow = tvShowList.getTvShows().get(i); // check only Tv shows matching datasource if (!tvShowFolders.contains(new File(tvShow.getPath()))) { continue; } // check and delete all not found MediaFiles cleanup(tvShow); } // start MI setTaskName(BUNDLE.getString("update.mediainfo")); publishState(); initThreadPool(1, "mediainfo"); LOGGER.info("getting Mediainfo..."); for (int i = tvShowList.getTvShows().size() - 1; i >= 0; i--) { if (cancel) { break; } TvShow tvShow = tvShowList.getTvShows().get(i); // check only Tv shows matching datasource if (!tvShowFolders.contains(new File(tvShow.getPath()))) { continue; } gatherMediaInformationForUngatheredMediaFiles(tvShow); } waitForCompletionOrCancel(); if (cancel) { return; } // build up the image cache if (Globals.settings.getTvShowSettings().isBuildImageCacheOnImport()) { List<File> imageFiles = new ArrayList<File>(); for (int i = tvShowList.getTvShows().size() - 1; i >= 0; i--) { if (cancel) { break; } TvShow tvShow = tvShowList.getTvShows().get(i); // check only Tv shows matching datasource if (!tvShowFolders.contains(new File(tvShow.getPath()))) { continue; } for (MediaFile mf : new ArrayList<MediaFile>(tvShow.getMediaFiles())) { if (mf.isGraphic()) { imageFiles.add(mf.getFile()); } } for (TvShowEpisode episode : tvShow.getEpisodes()) { for (MediaFile mf : new ArrayList<MediaFile>(episode.getMediaFiles())) { if (mf.isGraphic()) { imageFiles.add(mf.getFile()); } } } } ImageCacheTask task = new ImageCacheTask(imageFiles); TmmTaskManager.getInstance().addUnnamedTask(task); } }
/* * update one or more datasources */ private void updateDatasource() { List<File> imageFiles = new ArrayList<File>(); for (String path : dataSources) { File[] dirs = new File(path).listFiles(); // check whether the path is accessible (eg disconnected shares) if (dirs == null || dirs.length == 0) { // error - continue with next datasource LOGGER.warn("Datasource not available/empty " + path); MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, "update.datasource", "update.datasource.unavailable", new String[] {path})); continue; } // one thread here - more threads killed the UI initThreadPool(1, "update"); for (File subdir : dirs) { if (cancel) { break; } String directoryName = subdir.getName(); // check against unwanted dirs if (skipFolders.contains(directoryName.toUpperCase()) || directoryName.matches(skipFoldersRegex) || TvShowModuleManager.TV_SHOW_SETTINGS .getTvShowSkipFolders() .contains(subdir.getAbsolutePath())) { LOGGER.info("ignoring directory " + directoryName); continue; } // check this dir as TV show dir if (subdir.isDirectory()) { // check if there is a .tmmignore in this directory File tmmIgnore = new File(subdir, ".tmmignore"); if (!tmmIgnore.exists()) { submitTask(new FindTvShowTask(subdir, path)); } } // video FILE in DS root - not supported! if (subdir.isFile() && Globals.settings .getVideoFileType() .contains("." + FilenameUtils.getExtension(subdir.getName()))) { MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, "update.datasource", "update.datasource.episodeinroot", new String[] {subdir.getName()})); } } waitForCompletionOrCancel(); if (cancel) { break; } // cleanup setTaskName(BUNDLE.getString("update.cleanup")); setTaskDescription(null); setProgressDone(0); setWorkUnits(0); publishState(); LOGGER.info("removing orphaned tv shows/files..."); for (int i = tvShowList.getTvShows().size() - 1; i >= 0; i--) { if (cancel) { break; } TvShow tvShow = tvShowList.getTvShows().get(i); if (!new File(path).equals(new File(tvShow.getDataSource()))) { // check only Tv shows matching datasource continue; } File tvShowDir = new File(tvShow.getPath()); if (!tvShowDir.exists()) { tvShowList.removeTvShow(tvShow); } else { // do a cleanup cleanup(tvShow); } } // mediainfo setTaskName(BUNDLE.getString("update.mediainfo")); publishState(); initThreadPool(1, "mediainfo"); LOGGER.info("getting Mediainfo..."); for (int i = tvShowList.getTvShows().size() - 1; i >= 0; i--) { if (cancel) { break; } TvShow tvShow = tvShowList.getTvShows().get(i); if (!new File(path).equals(new File(tvShow.getDataSource()))) { // check only Tv shows matching datasource continue; } gatherMediaInformationForUngatheredMediaFiles(tvShow); } waitForCompletionOrCancel(); if (cancel) { break; } // build image cache on import if (Globals.settings.getTvShowSettings().isBuildImageCacheOnImport()) { for (TvShow tvShow : new ArrayList<TvShow>(tvShowList.getTvShows())) { if (!new File(path).equals(new File(tvShow.getDataSource()))) { continue; } for (MediaFile mf : new ArrayList<MediaFile>(tvShow.getMediaFiles())) { if (mf.isGraphic()) { imageFiles.add(mf.getFile()); } } for (TvShowEpisode episode : tvShow.getEpisodes()) { for (MediaFile mf : new ArrayList<MediaFile>(episode.getMediaFiles())) { if (mf.isGraphic()) { imageFiles.add(mf.getFile()); } } } } } } if (cancel) { return; } if (imageFiles.size() > 0) { ImageCacheTask task = new ImageCacheTask(imageFiles); TmmTaskManager.getInstance().addUnnamedTask(task); } if (Globals.settings.getTvShowSettings().getSyncTrakt()) { TmmTask task = new SyncTraktTvTask(false, false, true, true); TmmTaskManager.getInstance().addUnnamedTask(task); } }
private static String generateName( String template, TvShow tvShow, MediaFile mf, boolean forFile) { String filename = ""; List<TvShowEpisode> eps = TvShowList.getInstance().getTvEpisodesByFile(tvShow, mf.getFile()); if (eps == null || eps.size() == 0) { // this should not happen, but unluckily ODB does it sometimes; try a second time to get the // episode try { Thread.sleep(250); } catch (Exception ex) { } eps = TvShowList.getInstance().getTvEpisodesByFile(tvShow, mf.getFile()); } if (eps == null || eps.size() == 0) { return ""; } if (StringUtils.isBlank(template)) { filename = createDestination(SETTINGS.getRenamerFilename(), tvShow, eps); } else { filename = createDestination(template, tvShow, eps); } // since we can use this method for folders too, use the next options solely for files if (forFile) { if (mf.getType().equals(MediaFileType.THUMB)) { if (SETTINGS.isUseRenamerThumbPostfix()) { filename = filename + "-thumb"; } // else let the filename as is } if (mf.getType().equals(MediaFileType.FANART)) { filename = filename + "-fanart"; } if (mf.getType().equals(MediaFileType.TRAILER)) { filename = filename + "-trailer"; } if (mf.getType().equals(MediaFileType.VIDEO_EXTRA)) { String name = mf.getBasename(); Pattern p = Pattern.compile("(?i).*([ _.-]extras[ _.-]).*"); Matcher m = p.matcher(name); if (m.matches()) { name = name.substring(m.end(1)); // everything behind } // if not, MF must be within /extras/ folder - use name 1:1 filename = filename + "-extras-" + name; } if (mf.getType().equals(MediaFileType.SUBTITLE)) { List<MediaFileSubtitle> subtitles = mf.getSubtitles(); if (subtitles != null && subtitles.size() > 0) { MediaFileSubtitle mfs = mf.getSubtitles().get(0); if (mfs != null) { if (!mfs.getLanguage().isEmpty()) { filename = filename + "." + mfs.getLanguage(); } if (mfs.isForced()) { filename = filename + ".forced"; } } else { // TODO: meh, we didn't have an actual MF yet - need to parse filename ourselves (like // movie). But with a recent scan of files/DB this // should not occur. } } } } // end forFile // ASCII replacement if (SETTINGS.isAsciiReplacement()) { filename = StrgUtils.convertToAscii(filename, false); } filename = filename + "." + mf.getExtension(); // readd original extension return filename; }
/** * Renames a MediaFiles<br> * gets all episodes of it, creates season folder, updates MFs & DB * * @param mf the MediaFile * @param show the tvshow (only needed for path) */ public static void renameMediaFile(MediaFile mf, TvShow show) { // ####################################################### // Assumption: all multi-episodes share the same season!!! // ####################################################### List<TvShowEpisode> eps = TvShowList.getInstance().getTvEpisodesByFile(show, mf.getFile()); if (eps == null || eps.size() == 0) { // this should not happen, but unluckily ODB does it sometimes; try a second time to get the // episode try { Thread.sleep(250); } catch (Exception e) { } eps = TvShowList.getInstance().getTvEpisodesByFile(show, mf.getFile()); } if (eps == null || eps.size() == 0) { // FIXME: workaround for r1972 // when moving video file, all NFOs get deleted and a new gets created. // so this OLD NFO is not found anylonger - just delete it if (mf.getType() == MediaFileType.NFO) { FileUtils.deleteQuietly(mf.getFile()); return; } LOGGER.warn("No episodes found for file '" + mf.getFilename() + "' - skipping"); return; } // get first, for isDisc and season TvShowEpisode ep = eps.get(0); // test access rights or return LOGGER.debug( "testing file S:" + ep.getSeason() + " E:" + ep.getEpisode() + " MF:" + mf.getFile().getAbsolutePath()); File f = mf.getFile(); boolean testRenameOk = false; for (int i = 0; i < 5; i++) { testRenameOk = f.renameTo(f); // haahaa, try to rename to itself :P if (testRenameOk) { break; // ok it worked, step out } try { if (!f.exists()) { LOGGER.debug("Hmmm... file " + f + " does not even exists; delete from DB"); // delete from MF for (TvShowEpisode e : eps) { e.removeFromMediaFiles(mf); e.saveToDb(); e.writeNFO(); } return; } LOGGER.debug("rename did not work - sleep a while and try again..."); Thread.sleep(1000); } catch (InterruptedException e) { LOGGER.warn("I'm so excited - could not sleep"); } } if (!testRenameOk) { LOGGER.warn("File " + mf.getFile().getAbsolutePath() + " is not accessible!"); MessageManager.instance.pushMessage( new Message(MessageLevel.ERROR, mf.getFilename(), "message.renamer.failedrename")); return; } // create SeasonDir // String seasonName = "Season " + String.valueOf(ep.getSeason()); String seasonName = generateSeasonDir(SETTINGS.getRenamerSeasonFoldername(), ep); File seasonDir = null; if (StringUtils.isNotBlank(seasonName)) { seasonDir = new File(show.getPath(), seasonName); if (!seasonDir.exists()) { seasonDir.mkdir(); } } else { seasonDir = new File(show.getPath()); } // rename epFolder accordingly if (ep.isDisc() || mf.isDiscFile()) { // \Season 1\S01E02E03\VIDEO_TS\VIDEO_TS.VOB // ........ \epFolder \disc... \ file File disc = mf.getFile().getParentFile(); File epFolder = disc.getParentFile(); // sanity check if (!disc.getName().equalsIgnoreCase("BDMV") && !disc.getName().equalsIgnoreCase("VIDEO_TS")) { LOGGER.error( "Episode is labeled as 'on BD/DVD', but structure seems not to match. Better exit and do nothing... o_O"); return; } String newFoldername = FilenameUtils.getBaseName(generateFolderename(show, mf)); // w/o extension if (newFoldername != null && !newFoldername.isEmpty()) { File newEpFolder = new File(seasonDir + File.separator + newFoldername); File newDisc = new File(newEpFolder + File.separator + disc.getName()); // old disc name try { // if (!epFolder.equals(newEpFolder)) { if (!epFolder.getAbsolutePath().equals(newEpFolder.getAbsolutePath())) { boolean ok = false; try { ok = Utils.moveDirectorySafe(epFolder, newEpFolder); } catch (Exception e) { LOGGER.error(e.getMessage()); MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, epFolder.getName(), "message.renamer.failedrename", new String[] {":", e.getLocalizedMessage()})); } if (ok) { // iterate over all EPs & MFs and fix new path LOGGER.debug("updating *all* MFs for new path -> " + newEpFolder); for (TvShowEpisode e : eps) { e.updateMediaFilePath(disc, newDisc); e.setPath(newEpFolder.getPath()); e.saveToDb(); e.writeNFO(); } } // and cleanup cleanEmptyDir(epFolder); } else { // old and new folder are equal, do nothing } } catch (Exception e) { LOGGER.error("error moving video file " + disc.getName() + " to " + newFoldername, e); MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, mf.getFilename(), "message.renamer.failedrename", new String[] {":", e.getLocalizedMessage()})); } } } // end isDisc else { MediaFile newMF = new MediaFile(mf); // clone MF if (mf.getType().equals(MediaFileType.TRAILER)) { // move trailer into separate dir - not supported by XBMC File sample = new File(seasonDir, "sample"); if (!sample.exists()) { sample.mkdir(); } seasonDir = sample; // change directory storage } String filename = generateFilename(show, mf); LOGGER.debug("new filename should be " + filename); if (filename != null && !filename.isEmpty()) { File newFile = new File(seasonDir, filename); try { // if (!mf.getFile().equals(newFile)) { if (!mf.getFile().getAbsolutePath().equals(newFile.getAbsolutePath())) { File oldMfFile = mf.getFile(); boolean ok = false; try { ok = Utils.moveFileSafe(oldMfFile, newFile); } catch (Exception e) { LOGGER.error(e.getMessage()); MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, oldMfFile.getPath(), "message.renamer.failedrename", new String[] {":", e.getLocalizedMessage()})); } if (ok) { newMF.setPath(seasonDir.getAbsolutePath()); newMF.setFilename(filename); // iterate over all EPs and delete old / set new MF for (TvShowEpisode e : eps) { e.removeFromMediaFiles(mf); e.addToMediaFiles(newMF); e.setPath(seasonDir.getAbsolutePath()); e.saveToDb(); e.writeNFO(); } } // and cleanup cleanEmptyDir(oldMfFile.getParentFile()); } else { // old and new file are equal, keep MF } } catch (Exception e) { LOGGER.error( "error moving video file " + mf.getFilename() + " to " + newFile.getPath(), e); MessageManager.instance.pushMessage( new Message( MessageLevel.ERROR, mf.getFilename(), "message.renamer.failedrename", new String[] {":", e.getLocalizedMessage()})); } } } }