2018-11-14 03:35:48 +00:00
//
2019-04-22 23:01:36 +00:00
// m a i n . s w i f t
// R e a d m e G e n e r a t o r
2018-11-14 03:35:48 +00:00
//
2019-04-22 23:01:36 +00:00
// C r e a t e d b y S e r h i i L o n d a r o n 4 / 2 3 / 1 9 .
// C o p y r i g h t © 2 0 1 9 S e r h i i L o n d a r . A l l r i g h t s r e s e r v e d .
2018-11-14 03:35:48 +00:00
//
import Foundation
let header = " " "
< p align = " center " >
< img src = " ./icons/icon.png " >
</ p >
# Awesome macOS open source applications
< p align = " left " >
< a href = " https://github.com/sindresorhus/awesome " >< img alt = " Awesome " src = " https://cdn.rawgit.com/sindresorhus/awesome/d7305f38d29fed78fa85652e3a63e154dd8e8829/media/badge.svg " /></ a >
< a href = " https://gitter.im/open-source-mac-os-apps/Lobby?utm_source=share-link&utm_medium=link&utm_campaign=share-link " >< img alt = " Join the chat at gitter " src = " https://badges.gitter.im/Join%20Chat.svg " /></ a >
</ p >
2020-07-07 11:29:54 +00:00
List of awesome open source applications for macOS . This list contains a lot of native , and cross - platform apps . The main goal of this repository is to find free open source apps and start contributing . Feel free to [ contribute ] ( CONTRIBUTING . md ) to the list , any suggestions are welcome !
2021-10-16 09:43:03 +00:00
To receive all new or popular applications you can join our [ telegram channel ] ( https : // t . m e / o p e n s o u r c e m a c o s a p p s ) .
2020-10-14 11:01:01 +00:00
2018-11-14 03:35:48 +00:00
# # Support
2019-04-22 23:01:36 +00:00
2018-11-14 03:35:48 +00:00
Hey friend ! Help me out for a couple of : beers : ! < span class = " badge-patreon " >< a href = " https://www.patreon.com/serhiilondar " title = " Donate to this project using Patreon " >< img src = " https://img.shields.io/badge/patreon-donate-yellow.svg " alt = " Patreon donate button " /></ a > </ span >
2019-04-22 23:01:36 +00:00
# # Languages
2018-11-14 03:35:48 +00:00
You can see in which language an app is written . Currently there are following languages :
- ! [ c_icon ] - C language .
- ! [ cpp_icon ] - C ++ language .
- ! [ c_sharp_icon ] - C # language .
- ! [ clojure_icon ] - Clojure language .
- ! [ coffee_script_icon ] - CoffeeScript language .
- ! [ css_icon ] - CSS language .
2018-11-14 19:51:13 +00:00
- ! [ go_icon ] - Go language .
2018-11-14 03:35:48 +00:00
- ! [ elm_icon ] - Elm language .
- ! [ haskell_icon ] - Haskell language .
- ! [ javascript_icon ] - JavaScript language .
- ! [ lua_icon ] - Lua language .
- ! [ objective_c_icon ] - Objective - C language .
- ! [ python_icon ] - Python language .
- ! [ ruby_icon ] - Ruby language .
- ! [ rust_icon ] - Rust language .
2021-10-30 22:40:54 +00:00
- ! [ shell_icon ] - Shell language .
2018-11-14 03:35:48 +00:00
- ! [ swift_icon ] - Swift language .
- ! [ type_script_icon ] - TypeScript language .
# # Contents
- [ Audio ] ( # audio )
- [ Backup ] ( # backup )
- [ Browser ] ( # browser )
- [ Chat ] ( # chat )
- [ Cryptocurrency ] ( # cryptocurrency )
- [ Database ] ( # database )
- [ Development ] ( # development )
2019-04-22 23:01:36 +00:00
- [ Git ] ( # git )
- [ iOS / macOS ] ( # ios -- macos )
- [ JSON Parsing ] ( # json - parsing )
- [ Web development ] ( # web - development )
2019-10-09 08:58:54 +00:00
- [ Other development ] ( # other - development )
2018-11-14 03:35:48 +00:00
- [ Downloader ] ( # downloader )
- [ Editors ] ( # editors )
2019-04-22 23:01:36 +00:00
- [ CSV ] ( # csv )
- [ JSON ] ( # json )
- [ Markdown ] ( # markdown )
- [ TeX ] ( # tex )
- [ Text ] ( # text )
2018-11-14 03:35:48 +00:00
- [ Extensions ] ( # extensions )
- [ Finder ] ( # finder )
- [ Games ] ( # games )
- [ Graphics ] ( # graphics )
- [ IDE ] ( # ide )
- [ Images ] ( # images )
- [ Keyboard ] ( # keyboard )
- [ Mail ] ( # mail )
- [ Menubar ] ( # menubar )
- [ Music ] ( # music )
- [ News ] ( # news )
- [ Notes ] ( # notes )
2019-10-09 08:58:54 +00:00
- [ Other ] ( # other )
2018-11-14 03:35:48 +00:00
- [ Podcast ] ( # podcast )
- [ Productivity ] ( # productivity )
- [ Screensaver ] ( # screensaver )
- [ Security ] ( # security )
- [ Sharing Files ] ( # sharing - files )
- [ Social Networking ] ( # social - networking )
- [ Streaming ] ( # streaming )
- [ System ] ( # system )
- [ Terminal ] ( # terminal )
2019-04-24 10:15:33 +00:00
- [ Touch Bar ] ( # touch - bar )
2018-11-14 03:35:48 +00:00
- [ Utilities ] ( # utilities )
- [ VPN & Proxy ] ( # vpn -- proxy )
- [ Video ] ( # video )
- [ Wallpaper ] ( # wallpaper )
- [ Window Management ] ( # window - management )
# # Applications
" " "
let footer = " " "
# # Contributors
Thanks to all the people who contribute :
< a href = " https://github.com/serhii-londar/open-source-mac-os-apps/graphs/contributors " >< img src = " https://opencollective.com/open-source-mac-os-apps/contributors.svg?width=890&button=false " /></ a >
[ app_store ] : . / icons / app_store - 16. png ' App Store . '
[ c_icon ] : . / icons / c - 16. png ' C language . '
[ cpp_icon ] : . / icons / cpp - 16. png ' C ++ language . '
[ c_sharp_icon ] : . / icons / csharp - 16. png ' C # Language '
[ clojure_icon ] : . / icons / clojure - 16. png ' Clojure Language '
[ coffee_script_icon ] : . / icons / coffeescript - 16. png ' CoffeeScript language . '
[ css_icon ] : . / icons / css - 16. png ' CSS language . '
2018-11-14 19:51:13 +00:00
[ go_icon ] : . / icons / golang - 16. png ' Go language . '
2018-11-14 03:35:48 +00:00
[ elm_icon ] : . / icons / elm - 16. png ' Elm Language '
[ haskell_icon ] : . / icons / haskell - 16. png ' Haskell language . '
[ java_icon ] : . / icons / java - 16. png ' Java language . '
[ javascript_icon ] : . / icons / javascript - 16. png ' JavaScript language . '
[ lua_icon ] : . / icons / Lua - 16. png ' Lua language . '
[ objective_c_icon ] : . / icons / objective - c - 16. png ' Objective - C language . '
[ python_icon ] : . / icons / python - 16. png ' Python language . '
[ ruby_icon ] : . / icons / ruby - 16. png ' Ruby language . '
[ rust_icon ] : . / icons / rust - 16. png ' Rust language . '
2021-10-30 22:40:54 +00:00
[ shell_icon ] : . / icons / shell - 16. png ' Shell language . '
2018-11-14 03:35:48 +00:00
[ swift_icon ] : . / icons / swift - 16. png ' Swift language . '
[ type_script_icon ] : . / icons / typescript - 16. png ' TypeScript language . '
" " "
2019-04-22 23:01:36 +00:00
2018-11-14 03:35:48 +00:00
class JSONApplications : Codable {
let applications : [ JSONApplication ]
enum CodingKeys : String , CodingKey {
case applications
}
init ( applications : [ JSONApplication ] ) {
self . applications = applications
}
required public init ( from decoder : Decoder ) throws {
let values = try decoder . container ( keyedBy : CodingKeys . self )
applications = try values . decodeIfPresent ( [ JSONApplication ] . self , forKey : . applications ) ? ? [ ]
}
}
class JSONApplication : Codable {
var title : String
2019-04-22 23:01:36 +00:00
var iconURL : String
2018-11-14 03:35:48 +00:00
var repoURL : String
var shortDescription : String
var languages : [ String ]
var screenshots : [ String ]
2019-04-22 23:01:36 +00:00
var categories : [ String ]
var officialSite : String
2018-11-14 03:35:48 +00:00
enum CodingKeys : String , CodingKey {
case title
2019-04-22 23:01:36 +00:00
case iconURL = " icon_url "
2018-11-14 03:35:48 +00:00
case repoURL = " repo_url "
case shortDescription = " short_description "
case languages
case screenshots
2019-04-22 23:01:36 +00:00
case categories
case officialSite = " official_site "
2018-11-14 03:35:48 +00:00
}
2019-04-22 23:01:36 +00:00
init ( title : String , iconURL : String , repoURL : String , shortDescription : String , languages : [ String ] , screenshots : [ String ] , categories : [ String ] , officialSite : String ) {
2018-11-14 03:35:48 +00:00
self . title = title
2019-04-22 23:01:36 +00:00
self . iconURL = iconURL
2018-11-14 03:35:48 +00:00
self . repoURL = repoURL
self . shortDescription = shortDescription
self . languages = languages
self . screenshots = screenshots
2019-04-22 23:01:36 +00:00
self . categories = categories
self . officialSite = officialSite
2018-11-14 03:35:48 +00:00
}
}
class Categories : Codable {
let categories : [ Category ]
init ( categories : [ Category ] ) {
self . categories = categories
}
required public init ( from decoder : Decoder ) throws {
let values = try decoder . container ( keyedBy : CodingKeys . self )
categories = try values . decodeIfPresent ( [ Category ] . self , forKey : . categories ) ? ? [ ]
}
}
class Category : Codable {
let title , id , description : String
let parent : String ?
init ( title : String , id : String , description : String , parent : String ? ) {
self . title = title
self . id = id
self . description = description
self . parent = parent
}
}
class ReadmeGenerator {
var readmeString = String . empty
func generateReadme ( ) {
print ( " Start " )
2019-06-02 17:47:24 +00:00
do {
2020-01-07 08:19:03 +00:00
// g e t c u r r e n t f i l e p a t h :
let thisFilePath : String = #file
var url = URL ( fileURLWithPath : thisFilePath )
// c d . . / t o t h e r o o t f o l d e r : ( d e l e t e ` . g i t h u b / m a i n . s w i f t `
url = url . deletingLastPathComponent ( ) . deletingLastPathComponent ( )
let applicationsUrl = url . appendingPathComponent ( FilePaths . applications . rawValue )
let applicationsData = try Data ( contentsOf : applicationsUrl )
let categoriesData = try Data ( contentsOf : url . appendingPathComponent ( FilePaths . categories . rawValue ) )
2019-06-02 17:47:24 +00:00
let jsonDecoder = JSONDecoder ( )
let applicationsObject = try jsonDecoder . decode ( JSONApplications . self , from : applicationsData )
let categoriesObject = try jsonDecoder . decode ( Categories . self , from : categoriesData )
2018-11-14 03:35:48 +00:00
2019-06-02 17:47:24 +00:00
var categories = categoriesObject . categories
let subcategories = categories . filter ( { $0 . parent != nil && ! $0 . parent ! . isEmpty } )
let applications = applicationsObject . applications
2018-11-14 03:35:48 +00:00
for subcategory in subcategories {
2019-06-02 17:47:24 +00:00
if let index = categories . lastIndex ( where : { $0 . parent != subcategory . id } ) {
categories . remove ( at : index )
}
}
categories = categories . sorted ( by : { $0 . title < $1 . title } )
readmeString . append ( header )
print ( " Start iteration.... " )
for category in categories {
readmeString . append ( String . enter + String . section + String . space + category . title + String . enter )
var categoryApplications = applications . filter ( { $0 . categories . contains ( category . id ) } )
2018-11-14 03:35:48 +00:00
categoryApplications = categoryApplications . sorted ( by : { $0 . title < $1 . title } )
for application in categoryApplications {
readmeString . append ( application . markdownDescription ( ) )
readmeString . append ( String . enter )
}
2019-06-02 17:47:24 +00:00
var subcategories = subcategories . filter ( { $0 . parent = = category . id } )
guard subcategories . count > 0 else { continue }
subcategories = subcategories . sorted ( by : { $0 . title < $1 . title } )
for subcategory in subcategories {
readmeString . append ( String . enter + String . subsection + String . space + subcategory . title + String . enter )
var categoryApplications = applications . filter ( { $0 . categories . contains ( subcategory . id ) } )
categoryApplications = categoryApplications . sorted ( by : { $0 . title < $1 . title } )
for application in categoryApplications {
readmeString . append ( application . markdownDescription ( ) )
readmeString . append ( String . enter )
}
}
2018-11-14 03:35:48 +00:00
}
2019-06-02 17:47:24 +00:00
print ( " Finish iteration... " )
readmeString . append ( footer )
2020-01-07 08:19:03 +00:00
try readmeString . data ( using : . utf8 ) ? . write ( to : url . appendingPathComponent ( FilePaths . readme . rawValue ) )
2019-06-02 17:47:24 +00:00
print ( " Finish " )
} catch {
print ( error )
2018-11-14 03:35:48 +00:00
}
}
}
extension String {
static let empty = " "
static let space = " "
static let enter = " \n "
static let section = " ### "
static let subsection = " #### "
2019-04-22 23:01:36 +00:00
static let iconPrefix = " _icon "
2018-11-14 03:35:48 +00:00
}
extension JSONApplication {
func markdownDescription ( ) -> String {
var markdownDescription = String . empty
var languages : String = String . empty
for lang in self . languages {
2018-12-27 14:13:37 +00:00
languages . append ( " ![ \( lang ) \( String . iconPrefix ) ] " )
2018-11-14 03:35:48 +00:00
}
markdownDescription . append ( " - [ \( self . title ) ]( \( self . repoURL ) ) - \( self . shortDescription ) \( languages ) " )
2019-03-22 00:14:15 +00:00
/*
2019-04-22 23:01:36 +00:00
if self . screenshots . count > 0 {
var screenshotsString = String . empty
screenshotsString += ( String . space + Constants . detailsBeginString + String . space )
self . screenshots . forEach ( {
screenshotsString += ( String . space + ( NSString ( format : Constants . srcLinePattern as NSString , $0 as CVarArg ) as String ) + String . space )
} )
screenshotsString += ( String . space + Constants . detailsEndString + String . space )
markdownDescription . append ( screenshotsString )
}
*/
2018-11-14 03:35:48 +00:00
return markdownDescription
}
}
enum FilePaths : String {
2018-11-14 23:25:44 +00:00
case readme = " ./README.md "
case applications = " ./applications.json "
case categories = " ./categories.json "
2018-11-14 03:35:48 +00:00
}
struct Constants {
static let detailsBeginString = " <details> <summary> Screenshots </summary> <p float= \" left \" > "
static let detailsEndString = " </p></details> "
static let srcLinePattern = " <bt><img src='%@' width= \" 400 \" /> "
static let startProcessString = " ### Database "
static let endProcessString = " ### Development "
static func regex ( for type : String ) -> String {
return " \\ ((.+ \\ . \( type ) ) "
}
static func regex1 ( for type : String ) -> String {
return " \\ \" (.+ \\ . \( type ) ) "
}
}
ReadmeGenerator ( ) . generateReadme ( )
2019-04-22 23:01:36 +00:00