Merge pull request #4775 from jmarshallnz/empty_episode_playcount
[vuplus_xbmc] / xbmc / interfaces / AnnouncementManager.cpp
1 /*
2  *      Copyright (C) 2005-2013 Team XBMC
3  *      http://xbmc.org
4  *
5  *  This Program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2, or (at your option)
8  *  any later version.
9  *
10  *  This Program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with XBMC; see the file COPYING.  If not, see
17  *  <http://www.gnu.org/licenses/>.
18  *
19  */
20
21 #include "AnnouncementManager.h"
22 #include "threads/SingleLock.h"
23 #include <stdio.h>
24 #include "utils/log.h"
25 #include "utils/Variant.h"
26 #include "utils/StringUtils.h"
27 #include "FileItem.h"
28 #include "music/tags/MusicInfoTag.h"
29 #include "music/MusicDatabase.h"
30 #include "video/VideoDatabase.h"
31 #include "pvr/channels/PVRChannel.h"
32 #include "PlayListPlayer.h"
33
34 #define LOOKUP_PROPERTY "database-lookup"
35
36 using namespace std;
37 using namespace ANNOUNCEMENT;
38
39 #define m_announcers XBMC_GLOBAL_USE(ANNOUNCEMENT::CAnnouncementManager::Globals).m_announcers
40 #define m_critSection XBMC_GLOBAL_USE(ANNOUNCEMENT::CAnnouncementManager::Globals).m_critSection
41
42 void CAnnouncementManager::Deinitialize()
43 {
44   CSingleLock lock (m_critSection);
45   m_announcers.clear();
46 }
47
48 void CAnnouncementManager::AddAnnouncer(IAnnouncer *listener)
49 {
50   if (!listener)
51     return;
52
53   CSingleLock lock (m_critSection);
54   m_announcers.push_back(listener);
55 }
56
57 void CAnnouncementManager::RemoveAnnouncer(IAnnouncer *listener)
58 {
59   if (!listener)
60     return;
61
62   CSingleLock lock (m_critSection);
63   for (unsigned int i = 0; i < m_announcers.size(); i++)
64   {
65     if (m_announcers[i] == listener)
66     {
67       m_announcers.erase(m_announcers.begin() + i);
68       return;
69     }
70   }
71 }
72
73 void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message)
74 {
75   CVariant data;
76   Announce(flag, sender, message, data);
77 }
78
79 void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, CVariant &data)
80 {
81   CLog::Log(LOGDEBUG, "CAnnouncementManager - Announcement: %s from %s", message, sender);
82   CSingleLock lock (m_critSection);
83   for (unsigned int i = 0; i < m_announcers.size(); i++)
84     m_announcers[i]->Announce(flag, sender, message, data);
85 }
86
87 void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, CFileItemPtr item)
88 {
89   CVariant data;
90   Announce(flag, sender, message, item, data);
91 }
92
93 void CAnnouncementManager::Announce(AnnouncementFlag flag, const char *sender, const char *message, CFileItemPtr item, CVariant &data)
94 {
95   if (!item.get())
96   {
97     Announce(flag, sender, message, data);
98     return;
99   }
100
101   // Extract db id of item
102   CVariant object = data.isNull() || data.isObject() ? data : CVariant::VariantTypeObject;
103   CStdString type;
104   int id = 0;
105   
106   if(item->HasPVRChannelInfoTag())
107   {
108     const PVR::CPVRChannel *channel = item->GetPVRChannelInfoTag();
109     id = channel->ChannelID();
110     type = "channel";
111
112     object["item"]["title"] = channel->ChannelName();
113     object["item"]["channeltype"] = channel->IsRadio() ? "radio" : "tv";
114
115     if (data.isMember("player") && data["player"].isMember("playerid"))
116       object["player"]["playerid"] = channel->IsRadio() ? PLAYLIST_MUSIC : PLAYLIST_VIDEO;
117   }
118   else if (item->HasVideoInfoTag())
119   {
120     id = item->GetVideoInfoTag()->m_iDbId;
121
122     // TODO: Can be removed once this is properly handled when starting playback of a file
123     if (id <= 0 && !item->GetPath().empty() &&
124        (!item->HasProperty(LOOKUP_PROPERTY) || item->GetProperty(LOOKUP_PROPERTY).asBoolean()))
125     {
126       CVideoDatabase videodatabase;
127       if (videodatabase.Open())
128       {
129         CStdString path = item->GetPath();
130         CStdString videoInfoTagPath(item->GetVideoInfoTag()->m_strFileNameAndPath);
131         if (StringUtils::StartsWith(videoInfoTagPath, "removable://"))
132           path = videoInfoTagPath;
133         if (videodatabase.LoadVideoInfo(path, *item->GetVideoInfoTag()))
134           id = item->GetVideoInfoTag()->m_iDbId;
135
136         videodatabase.Close();
137       }
138     }
139
140     if (!item->GetVideoInfoTag()->m_type.empty())
141       type = item->GetVideoInfoTag()->m_type;
142     else
143       CVideoDatabase::VideoContentTypeToString((VIDEODB_CONTENT_TYPE)item->GetVideoContentType(), type);
144
145     if (id <= 0)
146     {
147       // TODO: Can be removed once this is properly handled when starting playback of a file
148       item->SetProperty(LOOKUP_PROPERTY, false);
149
150       CStdString title = item->GetVideoInfoTag()->m_strTitle;
151       if (title.empty())
152         title = item->GetLabel();
153       object["item"]["title"] = title;
154
155       switch (item->GetVideoContentType())
156       {
157       case VIDEODB_CONTENT_MOVIES:
158         if (item->GetVideoInfoTag()->m_iYear > 0)
159           object["item"]["year"] = item->GetVideoInfoTag()->m_iYear;
160         break;
161       case VIDEODB_CONTENT_EPISODES:
162         if (item->GetVideoInfoTag()->m_iEpisode >= 0)
163           object["item"]["episode"] = item->GetVideoInfoTag()->m_iEpisode;
164         if (item->GetVideoInfoTag()->m_iSeason >= 0)
165           object["item"]["season"] = item->GetVideoInfoTag()->m_iSeason;
166         if (!item->GetVideoInfoTag()->m_strShowTitle.empty())
167           object["item"]["showtitle"] = item->GetVideoInfoTag()->m_strShowTitle;
168         break;
169       case VIDEODB_CONTENT_MUSICVIDEOS:
170         if (!item->GetVideoInfoTag()->m_strAlbum.empty())
171           object["item"]["album"] = item->GetVideoInfoTag()->m_strAlbum;
172         if (!item->GetVideoInfoTag()->m_artist.empty())
173           object["item"]["artist"] = StringUtils::Join(item->GetVideoInfoTag()->m_artist, " / ");
174         break;
175       }
176     }
177   }
178   else if (item->HasMusicInfoTag())
179   {
180     id = item->GetMusicInfoTag()->GetDatabaseId();
181     type = "song";
182
183     // TODO: Can be removed once this is properly handled when starting playback of a file
184     if (id <= 0 && !item->GetPath().empty() &&
185        (!item->HasProperty(LOOKUP_PROPERTY) || item->GetProperty(LOOKUP_PROPERTY).asBoolean()))
186     {
187       CMusicDatabase musicdatabase;
188       if (musicdatabase.Open())
189       {
190         CSong song;
191         if (musicdatabase.GetSongByFileName(item->GetPath(), song, item->m_lStartOffset))
192         {
193           item->GetMusicInfoTag()->SetSong(song);
194           id = item->GetMusicInfoTag()->GetDatabaseId();
195         }
196
197         musicdatabase.Close();
198       }
199     }
200
201     if (id <= 0)
202     {
203       // TODO: Can be removed once this is properly handled when starting playback of a file
204       item->SetProperty(LOOKUP_PROPERTY, false);
205
206       CStdString title = item->GetMusicInfoTag()->GetTitle();
207       if (title.empty())
208         title = item->GetLabel();
209       object["item"]["title"] = title;
210
211       if (item->GetMusicInfoTag()->GetTrackNumber() > 0)
212         object["item"]["track"] = item->GetMusicInfoTag()->GetTrackNumber();
213       if (!item->GetMusicInfoTag()->GetAlbum().empty())
214         object["item"]["album"] = item->GetMusicInfoTag()->GetAlbum();
215       if (!item->GetMusicInfoTag()->GetArtist().empty())
216         object["item"]["artist"] = item->GetMusicInfoTag()->GetArtist();
217     }
218   }
219   else if (item->IsVideo())
220   {
221     // video item but has no video info tag.
222     type = "movies";
223     object["item"]["title"] = item->GetLabel();
224   }
225   else if (item->HasPictureInfoTag())
226   {
227     type = "picture";
228     object["item"]["file"] = item->GetPath();
229   }
230   else
231     type = "unknown";
232
233   object["item"]["type"] = type;
234   if (id > 0)
235     object["item"]["id"] = id;
236
237   Announce(flag, sender, message, object);
238 }