diff --git a/saori.pro b/saori.pro
index 225a8de..7be987b 100644
--- a/saori.pro
+++ b/saori.pro
@@ -33,7 +33,8 @@
     saoricache.cpp \
     saoriviewentry.cpp \
     saoriconfiguredialog.cpp \
-    saoritootwidget.cpp
+    saoritootwidget.cpp \
+    saoridownloader.cpp
 
 HEADERS += \
     saoriwindow.h \
@@ -46,7 +47,8 @@
     saoricache.h \
     saoriviewentry.h \
     saoriconfiguredialog.h \
-    saoritootwidget.h
+    saoritootwidget.h \
+    saoridownloader.h
 
 FORMS += \
     saoriwindow.ui \
diff --git a/saoricache.cpp b/saoricache.cpp
index 96b3420..ffe0095 100644
--- a/saoricache.cpp
+++ b/saoricache.cpp
@@ -51,6 +51,20 @@
 SaoriCache::SaoriCache(QObject *parent) : QObject(parent)
 {
     migration();
+    m_thread = new QThread;
+    m_downloader = new SaoriDownloader;
+    m_downloader->moveToThread(m_thread);
+    connect(this,&SaoriCache::initDownloader,m_downloader,&SaoriDownloader::initialize,Qt::QueuedConnection);
+    connect(this,&SaoriCache::get,m_downloader,&SaoriDownloader::get,Qt::QueuedConnection);
+    connect(m_downloader,&SaoriDownloader::downloaded,this,&SaoriCache::downloadFinished,Qt::QueuedConnection);
+    connect(m_downloader,&SaoriDownloader::error,this,&SaoriCache::networkError,Qt::QueuedConnection);
+    m_thread->start();
+    emit initDownloader();
+}
+
+SaoriCache::~SaoriCache()
+{
+    m_thread->exit();
 }
 
 void SaoriCache::removeFileCache(const QUrl url)
@@ -90,37 +104,7 @@
     m_nowloading.append(url);
     QNetworkRequest request;
     request.setUrl(url);
-    auto *reply = SaoriApplication::saori()->manager->get(request);
-    connect(reply,&QNetworkReply::finished,this,[=](){
-        if (reply->error() == QNetworkReply::NoError) {
-            QFile localfile(urlToFilename(url));
-            if (localfile.exists()) localfile.remove();
-            localfile.open(QIODevice::WriteOnly);
-            localfile.write(reply->readAll());
-            // TODO 100MBのファイルに100MBのメモリを使うのは如何なものか。
-            qint64 size = localfile.size();
-            localfile.close();
-            QSqlQuery query(*SaoriApplication::saori()->database());
-            query.prepare("INSERT INTO file_cache(url,filename,size,timestamp) values(?,?,?,?);");
-            query.addBindValue(url.toString());
-            query.addBindValue(urlToFilename(url));
-            query.addBindValue(size);
-            query.addBindValue(QDateTime::currentSecsSinceEpoch());
-            query.exec();
-            emit downloaded(url);
-        } else {
-            QSqlQuery query(*SaoriApplication::saori()->database());
-            query.prepare("INSERT INTO file_cache(url,filename,size,timestamp) values(?,?,?,?);");
-            query.addBindValue(url.toString());
-            query.addBindValue(":/icons/ionicons-md/md-alert.svg");
-            query.addBindValue("-1");
-            query.addBindValue(QDateTime::currentSecsSinceEpoch());
-            query.exec();
-            emit downloaded(url);
-        }
-        m_nowloading.removeAll(url);
-        reply->deleteLater();
-    });
+    emit get(request);
 }
 
 bool SaoriCache::isCached(const QUrl url)
@@ -143,3 +127,36 @@
     d.mkpath(SaoriApplication::saori()->cacheDirectory().absolutePath() + "/" + dir);
     return QString(SaoriApplication::saori()->cacheDirectory().absolutePath() + "/" + dir + "/" + file);
 }
+
+void SaoriCache::downloadFinished(QNetworkRequest req, QByteArray data)
+{
+    QFile localfile(urlToFilename(req.url()));
+    if (localfile.exists()) localfile.remove();
+    localfile.open(QIODevice::WriteOnly);
+    localfile.write(data);
+    // TODO 100MBのファイルに100MBのメモリを使うのは如何なものか。
+    qint64 size = localfile.size();
+    localfile.close();
+    QSqlQuery query(*SaoriApplication::saori()->database());
+    query.prepare("INSERT INTO file_cache(url,filename,size,timestamp) values(?,?,?,?);");
+    query.addBindValue(req.url().toString());
+    query.addBindValue(urlToFilename(req.url()));
+    query.addBindValue(size);
+    query.addBindValue(QDateTime::currentSecsSinceEpoch());
+    query.exec();
+    emit downloaded(req.url());
+    m_nowloading.removeAll(req.url());
+}
+
+void SaoriCache::networkError(QNetworkRequest req, QNetworkReply::NetworkError error)
+{
+    if (error == QNetworkReply::NoError) return;
+    QSqlQuery query(*SaoriApplication::saori()->database());
+    query.prepare("INSERT INTO file_cache(url,filename,size,timestamp) values(?,?,?,?);");
+    query.addBindValue(req.url().toString());
+    query.addBindValue(":/icons/ionicons-md/md-alert.svg");
+    query.addBindValue("-1");
+    query.addBindValue(QDateTime::currentSecsSinceEpoch());
+    query.exec();
+    emit downloaded(req.url());
+}
diff --git a/saoricache.h b/saoricache.h
index 834e139..4928c1e 100644
--- a/saoricache.h
+++ b/saoricache.h
@@ -30,18 +30,23 @@
 #include <QObject>
 #include <QUrl>
 #include <QList>
+#include <QThread>
+#include "saoridownloader.h"
 
 class SaoriCache : public QObject
 {
     Q_OBJECT
 public:
     explicit SaoriCache(QObject *parent = nullptr);
+    ~SaoriCache();
     void removeFileCache(const QUrl url);
     void reloadFileCache(const QUrl url);
     const QString fileCache(const QUrl url);
 
 protected:
     static QList<QUrl> m_nowloading;
+    SaoriDownloader *m_downloader;
+    QThread *m_thread;
 
 protected:
     bool migration();
@@ -50,8 +55,14 @@
     static const QString urlToFilename(QUrl url);
     const QString localfileName(const QUrl url);
 
+protected slots:
+    void downloadFinished(QNetworkRequest req,QByteArray data);
+    void networkError(QNetworkRequest req,QNetworkReply::NetworkError error);
+
 signals:
     void downloaded(const QUrl);
+    void initDownloader();
+    void get(QNetworkRequest);
 
 public slots:
 };
diff --git a/saoridownloader.cpp b/saoridownloader.cpp
new file mode 100644
index 0000000..9212d6f
--- /dev/null
+++ b/saoridownloader.cpp
@@ -0,0 +1,49 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#include <QThread>
+#include "saoridownloader.h"
+
+SaoriDownloader::SaoriDownloader(QObject *parent) : QObject(parent)
+{
+
+}
+
+void SaoriDownloader::initialize()
+{
+    m_manager = new QNetworkAccessManager(this);
+}
+
+void SaoriDownloader::get(QNetworkRequest req)
+{
+    auto reply = m_manager->get(req);
+    connect(reply,&QNetworkReply::finished,[=](){
+        emit error(req,reply->error());
+        if (reply->error() == QNetworkReply::NoError) {
+            emit downloaded(req,reply->readAll());
+        }
+    });
+}
diff --git a/saoridownloader.h b/saoridownloader.h
new file mode 100644
index 0000000..d09b878
--- /dev/null
+++ b/saoridownloader.h
@@ -0,0 +1,53 @@
+/***
+
+The MIT License
+
+Copyright (c) 2018 Teppei Tamra (TAM)
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+***/
+
+#ifndef SAORIDOWNLOADER_H
+#define SAORIDOWNLOADER_H
+
+#include <QObject>
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+
+class SaoriDownloader : public QObject
+{
+    Q_OBJECT
+public:
+    explicit SaoriDownloader(QObject *parent = nullptr);
+
+protected:
+    QNetworkAccessManager *m_manager;
+
+signals:
+    void downloaded(QNetworkRequest,QByteArray);
+    void error(QNetworkRequest,QNetworkReply::NetworkError);
+
+public slots:
+    void initialize();
+    void get(QNetworkRequest req);
+};
+
+#endif // SAORIDOWNLOADER_H