// Resets the configuration of this plugin. @Override public final void resetConfig() { Log.getInstance() .write(Log.LOGLEVEL_TRACE, "resetConfig: resetConfig received from Plugin Manager."); Log.getInstance().SetLogLevel(Log.LOGLEVEL_WARN); Configuration.SetServerProperty(PROPERTY_DEFAULT_MAX, DEFAULT_MAX_STRING); Configuration.SetServerProperty(PROPERTY_REDUCE_TO_MAX, "false"); Configuration.SetServerProperty(PROPERTY_KEEP_OLDEST, "true"); showInFocus = null; }
// Sets a configuration value for this plugin. @Override public void setConfigValue(String setting, String value) { Log.getInstance() .write( Log.LOGLEVEL_ALL, "PlugIn: setConfigValue received from Plugin Manager. Setting = " + setting + ":" + value); if (setting.startsWith(SETTING_LOGLEVEL)) { if (value.startsWith("None")) Log.getInstance().SetLogLevel(Log.LOGLEVEL_NONE); else if (value.startsWith("Error")) Log.getInstance().SetLogLevel(Log.LOGLEVEL_ERROR); else if (value.startsWith("Warn")) Log.getInstance().SetLogLevel(Log.LOGLEVEL_WARN); else if (value.startsWith("Trace")) Log.getInstance().SetLogLevel(Log.LOGLEVEL_TRACE); else if (value.startsWith("Verbose")) Log.getInstance().SetLogLevel(Log.LOGLEVEL_VERBOSE); else if (value.startsWith("Maximum")) Log.getInstance().SetLogLevel(Log.LOGLEVEL_ALL); else Log.getInstance().SetLogLevel(Log.LOGLEVEL_ERROR); } else if (setting.startsWith(SETTING_DEFAULT_MAX)) { if (value.equalsIgnoreCase("5309")) { System.out.println("LIR:: Deleting all user records."); UserRecordAPI.DeleteAllUserRecords(DataStore.STORE); showInFocus = null; } else Configuration.SetServerProperty(PROPERTY_DEFAULT_MAX, verifyMax(value)); } else if (setting.startsWith(SETTING_REDUCE_TO_MAX)) { Configuration.SetServerProperty(PROPERTY_REDUCE_TO_MAX, value); } else if (setting.startsWith(SETTING_KEEP_OLDEST)) { Configuration.SetServerProperty(PROPERTY_KEEP_OLDEST, value); } else if (setting.startsWith(SETTING_PICK_SHOW)) { // The user just selected a show. Put it in focus. showInFocus = Util.removeNumberMax(value); } else if (setting.startsWith(SETTING_HAVE_SHOW)) { // The user just selected a different show. Put it in focus. showInFocus = Util.removeNumberMax(value); } else if (setting.startsWith(SETTING_SHOW_MAX)) { // The user just entered a new max for this show. If it's non null add it. if (value == null || value.trim().length() == 0) return; try { Integer.parseInt(value); } catch (NumberFormatException e) { return; } DataStore store = new DataStore(showInFocus); store.addRecord(showInFocus); store.setMax(verifyMax(value)); } else if (setting.startsWith(SETTING_RESET_SHOW)) { // The user wants to reset this show so just delete the User Record. DataStore store = new DataStore(showInFocus); if (store.deleteRecord()) showInFocus = null; else Log.getInstance().write(Log.LOGLEVEL_WARN, "Plugin: Could not delete the User Record."); } }
// This method is called when the plugin should shutdown. @Override public void stop() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "stop: Stop received from Plugin Manager."); if (Global.IsClient()) { Log.getInstance().write(Log.LOGLEVEL_WARN, "stop: Running in Client mode."); return; } // registry.eventUnsubscribe(listener, "RecordingCompleted"); registry.eventUnsubscribe(listener, "RecordingStopped"); showInFocus = null; }
// This method is called after plugin shutdown to free any resources // used by the plugin. @Override public void destroy() { if (Global.IsClient()) { Log.getInstance().write(Log.LOGLEVEL_WARN, "destroy: Running in Client mode."); Log.getInstance().destroy(); return; } Log.getInstance().write(Log.LOGLEVEL_TRACE, "destroy: Destroy received from Plugin Manager."); Log.getInstance().destroy(); registry = null; listener = null; }
/* * Constructor. */ public DownloadThread() { RecordingMaps = new LinkedBlockingQueue<RecordingEpisode>(); stop = false; AbortCurrent = false; CurrentlyRecording = null; Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: Constructor completed."); }
public String getTitle() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: getTitle."); if (CurrentlyRecording == null) { return null; } return CurrentlyRecording.getRSSItemTitle(); }
public Long getCurrentDownloadSize() { Log.getInstance().write(Log.LOGLEVEL_VERBOSE, "DT: getCurrentDownloadSize."); if (CurrentlyRecording == null) { return 0L; } else { return CurrentlyRecording.getBlocksRecorded() * RecordingEpisode.BLOCK_SIZE; } }
@Override public void start() { System.out.println("LIR: Plugin: Starting. Version = " + VERSION); // Set the loglevel to what's in the .properties file. Integer DefaultLevel = Log.LOGLEVEL_WARN; String CurrentLevel = Configuration.GetServerProperty(Log.PROPERTY_LOGLEVEL, DefaultLevel.toString()); Integer SetLevel = Integer.decode(CurrentLevel); Log.getInstance().SetLogLevel(SetLevel); switch (Log.getInstance().GetLogLevel()) { case Log.LOGLEVEL_ALL: System.out.println("LIR: Plugin: LogLevel = Maximum."); break; case Log.LOGLEVEL_ERROR: System.out.println("LIR: Plugin: LogLevel = Error."); break; case Log.LOGLEVEL_NONE: System.out.println("LIR: Plugin: LogLevel = None."); break; case Log.LOGLEVEL_TRACE: System.out.println("LIR: Plugin: LogLevel = Trace."); break; case Log.LOGLEVEL_VERBOSE: System.out.println("LIR: Plugin: LogLevel = Verbose."); break; case Log.LOGLEVEL_WARN: System.out.println("LIR: Plugin: LogLevel = Warn."); break; default: System.out.println("LIR: Plugin: Error. Unknown LogLevel."); break; } // If we're running on a client we are done. if (Global.IsClient()) { Log.getInstance().write(Log.LOGLEVEL_WARN, "start: Running in Client mode."); return; } // Subscribe to what we need. Log.getInstance().write(Log.LOGLEVEL_TRACE, "start: Subscribing to events."); // registry.eventSubscribe(listener, "RecordingCompleted"); registry.eventSubscribe(listener, "RecordingStopped"); }
// Returns the current value of the specified setting for this plugin. @Override public String getConfigValue(String setting) { Log.getInstance() .write( Log.LOGLEVEL_ALL, "PlugIn: setConfigValue received from Plugin Manager. Setting = " + setting); if (setting.startsWith(SETTING_LOGLEVEL)) { switch (Log.getInstance().GetLogLevel()) { case Log.LOGLEVEL_ALL: return "Maximum"; case Log.LOGLEVEL_ERROR: return "Error"; case Log.LOGLEVEL_NONE: return "None"; case Log.LOGLEVEL_TRACE: return "Trace"; case Log.LOGLEVEL_VERBOSE: return "Verbose"; case Log.LOGLEVEL_WARN: return "Warn"; default: return "Unknown"; } } else if (setting.startsWith(SETTING_DEFAULT_MAX)) { return Configuration.GetServerProperty(PROPERTY_DEFAULT_MAX, DEFAULT_MAX_STRING); } else if (setting.startsWith(SETTING_REDUCE_TO_MAX)) { return Configuration.GetServerProperty(PROPERTY_REDUCE_TO_MAX, "false"); } else if (setting.startsWith(SETTING_KEEP_OLDEST)) { return Configuration.GetServerProperty(PROPERTY_KEEP_OLDEST, "true"); } else if (setting.startsWith(SETTING_PICK_SHOW)) { return "Select"; } else if (setting.startsWith(SETTING_HAVE_SHOW)) { return showInFocus; } else if (setting.startsWith(SETTING_SHOW_MAX)) { DataStore store = new DataStore(showInFocus); return (store.isMonitored() ? store.getMaxString() : ""); } else if (setting.startsWith(SETTING_RESET_SHOW)) { return "Reset Now"; } else return null; }
// Returns one of the constants above that indicates what type of value // is used for a specific settings. @Override public int getConfigType(String setting) { Log.getInstance() .write( Log.LOGLEVEL_ALL, "PlugIn: getConfigType received from Plugin Manager. Setting = " + setting); if (setting.startsWith(SETTING_LOGLEVEL)) return CONFIG_CHOICE; else if (setting.startsWith(SETTING_DEFAULT_MAX)) return CONFIG_TEXT; else if (setting.startsWith(SETTING_REDUCE_TO_MAX)) return CONFIG_BOOL; else if (setting.startsWith(SETTING_KEEP_OLDEST)) return CONFIG_BOOL; else if (setting.startsWith(SETTING_PICK_SHOW)) return CONFIG_CHOICE; else if (setting.startsWith(SETTING_HAVE_SHOW)) return CONFIG_CHOICE; else if (setting.startsWith(SETTING_SHOW_MAX)) return CONFIG_TEXT; else if (setting.startsWith(SETTING_RESET_SHOW)) return CONFIG_BUTTON; else return 0; }
// For CONFIG_CHOICE settings; this returns the list of choices. @Override public String[] getConfigOptions(String setting) { Log.getInstance() .write( Log.LOGLEVEL_ALL, "PlugIn: getConfigOptions received from Plugin Manager. Setting = " + setting); if (setting.startsWith(SETTING_LOGLEVEL)) { String[] values = {"None", "Error", "Warn", "Trace", "Verbose", "Maximum"}; return values; } else if (setting.startsWith(SETTING_PICK_SHOW) || setting.startsWith(SETTING_HAVE_SHOW)) { // The user wants to select a show to put in focus. The options are all // shows that are intelligent recordings. return Util.getAllIntelligentRecordingTitlesAndMax(); } else { return null; } }
// Returns the label used to present this setting to the user. @Override public String getConfigLabel(String setting) { if (setting.startsWith(SETTING_LOGLEVEL)) { return "Debug Logging Level"; } else if (setting.startsWith(SETTING_DEFAULT_MAX)) { return "Global Maximum to Keep"; } else if (setting.startsWith(SETTING_REDUCE_TO_MAX)) { return "Delete Excess Recordings"; } else if (setting.startsWith(SETTING_KEEP_OLDEST)) { return "Keep the Oldest Recordings"; } else if (setting.startsWith(SETTING_PICK_SHOW)) { return "Choose a Show"; } else if (setting.startsWith(SETTING_HAVE_SHOW)) { return "Limit This Show"; } else if (setting.startsWith(SETTING_SHOW_MAX)) { return "Max to Keep for This Show"; } else if (setting.startsWith(SETTING_RESET_SHOW)) { return "Use Default for This Show"; } else { Log.getInstance().write(Log.LOGLEVEL_WARN, "getConfigLabel: Unknown setting = " + setting); return null; } }
public RecordingEpisode getCurrentlyRecording() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: getCurrentlyRecording."); return CurrentlyRecording; }
/** * Returns the number of items in the download queue. Does NOT include the currently downloading * item, if any. * * <p> * * @return The number of items in the download queue. */ public Integer getNumberOfQueuedItems() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: getNumberOfItems."); return RecordingMaps.size(); }
/** The main thread that does all of the downloading. */ @Override public void run() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: Starting."); Thread.currentThread().setName("DownloadThread"); while (!stop) { // Get the first item in the queue and then remove it from the queue. try { CurrentlyRecording = RecordingMaps.take(); } catch (InterruptedException e) { Log.getInstance().write(Log.LOGLEVEL_WARN, "DT: Interrupted. Terminating."); return; } Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: Have work to do."); showCurrentlyRecording(CurrentlyRecording); // Make sure we have enough parameters. if (!CurrentlyRecording.isComplete()) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: Not enough parameters."); CurrentlyRecording.failed(); continue; } DownloadManager.getInstance().setCurrentlyRecordingID(CurrentlyRecording.getRequestID()); // Get all of the RSSItems for the Feed Context. List<RSSItem> RSSItems = CurrentlyRecording.getRSSItems(); if (RSSItems == null) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: null RSSItems."); CurrentlyRecording.failed(); continue; } Log.getInstance() .write(Log.LOGLEVEL_TRACE, "DT: Found episodes for podcast = " + RSSItems.size()); if (RSSItems.isEmpty()) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: No RSSItems."); CurrentlyRecording.failed(); continue; } // Get the one ChanItem (RSSItem) we are interested in. RSSItem ChanItem = CurrentlyRecording.getItemForID(RSSItems, CurrentlyRecording.getEpisodeID()); if (ChanItem == null) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: null ChanItem."); CurrentlyRecording.failed(); continue; } // Set the ChanItem. CurrentlyRecording.setChanItem(ChanItem); // Set the fileExt instance variable. CurrentlyRecording.setFileExt(); // Create the tempfile where the episode will be downloaded to. if (!CurrentlyRecording.setTempFile()) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: Failed to setTempFile."); CurrentlyRecording.failed(); continue; } // Download the episode to the tempfile. if (!CurrentlyRecording.download()) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: download failed."); CurrentlyRecording.failed(); continue; } // Check for 0 size download. if (CurrentlyRecording.isZeroSizeDownload()) { Log.getInstance().write(Log.LOGLEVEL_WARN, "DT: File is 0 bytes long."); CurrentlyRecording.failed(); continue; } // Move the tempfile to the final location and rename it to the final name. if (!CurrentlyRecording.moveToFinalLocation()) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: moveToFinalLocation failed."); CurrentlyRecording.failed(); continue; } // Import the episode into the Sage database as an imported media file. if (CurrentlyRecording.importAsAiring() == null) { Log.getInstance().write(Log.LOGLEVEL_ERROR, "DT: importAsMediaFile failed."); CurrentlyRecording.failed(); continue; } // Force Episode to update it's Airing information. int AiringID = CurrentlyRecording.getAiringID(); // It worked. Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: Completed successfully."); CurrentlyRecording.completed(); CurrentlyRecording = null; } // While !stop Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: Fatal error. Ending."); } // Run
public void abortCurrentDownload() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: Aborting current download."); if (CurrentlyRecording != null) CurrentlyRecording.abortCurrentDownload(); }
/** * Gets the status of the "Stop" flag. If Stop is set to true the DownloadThread will exit * normally after finishing any download that is in progress. * * <p> * * @return The status of the Stop flag. */ public boolean getStop() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: getStop."); return stop; }
/** * Set the "Stop" flag to to value specified. * * <p> * * @param state The new value of the Stop flag. */ public void setStop(boolean state) { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: setStop."); stop = state; if (stop) this.interrupt(); }
/** * Add an item to be downloaded. Details to follow.... * * <p> * * @param info an array of strings .... * @return true if it succeeded, false otherwise. */ public boolean addItem(RecordingEpisode episode) { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: addItem."); return RecordingMaps.add(episode); }
/** * Interface definition for implementation classes that listen for events from the SageTV core * * <p>Variable types are in brackets[] after the var name unless they are the same as the var name * itself. List of known core events: * * <p>MediaFileImported - vars: MediaFile ImportingStarted ImportingCompleted RecordingCompleted * (called when a complete recording is done) vars: MediaFile RecordingStarted (called when any * kind of recording is started) vars: MediaFile RecordingStopped (called whenever a recording is * stopped for any reason) vars: MediaFile AllPluginsLoaded RecordingScheduleChanged * ConflictStatusChanged SystemMessagePosted vars: SystemMessage EPGUpdateCompleted * MediaFileRemoved vars: MediaFile PlaybackStopped (called when the file is closed) vars: * MediaFile, UIContext[String], Duration[Long], MediaTime[Long], ChapterNum[Integer], * TitleNum[Integer] PlaybackFinished (called at the EOF) vars: MediaFile, UIContext[String], * Duration[Long], MediaTime[Long], ChapterNum[Integer], TitleNum[Integer] PlaybackStarted vars: * MediaFile, UIContext[String], Duration[Long], MediaTime[Long], ChapterNum[Integer], * TitleNum[Integer] FavoriteAdded vars: Favorite FavoriteModified vars: Favorite FavoriteRemoved * vars: Favorite PlaylistAdded vars: Playlist, UIContext[String] PlaylistModified vars: Playlist, * UIContext[String] PlaylistRemoved vars: Playlist, UIContext[String] ClientConnected vars: * IPAddress[String], MACAddress[String] (if its a placeshifter/extender, MACAddress is null * otherwise) ClientDisconnected vars: IPAddress[String], MACAddress[String] (if its a * placeshifter/extender, MACAddress is null otherwise) * * <p>This is a callback method invoked from the SageTV core for any events the listener has * subscribed to. See the sage.SageTVPluginRegistry interface definition for details regarding * subscribing and unsubscribing to events. The eventName will be a predefined String which * indicates the event type. The eventVars will be a Map of variables specific to the event * information. This Map should NOT be modified. The keys to the eventVars Map will generally be * Strings; but this may change in the future and plugins that submit events are not required to * follow that rule. */ @Override public synchronized void sageEvent(String eventName, java.util.Map eventVars) { Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Event received = " + eventName); // Check that we have the right event. if (!(eventName.startsWith("RecordingCompleted") || eventName.startsWith("RecordingStopped"))) { Log.getInstance() .write(Log.LOGLEVEL_WARN, "sageEvent: Unexpected event received = " + eventName); return; } // Check that we have a valid MediaFile. Object MediaFile = eventVars.get("MediaFile"); if (MediaFile == null) { Log.getInstance().write(Log.LOGLEVEL_WARN, "sageEvent: null MediaFile"); return; } Log.getInstance() .write( Log.LOGLEVEL_TRACE, "sageEvent: Finished recording " + AiringAPI.GetAiringTitle(MediaFile) + " - " + ShowAPI.GetShowEpisode(MediaFile)); // If it's a Manual, Favorite, or TimedRecord (manual) we do not need to worry about it. if (AiringAPI.IsFavorite(MediaFile) || AiringAPI.IsManualRecord(MediaFile)) { Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Is not an Intelligent Recording."); return; } // Create the DataStore which will allow us to access the data for this MediaFile. DataStore store = new DataStore(MediaFile); int maxToKeep; // If it's monitored keep the number specified. If it's not monitored use the // global default. if (store.isMonitored()) { Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Using max for this show."); maxToKeep = store.getMax(); } else { Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Using global max."); maxToKeep = Util.GetIntProperty(PROPERTY_DEFAULT_MAX, DEFAULT_MAX_STRING); } Log.getInstance() .write( Log.LOGLEVEL_TRACE, "sageEvent: Max to keep = " + (maxToKeep == DEFAULT_MAX ? "unlimited" : maxToKeep)); // See how many are already recorded. int numberRecorded = Util.getNumberRecorded(MediaFile); Log.getInstance() .write(Log.LOGLEVEL_TRACE, "sageEvent: Number already recorded = " + numberRecorded); // If it's unlimited or below the threshhold don't worry about it. if (maxToKeep == UNLIMITED || numberRecorded <= maxToKeep) { Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Below threshhold."); return; } Log.getInstance() .write( Log.LOGLEVEL_TRACE, "sageEvent: Threshhold exceeded. Deleting one or more " + AiringAPI.GetAiringTitle(MediaFile)); // Get the direction to sort. boolean keepOldest = Configuration.GetServerProperty(PROPERTY_KEEP_OLDEST, "true").equalsIgnoreCase("true"); Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Keep oldest = " + keepOldest); // Get all of the recordings in the proper order. Recordings at the beginning of the // List will be deleted first. List<Object> allRecorded = Util.getAllRecorded(MediaFile, "GetAiringStartTime", keepOldest); Log.getInstance() .write(Log.LOGLEVEL_TRACE, "sageEvent: Sorted list size = " + allRecorded.size()); if (Log.getInstance().GetLogLevel() <= Log.LOGLEVEL_VERBOSE) { for (Object MF : allRecorded) Log.getInstance() .write( Log.LOGLEVEL_VERBOSE, "sageEvent: Date recorded = " + Utility.PrintDateLong(AiringAPI.GetAiringStartTime(MF)) + " : " + Utility.PrintTimeLong(AiringAPI.GetAiringStartTime(MF)) + " - " + AiringAPI.GetAiringTitle(MF) + " - " + ShowAPI.GetShowEpisode(MF)); } boolean reduceToMax = Configuration.GetServerProperty(PROPERTY_REDUCE_TO_MAX, "false").equalsIgnoreCase("true"); // Calculate how many to delete. int numberToDelete = (reduceToMax ? numberRecorded - maxToKeep : 1); Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: Need to delete " + numberToDelete); // Sanity check. if (allRecorded == null || allRecorded.size() < numberToDelete || numberToDelete < 1) { Log.getInstance() .write( Log.LOGLEVEL_WARN, "sageEvent: Internal error. numberToDelete exceeds allRecorded. Deleting this MediaFile."); MediaFileAPI.DeleteFile(MediaFile); return; } for (int i = 0; i < numberToDelete; i++) { Object MF = allRecorded.get(i); // Log.getInstance().write(Log.LOGLEVEL_TRACE, "sageEvent: TESTMODE. Would have deleted " + // AiringAPI.GetAiringTitle(MF) + " - " + ShowAPI.GetShowEpisode(MF)); if (MediaFileAPI.DeleteFile(MF)) Log.getInstance() .write( Log.LOGLEVEL_TRACE, "sageEvent: Deleted " + AiringAPI.GetAiringTitle(MF) + " - " + ShowAPI.GetShowEpisode(MF)); else Log.getInstance() .write( Log.LOGLEVEL_WARN, "sageEvent: Failed to delete " + AiringAPI.GetAiringTitle(MF) + " - " + ShowAPI.GetShowEpisode(MF)); } }
public void setAbortCurrent(boolean state) { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: setAbortCurrent."); AbortCurrent = state; }
public boolean removeAllItems() { Log.getInstance().write(Log.LOGLEVEL_TRACE, "DT: removeAllItems."); RecordingMaps = new LinkedBlockingQueue<RecordingEpisode>(); return true; }
public void removeItem(RecordingEpisode episode) { if (!RecordingMaps.remove(episode)) { Log.getInstance() .write(Log.LOGLEVEL_ERROR, "DT: Failed to remove episode from RecordingMaps."); } }