diff --git a/src/Lib/Document/CRTPSubDocument.hh b/src/Lib/Document/CRTPSubDocument.hh
index 5963b9c0204a98b8f5d7ab3339a432910daa94c5..c89f25c587539613cc5ad1f0c00305629f2eb984 100644
--- a/src/Lib/Document/CRTPSubDocument.hh
+++ b/src/Lib/Document/CRTPSubDocument.hh
@@ -1,5 +1,4 @@
-#ifndef VIVY_CRTP_DOCUMENT_H
-#define VIVY_CRTP_DOCUMENT_H
+#pragma once
 
 #ifndef __cplusplus
 #error "This is a C++ header"
@@ -10,10 +9,13 @@
 #include "../Video.hh"
 #include "../Ass/Ass.hh"
 
+#define VIVY_ENABLE_IF_TYPE(Type) \
+    template <typename = typename std::enable_if<!std::is_same<Type, void>::value>>
+
 namespace Vivy
 {
 // The Big CRTP class for all common things to all the subdocuments
-template <class CRTPSubDocumentType, class Document> class CRTPSubDocument {
+template <class CRTPSubDocumentType, class Document, class Context> class CRTPSubDocument {
 public:
     using Type = CRTPSubDocumentType;
     friend std::unique_ptr<Document>;
@@ -47,56 +49,83 @@ public:
         return ret;
     }
 
+    // Get the default stream index or -1 if not possible.
+    VIVY_ENABLE_IF_TYPE(Context)
+    int getDefaultStreamIndex() const noexcept
+    {
+        if (auto ptr = getDefaultStream())
+            return ptr->getStreamIndex();
+        return -1;
+    }
+
+    // Get a pointer to the default stream, nullptr if not possible
+    VIVY_ENABLE_IF_TYPE(Context)
+    auto getDefaultStream() const
+    {
+        const Document *const self = static_cast<const Document *const>(this);
+        auto weakPtr               = self->contextPtr->getDefaultStream();
+        if (auto ptr = weakPtr.lock())
+            return ptr;
+        throw std::runtime_error("SubDocument has been deleted");
+    }
+
+    // Get the stream asked for, nullptr if no stream or if the index is invalid
+    VIVY_ENABLE_IF_TYPE(Context)
+    auto getStream(int index) const
+    {
+        const Document *const self = static_cast<const Document *const>(this);
+        auto weakPtr               = self->contextPtr->getStream(index);
+        if (auto ptr = weakPtr.lock())
+            return ptr;
+        throw std::runtime_error("SubDocument has been deleted");
+    }
+
     inline Type getType() const noexcept { return fileType; }
     inline QString getFilePath() const noexcept { return filePath; }
 };
 
 // Audio document
-class AudioSubDocument final : public CRTPSubDocument<AudioDocumentType, AudioSubDocument> {
+class AudioSubDocument final
+    : public CRTPSubDocument<AudioDocumentType, AudioSubDocument, AudioContext> {
     const QStringList &suffixList = Vivy::Utils::audioFileSuffix;
     std::unique_ptr<AudioContext> contextPtr{ nullptr };
 
     void initFromPath(const QString &);
 
     explicit AudioSubDocument() = default;
-    friend CRTPSubDocument<AudioDocumentType, AudioSubDocument>;
+    friend CRTPSubDocument<AudioDocumentType, AudioSubDocument, AudioContext>;
 
 public:
-    int getDefaultStreamIndex() const noexcept;
-    AudioContext::StreamPtr getDefaultStream() const noexcept;
-    AudioContext::StreamPtr getStream(int index) const noexcept;
-
     QString getElementName() const noexcept;
     QJsonDocument getProperties() const noexcept;
 };
 
 // Video document
-class VideoSubDocument final : public CRTPSubDocument<VideoDocumentType, VideoSubDocument> {
-    const QStringList &suffixList = Vivy::Utils::videoFileSuffix;
+class VideoSubDocument final
+    : public CRTPSubDocument<VideoDocumentType, VideoSubDocument, VideoContext> {
+    static constexpr inline bool hasContext = true;
+    const QStringList &suffixList           = Vivy::Utils::videoFileSuffix;
     std::unique_ptr<VideoContext> contextPtr{ nullptr };
 
     void initFromPath(const QString &);
 
     explicit VideoSubDocument() noexcept = default;
-    friend CRTPSubDocument<VideoDocumentType, VideoSubDocument>;
+    friend CRTPSubDocument<VideoDocumentType, VideoSubDocument, VideoContext>;
 
 public:
-    int getDefaultStreamIndex() const noexcept;
-    VideoContext::StreamPtr getDefaultStream() const noexcept;
-    VideoContext::StreamPtr getStream(int index) const noexcept;
-
     QString getElementName() const noexcept;
     QJsonDocument getProperties() const noexcept;
 };
 
 // ASS document
-class AssSubDocument final : public CRTPSubDocument<AssDocumentType, AssSubDocument> {
-    const QStringList &suffixList = Vivy::Utils::assFileSuffix;
+class AssSubDocument final : public CRTPSubDocument<AssDocumentType, AssSubDocument, void> {
+    static constexpr inline bool hasContext = false;
+    const QStringList &suffixList           = Vivy::Utils::assFileSuffix;
 
     void initFromPath(const QString &);
 
     explicit AssSubDocument() noexcept = default;
-    friend CRTPSubDocument<AssDocumentType, AssSubDocument>;
+    friend CRTPSubDocument<AssDocumentType, AssSubDocument, void>;
 
 public:
     QString getElementName() const noexcept;
@@ -109,7 +138,4 @@ private:
     QVector<Ass::StylePtr> styles;
     QVector<Ass::LinePtr> lines;
 };
-
 }
-
-#endif // VIVY_CRTP_DOCUMENT_H
diff --git a/src/Lib/Document/CRTPSubDocument/AudioSubDocument.cc b/src/Lib/Document/CRTPSubDocument/AudioSubDocument.cc
index d1e68c088c6baf3dc1a7f2c69f102e56cac60515..c26b99e424aa7b0c06efebd3f79628a11262b0dc 100644
--- a/src/Lib/Document/CRTPSubDocument/AudioSubDocument.cc
+++ b/src/Lib/Document/CRTPSubDocument/AudioSubDocument.cc
@@ -2,40 +2,6 @@
 
 using namespace Vivy;
 
-// Get the default stream index or -1 if not possible
-int
-AudioSubDocument::getDefaultStreamIndex() const noexcept
-{
-    if (auto ptr = getDefaultStream()) {
-        return ptr->getStreamIndex();
-    } else {
-        return -1;
-    }
-}
-
-// Get a pointer to the default stream, nullptr if not possible
-AudioContext::StreamPtr
-AudioSubDocument::getDefaultStream() const noexcept
-{
-    if (auto ptr = contextPtr->getDefaultStream().lock()) {
-        return ptr;
-    } else {
-        qCritical() << "Document deleted!";
-        return nullptr;
-    }
-}
-
-// Get the stream asked for, nullptr if no stream or if the index is invalid
-AudioContext::StreamPtr
-AudioSubDocument::getStream(int index) const noexcept
-{
-    if (auto ptr = contextPtr->getStream(index).lock()) {
-        return ptr;
-    } else {
-        return nullptr;
-    }
-}
-
 // Init an audio sub-document from a file
 void
 AudioSubDocument::initFromPath(const QString &path)
diff --git a/src/Lib/Document/CRTPSubDocument/VideoSubDocument.cc b/src/Lib/Document/CRTPSubDocument/VideoSubDocument.cc
index eaa2a7ed99c99a8d84c698c367f3fe0ae2723216..085131abdd7353a3f5b61434a4efb75c5aa4201d 100644
--- a/src/Lib/Document/CRTPSubDocument/VideoSubDocument.cc
+++ b/src/Lib/Document/CRTPSubDocument/VideoSubDocument.cc
@@ -2,40 +2,6 @@
 
 using namespace Vivy;
 
-// Get the default stream index or -1 if not possible
-int
-VideoSubDocument::getDefaultStreamIndex() const noexcept
-{
-    if (auto ptr = getDefaultStream()) {
-        return ptr->getStreamIndex();
-    } else {
-        return -1;
-    }
-}
-
-// Get a pointer to the default stream, nullptr if not possible
-VideoContext::StreamPtr
-VideoSubDocument::getDefaultStream() const noexcept
-{
-    if (auto ptr = contextPtr->getDefaultStream().lock()) {
-        return ptr;
-    } else {
-        qCritical() << "Document deleted!";
-        return nullptr;
-    }
-}
-
-// Get the stream asked for, nullptr if no stream or if the index is invalid
-VideoContext::StreamPtr
-VideoSubDocument::getStream(int index) const noexcept
-{
-    if (auto ptr = contextPtr->getStream(index).lock()) {
-        return ptr;
-    } else {
-        return nullptr;
-    }
-}
-
 // Init a video sub-document from a file
 void
 VideoSubDocument::initFromPath(const QString &path)