मेरा खुद बनाया हुआ ऑडियो प्लेयर
(nexo.sh)- 2025 में भी iPhone पर अपने पास मौजूद music files को आज़ादी से सुनना और sync करना मुश्किल है—इसी समस्या से शुरू होकर, local-first music player को SwiftUI में खुद implement किया गया
- Apple Music subscription बंद करने पर iCloud Music Library sync रुक जाता है, और iTunes Match सालाना $24.99 में 256kbps AAC copies को online store करने वाला अलग paid option है
- React Native/Expo में deeply nested iCloud folders को traverse करने और file permissions handle करने में failures और crashes अक्सर हुए, इसलिए Apple native APIs इस्तेमाल करने वाला SwiftUI implementation ज़्यादा simple विकल्प बना
- ऐप SQLite FTS5 से filename और artist, album, title जैसे metadata search करता है, और iCloud import, library management, playback screen को अलग-अलग structure करता है
- iOS में security-scoped bookmarks और personal development build limits की वजह से, किसी individual के बनाए app को लंबे समय तक reliably इस्तेमाल करने की प्रक्रिया में भी file access और distribution barriers बने रहते हैं
खुद music player क्यों बनाया
- iPhone पर अपने पास मौजूद music files चलाने के लिए Apple को पैसे देने या कई constraints को workaround करने की स्थिति अब भी बनी हुई है
- जिन users ने अपनी local music library पहले से व्यवस्थित कर रखी है, उनके लिए streaming service ज़रूरी चीज़ से ज़्यादा convenience feature जैसी है
- Apple Music subscription cancel करने पर iCloud Music Library आधारित device-to-device sync बंद हो जाता है
- यह feature subscription के पीछे है
- iTunes Match इस्तेमाल करने पर इसे सालाना $24.99 में फिर इस्तेमाल किया जा सकता है
- Match 256kbps AAC copies को online store करता है, और original files user द्वारा बदले बिना वैसी ही रहती हैं
- subscription न हो तो cloud sync गायब हो जाता है और cable/Wi‑Fi sync पर लौटना पड़ता है
- लक्ष्य था audio files import, organize और play करने वाला basic music player खुद बनाना
- तैयार ऐप full-text search, iCloud support और local-first experience देता है और GitHub पर public है
मौजूदा विकल्प क्यों fit नहीं हुए
-
Apple के default apps
- Files app से iCloud में मौजूद music files सीधे play की जा सकती हैं, लेकिन इसे music listening app के रूप में design नहीं किया गया है
- playlist management, metadata sorting, playback queue जैसे core features की कमी है
- music playback खुद संभव है, लेकिन overall user experience limited है, और इस बारे में Apple community discussions भी हैं
-
Third-party apps
- App Store में offline music playback apps बहुत हैं, लेकिन user के पहले से owned files play करने वाले apps पर भी अक्सर subscription-based pricing लागू होती है
- Doppler में one-time payment model का फायदा था
- हालांकि UX album management पर केंद्रित था, search quality संतोषजनक नहीं थी, और बहुत सारे nested folders वाला iCloud import slow और इस्तेमाल में कठिन था
React Native से SwiftUI में बदलने की प्रक्रिया
-
शुरू में चुना गया React Native/Expo
- पुराने Swift experience की वजह से Swift से बचते हुए, web development experience reuse करने के लिए पहले React Native/Expo चुना गया
- playback UI implement करना आसान था, और ज़रूरी features वाला दिखने वाला Gionatha Sturba का music-player template इस्तेमाल किया गया
- समस्या file system access और cloud file sync में बढ़ गई
expo-filesystemजैसी libraries basic file selection तो support करती थीं, लेकिन deeply nested iCloud directories की recursive traversal अक्सर fail होती थी या app crash करा देती थी- iOS sandbox explicit user permission के बिना app को files पढ़ने से रोकता है
- नतीजतन JavaScript-based approach Apple native APIs सीधे इस्तेमाल करने से ज़्यादा complex हो गई, और Swift पर switch करने से iCloud file access और sandbox permissions पर बेहतर control मिल सका
-
SwiftUI चुनने की वजह
- UIKit या storyboards के बजाय SwiftUI चुना गया ताकि declarative UI layer बने और domain logic व data sync पर focus किया जा सके
- Swift के
async/awaitऔर Swift Actors integration ने data flow और concurrency management को आसान बनाया - SwiftUI ने app को independent ViewModel components में structure करने में मदद की
- OpenAI o1 और DeepSeek जैसे LLMs ने pure UI code या data binding code generate करते समय complex interdependencies कम बनाईं
ऐप structure और data model
-
तीन मुख्य screens
- app Library import, Library management, Player and playback इन तीन flows में बंटा है
- Library import iCloud library folder जोड़ता है और सभी folders में audio files scan करके paths को SQLite database में insert करता है
- Library management added songs को manage करता है और playlists बनाता है
- Player and playback repeat, shuffle, queue management, play·pause·next song features संभालता है
- Apple का default file picker keyword से search किए गए multiple directories और multiple files को एक बार में select करने वाले flow के लिए fit नहीं है
- empty library के साथ app launch करने पर Sync tab में “Add iCloud Source” button दिखता है
- folder select करने पर tree traversal के दौरान progress bar दिखता है, और indexing खत्म होने पर Library tab पर जाता है
- पहली screen पर Playlists / Artists / Albums / Songs दिखते हैं
- track tap करने पर नीचे Mini-Player दिखता है, और इसे tap करने पर full-screen Player खुलता है
- full-screen Player shuffle, repeat, queue reordering और volume देता है
- Sync में “+” दबाकर दूसरा folder select करने पर नए songs background में merge होते हैं और restart की ज़रूरत नहीं होती
-
Server-style logic layer
- mobile app होने के बावजूद web·cloud backend experience के आधार पर backend-style architecture लागू किया गया
- domain·logic layer को View और ViewModel layers से अलग किया गया ताकि cloud sync, metadata parsing और SQLite data access reliably handle हो सकें
- layer structure इस प्रकार है
- SQLite original song rows और FTS index store करता है
- Repository database को wrap करता है और async API expose करता है
- domain Actor import, search, queue logic जैसे business rules own करता है
- ViewModel Actor को subscribe करता है और UI के लिए structs में convert करता है
- SwiftUI View received data को render करता है
- state changes thread-safe रखे जाते हैं, और iCloud sync·playback·UI को direct layers skip न करने के लिए अलग किया गया है
SQLite FTS5 से बना local search
- persistent storage के लिए SQLite इस्तेमाल किया गया, CoreData नहीं
- CoreData से बचने की वजह schema, raw queries, और खासकर full-text search को सीधे control करने की ज़रूरत थी
- iOS 11 के आसपास से FTS capability वाला SQLite बिना extra setup के इस्तेमाल किया जा सकता है
- normal queries के लिए SQLite.swift इस्तेमाल किया गया, लेकिन FTS queries को normal SQL statements से handle किया गया
- SQLite FTS5 filename और artist, album, title जैसे metadata को अलग search infrastructure के बिना query करने देता है
-
FTS table configuration
- दो FTS5 tables इस्तेमाल हुए
songs_fts:SQLiteSongRepositoryइस्तेमाल करता है औरartist,title,album,albumArtistको index करता हैsource_paths_fts:SQLiteSourcePathSearchRepositoryइस्तेमाल करता है औरfullPath,fileNameको index करता है- दोनों FTS tables base B-tree tables
songs,source_pathsके बगल में हैं - FTS UI में read-only है, और सभी writes Repository के अंदर handle होते हैं
songs_ftscreation example मेंsongIdकोUNINDEXEDरखा गया औरunicode61tokenizer इस्तेमाल किया गया- अलग-अलग characters handle करने के लिए
unicode61चुना गया - जिन keys को search नहीं करना है उन्हें
UNINDEXEDmark किया गया ताकि term dictionary बेवजह बड़ी न हो
-
Partial search और ranking
- user “lumine” type करे तो internally “lumine*” जैसा wildcard जोड़कर partial search results तुरंत मिलते हैं
- search result sorting के लिए SQLite का
bm25इस्तेमाल होता है - यह तरीका predictable schema, local-first approach और powerful full-text search देता है, और network dependency या external service add नहीं करता
iOS file access और bookmark constraints
- iOS apps file location याद रखने के लिए persistent bookmarks save कर सकते हैं
- लेकिन app sandbox के बाहर files पर extended access देने वाले security-scoped bookmarks केवल macOS पर उपलब्ध हैं
- iOS apps normal bookmarks से file paths याद रख सकते हैं और document picker के जरिए फिर access request कर सकते हैं, लेकिन यह guarantee नहीं है कि वह access silently जारी रहेगा
- संबंधित जानकारी Apple की bookmark documentation में है
- इसे mitigate करने के लिए files को app के अपने sandbox container में copy करने वाला fallback mechanism implement किया गया
- bookmark valid रहने के दौरान files को background में proactively copy किया जाता है
- iOS permissions reset कर दे तो invalid audio file references access करने का risk घटता है
- इस approach ने indexing speed भी improve की
- access active रहने के दौरान folder structure को एक बार scan किया जाता है
- सिर्फ relevant audio files import की जाती हैं
- deeply nested directories को safely traverse किया जाता है
- external locations की individual audio files को device restart के बाद भी reliably play करने की समस्या solve नहीं हुई
- native app में भी यह use case iOS पर पर्याप्त रूप से supported नहीं है, और file access reliably handle करना अब भी complex है
Playback और UI implementation
-
Metadata parsing
- audio file metadata parsing के लिए Apple AVFoundation framework का
AVURLAssetइस्तेमाल हुआ AVURLAssettitle, album artist जैसे media file metadata inspect कर सकता है- track number जैसे कुछ fields ID3 tags से सीधे ढूंढने पड़े
- official docs edge cases को पर्याप्त रूप से cover नहीं करते थे, इसलिए GitHub search से implementation examples reference किए गए
- audio file metadata parsing के लिए Apple AVFoundation framework का
-
Audio playback
- library indexing के बाद
AVAudioPlayerinstance initialize करके playback करने के तरीके से audio player implement किया गया - Control Center से music control करने के लिए
AVAudioPlayerDelegateprotocol implement करके Apple केMPRemoteCommandCenterसे connect करना पड़ता है MPRemoteCommandCenterapp को system-level playback controls पर respond करने देता है
- library indexing के बाद
Swift और Apple development experience
-
कठिन रहे पहलू
- Xcode के live SwiftUI previews प्रगति हैं, लेकिन overall development experience Flutter द्वारा 5 साल पहले दिए गए VSCode integration, live simulator reload और familiar debugging tools के level तक नहीं पहुंचा
- Swift के लिए Neovim या VSCode LSP support में
xcode-build-serverजैसे extra tools चाहिए, और यह web-centric ecosystem के developer experience जैसा नहीं है - Apple SDK के कुछ हिस्से अब भी Objective-C style में हैं
- Spotlight file search केवल
NSMetadataQueryसे expose होता है, औरNSMetadataQueryKVO व string keys इस्तेमाल करता है - Swift-friendly wrapper अभी नहीं है
- SwiftUI का declarative UI useful है, लेकिन iCloud permissions से जुड़ा full app behavior previews में emulate नहीं किया जा सकता, इसलिए cloud interactions को सीधे mock करना पड़ता है
-
अच्छे रहे पहलू
async/awaitकी वजह से I/O-centric concurrency code callbacks के बिना imperative code की तरह लिखा जा सका- Actor के अंदर synchronous code भी आसानी से रखा जा सका और JavaScript ecosystem की तरह call किया जा सका
- React Native या Flutter की open-source bindings तक सीमित रहने के बजाय Apple native libraries सीधे इस्तेमाल की जा सकीं
- कई Apple APIs में examples हैं, इसलिए शुरुआत करना आसान था
- SwiftUI का React-style UI composition productivity और exploration की गुंजाइश देता है
personal app को लंबे समय तक इस्तेमाल करना iOS पर कठिन
- लगभग 1.5 हफ्ते के implementation के बाद iCloud storage से audio files import कर सकने वाला local/offline music player बनाया गया
- लेकिन developer certificate न हो तो app केवल 7 दिन तक चलता है, उसके बाद फिर build करना पड़ता है
- Apple Developer Program में register करने के लिए $99 देने पड़ते हैं
- EU के DMA Act के बाद भी sideloading पूरी तरह open नहीं है
- EU users developer site से third-party marketplace app install कर सकते हैं
- developers को अब भी Apple के $99/year program में register करना पड़ता है
- Apple के Alternative Terms से भी सहमत होना पड़ता है
- personal·hobby use में 7-day development build limit खत्म नहीं होती
- iOS PWA में भी limitations बची हैं
- iOS 16~18.x updates के बाद भी PWA Safari sandbox के अंदर चलता है
- WebGL2 और web-push इस्तेमाल किए जा सकते हैं
- Web Bluetooth, USB, NFC, Background Sync, और लगभग 50MB से ज्यादा guaranteed storage नहीं मिलता
- WebGL Metal shim से गुजरता है, इसलिए actual framerate अक्सर native Metal app से पीछे रहता है
- AI ने unfamiliar technologies संभालने के लिए जरूरी knowledge को ज़्यादा accessible बनाकर software development complexity घटाई, लेकिन iOS apps को अब भी artificial rules follow करने पड़ते हैं
- किसी individual द्वारा खुद बनाया app भी एक हफ्ते से ज्यादा चलाना हो तो Apple की final hurdle बची रहती है, और यह personal app development व distribution को constrain करती है
1 टिप्पणियां
Hacker News की राय
Winamp के default music player होने वाले दौर से गुज़रा हूँ, और streaming के दौर में भी अब तक अपनी local music library को folders में व्यवस्थित रखता हूँ
यहाँ comments में बाकी लोगों की तरह, offline music सुनने के लिए hobby project के तौर पर एक old-school music player बनाया; यह 1-page HTML/JS app है, जिसमें पूरा keyboard control और साधारण queue feature डाला है
इसे देख सकते हैं: https://nobsutils.com/mp
directory के अंदर files का collection, पूरी collection को shuffle करना, सिर्फ़ किसी खास directory को play करना—ऐसी simplicity अच्छी लगती थी
वैसे अभी standard bookmark shortcut
cmd + dwebsite bookmark करने के बजाय theme बदल देता है25 साल तक FLAC format में music collection बनाया, और पिछले साल Android phone और 1TB MicroSD card खरीदा, जिससे सारा music डाल पाना संभव हुआ
technology के catch up करने तक यह लंबा project रहा, लेकिन अब सब कुछ जेब में रख सकता हूँ, इसलिए काफी संतुष्टि है
industry जो push कर रही है उसे stream करके, ads झेलते हुए control छोड़ देने वाला किरायेदार नहीं बनना चाहता—ऐसा सोचने वाला मैं अकेला नहीं हो सकता; और जो लोग अपना app तक खुद बनाते हैं, उन्हें देखना भी अच्छा लगता है
अच्छे से re-encode करें तो transparent audio quality के साथ, जिसमें फर्क सुनाई नहीं देता, कहीं छोटे card में सारा music रखा जा सकता है; backup के लिए desktop पर FLAC रख सकते हैं
मेरे collection में FLAC/APE/ALAC/WavePack सिर्फ़ करीब 25% ही हैं, फिर भी वह 3TB से ज़्यादा है, इसलिए चलते-फिरते music सुनना मुश्किल है
mobile device में क्या डालूँ, यह पहले से चुन ही नहीं पाता
server के लिए https://www.navidrome.org और client के लिए https://symfonium.app का combination बहुत अच्छा रहा
अब 2TB SD card भी आ गए हैं, तो price कम होने पर शायद एक खरीदूँगा
बदलने पर भी apply नहीं होता था, या apply होने के बाद अचानक गलत cover में बदल जाता था; देखने में यह Android bug जैसा लगता था
जानना चाहूँगा कि क्या आपको भी ऐसी problem हुई
पूरा album सुनना, लेकिन बीच में break लेने या device बदलने की सुविधा रखने के लिए मैंने खुद एक web app बनाया
मुझे album शुरू से अंत तक सुनना पसंद है, लेकिन कम से कम YouTube Music playback position याद नहीं रखता, और दूसरे device पर album फिर से खोलकर जहाँ छोड़ा था वह point ढूँढना पड़ता है, जो inconvenient था
मेरे web app में URL paste करने पर server
yt-dlpसे download करता है और वहीं से stream किया जा सकता है; यह playback position हमेशा याद रखता है, इसलिए car में phone पर सुनकर office में laptop पर वहीं से continue कर सकता हूँNTS Radio जैसे दूसरे sources से mixes जोड़ने पर भी यह ठीक बैठता है
अगर वह web app public है तो मैं उसे एक बार देखना चाहूँगा
अभी पूरा नहीं पढ़ा है, लेकिन अच्छा लेख है, और मुझे यह पढ़ना पसंद है कि developer ने ज़्यादा granular decisions कैसे और क्यों लिए
जिन audio players को try किया वे पसंद नहीं आए—इस विचार से सहमत हूँ
music apps की दुनिया में screen layout और UI लगभग universal हो गए लगते हैं, लेकिन मुझे वह पसंद नहीं और ठीक से समझ भी नहीं आता
ऐसा लगता है जैसे हर music app से लड़ाई करनी पड़ रही हो, इसलिए कुछ नया बनाने की कोशिश करने वाले लोग अच्छे लगते हैं
अब भी Apple Music app में अपनी local files डालकर इस्तेमाल करता हूँ
Apple Music streaming service बंद रखता हूँ, macOS के Apple Music app में सब import करने के बाद, 2007 की तरह phone को laptop से जोड़कर iPod की तरह sync करता हूँ
सब कुछ उम्मीद के मुताबिक काम करता है, और music अक्सर बदलता नहीं, इसलिए sync भी समस्या नहीं है
wired sync करते समय अजीब-सी nostalgia भी महसूस होती है
async/awaitन होने वाले समय में Swift में concurrency code को Go या JS/TS से ज़्यादा clumsy और boilerplate-heavy लगा—इस बात से सहमत होना मुश्किल हैasynchronous processing concurrency code लिखना आसान बना सकती है, लेकिन codebase बड़ा होने पर reasoning कम simple हो सकती है
complex asynchronous codebase में code flow और concurrency को समझना ज़्यादा कठिन होता है
अगर goal thread code execution cost घटाना है तो lightweight green threads जैसा solution है, और अगर goal thread code maintenance cost घटाना है तो asynchronous approach लंबे समय में ज़्यादा effort मांग सकती है
process या service-based encapsulation भर से भी बड़ा फायदा होता है
मुझे लगता है कि यह concurrency की खुद की failure नहीं, बल्कि async/await abstraction की limitation के ज़्यादा करीब है
मुझे उम्मीद थी कि लेख सिर्फ गानों को मैनेज और प्ले करने वाले software के बारे में नहीं, बल्कि भौतिक डिवाइस के बारे में भी होगा
कुछ साल पहले मैं अपने 10 साल के बेटे के लिए MP3 player खरीदना चाहता था, जिसे संगीत सुनना बहुत पसंद है लेकिन वह अभी phone इस्तेमाल करने के लिए तैयार नहीं था; विकल्प इतने खराब थे कि मैं हैरान रह गया
मुझे लगता है Apple ने iPod बंद करके एक बड़ा खालीपन बना दिया, जिसे कोई भर नहीं पाया
USB stick के रूप वाला iPod shuffle अब तक इस्तेमाल किए गए सबसे अच्छे MP3 players में से था: छोटा, अलग cable के बिना सीधे लग जाने वाला, और battery भी लंबे समय तक चलती थी
संगीत ब्राउज़ करने के लिए कोई screen नहीं थी, लेकिन यही उसका मकसद था; shuffle पर छोड़ देना था
अफसोस है कि इतना अपेक्षाकृत सरल concept भी hardware market में ठीक से दोहराया नहीं गया
लोग कहेंगे कि यह hardware की समस्या नहीं, software/DRM की समस्या है, लेकिन अच्छे, सस्ते portable music playback devices का न होना वाकई दुखद है
Spotify और smartphone की मौजूदगी ने MP3 players को मार दिया, और दोनों ने market की इतनी जगह घेर ली कि बाकी सबका दम घुट गया
उदाहरण के लिए https://www.fiio.com/cp13 और https://www.fiio.com/jm21 हैं
electronics और “पुराने” devices को फिर से इस्तेमाल में लाना सीखने के लिए यह छोटा educational project भी अच्छा है
बाहरी रूप को customize करने के कई विकल्प हैं, और Bluetooth या USB‑C जोड़ने जैसे गहरे modifications भी संभव हैं
जैसा दूसरों ने कहा, software side भी Windows पर iTunes और macOS में Finder/Music integration के साथ अब भी अच्छी तरह काम करती है
चीनी manufacturers Mini iPhone 16 या Mini S24 जैसे दिखने में अच्छे, music playback करने वाले और smartphone features वाले devices 50~100 dollars में बेच रहे हैं
माता-पिता MP3 player की जगह बच्चों को ऐसे ही devices खरीदकर देने की अधिक संभावना रखते हैं
14 साल के बेटे को phone न देना parenting का conventional तरीका नहीं है, और मैं इसका सम्मान करता हूँ, लेकिन लगता नहीं कि ऐसी demand अभी उपलब्ध supply से ज्यादा है
10 साल के बच्चे के लिए महंगा हो सकता है, लेकिन eBay पर used मिल जाए तो हो सकता है
Music.app से local music manage करना और Finder की iPhone sync इस्तेमाल करना वाला combination अब भी मेरे लिए ठीक काम करता है
हालांकि Music.app ऐसा लगता है जैसे Big Sur के भयानक rewrite के बाद कई सालों से maintain नहीं हुआ है, और इसमें परेशान करने वाले bugs भी हैं
कमियों के बावजूद यह combination मेरे देखे हुए सबसे अच्छे music library management + mobile sync solutions में से है, लेकिन software maintain नहीं हो रहा और cross-platform भी नहीं है, इसलिए आखिरकार शायद मुझे अपना system खुद लिखना पड़ेगा
OS 9 जमाने के निशान, जैसे modal settings/preferences window, सहित iTunes वाली अजीबोगरीब चीजें काफी बची हुई हैं
OS X settings window modal नहीं होनी चाहिए
मुझे अंदाजा है कि वे internally कोई ऐसा version बना रहे होंगे जो शुरुआत से दोबारा बनाया गया हो, जैसे Windows के लिए पूरी तरह नए WinUI-based Music को बनाया गया था
सबसे ज्यादा परेशान करने वाली चीज podcast sync थी; जब iTunes संभालता था तब यह ठीक चलता था, लेकिन Big Sur के Finder sync में bug है, जिससे किसी दूसरे track या podcast पर जाकर वापस आने पर playback position याद नहीं रहती
इसलिए कुछ मिनट से लंबे podcasts device पर practically इस्तेमाल करने लायक नहीं रहते
लोग Android पर जाने के बजाय सच में अपनी music app बना डालते हैं
सोचता हूँ, क्या वजह blue bubbles हैं, या यह कि सब कुछ “बस काम करता है”—offline music playback को छोड़कर
खुद bake करने में क्या दिक्कत है, मुझे समझ नहीं आता
वजह यह थी कि VLC app मेरे file server पर मौजूद FLAC का metadata भरोसेमंद तरीके से parse नहीं कर पाता था, और storage limit के कारण मैं पूरी music collection device पर store भी नहीं कर सकता था
मेरा app prototype है, क्योंकि मुझे और features चाहिए, लेकिन इसमें audio playback, remote file access, और FLAC metadata parsing है, इसलिए यह इतना काम कर जाता है कि extra features implement करने की motivation कम पड़ जाती है
लेखक की तरह, शुरुआत में मैं React Native इस्तेमाल करना चाहता था क्योंकि मेरे पास experience था और कुछ maintained apps भी थीं, लेकिन मैं किसी और platform को target या debug नहीं करना चाहता था
इसलिए मैंने SwiftUI आज़माने का फैसला किया, और एक खास tool[1] से hot reload जैसा कुछ बना लिया
यह काफी गंदा hack है जिसमें Xcode में custom linker flags डालने पड़ते हैं, लेकिन इतना काम करता है कि TypeScript और React Native का developer experience याद नहीं आता
[1] https://github.com/johnno1962/InjectionIII
सच कहूँ तो लेखक को पसंद आने वाला free music app नहीं मिला, यह थोड़ा अजीब लगता है
फिर भी कुछ बनाने के लिए बहाना होना जरूरी नहीं, शायद वह कहानी शुरू करने का narrative रहा हो
चुना हुआ music device पर भी रख सकते हैं
अगर आपके पास offline music collection है, तो https://play.google.com/store/apps/details?id=in.krosbits.mu... की सच में सिफारिश करूंगा
बिना किसी समस्या के बढ़िया काम करता है
Plex, Jellyfin, WebDAV, SMB आदि को भी support करता है