Task.h 8.69 KB
Newer Older
1
2
3
4
5
6
/*****************************************************************************
 * Media Library
 *****************************************************************************
 * Copyright (C) 2015 Hugo Beauzée-Luyssen, Videolabs
 *
 * Authors: Hugo Beauzée-Luyssen<hugo@beauzee.fr>
7
 *          Alexandre Fernandez <nerf@boboop.fr>
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
 *****************************************************************************/

#pragma once

#include <memory>
27
#include <utility>
28
#include <vector>
29
#include <string>
30
#include <unordered_map>
31

32
33
#include "database/DatabaseHelpers.h"

34
35
36
namespace medialibrary
{

37
38
39
40
41
42
namespace fs
{
class IDirectory;
class IFile;
}

43
44
class Media;
class File;
45
class Folder;
46
class Playlist;
47

48
49
namespace parser
{
50
51
class Task;
}
52

53
54
55
56
57
58
59
60
61
62
63
64
65
namespace policy
{
struct TaskTable
{
    static const std::string Name;
    static const std::string PrimaryKeyColumn;
    static int64_t parser::Task::*const PrimaryKey;
};
}

namespace parser
{

66
67
68
69
70
71
72
73
class ITaskCb
{
public:
    virtual ~ITaskCb() = default;
    virtual bool updateFileId( int64_t fileId ) = 0;
};

class Task : public DatabaseHelpers<Task, policy::TaskTable, cachepolicy::Uncached<Task>>, private ITaskCb
74
{
75
public:
76
77
78
79
80
81
82
83
84
85
86
    enum class Status
    {
        /// Default value.
        /// Also, having success = 0 is not the best idea ever.
        Unknown,
        /// All good
        Success,
        /// We can't compute this file for now (for instance the file was on a network drive which
        /// isn't connected anymore)
        TemporaryUnavailable,
        /// Something failed and we won't continue
87
88
89
90
91
92
93
94
        Fatal,
        /// The task must now be considered completed, regardless of the
        /// current step.
        Completed,
        /// The task should be discarded, regardless of its status
        /// This is likely to be used when trying to parse playlist items,
        /// as they already could have been queued before.
        Discarded,
95
96
    };

97
    enum class ParserStep : uint8_t
98
    {
99
100
101
        None = 0,
        MetadataExtraction = 1,
        MetadataAnalysis = 2,
102

103
        Completed = 1 | 2,
104
105
    };

106
    class Item
107
    {
108
    public:
109
        Item() = default;
110
111
112
113
114
115
116
        /**
         * @brief Item Construct a parser item with a given mrl and subitem index
         * @param mrl The item's mrl
         * @param subitemPosition A potential subitem index, if any, or 0 if none.
         *
         * The position is used to keep subitems ordering for playlists
         */
117
118
        Item( ITaskCb* taskCb, std::string mrl, unsigned int subitemIndex );
        Item( ITaskCb* taskCb, std::shared_ptr<fs::IFile> fileFs,
119
120
              std::shared_ptr<Folder> folder, std::shared_ptr<fs::IDirectory> folderFs,
              std::shared_ptr<Playlist> parentPlaylist, unsigned int parentPlaylistIndex );
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
        enum class Metadata : uint8_t
        {
            Title,
            ArtworkUrl,
            ShowName,
            Episode,
            Album,
            Genre,
            Date,
            AlbumArtist,
            Artist,
            TrackNumber,
            DiscNumber,
            DiscTotal,
        };
136

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
137
138
139
140
141
142
143
144
        struct MetadataHash
        {
            size_t operator()(Metadata m) const
            {
                return static_cast<size_t>( m );
            }
        };

145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
        struct Track
        {
            enum class Type : uint8_t
            {
                Video,
                Audio,
            };

            std::string codec;
            Type type;
            uint32_t bitrate;
            std::string language;
            std::string description;
            // Audio
            union
            {
                struct
                {
                    uint32_t nbChannels;
                    uint32_t rate;
                } a;
                struct
                {
                    // Video
                    uint32_t height;
                    uint32_t width;
                    uint32_t sarNum;
                    uint32_t sarDen;
                    uint32_t fpsNum;
                    uint32_t fpsDen;
                } v;
            };
        };

179
180
181
        std::string meta( Metadata type ) const;
        void setMeta( Metadata type, std::string value );

182
        const std::string& mrl() const;
183
        void setMrl( std::string mrl );
184

185
186
        size_t nbSubItems() const;
        const Item& subItem( unsigned int index ) const;
187
        Item& createSubItem( std::string mrl, unsigned int playlistIndex );
188

189
190
191
        int64_t duration() const;
        void setDuration( int64_t duration );

192
193
194
        const std::vector<Track>& tracks() const;
        void addTrack( Track t );

195
196
197
        std::shared_ptr<Media> media();
        void setMedia( std::shared_ptr<Media> media );

198
        std::shared_ptr<File> file();
199
        bool setFile( std::shared_ptr<File> file );
200
201
202
203
204
205
206
207
208
209
210

        std::shared_ptr<Folder> parentFolder();

        std::shared_ptr<fs::IFile> fileFs();

        std::shared_ptr<fs::IDirectory> parentFolderFs();

        std::shared_ptr<Playlist> parentPlaylist();

        unsigned int parentPlaylistIndex() const;

211
    private:
212
213
        ITaskCb* m_taskCb;

214
        std::string m_mrl;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
215
        std::unordered_map<Metadata, std::string, MetadataHash> m_metadata;
216
        std::vector<Item> m_subItems;
217
        std::vector<Track> m_tracks;
218
        int64_t m_duration;
219
        std::shared_ptr<Media> m_media;
220
221
222
223
224
225
        std::shared_ptr<File> m_file;
        std::shared_ptr<fs::IFile> m_fileFs;
        std::shared_ptr<Folder> m_parentFolder;
        std::shared_ptr<fs::IDirectory> m_parentFolderFs;
        std::shared_ptr<Playlist> m_parentPlaylist;
        unsigned int m_parentPlaylistIndex;
226
227
    };

228
229
    static_assert( std::is_move_assignable<Item>::value, "Item must be move assignable" );

230

231
232
233
234
235
    /*
     * Constructs a task to be resumed.
     * The Media is provided as a parameter to avoid this to implicitely query
     * the database for the media associated to the provided file
     */
236
237
    Task( MediaLibraryPtr ml, sqlite::Row& row );
    Task( MediaLibraryPtr ml, std::shared_ptr<fs::IFile> fileFs,
238
          std::shared_ptr<Folder> parentFolder,
239
          std::shared_ptr<fs::IDirectory> parentFolderFs,
240
          std::shared_ptr<Playlist> parentPlaylist,
241
          unsigned int parentPlaylistIndex );
242

243
244
245
246
247
248
249
    /*
     * We need to decouple the current parser state and the saved one.
     * For instance, metadata extraction won't save anything in DB, so while
     * we might want to know that it's been processed and metadata have been
     * extracted, in case we were to restart the parsing, we would need to
     * extract the same information again
     */
250
    void markStepCompleted( ParserStep stepCompleted );
251
252
253
254
255
256
257
258
    bool saveParserStep();
    bool isCompleted() const;
    bool isStepCompleted( ParserStep step ) const;
    /**
     * @brief startParserStep Do some internal book keeping to avoid restarting a step too many time
     */
    void startParserStep();

259
    virtual bool updateFileId( int64_t fileId ) override;
260
    int64_t id() const;
261

262
    Item& item();
263

264
265
    // Restore attached entities such as media/files
    bool restoreLinkedEntities();
266
    void setMrl( std::string mrl );
267

268
    unsigned int                    currentService;
269
270
271
272

    static void createTable( sqlite::Connection* dbConnection );
    static void resetRetryCount( MediaLibraryPtr ml );
    static void resetParsing( MediaLibraryPtr ml );
273
    static std::vector<std::shared_ptr<Task>> fetchUncompleted( MediaLibraryPtr ml );
274
275
276
277
    static std::shared_ptr<Task> create( MediaLibraryPtr ml, std::shared_ptr<fs::IFile> fileFs,
                                         std::shared_ptr<Folder> parentFolder,
                                         std::shared_ptr<fs::IDirectory> parentFolderFs,
                                         std::pair<std::shared_ptr<Playlist>, unsigned int> parentPlaylist );
278
    static void recoverUnscannedFiles( MediaLibraryPtr ml );
279
280
281
282
283
284
285
286
287

private:
    MediaLibraryPtr m_ml;
    int64_t     m_id;
    ParserStep  m_step;
    int         m_retryCount;
    int64_t     m_fileId;
    int64_t     m_parentFolderId;
    int64_t     m_parentPlaylistId;
288
    Item        m_item;
289

290
    friend policy::TaskTable;
291
292
293
};

}
294
295

}