~x3lectric/xbmc/svn-trunk

21726 by spiff_
added: addon database
1
/*
2
 *      Copyright (C) 2005-2010 Team XBMC
3
 *      http://www.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, write to
17
 *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18
 *  http://www.gnu.org/copyleft/gpl.html
19
 *
20
 */
21
22
#include "AddonDatabase.h"
23
#include "utils/log.h"
24
#include "DateTime.h"
25
26
using namespace ADDON;
27
28
CAddonDatabase::CAddonDatabase()
29
{
30
}
31
32
CAddonDatabase::~CAddonDatabase()
33
{
34
}
35
36
bool CAddonDatabase::Open()
37
{
38
  return CDatabase::Open();
39
}
40
41
bool CAddonDatabase::CreateTables()
42
{
43
  try
44
  {
45
    CDatabase::CreateTables();
46
47
    CLog::Log(LOGINFO, "create addon table");
48
    m_pDS->exec("CREATE TABLE addon (id integer primary key, type text,"
21781 by spiff_
fixed: store addon descriptions in the database
49
                "name text, summary text, description text, stars integer,"
22010 by spiff_
added: fanart support for addons
50
                "path text, addonID text, icon text, version text, "
51
                "changelog text, fanart text)\n");
21726 by spiff_
added: addon database
52
53
    CLog::Log(LOGINFO, "create addon index");
54
    m_pDS->exec("CREATE INDEX idxAddon ON addon(addonID)");
55
56
    CLog::Log(LOGINFO, "create repo table");
57
    m_pDS->exec("CREATE TABLE repo (id integer primary key, addonID text,"
58
                "checksum text, lastcheck text)\n");
59
60
    CLog::Log(LOGINFO, "create addonlinkrepo table");
61
    m_pDS->exec("CREATE TABLE addonlinkrepo (idRepo integer, idAddon integer)\n");
62
  }
63
  catch (...)
64
  {
65
    CLog::Log(LOGERROR, "%s unable to create tables", __FUNCTION__);
66
    return false;
67
  }
68
69
  return true;
70
}
71
72
bool CAddonDatabase::UpdateOldVersion(int version)
73
{
21781 by spiff_
fixed: store addon descriptions in the database
74
  if (version < 2)
75
  {
76
    m_pDS->exec("alter table addon add description text");
77
  }
22007 by spiff_
added: addon changelog support
78
  if (version < 3)
79
  {
80
    m_pDS->exec("alter table addon add changelog text");
81
  }
22010 by spiff_
added: fanart support for addons
82
  if (version < 4)
83
  {
84
    m_pDS->exec("alter table addon add fanart text");
85
  }
21726 by spiff_
added: addon database
86
  return true;
87
}
88
89
int CAddonDatabase::AddAddon(const AddonPtr& addon,
90
                             int idRepo)
91
{
92
  try
93
  {
94
    if (NULL == m_pDB.get()) return -1;
95
    if (NULL == m_pDS.get()) return -1;
96
97
    CStdString sql = FormatSQL("insert into addon (id, type, name, summary,"
22007 by spiff_
added: addon changelog support
98
                               "description, stars, path, icon, changelog, "
22010 by spiff_
added: fanart support for addons
99
                               "fanart, addonID, version)"
21781 by spiff_
fixed: store addon descriptions in the database
100
                               " values(NULL, '%s', '%s', '%s', '%s', %i,"
22010 by spiff_
added: fanart support for addons
101
                               "'%s', '%s', '%s', '%s', '%s','%s')",
21726 by spiff_
added: addon database
102
                               TranslateType(addon->Type(),false).c_str(),
103
                               addon->Name().c_str(), addon->Summary().c_str(),
21781 by spiff_
fixed: store addon descriptions in the database
104
                               addon->Description().c_str(),addon->Stars(),
21950 by jmarshallnz
added: Support for relative icon paths in addons
105
                               addon->Path().c_str(), addon->Props().icon.c_str(),
22010 by spiff_
added: fanart support for addons
106
                               addon->ChangeLog().c_str(),addon->FanArt().c_str(),
21781 by spiff_
fixed: store addon descriptions in the database
107
                               addon->ID().c_str(), addon->Version().str.c_str());
21726 by spiff_
added: addon database
108
    m_pDS->exec(sql.c_str());
21972 by jmarshallnz
fixed: compile warnings.
109
    int idAddon = (int)m_pDS->lastinsertid();
21726 by spiff_
added: addon database
110
111
    sql = FormatSQL("insert into addonlinkrepo (idRepo, idAddon) values (%i,%i)",idRepo,idAddon);
112
    m_pDS->exec(sql.c_str());
113
    return idAddon;
114
  }
115
  catch (...)
116
  {
117
    CLog::Log(LOGERROR, "%s failed on addon '%s'", __FUNCTION__, addon->Name().c_str());
118
  }
119
  return -1;
120
}
121
122
bool CAddonDatabase::GetAddon(const CStdString& id, AddonPtr& addon)
123
{
124
  try
125
  {
21972 by jmarshallnz
fixed: compile warnings.
126
    if (NULL == m_pDB.get()) return false;
127
    if (NULL == m_pDS2.get()) return false;
21726 by spiff_
added: addon database
128
21940 by spiff_
added: context menu entries to check a repo for updates / force an update
129
    CStdString sql = FormatSQL("select id from addon where addonID='%s' order by version desc",id.c_str());
21726 by spiff_
added: addon database
130
    m_pDS2->query(sql.c_str());
131
    if (!m_pDS2->eof())
132
      return GetAddon(m_pDS2->fv(0).get_asInt(),addon);
133
  }
134
  catch (...)
135
  {
136
    CLog::Log(LOGERROR, "%s failed on addon %s", __FUNCTION__, id.c_str());
137
  }
138
  addon.reset();
139
  return false;
140
}
141
142
bool CAddonDatabase::GetAddon(int id, AddonPtr& addon)
143
{
144
  try
145
  {
21972 by jmarshallnz
fixed: compile warnings.
146
    if (NULL == m_pDB.get()) return false;
147
    if (NULL == m_pDS2.get()) return false;
21726 by spiff_
added: addon database
148
149
    CStdString sql = FormatSQL("select * from addon where id=%i",id);
150
    m_pDS2->query(sql.c_str());
151
    if (!m_pDS2->eof())
152
    {
153
      AddonProps props(m_pDS2->fv("addonID" ).get_asString(),
154
                       TranslateType(m_pDS2->fv("type").get_asString()),
155
                       m_pDS2->fv("version").get_asString());
156
      props.name = m_pDS2->fv("name").get_asString();
157
      props.summary = m_pDS2->fv("summary").get_asString();
21781 by spiff_
fixed: store addon descriptions in the database
158
      props.description = m_pDS2->fv("description").get_asString();
22007 by spiff_
added: addon changelog support
159
      props.changelog = m_pDS2->fv("changelog").get_asString();
21726 by spiff_
added: addon database
160
      props.path = m_pDS2->fv("path").get_asString();
161
      props.icon = m_pDS2->fv("icon").get_asString();
22010 by spiff_
added: fanart support for addons
162
      props.fanart = m_pDS2->fv("fanart").get_asString();
21726 by spiff_
added: addon database
163
      addon = CAddonMgr::AddonFromProps(props);
164
      return true;
165
    }
166
  }
167
  catch (...)
168
  {
169
    CLog::Log(LOGERROR, "%s failed on addon %i", __FUNCTION__, id);
170
  }
171
  addon.reset();
172
  return false;
173
}
174
21923 by spiff_
added: 'all repositories' to the addon browser vfs
175
bool CAddonDatabase::GetAddons(VECADDONS& addons)
176
{
177
  try
178
  {
21972 by jmarshallnz
fixed: compile warnings.
179
    if (NULL == m_pDB.get()) return false;
180
    if (NULL == m_pDS2.get()) return false;
21923 by spiff_
added: 'all repositories' to the addon browser vfs
181
182
    CStdString sql = FormatSQL("select distinct addonID from addon");
183
    m_pDS->query(sql.c_str());
184
    while (!m_pDS->eof())
185
    {
186
      sql = FormatSQL("select id from addon where addonID='%s' order by version desc",m_pDS->fv(0).get_asString().c_str());
187
      m_pDS2->query(sql.c_str());
188
      AddonPtr addon;
189
      if (GetAddon(m_pDS2->fv(0).get_asInt(),addon))
190
        addons.push_back(addon);
191
      m_pDS->next();
192
    }
193
    m_pDS->close();
194
    return true;
195
  }
196
  catch (...)
197
  {
198
    CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
199
  }
200
  return false;
201
}
202
21940 by spiff_
added: context menu entries to check a repo for updates / force an update
203
void CAddonDatabase::DeleteRepository(const CStdString& id)
204
{
205
  try
206
  {
207
    if (NULL == m_pDB.get()) return;
208
    if (NULL == m_pDS.get()) return;
209
210
    CStdString sql = FormatSQL("select id from repo where addonID='%s'",id.c_str());
211
    m_pDS->query(sql.c_str());
212
    if (!m_pDS->eof())
213
      DeleteRepository(m_pDS->fv(0).get_asInt());
214
  }
215
  catch (...)
216
  {
217
    CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
218
  }
219
}
220
221
void CAddonDatabase::DeleteRepository(int idRepo)
222
{
223
  try
224
  {
225
    if (NULL == m_pDB.get()) return;
226
    if (NULL == m_pDS.get()) return;
227
228
    CStdString sql = FormatSQL("delete from repo where id=%i",idRepo);
229
    m_pDS->exec(sql.c_str());
230
    sql = FormatSQL("delete from addon where id in (select idAddon from addonlinkrepo where idRepo=%i)",idRepo);
231
    m_pDS->exec(sql.c_str());
232
    sql = FormatSQL("delete from addonlinkrepo where idRepo=%i",idRepo);
233
    m_pDS->exec(sql.c_str());
234
235
  }
236
  catch (...)
237
  {
238
    CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, idRepo);
239
  }
240
}
241
21726 by spiff_
added: addon database
242
int CAddonDatabase::AddRepository(const CStdString& id, const VECADDONS& addons, const CStdString& checksum)
243
{
244
  try
245
  {
246
    if (NULL == m_pDB.get()) return -1;
247
    if (NULL == m_pDS.get()) return -1;
248
249
    CStdString sql;
250
    int idRepo = GetRepoChecksum(id,sql);
251
    if (idRepo > -1)
21940 by spiff_
added: context menu entries to check a repo for updates / force an update
252
      DeleteRepository(idRepo);
21726 by spiff_
added: addon database
253
254
    CDateTime time = CDateTime::GetCurrentDateTime();
255
    sql = FormatSQL("insert into repo (id,addonID,checksum,lastcheck) values (NULL,'%s','%s','%s')",id.c_str(),checksum.c_str(),time.GetAsDBDateTime().c_str());
256
    m_pDS->exec(sql.c_str());
21972 by jmarshallnz
fixed: compile warnings.
257
    idRepo = (int)m_pDS->lastinsertid();
21726 by spiff_
added: addon database
258
    for (unsigned int i=0;i<addons.size();++i)
259
      AddAddon(addons[i],idRepo);
260
261
    return idRepo;
262
  }
263
  catch (...)
264
  {
265
    CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
266
  }
267
  return -1;
268
}
269
270
int CAddonDatabase::GetRepoChecksum(const CStdString& id, CStdString& checksum)
271
{
272
  try
273
  {
274
    if (NULL == m_pDB.get()) return -1;
275
    if (NULL == m_pDS.get()) return -1;
276
277
    CStdString strSQL = FormatSQL("select * from repo where addonID='%s'",id.c_str());
278
    m_pDS->query(strSQL.c_str());
279
    if (!m_pDS->eof())
280
    {
281
      checksum = m_pDS->fv("checksum").get_asString();
282
      return m_pDS->fv("id").get_asInt();
283
    }
284
  }
285
  catch (...)
286
  {
287
    CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
288
  }
289
  checksum.Empty();
290
  return -1;
291
}
292
293
int CAddonDatabase::GetRepoTimestamp(const CStdString& id, CStdString& timestamp)
294
{
295
  try
296
  {
297
    if (NULL == m_pDB.get()) return -1;
298
    if (NULL == m_pDS.get()) return -1;
299
300
    CStdString strSQL = FormatSQL("select * from repo where addonID='%s'",id.c_str());
301
    m_pDS->query(strSQL.c_str());
302
    if (!m_pDS->eof())
303
    {
304
      timestamp = m_pDS->fv("lastcheck").get_asString();
305
      return m_pDS->fv("id").get_asInt();
306
    }
307
  }
308
  catch (...)
309
  {
310
    CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
311
  }
312
  timestamp.Empty();
313
  return -1;
314
}
315
316
bool CAddonDatabase::SetRepoTimestamp(const CStdString& id, const CStdString& time)
317
{
318
  try
319
  {
21972 by jmarshallnz
fixed: compile warnings.
320
    if (NULL == m_pDB.get()) return false;
321
    if (NULL == m_pDS.get()) return false;
21726 by spiff_
added: addon database
322
323
    CStdString sql = FormatSQL("update repo set lastcheck='%s' where addonID='%s'",time.c_str(),id.c_str());
324
    m_pDS->exec(sql.c_str());
325
326
    return true;
327
  }
328
  catch (...)
329
  {
330
    CLog::Log(LOGERROR, "%s failed on repo '%s'", __FUNCTION__, id.c_str());
331
  }
332
  return false;
333
}
334
335
bool CAddonDatabase::GetRepository(int id, VECADDONS& addons)
336
{
337
  try
338
  {
21972 by jmarshallnz
fixed: compile warnings.
339
    if (NULL == m_pDB.get()) return false;
340
    if (NULL == m_pDS.get()) return false;
21726 by spiff_
added: addon database
341
342
    CStdString strSQL = FormatSQL("select * from addonlinkrepo where idRepo=%i",id);
343
    m_pDS->query(strSQL.c_str());
344
    while (!m_pDS->eof())
345
    {
346
      AddonPtr addon;
347
      GetAddon(m_pDS->fv("idAddon").get_asInt(),addon);
348
      addons.push_back(addon);
349
      m_pDS->next();
350
    }
351
    return true;
352
  }
353
  catch (...)
354
  {
355
    CLog::Log(LOGERROR, "%s failed on repo %i", __FUNCTION__, id);
356
  }
357
  return false;
358
}
359
360
bool CAddonDatabase::GetRepository(const CStdString& id, VECADDONS& addons)
361
{
362
  try
363
  {
21972 by jmarshallnz
fixed: compile warnings.
364
    if (NULL == m_pDB.get()) return false;
365
    if (NULL == m_pDS.get()) return false;
21726 by spiff_
added: addon database
366
367
    CStdString strSQL = FormatSQL("select id from repo where addonID='%s'",id.c_str());
368
    m_pDS->query(strSQL.c_str());
369
    if (!m_pDS->eof())
370
      return GetRepository(m_pDS->fv(0).get_asInt(),addons);
371
  }
372
  catch (...)
373
  {
374
    CLog::Log(LOGERROR, "%s failed on repo %s", __FUNCTION__, id.c_str());
375
  }
376
  return false;
377
}
378
379
bool CAddonDatabase::Search(const CStdString& search, VECADDONS& items)
380
{
381
  // first grab all the addons that match
382
  SearchTitle(search,items);
383
384
  return true;
385
}
386
387
bool CAddonDatabase::SearchTitle(const CStdString& search, VECADDONS& addons)
388
{
389
  try
390
  {
391
    if (NULL == m_pDB.get()) return false;
392
    if (NULL == m_pDS.get()) return false;
393
394
    CStdString strSQL;
395
    strSQL=FormatSQL("select idAddon from addon where name like '%s%%'", search.c_str());
396
397
    if (!m_pDS->query(strSQL.c_str())) return false;
398
    if (m_pDS->num_rows() == 0) return false;
399
400
    while (!m_pDS->eof())
401
    {
402
      AddonPtr addon;
403
      GetAddon(m_pDS->fv(0).get_asInt(),addon);
404
      if (addon->Type() >= ADDON_UNKNOWN+1 && addon->Type() < ADDON_SCRAPER_LIBRARY)
405
        addons.push_back(addon);
406
      m_pDS->next();
407
    }
408
    m_pDS->close();
409
    return true;
410
  }
411
  catch (...)
412
  {
413
    CLog::Log(LOGERROR, "%s failed", __FUNCTION__);
414
  }
415
  return false;
416
}
417
21775 by spiff_
changed: refactor to avoid c&p
418
void CAddonDatabase::SetPropertiesFromAddon(const AddonPtr& addon,
419
                                           CFileItemPtr& pItem)
420
{
421
  pItem->SetProperty("Addon.ID", addon->ID());
22004 by spiff_
added: addon.inttype info label (for internal use). thus we can pretty-print the addon.type one
422
  pItem->SetProperty("Addon.Type", TranslateType(addon->Type(),true));
423
  pItem->SetProperty("Addon.intType", TranslateType(addon->Type()));
21775 by spiff_
changed: refactor to avoid c&p
424
  pItem->SetProperty("Addon.Name", addon->Name());
21922 by spiff_
added: manual addon updates
425
  pItem->SetProperty("Addon.Version", addon->Version().str);
21775 by spiff_
changed: refactor to avoid c&p
426
  pItem->SetProperty("Addon.Summary", addon->Summary());
427
  pItem->SetProperty("Addon.Description", addon->Description());
428
  pItem->SetProperty("Addon.Creator", addon->Author());
429
  pItem->SetProperty("Addon.Disclaimer", addon->Disclaimer());
430
  pItem->SetProperty("Addon.Rating", addon->Stars());
431
  pItem->SetProperty("Addon.Path", addon->Path());
432
}