Task.h 8.32 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
87
88
89
    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
        Fatal
    };

90
    enum class ParserStep : uint8_t
91
    {
92
93
94
        None = 0,
        MetadataExtraction = 1,
        MetadataAnalysis = 2,
95

96
        Completed = 1 | 2,
97
98
    };

99
    class Item
100
    {
101
    public:
102
        Item() = default;
103
104
105
106
107
108
109
        /**
         * @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
         */
110
111
        Item( ITaskCb* taskCb, std::string mrl, unsigned int subitemIndex );
        Item( ITaskCb* taskCb, std::shared_ptr<fs::IFile> fileFs,
112
113
              std::shared_ptr<Folder> folder, std::shared_ptr<fs::IDirectory> folderFs,
              std::shared_ptr<Playlist> parentPlaylist, unsigned int parentPlaylistIndex );
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
        enum class Metadata : uint8_t
        {
            Title,
            ArtworkUrl,
            ShowName,
            Episode,
            Album,
            Genre,
            Date,
            AlbumArtist,
            Artist,
            TrackNumber,
            DiscNumber,
            DiscTotal,
        };
129

Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
130
131
132
133
134
135
136
137
        struct MetadataHash
        {
            size_t operator()(Metadata m) const
            {
                return static_cast<size_t>( m );
            }
        };

138
139
140
141
142
143
144
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
        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;
            };
        };

172
173
174
        std::string meta( Metadata type ) const;
        void setMeta( Metadata type, std::string value );

175
        const std::string& mrl() const;
176
        void setMrl( std::string mrl );
177

178
        const std::vector<Item>& subItems() const;
179
        Item& createSubItem( std::string mrl, unsigned int playlistIndex );
180

181
182
183
        int64_t duration() const;
        void setDuration( int64_t duration );

184
185
186
        const std::vector<Track>& tracks() const;
        void addTrack( Track t );

187
188
189
        std::shared_ptr<Media> media();
        void setMedia( std::shared_ptr<Media> media );

190
        std::shared_ptr<File> file();
191
        bool setFile( std::shared_ptr<File> file );
192
193
194
195
196
197
198
199
200
201
202

        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;

203
    private:
204
205
        ITaskCb* m_taskCb;

206
        std::string m_mrl;
Hugo Beauzée-Luyssen's avatar
Hugo Beauzée-Luyssen committed
207
        std::unordered_map<Metadata, std::string, MetadataHash> m_metadata;
208
        std::vector<Item> m_subItems;
209
        std::vector<Track> m_tracks;
210
        int64_t m_duration;
211
        std::shared_ptr<Media> m_media;
212
213
214
215
216
217
        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;
218
219
    };

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

222

223
224
225
226
227
    /*
     * 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
     */
228
229
    Task( MediaLibraryPtr ml, sqlite::Row& row );
    Task( MediaLibraryPtr ml, std::shared_ptr<fs::IFile> fileFs,
230
          std::shared_ptr<Folder> parentFolder,
231
          std::shared_ptr<fs::IDirectory> parentFolderFs,
232
          std::shared_ptr<Playlist> parentPlaylist,
233
          unsigned int parentPlaylistIndex );
234

235
236
237
238
239
240
241
    /*
     * 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
     */
242
    void markStepCompleted( ParserStep stepCompleted );
243
244
245
246
247
248
249
250
    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();

251
    virtual bool updateFileId( int64_t fileId ) override;
252
    int64_t id() const;
253

254
    Item& item();
255

256
257
    // Restore attached entities such as media/files
    bool restoreLinkedEntities();
258
    void setMrl( std::string mrl );
259

260
    unsigned int                    currentService;
261
262
263
264

    static void createTable( sqlite::Connection* dbConnection );
    static void resetRetryCount( MediaLibraryPtr ml );
    static void resetParsing( MediaLibraryPtr ml );
265
    static std::vector<std::shared_ptr<Task>> fetchUncompleted( MediaLibraryPtr ml );
266
267
268
269
    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 );
270
    static void recoverUnscannedFiles( MediaLibraryPtr ml );
271
272
273
274
275
276
277
278
279

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;
280
    Item        m_item;
281

282
    friend policy::TaskTable;
283
284
285
};

}
286
287

}