00001 #include <QCoreApplication>
00002 #include <QKeyEvent>
00003
00004 #include "mythcorecontext.h"
00005 #include "keybindings.h"
00006 #include "mythlogging.h"
00007 #include "mythevent.h"
00008 #include "mythuistatetracker.h"
00009 #include "mythuihelper.h"
00010 #include "mythmainwindow.h"
00011 #include "tv_play.h"
00012
00013 #include "videometadatalistmanager.h"
00014 #include "videometadata.h"
00015 #include "videoutils.h"
00016
00017 #include "frontend.h"
00018
00019 #define LOC QString("Frontend API: ")
00020
00021 QStringList Frontend::gActionList = QStringList();
00022 QHash<QString,QStringList> Frontend::gActionDescriptions = QHash<QString,QStringList>();
00023
00024 DTC::FrontendStatus* Frontend::GetStatus(void)
00025 {
00026 DTC::FrontendStatus *status = new DTC::FrontendStatus();
00027 MythUIStateTracker::GetFreshState(status->State());
00028 status->Process();
00029 return status;
00030 }
00031
00032 bool Frontend::SendMessage(const QString &Message, uint Timeout)
00033 {
00034 if (Message.isEmpty())
00035 return false;
00036
00037 QStringList data;
00038 if (Timeout > 0 && Timeout < 1000)
00039 data << QString::number(Timeout);
00040 qApp->postEvent(GetMythMainWindow(),
00041 new MythEvent(MythEvent::MythUserMessage, Message,
00042 data));
00043 return true;
00044 }
00045
00046 bool Frontend::SendAction(const QString &Action, const QString &Value,
00047 uint Width, uint Height)
00048 {
00049 if (!IsValidAction(Action))
00050 return false;
00051
00052 static const QStringList value_actions =
00053 QStringList() << ACTION_HANDLEMEDIA << ACTION_SETVOLUME <<
00054 ACTION_SETAUDIOSYNC << ACTION_SETBRIGHTNESS <<
00055 ACTION_SETCONTRAST << ACTION_SETCOLOUR <<
00056 ACTION_SETHUE << ACTION_JUMPCHAPTER <<
00057 ACTION_SWITCHTITLE << ACTION_SWITCHANGLE <<
00058 ACTION_SEEKABSOLUTE;
00059
00060 if (!Value.isEmpty() && value_actions.contains(Action))
00061 {
00062 MythEvent* me = new MythEvent(Action, QStringList(Value));
00063 qApp->postEvent(GetMythMainWindow(), me);
00064 return true;
00065 }
00066
00067 if (ACTION_SCREENSHOT == Action)
00068 {
00069 if (!Width || !Height)
00070 {
00071 LOG(VB_GENERAL, LOG_ERR, LOC + "Invalid screenshot parameters.");
00072 return false;
00073 }
00074
00075 QStringList args;
00076 args << QString::number(Width) << QString::number(Height);
00077 MythEvent* me = new MythEvent(Action, args);
00078 qApp->postEvent(GetMythMainWindow(), me);
00079 return true;
00080 }
00081
00082 QKeyEvent* ke = new QKeyEvent(QEvent::KeyPress, 0, Qt::NoModifier, Action);
00083 qApp->postEvent(GetMythMainWindow(), (QEvent*)ke);
00084 return true;
00085 }
00086
00087 bool Frontend::PlayRecording(int ChanID, const QDateTime &StartTime)
00088 {
00089 QDateTime starttime = StartTime;
00090
00091 if (!starttime.isValid() || ChanID <= 0)
00092 {
00093 LOG(VB_GENERAL, LOG_WARNING, LOC + "Invalid parameters.");
00094 return false;
00095 }
00096
00097 if (GetMythUI()->GetCurrentLocation().toLower() == "playback")
00098 {
00099 QString message = QString("NETWORK_CONTROL STOP");
00100 MythEvent me(message);
00101 gCoreContext->dispatch(me);
00102
00103 QTime timer;
00104 timer.start();
00105 while ((timer.elapsed() < 10000) &&
00106 (GetMythUI()->GetCurrentLocation().toLower() == "playback"))
00107 usleep(10000);
00108 }
00109
00110 if (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox")
00111 {
00112 GetMythMainWindow()->JumpTo("TV Recording Playback");
00113
00114 QTime timer;
00115 timer.start();
00116 while ((timer.elapsed() < 10000) &&
00117 (GetMythUI()->GetCurrentLocation().toLower() != "playbackbox"))
00118 usleep(10000);
00119
00120 timer.start();
00121 while ((timer.elapsed() < 10000) &&
00122 (!GetMythUI()->IsTopScreenInitialized()))
00123 usleep(10000);
00124 }
00125
00126 if (GetMythUI()->GetCurrentLocation().toLower() == "playbackbox")
00127 {
00128 LOG(VB_GENERAL, LOG_INFO, LOC +
00129 QString("PlayRecording, ChanID: %1 StartTime: %2")
00130 .arg(ChanID).arg(starttime.toString(Qt::ISODate)));
00131
00132 QString message = QString("NETWORK_CONTROL PLAY PROGRAM %1 %2 %3")
00133 .arg(ChanID)
00134 .arg(starttime.toLocalTime().toString("yyyyMMddhhmmss"))
00135 .arg("12345");
00136
00137 MythEvent me(message);
00138 gCoreContext->dispatch(me);
00139 return true;
00140 }
00141
00142 return false;
00143 }
00144
00145 bool Frontend::PlayVideo(const QString &Id, bool UseBookmark)
00146 {
00147 if (TV::IsTVRunning())
00148 {
00149 LOG(VB_GENERAL, LOG_WARNING, LOC +
00150 QString("Ignoring PlayVideo request - frontend is busy."));
00151 return false;
00152 }
00153
00154 bool ok;
00155 quint64 id = Id.toUInt(&ok);
00156 if (!ok)
00157 {
00158 LOG(VB_GENERAL, LOG_WARNING, LOC + QString("Invalid video Id."));
00159 return false;
00160 }
00161
00162 VideoMetadataListManager::VideoMetadataPtr metadata =
00163 VideoMetadataListManager::loadOneFromDatabase(id);
00164
00165 if (!metadata)
00166 {
00167 LOG(VB_GENERAL, LOG_WARNING, LOC +
00168 QString("Didn't find any video metadata."));
00169 return false;
00170 }
00171
00172 if (metadata->GetHost().isEmpty())
00173 {
00174 LOG(VB_GENERAL, LOG_WARNING, LOC +
00175 QString("No host for video."));
00176 return false;
00177 }
00178
00179 QString mrl = generate_file_url("Videos", metadata->GetHost(),
00180 metadata->GetFilename());
00181 LOG(VB_GENERAL, LOG_INFO, LOC +
00182 QString("PlayVideo, id: %1 usebookmark: %2 url: '%3'")
00183 .arg(id).arg(UseBookmark).arg(mrl));
00184
00185 QStringList args;
00186 args << mrl << metadata->GetPlot() << metadata->GetTitle()
00187 << metadata->GetSubtitle() << metadata->GetDirector()
00188 << QString::number(metadata->GetSeason())
00189 << QString::number(metadata->GetEpisode())
00190 << metadata->GetInetRef() << QString::number(metadata->GetLength())
00191 << QString::number(metadata->GetYear())
00192 << QString::number(metadata->GetID())
00193 << QString::number(UseBookmark);
00194
00195 MythEvent *me = new MythEvent(ACTION_HANDLEMEDIA, args);
00196 qApp->postEvent(GetMythMainWindow(), me);
00197
00198 return true;
00199 }
00200
00201 QStringList Frontend::GetContextList(void)
00202 {
00203 InitialiseActions();
00204 return gActionDescriptions.keys();
00205 }
00206
00207 DTC::FrontendActionList* Frontend::GetActionList(const QString &Context)
00208 {
00209 DTC::FrontendActionList *list = new DTC::FrontendActionList();
00210
00211 InitialiseActions();
00212
00213 QHashIterator<QString,QStringList> contexts(gActionDescriptions);
00214 while (contexts.hasNext())
00215 {
00216 contexts.next();
00217 if (!Context.isEmpty() && contexts.key() != Context)
00218 continue;
00219
00220
00221 QStringList actions = contexts.value();
00222 foreach (QString action, actions)
00223 {
00224 QStringList split = action.split(",");
00225 if (split.size() == 2)
00226 list->ActionList().insert(split[0], split[1]);
00227 }
00228 }
00229 return list;
00230 }
00231
00232 bool Frontend::IsValidAction(const QString &Action)
00233 {
00234 InitialiseActions();
00235 if (gActionList.contains(Action))
00236 return true;
00237
00238
00239 if (Action.startsWith("SELECTSUBTITLE_") ||
00240 Action.startsWith("SELECTTTC_") ||
00241 Action.startsWith("SELECTCC608_") ||
00242 Action.startsWith("SELECTCC708_") ||
00243 Action.startsWith("SELECTRAWTEXT_") ||
00244 Action.startsWith("SELECTAUDIO_"))
00245 {
00246 return true;
00247 }
00248
00249 LOG(VB_GENERAL, LOG_ERR, LOC + QString("Action '%1'' is invalid.")
00250 .arg(Action));
00251 return false;
00252 }
00253
00254 void Frontend::InitialiseActions(void)
00255 {
00256 static bool initialised = false;
00257 if (initialised)
00258 return;
00259
00260 initialised = true;
00261 KeyBindings *bindings = new KeyBindings(gCoreContext->GetHostName());
00262 if (bindings)
00263 {
00264 QStringList contexts = bindings->GetContexts();
00265 contexts.sort();
00266 foreach (QString context, contexts)
00267 {
00268 gActionDescriptions[context] = QStringList();
00269 QStringList ctx_actions = bindings->GetActions(context);
00270 ctx_actions.sort();
00271 gActionList += ctx_actions;
00272 foreach (QString actions, ctx_actions)
00273 {
00274 QString desc = actions + "," +
00275 bindings->GetActionDescription(context, actions);
00276 gActionDescriptions[context].append(desc);
00277 }
00278 }
00279 }
00280 gActionList.removeDuplicates();
00281 gActionList.sort();
00282
00283 foreach (QString actions, gActionList)
00284 LOG(VB_GENERAL, LOG_DEBUG, LOC + QString("Action: %1").arg(actions));
00285 }