{"id":51248987,"url":"https://github.com/korchasa/open-link-in","last_synced_at":"2026-06-29T06:04:25.226Z","repository":{"id":365329343,"uuid":"1271616484","full_name":"korchasa/open-link-in","owner":"korchasa","description":"Smart Links Opener — macOS default-browser router: open links per-domain in different browsers. Open source (GPLv3); paid build on the Mac App Store.","archived":false,"fork":false,"pushed_at":"2026-06-16T21:13:33.000Z","size":990,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-16T23:09:40.644Z","etag":null,"topics":["appkit","browser-picker","default-browser","macos","open-source","swift","swiftui"],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/korchasa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-06-16T21:03:20.000Z","updated_at":"2026-06-16T21:14:07.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/korchasa/open-link-in","commit_stats":null,"previous_names":["korchasa/open-link-in"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/korchasa/open-link-in","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/korchasa%2Fopen-link-in","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/korchasa%2Fopen-link-in/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/korchasa%2Fopen-link-in/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/korchasa%2Fopen-link-in/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/korchasa","download_url":"https://codeload.github.com/korchasa/open-link-in/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/korchasa%2Fopen-link-in/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34915020,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["appkit","browser-picker","default-browser","macos","open-source","swift","swiftui"],"created_at":"2026-06-29T06:04:24.299Z","updated_at":"2026-06-29T06:04:25.218Z","avatar_url":"https://github.com/korchasa.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Smart Links Opener\n\n[![License: GPL v3](https://img.shields.io/badge/License-GPLv3-blue.svg)](LICENSE)\n[![CI](https://github.com/korchasa/open-link-in/actions/workflows/ci.yml/badge.svg)](.github/workflows/ci.yml)\n\n\u003e Релизы в Mac App Store автоматизированы через GitHub Actions: пуш тега `vX.Y.Z`\n\u003e собирает песочничную сборку, подписывает и загружает её в App Store Connect.\n\u003e Первоначальная настройка (сертификаты, ключи, секреты) — см.\n\u003e [`documents/tasks/2026/06/appstore-cicd-setup.md`](documents/tasks/2026/06/appstore-cicd-setup.md).\n\nМинималистичное macOS-приложение, которое работает как браузер по умолчанию и\nоткрывает каждую ссылку в нужном браузере в зависимости от домена. Если правило\nдля домена не найдено — показывает выбор среди установленных браузеров с\nвозможностью сразу создать правило.\n\nНаписано на SwiftUI/AppKit (стандартный нативный стек macOS), без сторонних\nзависимостей.\n\n## Открытый код и сборка в App Store\n\nПроект **с открытым исходным кодом под GPL-3.0-or-later** — код можно изучать,\nменять и распространять (с сохранением открытости форков).\n\n- **Собрать бесплатно из исходников:** `./build.sh` (см. ниже). Полностью\n  функциональная версия.\n- **Купить в Mac App Store (~$3 / €3):** официальная подписанная и нотаризованная\n  сборка с автообновлением и в песочнице. Это удобство и способ поддержать\n  разработку — функциональность та же.\n\nТак как GPL несовместима с условиями Mac App Store, сторонние форки, как правило,\nне могут попасть в App Store; официальную платную сборку публикует автор как\nправообладатель (стандартное исключение для правообладателя — ваши права на код\nпо GPL это не ограничивает). Подробности — в `CONTRIBUTING.md`.\n\nДве конфигурации сборки:\n- `./build.sh prod` — открытая сборка, подпись Developer ID, Hardened Runtime, без\n  песочницы (распространение вне App Store: DMG/zip).\n- `./build.sh appstore` — сборка для Mac App Store с включённым App Sandbox.\n  Playbook публикации: `documents/tasks/2026/06/open-source-and-appstore.md`.\n\n## Возможности\n\n- Регистрируется в системе как веб-браузер (схемы `http`/`https`).\n- **Работает в фоне как агент** (`LSUIElement`): без иконки в Dock, управление\n  через иконку в строке меню. Совпавшие по правилу ссылки открываются мгновенно\n  и без окон, не перехватывая фокус.\n- Маршрутизация по доменам: правило `домен → браузер`, выигрывает самое длинное\n  совпадение (`bbc.co.uk` важнее `co.uk`).\n- **Поддержка субдоменов**: правило хранит домен второго уровня (`mail.google.com`\n  → `google.com`), и все его субдомены открываются в выбранном браузере.\n  Составные публичные суффиксы учитываются (`news.bbc.co.uk` → `bbc.co.uk`,\n  `user.github.io` → `user.github.io`). Префикс `www.` игнорируется.\n- При отсутствии правила — окно выбора браузера с галочкой «Запомнить выбор».\n- Окно управления правилами: добавление, смена браузера, удаление.\n- Кнопка «Сделать браузером по умолчанию» (системный API с диалогом согласия).\n- **Автозапуск при входе** через `SMAppService` (современный API Apple).\n- **Автоматическая интернационализация**: язык интерфейса выбирается системой\n  (10 языков: en, ru, uk, de, fr, es, it, pt-BR, ja, zh-Hans).\n- Список браузеров берётся из LaunchServices (реально установленные приложения).\n\n## Фоновый режим и иконка в строке меню\n\nПосле запуска приложение не показывает иконку в Dock — оно живёт в строке меню\n(значок «🔗»). Через меню доступны: «Правила…», переключатель браузера по\nумолчанию, «Запускать при входе» и «Выйти». Окно правил можно открыть в любой\nмомент из этого меню; закрытие окна не выгружает агента.\n\n## Соответствие требованиям Apple\n\n- Только публичные API: `NSWorkspace`, LaunchServices (через `NSWorkspace`),\n  `ServiceManagement`, Apple Events (`kAEGetURL`). Приватные/устаревшие вызовы\n  убраны.\n- Агент-приложение объявлено через `LSUIElement` и `NSApplication`\n  `.accessory` activation policy.\n- Сборка подписывается с **Hardened Runtime** (`--options runtime`).\n- App Sandbox намеренно не включается: маршрутизатор браузеров по своей сути\n  перечисляет и запускает произвольные приложения, что песочница запрещает.\n  Штатный путь распространения такой утилиты — подпись **Developer ID** и\n  **нотаризация** (вне Mac App Store).\n\n## Сборка\n\n```bash\n./build.sh\n```\n\nСкрипт компилирует релизную сборку, собирает `SmartLinksOpener.app`, подписывает\nad-hoc подписью и регистрирует бандл в LaunchServices.\n\n## Установка как браузера по умолчанию\n\n1. `open SmartLinksOpener.app` (или перенесите в `/Applications` и запустите).\n2. В окне приложения нажмите **«Сделать браузером по умолчанию»**.\n   macOS покажет системный запрос на подтверждение — подтвердите.\n   Либо вручную: *Системные настройки → Рабочий стол и Dock → Веб-браузер по\n   умолчанию → Smart Links Opener*.\n\nПосле этого любой клик по ссылке вне браузера попадёт в Smart Links Opener,\nкоторый мгновенно перенаправит её в нужный браузер либо предложит выбрать.\n\n## Как это устроено\n\n- `App.swift` — точка входа (`SwiftUI.App`), ловит входящие ссылки через\n  `.onOpenURL`.\n- `AppStore.swift` — состояние: список браузеров, правила (хранятся в\n  `UserDefaults`), сопоставление домена с браузером, открытие ссылки в\n  конкретном приложении через `NSWorkspace`.\n- `Domain.swift` — чистая логика доменов: сворачивание хоста до домена второго\n  уровня (registrable domain, eTLD+1) и проверка поддоменного совпадения.\n  Покрыта юнит-тестами (`Tests/SmartLinksOpenerTests/DomainTests.swift`).\n- `PickerView.swift` — окно выбора браузера для нового домена.\n- `RulesView.swift` — окно управления правилами и статусом браузера по умолчанию.\n- `Resources/Info.plist` — объявляет `CFBundleURLTypes` со схемами `http`/`https`,\n  благодаря чему система видит приложение как браузер.\n\n## Интернационализация\n\nСтроки интерфейса заданы английскими ключами (`LocalizedStringKey` /\n`String(localized:)`), а переводы лежат в `Resources/\u003cязык\u003e.lproj/Localizable.strings`.\nmacOS автоматически подбирает язык по настройкам системы; при отсутствии перевода\nиспользуется английская база (`CFBundleDevelopmentRegion = en`).\n\nДобавить язык: создайте `Resources/\u003cкод\u003e.lproj/Localizable.strings` (скопируйте\nключи из `en.lproj`), добавьте код в `CFBundleLocalizations` в `Resources/Info.plist`\nи пересоберите. Тексты-данные (домены, имена браузеров) не локализуются —\nв коде они выводятся через `Text(verbatim:)`.\n\n## Распространение\n\nДля локального запуска достаточно ad-hoc подписи (`./build.sh`).\n\n**Вне App Store (Developer ID + нотаризация):**\n\n```bash\n./build.sh prod\ncodesign --force --options runtime \\\n    --entitlements Resources/SmartLinksOpener.entitlements \\\n    --sign \"Developer ID Application: ВАШЕ ИМЯ (TEAMID)\" SmartLinksOpener.app\nxcrun notarytool submit SmartLinksOpener.app --keychain-profile \"AC\" --wait\nxcrun stapler staple SmartLinksOpener.app\n```\n\n**Mac App Store (платная сборка, App Sandbox):** полный playbook — в\n`documents/tasks/2026/06/open-source-and-appstore.md`. Кратко:\n\n```bash\nMAS_APP_IDENTITY=\"Apple Distribution: ВАШЕ ИМЯ (TEAMID)\" \\\nMAS_PROVISION_PROFILE=./SmartLinksOpener_MAS.provisionprofile \\\n  ./build.sh appstore\nproductbuild --component SmartLinksOpener-AppStore.app /Applications \\\n    --sign \"3rd Party Mac Developer Installer: ВАШЕ ИМЯ (TEAMID)\" SmartLinksOpener.pkg\nxcrun altool --upload-app -f SmartLinksOpener.pkg -t macos \\\n    --apiKey \u003cKEY_ID\u003e --apiIssuer \u003cISSUER_ID\u003e   # или Transporter.app\n```\n\nАвтозапуск (`SMAppService`) надёжно работает только для подписанного приложения,\nлежащего в `/Applications`.\n\n## Замечания\n\n- Идентификатор бандла: `dev.korchasa.SmartLinksOpener` (меняется в\n  `Resources/Info.plist`).\n- App Store-сборка в песочнице хранит правила в контейнере приложения\n  (`~/Library/Containers/dev.korchasa.SmartLinksOpener/…`), отдельно от открытой\n  Developer ID-сборки — это ожидаемо.\n\n## Лицензия\n\nCopyright © 2026 korchasa.\n\nLicensed under the GNU General Public License v3.0 or later (GPL-3.0-or-later) —\nsee [LICENSE](LICENSE). Вклад в проект — см. [CONTRIBUTING.md](CONTRIBUTING.md).\nКонфиденциальность — [PRIVACY.md](PRIVACY.md) (данные не собираются).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkorchasa%2Fopen-link-in","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkorchasa%2Fopen-link-in","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkorchasa%2Fopen-link-in/lists"}