diff --git a/android/app/src/main/java/com/rajarsheechatterjee/FileManager/FileManager.kt b/android/app/src/main/java/com/rajarsheechatterjee/FileManager/FileManager.kt
index b24c32e77..a4af0262a 100644
--- a/android/app/src/main/java/com/rajarsheechatterjee/FileManager/FileManager.kt
+++ b/android/app/src/main/java/com/rajarsheechatterjee/FileManager/FileManager.kt
@@ -6,22 +6,36 @@ import android.net.Uri
 import android.os.Build
 import android.os.Environment
 import android.provider.DocumentsContract
-import android.util.Base64
 import com.facebook.react.bridge.BaseActivityEventListener
 import com.facebook.react.bridge.Promise
 import com.facebook.react.bridge.ReactApplicationContext
 import com.facebook.react.bridge.ReactContextBaseJavaModule
 import com.facebook.react.bridge.ReactMethod
+import com.facebook.react.bridge.ReadableMap
 import com.facebook.react.bridge.WritableArray
 import com.facebook.react.bridge.WritableMap
 import com.facebook.react.bridge.WritableNativeArray
 import com.facebook.react.bridge.WritableNativeMap
-import kotlinx.coroutines.MainScope
+import com.facebook.react.modules.network.CookieJarContainer
+import com.facebook.react.modules.network.ForwardingCookieHandler
+import com.facebook.react.modules.network.OkHttpClientProvider
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.launch
+import okhttp3.Call
+import okhttp3.Callback
+import okhttp3.Headers
+import okhttp3.JavaNetCookieJar
+import okhttp3.Request
+import okhttp3.RequestBody.Companion.toRequestBody
+import okhttp3.Response
+import okio.buffer
+import okio.sink
 import java.io.BufferedReader
 import java.io.File
 import java.io.FileReader
 import java.io.FileWriter
+import java.io.IOException
 import java.io.InputStream
 import java.io.OutputStream
 
@@ -31,8 +45,9 @@ class FileManager(context: ReactApplicationContext) :
         return "FileManager"
     }
 
+    private val okHttpClient = OkHttpClientProvider.createClient()
     private var _promise: Promise? = null
-    private val coroutineScope = MainScope()
+    private val coroutineScope = CoroutineScope(Dispatchers.IO)
     private val activityEventListener = object : BaseActivityEventListener() {
         override fun onActivityResult(
             activity: Activity?,
@@ -60,6 +75,9 @@ class FileManager(context: ReactApplicationContext) :
 
     init {
         context.addActivityEventListener(activityEventListener)
+        val cookieContainer = okHttpClient.cookieJar as CookieJarContainer
+        val cookieHandler = ForwardingCookieHandler(reactApplicationContext)
+        cookieContainer.setCookieJar(JavaNetCookieJar(cookieHandler))
     }
 
     private fun getFileUri(filepath: String): Uri {
@@ -91,18 +109,11 @@ class FileManager(context: ReactApplicationContext) :
     }
 
     @ReactMethod
-    fun writeFile(path: String, content: String, encoding: String?, promise: Promise) {
+    fun writeFile(path: String, content: String, promise: Promise) {
         try {
-            if (encoding == null || encoding == "utf8") {
-                val fw = FileWriter(path)
-                fw.write(content)
-                fw.close()
-            } else {
-                val bytes = Base64.decode(content, Base64.DEFAULT)
-                val os = getOutputStream(path)
-                os.write(bytes)
-                os.close()
-            }
+            val fw = FileWriter(path)
+            fw.write(content)
+            fw.close()
             promise.resolve(null)
         } catch (e: Exception) {
             promise.reject(e)
@@ -147,7 +158,7 @@ class FileManager(context: ReactApplicationContext) :
         onDone: (() -> Unit)? = null,
         promise: Promise? = null
     ) {
-        coroutineScope.launch {
+        coroutineScope.launch(Dispatchers.IO) {
             val inputStream = getInputStream(filepath)
             val outputStream = getOutputStream(destPath)
             val buffer = ByteArray(1024)
@@ -179,7 +190,7 @@ class FileManager(context: ReactApplicationContext) :
     fun mkdir(filepath: String, promise: Promise) {
         try {
             val file = File(filepath)
-            if(!file.exists()){
+            if (!file.exists()) {
                 val created = file.mkdirs()
                 if (!created) throw Exception("Directory could not be created")
             }
@@ -271,6 +282,53 @@ class FileManager(context: ReactApplicationContext) :
         currentActivity?.startActivityForResult(intent, FOLDER_PICKER_REQUEST)
     }
 
+    @ReactMethod
+    fun downloadFile(
+        url: String,
+        destPath: String,
+        method: String,
+        headers: ReadableMap,
+        body: String?,
+        promise: Promise
+    ) {
+        coroutineScope.launch {
+            try {
+                val headersBuilder = Headers.Builder()
+                headers.entryIterator.forEach { entry ->
+                    headersBuilder.add(entry.key, entry.value.toString())
+                }
+                val requestBuilder = Request.Builder()
+                    .url(url)
+                    .headers(headersBuilder.build())
+                if (method.lowercase() == "get") {
+                    requestBuilder.get()
+                } else if (body != null) {
+                    requestBuilder.post(body.toRequestBody())
+                }
+
+                okHttpClient.newCall(requestBuilder.build())
+                    .enqueue(object : Callback {
+                        override fun onFailure(call: Call, e: IOException) {
+                            promise.reject(e)
+                        }
+
+                        override fun onResponse(call: Call, response: Response) {
+                            if (!response.isSuccessful || response.body == null) {
+                                promise.reject(Exception("Failed to download load: ${response.code}"))
+                                return
+                            }
+                            val sink = File(destPath).sink().buffer()
+                            response.body!!.source().readAll(sink)
+                            sink.close()
+                            promise.resolve(null)
+                        }
+                    })
+            } catch (e: Exception) {
+                promise.reject(e)
+            }
+        }
+    }
+
     companion object {
         const val FOLDER_PICKER_REQUEST = 1
     }
diff --git a/src/database/queries/ChapterQueries.ts b/src/database/queries/ChapterQueries.ts
index 2c701755e..0296c9d29 100644
--- a/src/database/queries/ChapterQueries.ts
+++ b/src/database/queries/ChapterQueries.ts
@@ -12,6 +12,7 @@ import { noop } from 'lodash-es';
 import { getString } from '@strings/translations';
 import FileManager from '@native/FileManager';
 import { NOVEL_STORAGE } from '@utils/Storages';
+import { downloadFile } from '@plugins/helpers/fetch';
 
 const db = SQLite.openDatabase('lnreader.db');
 const insertChapterQuery = `
@@ -260,13 +261,12 @@ const downloadFiles = async (
       const elem = loadedCheerio(imgs[i]);
       const url = elem.attr('src');
       if (url) {
-        const imageb64 = await plugin.fetchImage(url);
         const fileurl = folder + i + '.b64.png';
         elem.attr('src', `file://${fileurl}`);
-        FileManager.writeFile(fileurl, imageb64, 'base64');
+        await downloadFile(url, fileurl, plugin.imageRequestInit);
       }
     }
-    FileManager.writeFile(folder + 'index.html', loadedCheerio.html());
+    await FileManager.writeFile(folder + 'index.html', loadedCheerio.html());
   } catch (error) {
     throw error;
   }
diff --git a/src/database/queries/NovelQueries.ts b/src/database/queries/NovelQueries.ts
index 00dbda8cd..986167c9b 100644
--- a/src/database/queries/NovelQueries.ts
+++ b/src/database/queries/NovelQueries.ts
@@ -3,7 +3,7 @@ const db = SQLite.openDatabase('lnreader.db');
 
 import * as DocumentPicker from 'expo-document-picker';
 
-import { fetchImage, fetchNovel } from '@services/plugin/fetch';
+import { fetchNovel } from '@services/plugin/fetch';
 import { insertChapters } from './ChapterQueries';
 
 import { showToast } from '@utils/showToast';
@@ -14,6 +14,8 @@ import { BackupNovel, NovelInfo } from '../types';
 import { SourceNovel } from '@plugins/types';
 import { NOVEL_STORAGE } from '@utils/Storages';
 import FileManager from '@native/FileManager';
+import { downloadFile } from '@plugins/helpers/fetch';
+import { getPlugin } from '@plugins/pluginManager';
 
 export const insertNovelAndChapters = async (
   pluginId: string,
@@ -43,27 +45,25 @@ export const insertNovelAndChapters = async (
     });
   });
   if (novelId) {
-    const promises = [insertChapters(novelId, sourceNovel.chapters)];
     if (sourceNovel.cover) {
       const novelDir = NOVEL_STORAGE + '/' + pluginId + '/' + novelId;
       await FileManager.mkdir(novelDir);
-      const novelCoverUri = 'file://' + novelDir + '/cover.png';
-      promises.push(
-        fetchImage(pluginId, sourceNovel.cover).then(base64 => {
-          if (base64) {
-            FileManager.writeFile(novelCoverUri, base64, 'base64').then(() => {
-              db.transaction(tx => {
-                tx.executeSql('UPDATE Novel SET cover = ? WHERE id = ?', [
-                  novelCoverUri,
-                  novelId,
-                ]);
-              });
-            });
-          }
-        }),
-      );
+      const novelCoverPath = novelDir + '/cover.png';
+      const novelCoverUri = 'file://' + novelCoverPath;
+      downloadFile(
+        sourceNovel.cover,
+        novelCoverPath,
+        getPlugin(pluginId)?.imageRequestInit,
+      ).then(() => {
+        db.transaction(tx => {
+          tx.executeSql('UPDATE Novel SET cover = ? WHERE id = ?', [
+            novelCoverUri,
+            novelId,
+          ]);
+        });
+      });
     }
-    await Promise.all(promises);
+    await insertChapters(novelId, sourceNovel.chapters);
   }
   return novelId;
 };
diff --git a/src/native/FileManager.ts b/src/native/FileManager.ts
index 01dbeed9d..262b1de17 100644
--- a/src/native/FileManager.ts
+++ b/src/native/FileManager.ts
@@ -7,11 +7,7 @@ interface ReadDirResult {
 }
 
 interface FileManagerInterface {
-  writeFile: (
-    path: string,
-    content: string,
-    encoding?: 'utf8' | 'base64',
-  ) => Promise<void>;
+  writeFile: (path: string, content: string) => Promise<void>;
   readFile: (path: string) => Promise<string>;
   resolveExternalContentUri: (uriString: string) => Promise<string | null>;
   copyFile: (sourcePath: string, destPath: string) => Promise<void>;
@@ -21,17 +17,17 @@ interface FileManagerInterface {
   unlink: (filePath: string) => Promise<void>; // remove recursively
   readDir: (dirPath: string) => Promise<ReadDirResult[]>; // file/sub-folder names
   pickFolder: () => Promise<string | null>; // return path of folderc
+  downloadFile: (
+    url: string,
+    destPath: string,
+    method: string,
+    headers: Record<string, string> | Headers,
+    body?: string,
+  ) => Promise<void>;
   ExternalDirectoryPath: string;
   ExternalCachesDirectoryPath: string;
 }
 
 const { FileManager } = NativeModules;
 
-const _FileManager = {
-  ...FileManager,
-  writeFile: (path: string, destPath: string, encoding?: 'utf8' | 'base64') => {
-    return FileManager.writeFile(path, destPath, encoding || null);
-  },
-};
-
-export default _FileManager as FileManagerInterface;
+export default FileManager as FileManagerInterface;
diff --git a/src/plugins/helpers/fetch.ts b/src/plugins/helpers/fetch.ts
index fd23491c9..89f896921 100644
--- a/src/plugins/helpers/fetch.ts
+++ b/src/plugins/helpers/fetch.ts
@@ -1,4 +1,5 @@
 import { getUserAgent } from '@hooks/persisted/useUserAgent';
+import FileManager from '@native/FileManager';
 import { parse as parseProto } from 'protobufjs';
 
 type FetchInit = {
@@ -80,6 +81,21 @@ export const fetchFile = async (
   }
 };
 
+export const downloadFile = async (
+  url: string,
+  destPath: string,
+  init?: FetchInit,
+): Promise<void> => {
+  init = makeInit(init);
+  return FileManager.downloadFile(
+    url,
+    destPath,
+    init.method || 'get',
+    init.headers as Record<string, string>,
+    init.body?.toString(),
+  );
+};
+
 /**
  *
  * @param url
diff --git a/src/plugins/pluginManager.ts b/src/plugins/pluginManager.ts
index a51fd68c2..d01fded8b 100644
--- a/src/plugins/pluginManager.ts
+++ b/src/plugins/pluginManager.ts
@@ -9,7 +9,7 @@ import qs from 'qs';
 import { NovelStatus, Plugin, PluginItem } from './types';
 import { FilterTypes } from './types/filterTypes';
 import { isUrlAbsolute } from './helpers/isAbsoluteUrl';
-import { fetchApi, fetchFile, fetchProto, fetchText } from './helpers/fetch';
+import { fetchApi, fetchProto, fetchText } from './helpers/fetch';
 import { defaultCover } from './helpers/constants';
 import { Storage, LocalStorage, SessionStorage } from './helpers/storage';
 import { encode, decode } from 'urlencode';
@@ -28,7 +28,7 @@ const packages: Record<string, any> = {
   'qs': qs,
   'urlencode': { encode, decode },
   '@libs/novelStatus': { NovelStatus },
-  '@libs/fetch': { fetchApi, fetchFile, fetchText, fetchProto },
+  '@libs/fetch': { fetchApi, fetchText, fetchProto },
   '@libs/isAbsoluteUrl': { isUrlAbsolute },
   '@libs/filterInputs': { FilterTypes },
   '@libs/defaultCover': { defaultCover },
diff --git a/src/plugins/types/index.ts b/src/plugins/types/index.ts
index 64777b63c..8c0119259 100644
--- a/src/plugins/types/index.ts
+++ b/src/plugins/types/index.ts
@@ -55,7 +55,15 @@ export interface PluginItem {
   hasUpdate?: boolean;
 }
 
+export interface ImageRequestInit {
+  [x: string]: string | Record<string, string> | Headers | FormData | undefined;
+  method?: string;
+  headers?: Record<string, string>;
+  body?: string;
+}
+
 export interface Plugin extends PluginItem {
+  imageRequestInit?: ImageRequestInit;
   filters?: Filters;
   popularNovels: (
     pageNo: number,
@@ -65,7 +73,6 @@ export interface Plugin extends PluginItem {
   parsePage?: (novelPath: string, page: string) => Promise<SourcePage>;
   parseChapter: (chapterPath: string) => Promise<string>;
   searchNovels: (searchTerm: string, pageNo: number) => Promise<NovelItem[]>;
-  fetchImage: (url: string) => Promise<string>;
   resolveUrl?: (path: string, isNovel?: boolean) => string;
   webStorageUtilized?: boolean;
 }
diff --git a/src/screens/reader/components/WebViewReader.tsx b/src/screens/reader/components/WebViewReader.tsx
index c6ee4746d..1bef2c5b5 100644
--- a/src/screens/reader/components/WebViewReader.tsx
+++ b/src/screens/reader/components/WebViewReader.tsx
@@ -26,6 +26,7 @@ import { getBatteryLevelSync } from 'react-native-device-info';
 import * as Speech from 'expo-speech';
 import * as Clipboard from 'expo-clipboard';
 import { showToast } from '@utils/showToast';
+import { fetchFile } from '@plugins/helpers/fetch';
 
 type WebViewPostEvent = {
   type: string;
@@ -150,7 +151,11 @@ const WebViewReader: FC<WebViewReaderProps> = props => {
             break;
           case 'error-img':
             if (event.data && typeof event.data === 'string') {
-              plugin?.fetchImage(event.data).then(base64 => {
+              fetchFile(event.data, {
+                method: plugin?.imageRequestInit?.method,
+                headers: plugin?.imageRequestInit?.headers,
+                body: plugin?.imageRequestInit?.body,
+              }).then(base64 => {
                 webViewRef.current?.injectJavaScript(
                   `document.querySelector("img[error-src='${event.data}']").src="data:image/jpg;base64,${base64}"`,
                 );
diff --git a/src/services/plugin/fetch.ts b/src/services/plugin/fetch.ts
index 1cbc1eac2..c991b450d 100644
--- a/src/services/plugin/fetch.ts
+++ b/src/services/plugin/fetch.ts
@@ -10,14 +10,6 @@ export const fetchNovel = async (pluginId: string, novelPath: string) => {
   return res;
 };
 
-export const fetchImage = async (pluginId: string, imageUrl: string) => {
-  const plugin = getPlugin(pluginId);
-  if (!plugin) {
-    throw new Error(`Unknown plugin: ${pluginId}`);
-  }
-  return plugin.fetchImage(imageUrl);
-};
-
 export const fetchChapter = async (pluginId: string, chapterPath: string) => {
   const plugin = getPlugin(pluginId);
   let chapterText = `Unkown plugin: ${pluginId}`;
diff --git a/src/services/updates/LibraryUpdateQueries.ts b/src/services/updates/LibraryUpdateQueries.ts
index e4a3d138b..14f9ae50b 100644
--- a/src/services/updates/LibraryUpdateQueries.ts
+++ b/src/services/updates/LibraryUpdateQueries.ts
@@ -1,11 +1,12 @@
-import { fetchImage, fetchNovel, fetchPage } from '../plugin/fetch';
+import { fetchNovel, fetchPage } from '../plugin/fetch';
 import { downloadChapter } from '../../database/queries/ChapterQueries';
 
 import * as SQLite from 'expo-sqlite';
 import { ChapterItem, SourceNovel } from '@plugins/types';
-import { LOCAL_PLUGIN_ID } from '@plugins/pluginManager';
+import { getPlugin, LOCAL_PLUGIN_ID } from '@plugins/pluginManager';
 import FileManager from '@native/FileManager';
 import { NOVEL_STORAGE } from '@utils/Storages';
+import { downloadFile } from '@plugins/helpers/fetch';
 const db = SQLite.openDatabase('lnreader.db');
 
 const updateNovelMetadata = (
@@ -21,16 +22,14 @@ const updateNovelMetadata = (
       await FileManager.mkdir(novelDir);
     }
     if (cover) {
-      const novelCoverUri = 'file://' + novelDir + '/cover.png';
-      await fetchImage(pluginId, cover)
-        .then(base64 => {
-          if (base64) {
-            cover = novelCoverUri;
-            return FileManager.writeFile(novelCoverUri, base64, 'base64');
-          }
-        })
-        .catch(reject);
-      cover += '?' + Date.now();
+      const novelCoverPath = novelDir + '/cover.png';
+      const novelCoverUri = 'file://' + novelCoverPath;
+      await downloadFile(
+        cover,
+        novelCoverPath,
+        getPlugin(pluginId)?.imageRequestInit,
+      );
+      cover = novelCoverUri + '?' + Date.now();
     }
     db.transaction(tx => {
       tx.executeSql(