{"id":18369525,"url":"https://github.com/williewangwei/wlm3u","last_synced_at":"2025-04-06T17:32:07.741Z","repository":{"id":43040757,"uuid":"197013787","full_name":"WillieWangWei/WLM3U","owner":"WillieWangWei","description":"WLM3U is a M3U tool written in Swift.","archived":false,"fork":false,"pushed_at":"2020-06-01T13:40:47.000Z","size":338,"stargazers_count":149,"open_issues_count":2,"forks_count":28,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-03-22T04:03:36.202Z","etag":null,"topics":["ios","ios-demo","ios-lib","ios-swift","m3u","m3u-files","m3u-parser","m3u-playlist","m3u8","m3u8-downloader","m3u8-parser","m3u8-playlist","m3u8-videos","m3ua","swift","swift-framework","swift-library","swift5"],"latest_commit_sha":null,"homepage":"https://github.com/WillieWangWei/WLM3U","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WillieWangWei.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-15T14:22:03.000Z","updated_at":"2025-01-26T06:32:06.000Z","dependencies_parsed_at":"2022-08-12T10:11:28.372Z","dependency_job_id":null,"html_url":"https://github.com/WillieWangWei/WLM3U","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WillieWangWei%2FWLM3U","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WillieWangWei%2FWLM3U/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WillieWangWei%2FWLM3U/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WillieWangWei%2FWLM3U/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WillieWangWei","download_url":"https://codeload.github.com/WillieWangWei/WLM3U/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247522545,"owners_count":20952573,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ios","ios-demo","ios-lib","ios-swift","m3u","m3u-files","m3u-parser","m3u-playlist","m3u8","m3u8-downloader","m3u8-parser","m3u8-playlist","m3u8-videos","m3ua","swift","swift-framework","swift-library","swift5"],"created_at":"2024-11-05T23:29:41.811Z","updated_at":"2025-04-06T17:32:07.083Z","avatar_url":"https://github.com/WillieWangWei.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"![](https://repository-images.githubusercontent.com/197013787/4935d600-ae5c-11e9-868c-e5f2338abd1a)\n\n[![language](https://img.shields.io/badge/language-swift-orange.svg)](https://cocoapods.org/pods/WLM3U)\n[![Platform](https://img.shields.io/cocoapods/p/WLM3U.svg?style=flat)](https://cocoapods.org/pods/WLM3U)\n[![Version](https://img.shields.io/cocoapods/v/WLM3U.svg?style=flat)](https://cocoapods.org/pods/WLM3U)\n[![License](https://img.shields.io/cocoapods/l/WLM3U.svg?style=flat)](https://cocoapods.org/pods/WLM3U)\n\nWLM3U is a M3U tool written in Swift.\n\n## Example\n\nTo run the example project, clone the repo, and run `pod install` from the Example directory first.\n\n## Requirements\n\niOS   | Swift\n----- | -----\n10.0 + | 5.1 +\n\n## Installation\n\n### CocoaPods\n\n```ruby\npod 'WLM3U'\n```\n\n### Swift Package Manager\n\n```swift\ndependencies: [\n    .package(url: \"https://github.com/WillieWangWei/WLM3U.git\", .upToNextMajor(from: \"0.1.5\"))\n]\n```\n\n## Usage\n\n### Parsing M3U files\n\n```Swift\nlet url = URL(string:\"http://xxx.com/yyy.m3u8\")! // URL of the M3U file\nlet size: Int = \u003c#fileSize#\u003e                     // The total size of all ts files\n\nWLM3U\n    .attach(url: url,\n            size: size, \n            tsURL: { (path, url) -\u003e URL? in\n                if path.hasSuffix(\".ts\") {\n                    return url.appendingPathComponent(path)\n                } else {\n                    return nil\n                }\n    },\n            completion: { (result) in\n                switch result {\n                case .success(let model):\n                    print(\"[Attach Success] \" + model.name!)\n                case .failure(let error):\n                    print(\"[Attach Failure] \" + error.  localizedDescription)\n                }\n    })\n```\n\n### Download the ts file described by the M3U file\n\n```Swift\nlet url = URL(string:\"http://xxx.com/yyy.m3u8\")! // URL of the M3U file\nlet size: Int = \u003c#fileSize#\u003e                     // The total size of all ts files\n\nWLM3U\n    .attach(url: url, size: size)\n    .download(progress: { (progress, completedCount) in\n        progress       // Current download progress\n        completedCount // Download speed (B/S)\n        \n    }, completion: { (result) in\n        switch result {\n        case .success(let url):\n            url // The directory where the ts file is located\n        case .failure(let error):\n            print(\"[Download Failure] \" + error.localizedDescription)\n        }\n    })\n```\n\n### Combine downloaded ts files into one file\n\n```Swift\nlet url = URL(string:\"http://xxx.com/yyy.m3u8\")! // URL of the M3U file\nlet size: Int = \u003c#fileSize#\u003e                     // The total size of all ts files\n\nWLM3U\n    .attach(url: url, size: size)\n    .download()\n    .combine(completion: { (result) in\n        switch result {\n        case .success(let url):\n            url // The directory where the files are located after the combine is completed\n        case .failure(let error):\n            print(\"[Combine Failure] \" + error.localizedDescription)\n        }\n    })\n```\n\n### Automatically get the total size of the ts file\n\nWLM3U supports automatic acquisition of the total size of all files when calling the `WLM3U.attach()` function without passing the `size` parameter. The process of getting the size is asynchronous, you can get the size data by receiving `TaskGetFileSizeProgressNotification` and `TaskGetFileSizeCompletionNotification`.\n\n### Pause and Resume tasks\n\nTo simplify the interface, WLM3U does not have the concepts of `pause` and `resume`. They are the same as `cancel` and `attach`, so:\n\nWhen you need to pause a task, call `cancel(url: URL)` when you need to pause a task.\n\nWhen you need to cancel a task, call `cancel(url: URL)` and get the task cache directory through `folder(for url: URL)` and delete it.\n\nWhen you need to add a task, call `attach(url: URL)`.\n\nWhen you need to resume a task, call `attach(url: URL)`, if the previous cache exists locally, it will automatically continue to download the remaining files.\n\n### Listening status\n\nThe WLM3U has built-in notifications for several states that you can receive to process data:\n\n```Swift\n/// A notification that will be sent when the progress of the task changes.\npublic let TaskProgressNotification: Notification.Name\n\n/// A notification that will be sent when the progress of getting file size changes.\npublic let TaskGetFileSizeProgressNotification: Notification.Name\n\n/// A notification that will be sent when size of all files has got.\npublic let TaskGetFileSizeCompletionNotification: Notification.Name\n\n/// A notification that will be sent when the task ends.\npublic let TaskCompletionNotification: Notification.Name\n\n/// A notification that will be sent when a task has an error.\npublic let TaskErrorNotification: Notification.Name\n```\n\n## Playing downloaded files\n\nAVPlayer and WLM3U do not support playing local ts files at this time. Here are two simple and feasible alternatives.\n\n### Using GCDWebServer to build local services\n\n**Note: Do not call the `WLM3U.combine()` function when playing in this way.**\n\nUsing the [GCDWebServer](https://github.com/swisspol/GCDWebServer) library:\n\n```ruby\npod \"GCDWebServer\"\n```\n\nCreate a local HTTP service to provide the downloaded ts file:\n\n```Swift\nlet server = GCDWebServer()\nlet path = \u003c#folderPath#\u003e // The local directory where the ts file is located\nserver.addGETHandler(forBasePath: \"/\",\n                     directoryPath: path,\n                     indexFilename: \"file.m3u8\",\n                     cacheAge: 3600,\n                     allowRangeRequests: true)\nserver.start()\n```\n\nThen, use AVPlayer to play the ts file provided by the local service:\n\n```Swift\nlet url = URL(string: \"http://localhost:\\(server.port)/file.m3u8\")\nlet player = AVPlayer(url: url)\n```\n\n### Using FFmpeg to transcode ts files into mp4 files\n\nUsing the [mobile-ffmpeg-full](https://github.com/tanersener/mobile-ffmpeg) library：\n\n```ruby\npod \"mobile-ffmpeg-full\"\n```\n\nExecute the transcoding command:\n\n```Swift\nlet command = \"-i 'The path where the ts file is located' 'The path to which the mp4 file is saved'\"\n\nlet result = MobileFFmpeg.execute(command)\n\nif result == RETURN_CODE_SUCCESS {\n    // Transcode completion\n}\n```\n\n## Author\n\n\u003e Willie, willie.wangwei@gmail.com\n\n***\n\nWLM3U 是一个用 Swift 实现的 M3U 工具。\n\n## 示例\n\nclone 这个仓库，接着执行 `pod install` 命令，然后运行示例项目。\n\n## 要求\n\n\niOS   | Swift\n----- | -----\n9.0 + | 5.0 +\n\n## 安装\n\nWLM3U 可通过 [CocoaPods](https://cocoapods.org) 安装，只需将以下行添加到 Podfile 即可\n\n```ruby\npod 'WLM3U'\n```\n\n## 使用\n\n### 解析 M3U 文件\n\n```Swift\nlet url = URL(string:\"http://xxx.com/yyy.m3u8\")! // M3U 文件的 URL\nlet size: Int = \u003c#fileSize#\u003e                     // 所有 ts 文件的总大小\n\nWLM3U\n    .attach(url: url,\n            size: size, \n            tsURL: { (path, url) -\u003e URL? in\n                if path.hasSuffix(\".ts\") {\n                    return url.appendingPathComponent(path)\n                } else {\n                    return nil\n                }\n    },\n            completion: { (result) in\n                switch result {\n                case .success(let model):\n                    print(\"[Attach Success] \" + model.name!)\n                case .failure(let error):\n                    print(\"[Attach Failure] \" + error.  localizedDescription)\n                }\n    })\n```\n\n### 下载 M3U 文件描述的 ts 文件\n\n```Swift\nlet url = URL(string:\"http://xxx.com/yyy.m3u8\")! // M3U 文件的 URL\nlet size: Int = \u003c#fileSize#\u003e                     // 所有 ts 文件的总大小\n\nWLM3U\n    .attach(url: url, size: size)\n    .download(progress: { (progress, completedCount) in\n        progress       // 当前下载的进度\n        completedCount // 下载速度（ B/S ）\n        \n    }, completion: { (result) in\n        switch result {\n        case .success(let url):\n            url // ts 文件所在的目录\n        case .failure(let error):\n            print(\"[Download Failure] \" + error.localizedDescription)\n        }\n    })\n```\n\n### 将下载的 ts 文件合并成一个文件\n\n```Swift\nlet url = URL(string:\"http://xxx.com/yyy.m3u8\")! // M3U 文件的 URL\nlet size: Int = \u003c#fileSize#\u003e                     // 所有 ts 文件的总大小\n\nWLM3U\n    .attach(url: url, size: size)\n    .download()\n    .combine(completion: { (result) in\n        switch result {\n        case .success(let url):\n            url // 合并完成后文件所在的目录\n        case .failure(let error):\n            print(\"[Combine Failure] \" + error.localizedDescription)\n        }\n    })\n```\n\n### 自动获取 ts 文件总大小\n\n当调用 `WLM3U.attach()` 函数未传递 `size` 参数时，WLM3U 会自动获取所有文件的总大小。这个过程是异步的，可以通过接收 `TaskGetFileSizeProgressNotification` 和 `TaskGetFileSizeCompletionNotification` 来获取大小数据。\n\n### 暂停与恢复任务\n\n为了简化接口，WLM3U 没有 `暂停` 与 `恢复` 的概念，它们和 `取消` 与 `添加` 是一样的，所以：\n\n需要暂停一个任务时，调用 `cancel(url: URL)`。\n\n需要取消一个任务时，调用 `cancel(url: URL)`，并通过 `folder(for url: URL)` 获取到此任务缓存目录，并删除它即可。\n\n需要添加一个任务时，调用 `attach(url: URL)`。\n\n需要恢复一个任务时，调用 `attach(url: URL)`，如果本地存在之前的缓存，会自动继续下载剩余的文件。\n\n### 监听状态\n\nWLM3U 内置了几个状态的通知，你可以接收这些通知来处理数据：\n\n```Swift\n/// 下载进度发生变化时会发出的通知。\npublic let TaskProgressNotification: Notification.Name\n\n/// 获取文件总大小的进度发生变化时会发出的通知。\npublic let TaskGetFileSizeProgressNotification: Notification.Name\n\n/// 获取文件总大小完成时会发出的通知。\npublic let TaskGetFileSizeCompletionNotification: Notification.Name\n\n/// 任务完成时会发出的通知。\npublic let TaskCompletionNotification: Notification.Name\n\n/// 任务发生错误时会发出的通知。\npublic let TaskErrorNotification: Notification.Name\n```\n\n## 播放下载的文件\n\nAVPlayer 与 WLM3U 暂不支持播放本地 ts 文件，这里提供两个简单可行的替代方案。\n\n### 使用 GCDWebServer 搭建本地服务\n\n**注意：使用此方式播放时，不要调用 `WLM3U.combine()` 函数。**\n\n引入 [GCDWebServer](https://github.com/swisspol/GCDWebServer) 库：\n\n```ruby\npod \"GCDWebServer\"\n```\n\n创建本地 HTTP 服务来提供下载好的 ts 文件：\n\n```Swift\nlet server = GCDWebServer()\nlet path = \u003c#folderPath#\u003e // ts 文件所在的本地目录\nserver.addGETHandler(forBasePath: \"/\",\n                     directoryPath: path,\n                     indexFilename: \"file.m3u8\",\n                     cacheAge: 3600,\n                     allowRangeRequests: true)\nserver.start()\n```\n\n使用 AVPlayer 来播放本地服务提供的 ts 文件：\n\n```Swift\nlet url = URL(string: \"http://localhost:\\(server.port)/file.m3u8\")\nlet player = AVPlayer(url: url)\n```\n\n### 使用 FFmpeg 将 ts 文件转码成 mp4 文件\n\n引入 [mobile-ffmpeg-full](https://github.com/tanersener/mobile-ffmpeg) 库：\n\n```ruby\npod \"mobile-ffmpeg-full\"\n```\n\n执行转码命令：\n\n```Swift\nlet command = \"-i 'ts文件所在的路径' 'mp4文件要保存到的路径'\"\n\nlet result = MobileFFmpeg.execute(command)\n\nif result == RETURN_CODE_SUCCESS {\n    // 转码完成\n}\n```\n\n接下来直接播放转码得到的 mp4 文件即可。\n\n## 作者\n\n\u003e Willie, willie.wangwei@gmail.com\n\n## License\n\nWLM3U is available under the MIT license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliewangwei%2Fwlm3u","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwilliewangwei%2Fwlm3u","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwilliewangwei%2Fwlm3u/lists"}