{"id":15288680,"url":"https://github.com/enebin/aespa","last_synced_at":"2026-03-06T11:31:46.892Z","repository":{"id":174355811,"uuid":"648149292","full_name":"enebin/Aespa","owner":"enebin","description":"From camera to album, in just 2 lines","archived":false,"fork":false,"pushed_at":"2024-04-28T06:19:34.000Z","size":3661,"stargazers_count":62,"open_issues_count":2,"forks_count":10,"subscribers_count":4,"default_branch":"main","last_synced_at":"2024-04-28T12:36:55.156Z","etag":null,"topics":["avfoundation","camera","ios","recorder","swift","swift-package-manager","swiftui","uikit","video","xcode"],"latest_commit_sha":null,"homepage":"https://enebin.github.io/Aespa/documentation/aespa/","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/enebin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-01T10:12:44.000Z","updated_at":"2024-06-03T10:32:24.995Z","dependencies_parsed_at":"2024-04-27T12:32:07.577Z","dependency_job_id":"bb1e3c1f-c464-4d00-815a-9845966cce06","html_url":"https://github.com/enebin/Aespa","commit_stats":null,"previous_names":["enebin/aespa"],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enebin%2FAespa","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enebin%2FAespa/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enebin%2FAespa/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/enebin%2FAespa/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/enebin","download_url":"https://codeload.github.com/enebin/Aespa/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":219846842,"owners_count":16556424,"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":["avfoundation","camera","ios","recorder","swift","swift-package-manager","swiftui","uikit","video","xcode"],"created_at":"2024-09-30T15:52:04.125Z","updated_at":"2026-03-06T11:31:46.829Z","avatar_url":"https://github.com/enebin.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fenebin%2FAespa%2Fbadge%3Ftype%3Dswift-versions)](https://swiftpackageindex.com/enebin/Aespa)\n[![](https://img.shields.io/endpoint?url=https%3A%2F%2Fswiftpackageindex.com%2Fapi%2Fpackages%2Fenebin%2FAespa%2Fbadge%3Ftype%3Dplatforms)](https://swiftpackageindex.com/enebin/Aespa)\n[![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](https://github.com/apple/swift-package-manager)\n![Aespa. Ready-to-go package for easy and intuitive camera handling](Assets/header.jpg)\n\n\u003cdiv align=\"center\"\u003e\n\n### From camera to album. In just 2 lines.\n\n\u003c/div\u003e\n\n``` Swift \nlet aespaOption = AespaOption(albumName: \"YOUR_ALBUM_NAME\")\nlet aespaSession = Aespa.session(with: aespaOption)\n// Done!\n```\n\n### Quick link\n\n- **Demo app \u0026 usage example** can be found in [here](https://github.com/enebin/Aespa/tree/main/Demo/Aespa-iOS)\n- **Latest API documentation** can be found in [here](https://enebin.github.io/Aespa/documentation/aespa/)\n\n### Index\n- [Introduction](#Introduction)\n    - [Super Easy to Use](#Super-Easy-to-Use)\n    - [No more delegate](#No-more-delegate)\n    - [Also](#Also)\n- [Functionality](#Functionality)\n- [Installation](#Installation)\n    - [Swift Package Manager (SPM)](#Swift-Package-Manager-(SPM))\n- [Usage](#Usage)\n    - [Requirements](#Requirements)\n    - [Getting Started](#Getting-Started)\n- [Implementation Examples](#Implementation-Examples)\n    - [Configuration](#Configuration)\n    - [Recording \u0026 Capture](#Recording-\u0026-Capture)\n- [SwiftUI Integration](#SwiftUI-Integration)\n    - [Example Usage](#Example-Usage)\n- [Contributing](#Contributing)\n- [License](#License)\n\n---\n\n## Introduction\n\nAespa is a robust and intuitive Swift package for video and photo capturing, built with a focus on the ease of setting up and usage.\n\nIt is designed to be easy to use from beginners to intermediate developers. If you're new to video recording on iOS or if you're looking to simplify your existing camera setup, Aespa could be the perfect fit for your project.\n\n\n#### Super easy to use\n\n\u003cdetails\u003e\n\u003csummary\u003e Zip the boring configuration for session \u0026 album \u003c/summary\u003e\n\n*Before*\n``` mermaid\ngraph LR\nUser --\u003e RP[\"Permission Request\"]\nRP -- \"Granted\" --\u003e AS[\"AVCaptureSession\"]\nAS -- \"Connect\" --\u003e AI[\"AVCaptureVideoInput\"]\nAS -- \"Connect\" --\u003e AIA[\"AVCaptureAudioInput\"]\nAS -- \"Add\" --\u003e FO[\"AVCaptureFileOutput\"]\nFO --\u003e PHCollectionListChangeRequest\n```\n\n**Aespa**\n``` mermaid\ngraph LR\n   User --\u003e Aespa --\u003e Session \u0026 Album\n```\n\n- Aespa provides an accessible API that abstracts the complexity of `AVFoundation`, allowing you to manage video capturing tasks with ease.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e Offer essential preset configuration \u0026 customization \u003c/summary\u003e\n\n``` mermaid\ngraph TD\nAS[\"AespaSession\"]\nAS --\u003e RV[\"Recording a new video\"]\nAS --\u003e Se[\"Change zoom, video quailty, camera position, ...\"]\nAS --\u003e AV[\"Set options like stabilization, orientation ,...\"]\nAS --\u003e D[\"Fetching asset files\"]\n```\n- With Aespa, you can readily adjust a variety of settings. \n- For a higher degree of customization, it also supports the creation of custom tunings for the recording session, offering flexible control over your recording needs.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n\u003csummary\u003e Comprehensive error handling \u003c/summary\u003e\n\n- The package provides comprehensive error handling, allowing you to build robust applications with minimal effort.\n\n\u003c/details\u003e\n\n#### No more delegate\n\u003cdetails\u003e\n\n\u003csummary\u003e Combine support \u003c/summary\u003e\n\n``` mermaid\ngraph LR;\n    A[Session update] --\u003e|Trigger| B[previewLayerPublisher, ...]\n    B --\u003e|React to Changes| C[Subscribers]\n\n\t\tE[Background Thread] --Async--\u003e F[\"Configure session\"] --Finish--\u003e A\n```\n- Aespa's API leverages Swift's latest concurrency model to provide asynchronous functions, ensuring smooth and efficient execution of tasks.\n- Additionally, it is built with `Combine` in mind, enabling you to handle updates such as video output and preview layer  reactively using publishers and subscribers.\n\n\u003c/details\u003e\n\n#### Also\n- Automated system permission management.\n- Seamless image and video capture within a single preview session.\n- Thread-safe.\n- Support SPM.\n\n\n## Functionality\n\n\u003e **Note**\n\u003e \n\u003e You can access our **official documentation** for more comprehensive and up-to-date explanations in [here](https://enebin.github.io/Aespa/documentation/aespa/)\n\n### Manual options\n| Common                           | Description                                                                                                      |\n|----------------------------------|------------------------------------------------------------------------------------------------------------------|\n| ✨ `zoom`                        | Modifies the zoom factor.                                                                                        |\n| ✨ `position`                 | Changes the camera position.                                                                                     |\n| `orientation`                 | Modifies the orientation.                                                                                        |\n| `focus`                       | Alters the autofocusing mode.                                                                                    |\n| `quality`                     | Adjusts the video quality preset for the recording session.                                                      |\n| `doctor`                         | Checks if essential conditions to start recording are satisfied.                                                 |\n| `previewLayerPublisher`          | Responsible for emitting updates to the preview layer.                                                           |\n\n| Video                            | Description                                                                                                      |\n|----------------------------------|------------------------------------------------------------------------------------------------------------------|\n| ✨ `startRecording`      | Initiates the recording of a video session.                                                                      |\n| ✨ `stopRecording`              | Terminates the current video recording session and attempts to save the video file.                              |\n| `mute`                           | Mutes the audio input.                                                                                           |\n| `unmute`                         | Restores the audio input.                                                                                        |\n| `stabilization`               | Alters the stabilization mode.                                                                                   |\n| `torch`                       | Adjusts the torch mode and level.                                                                                |\n| `customize`                      | Customizes the session with a specific tuning configuration.                                                     |\n| ✨ `fetchVideoFiles`                | Fetches a list of recorded video files.                                                                          |\n| `videoFilePublisher`             | Emits a `Result` object containing a latest video file data.                          |\n\n| Photo                            | Description                                                                                                      |\n|----------------------------------|------------------------------------------------------------------------------------------------------------------|\n| ✨ `capturePhoto`               | Capture a photo and returns a result image file.          |\n| ✨ `flashMode`                   | Sets the flash mode for the photo capture session.                                                               |\n| `redEyeReduction`                | Enables or disables red-eye reduction for the photo capture session.                                             |\n| `customize`                      | Customizes the photo capture session with a specific `AVCapturePhotoSettings`.                                   |\n| ✨ `fetchPhotoFiles`                | Fetches a list of captured photos files.                                                                          |\n| `photoFilePublisher`             | Emits a `Result` object containing a latest image file data.                            |\n\n### `InteractivePreview`\nOne of main features, `InteractivePreview` provides a preset session for those who don't want to do complicated configurations.\n\n| Features               | Description                                                             |\n|------------------------|------------------------------------------------------------------------------------------------------------------|\n| Double tap to change camera  | Switches between the front and back camera upon double tapping.                                                  |\n| Pinch zoom          | Allows zooming in or out on the preview by using a pinch gesture.                                                |\n\n\n## Installation \n### Swift Package Manager (SPM)\nFollow these steps to install **Aespa** using SPM:\n\n1. From within Xcode 13 or later, choose `File` \u003e `Swift Packages` \u003e `Add Package Dependency`.\n2. At the next screen, enter the URL for the **Aespa** repository in the search bar then click `Next`.\n``` Text\nhttps://github.com/enebin/Aespa.git\n```\n3. For the `Version rule`, select `Up to Next Minor` and specify the current Aespa version then click `Next`.\n4. On the final screen, select the `Aespa` library and then click `Finish`.\n\n**Aespa** should now be integrated into your project 🚀.\n\n## Usage\n\n\u003e **Note**\n\u003e\n\u003e We offer an extensively detailed and ready-to-use code base for a SwiftUI app that showcases most of the package's features. \n\u003e You can access it [here, the demo app](https://github.com/enebin/Aespa/tree/main/Demo/Aespa-iOS).\n\n### Requirements\n- Swift 5.5+\n- iOS 14.0+\n\n### Getting started\n```swift\nimport Aespa\n```\n\n\u003c!-- INSERT_CODE: GETTING_STARTED --\u003e\n```swift\nlet option = AespaOption(albumName: \"YOUR_ALBUM_NAME\")\nlet aespaSession = Aespa.session(with: option)\n```\n\u003c!-- INSERT_CODE: END --\u003e\n\n## Implementation Exapmles\n### Configuration\n\u003c!-- INSERT_CODE: COMMON_SETTING --\u003e\n```swift\n// Common setting\naespaSession\n    .common(.focus(mode: .continuousAutoFocus))\n    .common(.changeMonitoring(enabled: true))\n    .common(.orientation(orientation: .portrait))\n    .common(.quality(preset: .high))\n    .common(.custom(tuner: WideColorCameraTuner())) { result in\n        if case .failure(let error) = result {\n            print(\"Error: \", error)\n        }\n    }\n```\n\u003c!-- INSERT_CODE: END --\u003e\n\n\u003c!-- INSERT_CODE: PHOTO_SETTING --\u003e\n```swift\n// Photo-only setting\naespaSession\n    .photo(.flashMode(mode: .on))\n    .photo(.redEyeReduction(enabled: true))\n```\n\u003c!-- INSERT_CODE: END --\u003e\n\n\u003c!-- INSERT_CODE: VIDEO_SETTING --\u003e\n```swift\n// Video-only setting\naespaSession\n    .video(.mute)\n    .video(.stabilization(mode: .auto))\n```\n\u003c!-- INSERT_CODE: END --\u003e\n\n### Recording \u0026 Capture\n\u003c!-- INSERT_CODE: RECORDING_AND_CAPTURE --\u003e\n```swift\n// Start recording\naespaSession.startRecording()\n// Later... stop recording\naespaSession.stopRecording()\n// Capture photo\naespaSession.capturePhoto()\n```\n\u003c!-- INSERT_CODE: END --\u003e\n\n### Get result\n\u003c!-- INSERT_CODE: GET_RESULT --\u003e\n```swift\naespaSession.stopRecording { result in\n    switch result {\n    case .success(let file):\n        print(file.path) // file://some/path\n    case .failure(let error):\n        print(error)\n    }\n}\n\n// or...\nTask {\n    let files = await aespaSession.fetchVideoFiles(limit: 1)\n}\n\n// or you can use publisher\naespaSession.videoFilePublisher.sink { result in\n    print(result)\n}\n```\n\u003c!-- INSERT_CODE: END --\u003e\n\n## SwiftUI Integration\nAespa also provides a super-easy way to integrate video capture functionality into SwiftUI applications. `AespaSession` includes a helper method to create a SwiftUI `UIViewRepresentable` that provides a preview of the video capture.\n\n### Example usage\n\u003c!-- INSERT_CODE: SWIFTUI_INTEGRATION --\u003e\n```swift\nimport Aespa\nimport SwiftUI\n\nstruct VideoContentView: View {\n    @StateObject private var viewModel = VideoContentViewModel()\n\n    var body: some View {\n        ZStack {\n            viewModel.preview\n                .frame(minWidth: 0,\n                       maxWidth: .infinity,\n                       minHeight: 0,\n                       maxHeight: .infinity)\n                .edgesIgnoringSafeArea(.all)\n        }\n    }\n}\n\nclass VideoContentViewModel: ObservableObject {\n    let aespaSession: AespaSession\n    var preview: some View {\n        aespaSession.interactivePreview()\n    }\n\n    init() {\n        let option = AespaOption(albumName: \"YOUR_ALBUM_NAME\")\n        self.aespaSession = Aespa.session(with: option)\n\n        setUp()\n    }\n\n    func setUp() {\n        aespaSession\n            .common(.quality(preset: .high))\n\n        // Other options\n        // ...\n    }\n}\n```\n\u003c!-- INSERT_CODE: END --\u003e\n\n\u003e **Note**\n\u003e \n\u003e In `UIKit`, you can access the preview through the `previewLayer` property of `AespaSession`. \n\u003e For more details, refer to the [AVCaptureVideoPreviewLayer](https://developer.apple.com/documentation/avfoundation/avcapturevideopreviewlayer) in the official Apple documentation.\n\n## Contributing\nContributions to Aespa are warmly welcomed. Please feel free to submit a pull request or create an issue if you find a bug or have a feature request.\n\n## License\nAespa 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%2Fenebin%2Faespa","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fenebin%2Faespa","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fenebin%2Faespa/lists"}