From e13de7268b72005750d01e6ba4150223dc9b5074 Mon Sep 17 00:00:00 2001 From: dvblogic Date: Thu, 30 Apr 2015 18:04:05 +0200 Subject: [PATCH] Version 1.9.13 backport to Helix Version 1.9.13.1 Added: Extended series settings dialog Added: "No grouping for single recording" setting Fixed: Long delay when starting transcoded stream from server that does not support it Speed and memory use optimizations --- addons/pvr.dvblink/addon/addon.xml.in | 2 +- addons/pvr.dvblink/addon/changelog.txt | 12 + .../resources/language/English/strings.po | 43 ++- .../pvr.dvblink/addon/resources/settings.xml | 4 +- .../skin.confluence/720p/RecordPrefs.xml | 112 +++++- addons/pvr.dvblink/src/DVBLinkClient.cpp | 343 ++++++++++++++---- addons/pvr.dvblink/src/DVBLinkClient.h | 18 +- addons/pvr.dvblink/src/DialogRecordPref.cpp | 90 ++++- addons/pvr.dvblink/src/DialogRecordPref.h | 24 +- addons/pvr.dvblink/src/HttpPostClient.cpp | 79 ++-- addons/pvr.dvblink/src/client.cpp | 48 ++- addons/pvr.dvblink/src/client.h | 3 +- lib/libdvblinkremote/Makefile.am | 2 + lib/libdvblinkremote/dvblinkremote.h | 26 ++ .../dvblinkremotecommunication.cpp | 10 + .../dvblinkremoteconnection.h | 2 + lib/libdvblinkremote/favorites.cpp | 131 +++++++ lib/libdvblinkremote/playback_item.cpp | 18 +- .../VS2010Express/libdvblinkremote.vcxproj | 2 + .../libdvblinkremote.vcxproj.filters | 6 + lib/libdvblinkremote/request.h | 45 ++- lib/libdvblinkremote/response.h | 94 +++++ lib/libdvblinkremote/scheduling.cpp | 45 ++- lib/libdvblinkremote/scheduling.h | 32 +- lib/libdvblinkremote/server_info.cpp | 76 ++++ lib/libdvblinkremote/xml_object_serializer.h | 41 +++ .../xml_object_serializer_factory.cpp | 18 +- 27 files changed, 1155 insertions(+), 171 deletions(-) create mode 100644 lib/libdvblinkremote/favorites.cpp create mode 100644 lib/libdvblinkremote/server_info.cpp diff --git a/addons/pvr.dvblink/addon/addon.xml.in b/addons/pvr.dvblink/addon/addon.xml.in index 85dd96c73..03c2517d4 100644 --- a/addons/pvr.dvblink/addon/addon.xml.in +++ b/addons/pvr.dvblink/addon/addon.xml.in @@ -1,7 +1,7 @@ diff --git a/addons/pvr.dvblink/addon/changelog.txt b/addons/pvr.dvblink/addon/changelog.txt index fff6264a7..040b40532 100644 --- a/addons/pvr.dvblink/addon/changelog.txt +++ b/addons/pvr.dvblink/addon/changelog.txt @@ -1,3 +1,15 @@ +[B]Version 1.9.13.1[/B] +Added: Extended series settings dialog +Added: "No grouping for single recording" setting +Fixed: Long delay when starting transcoded stream from server that does not support it +Speed and memory use optimizations + +[B]Version 1.9.13[/B] +Fixed: no timers are added from EPG of DVBLink TV Adviser product +Added: Grouping recordings by series +Added: Year to the episode title +Fixed: incorrect available disk space calculations + [B]Version 1.9.12[/B] Fixed: platform fixes diff --git a/addons/pvr.dvblink/addon/resources/language/English/strings.po b/addons/pvr.dvblink/addon/resources/language/English/strings.po index bfd99d7a5..8ef8cf96c 100644 --- a/addons/pvr.dvblink/addon/resources/language/English/strings.po +++ b/addons/pvr.dvblink/addon/resources/language/English/strings.po @@ -118,7 +118,12 @@ msgctxt "#30203" msgid "Combine title and episode name for recordings" msgstr "" -#empty strings from id 30204 to 32000 +msgctxt "#30204" +msgid "Group Recordings by Series" +msgstr "" + +#empty strings from id 30205 to 32000 + #category labels msgctxt "#32001" @@ -182,3 +187,39 @@ msgstr "" msgctxt "#32016" msgid "Delete the entire series" msgstr "" + +msgctxt "#32017" +msgid "Margin before (minutes)" +msgstr "" + +msgctxt "#32018" +msgid "Margin after (minutes)" +msgstr "" + +msgctxt "#32019" +msgid "New episodes only" +msgstr "" + +msgctxt "#32020" +msgid "Broadcast anytime" +msgstr "" + +msgctxt "#32021" +msgid "Number of episodes to keep" +msgstr "" + +msgctxt "#32022" +msgid "Default" +msgstr "" + +msgctxt "#32023" +msgid "Keep all" +msgstr "" + +msgctxt "#32024" +msgid "Playback failed. Server does not support transcoding" +msgstr "" + +msgctxt "#32025" +msgid "Do not group single recordings" +msgstr "" diff --git a/addons/pvr.dvblink/addon/resources/settings.xml b/addons/pvr.dvblink/addon/resources/settings.xml index 02e4e7de6..0617ef185 100644 --- a/addons/pvr.dvblink/addon/resources/settings.xml +++ b/addons/pvr.dvblink/addon/resources/settings.xml @@ -21,5 +21,7 @@ - + + + \ No newline at end of file diff --git a/addons/pvr.dvblink/addon/resources/skins/skin.confluence/720p/RecordPrefs.xml b/addons/pvr.dvblink/addon/resources/skins/skin.confluence/720p/RecordPrefs.xml index 6608daa57..221c6d90b 100644 --- a/addons/pvr.dvblink/addon/resources/skins/skin.confluence/720p/RecordPrefs.xml +++ b/addons/pvr.dvblink/addon/resources/skins/skin.confluence/720p/RecordPrefs.xml @@ -12,7 +12,7 @@ 0 0 800 - 300 + 530 DialogBack.png @@ -54,11 +54,11 @@ system.getbool(input.enablemouse) - + 40 100 720 - 100 + 360 episode recording 0 @@ -92,13 +92,109 @@ 11 11 10 - 1 + 12 + + + + Separator + 0 + 95 + 2 + 720 + stretch + separator2.png + + + + Record minutes before + 0 + 107 + 40 + 720 + + 11 + 11 + 11 + 13 + + + + Record minutes after + 0 + 154 + 40 + 720 + + 11 + 11 + 12 + 14 + + + + Separator + 0 + 204 + 2 + 720 + stretch + separator2.png + + + + new only + 0 + 216 + 40 + 720 + + font13 + grey2 + white + button-nofocus.png + button-focus2.png + 10 + 10 + 13 + 15 + + + + anytime + 0 + 261 + 40 + 720 + + font13 + grey2 + white + button-nofocus.png + button-focus2.png + 11 + 11 + 14 + 16 - + + number to keep + 0 + 306 + 40 + 720 + + 11 + 11 + 15 + 1 + + + + 190 - 235 + 455 Ok Button 0 @@ -111,7 +207,7 @@ button-focus.png font12_title - 11 + 16 2 2 10 @@ -128,7 +224,7 @@ button-focus.png font12_title - 11 + 16 1 1 10 diff --git a/addons/pvr.dvblink/src/DVBLinkClient.cpp b/addons/pvr.dvblink/src/DVBLinkClient.cpp index 5bac2fa45..2e8198d32 100644 --- a/addons/pvr.dvblink/src/DVBLinkClient.cpp +++ b/addons/pvr.dvblink/src/DVBLinkClient.cpp @@ -58,7 +58,7 @@ std::string DVBLinkClient::GetBuildInRecorderObjectID() } DVBLinkClient::DVBLinkClient(CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_pvr* pvr, CHelper_libXBMC_gui* gui, std::string clientname, std::string hostname, - long port, bool showinfomsg, std::string username, std::string password, bool add_episode_to_rec_title) + long port, bool showinfomsg, std::string username, std::string password, bool add_episode_to_rec_title, bool group_recordings_by_series, bool no_group_single_rec) { PVR = pvr; XBMC = xbmc; @@ -69,6 +69,11 @@ DVBLinkClient::DVBLinkClient(CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_pvr* p m_currentChannelId = 0; m_showinfomsg = showinfomsg; m_add_episode_to_rec_title = add_episode_to_rec_title; + m_group_recordings_by_series = group_recordings_by_series; + no_group_single_rec_ = no_group_single_rec; + setting_margins_supported_ = false; + favorites_supported_ = false; + transcoding_supported_ = false; m_httpClient = new HttpPostClient(XBMC,hostname, port, username, password); m_dvblinkRemoteCommunication = DVBLinkRemote::Connect((HttpClient&)*m_httpClient, m_hostname.c_str(), port, username.c_str(), password.c_str()); @@ -77,6 +82,27 @@ DVBLinkClient::DVBLinkClient(CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_pvr* p m_timerCount = -1; m_recordingCount = -1; + //get server version and build + GetServerInfoRequest server_info_request; + ServerInfo si; + if ((status = m_dvblinkRemoteCommunication->GetServerInfo(server_info_request, si)) == DVBLINK_REMOTE_STATUS_OK) + { + int server_build = atoi(si.build_.c_str()); + + //server with build earlier than 11410 does not support setting margins + setting_margins_supported_ = (server_build >= 11405); + } + + GetStreamingCapabilitiesRequest streamin_caps_request; + StreamingCapabilities streaming_caps; + status = m_dvblinkRemoteCommunication->GetStreamingCapabilities(streamin_caps_request, streaming_caps); + if (status == DVBLINK_REMOTE_STATUS_OK) + transcoding_supported_ = streaming_caps.IsTranscoderSupported(dvblinkremote::StreamingCapabilities::STREAMING_TRANSCODER_H264); + + GetFavoritesRequest favorites_request; + status = m_dvblinkRemoteCommunication->GetFavorites(favorites_request, channel_favorites_); + favorites_supported_ = (status == DVBLINK_REMOTE_STATUS_OK); + GetChannelsRequest request; m_channels = new ChannelList(); m_stream = new Stream(); @@ -88,7 +114,9 @@ DVBLinkClient::DVBLinkClient(CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_pvr* p for (std::vector::iterator it = m_channels->begin(); it < m_channels->end(); it++) { Channel* channel = (*it); - m_channelMap[++iChannelUnique] = channel; + int channel_id = ++iChannelUnique; + m_channelMap[channel_id] = channel; + inverse_channel_map_[channel->GetID()] = channel_id; } m_connected = true; @@ -100,7 +128,12 @@ DVBLinkClient::DVBLinkClient(CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_pvr* p } m_recordingsid = GetBuildInRecorderObjectID(); - m_recordingsid.append(DVBLINK_RECODINGS_BY_DATA_ID); + + m_recordingsid_by_date = m_recordingsid; + m_recordingsid_by_date.append(DVBLINK_RECODINGS_BY_DATA_ID); + + m_recordingsid_by_series = m_recordingsid; + m_recordingsid_by_series.append(DVBLINK_RECODINGS_BY_SERIES_ID); m_updating = true; CreateThread(); @@ -159,7 +192,11 @@ PVR_ERROR DVBLinkClient::GetChannels(ADDON_HANDLE handle, bool bRadio) PVR_CHANNEL xbmcChannel; memset(&xbmcChannel, 0, sizeof(PVR_CHANNEL)); xbmcChannel.bIsRadio = isRadio; - xbmcChannel.iChannelNumber =channel->Number; + if (channel->Number != -1) + { + xbmcChannel.iChannelNumber = channel->Number; + xbmcChannel.iSubChannelNumber = channel->SubNumber; + } xbmcChannel.iEncryptionSystem = 0; xbmcChannel.iUniqueId = (*it).first; @@ -173,6 +210,68 @@ PVR_ERROR DVBLinkClient::GetChannels(ADDON_HANDLE handle, bool bRadio) return PVR_ERROR_NO_ERROR; } +int DVBLinkClient::GetChannelGroupsAmount(void) +{ + if (!favorites_supported_) + return -1; + + return channel_favorites_.favorites_.size(); +} + +PVR_ERROR DVBLinkClient::GetChannelGroups(ADDON_HANDLE handle, bool bRadio) +{ + if (!favorites_supported_) + return PVR_ERROR_NOT_IMPLEMENTED; + + //no radio-only channel groups are supported + if (bRadio) + return PVR_ERROR_NO_ERROR; + + for (size_t i = 0; iTransferChannelGroup(handle, &group); + } + + return PVR_ERROR_NO_ERROR; +} + +PVR_ERROR DVBLinkClient::GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group) +{ + if (!favorites_supported_) + return PVR_ERROR_NOT_IMPLEMENTED; + + for (size_t i = 0; iNumber != -1) + member.iChannelNumber = ch->Number; + + PVR->TransferChannelGroupMember(handle, &member); + } + } + } + return PVR_ERROR_NO_ERROR; +} + int DVBLinkClient::GetTimersAmount() { return m_timerCount; @@ -263,7 +362,7 @@ PVR_ERROR DVBLinkClient::GetTimers(ADDON_HANDLE handle) xbmcTimer.bIsRepeating = rec->GetProgram().IsRepeatRecord; - PVR_STR2INT(xbmcTimer.iEpgUid, rec->GetProgram().GetID().c_str()); + xbmcTimer.iEpgUid = rec->GetProgram().GetStartTime(); xbmcTimer.startTime =rec->GetProgram().GetStartTime(); xbmcTimer.endTime = rec->GetProgram().GetStartTime() + rec->GetProgram().GetDuration(); @@ -290,6 +389,23 @@ PVR_ERROR DVBLinkClient::GetTimers(ADDON_HANDLE handle) return result; } +bool DVBLinkClient::get_dvblink_program_id(std::string& channelId, int start_time, std::string& dvblink_program_id) +{ + bool ret_val = false; + + EpgSearchResult epgSearchResult; + if (DoEPGSearch(epgSearchResult, channelId, start_time, start_time)) + { + if (epgSearchResult.size() > 0 && epgSearchResult.at(0)->GetEpgData().size() > 0) + { + dvblink_program_id = epgSearchResult.at(0)->GetEpgData().at(0)->GetID(); + ret_val = true; + } + } + + return ret_val; +} + static bool is_bit_set(int bit_num, unsigned char bit_field) { unsigned char mask = (0x01 << bit_num); @@ -306,25 +422,47 @@ PVR_ERROR DVBLinkClient::AddTimer(const PVR_TIMER &timer) if (timer.iEpgUid != -1) { bool record_series = false; + bool newOnly = true; + bool anytime = true; + int marginBefore = CDialogRecordPref::c_default_margin; + int marginAfter = CDialogRecordPref::c_default_margin; + int numberToKeep = CDialogRecordPref::c_keep_all_recordings; //do not ask if record is pressed during watching if (timer.startTime != 0) { // ask how to record this program - CDialogRecordPref vWindow(XBMC, GUI, record_series); + CDialogRecordPref vWindow(XBMC, GUI); int dlg_res = vWindow.DoModal(); if (dlg_res == 1) { record_series = vWindow.RecSeries; - } else + newOnly = vWindow.newOnly; + anytime = vWindow.anytime; + marginBefore = vWindow.marginBefore == CDialogRecordPref::c_default_margin ? CDialogRecordPref::c_default_margin : vWindow.marginBefore * 60; + marginAfter = vWindow.marginAfter == CDialogRecordPref::c_default_margin ? CDialogRecordPref::c_default_margin : vWindow.marginAfter * 60;; + numberToKeep = vWindow.numberToKeep; + } + else { if (dlg_res == 0) return PVR_ERROR_NO_ERROR; } } - char programId [128]; - PVR_INT2STR(programId,timer.iEpgUid); - addScheduleRequest = new AddScheduleByEpgRequest(channelId, programId, record_series); + std::string dvblink_program_id; + if (get_dvblink_program_id(channelId, timer.iEpgUid, dvblink_program_id)) + { + if (!setting_margins_supported_) + { + marginBefore = CDialogRecordPref::c_default_margin; + marginAfter = CDialogRecordPref::c_default_margin; + } + addScheduleRequest = new AddScheduleByEpgRequest(channelId, dvblink_program_id, record_series, newOnly, anytime, numberToKeep, marginBefore, marginAfter); + } + else + { + return PVR_ERROR_FAILED; + } } else { @@ -482,13 +620,13 @@ PVR_ERROR DVBLinkClient::DeleteRecording(const PVR_RECORDING& recording) return result; } -static std::string get_subtitle(int season, int episode, const std::string& episode_name) +static std::string get_subtitle(int season, int episode, const std::string& episode_name, int year) { std::string se_str; + char buf[1024]; + if (season > 0 || episode > 0) { - char buf[1024]; - se_str += "("; if (season > 0) { @@ -502,81 +640,131 @@ static std::string get_subtitle(int season, int episode, const std::string& epis } se_str += ")"; } + + if (year > 0) + { + if (se_str.size() > 0) + se_str += " "; + + se_str += "["; + sprintf(buf, "%04d", year); + se_str += buf; + se_str += "]"; + } + if (episode_name.size() > 0) - se_str += " " + episode_name; + { + if (se_str.size() > 0) + se_str += " - "; + + se_str += episode_name; + } + return se_str; } PVR_ERROR DVBLinkClient::GetRecordings(ADDON_HANDLE handle) { - PLATFORM::CLockObject critsec(m_mutex); - PVR_ERROR result = PVR_ERROR_FAILED; - DVBLinkRemoteStatusCode status; - m_recording_id_to_url_map.clear(); + PLATFORM::CLockObject critsec(m_mutex); + PVR_ERROR result = PVR_ERROR_FAILED; + DVBLinkRemoteStatusCode status; + m_recording_id_to_url_map.clear(); - GetPlaybackObjectRequest getPlaybackObjectRequest(m_hostname.c_str(), m_recordingsid); - getPlaybackObjectRequest.IncludeChildrenObjectsForRequestedObject = true; - GetPlaybackObjectResponse getPlaybackObjectResponse; + GetPlaybackObjectRequest getPlaybackObjectRequest(m_hostname.c_str(), m_recordingsid_by_date); + getPlaybackObjectRequest.IncludeChildrenObjectsForRequestedObject = true; + GetPlaybackObjectResponse getPlaybackObjectResponse; - if ((status = m_dvblinkRemoteCommunication->GetPlaybackObject(getPlaybackObjectRequest, getPlaybackObjectResponse)) != DVBLINK_REMOTE_STATUS_OK) - { - std::string error; - m_dvblinkRemoteCommunication->GetLastError(error); - XBMC->Log(LOG_ERROR,"Could not get recordings (Error code : %d Description : %s)", (int)status, error.c_str()); - //XBMC->QueueNotification(QUEUE_ERROR, XBMC->GetLocalizedString(32004), (int)status); - return result; - } - - XBMC->Log(LOG_INFO, "Found %d recordings", getPlaybackObjectResponse.GetPlaybackItems().size()); - - if (m_showinfomsg) - { - XBMC->QueueNotification(QUEUE_INFO, XBMC->GetLocalizedString(32009), getPlaybackObjectResponse.GetPlaybackItems().size()); - } + if ((status = m_dvblinkRemoteCommunication->GetPlaybackObject(getPlaybackObjectRequest, getPlaybackObjectResponse)) != DVBLINK_REMOTE_STATUS_OK) + { + std::string error; + m_dvblinkRemoteCommunication->GetLastError(error); + XBMC->Log(LOG_ERROR, "Could not get recordings (Error code : %d Description : %s)", (int)status, error.c_str()); + //XBMC->QueueNotification(QUEUE_ERROR, XBMC->GetLocalizedString(32004), (int)status); + return result; + } - for (std::vector::iterator it = getPlaybackObjectResponse.GetPlaybackItems().begin(); it < getPlaybackObjectResponse.GetPlaybackItems().end(); it++) - { - RecordedTvItem * tvitem = (RecordedTvItem *) *it; - PVR_RECORDING xbmcRecording; - memset(&xbmcRecording, 0, sizeof(PVR_RECORDING)); - - PVR_STRCPY(xbmcRecording.strRecordingId,tvitem->GetObjectID().c_str()); + XBMC->Log(LOG_INFO, "Found %d recordings", getPlaybackObjectResponse.GetPlaybackItems().size()); - std::string title = tvitem->GetMetadata().GetTitle(); - if (m_add_episode_to_rec_title) + if (m_showinfomsg) { - //form a title as "name - (SxxExx) subtitle" because XBMC does not display episode/season information almost anywhere - std::string se_str = get_subtitle(tvitem->GetMetadata().SeasonNumber, tvitem->GetMetadata().EpisodeNumber, tvitem->GetMetadata().SubTitle); - if (se_str.size() > 0) - title += " - " + se_str; + XBMC->QueueNotification(QUEUE_INFO, XBMC->GetLocalizedString(32009), getPlaybackObjectResponse.GetPlaybackItems().size()); } - PVR_STRCPY(xbmcRecording.strTitle, title.c_str()); - - xbmcRecording.recordingTime = tvitem->GetMetadata().GetStartTime(); - PVR_STRCPY(xbmcRecording.strPlot, tvitem->GetMetadata().ShortDescription.c_str()); - PVR_STRCPY(xbmcRecording.strPlotOutline, tvitem->GetMetadata().SubTitle.c_str()); -// PVR_STRCPY(xbmcRecording.strStreamURL, tvitem->GetPlaybackUrl().c_str()); - m_recording_id_to_url_map[xbmcRecording.strRecordingId] = tvitem->GetPlaybackUrl(); - xbmcRecording.iDuration = tvitem->GetMetadata().GetDuration(); - PVR_STRCPY(xbmcRecording.strChannelName, tvitem->ChannelName.c_str()); - PVR_STRCPY(xbmcRecording.strThumbnailPath, tvitem->GetThumbnailUrl().c_str()); - int genre_type, genre_subtype; - SetEPGGenre(tvitem->GetMetadata(), genre_type, genre_subtype); - if (genre_type == EPG_GENRE_USE_STRING) - { - xbmcRecording.iGenreType = EPG_EVENT_CONTENTMASK_UNDEFINED; - } else + + std::map schedule_to_num_map; + if (no_group_single_rec_) { - xbmcRecording.iGenreType = genre_type; - xbmcRecording.iGenreSubType = genre_subtype; + //build a map with scheule id -> number of recordings + for (std::vector::iterator it = getPlaybackObjectResponse.GetPlaybackItems().begin(); it < getPlaybackObjectResponse.GetPlaybackItems().end(); it++) + { + RecordedTvItem * tvitem = (RecordedTvItem *)*it; + if (tvitem->ScheduleId.size() > 0 && tvitem->SeriesSchedule) + { + if (schedule_to_num_map.find(tvitem->ScheduleId) == schedule_to_num_map.end()) + schedule_to_num_map[tvitem->ScheduleId] = 0; + + schedule_to_num_map[tvitem->ScheduleId] = schedule_to_num_map[tvitem->ScheduleId] + 1; + } + } } - PVR->TransferRecordingEntry(handle, &xbmcRecording); + for (std::vector::iterator it = getPlaybackObjectResponse.GetPlaybackItems().begin(); it < getPlaybackObjectResponse.GetPlaybackItems().end(); it++) + { + RecordedTvItem * tvitem = (RecordedTvItem *)*it; + PVR_RECORDING xbmcRecording; + memset(&xbmcRecording, 0, sizeof(PVR_RECORDING)); - } - m_recordingCount = getPlaybackObjectResponse.GetPlaybackItems().size(); - result = PVR_ERROR_NO_ERROR; - return result; + PVR_STRCPY(xbmcRecording.strRecordingId, tvitem->GetObjectID().c_str()); + + std::string title = tvitem->GetMetadata().GetTitle(); + if (m_add_episode_to_rec_title) + { + //form a title as "name - (SxxExx) subtitle" because XBMC does not display episode/season information almost anywhere + std::string se_str = get_subtitle(tvitem->GetMetadata().SeasonNumber, tvitem->GetMetadata().EpisodeNumber, tvitem->GetMetadata().SubTitle, (int)tvitem->GetMetadata().Year); + if (se_str.size() > 0) + title += " - " + se_str; + } + PVR_STRCPY(xbmcRecording.strTitle, title.c_str()); + + xbmcRecording.recordingTime = tvitem->GetMetadata().GetStartTime(); + PVR_STRCPY(xbmcRecording.strPlot, tvitem->GetMetadata().ShortDescription.c_str()); + PVR_STRCPY(xbmcRecording.strPlotOutline, tvitem->GetMetadata().SubTitle.c_str()); + // PVR_STRCPY(xbmcRecording.strStreamURL, tvitem->GetPlaybackUrl().c_str()); + m_recording_id_to_url_map[xbmcRecording.strRecordingId] = tvitem->GetPlaybackUrl(); + xbmcRecording.iDuration = tvitem->GetMetadata().GetDuration(); + PVR_STRCPY(xbmcRecording.strChannelName, tvitem->ChannelName.c_str()); + PVR_STRCPY(xbmcRecording.strThumbnailPath, tvitem->GetThumbnailUrl().c_str()); + int genre_type, genre_subtype; + SetEPGGenre(tvitem->GetMetadata(), genre_type, genre_subtype); + if (genre_type == EPG_GENRE_USE_STRING) + { + xbmcRecording.iGenreType = EPG_EVENT_CONTENTMASK_UNDEFINED; + } + else + { + xbmcRecording.iGenreType = genre_type; + xbmcRecording.iGenreSubType = genre_subtype; + } + + if (m_group_recordings_by_series) + { + if (tvitem->ScheduleId.size() > 0 && tvitem->SeriesSchedule && tvitem->ScheduleName.size() > 0) + { + bool b = true; + + if (no_group_single_rec_ && schedule_to_num_map.find(tvitem->ScheduleId) != schedule_to_num_map.end() && schedule_to_num_map[tvitem->ScheduleId] < 2) + b = false; + + if (b) + PVR_STRCPY(xbmcRecording.strDirectory, tvitem->ScheduleName.c_str()); + } + } + + PVR->TransferRecordingEntry(handle, &xbmcRecording); + + } + m_recordingCount = getPlaybackObjectResponse.GetPlaybackItems().size(); + result = PVR_ERROR_NO_ERROR; + return result; } bool DVBLinkClient::GetRecordingURL(const char* recording_id, std::string& url) @@ -605,7 +793,7 @@ void DVBLinkClient::GetDriveSpace(long long *iTotal, long long *iUsed) if ((status = m_dvblinkRemoteCommunication->GetRecordingSettings(recordingsettingsrequest, settings)) == DVBLINK_REMOTE_STATUS_OK) { *iTotal = settings.TotalSpace; - *iUsed = settings.AvailableSpace; + *iUsed = (settings.TotalSpace - settings.AvailableSpace); } } @@ -636,6 +824,13 @@ bool DVBLinkClient::OpenLiveStream(const PVR_CHANNEL &channel, bool use_timeshif { bool ret_val = false; + //if transcoding is requested and no transcoder is supported return false + if (use_transcoder && !transcoding_supported_) + { + XBMC->QueueNotification(QUEUE_ERROR, XBMC->GetLocalizedString(32024)); + return false; + } + PLATFORM::CLockObject critsec(m_mutex); if (m_live_streamer) @@ -847,7 +1042,7 @@ PVR_ERROR DVBLinkClient::GetEPGForChannel(ADDON_HANDLE handle, const PVR_CHANNEL EPG_TAG broadcast; memset(&broadcast, 0, sizeof(EPG_TAG)); - PVR_STR2INT(broadcast.iUniqueBroadcastId, p->GetID().c_str() ); + broadcast.iUniqueBroadcastId = p->GetStartTime(); broadcast.strTitle = p->GetTitle().c_str(); broadcast.iChannelNumber = channel.iChannelNumber; broadcast.startTime = p->GetStartTime(); diff --git a/addons/pvr.dvblink/src/DVBLinkClient.h b/addons/pvr.dvblink/src/DVBLinkClient.h index cd0f29dab..7e3a9188b 100644 --- a/addons/pvr.dvblink/src/DVBLinkClient.h +++ b/addons/pvr.dvblink/src/DVBLinkClient.h @@ -40,6 +40,7 @@ #define DVBLINK_BUILD_IN_RECORDER_SOURCE_ID "8F94B459-EFC0-4D91-9B29-EC3D72E92677" #define DVBLINK_RECODINGS_BY_DATA_ID "F6F08949-2A07-4074-9E9D-423D877270BB" +#define DVBLINK_RECODINGS_BY_SERIES_ID "0E03FEB8-BD8F-46e7-B3EF-34F6890FB458" typedef std::map recording_id_to_url_map_t; @@ -47,7 +48,7 @@ class DVBLinkClient : public PLATFORM::CThread { public: DVBLinkClient(ADDON::CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_pvr* pvr, CHelper_libXBMC_gui* gui, std::string clientname, std::string hostname, long port, - bool showinfomsg, std::string username, std::string password, bool add_episode_to_rec_title); + bool showinfomsg, std::string username, std::string password, bool add_episode_to_rec_title, bool group_recordings_by_series, bool no_group_single_rec); ~DVBLinkClient(void); int GetChannelsAmount(); PVR_ERROR GetChannels(ADDON_HANDLE handle, bool bRadio); @@ -60,6 +61,10 @@ class DVBLinkClient : public PLATFORM::CThread PVR_ERROR AddTimer(const PVR_TIMER &timer); PVR_ERROR DeleteTimer(const PVR_TIMER &timer); PVR_ERROR UpdateTimer(const PVR_TIMER &timer); + int GetChannelGroupsAmount(void); + PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio); + PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group); + bool GetStatus(); bool StartStreaming(const PVR_CHANNEL &channel, dvblinkremote::StreamRequest* streamRequest, std::string& stream_url); bool OpenLiveStream(const PVR_CHANNEL &channel, bool use_timeshift, bool use_transcoder, int width, int height, int bitrate, std::string audiotrack); @@ -82,6 +87,8 @@ class DVBLinkClient : public PLATFORM::CThread std::string GetRecordedTVByDateObjectID(const std::string& buildInRecoderObjectID); int GetInternalUniqueIdFromChannelId(const std::string& channelId); virtual void * Process(void); + bool build_recording_series_map(std::map& rec_id_to_series_name); + bool get_dvblink_program_id(std::string& channelId, int start_time, std::string& dvblink_program_id); std::string make_timer_hash(const std::string& timer_id, const std::string& schedule_id); bool parse_timer_hash(const char* timer_hash, std::string& timer_id, std::string& schedule_id); @@ -103,10 +110,19 @@ class DVBLinkClient : public PLATFORM::CThread std::string m_hostname; LiveStreamerBase* m_live_streamer; bool m_add_episode_to_rec_title; + bool m_group_recordings_by_series; bool m_showinfomsg; bool m_updating; std::string m_recordingsid; + std::string m_recordingsid_by_date; + std::string m_recordingsid_by_series; recording_id_to_url_map_t m_recording_id_to_url_map; + bool setting_margins_supported_; + bool favorites_supported_; + bool transcoding_supported_; + dvblinkremote::ChannelFavorites channel_favorites_; + std::map inverse_channel_map_; + bool no_group_single_rec_; }; /*! diff --git a/addons/pvr.dvblink/src/DialogRecordPref.cpp b/addons/pvr.dvblink/src/DialogRecordPref.cpp index 966bd90cc..823edacbd 100644 --- a/addons/pvr.dvblink/src/DialogRecordPref.cpp +++ b/addons/pvr.dvblink/src/DialogRecordPref.cpp @@ -31,10 +31,21 @@ using namespace ADDON; #define RADIO_BUTTON_EPISODE 10 #define RADIO_BUTTON_SERIES 11 +#define SPIN_MARGIN_BEFORE 12 +#define SPIN_MARGIN_AFTER 13 +#define RADIO_BUTTON_NEW_ONLY 14 +#define RADIO_BUTTON_ANYTIME 15 +#define SPIN_REC_TO_KEEP 16 -CDialogRecordPref::CDialogRecordPref(CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_gui* gui, bool recSeries) +CDialogRecordPref::CDialogRecordPref(CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_gui* gui) { - RecSeries = recSeries; + RecSeries = false; + newOnly = true; + anytime = true; + marginBefore = c_default_margin; + marginAfter = c_default_margin; + numberToKeep = c_keep_all_recordings; + GUI = gui; XBMC = xbmc; @@ -58,39 +69,108 @@ bool CDialogRecordPref::OnInit() // init radio buttons _radioRecEpisode = GUI->Control_getRadioButton(_window, RADIO_BUTTON_EPISODE); _radioRecSeries = GUI->Control_getRadioButton(_window, RADIO_BUTTON_SERIES); + _radioNewOnly = GUI->Control_getRadioButton(_window, RADIO_BUTTON_NEW_ONLY); + _radioAnytime = GUI->Control_getRadioButton(_window, RADIO_BUTTON_ANYTIME); + _marginBefore = GUI->Control_getSpin(_window, SPIN_MARGIN_BEFORE); + _marginAfter = GUI->Control_getSpin(_window, SPIN_MARGIN_AFTER); + _marginNumberToKeep = GUI->Control_getSpin(_window, SPIN_REC_TO_KEEP); + _radioRecEpisode->SetSelected(!RecSeries); - _radioRecSeries->SetSelected(RecSeries); + _radioRecSeries->SetSelected(RecSeries); + + PopulateMarginSpin(_marginBefore); + _marginBefore->SetValue(marginBefore); + + PopulateMarginSpin(_marginAfter); + _marginAfter->SetValue(marginAfter); + + PopulateKeepSpin(_marginNumberToKeep); + _marginNumberToKeep->SetValue(numberToKeep); + + _radioNewOnly->SetSelected(newOnly); + _radioAnytime->SetSelected(anytime); + + HideShowSeriesControls(RecSeries); return true; } +void CDialogRecordPref::PopulateMarginSpin(CAddonGUISpinControl* spin) +{ + spin->AddLabel(XBMC->GetLocalizedString(32022), c_default_margin); + spin->AddLabel("0", 0); + spin->AddLabel("1", 1); + spin->AddLabel("2", 2); + spin->AddLabel("3", 3); + spin->AddLabel("4", 4); + spin->AddLabel("5", 5); + spin->AddLabel("10", 10); + spin->AddLabel("15", 15); + spin->AddLabel("30", 30); + spin->AddLabel("60", 60); +} + +void CDialogRecordPref::PopulateKeepSpin(CAddonGUISpinControl* spin) +{ + spin->AddLabel(XBMC->GetLocalizedString(32023), c_keep_all_recordings); + spin->AddLabel("1", 1); + spin->AddLabel("2", 2); + spin->AddLabel("3", 3); + spin->AddLabel("4", 4); + spin->AddLabel("5", 5); + spin->AddLabel("6", 6); + spin->AddLabel("7", 7); + spin->AddLabel("8", 8); + spin->AddLabel("9", 9); + spin->AddLabel("10", 10); +} + bool CDialogRecordPref::OnClick(int controlId) { switch(controlId) { case BUTTON_OK: // save value from GUI, then FALLS THROUGH TO CANCEL RecSeries = _radioRecSeries->IsSelected(); - case BUTTON_CANCEL: + newOnly = _radioNewOnly->IsSelected(); + anytime = _radioAnytime->IsSelected(); + marginBefore = _marginBefore->GetValue(); + marginAfter = _marginAfter->GetValue(); + numberToKeep = _marginNumberToKeep->GetValue(); + case BUTTON_CANCEL: case BUTTON_CLOSE: if (_confirmed == -1) // if not previously confirmed, set to cancel value _confirmed = 0; _window->Close(); GUI->Control_releaseRadioButton(_radioRecEpisode); GUI->Control_releaseRadioButton(_radioRecSeries); - break; + GUI->Control_releaseRadioButton(_radioNewOnly); + GUI->Control_releaseRadioButton(_radioAnytime); + GUI->Control_releaseSpin(_marginBefore); + GUI->Control_releaseSpin(_marginAfter); + GUI->Control_releaseSpin(_marginNumberToKeep); + break; case RADIO_BUTTON_EPISODE: RecSeries = !_radioRecEpisode->IsSelected(); _radioRecSeries->SetSelected(RecSeries); + HideShowSeriesControls(RecSeries); break; case RADIO_BUTTON_SERIES: RecSeries = _radioRecSeries->IsSelected(); _radioRecEpisode->SetSelected(!RecSeries); + HideShowSeriesControls(RecSeries); break; } return true; } +void CDialogRecordPref::HideShowSeriesControls(bool bShow) +{ + _radioNewOnly->SetVisible(bShow); + _radioAnytime->SetVisible(bShow); + _marginNumberToKeep->SetVisible(bShow); +} + bool CDialogRecordPref::OnInitCB(GUIHANDLE cbhdl) { CDialogRecordPref* dialog = static_cast(cbhdl); diff --git a/addons/pvr.dvblink/src/DialogRecordPref.h b/addons/pvr.dvblink/src/DialogRecordPref.h index ed4ae941f..4b3164680 100644 --- a/addons/pvr.dvblink/src/DialogRecordPref.h +++ b/addons/pvr.dvblink/src/DialogRecordPref.h @@ -27,7 +27,11 @@ class CDialogRecordPref { public: - CDialogRecordPref(ADDON::CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_gui* gui, bool recSeries); + static const int c_keep_all_recordings = 0; + static const int c_default_margin = -1; + +public: + CDialogRecordPref(ADDON::CHelper_libXBMC_addon* xbmc, CHelper_libXBMC_gui* gui); virtual ~CDialogRecordPref(); bool Show(); @@ -35,11 +39,21 @@ class CDialogRecordPref int DoModal(); // returns -1=> load failed, 0=>canceled, 1=>confirmed // dialog specific params - bool RecSeries; // values returned - + bool RecSeries; + bool newOnly; + bool anytime; + int marginBefore; + int marginAfter; + int numberToKeep; + private: CAddonGUIRadioButton *_radioRecEpisode; CAddonGUIRadioButton *_radioRecSeries; + CAddonGUIRadioButton *_radioNewOnly; + CAddonGUIRadioButton *_radioAnytime; + CAddonGUISpinControl *_marginBefore; + CAddonGUISpinControl *_marginAfter; + CAddonGUISpinControl *_marginNumberToKeep; // following is needed for every dialog private: @@ -53,6 +67,10 @@ class CDialogRecordPref bool OnInit(); bool OnAction(int actionId); + void HideShowSeriesControls(bool bShow); + void PopulateMarginSpin(CAddonGUISpinControl* spin); + void PopulateKeepSpin(CAddonGUISpinControl* spin); + static bool OnClickCB(GUIHANDLE cbhdl, int controlId); static bool OnFocusCB(GUIHANDLE cbhdl, int controlId); static bool OnInitCB(GUIHANDLE cbhdl); diff --git a/addons/pvr.dvblink/src/HttpPostClient.cpp b/addons/pvr.dvblink/src/HttpPostClient.cpp index e0d8ca539..dc4b378bc 100644 --- a/addons/pvr.dvblink/src/HttpPostClient.cpp +++ b/addons/pvr.dvblink/src/HttpPostClient.cpp @@ -92,6 +92,7 @@ HttpPostClient::HttpPostClient(CHelper_libXBMC_addon *XBMC, const std::string& int HttpPostClient::SendPostRequest(HttpWebRequest& request) { + int ret_code = -100; std::string buffer; std::string message; char content_header[100]; @@ -141,51 +142,50 @@ int HttpPostClient::SendPostRequest(HttpWebRequest& request) SEND_RQ(buffer.c_str()); - char c1[1]; - int l,line_length; - bool loop = true; - bool bHeader = false; + const int read_buffer_size = 4096; + char read_buffer[read_buffer_size]; + int read_size = 0; + std::string response; + while ((read_size = recv(sock, read_buffer, read_buffer_size, 0)) > 0) + response.append(read_buffer, read_buffer + read_size); + close(sock); - while (loop) + if (response.size() > 0) { - l = recv(sock, c1, 1, 0); - if (l<0) loop = false; - if (c1[0]=='\n') - { - if (line_length == 0) - loop = false; - line_length = 0; - if (message.find("401 Unauthorized") != std::string::npos) + //header + std::string::size_type n = response.find("\r\n"); + if (n != std::string::npos) { - close(sock); - return -401; + std::string header = response.substr(0, n); + if (header.find("200 OK") != std::string::npos) + ret_code = 200; + if (header.find("401 Unauthorized") != std::string::npos) + ret_code = -401; + + if (ret_code == 200) + { + //body + const char* body_sep = "\r\n\r\n"; + n = response.find(body_sep); + if (n != std::string::npos) + { + m_responseData.assign(response.c_str() + n + strlen(body_sep)); + } else + { + ret_code = -105; + } + } + } + else + { + ret_code = -104; } - if (message.find("200 OK") != std::string::npos) - bHeader = true; - } - else if (c1[0]!='\r') - { - line_length++; - } - message += c1[0]; - } - - message=""; - if (bHeader) - { - char p[1024]; - while ((l = recv(sock,p,1023,0)) > 0) { - p[l] = '\0'; - message += p; - } } - else + else { - close(sock); - return -102; + ret_code = -102; } - //TODO: Use xbmc file code when it allows to post content-type application/x-www-form-urlencoded and authentication /* void* hFile = XBMC->OpenFileForWrite(request.GetUrl().c_str(), 0); @@ -215,11 +215,8 @@ int HttpPostClient::SendPostRequest(HttpWebRequest& request) } */ - m_responseData.clear(); - m_responseData.append(message); - close(sock); - return 200; + return ret_code; } bool HttpPostClient::SendRequest(HttpWebRequest& request) diff --git a/addons/pvr.dvblink/src/client.cpp b/addons/pvr.dvblink/src/client.cpp index 9d1ebf9c3..99a511a93 100644 --- a/addons/pvr.dvblink/src/client.cpp +++ b/addons/pvr.dvblink/src/client.cpp @@ -59,6 +59,8 @@ int g_iBitrate = DEFAULT_BITRATE; ///< Bitrat std::string g_szAudiotrack = DEFAULT_AUDIOTRACK; ///< Audiotrack to include in stream when using transcoding bool g_bUseTimeshift = DEFAULT_USETIMESHIFT; ///< Use timeshift bool g_bAddRecEpisode2title = DEFAULT_ADDRECEPISODE2TITLE; ///< Concatenate title and episode info for recordings +bool g_bGroupRecBySeries = DEFAULT_GROUPRECBYSERIES; ///< Group Recordings as Directories by series +bool g_bNoGroupSingleRec = DEFAULT_NOGROUP_SINGLE_REC; ///< Do not group single recordings CHelper_libXBMC_addon *XBMC = NULL; CHelper_libXBMC_pvr *PVR = NULL; CHelper_libXBMC_gui *GUI = NULL; @@ -212,6 +214,22 @@ ADDON_STATUS ADDON_Create(void* hdl, void* props) g_bAddRecEpisode2title = DEFAULT_ADDRECEPISODE2TITLE; } + /* Read setting "Group recordings by title" from settings.xml */ + if (!XBMC->GetSetting("group_recordings_by_series", &g_bGroupRecBySeries)) + { + /* If setting is unknown fallback to defaults */ + XBMC->Log(LOG_ERROR, "Couldn't get 'group_recordings_by_series' setting, falling back to 'true' as default"); + g_bGroupRecBySeries = DEFAULT_GROUPRECBYSERIES; + } + + /* Read setting "Group recordings by title" from settings.xml */ + if (!XBMC->GetSetting("no_group_for_single_record", &g_bNoGroupSingleRec)) + { + /* If setting is unknown fallback to defaults */ + XBMC->Log(LOG_ERROR, "Couldn't get 'no_group_for_single_record' setting, falling back to 'false' as default"); + g_bNoGroupSingleRec = DEFAULT_NOGROUP_SINGLE_REC; + } + /* Read setting "height" from settings.xml */ if (!XBMC->GetSetting("height", &g_iHeight)) { @@ -250,7 +268,7 @@ ADDON_STATUS ADDON_Create(void* hdl, void* props) /* Log the current settings for debugging purposes */ XBMC->Log(LOG_DEBUG, "settings: enable_transcoding='%i' host='%s', port=%i", g_bUseTranscoding, g_szHostname.c_str(), g_lPort); - dvblinkclient = new DVBLinkClient(XBMC, PVR, GUI, g_szClientname, g_szHostname, g_lPort, g_bShowInfoMSG, g_szUsername, g_szPassword, g_bAddRecEpisode2title); + dvblinkclient = new DVBLinkClient(XBMC, PVR, GUI, g_szClientname, g_szHostname, g_lPort, g_bShowInfoMSG, g_szUsername, g_szPassword, g_bAddRecEpisode2title, g_bGroupRecBySeries, g_bNoGroupSingleRec); if (dvblinkclient->GetStatus()) m_CurStatus = ADDON_STATUS_OK; @@ -349,6 +367,18 @@ ADDON_STATUS ADDON_SetSetting(const char *settingName, const void *settingValue) g_bAddRecEpisode2title = *(bool*)settingValue; return ADDON_STATUS_NEED_RESTART; } + else if (str == "group_recordings_by_series") + { + XBMC->Log(LOG_INFO, "Changed Setting 'group_recordings_by_series' from %u to %u", g_bGroupRecBySeries, *(int*)settingValue); + g_bGroupRecBySeries = *(bool*)settingValue; + return ADDON_STATUS_NEED_RESTART; + } + else if (str == "no_group_for_single_record") + { + XBMC->Log(LOG_INFO, "Changed Setting 'no_group_for_single_record' from %u to %u", g_bNoGroupSingleRec, *(int*)settingValue); + g_bNoGroupSingleRec = *(bool*)settingValue; + return ADDON_STATUS_NEED_RESTART; + } else if (str == "height") { XBMC->Log(LOG_INFO, "Changed Setting 'height' from %u to %u", g_iHeight, *(int*) settingValue); @@ -424,6 +454,7 @@ PVR_ERROR GetAddonCapabilities(PVR_ADDON_CAPABILITIES* pCapabilities) pCapabilities->bSupportsTV = true; pCapabilities->bSupportsRadio = true; pCapabilities->bHandlesInputStream = true; + pCapabilities->bSupportsChannelGroups = true; return PVR_ERROR_NO_ERROR; } @@ -786,17 +817,26 @@ PVR_ERROR DialogAddChannel(const PVR_CHANNEL &channel) int GetChannelGroupsAmount(void) { - return -1; + if (dvblinkclient) + return dvblinkclient->GetChannelGroupsAmount(); + + return -1; } PVR_ERROR GetChannelGroups(ADDON_HANDLE handle, bool bRadio) { - return PVR_ERROR_NOT_IMPLEMENTED; + if (dvblinkclient) + return dvblinkclient->GetChannelGroups(handle, bRadio); + + return PVR_ERROR_NOT_IMPLEMENTED; } PVR_ERROR GetChannelGroupMembers(ADDON_HANDLE handle, const PVR_CHANNEL_GROUP &group) { - return PVR_ERROR_NOT_IMPLEMENTED; + if (dvblinkclient) + return dvblinkclient->GetChannelGroupMembers(handle, group); + + return PVR_ERROR_NOT_IMPLEMENTED; } void DemuxReset(void) diff --git a/addons/pvr.dvblink/src/client.h b/addons/pvr.dvblink/src/client.h index 6999f4533..9d8133dde 100644 --- a/addons/pvr.dvblink/src/client.h +++ b/addons/pvr.dvblink/src/client.h @@ -41,4 +41,5 @@ #define DEFAULT_AUDIOTRACK "eng" #define DEFAULT_USETIMESHIFT false #define DEFAULT_ADDRECEPISODE2TITLE true - +#define DEFAULT_GROUPRECBYSERIES true +#define DEFAULT_NOGROUP_SINGLE_REC false diff --git a/lib/libdvblinkremote/Makefile.am b/lib/libdvblinkremote/Makefile.am index f8fbbbd7b..cc387a982 100644 --- a/lib/libdvblinkremote/Makefile.am +++ b/lib/libdvblinkremote/Makefile.am @@ -17,6 +17,8 @@ libdvblinkremote_la_SOURCES = channel.cpp \ recording_settings.cpp \ remove_playback_object_request.cpp \ scheduling.cpp \ + favorites.cpp \ + server_info.cpp \ stop_stream_request.cpp \ stream.cpp \ stream_request.cpp \ diff --git a/lib/libdvblinkremote/dvblinkremote.h b/lib/libdvblinkremote/dvblinkremote.h index 047585b6f..2a2f5193c 100644 --- a/lib/libdvblinkremote/dvblinkremote.h +++ b/lib/libdvblinkremote/dvblinkremote.h @@ -186,6 +186,16 @@ namespace dvblinkremote */ const std::string DVBLINK_REMOTE_SET_RECORDING_SETTING_CMD = "set_recording_settings"; + /** + * A constant string representing the DVBLink command for retrieving channel favorites lists. + */ + const std::string DVBLINK_REMOTE_GET_FAVORITES_CMD = "get_favorites"; + + /** + * A constant string representing the DVBLink command for retrieving server information. + */ + const std::string DVBLINK_REMOTE_GET_SERVER_INFO_CMD = "get_server_info"; + /** * A constant string representing a Real Time Transport Protocol stream type for Android devices. */ @@ -462,6 +472,22 @@ namespace dvblinkremote */ virtual DVBLinkRemoteStatusCode SetRecordingSettings(const SetRecordingSettingsRequest& request) = 0; + /** + * Gets favorites lists. + * @param[in] request A constant GetFavoritesRequest reference representing the get favorites request criterias. + * @param[in,out] response A ChannelFavorites reference that will be populated with channel favorites. + * @return A DVBLinkRemoteStatusCode representing the status of the executed method. + */ + virtual DVBLinkRemoteStatusCode GetFavorites(const GetFavoritesRequest& request, ChannelFavorites& response) = 0; + + /** + * Gets server information - id, version and build number. + * @param[in] request A constant GetServerInfoRequest reference representing the get server info request criterias. + * @param[in,out] response A ServerInfo reference that will be populated with server information. + * @return A DVBLinkRemoteStatusCode representing the status of the executed method. + */ + virtual DVBLinkRemoteStatusCode GetServerInfo(const GetServerInfoRequest& request, ServerInfo& response) = 0; + /** * Gets a description of the last occured error. * @param[in,out] err A string reference representing the string where the description of the last error will be provided. diff --git a/lib/libdvblinkremote/dvblinkremotecommunication.cpp b/lib/libdvblinkremote/dvblinkremotecommunication.cpp index e8579546f..b6a033445 100644 --- a/lib/libdvblinkremote/dvblinkremotecommunication.cpp +++ b/lib/libdvblinkremote/dvblinkremotecommunication.cpp @@ -226,6 +226,16 @@ DVBLinkRemoteStatusCode DVBLinkRemoteCommunication::GetM3uPlaylist(const GetM3uP return GetData(DVBLINK_REMOTE_GET_PLAYLIST_M3U_CMD, request, response); } +DVBLinkRemoteStatusCode DVBLinkRemoteCommunication::GetFavorites(const GetFavoritesRequest& request, ChannelFavorites& response) +{ + return GetData(DVBLINK_REMOTE_GET_FAVORITES_CMD, request, response); +} + +DVBLinkRemoteStatusCode DVBLinkRemoteCommunication::GetServerInfo(const GetServerInfoRequest& request, ServerInfo& response) +{ + return GetData(DVBLINK_REMOTE_GET_SERVER_INFO_CMD, request, response); +} + std::string DVBLinkRemoteCommunication::GetUrl() { char buffer[2000]; diff --git a/lib/libdvblinkremote/dvblinkremoteconnection.h b/lib/libdvblinkremote/dvblinkremoteconnection.h index d1e1abd0e..98f4ab3bd 100644 --- a/lib/libdvblinkremote/dvblinkremoteconnection.h +++ b/lib/libdvblinkremote/dvblinkremoteconnection.h @@ -63,6 +63,8 @@ namespace dvblinkremote DVBLinkRemoteStatusCode GetStreamingCapabilities(const GetStreamingCapabilitiesRequest& request, StreamingCapabilities& response); DVBLinkRemoteStatusCode GetRecordingSettings(const GetRecordingSettingsRequest& request, RecordingSettings& response); DVBLinkRemoteStatusCode SetRecordingSettings(const SetRecordingSettingsRequest& request); + DVBLinkRemoteStatusCode GetFavorites(const GetFavoritesRequest& request, ChannelFavorites& response); + DVBLinkRemoteStatusCode GetServerInfo(const GetServerInfoRequest& request, ServerInfo& response); void GetLastError(std::string& err); private: diff --git a/lib/libdvblinkremote/favorites.cpp b/lib/libdvblinkremote/favorites.cpp new file mode 100644 index 000000000..4e7f96a33 --- /dev/null +++ b/lib/libdvblinkremote/favorites.cpp @@ -0,0 +1,131 @@ +/*************************************************************************** + * Copyright (C) 2012 Marcus Efraimsson. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ***************************************************************************/ + +#include "request.h" +#include "response.h" +#include "xml_object_serializer.h" + +using namespace dvblinkremote; +using namespace dvblinkremoteserialization; + +GetFavoritesRequest::GetFavoritesRequest() +{ } + +GetFavoritesRequest::~GetFavoritesRequest() +{ } + +ChannelFavorite::ChannelFavorite(std::string& id, std::string& name, favorite_channel_list_t& channels) : +id_(id), name_(name), channels_(channels) +{ +} + +ChannelFavorite::~ChannelFavorite() +{ } + +ChannelFavorites::ChannelFavorites() +{ +} + +ChannelFavorites::ChannelFavorites(ChannelFavorites& favorites) +{ + favorites_ = favorites.favorites_; +} + +ChannelFavoritesSerializer::GetFavoritesResponseXmlDataDeserializer::GetFavoritesResponseXmlDataDeserializer(ChannelFavoritesSerializer& parent, ChannelFavorites& favoritesList) + : m_parent(parent), + m_favoritesList(favoritesList) +{ + +} + +ChannelFavorites::~ChannelFavorites() +{ + +} + +ChannelFavoritesSerializer::GetFavoritesResponseXmlDataDeserializer::~GetFavoritesResponseXmlDataDeserializer() +{ + +} + +bool ChannelFavoritesSerializer::GetFavoritesResponseXmlDataDeserializer::VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* attribute) +{ + if (strcmp(element.Name(), "favorite") == 0) + { + std::string id = Util::GetXmlFirstChildElementText(&element, "id"); + std::string name = Util::GetXmlFirstChildElementText(&element, "name"); + + //channels + ChannelFavorite::favorite_channel_list_t channels; + const tinyxml2::XMLElement* channels_element = element.FirstChildElement("channels"); + if (channels_element != NULL) + { + const tinyxml2::XMLElement* channel_element = channels_element->FirstChildElement(); + while (channel_element != NULL) + { + if (strcmp(channel_element->Name(), "channel") == 0) + { + if (channel_element->GetText() != NULL) + channels.push_back(channel_element->GetText()); + } + channel_element = channel_element->NextSiblingElement(); + } + + } + + ChannelFavorite cf(id, name, channels); + + m_favoritesList.favorites_.push_back(cf); + + return false; + } + + return true; +} + +bool GetFavoritesRequestSerializer::WriteObject(std::string& serializedData, GetFavoritesRequest& objectGraph) +{ + tinyxml2::XMLElement* rootElement = PrepareXmlDocumentForObjectSerialization("favorites"); + + tinyxml2::XMLPrinter* printer = new tinyxml2::XMLPrinter(); + GetXmlDocument().Accept(printer); + serializedData = std::string(printer->CStr()); + + return true; +} + +bool ChannelFavoritesSerializer::ReadObject(ChannelFavorites& object, const std::string& xml) +{ + tinyxml2::XMLDocument& doc = GetXmlDocument(); + + if (doc.Parse(xml.c_str()) == tinyxml2::XML_NO_ERROR) { + tinyxml2::XMLElement* elRoot = doc.FirstChildElement("favorites"); + GetFavoritesResponseXmlDataDeserializer* xmlDataDeserializer = new GetFavoritesResponseXmlDataDeserializer(*this, object); + elRoot->Accept(xmlDataDeserializer); + delete xmlDataDeserializer; + + return true; + } + + return false; +} diff --git a/lib/libdvblinkremote/playback_item.cpp b/lib/libdvblinkremote/playback_item.cpp index ff9a8b061..0e60668de 100644 --- a/lib/libdvblinkremote/playback_item.cpp +++ b/lib/libdvblinkremote/playback_item.cpp @@ -95,7 +95,8 @@ RecordedTvItem::RecordedTvItem(const std::string& objectId, const std::string& p ChannelName(""), ChannelNumber(0), ChannelSubNumber(0), - State(RecordedTvItem::RECORDED_TV_ITEM_STATE_IN_PROGRESS) + State(RecordedTvItem::RECORDED_TV_ITEM_STATE_IN_PROGRESS), + SeriesSchedule(false) { } @@ -197,6 +198,21 @@ bool GetPlaybackObjectResponseSerializer::PlaybackItemXmlDataDeserializer::Visit recordedTvitem->State = (RecordedTvItem::DVBLinkRecordedTvItemState)Util::GetXmlFirstChildElementTextAsInt(&element, "state"); } + if (m_parent.HasChildElement(element, "schedule_id")) + { + recordedTvitem->ScheduleId = Util::GetXmlFirstChildElementText(&element, "schedule_id"); + } + + if (m_parent.HasChildElement(element, "schedule_name")) + { + recordedTvitem->ScheduleName = Util::GetXmlFirstChildElementText(&element, "schedule_name"); + } + + if (m_parent.HasChildElement(element, "schedule_series")) + { + recordedTvitem->SeriesSchedule = true; + } + item = (PlaybackItem*)recordedTvitem; } else if (strcmp(element.Name(), "video") == 0) diff --git a/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj b/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj index 6ff3765e7..4cd9e37db 100644 --- a/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj +++ b/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj @@ -16,6 +16,7 @@ + @@ -28,6 +29,7 @@ + diff --git a/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj.filters b/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj.filters index 222af0ed0..a8895f969 100644 --- a/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj.filters +++ b/lib/libdvblinkremote/project/VS2010Express/libdvblinkremote.vcxproj.filters @@ -90,6 +90,12 @@ Source Files + + Source Files + + + Source Files + diff --git a/lib/libdvblinkremote/request.h b/lib/libdvblinkremote/request.h index 5ac064d4d..4591cb6de 100644 --- a/lib/libdvblinkremote/request.h +++ b/lib/libdvblinkremote/request.h @@ -751,7 +751,7 @@ namespace dvblinkremote { * @see DVBLinkManualScheduleDayMask * @param title of schedule */ - AddManualScheduleRequest(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title = ""); + AddManualScheduleRequest(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title = "", const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Destructor for cleaning up allocated memory. @@ -778,8 +778,9 @@ namespace dvblinkremote { * @param recordSeriesAnytime an optional constant boolean representing whether to * record only series starting around original program start time or any of them. * Default value is false. - */ - AddScheduleByEpgRequest(const std::string& channelId, const std::string& programId, const bool repeat = false, const bool newOnly = false, const bool recordSeriesAnytime = false); + * @param recordingsToKeep defines anumbr of recordings to keep in case of series recordings (0 - keep all). + */ + AddScheduleByEpgRequest(const std::string& channelId, const std::string& programId, const bool repeat = false, const bool newOnly = false, const bool recordSeriesAnytime = false, const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Destructor for cleaning up allocated memory. @@ -1319,4 +1320,42 @@ namespace dvblinkremote { int m_timeMarginAfterScheduledRecordings; std::string m_recordingPath; }; + + /** + * Class for getting channel favorites requests. + * This is used as input parameter for the IDVBLinkRemoteConnection::GetFavorites method. + * @see IDVBLinkRemoteConnection::GetFavorites() + */ + class GetFavoritesRequest : public Request + { + public: + /** + * Initializes a new instance of the dvblinkremote::GetFavoritesRequest class. + */ + GetFavoritesRequest(); + + /** + * Destructor for cleaning up allocated memory. + */ + ~GetFavoritesRequest(); + }; + + /** + * Class for getting server information requests. + * This is used as input parameter for the IDVBLinkRemoteConnection::GetServerInfo method. + * @see IDVBLinkRemoteConnection::GetServerInfo() + */ + class GetServerInfoRequest : public Request + { + public: + /** + * Initializes a new instance of the dvblinkremote::GetServerInfoRequest class. + */ + GetServerInfoRequest(); + + /** + * Destructor for cleaning up allocated memory. + */ + ~GetServerInfoRequest(); + }; } diff --git a/lib/libdvblinkremote/response.h b/lib/libdvblinkremote/response.h index 95c4395e5..ca4c62dda 100644 --- a/lib/libdvblinkremote/response.h +++ b/lib/libdvblinkremote/response.h @@ -1059,6 +1059,22 @@ namespace dvblinkremote { * The state of the recored TV item. */ DVBLinkRecordedTvItemState State; + + /** + * Id of the schedule, this recorded tv item belongs to + */ + std::string ScheduleId; + + /** + * Name of the schedule, this recorded tv item belongs to + */ + std::string ScheduleName; + + /** + * Indicates if the schedule was/is part of the series recordings + */ + bool SeriesSchedule; + }; /** @@ -1290,4 +1306,82 @@ namespace dvblinkremote { */ long AvailableSpace; }; + + class ChannelFavorite + { + public: + typedef std::vector favorite_channel_list_t; + + public: + ChannelFavorite(std::string& id, std::string& name, favorite_channel_list_t& channels); + + ~ChannelFavorite(); + + std::string& get_id() {return id_;} + std::string& get_name() { return name_; } + favorite_channel_list_t& get_channels() { return channels_; } + + private: + std::string id_; + std::string name_; + favorite_channel_list_t channels_; + }; + + /** + * Represent channel favorites which is used as output parameter for the + * IDVBLinkRemoteConnection::GetFavorites method. + * @see IDVBLinkRemoteConnection::GetFavorites() + */ + class ChannelFavorites : public Response + { + public: + typedef std::vector favorites_list_t; + + public: + /** + * Initializes a new instance of the dvblinkremote::ChannelFavorites class. + */ + ChannelFavorites(); + + /** + * Initializes a new instance of the dvblinkremote::ChannelFavorites class by coping another + * dvblinkremote::ChannelFavorites instance. + * @param recordingSettings a dvblinkremote::ChannelFavorites reference. + */ + ChannelFavorites(ChannelFavorites& favorites); + + /** + * Destructor for cleaning up allocated memory. + */ + ~ChannelFavorites(); + + favorites_list_t favorites_; + }; + + class ServerInfo : public Response + { + public: + /** + * Initializes a new instance of the dvblinkremote::ServerInfo class. + */ + ServerInfo(); + + /** + * Initializes a new instance of the dvblinkremote::ServerInfo class by coping another + * dvblinkremote::ServerInfo instance. + * @param server_info a dvblinkremote::ServerInfo reference. + */ + ServerInfo(ServerInfo& server_info); + + /** + * Destructor for cleaning up allocated memory. + */ + ~ServerInfo(); + + std::string install_id_; + std::string server_id_; + std::string version_; + std::string build_; + }; + } diff --git a/lib/libdvblinkremote/scheduling.cpp b/lib/libdvblinkremote/scheduling.cpp index 773272ab7..0bd250945 100644 --- a/lib/libdvblinkremote/scheduling.cpp +++ b/lib/libdvblinkremote/scheduling.cpp @@ -32,22 +32,26 @@ Schedule::Schedule() } -Schedule::Schedule(const DVBLinkScheduleType scheduleType, const std::string& channelId, const int recordingsToKeep) +Schedule::Schedule(const DVBLinkScheduleType scheduleType, const std::string& channelId, const int recordingsToKeep, const int marginBefore, const int marginAfter) : m_scheduleType(scheduleType), m_channelId(channelId), - RecordingsToKeep(recordingsToKeep) -{ + RecordingsToKeep(recordingsToKeep), + MarginBefore(marginBefore), + MarginAfter(marginAfter) +{ m_id = ""; UserParameter = ""; ForceAdd = false; } -Schedule::Schedule(const DVBLinkScheduleType scheduleType, const std::string& id, const std::string& channelId, const int recordingsToKeep) +Schedule::Schedule(const DVBLinkScheduleType scheduleType, const std::string& id, const std::string& channelId, const int recordingsToKeep, const int marginBefore, const int marginAfter) : m_scheduleType(scheduleType), m_id(id), m_channelId(channelId), - RecordingsToKeep(recordingsToKeep) -{ + RecordingsToKeep(recordingsToKeep), + MarginBefore(marginBefore), + MarginAfter(marginAfter) +{ UserParameter = ""; ForceAdd = false; } @@ -72,8 +76,8 @@ Schedule::DVBLinkScheduleType& Schedule::GetScheduleType() return m_scheduleType; } -ManualSchedule::ManualSchedule(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title) - : Schedule(SCHEDULE_TYPE_MANUAL, channelId), +ManualSchedule::ManualSchedule(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title, const int recordingsToKeep, const int marginBefore, const int marginAfter) + : Schedule(SCHEDULE_TYPE_MANUAL, channelId, recordingsToKeep, marginBefore, marginAfter), m_startTime(startTime), m_duration(duration), m_dayMask(dayMask), @@ -82,8 +86,8 @@ ManualSchedule::ManualSchedule(const std::string& channelId, const long startTim } -ManualSchedule::ManualSchedule(const std::string& id, const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title) - : Schedule(SCHEDULE_TYPE_MANUAL, id, channelId), +ManualSchedule::ManualSchedule(const std::string& id, const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title, const int recordingsToKeep, const int marginBefore, const int marginAfter) + : Schedule(SCHEDULE_TYPE_MANUAL, id, channelId, recordingsToKeep, marginBefore, marginAfter), m_startTime(startTime), m_duration(duration), m_dayMask(dayMask), @@ -112,8 +116,8 @@ long ManualSchedule::GetDayMask() return m_dayMask; } -EpgSchedule::EpgSchedule(const std::string& channelId, const std::string& programId, const bool repeat, const bool newOnly, const bool recordSeriesAnytime) - : Schedule(SCHEDULE_TYPE_BY_EPG, channelId), +EpgSchedule::EpgSchedule(const std::string& channelId, const std::string& programId, const bool repeat, const bool newOnly, const bool recordSeriesAnytime, const int recordingsToKeep, const int marginBefore, const int marginAfter) + : Schedule(SCHEDULE_TYPE_BY_EPG, channelId, recordingsToKeep, marginBefore, marginAfter), m_programId(programId), Repeat(repeat), NewOnly(newOnly), @@ -122,8 +126,9 @@ EpgSchedule::EpgSchedule(const std::string& channelId, const std::string& progra } -EpgSchedule::EpgSchedule(const std::string& id, const std::string& channelId, const std::string& programId, const bool repeat, const bool newOnly, const bool recordSeriesAnytime) - : Schedule(SCHEDULE_TYPE_BY_EPG, id, channelId), +EpgSchedule::EpgSchedule(const std::string& id, const std::string& channelId, const std::string& programId, const bool repeat, const bool newOnly, + const bool recordSeriesAnytime, const int recordingsToKeep, const int marginBefore, const int marginAfter) + : Schedule(SCHEDULE_TYPE_BY_EPG, id, channelId, recordingsToKeep, marginBefore, marginAfter), m_programId(programId), Repeat(repeat), NewOnly(newOnly), @@ -153,8 +158,8 @@ AddScheduleRequest::~AddScheduleRequest() } -AddManualScheduleRequest::AddManualScheduleRequest(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title) - : ManualSchedule(channelId, startTime, duration, dayMask, title), AddScheduleRequest(), Schedule(Schedule::SCHEDULE_TYPE_MANUAL, channelId) +AddManualScheduleRequest::AddManualScheduleRequest(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title, const int recordingsToKeep, const int marginBefore, const int marginAfter) + : ManualSchedule(channelId, startTime, duration, dayMask, title, recordingsToKeep, marginBefore, marginAfter), AddScheduleRequest(), Schedule(Schedule::SCHEDULE_TYPE_MANUAL, channelId, recordingsToKeep, marginBefore, marginAfter) { } @@ -164,8 +169,9 @@ AddManualScheduleRequest::~AddManualScheduleRequest() } -AddScheduleByEpgRequest::AddScheduleByEpgRequest(const std::string& channelId, const std::string& programId, const bool repeat, const bool newOnly, const bool recordSeriesAnytime) - : EpgSchedule(channelId, programId, repeat, newOnly, recordSeriesAnytime), AddScheduleRequest(), Schedule(Schedule::SCHEDULE_TYPE_BY_EPG, channelId) +AddScheduleByEpgRequest::AddScheduleByEpgRequest(const std::string& channelId, const std::string& programId, const bool repeat, const bool newOnly, + const bool recordSeriesAnytime, const int recordingsToKeep, const int marginBefore, const int marginAfter) + : EpgSchedule(channelId, programId, repeat, newOnly, recordSeriesAnytime, recordingsToKeep, marginBefore, marginAfter), AddScheduleRequest(), Schedule(Schedule::SCHEDULE_TYPE_BY_EPG, channelId, recordingsToKeep, marginBefore, marginAfter) { } @@ -187,6 +193,9 @@ bool AddScheduleRequestSerializer::WriteObject(std::string& serializedData, AddS rootElement->InsertEndChild(Util::CreateXmlElementWithText(&GetXmlDocument(), "force_add", objectGraph.ForceAdd)); } + rootElement->InsertEndChild(Util::CreateXmlElementWithText(&GetXmlDocument(), "margine_before", objectGraph.MarginBefore)); + rootElement->InsertEndChild(Util::CreateXmlElementWithText(&GetXmlDocument(), "margine_after", objectGraph.MarginAfter)); + if (objectGraph.GetScheduleType() == objectGraph.SCHEDULE_TYPE_MANUAL) { AddManualScheduleRequest& addManualScheduleRequest = (AddManualScheduleRequest&)objectGraph; diff --git a/lib/libdvblinkremote/scheduling.h b/lib/libdvblinkremote/scheduling.h index cfa1c603a..a4de7d862 100644 --- a/lib/libdvblinkremote/scheduling.h +++ b/lib/libdvblinkremote/scheduling.h @@ -49,8 +49,10 @@ namespace dvblinkremote { * @param channelId a constant string reference representing the channel identifier. * @param recordingsToKeep an optional constant integer representing how many recordings to * keep for a repeated recording. Default value is 0, i.e. keep all recordings. + * @param marginBefore a constant int, specifying a margin in minutes before recording starts (-1 - use default) + * @param marginAfter a constant int, specifying a margin in minutes after recording ends (-1 - use default) */ - Schedule(const DVBLinkScheduleType scheduleType, const std::string& channelId, const int recordingsToKeep = 0); + Schedule(const DVBLinkScheduleType scheduleType, const std::string& channelId, const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Initializes a new instance of the dvblinkremote::Schedule class. @@ -60,8 +62,10 @@ namespace dvblinkremote { * @param channelId a constant string reference representing the channel identifier. * @param recordingsToKeep an optional constant integer representing how many recordings to * keep for a repeated recording. Default value is 0, i.e. keep all recordings. + * @param marginBefore a constant int, specifying a margin in minutes before recording starts (-1 - use default) + * @param marginAfter a constant int, specifying a margin in minutes after recording ends (-1 - use default) */ - Schedule(const DVBLinkScheduleType scheduleType, const std::string& id, const std::string& channelId, const int recordingsToKeep = 0); + Schedule(const DVBLinkScheduleType scheduleType, const std::string& id, const std::string& channelId, const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Pure virtual destructor for cleaning up allocated memory. @@ -97,6 +101,16 @@ namespace dvblinkremote { */ int RecordingsToKeep; + /** + * Indicates margin in minutes before recording starts (-1 - use default margin) + */ + int MarginBefore; + + /** + * Indicates margin in minutes after recording ends (-1 - use default margin) + */ + int MarginAfter; + /** * Gets the type for the schedule . * @return DVBLinkScheduleType instance reference @@ -159,7 +173,7 @@ namespace dvblinkremote { * @see DVBLinkManualScheduleDayMask * @param title of schedule */ - ManualSchedule(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title = ""); + ManualSchedule(const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title = "", const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Initializes a new instance of the dvblinkremote::ManualSchedule class. @@ -172,7 +186,7 @@ namespace dvblinkremote { * @see DVBLinkManualScheduleDayMask * @param title of schedule */ - ManualSchedule(const std::string& id, const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title = ""); + ManualSchedule(const std::string& id, const std::string& channelId, const long startTime, const long duration, const long dayMask, const std::string& title = "", const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Pure virtual destructor for cleaning up allocated memory. @@ -236,8 +250,9 @@ namespace dvblinkremote { * @param recordSeriesAnytime an optional constant boolean representing whether to * record only series starting around original program start time or any of them. * Default value is false. - */ - EpgSchedule(const std::string& channelId, const std::string& programId, const bool repeat = false, const bool newOnly = false, const bool recordSeriesAnytime = false); + * @param recordingsToKeep defines a number of recordings to keep in case of series recordings (0 - keep all). + */ + EpgSchedule(const std::string& channelId, const std::string& programId, const bool repeat = false, const bool newOnly = false, const bool recordSeriesAnytime = false, const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Initializes a new instance of the dvblinkremote::EpgSchedule class. @@ -251,8 +266,9 @@ namespace dvblinkremote { * @param recordSeriesAnytime an optional constant boolean representing whether to * record only series starting around original program start time or any of them. * Default value is false. - */ - EpgSchedule(const std::string& id, const std::string& channelId, const std::string& programId, const bool repeat = false, const bool newOnly = false, const bool recordSeriesAnytime = false); + * @param recordingsToKeep defines a number of recordings to keep in case of series recordings (0 - keep all). + */ + EpgSchedule(const std::string& id, const std::string& channelId, const std::string& programId, const bool repeat = false, const bool newOnly = false, const bool recordSeriesAnytime = false, const int recordingsToKeep = 0, const int marginBefore = -1, const int marginAfter = -1); /** * Pure virtual destructor for cleaning up allocated memory. diff --git a/lib/libdvblinkremote/server_info.cpp b/lib/libdvblinkremote/server_info.cpp new file mode 100644 index 000000000..a308048ce --- /dev/null +++ b/lib/libdvblinkremote/server_info.cpp @@ -0,0 +1,76 @@ +/*************************************************************************** + * Copyright (C) 2012 Marcus Efraimsson. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + * + ***************************************************************************/ + +#include "request.h" +#include "response.h" +#include "xml_object_serializer.h" + +using namespace dvblinkremote; +using namespace dvblinkremoteserialization; + +GetServerInfoRequest::GetServerInfoRequest() +{ } + +GetServerInfoRequest::~GetServerInfoRequest() +{ } + +ServerInfo::ServerInfo() +{ } + +ServerInfo::ServerInfo(ServerInfo& server_info) +{ + install_id_ = server_info.install_id_; + server_id_ = server_info.server_id_; + build_ = server_info.build_; + version_ = server_info.version_; +} + +ServerInfo::~ServerInfo() +{ } + +bool GetServerInfoRequestSerializer::WriteObject(std::string& serializedData, GetServerInfoRequest& objectGraph) +{ + tinyxml2::XMLElement* rootElement = PrepareXmlDocumentForObjectSerialization("server_info"); + + tinyxml2::XMLPrinter* printer = new tinyxml2::XMLPrinter(); + GetXmlDocument().Accept(printer); + serializedData = std::string(printer->CStr()); + + return true; +} + +bool ServerInfoSerializer::ReadObject(ServerInfo& object, const std::string& xml) +{ + tinyxml2::XMLDocument& doc = GetXmlDocument(); + + if (doc.Parse(xml.c_str()) == tinyxml2::XML_NO_ERROR) { + tinyxml2::XMLElement* elRoot = doc.FirstChildElement("server_info"); + object.install_id_ = Util::GetXmlFirstChildElementText(elRoot, "install_id"); + object.server_id_ = Util::GetXmlFirstChildElementText(elRoot, "server_id"); + object.version_ = Util::GetXmlFirstChildElementText(elRoot, "version"); + object.build_ = Util::GetXmlFirstChildElementText(elRoot, "build"); + return true; + } + + return false; +} diff --git a/lib/libdvblinkremote/xml_object_serializer.h b/lib/libdvblinkremote/xml_object_serializer.h index 5e9e0a528..6fec937df 100644 --- a/lib/libdvblinkremote/xml_object_serializer.h +++ b/lib/libdvblinkremote/xml_object_serializer.h @@ -359,6 +359,47 @@ namespace dvblinkremoteserialization { bool WriteObject(std::string& serializedData, SetRecordingSettingsRequest& objectGraph); }; + class GetFavoritesRequestSerializer : public XmlObjectSerializer + { + public: + GetFavoritesRequestSerializer() : XmlObjectSerializer() { } + bool WriteObject(std::string& serializedData, GetFavoritesRequest& objectGraph); + }; + + class ChannelFavoritesSerializer : public XmlObjectSerializer + { + public: + ChannelFavoritesSerializer() : XmlObjectSerializer() { } + bool ReadObject(ChannelFavorites& object, const std::string& xml); + + private: + class GetFavoritesResponseXmlDataDeserializer : public tinyxml2::XMLVisitor + { + private: + ChannelFavoritesSerializer& m_parent; + ChannelFavorites& m_favoritesList; + + public: + GetFavoritesResponseXmlDataDeserializer(ChannelFavoritesSerializer& parent, ChannelFavorites& favoritesList); + ~GetFavoritesResponseXmlDataDeserializer(); + bool VisitEnter(const tinyxml2::XMLElement& element, const tinyxml2::XMLAttribute* attribute); + }; + }; + + class GetServerInfoRequestSerializer : public XmlObjectSerializer + { + public: + GetServerInfoRequestSerializer() : XmlObjectSerializer() { } + bool WriteObject(std::string& serializedData, GetServerInfoRequest& objectGraph); + }; + + class ServerInfoSerializer : public XmlObjectSerializer + { + public: + ServerInfoSerializer() : XmlObjectSerializer() { } + bool ReadObject(ServerInfo& object, const std::string& xml); + }; + class ItemMetadataSerializer { public: diff --git a/lib/libdvblinkremote/xml_object_serializer_factory.cpp b/lib/libdvblinkremote/xml_object_serializer_factory.cpp index 78db83f92..a799724f1 100644 --- a/lib/libdvblinkremote/xml_object_serializer_factory.cpp +++ b/lib/libdvblinkremote/xml_object_serializer_factory.cpp @@ -106,6 +106,14 @@ bool XmlObjectSerializerFactory::Serialize(const std::string& dvbLinkCommand, co requestSerializer = (XmlObjectSerializer*)new SetRecordingSettingsRequestSerializer(); result = ((SetRecordingSettingsRequestSerializer*)requestSerializer)->WriteObject(serializedData, (SetRecordingSettingsRequest&)request); } + else if (dvbLinkCommand == DVBLINK_REMOTE_GET_SERVER_INFO_CMD) { + requestSerializer = (XmlObjectSerializer*)new GetServerInfoRequestSerializer(); + result = ((GetServerInfoRequestSerializer*)requestSerializer)->WriteObject(serializedData, (GetServerInfoRequest&)request); + } + else if (dvbLinkCommand == DVBLINK_REMOTE_GET_FAVORITES_CMD) { + requestSerializer = (XmlObjectSerializer*)new GetFavoritesRequestSerializer(); + result = ((GetFavoritesRequestSerializer*)requestSerializer)->WriteObject(serializedData, (GetFavoritesRequest&)request); + } else { result = false; } @@ -159,7 +167,15 @@ bool XmlObjectSerializerFactory::Deserialize(const std::string& dvbLinkCommand, responseSerializer = (XmlObjectSerializer*)new RecordingSettingsSerializer(); result = ((RecordingSettingsSerializer*)responseSerializer)->ReadObject((RecordingSettings&)response, serializedData); } - else if (dvbLinkCommand == DVBLINK_REMOTE_ADD_SCHEDULE_CMD || + else if (dvbLinkCommand == DVBLINK_REMOTE_GET_FAVORITES_CMD) { + responseSerializer = (XmlObjectSerializer*)new ChannelFavoritesSerializer(); + result = ((ChannelFavoritesSerializer*)responseSerializer)->ReadObject((ChannelFavorites&)response, serializedData); + } + else if (dvbLinkCommand == DVBLINK_REMOTE_GET_SERVER_INFO_CMD) { + responseSerializer = (XmlObjectSerializer*)new ServerInfoSerializer(); + result = ((ServerInfoSerializer*)responseSerializer)->ReadObject((ServerInfo&)response, serializedData); + } + else if (dvbLinkCommand == DVBLINK_REMOTE_ADD_SCHEDULE_CMD || dvbLinkCommand == DVBLINK_REMOTE_UPDATE_SCHEDULE_CMD || dvbLinkCommand == DVBLINK_REMOTE_REMOVE_SCHEDULE_CMD || dvbLinkCommand == DVBLINK_REMOTE_REMOVE_RECORDING_CMD ||