org.tinymediamanager.TinyMediaManagerCMD Maven / Gradle / Ivy
The newest version!
/*
* Copyright 2012 - 2019 Manuel Laggner
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.tinymediamanager;
import static org.tinymediamanager.TinyMediaManager.shutdownLogger;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Locale;
import javax.swing.SwingWorker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tinymediamanager.core.ExportTemplate;
import org.tinymediamanager.core.MediaEntityExporter.TemplateType;
import org.tinymediamanager.core.entities.MediaFile;
import org.tinymediamanager.core.movie.MovieComparator;
import org.tinymediamanager.core.movie.MovieExporter;
import org.tinymediamanager.core.movie.MovieList;
import org.tinymediamanager.core.movie.MovieModuleManager;
import org.tinymediamanager.core.movie.MovieSearchAndScrapeOptions;
import org.tinymediamanager.core.movie.entities.Movie;
import org.tinymediamanager.core.movie.tasks.MovieRenameTask;
import org.tinymediamanager.core.movie.tasks.MovieScrapeTask;
import org.tinymediamanager.core.movie.tasks.MovieUpdateDatasourceTask;
import org.tinymediamanager.core.tasks.UpdaterTask;
import org.tinymediamanager.core.threading.TmmTask;
import org.tinymediamanager.core.threading.TmmTaskManager;
import org.tinymediamanager.core.tvshow.TvShowComparator;
import org.tinymediamanager.core.tvshow.TvShowExporter;
import org.tinymediamanager.core.tvshow.TvShowList;
import org.tinymediamanager.core.tvshow.TvShowModuleManager;
import org.tinymediamanager.core.tvshow.TvShowSearchAndScrapeOptions;
import org.tinymediamanager.core.tvshow.entities.TvShow;
import org.tinymediamanager.core.tvshow.entities.TvShowEpisode;
import org.tinymediamanager.core.tvshow.tasks.TvShowEpisodeScrapeTask;
import org.tinymediamanager.core.tvshow.tasks.TvShowRenameTask;
import org.tinymediamanager.core.tvshow.tasks.TvShowScrapeTask;
import org.tinymediamanager.core.tvshow.tasks.TvShowUpdateDatasourceTask;
import org.tinymediamanager.scraper.util.StrgUtils;
/**
* The class TinyMediaManagerCMD - used for all logic for the command line tool
*
* @author Manuel Laggner
*/
public class TinyMediaManagerCMD {
private static final Logger LOGGER = LoggerFactory.getLogger(TinyMediaManagerCMD.class);
private static boolean updateMovies = false;
private static boolean updateTv = false;
private static boolean scrapeAll = false;
private static boolean scrapeNew = false;
private static boolean scrapeUnscraped = false;
private static boolean rename = false;
private static boolean dryRun = false;
private static boolean checkFiles = false;
private static boolean export = false;
// datasource IDs
private static HashSet updateMovieDs = new HashSet<>();
private static HashSet updateTvDs = new HashSet<>();
private static Path exportTemplate = null;
private static Path exportDir = null;
/**
* parse command line params
*
* @param args
* an array of params to parse
*/
static void parseParams(String[] args) {
for (int i = 0; i < args.length; i++) {
String cmd = args[i];
if (cmd.equalsIgnoreCase("-updateMovies")) {
updateMovies = true;
}
else if (cmd.matches("(?)-updateMovies[1-9]")) {
updateMovies = true;
updateMovieDs.add(Integer.parseInt(StrgUtils.substr(cmd, "(?)-updateMovies(\\d)")));
}
else if (cmd.equalsIgnoreCase("-updateTv")) {
updateTv = true;
}
else if (cmd.matches("(?)-updateTv[1-9]")) {
updateTv = true;
updateTvDs.add(Integer.parseInt(StrgUtils.substr(cmd, "(?)-updateTv(\\d)")));
}
else if (cmd.equalsIgnoreCase("-update")) {
updateMovies = true;
updateTv = true;
}
else if (cmd.equalsIgnoreCase("-scrapeNew")) {
scrapeNew = true;
}
else if (cmd.equalsIgnoreCase("-scrapeAll")) {
scrapeAll = true;
}
else if (cmd.equalsIgnoreCase("-scrapeUnscraped")) {
scrapeUnscraped = true;
}
else if (cmd.equalsIgnoreCase("-dryRun")) {
dryRun = true;
if (args.length == 1) {
// haahaa - we specified dryRun as only argument
printSyntax();
shutdownLogger();
System.exit(0);
}
}
else if (cmd.equalsIgnoreCase("-checkFiles")) {
checkFiles = true;
}
else if (cmd.equalsIgnoreCase("-rename") || cmd.equalsIgnoreCase("-renameNew")) { // "new" deprecated
rename = true;
}
// else if (cmd.equalsIgnoreCase("-config")) {
// i++;
// if (i == args.length) { // config is last parameter
// System.out.println("ERROR: config not specified!");
// printSyntax();
// System.exit(0);
// }
// String file = args[i];
// if (Files.exists(Paths.get("data", file))) { // only check in default data path?
// // load custom settings
// Settings.getInstance("data", file);
// }
// else {
// System.out.println("ERROR: config file not found! " + file);
// printSyntax();
// System.exit(0);
// }
// }
// ************
// ** EXPORT **
// ************
else if (cmd.equalsIgnoreCase("-export")) {
try {
i++;
if (i == args.length || i == args.length - 1) { // export needs 2 parameters
throw new Exception("missing parameters");
}
exportTemplate = Paths.get("templates", args[i]);
if (!Files.isDirectory(exportTemplate)) {
throw new IOException("template folder not found/accessible");
}
i++;
exportDir = Paths.get(args[i]);
export = true;
}
catch (Exception e) {
System.out.println("ERROR: export failed because of: " + e.getMessage());
printSyntax();
shutdownLogger();
System.exit(0);
}
}
else if (cmd.toLowerCase(Locale.ROOT).contains("help")) { // -help, --help, help ...
printSyntax();
shutdownLogger();
System.exit(0);
}
else {
System.out.println("ERROR: unrecognized command " + cmd);
printSyntax();
shutdownLogger();
System.exit(0);
}
}
}
/**
* print the syntax to command line
*/
static void printSyntax() {
// @formatter:off
System.out.println("\n" +
"=====================================================\n" +
"=== tinyMediaManager (c) 2012-2019 Manuel Laggner ===\n" +
"=====================================================\n" +
"\n" +
"SYNTAX: Windows: tinyMediaManagerCMD.exe \n" +
" Linux: ./tinyMediaManagerCMD.sh \n" +
"\n" +
"\n" +
"PARAMETERS:\n" +
"\n" +
" UPDATE: Will scan your folders, and adds all found items to database\n" +
" Keeps an internal list of 'new' items (for this run only!)\n" +
"\n" +
" -updateMovies update all movie datasources\n" +
" -updateMoviesX replace X with 1-9 - just updates a single movie datasource; ordering like GUI\n" +
" -updateTv update all TvShow\n" +
" -updateTvX replace X with 1-9 - just updates a single TvShow datasource; ordering like GUI\n" +
" -update update all (short for '-updateMovies -updateTv')\n" +
"\n" +
" SCRAPE: auto-scrapes (force best match) your specified items:\n" +
" -scrapeNew only NEW FOUND movies/TvShows/episodes from former update\n" +
" -scrapeUnscraped all movies/TvShows/episodes, which have not yet been scraped\n" +
" -scrapeAll ALL movies/TvShows/episodes, whether they have already been scraped or not\n" +
"\n" +
" -rename rename & cleanup all the movies/TvShows/episodes from former scrape command\n" +
" -config file.xml specify an alternative configuration xml file\n" +
" -export template dir exports your complete movie/tv library with specified template to dir\n" +
" -checkFiles does a physical check, if all files in DB are existent on filesystem (might take long!)\n" +
"\n" +
"\n" +
"EXAMPLES:\n" +
"\n" +
" tinyMediaManagerCMD.exe -updateMovies -updateTv3 -scrapeNew -rename\n" +
" tinyMediaManagerCMD.exe -scrapeUnscraped -rename\n" +
" tinyMediaManagerCMD.exe -export ExcelXml /user/export/movies\n" +
" tinyMediaManagerCMD.exe -export TvShowDetailExampleXml /user/export/tv" +
"\n");
// @formatter:on
}
/**
* executes all the command line tasks, one after another
*/
static void startCommandLineTasks() {
try {
TmmTask task = null;
boolean updateAvailable = false;
if (scrapeNew || scrapeUnscraped || scrapeAll) {
// only do an update check when we are scraping online
// no need for a "forced" check for just updating the datasource
final SwingWorker updateWorker = new UpdaterTask();
updateWorker.run();
updateAvailable = updateWorker.get(); // blocking
if (updateAvailable) {
LOGGER.warn("There's a new TMM update available!");
LOGGER.warn("Please update to remove waiting time ;)");
for (int i = 20; i > 0; i--) {
System.out.print(i + "..");
Thread.sleep(1000);
}
System.out.println("0");
}
}
// @formatter:off
// ███╗ ███╗ ██████╗ ██╗ ██╗██╗███████╗███████╗
// ████╗ ████║██╔═══██╗██║ ██║██║██╔════╝██╔════╝
// ██╔████╔██║██║ ██║██║ ██║██║█████╗ ███████╗
// ██║╚██╔╝██║██║ ██║╚██╗ ██╔╝██║██╔══╝ ╚════██║
// ██║ ╚═╝ ██║╚██████╔╝ ╚████╔╝ ██║███████╗███████║
// ╚═╝ ╚═╝ ╚═════╝ ╚═══╝ ╚═╝╚══════╝╚══════╝
// @formatter:on
// *****************
// UPDATE
// *****************
if (updateMovies) {
LOGGER.info("Commandline - updating movies...");
if (updateMovieDs.isEmpty()) {
task = new MovieUpdateDatasourceTask();
task.run(); // blocking
}
else {
List dataSources = new ArrayList<>(MovieModuleManager.SETTINGS.getMovieDataSource());
for (Integer i : updateMovieDs) {
if (dataSources != null && dataSources.size() >= i - 1) {
task = new MovieUpdateDatasourceTask(dataSources.get(i - 1));
task.run(); // blocking
}
}
}
LOGGER.info("Found " + MovieList.getInstance().getNewMovies().size() + " new movies");
}
// *****************
// SCRAPE
// *****************
List moviesToScrape = new ArrayList<>();
if (scrapeAll) {
LOGGER.info("Commandline - scraping ALL movies...");
if (MovieList.getInstance().getMovieCount() > 0) {
moviesToScrape = MovieList.getInstance().getMovies();
}
}
else {
HashSet scrape = new HashSet<>(); // no dupes
if (scrapeNew) {
LOGGER.info("Commandline - scraping new movies...");
List newMovies = MovieList.getInstance().getNewMovies();
if (newMovies.size() > 0) {
scrape.addAll(newMovies);
}
}
if (scrapeUnscraped) {
LOGGER.info("Commandline - scraping all unscraped movies...");
List unscrapedMovies = MovieList.getInstance().getUnscrapedMovies();
if (unscrapedMovies.size() > 0) {
scrape.addAll(unscrapedMovies);
}
}
moviesToScrape.addAll(new ArrayList<>(scrape));
}
if (moviesToScrape.size() > 0) {
MovieSearchAndScrapeOptions options = new MovieSearchAndScrapeOptions();
options.loadDefaults();
if (dryRun) {
for (Movie movie : moviesToScrape) {
LOGGER.info("DRYRUN: would have scraped " + movie.getTitle());
}
}
else {
task = new MovieScrapeTask(moviesToScrape, true, options);
task.run(); // blocking
// wait for other tmm threads (artwork download et all)
while (TmmTaskManager.getInstance().poolRunning()) {
Thread.sleep(2000);
}
}
}
// *****************
// RENAME
// *****************
if (rename) {
LOGGER.info("Commandline - rename & cleanup movies...");
if (moviesToScrape.size() > 0) {
if (dryRun) {
for (Movie movie : moviesToScrape) {
LOGGER.info("DRYRUN: would have renamed " + movie.getTitle());
}
}
else {
task = new MovieRenameTask(moviesToScrape);
task.run(); // blocking}
}
}
}
// *****************
// EXPORT
// *****************
if (export) {
for (ExportTemplate t : MovieExporter.findTemplates(TemplateType.MOVIE)) {
if (t.getPath().equals(exportTemplate.toAbsolutePath().toString())) {
// ok, our template has been found under movies
LOGGER.info("Commandline - exporting movies...");
if (dryRun) {
LOGGER.info("DRYRUN: would have exported ALL movies to " + exportDir.toAbsolutePath());
}
else {
MovieExporter ex = new MovieExporter(Paths.get(t.getPath()));
List movies = MovieList.getInstance().getMovies();
movies.sort(new MovieComparator());
ex.export(movies, exportDir);
}
break;
}
}
}
// @formatter:off
// ████████╗██╗ ██╗███████╗██╗ ██╗ ██████╗ ██╗ ██╗███████╗
// ╚══██╔══╝██║ ██║██╔════╝██║ ██║██╔═══██╗██║ ██║██╔════╝
// ██║ ██║ ██║███████╗███████║██║ ██║██║ █╗ ██║███████╗
// ██║ ╚██╗ ██╔╝╚════██║██╔══██║██║ ██║██║███╗██║╚════██║
// ██║ ╚████╔╝ ███████║██║ ██║╚██████╔╝╚███╔███╔╝███████║
// ╚═╝ ╚═══╝ ╚══════╝╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝
// @formatter:on
// *****************
// UPDATE
// *****************
if (updateTv) {
LOGGER.info("Commandline - updating TvShows and episodes...");
if (updateTvDs.isEmpty()) {
task = new TvShowUpdateDatasourceTask();
task.run(); // blocking
}
else {
List dataSources = new ArrayList<>(TvShowModuleManager.SETTINGS.getTvShowDataSource());
for (Integer i : updateTvDs) {
if (dataSources != null && dataSources.size() >= i - 1) {
task = new TvShowUpdateDatasourceTask(dataSources.get(i - 1));
task.run(); // blocking
}
}
}
LOGGER.info("Commandline - found " + TvShowList.getInstance().getNewTvShows().size() + " TvShow(s) containing "
+ TvShowList.getInstance().getNewEpisodes().size() + " new episode(s)");
}
// *****************
// prepare shows/episodes for scrape
// *****************
List showToScrape = new ArrayList<>();
List episodeToScrape = new ArrayList<>();
if (scrapeAll) {
LOGGER.info("Commandline - scraping ALL TvShows...");
if (TvShowList.getInstance().getTvShowCount() > 0) {
showToScrape = TvShowList.getInstance().getTvShows();
episodeToScrape.clear(); // scraping complete show
}
}
else {
HashSet scrapeShow = new HashSet<>(); // no dupes
HashSet scrapeEpisode = new HashSet<>(); // no dupes
if (scrapeNew) {
List newTv = TvShowList.getInstance().getNewTvShows();
List newEp = TvShowList.getInstance().getNewEpisodes();
LOGGER.info("Commandline - scraping new TvShows...");
if (newTv.size() > 0) {
scrapeShow.addAll(newTv);
}
LOGGER.info("Commandline - scraping new episodes...");
if (newEp.size() > 0) {
scrapeEpisode.addAll(newEp);
}
}
if (scrapeUnscraped) {
LOGGER.info("Commandline - scraping unscraped TvShows...");
List unscrapedShows = TvShowList.getInstance().getUnscrapedTvShows();
List unscrapedEpisodes = TvShowList.getInstance().getUnscrapedEpisodes();
if (unscrapedShows.size() > 0) {
scrapeShow.addAll(unscrapedShows);
}
LOGGER.info("Commandline - scraping unscraped episodes...");
if (unscrapedEpisodes.size() > 0) {
scrapeEpisode.addAll(unscrapedEpisodes);
}
}
// if we scrape already the whole show, no need to scrape dedicated episodes for it
HashSet removedEpisode = new HashSet<>(); // no dupes
for (TvShowEpisode ep : scrapeEpisode) {
if (scrapeShow.contains(ep.getTvShow())) {
removedEpisode.add(ep);
}
}
scrapeEpisode.removeAll(removedEpisode);
showToScrape = new ArrayList<>(scrapeShow);
episodeToScrape = new ArrayList<>(scrapeEpisode);
}
// *****************
// do the scrape
// *****************
TvShowSearchAndScrapeOptions options = new TvShowSearchAndScrapeOptions();
options.loadDefaults();
if (showToScrape.size() > 0) {
if (dryRun) {
for (TvShow show : showToScrape) {
LOGGER.info("DRYRUN: would have scraped show " + show.getTitle() + " with " + show.getEpisodeCount() + " episodes");
}
}
else {
task = new TvShowScrapeTask(showToScrape, true, options);
task.run(); // blocking
// wait for other tmm threads (artwork download et all)
while (TmmTaskManager.getInstance().poolRunning()) {
Thread.sleep(2000);
}
}
}
if (episodeToScrape.size() > 0) {
if (dryRun) {
for (TvShowEpisode ep : episodeToScrape) {
LOGGER.info("DRYRUN: would have scraped episode " + ep.getTvShow().getTitle() + " S:" + ep.getSeason() + " E:" + ep.getEpisode());
}
}
else {
task = new TvShowEpisodeScrapeTask(episodeToScrape, options.getMetadataScraper(), options.getScraperMetadataConfig());
task.run(); // blocking
// wait for other tmm threads (artwork download et all)
while (TmmTaskManager.getInstance().poolRunning()) {
Thread.sleep(2000);
}
}
}
// *****************
// RENAME
// *****************
if (rename) {
LOGGER.info("Commandline - rename & cleanup new shows...");
if (showToScrape.size() > 0) {
if (dryRun) {
for (TvShow show : showToScrape) {
LOGGER.info("DRYRUN: would have renamed show " + show.getTitle() + " with " + show.getEpisodeCount() + " episodes");
}
}
else {
task = new TvShowRenameTask(showToScrape, null, true);
task.run(); // blocking
// wait for other tmm threads (artwork download et all)
while (TmmTaskManager.getInstance().poolRunning()) {
Thread.sleep(2000);
}
}
}
LOGGER.info("Commandline - rename & cleanup new episodes...");
if (episodeToScrape.size() > 0) {
if (dryRun) {
for (TvShowEpisode ep : episodeToScrape) {
LOGGER.info("DRYRUN: would have renamed episode " + ep.getTvShow().getTitle() + " S:" + ep.getSeason() + " E:" + ep.getEpisode());
}
}
else {
task = new TvShowRenameTask(null, episodeToScrape, true); // just rename new EPs AND root folder
task.run(); // blocking
}
}
}
// *****************
// EXPORT
// *****************
if (export) {
for (ExportTemplate t : TvShowExporter.findTemplates(TemplateType.TV_SHOW)) {
if (t.getPath().equals(exportTemplate.toAbsolutePath().toString())) {
// ok, our template has been found under movies
LOGGER.info("Commandline - exporting tv shows...");
if (dryRun) {
LOGGER.info("DRYRUN: would have exported ALL TV shows to " + exportDir.toAbsolutePath());
}
else {
TvShowExporter ex = new TvShowExporter(Paths.get(t.getPath()));
List tvShows = TvShowList.getInstance().getTvShows();
tvShows.sort(new TvShowComparator());
ex.export(tvShows, exportDir);
}
break;
}
}
}
if (checkFiles) {
boolean allOk = true;
// check db
LOGGER.info("Check all files if existing");
for (Movie m : MovieList.getInstance().getMovies()) {
System.out.print(".");
for (MediaFile mf : m.getMediaFiles()) {
if (!mf.exists()) {
System.out.println();
LOGGER.warn("MediaFile not found! " + mf.getFileAsPath());
allOk = false;
}
}
}
for (TvShow s : TvShowList.getInstance().getTvShows()) {
System.out.print(".");
for (MediaFile mf : s.getMediaFiles()) { // show MFs
if (!mf.exists()) {
System.out.println();
LOGGER.warn("MediaFile not found! " + mf.getFileAsPath());
allOk = false;
}
}
for (TvShowEpisode episode : new ArrayList<>(s.getEpisodes())) {
for (MediaFile mf : episode.getMediaFiles()) { // episode MFs
if (!mf.exists()) {
System.out.println();
LOGGER.warn("MediaFile not found! " + mf.getFileAsPath());
allOk = false;
}
}
}
}
System.out.println();
if (allOk) {
LOGGER.info("no problems found - everything ok :)");
}
}
if (updateAvailable) {
LOGGER.warn("=====================================================");
LOGGER.warn("There's a new TMM version available! Please update!");
LOGGER.warn("=====================================================");
}
}
catch (Exception e) {
LOGGER.error("Error executing command line task!", e);
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy