dyerc / doughnut Goto Github PK
View Code? Open in Web Editor NEWPodcast client (podcatcher) for Mac
Home Page: https://doughnutapp.com
License: GNU General Public License v3.0
Podcast client (podcatcher) for Mac
Home Page: https://doughnutapp.com
License: GNU General Public License v3.0
Hi, it would be nice to select multiple episodes of a podcast, for example, to mark them as un/played. I honestly don't want to right click on 400+ entries of a single podcast to mark them all played. The contrary (mark all played and then only selected unplayed) is also not favorable as it would still mean to mark 100 episodes as unplayed. :/
While listening to podcasts with Doughnut I noticed that after some time I get a prompt from OSX to quit an application because there is no memory left for other apps.
The app that used up all the RAM was Doughnut with incredible ~50 GB. Most of it was in swap memory.
The screenshot below show the high RAM usage.
While making this post it grew to ~20 GB.
A download can be queued multiple times
Version 1.1.1 - High sierra
Each time I choose "check manually" in preference, it save this choice, I can see it if I come back to the preference.
Then when I restart the app and go to preference, "check manually" have been replace with "---------------------" the line on the top of "check manually".
When this "---------------------" is selected it seems the feeds refresh very very often.
Maybe a solution for this is to delete the "---------------------" from the list.
In new beta version (Version 2.0.0.beta1 (84)) the views and logic have been somewhat change to be less dynamic (which was intentional AFAIR and in general it's good) - for example when episode finishes playing the feed and the episode stays there. But there is another issue - if we have filtered feeds view with "new episodes" and in the meantime there would a be a new episode in a feed that previously didn't have any feeds that means it won't show up until "new episodes" filter is disabled and re-enabled (and considering it now requires lots more clicks it's kinda cumbersome)
I think a dedicated homepage can be build for Doughnut and GitHub Pages can be an ideal hosting option.
The homepage can be used to introduce main features of Doughnut, guide users to download and serve static files like appcast.xml
. Currently we serve appcast.xml
with raw.githubusercontent.com
, which has a rate limit and doesn't go through CDN.
I sync an OPML file between my Android phone and my macOS laptop, but I had to manually copy-paste the feed URLs of my subscriptions when setting up Doughnut. Would be nice to have an option to import an OPML file in the future.
And for users who wish to backup or migrate to other software, an export option would also be nice.
For users listening with Bluetooth headphones or speakers, or with AirPlay devices such as the HomePod. It helps with a button to switch the playback back and forth between those connected devices and the internal speaker.
Based on observation it seems that feeds are updated sequentially, which takes some time with rather long list of subscriptions. Doing it concurrently should speed up the process.
Expected results:
The operations are slow to be responded.
Actual results:
The played(or starred) status should be updated immediately.
Use case: If I found a bunch of podcasts I want to subscribe to, it would be cool to have a large plain-text field to paste all the feed URLs into and one button to subscribe to all of them. Additionally it could serve as a format-agnostic alternative to #11.
Podcasting services rely heavily on User-Agent
header to serve best-suited audio format and for analytics. The Open Podcast Analytics Working Group (OPAWG) maintains lists of audio user agents and RSS user agents. While it's technically possible to customize the user agents for various components of Doughnut. This issue serves as a thread to discuss the proper format for the user agent of Doughnut.
Some resources of best practises of user agents:
Update Aug.28:
Since we have a website for Doughnut, it's better to include the site URL like how Overcast does.
Update Jul.12:
Here's the examples of current (default) user agents of Doughnut:
URLSession
requests: Doughnut/1656606889 CFNetwork/1385 Darwin/22.0.0
WKWebView
: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Doughnut
AppleCoreMedia/1.0.0.22A5295h (Macintosh; U; Intel Mac OS X 13_0; zh_cn)
After examining user agents from various podcast clients, the above user agents should be acceptable (can be identified from the keyword Doughnut
) except for media playback.
PR #92 implements a distinguishable user agent for Player
in the following format:
Doughnut/x.y.z.build (+https://doughnutapp.com/; Podcast Client; macOS Version x.y.x (Build xxxxxx))
Example:
Doughnut/2.0.0-rc.1.1653423049 (+https://doughnutapp.com/; Podcast Client; macOS Version 13.0 (Build 22A5295h))
Doughnut/x.y.z.build CFNetwork/x.y.z Darwin/x.y.z (arch)
for URLSession
requests of audio downloads, feeds and images.
Example: Doughnut/2.0.0.1654319012 CFNetwork/1333.0.4 Darwin/21.5.0 (arm64)
AppleCoreMedia/x.y.z.build (Macintosh; U; Intel Mac OS X x_y; lang) Doughnut/x.y.z.build.arch
(same prefix for AVPlayer
, but with Doughnut version postfix) for audio streaming.
Example: AppleCoreMedia/1.0.0.21F79 (Macintosh; U; Intel Mac OS X 12_4; en_us) Doughnut/2.0.0.1654319012.arm64
Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/x.y.z (KHTML, like Gecko) Doughnut/x.y.z.build.arch
(same prefix for WKWebView
, but with Doughnut version postfix) for the webView.
Example: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Doughnut/2.0.0.1654319012.arm64
Feel free to share your ideas :-).
Newly fetched episodes appears in the list but clicking on play has no effect and disappears once Doughnut is restarted.
Currently batch actions (e.g. marking multiple episodes as played or favorite) can cause significant performance issues with a large scale of items. These actions should be implemented with bulk database UPDATE
operations.
Currently we know what's the episode's length only once we start playing. It would be nice to have this info displayed for all episodes. From what I can see the information is enclosed in <itunes:duration/>
Needs further investigation
Would be really awesome. The iTunes user experience of queuing serves as a good model, where there are context menu options for both queuing episodes “up next” and to the bottom of the queue.
It would be great if Doughnut could synchronise with gpodder API (either gpodder.net or nextcloud implementation: https://github.com/thrillfall/nextcloud-gpodder)
#56 introduced more static list (to maintain selection and to avoid feeds disappearing once everything is played I guess) it kinda breaks the list if you have empty list and then some feeds get updated - instead of having the list ordered by number of unplayed episodes the feeds with new episodes stay as they are thus without scrolling the list it's hard to know that something new appeared.
What's more, I think that filtered view is also broken - if we are in that view feeds with new episodes aren't added/displayed without toggling the filtering off/on again.
It would be nice if feed list / episode list filtering/toggle (all/updated) would be remembered across restarts.
Self-explanatory. All media players have it, I was surprised that media keys work but not Spacebar
.
Currently the only options to navigate through the episode is to either drag the slider or use skip/rewind options. It would be handy to have "Jump to time" option as well for the moments when we started listening episode on, for example, mobile phone (no synchronisation).
Some feeds also include chapters with timestamps, for example https://anchor.fm/s/13a6bdec/podcast/rss:
<item>
<title><![CDATA[Raport o stanie świata - 18 marca 2022]]></title>
<description><![CDATA[<p>Już ponad trzy tygodnie trwa inwazja Rosji na Ukrainę. Dziś zaatakowane zostały cele w okolicach Lwowa. Cały czas trwa oblężenie Mariupola, ostrzał Charkowa, Kijowa i wielu innych ukraińskich miast. Flota rosyjska przemieszcza się w kierunku Odessy. Rosjanie atakują cele cywilne, szpitale, szkoły, budynki mieszkalne, ale nie osiągają znaczących sukcesów w żadnym kierunku uderzenia. Prezydent Wołodymyr Zełenski wygłosił serię przemówień w parlamentach krajów zachodnich: USA, Kanady, Niemiec, Polski, Wielkiej Brytanii. Brytyjski dziennik Financial Times opublikował plan rosyjsko-ukraińskich rozmów pokojowych, władze Ukrainy zaprzeczają jakoby były gotowe na jakiekolwiek ustępstwa.</p>
<p>Iran wypuścił na wolność dwoje obywateli brytyjskich przetrzymywanych od lat pod zarzutem działalności antypaństwowej. Trwają negocjacje z Iranem w sprawie zniesienia sankcji i z Arabią Saudyjską w sprawie zwiększenia wydobycia ropy.</p>
<p>Czy Rosja szykuje się do użycia broni chemicznej i biologicznej w Ukrainie?</p>
<p>Wielkie instytucje kultury na świecie zrywają kontakty z artystami rosyjskimi. Czy bojkot kulturalny Rosji ma sens?</p>
<p>Opowiemy również o laureacie najważniejszej nagrody w światowej architekturze, którym w tym roku został po raz pierwszy Afrykanin.</p>
<p>I o przeszłości, którą politycy chcieliby wymazać, ale to nie takie proste.</p>
<p>Rozkład jazdy:</p>
<p>(2:38) Żadan i Sobaki - Автозак</p>
<p>(6:06) Wojciech Konończuk podsumowuje 3 tygodnie wojny w Ukrainie</p>
<p>(29:39) Łukasz Fyderek o negocjacjach z Iranem</p>
<p>(52:27) Kalusz, Skofka - Додому</p>
<p>(56:02) Świat z boku - Grzegorz Dobiecki o przeszłości polityków</p>
<p>(1:01:06) Podziękowania</p>
<p>(1:05:52) Anna Dudzińska o laureacie nagrody Pritzkera</p>
<p>(1:16:33) Piotr Kamiński o bojkocie kulturalnym Rosji</p>
<p>(1:43:51) Tomasz Rożek o broniach chemicznych i biologicznych</p>
<p>(1:58:46) Do usłyszenia</p>
<p>(1:59:10) The Hardkiss - Żiwa</p>
]]></description>
<link>https://anchor.fm/dariusz-rosiak/episodes/Raport-o-stanie-wiata---18-marca-2022-e1ftm92</link>
<guid isPermaLink="false">ebbe703c-a684-4487-a3ab-5a3a5d73b7e4</guid>
<dc:creator><![CDATA[Dariusz Rosiak]]></dc:creator>
<pubDate>Fri, 18 Mar 2022 18:20:11 GMT</pubDate>
<enclosure url="https://anchor.fm/s/13a6bdec/podcast/play/49256162/https%3A%2F%2Fd3ctxlq1ktw2nl.cloudfront.net%2Fstaging%2F2022-2-18%2F254568507-44100-2-6d2928bca1622.m4a" length="119563857" type="audio/x-m4a"/>
<itunes:summary><p>Już ponad trzy tygodnie trwa inwazja Rosji na Ukrainę. Dziś zaatakowane zostały cele w okolicach Lwowa. Cały czas trwa oblężenie Mariupola, ostrzał Charkowa, Kijowa i wielu innych ukraińskich miast. Flota rosyjska przemieszcza się w kierunku Odessy. Rosjanie atakują cele cywilne, szpitale, szkoły, budynki mieszkalne, ale nie osiągają znaczących sukcesów w żadnym kierunku uderzenia. Prezydent Wołodymyr Zełenski wygłosił serię przemówień w parlamentach krajów zachodnich: USA, Kanady, Niemiec, Polski, Wielkiej Brytanii. Brytyjski dziennik Financial Times opublikował plan rosyjsko-ukraińskich rozmów pokojowych, władze Ukrainy zaprzeczają jakoby były gotowe na jakiekolwiek ustępstwa.</p>
<p>Iran wypuścił na wolność dwoje obywateli brytyjskich przetrzymywanych od lat pod zarzutem działalności antypaństwowej. Trwają negocjacje z Iranem w sprawie zniesienia sankcji i z Arabią Saudyjską w sprawie zwiększenia wydobycia ropy.</p>
<p>Czy Rosja szykuje się do użycia broni chemicznej i biologicznej w Ukrainie?</p>
<p>Wielkie instytucje kultury na świecie zrywają kontakty z artystami rosyjskimi. Czy bojkot kulturalny Rosji ma sens?</p>
<p>Opowiemy również o laureacie najważniejszej nagrody w światowej architekturze, którym w tym roku został po raz pierwszy Afrykanin.</p>
<p>I o przeszłości, którą politycy chcieliby wymazać, ale to nie takie proste.</p>
<p>Rozkład jazdy:</p>
<p>(2:38) Żadan i Sobaki - Автозак</p>
<p>(6:06) Wojciech Konończuk podsumowuje 3 tygodnie wojny w Ukrainie</p>
<p>(29:39) Łukasz Fyderek o negocjacjach z Iranem</p>
<p>(52:27) Kalusz, Skofka - Додому</p>
<p>(56:02) Świat z boku - Grzegorz Dobiecki o przeszłości polityków</p>
<p>(1:01:06) Podziękowania</p>
<p>(1:05:52) Anna Dudzińska o laureacie nagrody Pritzkera</p>
<p>(1:16:33) Piotr Kamiński o bojkocie kulturalnym Rosji</p>
<p>(1:43:51) Tomasz Rożek o broniach chemicznych i biologicznych</p>
<p>(1:58:46) Do usłyszenia</p>
<p>(1:59:10) The Hardkiss - Żiwa</p>
</itunes:summary>
<itunes:explicit>No</itunes:explicit>
<itunes:duration>7392</itunes:duration>
<itunes:image href="https://d3t3ozftmdmh3i.cloudfront.net/production/podcast_uploaded_episode/3196947/3196947-1647627042217-cf1f93722ef2c.jpg"/>
<itunes:episodeType>full</itunes:episodeType>
</item>
And some applications (AntenaPod on android) allows clicking on the timestamp to jump directly to that position.
Doughnut is currently a pure Swift project. Migrating from CocoaPods to Swift Package Manager can make the project significantly easier to maintain. The migration can help new contributors to get started rapidly since new developers to Apple platforms may not be familiar with CocoaPods setup.
I just tested new beta version and I ran "into issue" and I think this is the change that introduced it. Previously it was possibly to quickly toggle between view with feeds with new episodes and all feeds, currently this is hidden behind menu at the bottom (which also has filter sub-menu) but instead of single click (to get list only with updated feeds) one has to click on the icon and then navigate to submenu and select "new episodes". Having this handy (or at leasts sticky/remembered between restarts) would be convenient.
Originally posted by @woj-tek in #49 (comment)
Expected results: I would expect that Doughnut would jump playback to that position
Actual results: the progress indicator jumps to clicked position but then immediately jumps back to previous one without changing playback location.
Doughnut 1.0.2 (8), macOS 10.14.3 (18D109)
I tried clicking an episode twice to play it, and this happened. Once the episodes start playing, I am only able to stop playing one instance.
Current behavior: The Download option (⌘L) is disabled when multiple episodes are selected.
Desired behavior: The Download option (⌘L) is enabled when multiple episodes are selected and downloads all selected episodes.
With lots of podcast subscriptions and library based on a networked drive, writes to the database can be quite delayed from UI state
Deleting when Move to Trash isn't available. 'permanently delete' eg. on shared storage
Currently a binary of MPV is bundled with Doughnut and used to actually play media files from a stream or locally. This issue tracks the thought process of whether that is a good or bad idea. At the very least, in the future I would like to prune the MPV build so that it only includes required codecs.
The all will crash on the first launch. I clicked on "default library" (as I do not have one yet) and the app immediatelly crashed because it could not find the library file (.dnl in ~/Music/Doughnut/). The second launch seems to work fine. I guess the library file gets created after the first check. Maybe a concurrency or logical execution issue?
In the spirit of HTTPS Everywhere, it would be advantageous to have http://
URLs for podcast feeds (when subscribing initially), artwork, and episode downloads be automatically rewritten to https://
. Then if that fails (e.g. if the domain does not have HTTPS enabled), Doughnut falls back to http://
.
HTTPS helps hide some information from internet service providers and others who may be monitoring network activity and blocking certain websites.
Really enjoying the simple to use Electron version (iTunes way too bloated for me right now) and was going to try the Swift version. Had some few problems. When I run "pod install" this happens:
Analyzing dependencies
Pre-downloading: `FeedKit` from `https://github.com/CD1212/FeedKit.git`
[!] Unable to find a specification for `GRDB.swift`
[!] Automatically assigning platform osx with version 10.12 on target Doughnut because no platform was specified. Please specify a platform for this target in your Podfile. See `https://guides.cocoapods.org/syntax/podfile.html#platform`.
I've updated CocoaPods and everything. When I tried building the app in Xcode, I got these 3 errors:
diff: /Podfile.lock: No such file or directory
diff: /Manifest.lock: No such file or directory
error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.
Any help would be great. Thanks!
Using OSLog
framework instead of print
statements improves logging performance and better supports debugging and analysis.
The app could benefit of keyboard shortcuts. E.g., one I am missing is to add a new podcast subscription (preferably ⌘N as ⌘S is reserved for save). Adding a non-subscription podcast could be ⌘⇧N. Also, I tried to close the settings window with ⌘W, which also didn't work. I assume there are countless other instances where my workflow would be stopped by missing support for shortcuts (e.g., ⌘i for podcast info, ⌫ or ⌘⌫ to delete/unsubscribe of a feed, etc.).
1.0.2 (8), 10.14.3 (18D109)
Not sure if it’s a bug or missing feature.
Menu list appears and items should be disabled.
Doughnut crashes with index out of range at EpisodeViewController.swift line 222.
Bound check before setting the value to episode
constant.
N/A
Backtrace:
(lldb) bt
* thread #1, queue = 'com.apple.main-thread', stop reason = Fatal error: Index out of range
frame #0: 0x00007fff2ca4d890 libswiftCore.dylib`_swift_runtime_on_report
frame #1: 0x00007fff2cac7ef3 libswiftCore.dylib`_swift_stdlib_reportFatalErrorInFile + 211
frame #2: 0x00007fff2c757030 libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 480
frame #3: 0x00007fff2c756b87 libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 87
frame #4: 0x00007fff2c756863 libswiftCore.dylib`closure #1 (Swift.UnsafeBufferPointer<Swift.UInt8>) -> () in Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 99
frame #5: 0x00007fff2c7564d1 libswiftCore.dylib`Swift._assertionFailure(_: Swift.StaticString, _: Swift.StaticString, file: Swift.StaticString, line: Swift.UInt, flags: Swift.UInt32) -> Swift.Never + 513
frame #6: 0x00007fff2c738429 libswiftCore.dylib`Swift._ArrayBuffer._checkInoutAndNativeTypeCheckedBounds(_: Swift.Int, wasNativeTypeChecked: Swift.Bool) -> () + 249
frame #7: 0x00007fff2c73d14e libswiftCore.dylib`Swift.Array.subscript.getter : (Swift.Int) -> A + 78
* frame #8: 0x0000000109a2e8f5 Doughnut`EpisodeViewController.validateMenuItem(menuItem=0x0000600003f75d50, self=0x0000600002374370) at EpisodeViewController.swift:222:27
frame #9: 0x0000000109a2f4f4 Doughnut`@objc EpisodeViewController.validateMenuItem(_:) at <compiler-generated>:0
frame #10: 0x00007fff22e3ac5a AppKit`-[NSMenu _enableItem:] + 634
frame #11: 0x00007fff22f87fe3 AppKit`-[NSCarbonMenuImpl _carbonUpdateStatusEvent:handlerCallRef:] + 437
frame #12: 0x00007fff22f6e409 AppKit`NSSLMMenuEventHandler + 889
frame #13: 0x00007fff286a84a0 HIToolbox`DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 1431
frame #14: 0x00007fff286a7879 HIToolbox`SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 329
frame #15: 0x00007fff286bd18a HIToolbox`SendEventToEventTarget + 39
frame #16: 0x00007fff2871d0d7 HIToolbox`SendHICommandEvent(unsigned int, HICommand const*, unsigned int, unsigned int, unsigned char, void const*, OpaqueEventTargetRef*, OpaqueEventTargetRef*, OpaqueEventRef**) + 368
frame #17: 0x00007fff2872cea8 HIToolbox`UpdateHICommandStatusWithCachedEvent + 51
frame #18: 0x00007fff286a3ac6 HIToolbox`HIApplication::EventHandler(OpaqueEventHandlerCallRef*, OpaqueEventRef*, void*) + 2574
frame #19: 0x00007fff286a84a0 HIToolbox`DispatchEventToHandlers(EventTargetRec*, OpaqueEventRef*, HandlerCallRec*) + 1431
frame #20: 0x00007fff286a7879 HIToolbox`SendEventToEventTargetInternal(OpaqueEventRef*, OpaqueEventTargetRef*, HandlerCallRec*) + 329
frame #21: 0x00007fff286bd18a HIToolbox`SendEventToEventTarget + 39
frame #22: 0x00007fff2885526e HIToolbox`SendEnableMenu(OpaqueEventTargetRef*, OpaqueMenuRef*, double, unsigned char, unsigned int) + 156
frame #23: 0x00007fff2872c977 HIToolbox`SendMenuOpening(MenuSelectData*, MenuData*, double, unsigned int, unsigned int, __CFDictionary*, unsigned char, unsigned char*) + 599
frame #24: 0x00007fff288534a9 HIToolbox`PopUpMenuSelectCore(MenuData*, Point, double, Point, unsigned short, unsigned int, unsigned int, Rect const*, unsigned short, unsigned int, Rect const*, Rect const*, __CFDictionary const*, __CFString const*, OpaqueMenuRef**, unsigned short*) + 835
frame #25: 0x00007fff28852c7a HIToolbox`_HandlePopUpMenuSelection8(OpaqueMenuRef*, OpaqueEventRef*, unsigned int, Point, unsigned short, unsigned int, unsigned int, Rect const*, unsigned short, Rect const*, Rect const*, __CFDictionary const*, __CFString const*, OpaqueMenuRef**, unsigned short*) + 410
frame #26: 0x00007fff28724db9 HIToolbox`_HandlePopUpMenuSelectionWithDictionary + 329
frame #27: 0x00007fff23134ede AppKit`SLMPerformPopUpCarbonMenu + 2223
frame #28: 0x00007fff22fd0e19 AppKit`_NSSLMPopUpCarbonMenu3 + 1096
frame #29: 0x00007fff23072f7d AppKit`-[NSCarbonMenuImpl _popUpContextMenu:withEvent:forView:withFont:] + 208
frame #30: 0x00007fff23072e09 AppKit`-[NSMenu _popUpContextMenu:withEvent:forView:withFont:] + 209
frame #31: 0x00007fff234fad66 AppKit`-[NSView _showMenuForEvent:] + 85
frame #32: 0x00007fff2306cfbb AppKit`-[NSView rightMouseDown:] + 100
frame #33: 0x00007fff2319907b AppKit`-[NSControl _rightMouseUpOrDown:] + 493
frame #34: 0x00007fff22df2f58 AppKit`-[NSWindow(NSEventRouting) _reallySendEvent:isDelayedEvent:] + 6482
frame #35: 0x00007fff22df13ea AppKit`-[NSWindow(NSEventRouting) sendEvent:] + 347
frame #36: 0x00007fff22df012a AppKit`-[NSApplication(NSEvent) sendEvent:] + 2742
frame #37: 0x00000001099d9fca Doughnut`DoughnutApp.sendEvent(event=0x0000600002163180, self=0x00007fdf405055a0) at DoughnutApp.swift:44:11
frame #38: 0x00000001099da094 Doughnut`@objc DoughnutApp.sendEvent(_:) at <compiler-generated>:0
frame #39: 0x00007fff230c836e AppKit`-[NSApplication _handleEvent:] + 65
frame #40: 0x00007fff22c58b2f AppKit`-[NSApplication run] + 623
frame #41: 0x00007fff22c2cdf2 AppKit`NSApplicationMain + 816
frame #42: 0x0000000109a37cbd Doughnut`main at AppDelegate.swift:23:7
frame #43: 0x00007fff2036f621 libdyld.dylib`start + 1
frame #44: 0x00007fff2036f621 libdyld.dylib`start + 1
N/A
Expected results:
I should go back 5 seconds
Actual results:
I'm taken back 15 seconds (i.e. default value
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.