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