1 /*
2 * * Copyright (C) 2009-2011 Ali <aliov@xfce.org>
3 * * Copyright (C) 2012-2017 Simon Steinbeiß <ochosi@xfce.org>
4 * * Copyright (C) 2012-2020 Sean Davis <bluesabre@xfce.org>
5 *
6 * Licensed under the GNU General Public License Version 2
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30
31 #include <glib.h>
32 #include <gio/gio.h>
33
34 #ifdef HAVE_TAGLIBC
35 #include <taglib/tag_c.h>
36 #endif
37
38 #include "src/misc/parole-file.h"
39
40
41 struct _ParoleFilePrivate {
42 gchar *filename;
43 gchar *display_name;
44 gchar *uri;
45 gchar *content_type;
46 gchar *directory;
47 gchar *custom_subtitles;
48 gint dvd_chapter;
49 };
50
51 enum {
52 PROP_0,
53 PROP_PATH,
54 PROP_DISPLAY_NAME,
55 PROP_URI,
56 PROP_CONTENT_TYPE,
57 PROP_DIRECTORY,
58 PROP_CUSTOM_SUBTITLES,
59 PROP_DVD_CHAPTER
60 };
61
G_DEFINE_TYPE_WITH_PRIVATE(ParoleFile,parole_file,G_TYPE_OBJECT)62 G_DEFINE_TYPE_WITH_PRIVATE(ParoleFile, parole_file, G_TYPE_OBJECT)
63
64 static void
65 parole_file_finalize(GObject *object) {
66 ParoleFile *file;
67
68 file = PAROLE_FILE(object);
69
70 if ( file->priv->filename )
71 g_free(file->priv->filename);
72
73 if ( file->priv->uri )
74 g_free(file->priv->uri);
75
76 if ( file->priv->display_name )
77 g_free(file->priv->display_name);
78
79 if ( file->priv->content_type )
80 g_free(file->priv->content_type);
81
82 if ( file->priv->directory )
83 g_free(file->priv->directory);
84
85 if ( file->priv->custom_subtitles )
86 g_free(file->priv->custom_subtitles);
87
88 G_OBJECT_CLASS(parole_file_parent_class)->finalize(object);
89 }
90
91 static void
parole_file_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)92 parole_file_set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) {
93 ParoleFile *file;
94 file = PAROLE_FILE(object);
95
96 switch (prop_id) {
97 case PROP_PATH:
98 file->priv->filename = g_value_dup_string(value);
99 break;
100 case PROP_DISPLAY_NAME:
101 file->priv->display_name = g_value_dup_string(value);
102 break;
103 case PROP_DIRECTORY:
104 file->priv->directory = g_value_dup_string(value);
105 break;
106 case PROP_CUSTOM_SUBTITLES:
107 file->priv->custom_subtitles = g_value_dup_string(value);
108 break;
109 case PROP_DVD_CHAPTER:
110 file->priv->dvd_chapter = g_value_get_int(value);
111 break;
112 default:
113 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
114 break;
115 }
116 }
117
118 static void
parole_file_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)119 parole_file_get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) {
120 ParoleFile *file;
121
122 file = PAROLE_FILE(object);
123
124 switch (prop_id) {
125 case PROP_PATH:
126 g_value_set_string(value, file->priv->filename);
127 break;
128 case PROP_URI:
129 g_value_set_string(value, file->priv->filename);
130 break;
131 case PROP_CONTENT_TYPE:
132 g_value_set_string(value, file->priv->content_type);
133 break;
134 case PROP_DISPLAY_NAME:
135 g_value_set_string(value, file->priv->display_name);
136 break;
137 case PROP_DIRECTORY:
138 g_value_set_string(value, file->priv->directory);
139 break;
140 case PROP_CUSTOM_SUBTITLES:
141 g_value_set_string(value, file->priv->custom_subtitles);
142 break;
143 case PROP_DVD_CHAPTER:
144 g_value_set_int(value, file->priv->dvd_chapter);
145 break;
146 default:
147 G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
148 break;
149 }
150 }
151
152 static void
parole_file_constructed(GObject * object)153 parole_file_constructed(GObject *object) {
154 GFile *gfile;
155 GFileInfo *info;
156 ParoleFile *file;
157 GError *error = NULL;
158
159 gchar *filename;
160
161 file = PAROLE_FILE(object);
162
163 filename = g_strdup(file->priv->filename);
164
165 if ( g_str_has_prefix(filename, "cdda") ) {
166 file->priv->directory = NULL;
167 file->priv->uri = g_strdup(filename);
168 file->priv->content_type = g_strdup("cdda");
169 g_free(filename);
170 return;
171 }
172
173 if ( g_str_has_prefix(filename, "dvd") ) {
174 file->priv->directory = NULL;
175 file->priv->uri = g_strdup("dvd:/");
176 file->priv->content_type = g_strdup("dvd");
177 g_free(filename);
178 return;
179 }
180
181 g_free(filename);
182
183 gfile = g_file_new_for_commandline_arg(file->priv->filename);
184
185 info = g_file_query_info(gfile,
186 "standard::*,",
187 0,
188 NULL,
189 &error);
190
191
192 file->priv->directory = g_file_get_path(g_file_get_parent(gfile));
193
194 if ( error ) {
195 if (G_LIKELY(error->code == G_IO_ERROR_NOT_SUPPORTED)) {
196 g_error_free(error);
197 if (!file->priv->display_name)
198 file->priv->display_name = g_file_get_basename(gfile);
199 } else {
200 if (!file->priv->display_name)
201 file->priv->display_name = g_strdup(file->priv->filename);
202 g_warning("Unable to read file info %s", error->message);
203 }
204 goto out;
205 }
206 #ifdef HAVE_TAGLIBC
207 if (!error) {
208 TagLib_File *tag_file;
209 TagLib_Tag *tag;
210 gchar *title;
211 gchar *title_s;
212
213 tag_file = taglib_file_new(file->priv->filename);
214
215 if ( tag_file ) {
216 tag = taglib_file_tag(tag_file);
217 if ( tag ) {
218 title = taglib_tag_title(tag);
219
220 if ( title ) {
221 title_s = g_strstrip(title);
222 if ( strlen(title_s) ) {
223 file->priv->display_name = g_strdup(title_s);
224 }
225 }
226
227 taglib_tag_free_strings();
228 }
229 taglib_file_free(tag_file);
230 }
231 }
232 #endif
233
234 if (!file->priv->display_name)
235 file->priv->display_name = g_strdup(g_file_info_get_display_name(info));
236
237 file->priv->content_type = g_strdup(g_file_info_get_content_type(info));
238
239 g_object_unref(info);
240
241 out:
242 file->priv->uri = g_file_get_uri(gfile);
243 g_object_unref(gfile);
244 }
245
246 static void
parole_file_class_init(ParoleFileClass * klass)247 parole_file_class_init(ParoleFileClass *klass) {
248 GObjectClass *object_class = G_OBJECT_CLASS(klass);
249
250 object_class->finalize = parole_file_finalize;
251
252 object_class->constructed = parole_file_constructed;
253 object_class->set_property = parole_file_set_property;
254 object_class->get_property = parole_file_get_property;
255
256 /**
257 * ParoleFile:filename:
258 *
259 * The file name of the file.
260 *
261 * Since: 0.2
262 **/
263 g_object_class_install_property(object_class,
264 PROP_PATH,
265 g_param_spec_string("filename",
266 "File name",
267 "The file name",
268 NULL,
269 G_PARAM_CONSTRUCT_ONLY|
270 G_PARAM_READWRITE));
271
272 /**
273 * ParoleFile:display-name:
274 *
275 * A UTF-8 name that can be displayed in the UI.
276 *
277 * Since: 0.2
278 **/
279 g_object_class_install_property(object_class,
280 PROP_DISPLAY_NAME,
281 g_param_spec_string("display-name",
282 "Display name",
283 "A UTF-8 name that can be displayed in the UI",
284 NULL,
285 G_PARAM_CONSTRUCT_ONLY|
286 G_PARAM_READWRITE));
287
288 /**
289 * ParoleFile:uri:
290 *
291 * The uri of the file.
292 *
293 * Since: 0.2
294 **/
295 g_object_class_install_property(object_class,
296 PROP_URI,
297 g_param_spec_string("uri",
298 "Uri",
299 "The uri of the file",
300 NULL,
301 G_PARAM_READABLE));
302
303 /**
304 * ParoleFile:content-type:
305 *
306 * The content type of the file.
307 *
308 * Since: 0.2
309 **/
310 g_object_class_install_property(object_class,
311 PROP_CONTENT_TYPE,
312 g_param_spec_string("content-type",
313 "Content type",
314 "The content type of the file",
315 NULL,
316 G_PARAM_READABLE));
317
318 /**
319 * ParoleFile:directory:
320 *
321 * The parent directory of the file.
322 *
323 * Since: 0.2
324 **/
325 g_object_class_install_property(object_class,
326 PROP_DIRECTORY,
327 g_param_spec_string("directory",
328 "Parent directory",
329 "The parent directory of the file",
330 NULL,
331 G_PARAM_CONSTRUCT_ONLY|
332 G_PARAM_READWRITE));
333
334 /**
335 * ParoleFile:custom_subtitles:
336 *
337 * The custom subtitles set by the user.
338 *
339 * Since: 0.4
340 **/
341 g_object_class_install_property(object_class,
342 PROP_CUSTOM_SUBTITLES,
343 g_param_spec_string("custom_subtitles",
344 "Custom Subtitles",
345 "The custom subtitles set by the user",
346 NULL,
347 G_PARAM_CONSTRUCT_ONLY|
348 G_PARAM_READWRITE));
349
350 /**
351 * ParoleFile:dvd_chapter:
352 *
353 * DVD Chapter, used for seeking a DVD using the playlist.
354 *
355 * Since: 0.4
356 **/
357 g_object_class_install_property(object_class,
358 PROP_DVD_CHAPTER,
359 g_param_spec_int("dvd-chapter",
360 "DVD Chapter",
361 "DVD Chapter, used for seeking a DVD using the playlist.",
362 -1,
363 1000,
364 -1,
365 G_PARAM_CONSTRUCT_ONLY|
366 G_PARAM_READWRITE));
367 }
368
369 static void
parole_file_init(ParoleFile * file)370 parole_file_init(ParoleFile *file) {
371 file->priv = parole_file_get_instance_private(file);
372
373 file->priv->filename = NULL;
374 file->priv->display_name = NULL;
375 file->priv->uri = NULL;
376 file->priv->content_type = NULL;
377 file->priv->directory = NULL;
378 file->priv->custom_subtitles = NULL;
379 file->priv->dvd_chapter = 0;
380 }
381
382 /**
383 * parole_file_new:
384 * @filename: filename
385 *
386 * Create a new #ParoleFile.
387 *
388 * Returns: A new #ParoleFile object
389 *
390 * Since: 0.2
391 **/
392 ParoleFile *
parole_file_new(const gchar * filename)393 parole_file_new(const gchar *filename) {
394 ParoleFile *file = NULL;
395 file = g_object_new(PAROLE_TYPE_FILE, "filename", filename, NULL);
396 return file;
397 }
398
399 /**
400 * parole_file_new_with_display_name:
401 * @filename: filename
402 * @display_name: the name to display
403 *
404 * Create a new #ParoleFile for a file stored on the filesystem.
405 *
406 * Returns: A new #ParoleFile object
407 *
408 * Since: 0.2
409 **/
410 ParoleFile *
parole_file_new_with_display_name(const gchar * filename,const gchar * display_name)411 parole_file_new_with_display_name(const gchar *filename, const gchar *display_name) {
412 ParoleFile *file = NULL;
413
414 file = g_object_new(PAROLE_TYPE_FILE,
415 "filename", filename,
416 "display-name", display_name,
417 NULL);
418
419 return file;
420 }
421
422 /**
423 * parole_file_new_cdda_track:
424 * @track_num: cd track number
425 * @display_name: the track name to display
426 *
427 * Create a new #ParoleFile object for a CD track number.
428 *
429 * Returns: A new #ParoleFile object
430 *
431 * Since: 0.4
432 **/
433 ParoleFile *
parole_file_new_cdda_track(const gint track_num,const gchar * display_name)434 parole_file_new_cdda_track(const gint track_num, const gchar *display_name) {
435 ParoleFile *file = NULL;
436 gchar *uri = g_strdup_printf("cdda://%i", track_num);
437
438 file = g_object_new(PAROLE_TYPE_FILE,
439 "filename", uri,
440 "display-name", display_name,
441 NULL);
442
443 g_free(uri);
444 return file;
445 }
446
447 /**
448 * parole_file_new_dvd_chapter:
449 * @chapter_num: dvd chapter number
450 * @display_name: the chapter name to display
451 *
452 * Create a new #ParoleFile object for a DVD chapter number.
453 *
454 * Returns: A new #ParoleFile object
455 *
456 * Since: 0.4
457 **/
458 ParoleFile *
parole_file_new_dvd_chapter(gint chapter_num,const gchar * display_name)459 parole_file_new_dvd_chapter(gint chapter_num, const gchar *display_name) {
460 ParoleFile *file = NULL;
461 const gchar uri[] = "dvd:/";
462
463 file = g_object_new(PAROLE_TYPE_FILE,
464 "filename", uri,
465 "display-name", display_name,
466 "dvd-chapter", chapter_num,
467 NULL);
468 return file;
469 }
470
471 /**
472 * parole_file_get_file_name:
473 * @file: a #ParoleFile
474 *
475 * Get the filename for a #ParoleFile.
476 *
477 * Returns: A string containing the file name
478 *
479 * Since: 0.2
480 **/
481 const gchar *
parole_file_get_file_name(const ParoleFile * file)482 parole_file_get_file_name(const ParoleFile *file) {
483 g_return_val_if_fail(PAROLE_IS_FILE(file), NULL);
484
485 return file->priv->filename;
486 }
487
488 /**
489 * parole_file_get_display_name:
490 * @file: a #ParoleFile
491 *
492 * Get the display name for a #ParoleFile.
493 *
494 * Returns: A string containing the display name
495 *
496 * Since: 0.2
497 **/
498 const gchar *
parole_file_get_display_name(const ParoleFile * file)499 parole_file_get_display_name(const ParoleFile *file) {
500 g_return_val_if_fail(PAROLE_IS_FILE(file), NULL);
501
502 return file->priv->display_name;
503 }
504
505 /**
506 * parole_file_get_uri:
507 * @file: a #ParoleFile
508 *
509 * Get the file uri for a #ParoleFile.
510 *
511 * Returns: A string containing the file uri
512 *
513 * Since: 0.2
514 **/
515 const gchar *
parole_file_get_uri(const ParoleFile * file)516 parole_file_get_uri(const ParoleFile *file) {
517 g_return_val_if_fail(PAROLE_IS_FILE(file), NULL);
518
519 return file->priv->uri;
520 }
521
522 /**
523 * parole_file_get_content_type:
524 * @file: a #ParoleFile
525 *
526 * Get the content type for a #ParoleFile.
527 *
528 * Returns: A string containing the content type of the file
529 *
530 * Since: 0.2
531 **/
532 const gchar *
parole_file_get_content_type(const ParoleFile * file)533 parole_file_get_content_type(const ParoleFile *file) {
534 g_return_val_if_fail(PAROLE_IS_FILE(file), NULL);
535
536 return file->priv->content_type;
537 }
538
539 /**
540 * parole_file_get_directory:
541 * @file: a #ParoleFile
542 *
543 * Get the parent directory path for a #ParoleFile.
544 *
545 * Returns: A string containing the parent directory path
546 *
547 * Since: 0.2
548 **/
549 const gchar *
parole_file_get_directory(const ParoleFile * file)550 parole_file_get_directory(const ParoleFile *file) {
551 g_return_val_if_fail(PAROLE_IS_FILE(file), NULL);
552
553 return file->priv->directory;
554 }
555
556 /**
557 * parole_file_get_custom_subtitles:
558 * @file: a #ParoleFile
559 *
560 * Get the custom subtitles path for a #ParoleFile.
561 *
562 * Returns: A string containing the custom subtitles file path
563 *
564 * Since: 0.4
565 **/
566 const gchar *
parole_file_get_custom_subtitles(const ParoleFile * file)567 parole_file_get_custom_subtitles(const ParoleFile *file) {
568 g_return_val_if_fail(PAROLE_IS_FILE(file), NULL);
569
570 return file->priv->custom_subtitles;
571 }
572
573 /**
574 * parole_file_set_custom_subtitles:
575 * @file: a #ParoleFile
576 * @suburi: uri for the subtitles file
577 *
578 * Set the custom subtitles path for a #ParoleFile.
579 *
580 * Since: 0.4
581 **/
582 void
parole_file_set_custom_subtitles(const ParoleFile * file,gchar * suburi)583 parole_file_set_custom_subtitles(const ParoleFile *file, gchar *suburi) {
584 GValue value = G_VALUE_INIT;
585 g_value_init(&value, G_TYPE_STRING);
586 g_value_set_static_string(&value, suburi);
587
588 parole_file_set_property(G_OBJECT(file), PROP_CUSTOM_SUBTITLES,
589 &value, g_param_spec_string("custom_subtitles",
590 "Custom Subtitles",
591 "The custom subtitles set by the user",
592 NULL,
593 G_PARAM_CONSTRUCT_ONLY|
594 G_PARAM_READWRITE));
595 }
596
597 /**
598 * parole_file_get_dvd_chapter:
599 * @file: a #ParoleFile
600 *
601 * Get the chapter number for a #ParoleFile.
602 *
603 * Returns: An int containing the dvd chapter number
604 *
605 * Since: 0.4
606 **/
607 gint
parole_file_get_dvd_chapter(const ParoleFile * file)608 parole_file_get_dvd_chapter(const ParoleFile *file) {
609 // g_return_val_if_fail (PAROLE_IS_FILE (file), NULL);
610
611 return file->priv->dvd_chapter;
612 }
613
614 /**
615 * parole_file_set_dvd_chapter:
616 * @file: a #ParoleFile
617 * @dvd_chapter: chapter number to store
618 *
619 * Set the chapter number for a #ParoleFile.
620 *
621 * Since: 0.4
622 **/
623 void
parole_file_set_dvd_chapter(const ParoleFile * file,gint dvd_chapter)624 parole_file_set_dvd_chapter(const ParoleFile *file, gint dvd_chapter) {
625 GValue value = G_VALUE_INIT;
626 g_value_init(&value, G_TYPE_INT);
627 g_value_set_int(&value, dvd_chapter);
628
629 parole_file_set_property(G_OBJECT(file), PROP_DVD_CHAPTER,
630 &value, g_param_spec_int("dvd-chapter",
631 "DVD Chapter",
632 "DVD Chapter, used for seeking a DVD using the playlist.",
633 -1,
634 1000,
635 -1,
636 G_PARAM_CONSTRUCT_ONLY|
637 G_PARAM_READWRITE));
638 }
639