sbMediaExportTaskWriter.cpp
Go to the documentation of this file.
1 /*
2  *=BEGIN SONGBIRD GPL
3  *
4  * This file is part of the Songbird web player.
5  *
6  * Copyright(c) 2005-2009 POTI, Inc.
7  * http://www.songbirdnest.com
8  *
9  * This file may be licensed under the terms of of the
10  * GNU General Public License Version 2 (the ``GPL'').
11  *
12  * Software distributed under the License is distributed
13  * on an ``AS IS'' basis, WITHOUT WARRANTY OF ANY KIND, either
14  * express or implied. See the GPL for the specific language
15  * governing rights and limitations.
16  *
17  * You should have received a copy of the GPL along with this
18  * program. If not, go to http://www.gnu.org/licenses/gpl.html
19  * or write to the Free Software Foundation, Inc.,
20  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
21  *
22  *=END SONGBIRD GPL
23  */
24 
26 
27 #include <nsIFile.h>
28 #include <nsIURI.h>
29 #include <nsIFileURL.h>
30 #include <nsDirectoryServiceUtils.h>
31 #include <nsComponentManagerUtils.h>
32 #include <nsServiceManagerUtils.h>
33 #include <sbStandardProperties.h>
34 #include <sbDebugUtils.h>
35 
36 
37 /*
38  This class helps create the exported media task file.
39  The current structure of the file looks like:
40 
41  [schema-version:1]
42  [added-medialists]
43  0=Added Playlist 1
44  1=Added Playlist 2
45  [removed-medialists]
46  0=Removed Playlist A
47  1=Removed Playlist B
48  [updated-smartplaylist:SMART PLAYLIST]
49  0=/path/to/file1.mp3
50  1=/path/to/file2.mp3
51  [added-mediaitems:TEST PLAYLIST]
52  0=/path/to/file1.mp3
53  1=/path/to/file2.mp3
54  2=/path/to/file3.mp3
55 
56  All playlist names and filenames are URL-escaped, and after unescaping will
57  be in UTF-8.
58 
59 */
60 
61 
62 NS_IMPL_ISUPPORTS0(sbMediaExportTaskWriter)
63 
65 {
66  SB_PRLOG_SETUP(sbMediaExportTaskWriter);
67 }
68 
70 {
71 }
72 
73 nsresult
75 {
76  LOG("%s: Setting up a task writer instance", __FUNCTION__);
77 
78  // Create an nsINetUtil instance to do URL-escaping.
79  nsresult rv;
80  mNetUtil = do_GetService(NS_IOSERVICE_CONTRACTID, &rv);
81  NS_ENSURE_SUCCESS(rv, rv);
82 
83  // First, setup the actual export data file to write to.
84  nsCOMPtr<nsIFile> taskFile;
85  rv = NS_GetSpecialDirectory(NS_APP_APPLICATION_REGISTRY_DIR,
86  getter_AddRefs(taskFile));
87  NS_ENSURE_SUCCESS(rv, rv);
88 
89  // Determine if a task file already exists.
90  rv = taskFile->Append(NS_LITERAL_STRING(TASKFILE_NAME));
91  NS_ENSURE_SUCCESS(rv, rv);
92 
93  PRBool exists = PR_FALSE;
94  rv = taskFile->Exists(&exists);
95  NS_ENSURE_SUCCESS(rv, rv);
96 
97  // If an existing task file already exists. Find a unique extension.
98  // NOTE: Consider using nsIFile::CreateUnique
99  PRUint32 curNumeralExtension = 0;
100  while (exists) {
101  nsCString leafName(TASKFILE_NAME);
102  leafName.AppendInt(++curNumeralExtension);
103 
104  rv = taskFile->SetNativeLeafName(leafName);
105  NS_ENSURE_SUCCESS(rv, rv);
106 
107  rv = taskFile->Exists(&exists);
108  NS_ENSURE_SUCCESS(rv, rv);
109  }
110 
111  rv = taskFile->Create(nsIFile::NORMAL_FILE_TYPE, 0600);
112  NS_ENSURE_SUCCESS(rv, rv);
113 
114  rv = taskFile->GetPath(mTaskFilepath);
115  NS_ENSURE_SUCCESS(rv, rv);
116 
117  LOG("%s: Creating task file at '%s'",
118  __FUNCTION__, NS_ConvertUTF16toUTF8(mTaskFilepath).get());
119 
120  // Init the output stream based on the file created above.
121 #if defined(XP_WIN)
122  mOutputStream.open(mTaskFilepath.get());
123 #else
124  mOutputStream.open(NS_ConvertUTF16toUTF8(mTaskFilepath).get());
125 #endif
126  // Write out the current schema version to disk
127  mOutputStream << "["
129  << ":"
131  << "]"
132  << std::endl;
133 
134  return NS_OK;
135 }
136 
137 nsresult
139 {
140  LOG("%s: Done writing task file at '%s'",
141  __FUNCTION__, mTaskFilepath.get());
142 
143  mOutputStream.close();
144  return NS_OK;
145 }
146 
147 nsresult
149 {
150  LOG("%s Writing header '%s'",
151  __FUNCTION__, TASKFILE_ADDEDMEDIALISTS_HEADER);
152 
153  mOutputStream << "["
155  << "]"
156  << std::endl;
157 
158  // Reset the output index
159  mCurOutputIndex = 0;
160  return NS_OK;
161 }
162 
163 nsresult
165 {
166  LOG("%s Writing header '%s'",
167  __FUNCTION__, TASKFILE_REMOVEDMEDIALISTS_HEADER);
168 
169  mOutputStream << "["
171  << "]"
172  << std::endl;
173 
174  // Reset the output index
175  mCurOutputIndex = 0;
176  return NS_OK;
177 }
178 
179 nsresult
181 {
182  NS_ENSURE_ARG_POINTER(aMediaList);
183 
184  LOG("%s Writing header '%s'",
186 
187  nsresult rv;
188 
189  nsString mediaListName;
190  rv = aMediaList->GetName(mediaListName);
191  NS_ENSURE_SUCCESS(rv, rv);
192 
193  nsCString escaped;
194  rv = mNetUtil->EscapeString(NS_ConvertUTF16toUTF8(mediaListName),
195  nsINetUtil::ESCAPE_URL_PATH,
196  escaped);
197  NS_ENSURE_SUCCESS(rv, rv);
198 
199  mOutputStream << "["
201  << ":"
202  << escaped.get()
203  << "]"
204  << std::endl;
205 
206  mCurOutputIndex = 0;
207  return NS_OK;
208 }
209 
210 nsresult
212 {
213  NS_ENSURE_ARG_POINTER(aMediaList);
214 
215  nsresult rv;
216  nsString mediaListName;
217  rv = aMediaList->GetName(mediaListName);
218  NS_ENSURE_SUCCESS(rv, rv);
219 
220  nsCString escaped;
221  if (aIsMainLibrary) {
222  // If you use this as your playlist name, you get what you deserve.
223  escaped.AssignLiteral(SONGBIRD_MAIN_LIBRARY_NAME);
224  } else {
225  rv = mNetUtil->EscapeString(NS_ConvertUTF16toUTF8(mediaListName),
226  nsINetUtil::ESCAPE_URL_PATH, escaped);
227  NS_ENSURE_SUCCESS(rv, rv);
228  }
229 
230  LOG("%s: Writing header '%s' for medialist name '%s'",
231  __FUNCTION__,
232  TASKFILE_ADDEDMEDIAITEMS_HEADER, escaped.get());
233 
234  // Header format looks like this
235  // [added-mediaitems:Playlist Name]
236  mOutputStream << "["
238  << ":"
239  << escaped.get()
240  << "]"
241  << std::endl;
242 
243  // Reset the output index
244  mCurOutputIndex = 0;
245  return NS_OK;
246 }
247 
248 nsresult
250 {
251  LOG("%s: Writing header '%s' for updated items",
252  __FUNCTION__,
254 
255  // Header format looks like this
256  // [updated-mediaitems]
257  mOutputStream << "["
259  << "]"
260  << std::endl;
261 
262  // Reset the output index
263  mCurOutputIndex = 0;
264  return NS_OK;
265 }
266 
267 nsresult
269 {
270  NS_ENSURE_ARG_POINTER(aMediaItem);
271  nsresult rv;
272 
273  // Get the path of mediaitem and write that info to disk
274  nsCOMPtr<nsIURI> contentUri;
275  rv = aMediaItem->GetContentSrc(getter_AddRefs(contentUri));
276  NS_ENSURE_SUCCESS(rv, rv);
277 
278  nsCOMPtr<nsIFileURL> contentFileURL = do_QueryInterface(contentUri, &rv);
279  if (NS_FAILED(rv) || !contentFileURL) {
280  // If this is not a local resource, just warn and return.
281  NS_WARNING("WARNING: Tried to write a remote mediaitem resource!");
282  return NS_OK;
283  }
284 
285  nsCOMPtr<nsIFile> contentFile;
286  rv = contentFileURL->GetFile(getter_AddRefs(contentFile));
287  NS_ENSURE_SUCCESS(rv, rv);
288 
289  nsString itemContentPath;
290  rv = contentFile->GetPath(itemContentPath);
291  NS_ENSURE_SUCCESS(rv, rv);
292 
293  PRBool exists = PR_FALSE;
294  rv = contentFile->Exists(&exists);
295  NS_ENSURE_SUCCESS(rv, rv);
296  NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
297 
298  nsCString escaped;
299  rv = mNetUtil->EscapeString(NS_ConvertUTF16toUTF8(itemContentPath),
300  nsINetUtil::ESCAPE_URL_PATH, escaped);
301  NS_ENSURE_SUCCESS(rv, rv);
302 
303  nsString guid;
304  rv = aMediaItem->GetGuid(guid);
305  NS_ENSURE_SUCCESS(rv, rv);
306 
307  LOG("%s: Writing added track '%s'",
308  __FUNCTION__, escaped.get());
309 
310  mOutputStream << NS_LossyConvertUTF16toASCII(guid).get()
311  << "="
312  << escaped.get()
313  << std::endl;
314 
315  return NS_OK;
316 }
317 
318 nsresult
320 {
321  NS_ENSURE_ARG_POINTER(aMediaItem);
322  nsresult rv;
323 
324  // Get the itunes id of the media item
325  nsString iTunesID;
326  rv = aMediaItem->GetProperty(NS_LITERAL_STRING(SB_PROPERTY_ITUNES_GUID),
327  iTunesID);
328  NS_ENSURE_SUCCESS(rv, rv);
329  NS_ENSURE_TRUE(!iTunesID.IsEmpty(), NS_ERROR_FAILURE);
330 
331  // Get the path of mediaitem and write that info to disk
332  nsCOMPtr<nsIURI> contentUri;
333  rv = aMediaItem->GetContentSrc(getter_AddRefs(contentUri));
334  NS_ENSURE_SUCCESS(rv, rv);
335 
336  nsCOMPtr<nsIFileURL> contentFileURL = do_QueryInterface(contentUri, &rv);
337  if (NS_FAILED(rv) || !contentFileURL) {
338  // If this is not a local resource, just warn and return.
339  NS_WARNING("WARNING: Tried to write a remote mediaitem resource!");
340  return NS_OK;
341  }
342 
343  nsCOMPtr<nsIFile> contentFile;
344  rv = contentFileURL->GetFile(getter_AddRefs(contentFile));
345  NS_ENSURE_SUCCESS(rv, rv);
346 
347  nsString itemContentPath;
348  rv = contentFile->GetPath(itemContentPath);
349  NS_ENSURE_SUCCESS(rv, rv);
350 
351  PRBool exists = PR_FALSE;
352  rv = contentFile->Exists(&exists);
353  NS_ENSURE_SUCCESS(rv, rv);
354  NS_ENSURE_TRUE(exists, NS_ERROR_FILE_NOT_FOUND);
355 
356  nsCString escaped;
357  rv = mNetUtil->EscapeString(NS_ConvertUTF16toUTF8(itemContentPath),
358  nsINetUtil::ESCAPE_URL_PATH, escaped);
359  NS_ENSURE_SUCCESS(rv, rv);
360 
361  LOG("%s: Writing updated track '%s' -> '%s'",
362  __FUNCTION__,
363  NS_LossyConvertUTF16toASCII(iTunesID).get(),
364  escaped.get());
365 
366  mOutputStream << NS_LossyConvertUTF16toASCII(iTunesID).get()
367  << "="
368  << escaped.get()
369  << std::endl;
370 
371  return NS_OK;
372 }
373 
374 nsresult
376 {
377  NS_ENSURE_ARG_POINTER(aMediaList);
378 
379  nsresult rv;
380  nsString listName;
381  rv = aMediaList->GetName(listName);
382  NS_ENSURE_SUCCESS(rv, rv);
383 
384  nsCString escaped;
385  rv = mNetUtil->EscapeString(NS_ConvertUTF16toUTF8(listName),
386  nsINetUtil::ESCAPE_URL_PATH, escaped);
387  NS_ENSURE_SUCCESS(rv, rv);
388 
389  LOG("%s: Writing media list name '%s'",
390  __FUNCTION__, escaped.get());
391 
392  mOutputStream << mCurOutputIndex++
393  << "="
394  << escaped.get()
395  << std::endl;
396 
397  return NS_OK;
398 }
399 
400 nsresult
402 {
403  nsCString escaped;
404  nsresult rv = mNetUtil->EscapeString(NS_ConvertUTF16toUTF8(aString),
405  nsINetUtil::ESCAPE_URL_PATH, escaped);
406  NS_ENSURE_SUCCESS(rv, rv);
407 
408  LOG("%s: Writing string '%s'",
409  __FUNCTION__, escaped.get());
410 
411  mOutputStream << mCurOutputIndex++
412  << "="
413  << escaped.get()
414  << std::endl;
415 
416  return NS_OK;
417 }
418 
nsresult WriteAddedMediaItemsListHeader(sbIMediaList *aMediaList, PRBool aIsMainLibrary=PR_FALSE)
#define SB_PRLOG_SETUP(x)
Definition: sbDebugUtils.h:115
return NS_OK
#define LOG(args)
NS_DECL_ISUPPORTS nsresult Init()
var TASKFILE_SCHEMAVERSION
nsresult WriteUpdatedSmartPlaylistHeader(sbIMediaList *aMediaList)
var TASKFILE_REMOVEDMEDIALISTS_HEADER
var TASKFILE_NAME
A brief description of the contents of this interface.
#define TASKFILE_UPDATEDSMARTPLAYLIST_HEADER
nsresult WriteMediaListName(sbIMediaList *aMediaList)
var TASKFILE_ADDEDMEDIALISTS_HEADER
var TASKFILE_ADDEDMEDIAITEMS_HEADER
nsresult WriteUpdatedTrack(sbIMediaItem *aMediaItem)
#define TASKFILE_SCHEMAVERSION_HEADER
var TASKFILE_UPDATEDMEDIAITEMS_HEADER
#define SONGBIRD_MAIN_LIBRARY_NAME
nsresult WriteEscapedString(const nsAString &aString)
Interface that defines a single item of media in the system.
#define SB_PROPERTY_ITUNES_GUID
nsresult WriteAddedTrack(sbIMediaItem *aMediaItem)