From 8955853a684d20c993398c30f6e498831eaee395 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?=E5=B0=B9=E8=88=9F?= <Yz1314520>
Date: Sun, 16 Mar 2025 14:26:18 +0800
Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A42?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 m3u8_download.py                              |   6 +-
 {m3u8_To_MP4 => m3u8_to_mp4}/__init__.py      |  38 +++---
 .../async_processor.py                        |  10 +-
 .../helpers/__init__.py                       |   0
 .../helpers/os_helper.py                      |   0
 .../helpers/path_helper.py                    |   2 +-
 .../helpers/printer_helper.py                 |   0
 .../multithreads_processor.py                 |   6 +-
 .../networks/__init__.py                      |   0
 .../networks/asynchronous/__init__.py         |   0
 .../networks/asynchronous/async_DNS.py        |   2 +-
 .../networks/asynchronous/async_http.py       |   4 +-
 .../asynchronous/async_producer_consumer.py   |   8 +-
 .../networks/http_base.py                     |   0
 .../networks/synchronous/__init__.py          |   0
 .../networks/synchronous/sync_DNS.py          |   2 +-
 .../networks/synchronous/sync_http.py         |   4 +-
 .../synchronous/sync_http_requester.py        |   0
 .../v2_abstract_crawler_processor.py          |  10 +-
 .../v2_abstract_task_processor.py             |   4 +-
 .../v2_async_processor.py                     |   4 +-
 .../v2_multithreads_processor.py              |   8 +-
 utils/{log.py => Log.py}                      |   0
 utils/SQLiteDB.py                             | 125 ++++++++++++++++++
 24 files changed, 179 insertions(+), 54 deletions(-)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/__init__.py (84%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/async_processor.py (97%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/helpers/__init__.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/helpers/os_helper.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/helpers/path_helper.py (96%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/helpers/printer_helper.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/multithreads_processor.py (98%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/__init__.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/asynchronous/__init__.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/asynchronous/async_DNS.py (92%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/asynchronous/async_http.py (98%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/asynchronous/async_producer_consumer.py (96%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/http_base.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/synchronous/__init__.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/synchronous/sync_DNS.py (94%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/synchronous/sync_http.py (96%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/networks/synchronous/sync_http_requester.py (100%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/v2_abstract_crawler_processor.py (97%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/v2_abstract_task_processor.py (98%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/v2_async_processor.py (90%)
 rename {m3u8_To_MP4 => m3u8_to_mp4}/v2_multithreads_processor.py (96%)
 rename utils/{log.py => Log.py} (100%)
 create mode 100644 utils/SQLiteDB.py

diff --git a/m3u8_download.py b/m3u8_download.py
index bc20aa9..2d278e1 100644
--- a/m3u8_download.py
+++ b/m3u8_download.py
@@ -1,8 +1,8 @@
-import m3u8_To_MP4
+import m3u8_to_mp4
 from utils.MySqlUtil import MySqlUtil
 from apscheduler.schedulers.blocking import BlockingScheduler
 import time
-from utils.log import Log
+from utils.Log import Log
 from pathlib import Path
 
 
@@ -30,7 +30,7 @@ def download_m3u8(download_path='./mp4/'):
         log.info(f"任务下载中,正在下载 {name}...")
 
         # 下载 m3u8 文件并转换为 MP4
-        m3u8_To_MP4.multithread_download(url, file_path=str(file_path))
+        m3u8_to_mp4.multithread_download(url, file_path=str(file_path))
         log.info(f"成功下载并转换 {name} to {file_path}.")
 
     except Exception as e:
diff --git a/m3u8_To_MP4/__init__.py b/m3u8_to_mp4/__init__.py
similarity index 84%
rename from m3u8_To_MP4/__init__.py
rename to m3u8_to_mp4/__init__.py
index 26f9d0d..3bebd12 100644
--- a/m3u8_To_MP4/__init__.py
+++ b/m3u8_to_mp4/__init__.py
@@ -15,7 +15,7 @@ m3u8_to_mp4.download("https://xxx.com/xxx/index.m3u8")
 import logging
 import subprocess
 
-from m3u8_To_MP4.helpers import printer_helper
+from m3u8_to_mp4.helpers import printer_helper
 
 printer_helper.config_logging()
 
@@ -34,11 +34,11 @@ def verify_ffmpey():
 
 
 # define API
-import m3u8_To_MP4.multithreads_processor
-from m3u8_To_MP4.v2_async_processor import AsynchronousFileCrawler
-from m3u8_To_MP4.v2_async_processor import AsynchronousUriCrawler
-from m3u8_To_MP4.v2_multithreads_processor import MultiThreadsFileCrawler
-from m3u8_To_MP4.v2_multithreads_processor import MultiThreadsUriCrawler
+import m3u8_to_mp4.multithreads_processor
+from m3u8_to_mp4.v2_async_processor import AsynchronousFileCrawler
+from m3u8_to_mp4.v2_async_processor import AsynchronousUriCrawler
+from m3u8_to_mp4.v2_multithreads_processor import MultiThreadsFileCrawler
+from m3u8_to_mp4.v2_multithreads_processor import MultiThreadsUriCrawler
 
 __all__ = (
     "MultiThreadsFileCrawler",
@@ -56,7 +56,7 @@ __all__ = (
 
 
 # ================ Async ===================
-def async_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customized_http_header=None, max_retry_times=3,
+def async_download(m3u8_uri, file_path='./m3u8_to_mp4.ts', customized_http_header=None, max_retry_times=3,
                    num_concurrent=50, tmpdir=None):
     '''
     Download mp4 video from given m3u uri.
@@ -69,7 +69,7 @@ def async_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customized_http_heade
     :return:
     '''
 
-    with m3u8_To_MP4.v2_async_processor.AsynchronousUriCrawler(m3u8_uri,
+    with m3u8_to_mp4.v2_async_processor.AsynchronousUriCrawler(m3u8_uri,
                                                                file_path,
                                                                customized_http_header,
                                                                max_retry_times,
@@ -78,9 +78,9 @@ def async_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customized_http_heade
         crawler.fetch_mp4_by_m3u8_uri('ts')
 
 
-def async_uri_download(m3u8_uri, file_path='./m3u8_To_MP4.mp4', customized_http_header=None,
+def async_uri_download(m3u8_uri, file_path='./m3u8_to_mp4.mp4', customized_http_header=None,
                        max_retry_times=3, num_concurrent=50, tmpdir=None):
-    with m3u8_To_MP4.v2_async_processor.AsynchronousUriCrawler(m3u8_uri,
+    with m3u8_to_mp4.v2_async_processor.AsynchronousUriCrawler(m3u8_uri,
                                                                file_path,
                                                                customized_http_header,
                                                                max_retry_times,
@@ -89,9 +89,9 @@ def async_uri_download(m3u8_uri, file_path='./m3u8_To_MP4.mp4', customized_http_
         crawler.fetch_mp4_by_m3u8_uri('ts')
 
 
-def async_file_download(m3u8_uri, m3u8_file_path, file_path='./m3u8_To_MP4.ts', customized_http_header=None,
+def async_file_download(m3u8_uri, m3u8_file_path, file_path='./m3u8_to_mp4.ts', customized_http_header=None,
                         max_retry_times=3, num_concurrent=50, tmpdir=None):
-    with m3u8_To_MP4.v2_async_processor.AsynchronousFileCrawler(m3u8_uri,
+    with m3u8_to_mp4.v2_async_processor.AsynchronousFileCrawler(m3u8_uri,
                                                                 m3u8_file_path,
                                                                 file_path,
                                                                 customized_http_header,
@@ -102,7 +102,7 @@ def async_file_download(m3u8_uri, m3u8_file_path, file_path='./m3u8_To_MP4.ts',
 
 
 # ================ MultiThread ===================
-def multithread_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customized_http_header=None,
+def multithread_download(m3u8_uri, file_path='./m3u8_to_mp4.ts', customized_http_header=None,
                          max_retry_times=3, max_num_workers=100, tmpdir=None):
     '''
     Download mp4 video from given m3u uri.
@@ -114,7 +114,7 @@ def multithread_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customized_http
     :param mp4_file_name: a mp4 file name with suffix ".mp4"
     :return:
     '''
-    with m3u8_To_MP4.v2_multithreads_processor.MultiThreadsUriCrawler(m3u8_uri,
+    with m3u8_to_mp4.v2_multithreads_processor.MultiThreadsUriCrawler(m3u8_uri,
                                                                       file_path,
                                                                       customized_http_header,
                                                                       max_retry_times,
@@ -123,9 +123,9 @@ def multithread_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customized_http
         crawler.fetch_mp4_by_m3u8_uri('ts')
 
 
-def multithread_uri_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customied_http_header=None,
+def multithread_uri_download(m3u8_uri, file_path='./m3u8_to_mp4.ts', customied_http_header=None,
                              max_retry_times=3, max_num_workers=100, tmpdir=None):
-    with m3u8_To_MP4.v2_multithreads_processor.MultiThreadsUriCrawler(m3u8_uri,
+    with m3u8_to_mp4.v2_multithreads_processor.MultiThreadsUriCrawler(m3u8_uri,
                                                                       file_path,
                                                                       customied_http_header,
                                                                       max_retry_times,
@@ -137,7 +137,7 @@ def multithread_uri_download(m3u8_uri, file_path='./m3u8_To_MP4.ts', customied_h
 def multithread_file_download(m3u8_uri, m3u8_file_path, file_path,
                               customized_http_header=None, max_retry_times=3,
                               max_num_workers=100, tmpdir=None):
-    with m3u8_To_MP4.v2_multithreads_processor.MultiThreadsFileCrawler(
+    with m3u8_to_mp4.v2_multithreads_processor.MultiThreadsFileCrawler(
             m3u8_uri, m3u8_file_path, file_path, customized_http_header, max_retry_times,
             max_num_workers, tmpdir) as crawler:
         crawler.fetch_mp4_by_m3u8_uri(True)
@@ -148,7 +148,7 @@ import warnings
 
 
 def download(m3u8_uri, max_retry_times=3, max_num_workers=100,
-             mp4_file_dir='./', mp4_file_name='m3u8_To_MP4', tmpdir=None):
+             mp4_file_dir='./', mp4_file_name='m3u8_to_mp4', tmpdir=None):
     '''
     Download mp4 video from given m3u uri.
 
@@ -163,7 +163,7 @@ def download(m3u8_uri, max_retry_times=3, max_num_workers=100,
             'download function is deprecated, and please use multithread_download.',
             DeprecationWarning)
 
-    with m3u8_To_MP4.multithreads_processor.Crawler(m3u8_uri, max_retry_times,
+    with m3u8_to_mp4.multithreads_processor.Crawler(m3u8_uri, max_retry_times,
                                                     max_num_workers,
                                                     mp4_file_dir,
                                                     mp4_file_name,
diff --git a/m3u8_To_MP4/async_processor.py b/m3u8_to_mp4/async_processor.py
similarity index 97%
rename from m3u8_To_MP4/async_processor.py
rename to m3u8_to_mp4/async_processor.py
index bb45f6e..badae84 100644
--- a/m3u8_To_MP4/async_processor.py
+++ b/m3u8_to_mp4/async_processor.py
@@ -11,11 +11,11 @@ import zlib
 
 import m3u8
 
-from m3u8_To_MP4.helpers import path_helper
-from m3u8_To_MP4.helpers import printer_helper
-from m3u8_To_MP4.networks.asynchronous import async_producer_consumer
-from m3u8_To_MP4.networks.synchronous import sync_DNS
-from m3u8_To_MP4.networks.synchronous import sync_http
+from m3u8_to_mp4.helpers import path_helper
+from m3u8_to_mp4.helpers import printer_helper
+from m3u8_to_mp4.networks.asynchronous import async_producer_consumer
+from m3u8_to_mp4.networks.synchronous import sync_DNS
+from m3u8_to_mp4.networks.synchronous import sync_http
 
 printer_helper.config_logging()
 
diff --git a/m3u8_To_MP4/helpers/__init__.py b/m3u8_to_mp4/helpers/__init__.py
similarity index 100%
rename from m3u8_To_MP4/helpers/__init__.py
rename to m3u8_to_mp4/helpers/__init__.py
diff --git a/m3u8_To_MP4/helpers/os_helper.py b/m3u8_to_mp4/helpers/os_helper.py
similarity index 100%
rename from m3u8_To_MP4/helpers/os_helper.py
rename to m3u8_to_mp4/helpers/os_helper.py
diff --git a/m3u8_To_MP4/helpers/path_helper.py b/m3u8_to_mp4/helpers/path_helper.py
similarity index 96%
rename from m3u8_To_MP4/helpers/path_helper.py
rename to m3u8_to_mp4/helpers/path_helper.py
index 69eb81d..101e793 100644
--- a/m3u8_To_MP4/helpers/path_helper.py
+++ b/m3u8_to_mp4/helpers/path_helper.py
@@ -32,7 +32,7 @@ def random_5_char():
 
 def random_name():
     dt_str = datetime.datetime.now().strftime('%Y-%m-%d %H-%M-%S')
-    return 'm3u8_To_MP4' + dt_str + random_5_char()+'.mp4'
+    return 'm3u8_to_mp4' + dt_str + random_5_char()+'.mp4'
 
 
 def calibrate_name(name):
diff --git a/m3u8_To_MP4/helpers/printer_helper.py b/m3u8_to_mp4/helpers/printer_helper.py
similarity index 100%
rename from m3u8_To_MP4/helpers/printer_helper.py
rename to m3u8_to_mp4/helpers/printer_helper.py
diff --git a/m3u8_To_MP4/multithreads_processor.py b/m3u8_to_mp4/multithreads_processor.py
similarity index 98%
rename from m3u8_To_MP4/multithreads_processor.py
rename to m3u8_to_mp4/multithreads_processor.py
index 9a2c10b..e2502d2 100644
--- a/m3u8_To_MP4/multithreads_processor.py
+++ b/m3u8_to_mp4/multithreads_processor.py
@@ -12,9 +12,9 @@ import time
 import m3u8
 from Crypto.Cipher import AES
 
-from m3u8_To_MP4.helpers import path_helper
-from m3u8_To_MP4.helpers import printer_helper
-from m3u8_To_MP4.networks.synchronous.sync_http_requester import request_for
+from m3u8_to_mp4.helpers import path_helper
+from m3u8_to_mp4.helpers import printer_helper
+from m3u8_to_mp4.networks.synchronous.sync_http_requester import request_for
 
 printer_helper.config_logging()
 
diff --git a/m3u8_To_MP4/networks/__init__.py b/m3u8_to_mp4/networks/__init__.py
similarity index 100%
rename from m3u8_To_MP4/networks/__init__.py
rename to m3u8_to_mp4/networks/__init__.py
diff --git a/m3u8_To_MP4/networks/asynchronous/__init__.py b/m3u8_to_mp4/networks/asynchronous/__init__.py
similarity index 100%
rename from m3u8_To_MP4/networks/asynchronous/__init__.py
rename to m3u8_to_mp4/networks/asynchronous/__init__.py
diff --git a/m3u8_To_MP4/networks/asynchronous/async_DNS.py b/m3u8_to_mp4/networks/asynchronous/async_DNS.py
similarity index 92%
rename from m3u8_To_MP4/networks/asynchronous/async_DNS.py
rename to m3u8_to_mp4/networks/asynchronous/async_DNS.py
index fe560d1..d64e521 100644
--- a/m3u8_To_MP4/networks/asynchronous/async_DNS.py
+++ b/m3u8_to_mp4/networks/asynchronous/async_DNS.py
@@ -3,7 +3,7 @@ import asyncio
 import socket
 import urllib.parse
 
-from m3u8_To_MP4.networks.http_base import AddressInfo
+from m3u8_to_mp4.networks.http_base import AddressInfo
 
 
 async def available_addr_infos_of_url(url):
diff --git a/m3u8_To_MP4/networks/asynchronous/async_http.py b/m3u8_to_mp4/networks/asynchronous/async_http.py
similarity index 98%
rename from m3u8_To_MP4/networks/asynchronous/async_http.py
rename to m3u8_to_mp4/networks/asynchronous/async_http.py
index b39903f..f007306 100644
--- a/m3u8_To_MP4/networks/asynchronous/async_http.py
+++ b/m3u8_to_mp4/networks/asynchronous/async_http.py
@@ -6,8 +6,8 @@ import urllib.parse
 import urllib.request
 import urllib.response
 
-from m3u8_To_MP4.helpers import path_helper
-from m3u8_To_MP4.networks import http_base
+from m3u8_to_mp4.helpers import path_helper
+from m3u8_to_mp4.networks import http_base
 
 
 def http_get_header(domain_name, port, resource_path_at_server, is_keep_alive):
diff --git a/m3u8_To_MP4/networks/asynchronous/async_producer_consumer.py b/m3u8_to_mp4/networks/asynchronous/async_producer_consumer.py
similarity index 96%
rename from m3u8_To_MP4/networks/asynchronous/async_producer_consumer.py
rename to m3u8_to_mp4/networks/asynchronous/async_producer_consumer.py
index ba6c725..f97e137 100644
--- a/m3u8_To_MP4/networks/asynchronous/async_producer_consumer.py
+++ b/m3u8_to_mp4/networks/asynchronous/async_producer_consumer.py
@@ -12,10 +12,10 @@ from multiprocessing import JoinableQueue, Process
 
 from Crypto.Cipher import AES
 
-from m3u8_To_MP4.helpers import path_helper
-from m3u8_To_MP4.helpers import printer_helper
-from m3u8_To_MP4.networks import http_base
-from m3u8_To_MP4.networks.asynchronous import async_http
+from m3u8_to_mp4.helpers import path_helper
+from m3u8_to_mp4.helpers import printer_helper
+from m3u8_to_mp4.networks import http_base
+from m3u8_to_mp4.networks.asynchronous import async_http
 
 
 async def ts_request(concurrent_condition, ssl_context, addr_info,
diff --git a/m3u8_To_MP4/networks/http_base.py b/m3u8_to_mp4/networks/http_base.py
similarity index 100%
rename from m3u8_To_MP4/networks/http_base.py
rename to m3u8_to_mp4/networks/http_base.py
diff --git a/m3u8_To_MP4/networks/synchronous/__init__.py b/m3u8_to_mp4/networks/synchronous/__init__.py
similarity index 100%
rename from m3u8_To_MP4/networks/synchronous/__init__.py
rename to m3u8_to_mp4/networks/synchronous/__init__.py
diff --git a/m3u8_To_MP4/networks/synchronous/sync_DNS.py b/m3u8_to_mp4/networks/synchronous/sync_DNS.py
similarity index 94%
rename from m3u8_To_MP4/networks/synchronous/sync_DNS.py
rename to m3u8_to_mp4/networks/synchronous/sync_DNS.py
index fb5a27b..acaa929 100644
--- a/m3u8_To_MP4/networks/synchronous/sync_DNS.py
+++ b/m3u8_to_mp4/networks/synchronous/sync_DNS.py
@@ -3,7 +3,7 @@ import re
 import socket
 import urllib.parse
 
-from m3u8_To_MP4.networks.http_base import AddressInfo
+from m3u8_to_mp4.networks.http_base import AddressInfo
 
 
 def available_addr_infos_of_url(url):
diff --git a/m3u8_To_MP4/networks/synchronous/sync_http.py b/m3u8_to_mp4/networks/synchronous/sync_http.py
similarity index 96%
rename from m3u8_To_MP4/networks/synchronous/sync_http.py
rename to m3u8_to_mp4/networks/synchronous/sync_http.py
index e9f3dd5..80de090 100644
--- a/m3u8_To_MP4/networks/synchronous/sync_http.py
+++ b/m3u8_to_mp4/networks/synchronous/sync_http.py
@@ -4,8 +4,8 @@ import urllib.parse
 import urllib.request
 import urllib.response
 
-from m3u8_To_MP4.helpers import path_helper
-from m3u8_To_MP4.networks import http_base
+from m3u8_to_mp4.helpers import path_helper
+from m3u8_to_mp4.networks import http_base
 
 
 def http_get_header(domain_name, port, resource_path_at_server, is_keep_alive,
diff --git a/m3u8_To_MP4/networks/synchronous/sync_http_requester.py b/m3u8_to_mp4/networks/synchronous/sync_http_requester.py
similarity index 100%
rename from m3u8_To_MP4/networks/synchronous/sync_http_requester.py
rename to m3u8_to_mp4/networks/synchronous/sync_http_requester.py
diff --git a/m3u8_To_MP4/v2_abstract_crawler_processor.py b/m3u8_to_mp4/v2_abstract_crawler_processor.py
similarity index 97%
rename from m3u8_To_MP4/v2_abstract_crawler_processor.py
rename to m3u8_to_mp4/v2_abstract_crawler_processor.py
index 25e8d1c..5f9d372 100644
--- a/m3u8_To_MP4/v2_abstract_crawler_processor.py
+++ b/m3u8_to_mp4/v2_abstract_crawler_processor.py
@@ -9,10 +9,10 @@ import time
 import warnings
 import zlib
 
-from m3u8_To_MP4.helpers import path_helper
-from m3u8_To_MP4.helpers import printer_helper
-from m3u8_To_MP4.helpers.os_helper import get_core_count
-from m3u8_To_MP4.networks.synchronous import sync_DNS
+from m3u8_to_mp4.helpers import path_helper
+from m3u8_to_mp4.helpers import printer_helper
+from m3u8_to_mp4.helpers.os_helper import get_core_count
+from m3u8_to_mp4.networks.synchronous import sync_DNS
 
 printer_helper.config_logging()
 
@@ -20,7 +20,7 @@ printer_helper.config_logging()
 class AbstractCrawler(object):
     def __init__(self,
                  m3u8_uri,
-                 file_path='./m3u8_To_MP4.mp4',
+                 file_path='./m3u8_to_mp4.mp4',
                  customized_http_header=None,
                  max_retry_times=3,
                  num_concurrent=50,
diff --git a/m3u8_To_MP4/v2_abstract_task_processor.py b/m3u8_to_mp4/v2_abstract_task_processor.py
similarity index 98%
rename from m3u8_To_MP4/v2_abstract_task_processor.py
rename to m3u8_to_mp4/v2_abstract_task_processor.py
index 2c18f9b..aec08fb 100644
--- a/m3u8_To_MP4/v2_abstract_task_processor.py
+++ b/m3u8_to_mp4/v2_abstract_task_processor.py
@@ -5,8 +5,8 @@ import os.path
 
 import m3u8
 
-from m3u8_To_MP4.networks.synchronous import sync_http
-from m3u8_To_MP4.v2_abstract_crawler_processor import AbstractCrawler
+from m3u8_to_mp4.networks.synchronous import sync_http
+from m3u8_to_mp4.v2_abstract_crawler_processor import AbstractCrawler
 
 EncryptedKey = collections.namedtuple(typename='EncryptedKey',
                                       field_names=['method', 'value', 'iv'])
diff --git a/m3u8_To_MP4/v2_async_processor.py b/m3u8_to_mp4/v2_async_processor.py
similarity index 90%
rename from m3u8_To_MP4/v2_async_processor.py
rename to m3u8_to_mp4/v2_async_processor.py
index ba94750..7d5306c 100644
--- a/m3u8_To_MP4/v2_async_processor.py
+++ b/m3u8_to_mp4/v2_async_processor.py
@@ -1,6 +1,6 @@
 # -*- coding: utf-8 -*-
-from m3u8_To_MP4 import v2_abstract_task_processor
-from m3u8_To_MP4.networks.asynchronous import async_producer_consumer
+from m3u8_to_mp4 import v2_abstract_task_processor
+from m3u8_to_mp4.networks.asynchronous import async_producer_consumer
 
 
 class AsynchronousFileCrawler(v2_abstract_task_processor.AbstractFileCrawler):
diff --git a/m3u8_To_MP4/v2_multithreads_processor.py b/m3u8_to_mp4/v2_multithreads_processor.py
similarity index 96%
rename from m3u8_To_MP4/v2_multithreads_processor.py
rename to m3u8_to_mp4/v2_multithreads_processor.py
index 9274530..93de83a 100644
--- a/m3u8_To_MP4/v2_multithreads_processor.py
+++ b/m3u8_to_mp4/v2_multithreads_processor.py
@@ -6,10 +6,10 @@ import sys
 
 from Crypto.Cipher import AES
 
-from m3u8_To_MP4 import v2_abstract_task_processor
-from m3u8_To_MP4.helpers import path_helper
-from m3u8_To_MP4.helpers import printer_helper
-from m3u8_To_MP4.networks.synchronous.sync_http_requester import request_for
+from m3u8_to_mp4 import v2_abstract_task_processor
+from m3u8_to_mp4.helpers import path_helper
+from m3u8_to_mp4.helpers import printer_helper
+from m3u8_to_mp4.networks.synchronous.sync_http_requester import request_for
 
 
 def download_segment(segment_url, customized_http_header):
diff --git a/utils/log.py b/utils/Log.py
similarity index 100%
rename from utils/log.py
rename to utils/Log.py
diff --git a/utils/SQLiteDB.py b/utils/SQLiteDB.py
new file mode 100644
index 0000000..f5f8a35
--- /dev/null
+++ b/utils/SQLiteDB.py
@@ -0,0 +1,125 @@
+import sqlite3
+from typing import Optional, List, Tuple, Any
+
+
+class SQLiteDB:
+    def __init__(self, db_path: str = "./sqlite/movies.db"):
+        self.db_path = db_path
+        self.conn: Optional[sqlite3.Connection] = None
+        self.cursor: Optional[sqlite3.Cursor] = None
+        self._init_db()
+
+    def _init_db(self) -> None:
+        """初始化数据库并创建表(基于网页4、网页5、网页7的表结构设计)[4,5,7](@ref)"""
+        create_table_sql = """
+        CREATE TABLE IF NOT EXISTS movie (
+            id INTEGER PRIMARY KEY AUTOINCREMENT,
+            name TEXT NOT NULL,
+            path TEXT NOT NULL,
+            is_download INTEGER DEFAULT 0
+        )
+        """
+        self.connect()
+        if self.cursor:
+            self.cursor.execute(create_table_sql)
+            self.conn.commit()
+
+    def connect(self) -> None:
+        """建立数据库连接(基于网页2、网页5的连接方式)[2,5](@ref)"""
+        try:
+            self.conn = sqlite3.connect(self.db_path)
+            self.cursor = self.ursor.cursor()
+            self.conn.execute("PRAGMA foreign_keys = ON")  # 启用外键约束
+        except sqlite3.Error as e:
+            raise ConnectionError(f"数据库连接失败: {e}")
+
+    def close(self) -> None:
+        """安全关闭连接(参考网页6的资源管理)[6](@ref)"""
+        if self.cursor:
+            self.cursor.close()
+        if self.conn:
+            self.conn.close()
+
+    def execute(
+            self,
+            sql: str,
+            params: Optional[Tuple[Any, ...]] = None,
+            commit: bool = True
+    ) -> int:
+        """
+        执行单条SQL语句(集成网页1、网页7的参数化查询)[1,7](@ref)
+        :param sql: 含占位符的SQL语句
+        :param params: 参数元组(防SQL注入)
+        :param commit: 是否自动提交事务
+        :return: 影响的行数
+        """
+        try:
+            if params:
+                self.cursor.execute(sql, params)
+            else:
+                self.cursor.execute(sql)
+            if commit and self.conn:
+                self.conn.commit()
+            return self.cursor.rowcount
+        except sqlite3.Error as e:
+            if self.conn:
+                self.conn.rollback()
+            raise RuntimeError(f"SQL执行失败: {e}")
+
+    # ---- 高级操作方法 ----
+    def insert_movie(self, name: str, path: str) -> int:
+        """插入电影记录(演示特定业务方法)"""
+        return self.execute(
+            "INSERT INTO movie (name, path) VALUES (?, ?)",
+            (name, path)
+        )
+
+    def mark_downloaded(self, movie_id: int) -> int:
+        """标记电影为已下载(业务逻辑示例)[6](@ref)"""
+        return self.execute(
+            "UPDATE movie SET is_download = 1 WHERE id = ?",
+            (movie_id,)
+        )
+
+    def get_undownloaded(self) -> List[Tuple]:
+        """查询未下载的电影(返回完整记录元组)[4,6](@ref)"""
+        self.execute("SELECT * FROM movie WHERE is_download = 0", commit=False)
+        return self.cursor.fetchall()
+
+    # ---- 上下文管理器支持 ----
+    def __enter__(self):
+        self.connect()
+        return self
+
+    def __exit__(self, exc_type, exc_val, exc_tb):
+        self.close()
+
+
+# ==================== 使用示例 ====================
+if __name__ == "__main__":
+    # 示例1:自动建表并插入数据
+    with SQLiteDB() as db:
+        # 批量插入演示(集成网页5的executemany方法)[5](@ref)
+        movies = [("泰坦尼克号", "/movies/titanic"), ("阿凡达", "/movies/avatar")]
+        db.executemany(
+            "INSERT INTO movie (name, path) VALUES (?, ?)",
+            movies
+        )
+
+        # 查询未下载记录(基于网页6的查询模式)[6](@ref)
+        print("待下载电影:", db.get_undownloaded())
+    #
+    # # 示例2:更新操作
+    # with SQLiteDB() as db:
+    #     db.mark_downloaded(1)
+    #     print("更新后的记录:", db.get_undownloaded())
+    #
+    # # 示例3:事务回滚演示
+    # try:
+    #     with SQLiteDB() as db:
+    #         db.execute("BEGIN TRANSACTION", commit=False)
+    #         db.insert_movie("黑客帝国", "/movies/matrix")
+    #         raise RuntimeError("模拟业务异常")  # 触发回滚
+    #         db.execute("COMMIT", commit=True)
+    # except Exception as e:
+    #     print(f"事务回滚成功: {e}")
\ No newline at end of file