알람 타이머(Ctrl + Alt + A)

Ctrl + Alt + A를 누르면 알람 창을 띄웁니다.

  1. // ==UserScript==
  2. // @name 알람 타이머(Ctrl + Alt + A)
  3. // @namespace 알람 타이머(Ctrl + Alt + A)
  4. // @match *://*/*
  5. // @version 0.4
  6. // @description Ctrl + Alt + A를 누르면 알람 창을 띄웁니다.
  7. // @icon https://cdn-icons-png.flaticon.com/512/7348/7348045.png
  8. // @author mickey90427 <mickey90427@naver.com>
  9. // @grant GM_setValue
  10. // @grant GM_getValue
  11. // @license MIT
  12. // ==/UserScript==
  13. // image : https://www.flaticon.com/kr/free-icon/alarm_7348045
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. const defaultMusicUrl = 'https://mabinoger.com/web/jukebox/mp3/Sliab_Cuiliin.mp3';
  19. let alarmTime = null;
  20. let countdownInterval = null;
  21. let timePickerOpen = false;
  22. let alarmAudio = new Audio(GM_getValue('alarmMusic', defaultMusicUrl));
  23. alarmAudio.loop = true; // 음악 반복 재생 설정
  24.  
  25. // CSS styles for countdown box and time picker
  26. const styles = `
  27. #timePicker {
  28. position: fixed;
  29. top: 50%;
  30. left: 50%;
  31. transform: translate(-50%, -50%);
  32. padding: 20px;
  33. background: rgba(0, 0, 0, 0.9);
  34. color: white;
  35. z-index: 9999;
  36. border-radius: 10px;
  37. }
  38. #countdownBox {
  39. position: fixed;
  40. top: 30%;
  41. left: 50%;
  42. transform: translate(-50%, -50%);
  43. padding: 10px;
  44. background: rgba(0, 0, 0, 0.7);
  45. color: white;
  46. font-size: 24px;
  47. z-index: 9999;
  48. cursor: pointer;
  49. }
  50. #alarmButton {
  51. position: fixed;
  52. top: 60%;
  53. left: 50%;
  54. transform: translate(-50%, -50%);
  55. padding: 5px 15px;
  56. background: red;
  57. color: white;
  58. font-size: 16px;
  59. cursor: pointer;
  60. z-index: 9999;
  61. border-radius: 5px;
  62. }
  63. #setAlarmButton, #setMusicButton {
  64. padding: 5px 10px;
  65. border: none;
  66. border-radius: 5px;
  67. cursor: pointer;
  68. font-size: 14px;
  69. margin-top: 10px;
  70. width: 100%; /* 너비 고정 */
  71. height: 40px; /* 높이 고정 */
  72. }
  73. #setAlarmButton {
  74. background: #4CAF50; /* Set Alarm 버튼 색상 */
  75. }
  76. #setMusicButton {
  77. background: #2196F3; /* Set Music 버튼 색상 */
  78. }
  79. input[type="number"] {
  80. width: 60px; /* 입력창 너비 고정 */
  81. height: 40px; /* 입력창 높이 고정 */
  82. margin-right: 5px;
  83. font-size: 16px; /* 폰트 크기 조정 */
  84. text-align: center; /* 가운데 정렬 */
  85. }
  86. `;
  87.  
  88. const styleSheet = document.createElement("style");
  89. styleSheet.type = "text/css";
  90. styleSheet.innerText = styles;
  91. document.head.appendChild(styleSheet);
  92.  
  93. // 기본 음악 주소가 Tampermonkey의 저장소에 없는 경우 초기화
  94. if (!GM_getValue('alarmMusic')) {
  95. GM_setValue('alarmMusic', defaultMusicUrl);
  96. }
  97.  
  98. function toggleTimeDialog() {
  99. if (timePickerOpen) {
  100. document.getElementById('timePicker')?.remove();
  101. timePickerOpen = false;
  102. } else {
  103. const picker = createTimePicker();
  104. document.body.appendChild(picker);
  105. timePickerOpen = true;
  106. }
  107. }
  108.  
  109. function createTimePicker() {
  110. const timePicker = document.createElement('div');
  111. timePicker.id = 'timePicker';
  112.  
  113. const hoursInput = createInputElement('hour', 12);
  114. const minutesInput = createInputElement('minute', 59);
  115. const secondsInput = createInputElement('second', 59);
  116. const amPmSelect = document.createElement('select');
  117. const amOption = document.createElement('option');
  118. amOption.value = 'AM';
  119. amOption.text = 'AM';
  120. const pmOption = document.createElement('option');
  121. pmOption.value = 'PM';
  122. pmOption.text = 'PM';
  123. amPmSelect.appendChild(amOption);
  124. amPmSelect.appendChild(pmOption);
  125.  
  126. // 현재 시간 가져오기 및 30초 더하기
  127. const now = new Date();
  128. now.setSeconds(now.getSeconds() + 30); // 현재 시간에 30초 추가
  129. const currentHour = now.getHours();
  130. hoursInput.value = (currentHour % 12) || 12; // 12시간 형식
  131. minutesInput.value = now.getMinutes();
  132. secondsInput.value = now.getSeconds();
  133.  
  134. const setButton = document.createElement('button');
  135. setButton.id = 'setAlarmButton';
  136. setButton.innerText = 'Set Alarm';
  137. setButton.onclick = () => {
  138. // 기존 알람 중지
  139. stopAlarm();
  140.  
  141. const hour = parseInt(hoursInput.value);
  142. const minute = parseInt(minutesInput.value);
  143. const second = parseInt(secondsInput.value);
  144. const amPm = amPmSelect.value;
  145.  
  146. // 24시간 형식으로 변환
  147. const adjustedHour = amPm === 'PM' && hour < 12 ? hour + 12 : (amPm === 'AM' && hour === 12 ? 0 : hour);
  148. // 알람 시간 생성
  149. const alarmDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), adjustedHour, minute, second);
  150. alarmTime = Math.floor(alarmDate.getTime() / 1000); // Unix 타임스탬프 저장
  151. timePicker.remove(); // 시간 선택창 닫기
  152. timePickerOpen = false; // 플래그 업데이트
  153. startCountdown(); // 카운트다운 시작
  154. };
  155.  
  156. const setMusicButton = document.createElement('button');
  157. setMusicButton.id = 'setMusicButton';
  158. setMusicButton.innerText = 'Set Music';
  159. setMusicButton.onclick = () => {
  160. const musicUrl = prompt('Enter music URL:', GM_getValue('alarmMusic'));
  161. if (musicUrl) {
  162. GM_setValue('alarmMusic', musicUrl);
  163. alarmAudio.src = musicUrl; // 새로운 음악 주소로 업데이트
  164. }
  165. };
  166.  
  167. timePicker.appendChild(hoursInput);
  168. timePicker.appendChild(document.createTextNode(':'));
  169. timePicker.appendChild(minutesInput);
  170. timePicker.appendChild(document.createTextNode(':'));
  171. timePicker.appendChild(secondsInput);
  172. timePicker.appendChild(amPmSelect);
  173. timePicker.appendChild(setButton);
  174. timePicker.appendChild(setMusicButton); // Set Music 버튼 추가
  175. return timePicker;
  176. }
  177.  
  178. function createInputElement(label, max) {
  179. const input = document.createElement('input');
  180. input.type = 'number';
  181. input.min = '0';
  182. input.max = max.toString();
  183. input.placeholder = label.charAt(0).toUpperCase() + label.slice(1);
  184. return input;
  185. }
  186.  
  187. function startCountdown() {
  188. if (countdownInterval) {
  189. clearInterval(countdownInterval);
  190. }
  191.  
  192. countdownInterval = setInterval(() => {
  193. const now = Math.floor(Date.now() / 1000);
  194. const remaining = alarmTime - now;
  195.  
  196. if (remaining <= 0) {
  197. clearInterval(countdownInterval);
  198. playAlarm();
  199. } else {
  200. updateCountdown(remaining);
  201. }
  202. }, 1000);
  203. }
  204.  
  205. function updateCountdown(remaining) {
  206. const countdownBox = document.getElementById('countdownBox') || createCountdownBox();
  207. countdownBox.innerText = `Remaining time: ${remaining} seconds`;
  208. }
  209.  
  210. function createCountdownBox() {
  211. const box = document.createElement('div');
  212. box.id = 'countdownBox';
  213. box.onclick = stopAlarm; // 클릭 시 알람 종료
  214. document.body.appendChild(box);
  215. return box;
  216. }
  217.  
  218. function playAlarm() {
  219. // 최신 음악 URL을 가져옵니다
  220. alarmAudio.src = GM_getValue('alarmMusic', defaultMusicUrl); // 음악 URL 업데이트
  221. alarmAudio.play(); // 음악 재생
  222. alarmAudio.currentTime = 0; // 음악 시작 위치를 처음으로 설정
  223.  
  224. const alarmButton = document.createElement('div');
  225. alarmButton.id = 'alarmButton';
  226. alarmButton.innerText = 'Stop Alarm';
  227. alarmButton.onclick = stopAlarm; // 클릭 시 알람 종료
  228. document.body.appendChild(alarmButton);
  229.  
  230. const countdownBox = document.getElementById('countdownBox');
  231. if (countdownBox) {
  232. countdownBox.remove(); // 카운트다운 박스 제거
  233. }
  234. }
  235.  
  236. function stopAlarm() {
  237. alarmAudio.pause();
  238. alarmAudio.currentTime = 0;
  239. const alarmButton = document.getElementById('alarmButton');
  240. if (alarmButton) {
  241. alarmButton.remove(); // 알람 버튼 제거
  242. }
  243. if (countdownInterval) {
  244. clearInterval(countdownInterval);
  245. }
  246. const countdownBox = document.getElementById('countdownBox');
  247. if (countdownBox) {
  248. countdownBox.remove(); // 카운트다운 박스 제거
  249. }
  250. }
  251.  
  252. // Ctrl + Alt + A 키 조합으로 알람 설정 열기
  253. document.addEventListener('keydown', (event) => {
  254. if (event.ctrlKey && event.altKey && event.key === 'a') {
  255. toggleTimeDialog();
  256. }
  257. });
  258. })();