├── .gitignore
├── applet.icns
├── TuneOut.scptd
└── Contents
│ ├── Resources
│ ├── clear.png
│ ├── Scripts
│ │ └── main.scpt
│ └── description.rtfd
│ │ └── TXT.rtf
│ ├── _CodeSignature
│ ├── CodeDirectory
│ ├── CodeSignature
│ ├── CodeRequirements
│ ├── CodeRequirements-1
│ └── CodeResources
│ └── Info.plist
├── README.md
└── TuneOut.applescript
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | .DS_Store
3 | TuneOut.app
4 |
--------------------------------------------------------------------------------
/applet.icns:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/purrloftruth/tuneout/HEAD/applet.icns
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/Resources/clear.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/purrloftruth/tuneout/HEAD/TuneOut.scptd/Contents/Resources/clear.png
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/Resources/Scripts/main.scpt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/purrloftruth/tuneout/HEAD/TuneOut.scptd/Contents/Resources/Scripts/main.scpt
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/_CodeSignature/CodeDirectory:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/purrloftruth/tuneout/HEAD/TuneOut.scptd/Contents/_CodeSignature/CodeDirectory
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/_CodeSignature/CodeSignature:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/purrloftruth/tuneout/HEAD/TuneOut.scptd/Contents/_CodeSignature/CodeSignature
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/_CodeSignature/CodeRequirements:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/purrloftruth/tuneout/HEAD/TuneOut.scptd/Contents/_CodeSignature/CodeRequirements
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/_CodeSignature/CodeRequirements-1:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/purrloftruth/tuneout/HEAD/TuneOut.scptd/Contents/_CodeSignature/CodeRequirements-1
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleAllowMixedLocalizations
6 |
7 | CFBundleDevelopmentRegion
8 | English
9 | CFBundleIdentifier
10 | org.purrl.TuneOut
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | TuneOut
15 | CFBundleShortVersionString
16 | 0.9-alpha
17 | LSMinimumSystemVersionByArchitecture
18 |
19 | x86_64
20 | 10.6
21 |
22 | LSRequiresCarbon
23 |
24 | WindowState
25 |
26 | bundleDividerCollapsed
27 |
28 | bundlePositionOfDivider
29 | 783
30 | dividerCollapsed
31 |
32 | eventLogLevel
33 | 0
34 | name
35 | ScriptWindowState
36 | positionOfDivider
37 | 420
38 | savedFrame
39 | 33 44 1082 834 0 0 1440 878
40 | selectedTab
41 | log
42 |
43 |
44 |
45 |
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/Resources/description.rtfd/TXT.rtf:
--------------------------------------------------------------------------------
1 | {\rtf1\ansi\ansicpg1252\cocoartf1671\cocoasubrtf600
2 | {\fonttbl\f0\fnil\fcharset0 Verdana;}
3 | {\colortbl;\red255\green255\blue255;\red76\green78\blue78;}
4 | {\*\expandedcolortbl;;\csgenericrgb\c29999\c30457\c30457;}
5 | \vieww10800\viewh8400\viewkind0
6 | \deftab720
7 | \pard\tx577\tx1155\tx1733\tx2311\tx2889\tx3467\tx4045\tx4623\tx5201\tx5779\tx6357\tx6935\tx7513\tx8091\tx8669\tx9247\tx9825\tx10403\tx10981\tx11559\tx12137\tx12715\tx13293\tx13871\tx14449\tx15027\tx15605\tx16183\tx16761\tx17339\tx17917\tx18495\tx19072\tx19650\tx20228\tx20806\tx21384\tx21962\tx22540\tx23118\tx23696\tx24274\tx24852\tx25430\tx26008\tx26586\tx27164\tx27742\tx28320\tx28898\tx29476\tx30054\tx30632\tx31210\tx31788\tx32366\tx32944\tx33522\tx34100\tx34678\tx35256\tx35834\tx36412\tx36990\tx37567\tx38145\tx38723\tx39301\tx39879\tx40457\tx41035\tx41613\tx42191\tx42769\tx43347\tx43925\tx44503\tx45081\tx45659\tx46237\tx46815\tx47393\tx47971\tx48549\tx49127\tx49705\tx50283\tx50861\tx51439\tx52017\tx52595\tx53173\tx53751\tx54329\tx54907\tx55485\tx56062\tx56640\tx57218\tx57796\pardeftab720\partightenfactor0
8 |
9 | \f0\fs24 \cf2 \CocoaLigature0 TuneOut is an AppleScript application that saves the currently playing iTunes, Spotify, Nightbot or Moobot track's information to a file (~/Library/Application Support/TuneOut/np.txt, specifically). This might be useful if you use an application like OBS to stream live video and want to incorporate your currently playing song on the display.\
10 | \pard\tx577\tx1155\tx1733\tx2311\tx2889\tx3467\tx4045\tx4623\tx5201\tx5779\tx6357\tx6935\tx7513\tx8091\tx8669\tx9247\tx9825\tx10403\tx10981\tx11559\tx12137\tx12715\tx13293\tx13871\tx14449\tx15027\tx15605\tx16183\tx16761\tx17339\tx17917\tx18495\tx19072\tx19650\tx20228\tx20806\tx21384\tx21962\tx22540\tx23118\tx23696\tx24274\tx24852\tx25430\tx26008\tx26586\tx27164\tx27742\tx28320\tx28898\tx29476\tx30054\tx30632\tx31210\tx31788\tx32366\tx32944\tx33522\tx34100\tx34678\tx35256\tx35834\tx36412\tx36990\tx37567\tx38145\tx38723\tx39301\tx39879\tx40457\tx41035\tx41613\tx42191\tx42769\tx43347\tx43925\tx44503\tx45081\tx45659\tx46237\tx46815\tx47393\tx47971\tx48549\tx49127\tx49705\tx50283\tx50861\tx51439\tx52017\tx52595\tx53173\tx53751\tx54329\tx54907\tx55485\tx56062\tx56640\tx57218\tx57796\pardeftab720\li785\fi-786\pardirnatural\partightenfactor0
11 | \cf2 \
12 | Copyright \'a9 2016, 2019 Ruth Harris.\
13 | \
14 | Permission is hereby granted, free of charge, to any person obtaining a copy\
15 | of this software and associated documentation files (the "Software"), to deal\
16 | in the Software without restriction, including without limitation the rights\
17 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\
18 | copies of the Software, and to permit persons to whom the Software is\
19 | furnished to do so, subject to the following conditions:\
20 | \
21 | The above copyright notice and this permission notice shall be included in all\
22 | copies or substantial portions of the Software.\
23 | \
24 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\
25 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\
26 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\
27 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\
28 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\
29 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\
30 | SOFTWARE.}
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # _This is old, unmaintained software which should not be used in a modern production context._
2 |
3 | # TuneOut
4 |
5 | TuneOut is an AppleScript application that saves the currently playing iTunes, Spotify, Nightbot or Moobot track's information to a file (~/Library/Application Support/TuneOut/np.txt, specifically). This might be useful if you use an application like OBS to stream live video and want to incorporate your currently playing song on the display.
6 |
7 | ## How to use
8 |
9 | 1. Download the latest version of TuneOut.app from the project's [releases](http://github.com/wonaldson/tuneout/releases) page and unzip the file.
10 | 2. Double-click the .app file. (Depending on your Gatekeeper settings, you may have to right-click the .app file and click "Open".)
11 | 3. Point your OBS text-as-file location to `~/Library/Application Support/TuneOut/np.txt`, where `~` consists of your User folder (usually `/Users/{your user name here}`).
12 | 4. For iTunes cover art support, point your OBS image location to `~/Library/Application Support/TuneOut/art.png`.
13 | 5. There is no step five!
14 |
15 | ## How to build
16 |
17 | 1. Clone the repository to your macOS computer.
18 | 2. In `build.command`, replace the code signing identity with your own.
19 | 3. In the repository directory, make `build.command` executable: `chmod +x build.command`
20 | 4. Double-click `build.command` in Finder or run it in the terminal: `./build.command`
21 |
22 | TuneOut.app will be built in `./build/` (where `.` is the repository folder) and a .zip file with the version number will be created.
23 |
24 | ## Caveats
25 |
26 | If you play songs with non-latin characters, make sure your font supports them. The font renderer used by OBS does not fall back to fonts where the glyphs needed appears like macOS font rendering typically does.
27 |
28 | Support for web players such as Nightbot and Moobot only functions when running in Safari or Google Chrome.
29 |
30 | To enable Safari support, you must enable "Allow JavaScript from Apple Events" in Safari's Develop menu. If you do not have a Develop menu, it can be enabled in the Advanced section of Safari's Preferences.
31 |
32 | ## Thanks
33 |
34 | To [dzomb](https://github.com/dzomb) who wrote the [original version](https://github.com/dzomb/tuneout) of this script and to [wildgift](http://twitch.tv/wildgifticus) for getting me to write this.
35 |
36 | Additional thanks to [Christopher T. Howlett](http://howlettstudios.com) for the royalty-free tuning fork shape used in our icon.
37 |
38 | ## License
39 |
40 | TuneOut is licensed under the MIT license.
41 |
42 | Copyright © 2016, 2019 Ruth Harris.
43 |
44 | Permission is hereby granted, free of charge, to any person obtaining a copy
45 | of this software and associated documentation files (the "Software"), to deal
46 | in the Software without restriction, including without limitation the rights
47 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
48 | copies of the Software, and to permit persons to whom the Software is
49 | furnished to do so, subject to the following conditions:
50 |
51 | The above copyright notice and this permission notice shall be included in all
52 | copies or substantial portions of the Software.
53 |
54 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
55 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
56 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
57 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
58 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
59 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
60 | SOFTWARE.
61 |
--------------------------------------------------------------------------------
/TuneOut.scptd/Contents/_CodeSignature/CodeResources:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | files
6 |
7 | Resources/Scripts/main.scpt
8 |
9 | 4gA9RX9soWC/MlRUUkGEDu9wCUw=
10 |
11 | Resources/clear.png
12 |
13 | m+UVI9rvGvfLC7nvM7JcKMQ4aYU=
14 |
15 | Resources/description.rtfd/TXT.rtf
16 |
17 | RSqAMCQ01ANvneZBRmqyh3nrpDE=
18 |
19 |
20 | files2
21 |
22 | Resources/Scripts/main.scpt
23 |
24 | hash
25 |
26 | 4gA9RX9soWC/MlRUUkGEDu9wCUw=
27 |
28 | hash2
29 |
30 | wKpqjRNLiAEkKDEC+JgVKKgH4sEaOjqW0gSxAPp1IqI=
31 |
32 |
33 | Resources/clear.png
34 |
35 | hash
36 |
37 | m+UVI9rvGvfLC7nvM7JcKMQ4aYU=
38 |
39 | hash2
40 |
41 | Xnbscatt7CrsjvS1EsMdCMjVaIYZAP5DkratmUCRePE=
42 |
43 |
44 | Resources/description.rtfd/TXT.rtf
45 |
46 | hash
47 |
48 | RSqAMCQ01ANvneZBRmqyh3nrpDE=
49 |
50 | hash2
51 |
52 | 9YB/nPVm0BiMsOcQByz7AMlZifvvQNty/u84KKkm7L4=
53 |
54 |
55 |
56 | rules
57 |
58 | ^Resources/
59 |
60 | ^Resources/.*\.lproj/
61 |
62 | optional
63 |
64 | weight
65 | 1000
66 |
67 | ^Resources/.*\.lproj/locversion.plist$
68 |
69 | omit
70 |
71 | weight
72 | 1100
73 |
74 | ^Resources/Base\.lproj/
75 |
76 | weight
77 | 1010
78 |
79 | ^version.plist$
80 |
81 |
82 | rules2
83 |
84 | .*\.dSYM($|/)
85 |
86 | weight
87 | 11
88 |
89 | ^(.*/)?\.DS_Store$
90 |
91 | omit
92 |
93 | weight
94 | 2000
95 |
96 | ^(Frameworks|SharedFrameworks|PlugIns|Plug-ins|XPCServices|Helpers|MacOS|Library/(Automator|Spotlight|LoginItems))/
97 |
98 | nested
99 |
100 | weight
101 | 10
102 |
103 | ^.*
104 |
105 | ^Info\.plist$
106 |
107 | omit
108 |
109 | weight
110 | 20
111 |
112 | ^PkgInfo$
113 |
114 | omit
115 |
116 | weight
117 | 20
118 |
119 | ^Resources/
120 |
121 | weight
122 | 20
123 |
124 | ^Resources/.*\.lproj/
125 |
126 | optional
127 |
128 | weight
129 | 1000
130 |
131 | ^Resources/.*\.lproj/locversion.plist$
132 |
133 | omit
134 |
135 | weight
136 | 1100
137 |
138 | ^Resources/Base\.lproj/
139 |
140 | weight
141 | 1010
142 |
143 | ^[^/]+$
144 |
145 | nested
146 |
147 | weight
148 | 10
149 |
150 | ^embedded\.provisionprofile$
151 |
152 | weight
153 | 20
154 |
155 | ^version\.plist$
156 |
157 | weight
158 | 20
159 |
160 |
161 |
162 |
163 |
--------------------------------------------------------------------------------
/TuneOut.applescript:
--------------------------------------------------------------------------------
1 | (*
2 |
3 | Copyright © 2016, 2019 Ruth Harris.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 | *)
24 |
25 | (* Thanks *)
26 | # Thanks to dzomb who wrote the original version of this script.
27 | # You can find that here: https://github.com/dzomb/tuneout
28 |
29 |
30 | (* Editing below this line may break things. *)
31 |
32 | (* thanks to http://www.macosxautomation.com/applescript/sbrt/sbrt-09.html *)
33 | (* thanks to http://macscripter.net/viewtopic.php?id=24534 for unicode help *)
34 | on write_to_file(this_data, target_file, append_data)
35 | try
36 | set the target_file to the target_file as string
37 | set the open_target_file to open for access file target_file with write permission
38 | if append_data is false then set eof of the open_target_file to 0
39 | write this_data to the open_target_file as Çclass utf8È starting at eof
40 | close access the open_target_file
41 | return true
42 | on error
43 | try
44 | close access file target_file
45 | end try
46 | return false
47 | end try
48 | end write_to_file
49 |
50 | on binary_write_to_file(this_data, target_file, append_data)
51 | try
52 | set the target_file to the target_file as string
53 | set the open_target_file to open for access file target_file with write permission
54 | if append_data is false then set eof of the open_target_file to 0
55 | write this_data to the open_target_file starting at eof
56 | close access the open_target_file
57 | return true
58 | on error
59 | try
60 | close access file target_file
61 | end try
62 | return false
63 | end try
64 | end binary_write_to_file
65 |
66 | on debug(errorText, displayNotification)
67 | if my debugMode then
68 | log "DEBUG: " & errorText
69 | if displayNotification then display notification "DEBUG: " & errorText
70 | end if
71 | end debug
72 |
73 | on check_web_player(playerTitle, desiredPageTitle, determinePlayerStateCode, grabTrackCode, stoppedWhenNotPlaying)
74 | set rawTrack to null
75 | set rawArt to null
76 |
77 | if not my safariDisabled then
78 | (* Safari Support *)
79 | try
80 | if application "Safari" is running then
81 | tell application "Safari"
82 | set safariTab to null
83 |
84 | repeat with i in (windows whose its document is not missing value)
85 | if (count of (tabs of i)) is greater than 0 then
86 | repeat with j in (tabs of i)
87 | if name of j is desiredPageTitle then
88 | set safariTab to j
89 | exit repeat
90 | end if
91 | end repeat
92 | if safariTab is not null then
93 | exit repeat
94 | end if
95 | end if
96 | end repeat
97 |
98 | if safariTab is not null then
99 | tell safariTab
100 | set isPlaying to do JavaScript determinePlayerStateCode
101 | if isPlaying then
102 | set rawTrack to do JavaScript grabTrackCode
103 | else
104 | if not stoppedWhenNotPlaying then set rawTrack to "Paused"
105 | end if
106 | end tell
107 | end if
108 |
109 | end tell
110 | end if
111 | on error errStr number errorNumber
112 | debug("[SAFARI] " & desiredPageTitle & " had a booboo. " & errStr & space & errorNumber, true)
113 | set rawTrack to missing value
114 | set rawArt to missing value
115 | if my debugMode then error errStr number errorNumber
116 | end try
117 | end if
118 | if (rawTrack is null or rawTrack is missing value) and (rawArt is null or rawArt is missing value) then
119 | (* Google Chrome Support *)
120 | try
121 | if application "Google Chrome" is running then
122 | tell application "Google Chrome"
123 | set chromeTab to null
124 |
125 | repeat with i in (windows)
126 | if (count of (tabs of i)) is greater than 0 then
127 | repeat with j in (tabs of i)
128 | if title of j is desiredPageTitle then
129 | set chromeTab to j
130 | exit repeat
131 | end if
132 | end repeat
133 | if chromeTab is not null then
134 | exit repeat
135 | end if
136 | end if
137 | end repeat
138 |
139 | if chromeTab is not null then
140 | tell chromeTab
141 | set isPlaying to execute javascript determinePlayerStateCode
142 | if isPlaying then
143 | set rawTrack to execute javascript grabTrackCode
144 | else
145 | if not stoppedWhenNotPlaying then set rawTrack to "Paused"
146 | end if
147 | end tell
148 | end if
149 |
150 | end tell
151 | end if
152 | on error errStr number errorNumber
153 | debug("[CHROME] " & desiredPageTitle & " had a booboo. " & errStr & space & errorNumber, true)
154 | set rawTrack to missing value
155 | set rawArt to missing value
156 | if my debugMode then error errStr number errorNumber
157 | end try
158 | end if
159 |
160 | return {track:rawTrack, art:rawArt}
161 | end check_web_player
162 |
163 | on check_iTunes()
164 | set rawTrack to null
165 | set rawArt to null
166 |
167 | try
168 | if application "iTunes" is running then
169 | tell application "iTunes"
170 | if player state is not stopped then
171 | (* First, let's try and figure out the art situation *)
172 |
173 | try
174 | set artwk to first artwork of current track
175 | set rawArt to raw data of artwk
176 | end try
177 |
178 | (* Now we'll deal with track data *)
179 |
180 | if player state is paused then
181 | set rawTrack to "Paused"
182 |
183 | else
184 | if kind of current track is "Internet audio stream" then
185 | set rawTrack to current stream title
186 | else
187 | if artist of current track is "" then
188 | set rawTrack to name of current track
189 | else
190 | set rawTrack to artist of current track & " - " & name of current track
191 | end if
192 | end if
193 | end if
194 | end if
195 | end tell
196 | end if
197 | on error errStr number errorNumber
198 | debug("iTunes had a booboo. " & errStr & space & errorNumber, true)
199 | if my debugMode then error errStr number errorNumber
200 | return {track:missing value, art:missing value}
201 | end try
202 |
203 | return {track:rawTrack, art:rawArt}
204 | end check_iTunes
205 |
206 | on check_spotify()
207 | set rawTrack to null
208 | set rawArt to null
209 |
210 | try
211 | if application "Spotify" is running then
212 | tell application "Spotify"
213 | if player state is not stopped then
214 | (* First, let's try and figure out the art situation *)
215 |
216 | set spotifyArtUrl to artwork url of current track
217 | if spotifyArtUrl is not my spotifyArtUrlOld then
218 | (* If you can figure out a way to do this without saving it to the filesystem
219 | and also doesn't glitch out the art, please file a pull request. For some
220 | reason it's almost as if the script continues on without waiting for the
221 | file to fully download. *)
222 |
223 | set result to do shell script "curl " & spotifyArtUrl & " -o " & quoted form of POSIX path of my spotifyArtTempFullPathT
224 | set rawArt to read file (my spotifyArtTempFullPathT)
225 |
226 | set my spotifyArtUrlOld to spotifyArtUrl
227 | else
228 | set rawArt to my rawArtOld
229 | end if
230 |
231 | (* Now we'll deal with track data *)
232 |
233 | if player state is paused then
234 | set rawTrack to "Paused"
235 |
236 | else
237 | if artist of current track is "" then
238 | set rawTrack to name of current track
239 | else
240 | set rawTrack to artist of current track & " - " & name of current track
241 | end if
242 | end if
243 | end if
244 | end tell
245 | end if
246 | on error errStr number errorNumber
247 | debug("Spotify had a booboo. " & errStr & space & errorNumber, true)
248 | if my debugMode then error errStr number errorNumber
249 | return {track:missing value, art:missing value}
250 | end try
251 |
252 | return {track:rawTrack, art:rawArt}
253 | end check_spotify
254 |
255 | on check_playful_stream()
256 | set playerTitle to "Playful Stream"
257 | set desiredPageTitle to "Playful"
258 | set determinePlayerStateCode to "(document.getElementById('b-pause').style.visibility == 'visible');"
259 | set grabTrackCode to "document.getElementById('now-playing-data').textContent;"
260 | set stoppedWhenNotPlaying to false
261 |
262 | return check_web_player(playerTitle, desiredPageTitle, determinePlayerStateCode, grabTrackCode, stoppedWhenNotPlaying)
263 | end check_playful_stream
264 |
265 | on check_nightbot()
266 | set playerTitle to "Nightbot"
267 | set desiredPageTitle to "Nightbot - Song Requests"
268 | set determinePlayerStateCode to "document.getElementsByClassName('pause-play-container')[0].getElementsByClassName('fa-play')[0].classList.contains('ng-hide');"
269 |
270 | set grabTrackCode to "document.getElementsByClassName('current-track')[0].getElementsByTagName('h4')[0].textContent;"
271 | set stoppedWhenNotPlaying to false
272 |
273 | return check_web_player(playerTitle, desiredPageTitle, determinePlayerStateCode, grabTrackCode, stoppedWhenNotPlaying)
274 | end check_nightbot
275 |
276 | on check_moobot()
277 | set playerTitle to "Moobot"
278 | set desiredPageTitle to "Moobot, your Twitch chat moderator bot"
279 | set determinePlayerStateCode to "(document.getElementsByClassName('widget-songrequests')[0].getElementsByClassName('btn-play')[0].getElementsByClassName('icon-stop')[0] != null);"
280 | set grabTrackCode to "
281 | while (document.getElementById('songrequests-widget-info') == null) {
282 | document.getElementsByClassName('widget-songrequests')[0].getElementsByClassName('btn-info')[0].click();
283 | }
284 | document.getElementById('songrequests-widget-info').getElementsByTagName('p')[0].textContent;"
285 | set stoppedWhenNotPlaying to true
286 |
287 | return check_web_player(playerTitle, desiredPageTitle, determinePlayerStateCode, grabTrackCode, stoppedWhenNotPlaying)
288 | end check_moobot
289 |
290 | on test_safari()
291 | try
292 | tell application "Safari"
293 | tell tab 1 of window 1
294 | do JavaScript "return true;"
295 | end tell
296 | end tell
297 | on error errStr number errNumber
298 | set result to button returned of (display dialog "You must enable the 'Allow JavaScript from Apple Events' option in Safari's Develop menu to use web-based players with Safari.
299 |
300 | Continue without Safari support? " with icon caution with title my appName)
301 | if result is "Cancel" then
302 | error number -128
303 | else
304 | set my safariDisabled to true
305 | end if
306 | end try
307 | end test_safari
308 |
309 | on run
310 | set appName to "TuneOut"
311 | set appVersion to "0.8"
312 | set debugMode to (name of current application is not appName)
313 |
314 | set applicationSupportPathP to path to application support from user domain as Unicode text
315 | set applicationSupportPath to applicationSupportPathP & appName & ":"
316 | set applicationSupportPathT to applicationSupportPath & "tmp:"
317 |
318 | tell application "Finder"
319 | if (exists applicationSupportPath) is false then make new folder at applicationSupportPathP with properties {name:appName}
320 | if (exists applicationSupportPathT) is false then make new folder at applicationSupportPath with properties {name:"tmp"}
321 | end tell
322 |
323 | set textFilename to "np.txt"
324 | set artFilename to "art.png"
325 | set artTempFilename to "art.tmp"
326 | set clearArtFilename to "clear.png"
327 | set spotifyArtTempFilename to "spotify.jpg"
328 | set logFilename to "debug.txt" (* Unused *)
329 |
330 | set textFullPath to applicationSupportPath & textFilename
331 | set textFullPathT to applicationSupportPathT & textFilename
332 | set artFullPath to applicationSupportPath & artFilename
333 | set artFullPathT to applicationSupportPathT & artFilename
334 | set artTempFullPath to applicationSupportPath & artTempFilename
335 | set artTempFullPathT to applicationSupportPathT & artTempFilename
336 | set spotifyArtTempFullPathT to applicationSupportPathT & spotifyArtTempFilename
337 | set logFullPath to applicationSupportPath & logFilename (* Unused *)
338 |
339 | set supportedPlayers to {"iTunes", "Spotify", "Playful Stream", "Nightbot", "Moobot"}
340 |
341 | set rawTrackOld to ""
342 | set rawArtOld to null
343 | set dataPlayersOld to {}
344 | set spotifyArtUrlOld to ""
345 |
346 | set safariDisabled to false
347 |
348 | repeat with i from 1 to count of supportedPlayers
349 | copy {track:null, art:null} to the end of dataPlayersOld
350 | end repeat
351 |
352 | set clearData to read (path to resource clearArtFilename)
353 |
354 | tell application "Image Events"
355 | launch
356 | end tell
357 |
358 | set operational to false
359 |
360 | try
361 | test_safari()
362 | on error errStr number errNumber
363 | if errNumber is -128 then
364 | if name of current application is appName then
365 | return
366 | quit
367 | else
368 | error number -128
369 | end if
370 | end if
371 | end try
372 |
373 | debug("Hello, I am " & appName & " (" & appVersion & ")", false)
374 | debug("Debugging is enabled.", false)
375 |
376 | set operational to true
377 |
378 | display notification appName & space & appVersion & " is now running. To quit, right-click the Dock icon and click \"Quit\"." sound name "Submarine"
379 |
380 | (* Script editor testing *)
381 |
382 | if name of current application is not appName then
383 | repeat while true
384 | set d to idle
385 | delay d
386 | end repeat
387 | end if
388 | end run
389 |
390 | on idle
391 | if my operational then
392 | set chosenData to {track:null, art:null}
393 | set dataPlayers to {}
394 |
395 | copy check_iTunes() to end of dataPlayers
396 | copy check_spotify() to end of dataPlayers
397 | copy check_playful_stream() to end of dataPlayers
398 | copy check_nightbot() to end of dataPlayers
399 | copy check_moobot() to end of dataPlayers
400 |
401 | debug("
402 | Iteration for " & (current date), false)
403 | debug("iTunes: " & track of item 1 of dataPlayers, false)
404 | debug("Spotify: " & track of item 2 of dataPlayers, false)
405 | debug("Playful Stream: " & track of item 3 of dataPlayers, false)
406 | debug("Nightbot: " & track of item 4 of dataPlayers, false)
407 | debug("Moobot: " & track of item 5 of dataPlayers, false)
408 |
409 | repeat with i from 1 to count of dataPlayers
410 | if track of item i of dataPlayers is not null then
411 | if track of item i of dataPlayers is not missing value then
412 | set chosenData to item i of dataPlayers
413 | else
414 | debug("We had a missing value error. " & (current date), true)
415 | set chosenData to item i of my dataPlayersOld
416 | end if
417 | if track of chosenData is not null then exit repeat
418 | end if
419 | end repeat
420 |
421 | set rawTrack to track of chosenData
422 | set rawArt to art of chosenData
423 |
424 | (* If we don't have any data... *)
425 | if rawTrack is null then set rawTrack to "Stopped"
426 | if rawArt is null then set rawArt to my clearData
427 |
428 | (* Write images & text to temp files if they have changed *)
429 | if rawArt is not equal to my rawArtOld then
430 | my binary_write_to_file(rawArt, my artTempFullPathT, false)
431 |
432 | tell application "Image Events"
433 | set tempImage to open my artTempFullPathT
434 | scale tempImage to size 1000
435 | save tempImage as PNG in my artFullPathT
436 | close tempImage
437 | my debug("Art successfully saved.", false)
438 | end tell
439 | end if
440 |
441 | if rawTrack is not equal to my rawTrackOld then
442 | my write_to_file(rawTrack, my textFullPathT, false)
443 | debug("Track data changed. Writing: " & rawTrack, false)
444 | end if
445 |
446 | (* Move them at the same time to update simultaneously instead of staggered *)
447 | if rawTrack is not equal to my rawTrackOld then
448 | do shell script "mv " & quoted form of POSIX path of my textFullPathT & space & quoted form of POSIX path of my applicationSupportPath
449 | end if
450 |
451 | if rawArt is not equal to my rawArtOld then
452 | do shell script "mv " & quoted form of POSIX path of my artFullPathT & space & quoted form of POSIX path of my applicationSupportPath
453 | end if
454 |
455 | (* Finally, update old data listing *)
456 | if rawArt is not equal to my rawArtOld then
457 | set my rawArtOld to rawArt
458 | end if
459 |
460 | if rawTrack is not equal to my rawTrackOld then
461 | set my rawTrackOld to rawTrack
462 | end if
463 |
464 | set my dataPlayersOld to dataPlayers
465 |
466 | debug("We ended up with " & rawTrack, false)
467 | else
468 | quit
469 | end if
470 |
471 | return 0.5
472 | end idle
473 |
474 | on reopen
475 | display notification (my rawTrackOld) with title "Current track display"
476 | end reopen
477 |
478 | on quit
479 | try
480 | log "I think we're done here."
481 | write_to_file("Stopped", my textFullPath, false)
482 | binary_write_to_file(my clearData, my artFullPath, false)
483 |
484 | close access textReference
485 | close access artReference
486 | log "Successfully closed down."
487 | end try
488 | continue quit
489 | end quit
490 |
491 |
492 |
--------------------------------------------------------------------------------