Compare commits

..

91 Commits
1.0 ... v1.2

Author SHA1 Message Date
Florian Metz
bec69b3abf Create messages.json (POEditor.com) 2018-11-02 01:52:13 +01:00
Florian Metz
530e82cc6d Windows fixes for V1.2 2018-11-02 01:28:00 +01:00
Timeraa
29765230b1 Basically everything for 1.2 :P 2018-11-01 19:53:24 +01:00
Timeraa
29a556c7d1 Version 1.2 Preparations 2018-11-01 14:58:59 +01:00
Timeraa
7f3d4ba8aa Readme update 2018-10-27 14:24:14 +02:00
Timeraa
9c714c9c4e Small changes here and there 2018-10-27 14:20:34 +02:00
Timeraa
91ef9955b4 More support 2018-10-27 14:20:00 +02:00
Timeraa
97f0f3784d Merge branch 'master' of https://github.com/Timeraa/YT-Presence 2018-10-26 21:02:42 +02:00
Timeraa
42d903ac16 added some strings 2018-10-26 21:02:39 +02:00
Timeraa
b9111348d3 Rewrites here and there 2018-10-26 21:01:29 +02:00
Fruxh
69b7fa79de fixed hyperlinks 2018-10-21 10:59:49 +02:00
Timeraa
4c67233e83 Readme update 2018-10-21 01:49:32 +02:00
Timeraa
c9d14992b9 Updates... 2018-10-21 01:07:31 +02:00
Timeraa
f06411e018 Merge branch 'master' of https://github.com/Timeraa/YT-Presence 2018-10-21 01:04:04 +02:00
Timeraa
73b9c419ff Small bug fixes 2018-10-21 01:04:01 +02:00
Florian Metz
e763d98134 Better Readme Part1 2018-10-21 01:01:18 +02:00
Florian Metz
0533256b87 Update messages.json (POEditor.com) 2018-10-21 00:59:42 +02:00
Florian Metz
4d0c874a95 Update messages.json (POEditor.com) 2018-10-21 00:59:40 +02:00
Florian Metz
ae1608e0bb Update messages.json (POEditor.com) 2018-10-21 00:59:38 +02:00
Florian Metz
88ae7c8994 Update messages.json (POEditor.com) 2018-10-21 00:59:36 +02:00
Florian Metz
d697ce8c81 Update messages.json (POEditor.com) 2018-10-21 00:59:34 +02:00
Florian Metz
a684cf1294 Update en_EN.json (POEditor.com) 2018-10-21 00:59:32 +02:00
Timeraa
b9d4028074 Added languages 2018-10-21 00:54:39 +02:00
Timeraa
916cb7e76f V1.1.2 2018-10-21 00:35:15 +02:00
Paz
6dd61af5dd ok!!!!! 2018-10-21 00:05:25 +08:00
Paz
5bee7c0791 eawrgweraghwaehr 2018-10-21 00:01:00 +08:00
Paz
a4a731f04a rehgerhherh 2018-10-21 00:00:48 +08:00
Paz
b15d3c5375 FINAL CHANGES NOW 2018-10-21 00:00:12 +08:00
Paz
99ba73f194 hopefully final changes 2018-10-20 23:59:38 +08:00
Paz
1456c15f91 Update README.md 2018-10-20 23:55:19 +08:00
Paz
8a26580453 Add files via upload 2018-10-20 23:41:49 +08:00
Paz
af393ad0ca Delete donateonpaypal.png 2018-10-20 23:41:37 +08:00
Paz
8a46f3a7d2 Update README.md 2018-10-20 23:41:02 +08:00
Paz
0aff71496c Add files via upload 2018-10-20 23:40:41 +08:00
Paz
f3a5642bcd Delete paypal.png 2018-10-20 23:40:25 +08:00
Paz
b97e6e0870 Update README.md 2018-10-20 23:39:57 +08:00
Paz
3e704c3d22 Update README.md 2018-10-20 23:22:51 +08:00
Paz
ae02fa80ce Update README.md 2018-10-20 23:22:18 +08:00
Paz
ec5c1038b3 Update README.md 2018-10-20 23:21:55 +08:00
Paz
e5e6295a83 Add files via upload 2018-10-20 23:18:57 +08:00
Paz
19560fe60f Add files via upload 2018-10-20 23:13:23 +08:00
Paz
1f1b469a4b Add files via upload 2018-10-20 23:12:22 +08:00
Paz
eb095a7497 Delete patreonBTN.png 2018-10-20 23:11:51 +08:00
Paz
6415b095ab Delete discord-logo.svg 2018-10-20 23:11:39 +08:00
Paz
d93c959da8 Delete developerMode.png 2018-10-20 23:11:28 +08:00
Paz
09893e1409 Delete loadUnpackedExtension.png 2018-10-20 23:11:15 +08:00
Paz
93ec6384d0 Create discord.svg 2018-10-20 23:10:37 +08:00
Paz
a221bf33b2 Delete logo.png 2018-10-20 23:10:07 +08:00
Paz
c7ec3d2197 Delete icon.png 2018-10-20 23:09:57 +08:00
Paz
18d04099fd Create logo.png 2018-10-20 23:09:24 +08:00
Timeraa
fec52ee19f Fix for #15 2018-10-19 14:15:48 +02:00
Timeraa
d87a22da23 Description translations... 2018-10-17 20:23:48 +02:00
Timeraa
4bda273947 Translation update! <3 2018-10-17 20:17:52 +02:00
Timeraa
7c8a2e32b4 Added Patreon link 2018-10-17 19:20:13 +02:00
Timeraa
45e8d0c2b6 Merge branch 'master' of https://github.com/Timeraa/YT-Presence 2018-10-17 18:06:03 +02:00
Timeraa
3fe0b93567 Help 2018-10-17 18:06:01 +02:00
Timeraa
06147dd5cc small things lul 2018-10-17 18:05:34 +02:00
Florian Metz
44dae3832e Version update 2018-10-16 17:24:47 +02:00
Timeraa
4f06d804e9 Updated Readme.md 2018-10-16 15:19:47 +02:00
Timeraa
fb87b201da Version bump! 2018-10-16 15:10:49 +02:00
Timeraa
a58090b334 Bug fix 2018-10-16 15:08:35 +02:00
Timeraa
0050bfe36f SoundCloud support 2018-10-16 14:58:40 +02:00
Timeraa
d40233cb1e Typo 2018-10-14 19:56:19 +02:00
Timeraa
3125f8e7d1 Updated Readme file 2018-10-14 19:53:18 +02:00
Timeraa
0646fb77f2 Twitch Support and small improvements in Netflix.js 2018-10-14 16:50:46 +02:00
Timeraa
c5a3a17a94 Netflix Support 2018-10-14 14:48:49 +02:00
Timeraa
e4b1880025 forgot the logo... 2018-10-14 12:51:24 +02:00
Timeraa
c0b74c1605 Small changes to Readme 2018-10-14 12:51:09 +02:00
Timeraa
96aed66af2 Presence fix when changing from YouTube to other service 2018-10-13 14:56:04 +02:00
Timeraa
65e23a90a1 Code organisation 2018-10-13 14:49:59 +02:00
Timeraa
f3405b5724 YT Music improvements, Port change + Netflix "semi-support" 2018-10-12 22:16:34 +02:00
Timeraa
5bef1e5663 code cleanup 2018-10-09 19:44:46 +02:00
Timeraa
5120cee05a Extension organisation + Connection info 2018-10-09 19:04:59 +02:00
Timeraa
895e593d02 syntax fix 2018-10-09 19:04:43 +02:00
Timeraa
32d8070119 Faster song/video recognition 2018-10-09 17:32:49 +02:00
Timeraa
46273ecbe5 Fixed decode error (Mac menubar) 2018-10-09 17:27:20 +02:00
Timeraa
4268099a06 Window organisation 2018-10-09 17:26:54 +02:00
Timeraa
921db2f6cb Updated Mac installer 2018-10-09 15:57:22 +02:00
Florian Metz
f640c45464 Shortened description, too long. 2018-10-07 20:14:39 +02:00
Florian Metz
d4dc7a32a4 Updated readme.md 2018-10-07 20:14:07 +02:00
Florian Metz
33e5171742 Final preparation for V1.0 2018-10-07 17:46:25 +02:00
Timeraa
ebb4857782 Fix for RPC not working with autostart 2018-10-07 15:08:03 +02:00
Timeraa
c47d253967 Final? preparations for V1.0 (Mac OS side) 2018-10-07 03:58:39 +02:00
Timeraa
c58e7d2ccf fixes 2018-10-05 18:35:19 +02:00
Timeraa
f3cad86f6f Bug fixes/squirrel stuffs 2018-10-05 18:31:06 +02:00
Timeraa
a23655de42 small changes. 2018-09-23 18:48:31 +02:00
Timeraa
b7b899ea40 Troubleshooting + organisation stuffs 2018-09-22 22:43:03 +02:00
Timeraa
89029b1bc3 Some improvements 2018-09-22 21:30:50 +02:00
Timeraa
9b4212e00c Added new Discord link to readme 2018-09-22 21:30:38 +02:00
Timeraa
6b158e1e23 Oops, uploaded extension 2018-09-22 21:30:27 +02:00
Timeraa
6cae350ef2 Version 1.0 (Dev-build) 2018-09-22 20:33:32 +02:00
111 changed files with 9918 additions and 4125 deletions

6
.gitignore vendored
View File

@@ -1,4 +1,6 @@
node_modules
out
.vscode
dist
dist
website
server
.vscode

View File

@@ -0,0 +1,104 @@
{
"appDesc": {
"message": "PreMiD fügt eine Discord-Rich-Presence-Integration, Kontrolle über Multimediatasten und viele weitere Funktionen zu YouTube/YouTube Music, Twitch etc. hinzu."
},
"connected": {
"message": "Verbunden"
},
"disconnected": {
"message": "Getrennt"
},
"installedThanks": {
"message": "Vielen Dank, für das Installieren von PreMiD"
},
"installedApp": {
"message": "Hast du das Programm bereits installiert?"
},
"installedNo": {
"message": "Nein? Folge dieser Anleitung:"
},
"installedStepApp": {
"message": "Lade die neueste Version von $1 herunter"
},
"installedStepAppMyRepository": {
"message": "meinem GitHub Repository"
},
"installedWaitInstalled": {
"message": "Offne das Installationsprogramm und warte bis die Installation abgeschlossen ist"
},
"installedMayWarning": {
"message": "Möglicherweise bekommst du eine Warnung von deiner FireWall und SmartScreen (Es ist kein Virus. Das verspreche ich dir!)"
},
"installedAppAutostart": {
"message": "Das Programm sollte automatisch starten. Du kannst dies prüfen, indem du auf deine Taskbar (Windows) oder deine Menubar (MacOS) schaust"
},
"installedYes": {
"message": "Ja? Jetzt bist du bereit!"
},
"installedStart": {
"message": "Starte, indem du ein Video auf YouTube, deine Lieblingsstreamer auf Twitch, deine Lieblings Animes auf KissAnime oder JKAnime anschaust oder vielleicht sogar Netflix... Wer weiß?<br>Oder du hörst dir deine Lieblingslieder auf SoundCloud und YouTube Music an. Einstellungen findest du indem du auf das PreMiD icon in deinem Browser klickst."
},
"installedSupportMe": {
"message": "Unterstütze mich!"
},
"updatedYTPUpdated": {
"message": "PreMiD wurde aktualisiert!"
},
"updatedWhatsNew": {
"message": "Was ist neu?"
},
"updatedWhatChanged": {
"message": "Was hat sich geändert?"
},
"updatedAdded0": {
"message": "Support für JKAnime & KissAnime"
},
"updatedAdded1": {
"message": "Erweiterungs Popup"
},
"updatedChanged0": {
"message": "Eine Menge und Ich meine eine Menge Neuschreibungen!"
},
"updatedChanged1": {
"message": "Große Schnelligkeits Verbesserungen der App"
},
"updatedAdded2": {
"message": "Einstellungs Synchronisation (Google Account)"
},
"playbackPlaying": {
"message": "Wiedergabe"
},
"playbackPaused": {
"message": "Wiedergabe pausiert"
},
"about": {
"message": "Über"
},
"feedback": {
"message": "Feedback"
},
"options": {
"message": "Optionen"
},
"general": {
"message": "Allgemein"
},
"enabled": {
"message": "Eingeschaltet"
},
"titleMenubar": {
"message": "Titel Menubar"
},
"mediaControls": {
"message": "Medien Kontrolle"
},
"checkForUpdates": {
"message": "Nach Updates suchen"
},
"systemStartup": {
"message": "System start"
},
"presences": {
"message": "Presencen"
}
}

View File

@@ -0,0 +1,104 @@
{
"appDesc": {
"message": "PreMiD adds Discord Rich Presence integration, Media controls and much more to YouTube/YouTube Music, Twitch etc..."
},
"connected": {
"message": "Connected"
},
"disconnected": {
"message": "Disconnected"
},
"installedThanks": {
"message": "Thank you for installing PreMiD"
},
"installedApp": {
"message": "Did you install the application yet?"
},
"installedNo": {
"message": "No? Follow these steps:"
},
"installedStepApp": {
"message": "Download the latest version from $1"
},
"installedStepAppMyRepository": {
"message": "my repository"
},
"installedWaitInstalled": {
"message": "Open the installer and wait until it installed"
},
"installedMayWarning": {
"message": "You may receive a warning about FireWall and SmartScreen (Its not a virus i promise)"
},
"installedAppAutostart": {
"message": "The application should start automatically, you can check this by looking at your taskbar (Windows) or your menubar (MacOS)"
},
"installedYes": {
"message": "Yes? You are ready to go!"
},
"installedStart": {
"message": "Start by watching a video on YouTube, watching your loved streamers on Twitch, Watch your favourite animes on KissAnime or JKAnime, maybe even Netflix... Who knows?<br>Or you just listen to your favourite songs on SoundCloud and YouTube Music. Settings can be found by clicking the PreMiD icon in your browser."
},
"installedSupportMe": {
"message": "Support me!"
},
"updatedYTPUpdated": {
"message": "PreMiD has been updated!"
},
"updatedWhatsNew": {
"message": "Whats new?"
},
"updatedWhatChanged": {
"message": "What changed?"
},
"playbackPlaying": {
"message": "Playing back"
},
"playbackPaused": {
"message": "Playback paused"
},
"about": {
"message": "About"
},
"feedback": {
"message": "Feedback"
},
"options": {
"message": "Options"
},
"general": {
"message": "General"
},
"enabled": {
"message": "Enabled"
},
"titleMenubar": {
"message": "Title Menubar"
},
"mediaControls": {
"message": "Media Controls"
},
"checkForUpdates": {
"message": "Check for updates"
},
"systemStartup": {
"message": "System startup"
},
"presences": {
"message": "Presences"
},
"updatedAdded0": {
"message": "Support for JKAnime & KissAnime"
},
"updatedAdded1": {
"message": "Extension popup"
},
"updatedAdded2": {
"message": "Settings Sync (Google Account)"
},
"updatedChanged0": {
"message": "A lot and I mean a lot of rewrites!"
},
"updatedChanged1": {
"message": "Huge speed improvements to App"
}
}

View File

@@ -1,20 +0,0 @@
//* Used to send response to app
function sendAlive() {
$.ajax({
async: true,
crossDomain: true,
url: "http://localhost:3000/",
method: "POST",
headers: {
"content-type": "application/json"
},
processData: false,
data: JSON.stringify({
connected: true,
service: "keepAlive"
}),
error: function(jqXHR, textStatus, errorThrown) {}
})
}
setInterval(sendAlive, 1*5000)

54
Extension/css/connect.css Normal file
View File

@@ -0,0 +1,54 @@
#ytp-connectinfo {
position: fixed;
top: -50px;
right: 0;
z-index: 10000;
min-width: 175px;
border-bottom-left-radius: 5px;
height: 50px;
background-color: rgba(255, 255, 255, 0.5);
user-select: none;
animation-name: slideIn;
animation-duration: 5s;
animation-timing-function: cubic-bezier(0.19, 1, 0.22, 1);
color: black;
}
#ytp-connectinfo * {
margin: 0;
padding: 0;
}
#ytp-connectinfo img {
float: left;
margin: 5px;
width: 40px;
height: 40px;
}
#ytp-connectinfo h1 {
font-size: 20px;
margin-top: 4px;
}
#ytp-connectinfo h2 {
font-size: 17px;
}
@keyframes slideIn {
0% {
top: -50px;
}
10% {
top: 0;
}
90% {
top: 0;
}
100% {
top: -50px;
}
}

78
Extension/css/inputs.css Normal file
View File

@@ -0,0 +1,78 @@
/* The switch - the box around the slider */
.switch {
position: relative;
display: inline-block;
width: 35px;
height: 15px;
}
/* Hide default HTML checkbox */
.switch input {
display: none;
}
/* The slider */
.slider {
position: absolute;
cursor: pointer;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgb(255, 75, 75);
-webkit-transition: 0.25s;
transition: 0.25s;
}
.slider:before {
position: absolute;
content: "";
height: 17px;
width: 17px;
left: -2.5px;
top: -2.5px;
background-color: white;
-webkit-transition: 0.25s;
transition: 0.25s cubic-bezier(0.215, 0.61, 0.355, 1);
border: 1px solid lightgray;
}
input:checked + .slider {
background-color: rgb(75, 255, 75);
}
input:disabled + .slider {
background-color: rgb(255, 75, 75);
cursor: not-allowed;
}
input:disabled + .slider:before {
background-color: rgb(255, 75, 75);
border: 1px solid rgb(255, 75, 75);
cursor: not-allowed;
}
input:focus + .slider {
box-shadow: 0 0 1px rgb(75, 255, 75);
}
input:hover + .slider {
transform: scale(1.1);
}
input:checked + .slider:before {
transform: translateX(20px);
}
/* Rounded sliders */
.slider.round {
border-radius: 34px;
}
.slider.round:before {
border-radius: 50%;
}

15
Extension/css/options.css Normal file
View File

@@ -0,0 +1,15 @@
.right {
float: right;
}
#content h1 {
margin: 5px;
}
table {
margin: 5px;
}
tr td:first-child {
width: 90%;
}

98
Extension/css/popup.css Normal file
View File

@@ -0,0 +1,98 @@
html,
body {
margin: 0;
padding: 0;
height: 0;
width: 325px;
background-color: #282828;
}
#header {
height: 50px;
background-color: #596cae;
color: white;
text-align: center;
line-height: 50px;
}
#header h1 {
margin: 0;
font-weight: 900;
display: inline;
}
#header h1:last-child {
position: absolute;
font-weight: 700;
float: right;
right: 10px;
}
#content {
margin-top: 10px;
margin-bottom: 10px;
}
#panel {
transition: 0.5s all cubic-bezier(0.175, 0.885, 0.32, 1.275);
display: inline-block;
margin: 5px;
width: 150px;
height: 125px;
background-color: #596cae;
border-radius: 5px;
color: white;
text-align: center;
}
#panel:not(.open) {
cursor: pointer;
}
#panel:not(.open):hover {
transform: scale(1.05);
}
#panel #icon {
margin-top: 25px;
width: 50px;
height: 50px;
font-size: 50px;
}
.about {
background-color: #ff9d09 !important;
}
.options {
background-color: #7a7a7a !important;
}
.github {
background-color: #fa503c !important;
}
.open {
position: fixed;
transition: 0.5s all ease-out;
transform: scale(5);
cursor: default;
}
.open * {
transition: 0.15s all ease-out;
opacity: 0;
}
.panelContent {
position: relative;
color: white;
}
.panelContent:not(.open) {
display: none;
}
.panelContent.open {
display: block;
}

20
Extension/css/reset.css Normal file
View File

@@ -0,0 +1,20 @@
html,
body {
margin: 0;
padding: 0;
height: 0;
width: 325px;
background-color: #282828;
}
* {
color: #fff;
}
#header {
height: 50px;
background-color: #7289da;
color: white;
text-align: center;
line-height: 50px;
}

106
Extension/css/tab.css Normal file
View File

@@ -0,0 +1,106 @@
html,
body {
margin: 0;
padding: 0;
background-color: 282828;
color: white;
}
#header,
#footer {
background-color: #7289da;
color: white;
height: 60px;
}
#icon {
margin: 5px;
width: 50px;
float: left;
}
#title {
float: left;
font-size: 25px;
font-weight: 900;
margin-top: 15px;
}
#version {
margin-right: 15px;
font-size: 25px;
font-weight: 700;
float: right;
}
#content {
margin: 10px;
}
h1:not(#title):not(#version),
h2,
h3 {
margin: 0;
}
h1 {
position: relative;
font-size: 25px;
font-weight: 700;
}
h2 {
margin-top: 5px;
font-size: 20px;
}
h2:last-of-type {
margin-bottom: 5px;
}
h3 {
margin-top: 5px;
font-size: 18px;
}
p {
margin: 5px;
}
p,
li {
font-size: 17px;
}
ul {
margin: 0;
margin-top: 5px;
margin-bottom: 5px;
}
a {
transition: all 0.25s cubic-bezier(0.6, 0.29, 0.35, 0.85);
position: relative;
color: rgb(0, 125, 255);
text-decoration: none;
cursor: pointer;
}
a.hu:after {
transition: width 0.25s cubic-bezier(0.6, 0.29, 0.35, 0.85);
content: "";
position: absolute;
left: 0;
bottom: -1px;
height: 2px;
width: 0;
background-color: rgb(0, 125, 255);
}
a:hover {
color: rgb(0, 150, 255);
}
a.hu:hover:after {
width: 100%;
}

View File

@@ -1,56 +0,0 @@
//* Start interval
window.onload = function() {
setInterval(updateData, 1000)
}
//* Create needed variables
let urlForVideo,
songTime,
calcDifference = []
function updateData() {
if (document.location.href.includes("youtube"))
urlForVideo = document.location.href
if ($(".ytp-time-current").html() != " ") {
const data = {
connected: true,
service: "yt",
url: urlForVideo,
currentSongTitle: $(".style-scope.ytd-video-primary-info-renderer")
.children()
.eq(2)
.contents()
.first()
.html(),
currentSongAuthor: $(
"#upload-info .style-scope .ytd-video-owner-renderer"
)
.contents()
.first()
.html(),
currentSongStartTime: getSeconds($(".ytp-time-current").html()),
currentSongEndTime: getSeconds($(".ytp-time-duration").html()),
currentSongCover: "NAN"
}
$.ajax({
async: true,
crossDomain: true,
url: "http://localhost:3000/",
method: "POST",
headers: {
"content-type": "application/json"
},
processData: false,
data: JSON.stringify(data),
error: function(jqXHR, textStatus, errorThrown) {}
})
}
}
function getSeconds(string) {
const a = string.split(":")
const seconds = +a[0] * 60 + +a[1]
return seconds
}

View File

@@ -1,88 +0,0 @@
//* Start interval
$(document).ready(() => {
setInterval(updateData, 1000)
})
//* Create needed variables
let songTime,
splitTime,
songStartTime,
songEndTime,
songTitle,
songCover,
songAuthors = []
function updateData() {
//* Clear old authors
songAuthors = []
if($(".time-info.style-scope.ytmusic-player-bar").html() != "" &&
$(".time-info.style-scope.ytmusic-player-bar").html() != " ") {
//* Get song Time String (2:10 / 3:21)
songTime = $(".time-info.style-scope.ytmusic-player-bar").html()
//* Split to array ["2:10", "3:21"]
splitTime = songTime.split(" / ", 2)
//* Convert to seconds
songStartTime = getSeconds(splitTime[0])
songEndTime = getSeconds(splitTime[1])
//* Get Song title
songTitle = $(".title.style-scope.ytmusic-player-bar").html()
//* Get Song cover/thumbnail
songCover = $(".image.style-scope.ytmusic-player-bar").attr("src")
//* Get all authors
$(".byline.ytmusic-player-bar").contents().each(function(index, item) {
if(item.classList != undefined) {
if(item.classList.contains("yt-simple-endpoint") == true) {
songAuthors.push(item.innerHTML)
}
}
})
//* If no authors found in previous method use this
if(songAuthors.length == 0 || songAuthors.length == 1) {
//* Clear old list
songAuthors = []
songAuthors.push($(".byline.ytmusic-player-bar").contents().first().text())
}
var startTime = Date.now();
var endTime =
Math.floor(startTime / 1000) -
songStartTime +
songEndTime;
const data = {
connected: true,
service: "ytm",
currentSongTitle: songTitle,
currentSongAuthors: songAuthors,
currentSongStartTimeSeconds: songStartTime,
currentSongStartTime: startTime,
currentSongEndTime: endTime,
currentSongCover: songCover
}
//* Send data to app/server
$.ajax({
async: true,
crossDomain: true,
url: "http://localhost:3000/",
method: "POST",
headers: {
"content-type": "application/json"
},
processData: false,
data: JSON.stringify(data)
})
}
}
//* Used to extract seconds from Syntax
//* 1:39 => 99
function getSeconds(string) {
const s = string.split(":")
const seconds = +s[0] * 60 + +s[1]
return seconds
}

View File

@@ -0,0 +1,137 @@
<html>
<head>
<link rel="stylesheet" href="../../css/reset.css">
<link rel="stylesheet" href="../../css/inputs.css">
<link rel="stylesheet" href="../../css/options.css">
</head>
<body>
<div id="header">
<h1 class="Ppreferences"></h1>
</div>
<div id="content">
<h1 class="Pgeneral"></h1>
<table>
<thead>
<td></td>
<td></td>
</thead>
<tbody>
<tr id="tPresence">
<td class="Penabled"></td>
<td class="right">
<label class="switch">
<input class="togglePresence" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td class="PmediaControls"></td>
<td class="right">
<label class="switch">
<input class="toggleMediaControls" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td class="PcheckForUpdates"></td>
<td class="right">
<label class="switch">
<input class="toggleCheckUpdates" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td class="PsystemStartup"></td>
<td class="right">
<label class="switch">
<input class="toggleSystemStartup" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
</tbody>
</table>
<h1 class="Ppresences"></h1>
<table>
<thead>
<td></td>
<td></td>
</thead>
<tbody>
<tr>
<td>YouTube</td>
<td class="right">
<label class="switch">
<input class="toggleYouTube" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>YouTube Music</td>
<td class="right">
<label class="switch">
<input class="toggleYouTubeMusic" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>Twitch</td>
<td class="right">
<label class="switch">
<input class="toggleTwitch" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>SoundCloud</td>
<td class="right">
<label class="switch">
<input class="toggleSoundCloud" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>Netflix</td>
<td class="right">
<label class="switch">
<input class="toggleNetflix" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>KissAnime</td>
<td class="right">
<label class="switch">
<input class="toggleKissAnime" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>JKAnime</td>
<td class="right">
<label class="switch">
<input class="toggleJKAnime" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
</tbody>
</table>
</div>
<script src="../../js/util/jquery-3.3.1.min.js"></script>
<script src="../../js/util/socket.io-2.1.1.min.js"></script>
<script src="../../js/options.js"></script>
</body>
</html>

View File

@@ -0,0 +1,28 @@
<html>
<head>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.4.1/css/all.css" integrity="sha384-5sAR7xN1Nv6T6+dT2mhtzEpVJvfS3NScPQTrOxhwjIuvcA67KV2R5Jz6kr4abQsz"
crossorigin="anonymous">
<link rel="stylesheet" href="../../css/popup.css">
</head>
<body>
<div id="header">
<h1 class="Pname"></h1>
<h1 class="Pversion"></h1>
</div>
<div id="content">
<div id="panel" class="github">
<i id="icon" class="fab fa-github"></i>
<h1 id="name">GitHub</h1>
</div>
<div id="panel" class="options">
<i id="icon" class="fas fa-cog"></i>
<h1 id="name" class="Poptions"></h1>
</div>
</div>
<script src="../../js/util/jquery-3.3.1.min.js"></script>
<script src="../../js/popup.js"></script>
</body>
</html>

View File

@@ -0,0 +1,36 @@
<html>
<head>
<title>PreMiD</title>
<link rel="stylesheet" href="../../css/tab.css">
</head>
<body>
<div id="header">
<img id="icon" src="../../icon.png" draggable="false">
<h1 id="title">PreMiD</h1>
<h1 id="version"></h1>
</div>
<div id="content">
<h1 id="installedThanks"></h1>
<h2 id="installedApp"></h2>
<h3 id="installedNo"></h3>
<ul>
<li id="installedStepApp"></li>
<li id="installedWaitInstalled"></li>
<li id="installedMayWarning"></li>
<li id="installedAppAutostart"></li>
</ul>
<h3 id="installedYes"></h3>
<p id="installedStart"></p>
<h2 id="installedSupportMe"></h2>
<a href="https://www.patreon.com/bePatron?u=4610890" target="_blank" data-patreon-widget-type="become-patron-button"><img
src="../../images/patreonBTN.png" draggable="false" height="50px" alt="Support me on Patreon!"></a>
<a href="https://discord.gg/Kw7WaYn" target="_blank" title="Join our Discord!">
<img src="../../images/discord-logo.svg" height="50px" draggable="false" alt="Join my Discord!">
</a>
</div>
<script src="../../js/installed.js"></script>
</body>
</html>

View File

@@ -0,0 +1,32 @@
<html>
<head>
<title>PreMiD</title>
<link rel="stylesheet" href="../../css/tab.css">
</head>
<body>
<div id="header">
<img id="icon" src="../../icon.png" draggable="false">
<h1 id="title">PreMiD</h1>
<h1 id="version"></h1>
</div>
<div id="content">
<h1 id="updatedYTPUpdated"></h1>
<h2 id="updatedWhatsNew"></h2>
<ul id="updatedWhatsNewList">
</ul>
<h2 id="updatedWhatChanged"></h2>
<ul id="updatedWhatChangedList">
</ul>
<h2 id="installedSupportMe"></h2>
<a href="https://www.patreon.com/bePatron?u=4610890" target="_blank" data-patreon-widget-type="become-patron-button"><img
src="../../images/patreonBTN.png" draggable="false" height="50px" alt="Support me on Patreon!"></a>
<a href="https://discord.gg/Kw7WaYn" target="_blank" title="Join our Discord!">
<img src="../../images/discord-logo.svg" height="50px" draggable="false" alt="Join my Discord!">
</a>
</div>
<script src="../../js/updated.js"></script>
</body>
</html>

BIN
Extension/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -0,0 +1 @@
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 272.1"><style>.st0{fill:#7289DA;}</style><path class="st0" d="M142.8 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11s-4.6-11-10.2-11zM106.3 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11 .1-6.1-4.5-11-10.2-11z"/><path class="st0" d="M191.4 36.9h-134c-11.3 0-20.5 9.2-20.5 20.5v134c0 11.3 9.2 20.5 20.5 20.5h113.4l-5.3-18.3 12.8 11.8 12.1 11.1 21.6 18.7V57.4c-.1-11.3-9.3-20.5-20.6-20.5zm-38.6 129.5s-3.6-4.3-6.6-8c13.1-3.7 18.1-11.8 18.1-11.8-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.4-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.6-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.2-1.8-1-2.8-1.7-2.8-1.7s4.8 7.9 17.5 11.7c-3 3.8-6.7 8.2-6.7 8.2-22.1-.7-30.5-15.1-30.5-15.1 0-31.9 14.4-57.8 14.4-57.8 14.4-10.7 28-10.4 28-10.4l1 1.2c-18 5.1-26.2 13-26.2 13s2.2-1.2 5.9-2.8c10.7-4.7 19.2-5.9 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.5 0 0-7.9-7.5-24.9-12.6l1.4-1.6s13.7-.3 28 10.4c0 0 14.4 25.9 14.4 57.8 0-.1-8.4 14.3-30.5 15zM303.8 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1h33.2c17.8.1 34.5-8.8 34.5-29.2v-29.8c.1-20.8-16.6-29.9-34.4-29.9zm174 59.7v-30.6c0-11 19.8-13.5 25.8-2.5l18.3-7.4c-7.2-15.8-20.3-20.4-31.2-20.4-17.8 0-35.4 10.3-35.4 30.3v30.6c0 20.2 17.6 30.3 35 30.3 11.2 0 24.6-5.5 32-19.9l-19.6-9c-4.8 12.3-24.9 9.3-24.9-1.4zM417.3 113c-6.9-1.5-11.5-4-11.8-8.3.4-10.3 16.3-10.7 25.6-.8l14.7-11.3c-9.2-11.2-19.6-14.2-30.3-14.2-16.3 0-32.1 9.2-32.1 26.6 0 16.9 13 26 27.3 28.2 7.3 1 15.4 3.9 15.2 8.9-.6 9.5-20.2 9-29.1-1.8l-14.2 13.3c8.3 10.7 19.6 16.1 30.2 16.1 16.3 0 34.4-9.4 35.1-26.6 1-21.7-14.8-27.2-30.6-30.1zm-67 55.5h22.4V79.7h-22.4v88.8zM728 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1H728c17.8.1 34.5-8.8 34.5-29.2v-29.8c0-20.8-16.7-29.9-34.5-29.9zm-162.9-1.2c-18.4 0-36.7 10-36.7 30.5v30.3c0 20.3 18.4 30.5 36.9 30.5 18.4 0 36.7-10.2 36.7-30.5V109c0-20.4-18.5-30.5-36.9-30.5zm14.4 60.8c0 6.4-7.2 9.7-14.3 9.7-7.2 0-14.4-3.1-14.4-9.7V109c0-6.5 7-10 14-10 7.3 0 14.7 3.1 14.7 10v30.3zM682.4 109c-.5-20.8-14.7-29.2-33-29.2h-35.5v88.8h22.7v-28.2h4l20.6 28.2h28L665 138.1c10.7-3.4 17.4-12.7 17.4-29.1zm-32.6 12h-13.2v-20.3h13.2c14.1 0 14.1 20.3 0 20.3z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

View File

@@ -0,0 +1,62 @@
chrome.runtime.onInstalled.addListener(function(details) {
switch(details.reason) {
case "install": {
chrome.tabs.create({url: "html/tabs/installed.html"})
break;
}
case "update": {
chrome.tabs.create({url: "html/tabs/updated.html"})
break;
}
}
})
//* Tab Priority
var lastAllowedTab = null,
allowedURL = []
setInterval(() => {
chrome.storage.sync.get(['options'], function(result) {
allowedURL = ["www.youtube.com", "music.youtube.com", "twitch.tv", "soundcloud.com", "netflix.com", "kissanime.ac", "kissanime.ru", "jkanime.net"]
var options = result.options
if(!options.enabled) allowedURL = []
if(!options.youtube) allowedURL.remove("www.youtube.com")
if(!options.youtubeMusic) allowedURL.remove("music.youtube.com")
if(!options.twitch) allowedURL.remove("twitch.tv")
if(!options.soundcloud) allowedURL.remove("soundcloud.com")
if(!options.netflix) allowedURL.remove("netflix.com")
if(!options.kissanime) allowedURL.remove("kissanime.ac") && allowedURL.remove('kissanime.ru')
if(!options.jkanime) allowedURL.remove("jkanime.net")
})
chrome.tabs.getAllInWindow(null, (tabs) => {
for (var i = 0; i < allowedURL.length; i++) {
var currentTab = tabs.find(tab => tab.highlighted)
if(currentTab.url.indexOf(allowedURL[i]) > -1) {
lastAllowedTab = currentTab.id
}
}
if(lastAllowedTab != null) {
chrome.tabs.sendMessage(lastAllowedTab, {"high": true})
}
})
}, 500)
Array.prototype.remove = function() {
var what, a = arguments, L = a.length, ax;
while (L && this.length) {
what = a[--L];
while ((ax = this.indexOf(what)) !== -1) {
this.splice(ax, 1);
}
}
return this;
};
//* Create socket connection to application
var socket = io.connect('http://localhost:3020/');
setInterval(() => {
chrome.storage.sync.get(['options'], function(result) {
socket.emit('settingsChange', result)
})
}, 1000)

11
Extension/js/installed.js Normal file
View File

@@ -0,0 +1,11 @@
document.getElementById('version').innerHTML = 'V' + chrome.runtime.getManifest().version
document.getElementById('installedThanks').innerHTML = chrome.i18n.getMessage("installedThanks")
document.getElementById('installedApp').innerHTML = chrome.i18n.getMessage("installedApp")
document.getElementById('installedNo').innerHTML = chrome.i18n.getMessage("installedNo")
document.getElementById('installedStepApp').innerHTML = chrome.i18n.getMessage("installedStepApp", "<a class='hu' target='_blank' href='https://github.com/Timeraa/PreMiD/releases/latest'>" + chrome.i18n.getMessage("installedStepAppMyRepository") + "</a>")
document.getElementById('installedWaitInstalled').innerHTML = chrome.i18n.getMessage("installedWaitInstalled")
document.getElementById('installedMayWarning').innerHTML = chrome.i18n.getMessage("installedMayWarning")
document.getElementById('installedAppAutostart').innerHTML = chrome.i18n.getMessage("installedAppAutostart")
document.getElementById('installedYes').innerHTML = chrome.i18n.getMessage("installedYes")
document.getElementById('installedStart').innerHTML = chrome.i18n.getMessage("installedStart")
document.getElementById('installedSupportMe').innerHTML = chrome.i18n.getMessage("installedSupportMe")

140
Extension/js/options.js Normal file
View File

@@ -0,0 +1,140 @@
let options = undefined
$('.Ppreferences').html(chrome.i18n.getMessage('options'))
$('.Pgeneral').html(chrome.i18n.getMessage('general'))
$('.Penabled').html(chrome.i18n.getMessage('enabled'))
$('.PmediaControls').html(chrome.i18n.getMessage('mediaControls'))
$('.PcheckForUpdates').html(chrome.i18n.getMessage('checkForUpdates'))
$('.PsystemStartup').html(chrome.i18n.getMessage('systemStartup'))
$('.Ppresences').html(chrome.i18n.getMessage('presences'))
chrome.runtime.getPlatformInfo(function(info) {
if(info.os == "mac")
$('<tr><td>Title Menubar</td><td><label class="switch"><input class="toggleTitleMenubar" type="checkbox"><span class="slider round"></span></label></td></tr>').insertAfter('#tPresence')
titleMenubarToggle = $('.toggleTitleMenubar')
titleMenubarToggle.change(tMB);
})
$(document).ready(function() {
var enabledToggle = $('.togglePresence'),
youtubeToggle = $('.toggleYouTube'),
youtubeMusicToggle = $('.toggleYouTubeMusic'),
twitchToggle = $('.toggleTwitch'),
soundcloudToggle = $('.toggleSoundCloud'),
netflixToggle = $('.toggleNetflix'),
kissanimeToggle = $('.toggleKissAnime'),
jkanimeToggle = $('.toggleJKAnime')
mediaControlsToggle = $('.toggleMediaControls')
checkForUpdatesToggle = $('.toggleCheckUpdates')
systemStartupToggle = $('.toggleSystemStartup')
enabledToggle.change(tEnabled);
youtubeToggle.change(tYT);
youtubeMusicToggle.change(tYTM);
twitchToggle.change(tT);
soundcloudToggle.change(tSC);
netflixToggle.change(tN);
kissanimeToggle.change(tKA);
jkanimeToggle.change(tJKA);
mediaControlsToggle.change(tMC);
checkForUpdatesToggle.change(tCFU);
systemStartupToggle.change(tSS);
chrome.storage.sync.get(['options'], function(result) {
options = result.options
if(result.options == undefined) {
chrome.storage.sync.set({options: {enabled: true, youtube: true, youtubeMusic: true, twitch: true, soundcloud: true, netflix: true, kissanime: true, jkanime: true, titleMenubar: true, mediaControls: true, checkForUpdates: true, systemStartup: true}})
enabledToggle.prop('checked', true)
youtubeToggle.prop('checked', true)
youtubeMusicToggle.prop('checked', true)
twitchToggle.prop('checked', true)
soundcloudToggle.prop('checked', true)
netflixToggle.prop('checked', true)
kissanimeToggle.prop('checked', true)
jkanimeToggle.prop('checked', true)
if(titleMenubarToggle != undefined)
titleMenubarToggle.prop('checked', true)
mediaControlsToggle.prop('checked', true)
checkForUpdatesToggle.prop('checked', true)
systemStartupToggle.prop('checked', true)
} else {
enabledToggle.prop('checked', result.options.enabled)
youtubeToggle.prop('checked', result.options.youtube)
youtubeMusicToggle.prop('checked', result.options.youtubeMusic)
twitchToggle.prop('checked', result.options.twitch)
soundcloudToggle.prop('checked', result.options.soundcloud)
netflixToggle.prop('checked', result.options.netflix)
kissanimeToggle.prop('checked', result.options.kissanime)
jkanimeToggle.prop('checked', result.options.jkanime)
if(titleMenubarToggle != undefined)
titleMenubarToggle.prop('checked', result.options.titleMenubar)
mediaControlsToggle.prop('checked', result.options.mediaControls)
checkForUpdatesToggle.prop('checked', result.options.checkForUpdates)
systemStartupToggle.prop('checked', result.options.systemStartup)
}
})
})
function tEnabled() {
options.enabled = !options.enabled
sync()
}
function tYT() {
options.youtube = !options.youtube
sync()
}
function tYTM() {
options.youtubeMusic = !options.youtubeMusic
sync()
}
function tT() {
options.twitch = !options.twitch
sync()
}
function tSC() {
options.soundcloud = !options.soundcloud
sync()
}
function tN() {
options.netflix = !options.netflix
sync()
}
function tKA() {
options.kissanime = !options.kissanime
sync()
}
function tJKA() {
options.jkanime = !options.jkanime
sync()
}
function tMB() {
options.titleMenubar = !options.titleMenubar
sync()
}
function tMC() {
options.mediaControls = !options.mediaControls
sync()
}
function tCFU() {
options.checkForUpdates = !options.checkForUpdates
sync()
}
function tSS() {
options.systemStartup = !options.systemStartup
sync()
}
function sync() {
chrome.storage.sync.set({options: options})
}

20
Extension/js/popup.js Normal file
View File

@@ -0,0 +1,20 @@
$(document).ready(function() {
$('.Pname').html(chrome.runtime.getManifest().name)
$('.Pversion').html('V' + chrome.runtime.getManifest().version)
$('.Pabout').html(chrome.i18n.getMessage('about'))
$('.Pfeedback').html(chrome.i18n.getMessage('feedback'))
$('.Poptions').html(chrome.i18n.getMessage('options'))
$('#content #panel').each(function() {
this.addEventListener('click', updateItem)
})
})
function updateItem() {
$(this).addClass('open')
setTimeout(() => {
if($(this).attr("class").split(' ')[0] == "github") {
chrome.tabs.create({url: 'https://github.com/Timeraa/PreMiD'})
} else window.location.href= $(this).attr("class").split(' ')[0] + ".html";
}, 350)
}

View File

@@ -0,0 +1,146 @@
let videoRunning = false,
tabActive = 0,
dataUpdaterRunning = false,
dataUpdater
//* Update data and send to application
$(document).ready(() => {
setInterval(playbackChange, 250)
//* Tab Priority
setInterval(() => {
if(tabActive == 5) {
dataUpdaterRunning = false
videoRunning = false
clearInterval(dataUpdater)
}
if(tabActive >= 9 && dataUpdaterRunning == false) {
dataUpdaterRunning = true
dataUpdater = setInterval(updateData, 1000)
}
if(tabActive > 0) tabActive--
}, 500)
})
chrome.runtime.onMessage.addListener(((message, sender) => {
if(tabActive <= 9) tabActive += 2
if(tabActive == 0) tabActive = 5
}))
//* Handle Media Keys from sent by application
socket.on('mediaKeyHandler', handleMediaKeys)
/**
* Handles Media Keys for easy media control
* @param {Object} data Data received from socket
*/
function handleMediaKeys(data) {
//* Check if the data is for YTM & if music is running
//* Media control buttons
if (videoRunning) {
//* Switch cases for playback / Clicks corresponding buttons
switch (data.playback) {
case "pause":
$('.server-box iframe:first').contents().find('video:first')[0].paused ? $('.server-box iframe:first').contents().find('video:first')[0].play() : $('.server-box iframe:first').contents().find('video:first')[0].pause()
updateData("playPauseTrack")
break
}
}
}
/**
* Update Data and send it to the App
* @param {String} playbackChange Playback if changed
*/
function updateData(playbackChange = false) {
var eventType
videoRunning = $('.video-header h1').html() != "" && $('.server-box iframe:first').contents().find('video:first')[0] != undefined && !isNaN($('.server-box iframe:first').contents().find('video:first')[0].duration) ? true : false
if(videoRunning) {
var videoTitle = $('.video-header h1').html(),
videoEpisode = 'Episode ' + $('.video-header h1').html().split(' - ').pop(),
videoTimeSeconds = Math.floor($('.server-box iframe:first').contents().find('video:first')[0].currentTime),
videoDurationSeconds = Math.floor($('.server-box iframe:first').contents().find('video:first')[0].duration),
videoTimestamps = getTimestamps(videoTimeSeconds, videoDurationSeconds)
playback = $('.server-box iframe:first').contents().find('video:first')[0].paused ? "paused" : "playing"
if (playbackChange) eventType = 'playBackChange'; else eventType = 'updateData';
var playbackBoolean = !$('.server-box iframe:first').contents().find('video:first')[0].paused
var smallImageKey = playbackBoolean ? 'play' : 'pause',
smallImageText = playbackBoolean ? chrome.i18n.getMessage('playbackPlaying') : chrome.i18n.getMessage('playbackPaused')
if(playbackBoolean) {
var data = {
clientID: '505709790811389962',
presenceData: {
details: $('<div/>').html(videoTitle).text(),
state: $('<div/>').html(videoEpisode).text(),
largeImageKey: 'jka_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
startTimestamp: videoTimestamps[0],
endTimestamp: videoTimestamps[1]
},
currentSeconds: videoTimeSeconds,
durationSeconds: videoDurationSeconds,
trayTitle: $('<div/>').html(videoTitle).text(),
playback: playbackBoolean,
service: 'JKAnime'
}
} else {
var data = {
clientID: '505709790811389962',
presenceData: {
details: $('<div/>').html(videoTitle).text(),
state: $('<div/>').html(videoEpisode).text(),
largeImageKey: 'jka_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
},
currentSeconds: videoTimeSeconds,
durationSeconds: videoDurationSeconds,
trayTitle: $('<div/>').html(videoTitle).text(),
playback: playbackBoolean,
service: 'JKAnime'
}
}
console.log(data)
}
if(socket.connected) socket.emit(eventType, data)
}
/**
* Get Timestamps
* @param {Number} videoTime Song Time
* @param {Number} videoDuration Song Duration
*/
function getTimestamps(videoTime, videoDuration) {
var startTime = Date.now();
var endTime =
Math.floor(startTime / 1000) -
videoTime +
videoDuration;
return [Math.floor(startTime/1000), endTime]
}
/**
* Toggles playback
*/
function togglePlayback() {
//* Toggle playback variable
playback = !playback
//* Send status to application
updateData(playback ? "playing" : "paused")
}
var lastPlayback = false
function playbackChange() {
if(videoRunning) {
if($('.server-box iframe:first').contents().find('video:first')[0].paused != lastPlayback) {
togglePlayback()
lastPlayback = $('.server-box iframe:first').contents().find('video:first')[0].paused
}
}
}

View File

@@ -0,0 +1,145 @@
let videoRunning = false,
tabActive = 0,
dataUpdaterRunning = false,
dataUpdater
//* Update data and send to application
$(document).ready(() => {
setInterval(playbackChange, 250)
//* Tab Priority
setInterval(() => {
if(tabActive == 5) {
dataUpdaterRunning = false
videoRunning = false
clearInterval(dataUpdater)
}
if(tabActive >= 9 && dataUpdaterRunning == false) {
dataUpdaterRunning = true
dataUpdater = setInterval(updateData, 1000)
}
if(tabActive > 0) tabActive--
}, 500)
})
chrome.runtime.onMessage.addListener(((message, sender) => {
if(tabActive <= 9) tabActive += 2
if(tabActive == 0) tabActive = 5
}))
//* Handle Media Keys from sent by application
socket.on('mediaKeyHandler', handleMediaKeys)
/**
* Handles Media Keys for easy media control
* @param {Object} data Data received from socket
*/
function handleMediaKeys(data) {
//* Check if the data is for YTM & if music is running
//* Media control buttons
if (videoRunning) {
//* Switch cases for playback / Clicks corresponding buttons
switch (data.playback) {
case "pause":
$('#player_html5_html5_api')[0].paused ? $('#player_html5_html5_api')[0].play() : $('#player_html5_html5_api')[0].pause()
updateData("playPauseTrack")
break
}
}
}
/**
* Update Data and send it to the App
* @param {String} playbackChange Playback if changed
*/
function updateData(playbackChange = false) {
var eventType
videoRunning = $('.movie_back_link strong').html() != "" && $('#player_html5_html5_api')[0] != undefined && !isNaN($('#player_html5_html5_api')[0].duration) ? true : false
if(videoRunning) {
var videoTitle = $('.movie_back_link strong').html(),
videoEpisode = $('#selectEpisode option:selected').text().trim(),
videoTimeSeconds = Math.floor($('#player_html5_html5_api')[0].currentTime),
videoDurationSeconds = Math.floor($('#player_html5_html5_api')[0].duration),
videoTimestamps = getTimestamps(videoTimeSeconds, videoDurationSeconds)
playback = $('#player_html5_html5_api')[0].paused ? "paused" : "playing"
if (playbackChange) eventType = 'playBackChange'; else eventType = 'updateData';
var playbackBoolean = !$('#player_html5_html5_api')[0].paused
var smallImageKey = playbackBoolean ? 'play' : 'pause',
smallImageText = playbackBoolean ? chrome.i18n.getMessage('playbackPlaying') : chrome.i18n.getMessage('playbackPaused')
if(playbackBoolean) {
var data = {
clientID: '505704053238398986',
presenceData: {
details: $('<div/>').html(videoTitle).text(),
state: $('<div/>').html(videoEpisode).text(),
largeImageKey: 'ka_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
startTimestamp: videoTimestamps[0],
endTimestamp: videoTimestamps[1]
},
currentSeconds: videoTimeSeconds,
durationSeconds: videoDurationSeconds,
trayTitle: $('<div/>').html(videoTitle).text(),
playback: playbackBoolean,
service: 'KissAnime'
}
} else {
var data = {
clientID: '505704053238398986',
presenceData: {
details: $('<div/>').html(videoTitle).text(),
state: $('<div/>').html(videoEpisode).text(),
largeImageKey: 'ka_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
},
currentSeconds: videoTimeSeconds,
durationSeconds: videoDurationSeconds,
trayTitle: $('<div/>').html(videoTitle).text(),
playback: playbackBoolean,
service: 'KissAnime'
}
}
}
if(socket.connected) socket.emit(eventType, data)
}
/**
* Get Timestamps
* @param {Number} videoTime Song Time
* @param {Number} videoDuration Song Duration
*/
function getTimestamps(videoTime, videoDuration) {
var startTime = Date.now();
var endTime =
Math.floor(startTime / 1000) -
videoTime +
videoDuration;
return [Math.floor(startTime/1000), endTime]
}
/**
* Toggles playback
*/
function togglePlayback() {
//* Toggle playback variable
playback = !playback
//* Send status to application
updateData(playback ? "playing" : "paused")
}
var lastPlayback = false
function playbackChange() {
if(videoRunning) {
if($('#player_html5_html5_api')[0].paused != lastPlayback) {
togglePlayback()
lastPlayback = $('#player_html5_html5_api')[0].paused
}
}
}

View File

@@ -0,0 +1,156 @@
let playback = true,
eventType,
playbackNew,
tabActive = 0,
dataUpdaterRunning = false,
dataUpdater
var lastPlaybackState = true
setInterval(() => {
if($('.VideoContainer div video')[0] != null && $('.VideoContainer div video')[0].paused && lastPlaybackState == true) {
handlePlayPause()
lastPlaybackState = false;
}
if($('.VideoContainer div video')[0] != null && !$('.VideoContainer div video')[0].paused && lastPlaybackState == false) {
handlePlayPause()
lastPlaybackState = true;
}
}, 500)
//* When we receive messages from the application
socket.on('mediaKeyHandler', function (data) {
//* Check if the data is for YTM & if music is running
//* Media control buttons
if (musicRunning) {
//* Switch cases for playback / Clicks corresponding buttons
switch (data.playback) {
case "pause":
$('.VideoContainer div video')[0].paused ? $('.VideoContainer div video')[0].play() : $('.VideoContainer div video')[0].pause()
updateData("playPauseVideo")
break
case "nextTrack":
$('.button-nfplayerNextEpisode').click()
//* Prevent playback from being paused again
playback = true
//* Send response back to application
updateData("nextVideo")
break
}
}
})
function handlePlayPause() {
//* Toggle playback variable
if (playback == true) playback = false; else playback = true;
//* Send status to application
updateData(playback ? "playing" : "paused")
}
function checkPlayChange() {
//* Correct playback if out of sync
if (playback == false) {
//* Check if playbutton on page matches variable
if ($('.ytp-play-button svg').prop("outerHTML") == playButton) {
//* Update playback variable
playback = true
//* Pause song
$('.ytp-play-button').click()
}
}
//* Set musicRunning variable to true if url has /watch or music title not empty
if (document.location.pathname.includes("/watch")) musicRunning = true; else musicRunning = false;
}
//* Start interval
window.onload = function () {
//* Tab Priority
setInterval(() => {
if(tabActive == 5) {
dataUpdaterRunning = false
clearInterval(dataUpdater)
}
if(tabActive >= 9 && dataUpdaterRunning == false) {
dataUpdaterRunning = true
dataUpdater = setInterval(updateData, 1000)
}
if(tabActive > 0) tabActive--
}, 500)
}
chrome.runtime.onMessage.addListener(((message, sender) => {
if(tabActive <= 9) tabActive += 2
if(tabActive == 0) tabActive = 5
}))
//* Create needed variables
let urlForVideo,
songTime,
calcDifference = []
function updateData(playbackChange = false) {
if (document.location.pathname.includes("/watch")) musicRunning = true; else musicRunning = false;
urlForVideo = document.location.href
if ($(".time-remaining__time").html() != "") {
let data
if (playbackChange != false) {
var eventType = 'playBackChange'
} else {
var eventType = 'updateData'
}
var endTime
if(musicRunning && $('.VideoContainer div video')[0] != undefined) {
var startTime = Math.floor(Date.now()/1000);
endTime = startTime -
Math.floor($('.VideoContainer div video')[0].currentTime) +
Math.floor($('.VideoContainer div video')[0].duration);
var playbackBoolean = !$('.VideoContainer div video')[0].paused
var smallImageKey = playbackBoolean ? "play" : "pause"
smallImageText = playbackBoolean ? chrome.i18n.getMessage('playbackPlaying') : chrome.i18n.getMessage('playbackPaused')
if(playbackBoolean) {
data = {
clientID: '499981204045430784',
presenceData: {
details: $('.ellipsize-text').children().html(),
state: $($('.ellipsize-text').children().get(1)).html(),
largeImageKey: 'nflix_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
startTimestamp: startTime,
endTimestamp: endTime
},
currentSeconds: Math.floor($('.VideoContainer div video')[0].currentTime),
durationSeconds: Math.floor($('.VideoContainer div video')[0].duration),
trayTitle: $('.ellipsize-text').children().html(),
playback: playbackBoolean,
service: 'Netflix'
}
} else {
data = {
clientID: '499981204045430784',
presenceData: {
details: $('.ellipsize-text').children().html(),
state: $($('.ellipsize-text').children().get(1)).html(),
largeImageKey: 'nflix_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText
},
currentSeconds: Math.floor($('.VideoContainer div video')[0].currentTime),
durationSeconds: Math.floor($('.VideoContainer div video')[0].duration),
trayTitle: $('.ellipsize-text').children().html(),
playback: playbackBoolean,
service: 'Netflix'
}
}
}
if (socket.connected) socket.emit(eventType, data)
}
}

View File

@@ -0,0 +1,182 @@
let playback = true,
eventType,
playbackNew,
tabActive = 0,
dataUpdaterRunning = false,
dataUpdater
var lastPlaybackState = true
setInterval(() => {
if($('.playControl').hasClass('playing') && lastPlaybackState == true) {
handlePlayPause()
lastPlaybackState = false;
}
if(!$('.playControl').hasClass('playing') && lastPlaybackState == false) {
handlePlayPause()
lastPlaybackState = true;
}
}, 500)
//* When we receive messages from the application
socket.on('mediaKeyHandler', function (data) {
//* Check if the data is for YTM & if music is running
//* Media control buttons
if ($('.playControl') != undefined) {
//* Switch cases for playback / Clicks corresponding buttons
switch (data.playback) {
case "pause":
$('.playControl').click()
updateData("playPauseVideo")
break
case "nextTrack":
$('.skipControl__next').click()
//* Prevent playback from being paused again
playback = true
//* Send response back to application
updateData("nextVideo")
break
case "previousTrack":
$('.skipControl__previous').click()
//* Prevent playback from being paused again
playback = true
//* Send response back to application
updateData("nextVideo")
break
}
}
})
function handlePlayPause() {
//* Toggle playback variable
if (playback == true) playback = false; else playback = true;
//* Send status to application
updateData(playback ? "playing" : "paused")
}
function checkPlayChange() {
//* Correct playback if out of sync
if (playback == false) {
//* Check if playbutton on page matches variable
if ($('.ytp-play-button svg').prop("outerHTML") == playButton) {
//* Update playback variable
playback = true
//* Pause song
$('.ytp-play-button').click()
}
}
}
//* Start interval
window.onload = function () {
//* Tab Priority
setInterval(() => {
if(tabActive == 5) {
dataUpdaterRunning = false
clearInterval(dataUpdater)
}
if(tabActive >= 9 && dataUpdaterRunning == false) {
dataUpdaterRunning = true
dataUpdater = setInterval(updateData, 1000)
}
if(tabActive > 0) tabActive--
}, 500)
}
chrome.runtime.onMessage.addListener(((message, sender) => {
if(tabActive <= 9) tabActive += 2
if(tabActive == 0) tabActive = 5
}))
//* Create needed variables
let urlForVideo,
songTime,
calcDifference = []
function updateData(playbackChange = false) {
urlForVideo = document.location.href
if ($(".time-remaining__time").html() != "") {
let data
if (playbackChange != false) {
var eventType = 'playBackChange'
} else {
var eventType = 'updateData'
}
var endTime
if($('.playbackSoundBadge__titleContextContainer') != undefined) {
var startTime = Math.floor(Date.now()/1000);
endTime = startTime -
getSeconds($('.playbackTimeline__timePassed').children().get(1).innerHTML) + getSeconds($('.playbackTimeline__duration').children().get(1).innerHTML);
var playbackBoolean = $('.playControl').hasClass('playing')
var smallImageKey = playbackBoolean ? 'play' : 'pause',
smallImageText = playbackBoolean ? chrome.i18n.getMessage('playbackPlaying') : chrome.i18n.getMessage('playbackPaused')
var songTitle = $('.playbackSoundBadge__titleLink').children().get(1).innerHTML,
songAuthorsString = $('.playbackSoundBadge__titleContextContainer').children().get(0).innerHTML;
if(playbackBoolean) {
data = {
clientID: '501021185887436810',
presenceData: {
details: $('<div/>').html(songTitle).text(),
state: $('<div/>').html(songAuthorsString).text(),
largeImageKey: 'scloud_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
startTimestamp: startTime,
endTimestamp: endTime
},
currentSeconds: getSeconds($('.playbackTimeline__timePassed').children().get(1).innerHTML),
durationSeconds: getSeconds($('.playbackTimeline__duration').children().get(1).innerHTML),
trayTitle: $('<div/>').html(songTitle).text(),
playback: playbackBoolean,
service: 'SoundCloud'
}
} else {
data = {
clientID: '501021185887436810',
presenceData: {
details: $('<div/>').html(songTitle).text(),
state: $('<div/>').html(songAuthorsString).text(),
largeImageKey: 'scloud_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText
},
currentSeconds: getSeconds($('.playbackTimeline__timePassed').children().get(1).innerHTML),
durationSeconds: getSeconds($('.playbackTimeline__duration').children().get(1).innerHTML),
trayTitle: $('<div/>').html(songTitle).text(),
playback: playbackBoolean,
service: 'SoundCloud'
}
}
/*data = {
scloud: {
url: urlForVideo,
songTitle: $('.playbackSoundBadge__titleLink').children().get(1).innerHTML,
songAuthor: $('.playbackSoundBadge__titleContextContainer').children().get(0).innerHTML,
songCurrentTimeSeconds: getSeconds($('.playbackTimeline__timePassed').children().get(1).innerHTML),
songEndTimeSeconds: getSeconds($('.playbackTimeline__duration').children().get(1).innerHTML),
songCurrentTime: startTime,
songEndTime: endTime,
playback: $('.playControl').hasClass('playing') ? "playing" : "paused"
}
} */
}
if (socket.connected) socket.emit(eventType, data)
}
}
function getSeconds(string) {
const a = string.split(":")
const seconds = +a[0] * 60 + +a[1]
return seconds
}

View File

@@ -0,0 +1,175 @@
let playback = true,
eventType,
playbackNew,
lastURL = null,
startTimeStamp,
tabActive = 0,
dataUpdaterRunning = false,
dataUpdater;
var lastPlaybackState = true;
setInterval(() => {
if (
$(".player-video video")[0] != null &&
$(".player-video video")[0].paused &&
lastPlaybackState == true
) {
handlePlayPause();
lastPlaybackState = false;
}
if (
$(".player-video video")[0] != null &&
!$(".player-video video")[0].paused &&
lastPlaybackState == false
) {
handlePlayPause();
lastPlaybackState = true;
}
}, 500);
//* When we receive messages from the application
socket.on("mediaKeyHandler", function(data) {
//* Check if the data is for twitch & if music is running
//* Media control buttons
if ($(".player-video video")[0] != null) {
//* Switch cases for playback / Clicks corresponding buttons
switch (data.playback) {
case "pause":
$(".player-video video")[0].paused
? $(".qa-pause-play-button").click()
: $(".qa-pause-play-button").click();
updateData("playPauseVideo");
break;
}
}
});
function handlePlayPause() {
//* Toggle playback variable
if (playback == true) playback = false;
else playback = true;
//* Send status to application
updateData(playback ? "playing" : "paused");
}
function checkPlayChange() {
//* Correct playback if out of sync
if (playback == false) {
//* Check if playbutton on page matches variable
if ($(".ytp-play-button svg").prop("outerHTML") == playButton) {
//* Update playback variable
playback = true;
//* Pause song
$(".ytp-play-button").click();
}
}
}
//* Start interval
window.onload = function() {
//* Tab Priority
setInterval(() => {
if (tabActive == 5) {
dataUpdaterRunning = false;
clearInterval(dataUpdater);
}
if (tabActive >= 9 && dataUpdaterRunning == false) {
dataUpdaterRunning = true;
dataUpdater = setInterval(updateData, 1000);
}
if (tabActive > 0) tabActive--;
}, 500);
};
chrome.runtime.onMessage.addListener((message, sender) => {
if (tabActive <= 9) tabActive += 2;
if (tabActive == 0) tabActive = 5;
});
//* Create needed variables
let urlForVideo,
songTime,
calcDifference = [];
function updateData(playbackChange = false) {
urlForVideo = document.location.href;
if (playbackChange != false) {
var eventType = "playBackChange";
} else {
var eventType = "updateData";
}
if (
$(".player-video video")[0] != undefined &&
$(".tw-ellipsis.tw-mg-b-05").children().length > 0
) {
if (urlForVideo != lastURL) {
lastURL = urlForVideo;
startTimeStamp = Math.floor(Date.now() / 1000);
}
var playbackBoolean = !$(".player-video video")[0].paused;
var smallImageKey = playbackBoolean ? "play" : "pause",
smallImageText = playbackBoolean
? chrome.i18n.getMessage("playbackPlaying")
: chrome.i18n.getMessage("playbackPaused");
var streamTitle = $(".tw-ellipsis.tw-mg-b-05")
.children()
.get(0).innerHTML,
streamHost = $(".channel-header__user h5").html();
if (playbackBoolean) {
var data = {
clientID: "501021996336021504",
presenceData: {
details: $("<div/>")
.html(streamTitle)
.text(),
state: $("<div/>")
.html(streamHost)
.text(),
largeImageKey: "twitch_lg",
largeImageText:
chrome.runtime.getManifest().name +
" V" +
chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
startTimestamp: startTimeStamp
},
trayTitle: $("<div/>")
.html(streamTitle)
.text(),
playback: playbackBoolean,
service: "Twitch"
};
} else {
var data = {
clientID: "501021996336021504",
presenceData: {
details: $("<div/>")
.html(streamTitle)
.text(),
state: $("<div/>")
.html(streamHost)
.text(),
largeImageKey: "twitch_lg",
largeImageText:
chrome.runtime.getManifest().name +
" V" +
chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText
},
trayTitle: $("<div/>")
.html(streamTitle)
.text(),
playback: playbackBoolean,
service: "Twitch"
};
}
}
if (socket.connected) socket.emit(eventType, data);
}

View File

@@ -0,0 +1,155 @@
let videoRunning = false,
tabActive = 0,
dataUpdaterRunning = false,
dataUpdater
//* Update data and send to application
$(document).ready(() => {
setInterval(playbackChange, 250)
//* Tab Priority
setInterval(() => {
if(tabActive == 5) {
dataUpdaterRunning = false
videoRunning = false
clearInterval(dataUpdater)
}
if(tabActive >= 9 && dataUpdaterRunning == false) {
dataUpdaterRunning = true
dataUpdater = setInterval(updateData, 1000)
}
if(tabActive > 0) tabActive--
}, 500)
})
chrome.runtime.onMessage.addListener(((message, sender) => {
if(tabActive <= 9) tabActive += 2
if(tabActive == 0) tabActive = 5
}))
//* Handle Media Keys from sent by application
socket.on('mediaKeyHandler', handleMediaKeys)
/**
* Handles Media Keys for easy media control
* @param {Object} data Data received from socket
*/
function handleMediaKeys(data) {
//* Check if the data is for YTM & if music is running
//* Media control buttons
if (videoRunning) {
//* Switch cases for playback / Clicks corresponding buttons
switch (data.playback) {
case "pause":
$('.ytp-play-button').click()
updateData("playPauseTrack")
break
case "nextTrack":
$('.ytp-next-button')[0].click()
//* Send response back to application
updateData("nextTrack")
break
case "previousTrack":
$('.ytp-prev-button')[0].click()
//* Send response back to application
updateData("previousTrack")
break
}
}
}
/**
* Update Data and send it to the App
* @param {String} playbackChange Playback if changed
*/
function updateData(playbackChange = false) {
var eventType
videoRunning = $('.ytd-video-primary-info-renderer .title').text() != "" && $('.video-stream')[0] != undefined && !isNaN($('.video-stream')[0].duration) ? true : false
if(videoRunning) {
var videoTitle = $('.ytd-video-primary-info-renderer .title').text(),
videoAuthor = $("#upload-info .style-scope .ytd-video-owner-renderer").contents().first().html(),
videoTimeSeconds = Math.floor($('.video-stream')[0].currentTime),
videoDurationSeconds = Math.floor($('.video-stream')[0].duration),
videoTimestamps = getTimestamps(videoTimeSeconds, videoDurationSeconds)
playback = $('.video-stream')[0].paused ? "paused" : "playing"
if (playbackChange) eventType = 'playBackChange'; else eventType = 'updateData';
var playbackBoolean = !$('.video-stream')[0].paused
var smallImageKey = playbackBoolean ? 'play' : 'pause',
smallImageText = playbackBoolean ? chrome.i18n.getMessage('playbackPlaying') : chrome.i18n.getMessage('playbackPaused')
if(playbackBoolean) {
var data = {
clientID: '463097721130188830',
presenceData: {
details: $('<div/>').html(videoTitle).text(),
state: $('<div/>').html(videoAuthor).text(),
largeImageKey: 'yt_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
startTimestamp: videoTimestamps[0],
endTimestamp: videoTimestamps[1]
},
currentSeconds: videoTimeSeconds,
durationSeconds: videoDurationSeconds,
trayTitle: $('<div/>').html(videoTitle).text(),
playback: playbackBoolean,
service: 'YouTube'
}
} else {
var data = {
clientID: '463097721130188830',
presenceData: {
details: $('<div/>').html(videoTitle).text(),
state: $('<div/>').html(videoAuthor).text(),
largeImageKey: 'yt_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
},
currentSeconds: videoTimeSeconds,
durationSeconds: videoDurationSeconds,
trayTitle: $('<div/>').html(videoTitle).text(),
playback: playbackBoolean,
service: 'YouTube'
}
}
}
if(socket.connected) socket.emit(eventType, data)
}
/**
* Get Timestamps
* @param {Number} videoTime Song Time
* @param {Number} videoDuration Song Duration
*/
function getTimestamps(videoTime, videoDuration) {
var startTime = Date.now();
var endTime =
Math.floor(startTime / 1000) -
videoTime +
videoDuration;
return [Math.floor(startTime/1000), endTime]
}
/**
* Toggles playback
*/
function togglePlayback() {
//* Toggle playback variable
playback = !playback
//* Send status to application
updateData(playback ? "playing" : "paused")
}
var lastPlayback = false
function playbackChange() {
if(videoRunning) {
if($('.video-stream')[0].paused != lastPlayback) {
togglePlayback()
lastPlayback = $('.video-stream')[0].paused
}
}
}

View File

@@ -0,0 +1,192 @@
let musicRunning = false,
tabActive = 0,
dataUpdaterRunning = false,
dataUpdater
//* Update data and send to application
$(document).ready(() => {
setInterval(playbackChange, 250)
//* Tab Priority
setInterval(() => {
if(tabActive == 5) {
dataUpdaterRunning = false
musicRunning = false
clearInterval(dataUpdater)
}
if(tabActive >= 9 && dataUpdaterRunning == false) {
dataUpdaterRunning = true
dataUpdater = setInterval(updateData, 1000)
}
if(tabActive > 0) tabActive--
}, 500)
})
//* Tab Priority
chrome.runtime.onMessage.addListener(((message, sender) => {
if(tabActive <= 9) tabActive += 2
if(tabActive == 0) tabActive = 5
}))
//* Handle Media Keys from sent by application
socket.on('mediaKeyHandler', handleMediaKeys)
/**
* Handles Media Keys for easy media control
* @param {Object} data Data received from socket
*/
function handleMediaKeys(data) {
//* Check if the data is for YTM & if music is running
//* Media control buttons
if (musicRunning) {
//* Switch cases for playback / Clicks corresponding buttons
switch (data.playback) {
case "pause":
$('.play-pause-button').click()
updateData("playPauseTrack")
break
case "nextTrack":
$('.next-button').click()
//* Send response back to application
updateData("nextTrack")
break
case "previousTrack":
$('.previous-button').click()
//* Send response back to application
updateData("previousTrack")
break
}
}
}
/**
* Update Data and send it to the App
* @param {String} playbackChange Playback if changed
*/
function updateData(playbackChange = false) {
var eventType
musicRunning = $(".title.style-scope.ytmusic-player-bar").html() != "" && $('.video-stream')[0] != undefined && !isNaN($('.video-stream')[0].duration) ? true : false
if(musicRunning) {
var songTitle = $(".title.style-scope.ytmusic-player-bar").html(),
songAuthors = getAuthors(),
songTimeSeconds = Math.floor($('.video-stream')[0].currentTime),
songDurationSeconds = Math.floor($('.video-stream')[0].duration),
songTimestamps = getTimestamps(songTimeSeconds, songDurationSeconds)
playback = $('.video-stream')[0].paused ? "paused" : "playing",
songAuthorsString = null;
if (playbackChange) eventType = 'playBackChange'; else eventType = 'updateData';
songAuthors.forEach((author, index, authors) => {
if (index == 0)
songAuthorsString = author;
else if (index < authors.length - 2)
songAuthorsString = songAuthorsString + ", " + author;
else if (index < authors.length - 1) songAuthorsString = songAuthorsString + " and " + author;
else songAuthorsString = songAuthorsString + " &bull; " + author;
});
var playbackBoolean = !$('.video-stream')[0].paused
var smallImageKey = playbackBoolean ? 'play' : 'pause',
smallImageText = playbackBoolean ? chrome.i18n.getMessage('playbackPlaying') : chrome.i18n.getMessage('playbackPaused')
if(playbackBoolean) {
var data = {
clientID: '463151177836658699',
presenceData: {
details: $('<div/>').html(songTitle).text(),
state: $('<div/>').html(songAuthorsString).text(),
largeImageKey: 'ytm_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText,
startTimestamp: songTimestamps[0],
endTimestamp: songTimestamps[1]
},
currentSeconds: songTimeSeconds,
durationSeconds: songDurationSeconds,
trayTitle: $('<div/>').html(songTitle).text(),
playback: playbackBoolean,
service: 'YouTube Music'
}
} else {
var data = {
clientID: '463151177836658699',
presenceData: {
details: $('<div/>').html(songTitle).text(),
state: $('<div/>').html(songAuthorsString).text(),
largeImageKey: 'ytm_lg',
largeImageText: chrome.runtime.getManifest().name + ' V' + chrome.runtime.getManifest().version,
smallImageKey: smallImageKey,
smallImageText: smallImageText
},
currentSeconds: songTimeSeconds,
durationSeconds: songDurationSeconds,
trayTitle: $('<div/>').html(songTitle).text(),
playback: playbackBoolean,
service: 'YouTube Music'
}
}
}
//* If socket connection, send data
if(socket.connected) socket.emit(eventType, data)
}
/**
* Get authors of Song
*/
function getAuthors() {
var songAuthors = []
//* Extract authors as array
$(".byline.ytmusic-player-bar").contents().each(function (index, item) {
if (item.classList != undefined) {
if (item.classList.contains("yt-simple-endpoint") == true) {
songAuthors.push(item.innerHTML)
}
}
})
//* If no authors found in previous method use this
if (songAuthors.length == 0 || songAuthors.length == 1) {
//* Clear old list
songAuthors = []
songAuthors.push($(".byline.ytmusic-player-bar").contents().first().text())
}
return songAuthors
}
/**
* Get Timestamps
* @param {Number} songTime Song Time
* @param {Number} songDuration Song Duration
*/
function getTimestamps(songTime, songDuration) {
var startTime = Date.now();
var endTime =
Math.floor(startTime / 1000) -
songTime +
songDuration;
return [Math.floor(startTime/1000), endTime]
}
/**
* Toggles playback
*/
function togglePlayback() {
//* Toggle playback variable
playback = !playback
//* Send status to application
updateData(playback ? "playing" : "paused")
}
var lastPlayback = false
function playbackChange() {
if(musicRunning) {
if($('.video-stream')[0].paused != lastPlayback) {
togglePlayback()
lastPlayback = $('.video-stream')[0].paused
}
}
}

27
Extension/js/updated.js Normal file
View File

@@ -0,0 +1,27 @@
document.getElementById('version').innerHTML = 'V' + chrome.runtime.getManifest().version
document.getElementById('updatedYTPUpdated').innerHTML = chrome.i18n.getMessage("updatedYTPUpdated")
document.getElementById('updatedWhatsNew').innerHTML = chrome.i18n.getMessage("updatedWhatsNew")
var hasNextChanged = true,
index = 0
while(hasNextChanged) {
if(chrome.i18n.getMessage("updatedAdded" + index) != "") {
var item = document.getElementById('updatedWhatsNewList').appendChild(document.createElement('li'))
item.innerHTML = chrome.i18n.getMessage("updatedAdded" + index)
} else hasNextChanged = false;
index++
}
document.getElementById('updatedWhatChanged').innerHTML = chrome.i18n.getMessage("updatedWhatChanged")
var hasNextChanged = true,
index = 0
while(hasNextChanged) {
if(chrome.i18n.getMessage("updatedChanged" + index) != "") {
var item = document.getElementById('updatedWhatChangedList').appendChild(document.createElement('li'))
item.innerHTML = chrome.i18n.getMessage("updatedChanged" + index)
} else hasNextChanged = false;
index++
}
document.getElementById('installedSupportMe').innerHTML = chrome.i18n.getMessage("installedSupportMe")

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,27 @@
//* Create socket connection to application
var socket = io.connect('http://localhost:3020/');
//* Log when connected
socket.on('connect', socketConnect)
socket.on('disconnect', socketDisconnect)
function socketConnect() {
console.log(chrome.runtime.getManifest().name + ': %c' + chrome.i18n.getMessage('connected'), "color: green; font-weight: 700")
if(sessionStorage['ytpconnected'] == null || sessionStorage['ytpconnected'] == 'false') {
sessionStorage['ytpconnected'] = 'true'
insertConnectionInfo(chrome.i18n.getMessage("connected"))
}
}
function socketDisconnect() {
console.log(chrome.runtime.getManifest().name + ': %c' + chrome.i18n.getMessage('disconnected'), "color: red; font-weight: 700")
sessionStorage['ytpconnected'] = 'false'
insertConnectionInfo(chrome.i18n.getMessage("disconnected"))
}
function insertConnectionInfo(message) {
$('<div id="ytp-connectinfo"><img draggable="false" src="https://raw.githubusercontent.com/Timeraa/YT-Presence/master/icon.png"><h1>' + chrome.runtime.getManifest().name + '</h1><h2>' + message + '</h2></div>').appendTo('body')
setTimeout(() => {
$('#ytp-connectinfo').remove()
}, 5*1000)
}

View File

@@ -1,29 +1,75 @@
{
"name": "YT Presence",
"version": "0.3",
"description": "Discord Rich Presence for YouTube and YouTube Music.",
"manifest_version": 3,
"name": "PreMiD",
"author": "Timeraa",
"version": "1.2",
"description": "__MSG_appDesc__",
"manifest_version": 2,
"default_locale": "en",
"icons": {
"2024": "images/icon.png"
"2024": "icon.png"
},
"background": {
"scripts": ["jquery-3.3.1.min.js", "background.js"],
"persistent": true
"scripts": ["js/util/socket.io-2.1.1.min.js", "js/background.js"],
"presistent": false
},
"browser_action": {
"default_popup": "html/popup/popup.html",
"default_icon": {
"2024": "images/icon.png"
"2024": "icon.png"
}
},
"content_scripts": [
{
"js": ["jquery-3.3.1.min.js", "handleYTM.js"],
"js": [
"js/util/jquery-3.3.1.min.js",
"js/util/socket.io-2.1.1.min.js",
"js/util/socketConnector.js"
],
"css": ["css/connect.css"],
"matches": [
"https://www.youtube.com/*",
"https://music.youtube.com/*",
"https://*.netflix.com/*",
"https://soundcloud.com/*",
"https://*.twitch.tv/*",
"https://kissanime.ac/*",
"https://kissanime.ru/*",
"https://jkanime.net/*"
]
},
{
"js": ["js/presences/YouTubeMusic.js"],
"matches": ["https://music.youtube.com/*"]
},
{
"js": ["jquery-3.3.1.min.js", "handleYT.js"],
"js": ["js/presences/YouTube.js"],
"matches": ["https://www.youtube.com/*"]
},
{
"js": ["js/presences/Netflix.js"],
"matches": ["https://*.netflix.com/*"]
},
{
"js": ["js/presences/SoundCloud.js"],
"matches": ["https://*.soundcloud.com/*"]
},
{
"js": ["js/presences/Twitch.js"],
"matches": ["https://*.twitch.tv/*"]
},
{
"js": ["js/presences/KissAnime.js"],
"matches": ["https://kissanime.ac/*", "https://kissanime.ru/*"]
},
{
"js": ["js/presences/JKAnime.js"],
"matches": ["https://jkanime.net/*"]
}
],
"permissions": ["http://localhost/*", "tabs"]
"permissions": [
"http://localhost:3020/",
"tabs",
"storage",
"declarativeContent"
]
}

198
README.md
View File

@@ -1,58 +1,97 @@
## ![version](https://img.shields.io/badge/Version-0.3-brightgreen.svg?style=flat-square)
## ![version](https://img.shields.io/badge/Version-1.2-brightgreen.svg?style=flat-square) [![Discord](https://img.shields.io/discord/493130730549805057.svg?style=flat-square)](https://discord.gg/Kw7WaYn)
# <img src="icon.png" width="20" draggable="false"><b> </b>YouTube Presence &middot; Watcha watching there? 👀
# <img src="gitassets/premid.webp" width="24px" draggable="false"><b> </b>PreMiD &middot; Discord Rich Presence for your Media!
_Show your current YouTube video/song in your Discord profile_
<a target="_blank" href="https://discord.gg/Kw7WaYn" title="Join our Discord!">
<img src="gitassets/discord.svg" height="50px" draggable="false" alt="Join my Discord!">
</a>&nbsp;
<a target="_blank" href="https://www.patreon.com/bePatron?u=4610890" data-patreon-widget-type="become-patron-button"><img src="gitassets/patreonBTN.png" draggable="false" height="50px" alt="Support me on Patreon!"></a>&nbsp;
<a target="_blank" href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZU8Q766ACS2WS&lc=US"><img src="gitassets/PayPal.svg" height="50px" draggable="false" alt="PayPal"></a>
## Table of contents
# About
- [Table of contents](#table-of-contents)
- [Installing the Extension](#installing-the-extension)
- [Installing the Application](#installing-the-application)
- Mac OS
- Windows
- [FAQ](#faq-·-frequently-asked-questions)
- Why can't i install it on the Chrome Web Store?
- Is this project up to date?
- Will this project stay free?
## Summary
## Installing the Extension
**PreMiD** is a simple, configurable utility that allows you to show what you're watching/listening in your Discord **now playing status**. It supports [many different platforms](#support), and will support multiple users watching the same content simultaneously in an upcoming update.
## Features
- Integrates with Discord's official Rich Presence API library.
- Supports your keyboard's **Media Control** function keys.
- Automatically clears your current presence after 1 minute of inactivity.
- Supports **YouTube, YouTube Music, Netflix, SoundCloud, JKAnime, KissAnime** and many more to come.
- _Watch parties and more are coming soon!_
# Table of contents
- [About](#about)
- [Summary](#summary)
- [Features](#features)
- [Support](#support)
- [Operating Systems](#operating-systems)
- [Browsers](#browsers)
- [Services](#services)
- [Installation](#installation)
- [Extension](#extension)
- Chrome
- Opera
- [Application](#application)
- Mac OS
- Windows
# Support
### **Operating Systems**
- Windows
- Mac OS
### **Browsers**
- Chrome
- Opera
### **Services**
- YouTube
- YouTube Music
- Netflix
- SoundCloud
- Twitch
- JKAnime
- KissAnime
One missing? Open an [Issue](https://github.com/Timeraa/PreMiD/issues/new?template=feature_request.md)!
# Installation
## Extension
<details>
<summary><b><u>Installing the Chrome extension</u></b> (Click to expand)</summary>
<h1>Chrome extension installation</h1>
<h1>Chrome Extension Installation</h1>
<ol>
<li>Download the latest version of the <a href="https://github.com/Timeraa/YT-Presence/releases/latest">extension</a>
<li>Click <a href="https://chrome.google.com/webstore/detail/yt-presence/agjnjboanicjcpenljmaaigopkgdnihi">this</a> link</li>
</li>
<li>Extract the downloaded <b>.zip</b> file</li>
<li>Open Chrome</li>
<li>Go to <a href="chrome://extensions/">chrome://extensions/</a></li>
<li>Turn on <b>Developer mode</b><br>
<img src="developerMode.png">
</li>
<li>Click "<b>Load unpacked extension</b>"<br>
<img src="loadUnpackedExtension.png">
</li>
<li>Load the extracted <b>Extension</b> folder</li>
<li>Install the <a href="#installing-the-application">application</a></li>
<li>Click "add to Chrome"</li>
<li>Install the <a href="#application">application</a></li>
</ol>
</details>
<details>
<summary><b><u>Installing the Opera extension</u></b> (Click to expand)</summary>
<h1>Opera extension installation</h1>
<h1>Opera Extension Installation</h1>
<ol>
<li>Download the latest version of the <a href="https://github.com/Timeraa/YT-Presence/releases/latest">extension</a>
</li>
<li>Extract the downloaded <b>.zip</b> file</li>
<li>Open Opera</li>
<li>Go to <a href="chrome://extensions/">chrome://extensions/</a></li>
<li>Drag and drop the extension's folder on the page<br>
<li>Load the extracted <b>Extension</b> folder</li>
<li>Install the <a href="#installing-the-application">application</a></li>
<li>Drag and drop the Folder <b>"Extension"</b> on the page<br>
<li>Install the <a href="#application">application</a></li>
</ol>
</details>
## Installing the Application
## Application
<details>
<summary><b><u>Mac OS</u></b> (Click to expand)</summary>
@@ -60,12 +99,12 @@ _Show your current YouTube video/song in your Discord profile_
<ol>
<li>Download the latest version of the <a href="https://github.com/Timeraa/YT-Presence/releases/latest">application</a>
</li>
<li>Extract the downloaded <b>.zip</b> file</li>
<li>Open the extracted folder and run the <b>.dmg</b> file</li>
<li>Drag <b>YT Presence</b> Into your <b>Applications</b> Folder</li>
<li>Open your Launchpad</li>
<li>Open <b>YT Presence</b></li>
<li>Enjoy!</li>
<li>Open the downloaded <b>.dmg</b> file</li>
<li>Drag <b>PreMiD</b> Into your <b>Applications</b> Folder</li>
<li>Open your Launchpad or press F4</li>
<li>Open <b>PreMiD</b></li>
<li>Press <b>"Allow"</b> if a window pops up</li>
<li>Install <a href="#extension">extension</a> if not already</li>
</ol>
</details>
@@ -73,28 +112,71 @@ _Show your current YouTube video/song in your Discord profile_
<summary><b><u>Windows</u></b> (Click to expand)</summary>
<h1>Installation on Windows</h1>
<ol>
<li>Extract the downloaded <b>.zip</b> file</li>
<li>Open extracted folder and run <b>YT Presence.exe</b></li>
<li>Download the latest installer from <a href="https://github.com/Timeraa/YT-Presence/releases/">here</a></li>
<li>Open the downloaded <b>.exe</b> installer</li>
<li>If SmartScreen comes up press more informations then press run anyways. (It's not a virus, I promise.)</li>
<li>YouTube Presence should install itself and start automatically. (You can tell by looking at the taskbar.)</li>
<li>Install the <a href="#extension">extension</a>, if you haven't already.</li>
</ol>
</details>
<br>
**Note: The windows version does not have an installer at the moment. I am working hard on packaging the application into an installer. Please be patient. Thanks**
## FAQ &middot; Frequently Asked Questions
> ## Why can't i install the extension on the **Chrome Web Store**?<br>
- Because i need to activate my google account as a Developer account but that requires **5$** and i am not paying it until i receive donations for this Project. <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZU8Q766ACS2WS&lc=US">Donate here</a>
> ## Is this project still up to date?<br>
- Yes! I use and work on this program and extension almost everyday!<br>There are currently no plans on discontinuing this Project.
> ## Will this project stay free?<br>
- Of course! Its open source! But i would highly appreciate a little bit of Money to activate the Google Developer Account so that i can put the Chrome extension on the Chrome Web store. And it would help me to get the money needed for future plans like a **Driving license** 😎<br><br><a href="https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=ZU8Q766ACS2WS&lc=US">Donate here</a>
---
### YT Presence version 0.3 &middot; By Timeraa
<h1 style="text-align: center;">Creator</h1>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/timeraa.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Timeraa</h2>
</div>
<h1 style="text-align: center;">Admin & Translation Manager</h1>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/fruxh.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Fruxh</h2>
</div>
<h1 style="text-align: center;">Patrons \ Donators</h1>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/fruxh.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Fruxh</h2>
<h3 style="text-align: center; font-weight: 700;margin: 0;">Patron</h3>
</div>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/UMU.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">UMU</h2>
<h3 style="text-align: center; font-weight: 700;margin: 0;">Patron</h3>
</div>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/paz.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Paz</h2>
<h3 style="text-align: center; font-weight: 700;margin: 0;">Paypal</h3>
</div>
<h1 style="text-align: center;">Translators</h1>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/timeraa.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Timeraa</h2>
</div>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/fruxh.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Fruxh</h2>
</div>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/restrike.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Restrike</h2>
</div>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/xiRDX.gif" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">2dward.</h2>
</div>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/ufo.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">Ufo</h2>
</div>
<div style="margin: 5px; width: 100px; display: inline-block;">
<img draggable="false" src="gitassets/VerifyBot.png" style="border-radius: 50%;" width="100px">
<h2 style="text-align: center; font-weight: 700; margin: 0;">VerifyBot</h2>
</div>
---
### PreMiD - Discord Rich Presence for your Media!

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,9 +0,0 @@
var electronInstaller = require('electron-winstaller');
resultPromise = electronInstaller.createWindowsInstaller({
appDirectory: '/out/YT Presence-win32-64x',
outputDirectory: '/dist/installerWindows',
authors: 'Timeraa',
});
resultPromise.then(() => console.log("It worked!"), (e) => console.log(`No dice: ${e.message}`));

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

BIN
dmg-background.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@@ -1,15 +0,0 @@
// config.forge.js
const path = require('path')
module.exports = {
packagerConfig: {
appBundleId: "eu.Timeraa.YTPresence",
icon: path.resolve(__dirname, 'appIcon.icns')
},
make_targets: {
win32: ["squirrel"], // An array of win32 make targets
darwin: ["dmg"], // An array of darwin make targets
linux: ["deb", "rpm", "flatpak", "snap"] // An array of linux make targets
}
}

55
gitassets/PayPal.svg Normal file
View File

@@ -0,0 +1,55 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.4, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="124px" height="33px" viewBox="0 0 124 33" enable-background="new 0 0 124 33" xml:space="preserve">
<path fill="#253B80" d="M46.211,6.749h-6.839c-0.468,0-0.866,0.34-0.939,0.802l-2.766,17.537c-0.055,0.346,0.213,0.658,0.564,0.658
h3.265c0.468,0,0.866-0.34,0.939-0.803l0.746-4.73c0.072-0.463,0.471-0.803,0.938-0.803h2.165c4.505,0,7.105-2.18,7.784-6.5
c0.306-1.89,0.013-3.375-0.872-4.415C50.224,7.353,48.5,6.749,46.211,6.749z M47,13.154c-0.374,2.454-2.249,2.454-4.062,2.454
h-1.032l0.724-4.583c0.043-0.277,0.283-0.481,0.563-0.481h0.473c1.235,0,2.4,0,3.002,0.704C47.027,11.668,47.137,12.292,47,13.154z"
/>
<path fill="#253B80" d="M66.654,13.075h-3.275c-0.279,0-0.52,0.204-0.563,0.481l-0.145,0.916l-0.229-0.332
c-0.709-1.029-2.29-1.373-3.868-1.373c-3.619,0-6.71,2.741-7.312,6.586c-0.313,1.918,0.132,3.752,1.22,5.031
c0.998,1.176,2.426,1.666,4.125,1.666c2.916,0,4.533-1.875,4.533-1.875l-0.146,0.91c-0.055,0.348,0.213,0.66,0.562,0.66h2.95
c0.469,0,0.865-0.34,0.939-0.803l1.77-11.209C67.271,13.388,67.004,13.075,66.654,13.075z M62.089,19.449
c-0.316,1.871-1.801,3.127-3.695,3.127c-0.951,0-1.711-0.305-2.199-0.883c-0.484-0.574-0.668-1.391-0.514-2.301
c0.295-1.855,1.805-3.152,3.67-3.152c0.93,0,1.686,0.309,2.184,0.892C62.034,17.721,62.232,18.543,62.089,19.449z"/>
<path fill="#253B80" d="M84.096,13.075h-3.291c-0.314,0-0.609,0.156-0.787,0.417l-4.539,6.686l-1.924-6.425
c-0.121-0.402-0.492-0.678-0.912-0.678h-3.234c-0.393,0-0.666,0.384-0.541,0.754l3.625,10.638l-3.408,4.811
c-0.268,0.379,0.002,0.9,0.465,0.9h3.287c0.312,0,0.604-0.152,0.781-0.408L84.564,13.97C84.826,13.592,84.557,13.075,84.096,13.075z
"/>
<path fill="#179BD7" d="M94.992,6.749h-6.84c-0.467,0-0.865,0.34-0.938,0.802l-2.766,17.537c-0.055,0.346,0.213,0.658,0.562,0.658
h3.51c0.326,0,0.605-0.238,0.656-0.562l0.785-4.971c0.072-0.463,0.471-0.803,0.938-0.803h2.164c4.506,0,7.105-2.18,7.785-6.5
c0.307-1.89,0.012-3.375-0.873-4.415C99.004,7.353,97.281,6.749,94.992,6.749z M95.781,13.154c-0.373,2.454-2.248,2.454-4.062,2.454
h-1.031l0.725-4.583c0.043-0.277,0.281-0.481,0.562-0.481h0.473c1.234,0,2.4,0,3.002,0.704
C95.809,11.668,95.918,12.292,95.781,13.154z"/>
<path fill="#179BD7" d="M115.434,13.075h-3.273c-0.281,0-0.52,0.204-0.562,0.481l-0.145,0.916l-0.23-0.332
c-0.709-1.029-2.289-1.373-3.867-1.373c-3.619,0-6.709,2.741-7.311,6.586c-0.312,1.918,0.131,3.752,1.219,5.031
c1,1.176,2.426,1.666,4.125,1.666c2.916,0,4.533-1.875,4.533-1.875l-0.146,0.91c-0.055,0.348,0.213,0.66,0.564,0.66h2.949
c0.467,0,0.865-0.34,0.938-0.803l1.771-11.209C116.053,13.388,115.785,13.075,115.434,13.075z M110.869,19.449
c-0.314,1.871-1.801,3.127-3.695,3.127c-0.949,0-1.711-0.305-2.199-0.883c-0.484-0.574-0.666-1.391-0.514-2.301
c0.297-1.855,1.805-3.152,3.67-3.152c0.93,0,1.686,0.309,2.184,0.892C110.816,17.721,111.014,18.543,110.869,19.449z"/>
<path fill="#179BD7" d="M119.295,7.23l-2.807,17.858c-0.055,0.346,0.213,0.658,0.562,0.658h2.822c0.469,0,0.867-0.34,0.939-0.803
l2.768-17.536c0.055-0.346-0.213-0.659-0.562-0.659h-3.16C119.578,6.749,119.338,6.953,119.295,7.23z"/>
<path fill="#253B80" d="M7.266,29.154l0.523-3.322l-1.165-0.027H1.061L4.927,1.292C4.939,1.218,4.978,1.149,5.035,1.1
c0.057-0.049,0.13-0.076,0.206-0.076h9.38c3.114,0,5.263,0.648,6.385,1.927c0.526,0.6,0.861,1.227,1.023,1.917
c0.17,0.724,0.173,1.589,0.007,2.644l-0.012,0.077v0.676l0.526,0.298c0.443,0.235,0.795,0.504,1.065,0.812
c0.45,0.513,0.741,1.165,0.864,1.938c0.127,0.795,0.085,1.741-0.123,2.812c-0.24,1.232-0.628,2.305-1.152,3.183
c-0.482,0.809-1.096,1.48-1.825,2c-0.696,0.494-1.523,0.869-2.458,1.109c-0.906,0.236-1.939,0.355-3.072,0.355h-0.73
c-0.522,0-1.029,0.188-1.427,0.525c-0.399,0.344-0.663,0.814-0.744,1.328l-0.055,0.299l-0.924,5.855l-0.042,0.215
c-0.011,0.068-0.03,0.102-0.058,0.125c-0.025,0.021-0.061,0.035-0.096,0.035H7.266z"/>
<path fill="#179BD7" d="M23.048,7.667L23.048,7.667L23.048,7.667c-0.028,0.179-0.06,0.362-0.096,0.55
c-1.237,6.351-5.469,8.545-10.874,8.545H9.326c-0.661,0-1.218,0.48-1.321,1.132l0,0l0,0L6.596,26.83l-0.399,2.533
c-0.067,0.428,0.263,0.814,0.695,0.814h4.881c0.578,0,1.069-0.42,1.16-0.99l0.048-0.248l0.919-5.832l0.059-0.32
c0.09-0.572,0.582-0.992,1.16-0.992h0.73c4.729,0,8.431-1.92,9.513-7.476c0.452-2.321,0.218-4.259-0.978-5.622
C24.022,8.286,23.573,7.945,23.048,7.667z"/>
<path fill="#222D65" d="M21.754,7.151c-0.189-0.055-0.384-0.105-0.584-0.15c-0.201-0.044-0.407-0.083-0.619-0.117
c-0.742-0.12-1.555-0.177-2.426-0.177h-7.352c-0.181,0-0.353,0.041-0.507,0.115C9.927,6.985,9.675,7.306,9.614,7.699L8.05,17.605
l-0.045,0.289c0.103-0.652,0.66-1.132,1.321-1.132h2.752c5.405,0,9.637-2.195,10.874-8.545c0.037-0.188,0.068-0.371,0.096-0.55
c-0.313-0.166-0.652-0.308-1.017-0.429C21.941,7.208,21.848,7.179,21.754,7.151z"/>
<path fill="#253B80" d="M9.614,7.699c0.061-0.393,0.313-0.714,0.652-0.876c0.155-0.074,0.326-0.115,0.507-0.115h7.352
c0.871,0,1.684,0.057,2.426,0.177c0.212,0.034,0.418,0.073,0.619,0.117c0.2,0.045,0.395,0.095,0.584,0.15
c0.094,0.028,0.187,0.057,0.278,0.086c0.365,0.121,0.704,0.264,1.017,0.429c0.368-2.347-0.003-3.945-1.272-5.392
C20.378,0.682,17.853,0,14.622,0h-9.38c-0.66,0-1.223,0.48-1.325,1.133L0.01,25.898c-0.077,0.49,0.301,0.932,0.795,0.932h5.791
l1.454-9.225L9.614,7.699z"/>
</svg>

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
gitassets/UMU.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
gitassets/VerifyBot.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

1
gitassets/discord.svg Normal file
View File

@@ -0,0 +1 @@
<svg id="Layer_1" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 800 272.1"><style>.st0{fill:#7289DA;}</style><path class="st0" d="M142.8 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11s-4.6-11-10.2-11zM106.3 120.1c-5.7 0-10.2 4.9-10.2 11s4.6 11 10.2 11c5.7 0 10.2-4.9 10.2-11 .1-6.1-4.5-11-10.2-11z"/><path class="st0" d="M191.4 36.9h-134c-11.3 0-20.5 9.2-20.5 20.5v134c0 11.3 9.2 20.5 20.5 20.5h113.4l-5.3-18.3 12.8 11.8 12.1 11.1 21.6 18.7V57.4c-.1-11.3-9.3-20.5-20.6-20.5zm-38.6 129.5s-3.6-4.3-6.6-8c13.1-3.7 18.1-11.8 18.1-11.8-4.1 2.7-8 4.6-11.5 5.9-5 2.1-9.8 3.4-14.5 4.3-9.6 1.8-18.4 1.3-25.9-.1-5.7-1.1-10.6-2.6-14.7-4.3-2.3-.9-4.8-2-7.3-3.4-.3-.2-.6-.3-.9-.5-.2-.1-.3-.2-.4-.2-1.8-1-2.8-1.7-2.8-1.7s4.8 7.9 17.5 11.7c-3 3.8-6.7 8.2-6.7 8.2-22.1-.7-30.5-15.1-30.5-15.1 0-31.9 14.4-57.8 14.4-57.8 14.4-10.7 28-10.4 28-10.4l1 1.2c-18 5.1-26.2 13-26.2 13s2.2-1.2 5.9-2.8c10.7-4.7 19.2-5.9 22.7-6.3.6-.1 1.1-.2 1.7-.2 6.1-.8 13-1 20.2-.2 9.5 1.1 19.7 3.9 30.1 9.5 0 0-7.9-7.5-24.9-12.6l1.4-1.6s13.7-.3 28 10.4c0 0 14.4 25.9 14.4 57.8 0-.1-8.4 14.3-30.5 15zM303.8 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1h33.2c17.8.1 34.5-8.8 34.5-29.2v-29.8c.1-20.8-16.6-29.9-34.4-29.9zm174 59.7v-30.6c0-11 19.8-13.5 25.8-2.5l18.3-7.4c-7.2-15.8-20.3-20.4-31.2-20.4-17.8 0-35.4 10.3-35.4 30.3v30.6c0 20.2 17.6 30.3 35 30.3 11.2 0 24.6-5.5 32-19.9l-19.6-9c-4.8 12.3-24.9 9.3-24.9-1.4zM417.3 113c-6.9-1.5-11.5-4-11.8-8.3.4-10.3 16.3-10.7 25.6-.8l14.7-11.3c-9.2-11.2-19.6-14.2-30.3-14.2-16.3 0-32.1 9.2-32.1 26.6 0 16.9 13 26 27.3 28.2 7.3 1 15.4 3.9 15.2 8.9-.6 9.5-20.2 9-29.1-1.8l-14.2 13.3c8.3 10.7 19.6 16.1 30.2 16.1 16.3 0 34.4-9.4 35.1-26.6 1-21.7-14.8-27.2-30.6-30.1zm-67 55.5h22.4V79.7h-22.4v88.8zM728 79.7h-33.2V117l22.1 19.9v-36.2h11.8c7.5 0 11.2 3.6 11.2 9.4v27.7c0 5.8-3.5 9.7-11.2 9.7h-34v21.1H728c17.8.1 34.5-8.8 34.5-29.2v-29.8c0-20.8-16.7-29.9-34.5-29.9zm-162.9-1.2c-18.4 0-36.7 10-36.7 30.5v30.3c0 20.3 18.4 30.5 36.9 30.5 18.4 0 36.7-10.2 36.7-30.5V109c0-20.4-18.5-30.5-36.9-30.5zm14.4 60.8c0 6.4-7.2 9.7-14.3 9.7-7.2 0-14.4-3.1-14.4-9.7V109c0-6.5 7-10 14-10 7.3 0 14.7 3.1 14.7 10v30.3zM682.4 109c-.5-20.8-14.7-29.2-33-29.2h-35.5v88.8h22.7v-28.2h4l20.6 28.2h28L665 138.1c10.7-3.4 17.4-12.7 17.4-29.1zm-32.6 12h-13.2v-20.3h13.2c14.1 0 14.1 20.3 0 20.3z"/></svg>

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
gitassets/fruxh.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

BIN
gitassets/patreonBTN.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
gitassets/paz.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

BIN
gitassets/premid.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

BIN
gitassets/restrike.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 500 KiB

BIN
gitassets/timeraa.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

BIN
gitassets/ufo.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 178 KiB

BIN
gitassets/xiRDX.gif Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
icon.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

After

Width:  |  Height:  |  Size: 18 KiB

39
installer.js Normal file
View File

@@ -0,0 +1,39 @@
var os = require('os')
var os = os.platform()
var path = require('path')
var chalk = require('chalk')
if(os == 'darwin') {
console.log(chalk.yellow("Creating installer for Mac OS..."))
var createDMG = require('electron-installer-dmg')
createDMG({
appPath: "./out/PreMiD-darwin-x64/PreMiD.app",
name: "PreMiD",
background: "./dmg-background.png",
icon: "./appIcon.icns",
contents: [
{ x: 500, y: 250, type: 'link', path: '/Applications'},
{ x: 175, y: 250, type: 'file', path: path.join(__dirname, './out/PreMiD-darwin-x64/PreMiD.app')}
],
out: "./dist/installer/",
overwrite: true
}, function done(err) {
if(err) console.error(err);
else console.log(chalk.green("Created installer for Mac OS!"))
})
} else if(os == "win32") {
console.log(chalk.yellow("Creating installer for Windows..."))
var electronInstaller = require('electron-winstaller');
resultPromise = electronInstaller.createWindowsInstaller({
appDirectory: './out/PreMiD-win32-x64',
outputDirectory: './dist/installer/',
exe: './PreMiD.exe',
iconUrl: 'https://raw.githubusercontent.com/Timeraa/PreMiD/master/appIcon.ico',
noMsi: true
});
resultPromise.then(() => console.log(chalk.green("Created installer for Windows!")), (e) => console.log(`No dice: ${e.message}`));
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

3340
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,45 +1,25 @@
{
"name": "yt-presence",
"productName": "YT Presence",
"version": "0.3.0",
"description": "Show your current YouTube Video / Song in your Discord profile.",
"main": "src/index.js",
"repository": "Timeraa/YT-Presence",
"name": "premid",
"productName": "PreMiD",
"version": "1.2.0",
"description": "PreMiD adds cool Features to YouTube/YouTube Music. Like for example Discord Rich Presence integration, Media controls and much more.",
"main": "index.js",
"repository": "Timeraa/PreMiD",
"scripts": {
"start": "electron-forge start",
"package": "electron-forge package",
"make": "electron-forge make",
"publish": "electron-forge publish",
"lint": "echo \"No linting configured\"",
"create-installer-mac": "electron-installer-dmg ./out/YT\\ Presence-darwin-x64/YT\\ Presence.app YT\\ Presence\\ Installer --overwrite --icon=./appIcon.icns --out=./dist",
"create-installer-windows": "electron-installer-windows --src ./out/YT\\ Presence-win32-x64/ --dest ./dist"
"start": "electron src/.",
"pkgmac": "electron-packager ./src/ --out=./out/ --asar --overwrite --icon=./appIcon.ico --osx-sign.identity='Florian Metz'",
"pkgwin": "electron-packager ./src/ --out=./out/ --overwrite --icon=./appIcon.ico",
"installer-mac": "npm run pkgmac && node installer",
"installer-win": "npm run pkgwin && node installer"
},
"keywords": [],
"author": "Timeraa",
"license": "MIT",
"config": {
"forge": "./forge.config.js"
},
"dependencies": {
"auto-launch": "^5.0.5",
"chalk": "^2.4.1",
"discord-rpc": "^3.0.0",
"electron-config": "^1.0.0",
"electron-squirrel-startup": "^1.0.0",
"express": "^4.16.3",
"fs": "0.0.1-security",
"html-entities": "^1.2.1",
"menubar": "^5.2.3",
"request": "^2.87.0"
},
"devDependencies": {
"@electron-forge/cli": "^6.0.0-beta.22",
"@electron-forge/maker-deb": "^6.0.0-beta.22",
"@electron-forge/maker-rpm": "^6.0.0-beta.22",
"@electron-forge/maker-squirrel": "^6.0.0-beta.22",
"@electron-forge/maker-zip": "^6.0.0-beta.22",
"electron": "2.0.4",
"chalk": "^2.4.1",
"electron-installer-dmg": "^1.0.0",
"electron-installer-windows": "^1.1.0"
"electron-installer-windows": "^1.1.0",
"electron-packager": "^12.2.0",
"electron-winstaller": "^2.7.0"
}
}

View File

@@ -1,72 +0,0 @@
#header {
height: 50px;
width: 100vw;
background-color: #ce1d2a;
box-shadow: 0px 0px 8px 2px #cccccc;
}
#logo {
position: relative;
margin-top: 5px;
margin-left: 10px;
}
#title {
margin: 0;
position: absolute;
top: 3px;
width: 100vw;
text-align: center;
color: white;
font-weight: bold;
}
#options {
border-collapse: collapse;
width: 90%;
margin-left: 5%;
margin-right: 5%;
}
#options th:nth-child(1) {
width: 90%;
}
#options th:nth-child(2) {
width: 10%;
}
#options tbody tr {
transition: 1s ease-out;
height: 35px;
}
#options tbody tr:not(:last-child) {
border-bottom: 1px solid #ccc;
}
#close-btn {
transition: 0.1s all ease-out;
margin-top: 10px;
appearance: none;
border: none;
outline: none;
cursor: pointer;
background-color: #ce1d2a;
color: white;
width: 75px;
height: 30px;
border-radius: 5px;
font-size: 20px;
margin-left: 50%;
transform: translateX(-50%);
box-shadow: 0px 0px 8px 2px #cccccc;
}
#close-btn:hover {
transform: translateX(-50%) scale(1.1);
}
#close-btn:active {
transform: translateX(-50%) scale(0.9);
}

View File

@@ -1,35 +0,0 @@
@font-face {
font-family: "Roboto";
src: url("../fonts/Roboto/Roboto-Thin.ttf") format("truetype");
font-weight: 100;
font-style: normal;
}
@font-face {
font-family: "Roboto";
src: url("../fonts/Roboto/Roboto-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Roboto";
src: url("../fonts/Roboto/Roboto-Black.ttf") format("truetype");
font-weight: bold;
font-style: normal;
}
* {
font-family: "Roboto", sans-serif;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
html,
body {
margin: 0;
padding: 0;
}

View File

@@ -1,79 +0,0 @@
html {
background-color: #ce1d2a;
overflow: hidden;
}
#left {
width: 50px;
float: left;
}
#logo {
margin-top: 5px;
margin-left: 5px;
}
#loaderWrapper h1 {
position: absolute;
width: 100vw;
top: 30px;
text-align: center;
font-family: sans-serif;
font-size: 15px;
color: white;
}
#loader {
position: absolute;
left: 100px;
top: 20px;
}
#loader #dot {
opacity: 0;
position: absolute;
display: inline-block;
width: 10px;
height: 10px;
border-radius: 100%;
background-color: white;
}
#dot:nth-child(1) {
animation-name: dotLoading;
animation-duration: 1.5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
#dot:nth-child(2) {
animation-name: dotLoading;
animation-duration: 1.5s;
animation-delay: 0.25s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
#dot:nth-child(3) {
animation-name: dotLoading;
animation-duration: 1.5s;
animation-delay: 0.5s;
animation-timing-function: ease-in-out;
animation-iteration-count: infinite;
}
@keyframes dotLoading {
0% {
margin-left: 0px;
opacity: 0;
}
25% {
opacity: 1;
}
100% {
margin-left: 225px;
opacity: 0;
}
}

View File

@@ -1,202 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 379 B

After

Width:  |  Height:  |  Size: 885 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 660 B

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
src/assets/images/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

View File

@@ -1,159 +0,0 @@
//* Declare needed constants
const remote = require('electron').remote
const app = remote.app
const AutoLaunch = require('auto-launch');
const Config = require('electron-config')
const userSettings = new Config({
name: "userSettings"
})
var togglePresence,
toggleYouTube,
toggleYouTubeMusic,
toggleTitleMenubar;
$(() => {
var os = require('os')
if (os.platform() == "darwin") {
$('<tr><td class="noselect">Title menubar</td><td class="right"><label class="switch"><input class="toggleTitleMenubar" type="checkbox"><span class="slider round"></span></label></td></tr>').insertAfter('.ytmToggle')
}
togglePresence = $(".togglePresence"),
toggleYouTube = $(".toggleYouTube"),
toggleYouTubeMusic = $(".toggleYouTubeMusic");
toggleTitleMenubar = $(".toggleTitleMenubar");
toggleAutoLaunch = $(".toggleAutoLaunch");
toggleAutoUpdate = $(".toggleAutoUpdate");
togglePresence.change(switchPresence);
toggleYouTube.change(switchYouTube);
toggleYouTubeMusic.change(switchYouTubeMusic);
toggleTitleMenubar.change(switchTitleMenubar);
toggleAutoLaunch.change(switchAutomaticStartup);
toggleAutoUpdate.change(switchAutoUpdate);
if (userSettings.get('enabled') == true) togglePresence.prop("checked", true)
else {
togglePresence.prop("checked", false)
toggleYouTube.prop("checked", false)
toggleYouTubeMusic.prop("checked", false)
toggleYouTube.attr("disabled", "disabled")
toggleYouTubeMusic.attr("disabled", "disabled")
toggleTitleMenubar.attr("disabled", "disabled")
}
if (userSettings.get('youTube') == true) {
toggleYouTube.prop("checked", true)
toggleYouTube.removeAttr("disabled")
} else toggleYouTube.prop("checked", false)
if (userSettings.get('youTubeMusic') == true) {
toggleYouTubeMusic.prop("checked", true)
toggleYouTubeMusic.removeAttr("disabled")
} else toggleYouTubeMusic.prop("checked", false)
if (userSettings.get('titleMenubar') == true) {
toggleTitleMenubar.prop("checked", true)
toggleTitleMenubar.removeAttr("disabled")
} else toggleTitleMenubar.prop("checked", false)
if (userSettings.get('autoLaunch') == true) {
toggleAutoLaunch.prop("checked", true)
toggleAutoLaunch.removeAttr("disabled")
} else toggleAutoLaunch.prop("checked", false)
if (userSettings.get('autoUpdateCheck') == true) {
toggleAutoUpdate.prop("checked", true)
toggleAutoUpdate.removeAttr("disabled")
} else toggleAutoUpdate.prop("checked", false)
})
function switchPresence() {
if (userSettings.get('enabled') == true) {
userSettings.set('enabled', false);
userSettings.set('youTube', false);
userSettings.set('youTubeMusic', false);
userSettings.set('titleMenubar', false);
toggleYouTube.prop("checked", false)
toggleYouTube.attr("disabled", "disabled")
toggleYouTubeMusic.prop("checked", false)
toggleYouTubeMusic.attr("disabled", "disabled")
toggleTitleMenubar.prop("checked", false)
toggleTitleMenubar.attr("disabled", "disabled")
} else {
userSettings.set('enabled', true);
toggleYouTube.removeAttr("disabled")
toggleYouTubeMusic.removeAttr("disabled")
toggleTitleMenubar.removeAttr("disabled")
}
}
function switchYouTube() {
if (userSettings.get('youTube') == true) {
userSettings.set('youTube', false)
toggleYouTube.prop("checked", false)
} else {
userSettings.set('youTube', true)
toggleYouTube.prop("checked", true)
}
}
function switchYouTubeMusic() {
if (userSettings.get('youTubeMusic') == true) {
userSettings.set('youTubeMusic', false);
toggleYouTubeMusic.prop("checked", false)
} else {
userSettings.set('youTubeMusic', true);
toggleYouTubeMusic.prop("checked", true)
}
}
function switchTitleMenubar() {
if (userSettings.get('titleMenubar') == true) {
userSettings.set('titleMenubar', false);
toggleTitleMenubar.prop("checked", false)
} else {
userSettings.set('titleMenubar', true);
toggleTitleMenubar.prop("checked", true)
}
}
function switchAutomaticStartup() {
//* Add App to AutoLaunch
let autoLaunch = new AutoLaunch({
name: 'YT Presence',
path: app.getPath('exe'),
isHidden: true
});
if (userSettings.get('autoLaunch') == true) {
autoLaunch.isEnabled().then((isEnabled) => {
if(isEnabled) autoLaunch.disable()
}).catch((err) => {
console.log("Error while adding App to autostart.")
})
userSettings.set('autoLaunch', false);
toggleAutoLaunch.prop("checked", false)
} else {
autoLaunch.isEnabled().then((isEnabled) => {
if(!isEnabled) autoLaunch.enable()
}).catch((err) => {
console.log("Error while adding App to autostart.")
})
userSettings.set('autoLaunch', true);
toggleAutoLaunch.prop("checked", true)
}
}
function switchAutoUpdate() {
if (userSettings.get('autoUpdateCheck') == true) {
userSettings.set('autoUpdateCheck', false);
toggleAutoUpdate.prop("checked", false)
} else {
userSettings.set('autoUpdateCheck', true);
toggleAutoUpdate.prop("checked", true)
}
}

View File

@@ -1,5 +0,0 @@
{
"yt_client_id": "463097721130188830",
"ytm_client_id": "463151177836658699",
"version": 1.0
}

View File

@@ -1,44 +1,49 @@
//* Handle Winstall
require('./util/handleWinstall')
require('./util/handleWinstall')
//#region Define constants
//* Declare needed constants
const {app} = require('electron')
const AutoLaunch = require('auto-launch')
//* Require config
const config = require('./config.json');
const constants = require('./util/constants')
var pjson = require('./package.json');
//* Require electron-config
var os = require('os')
//* Update constant in file
constants.platform = os.platform()
const os = require('os')
//* Require Update checker
const updater = require('./util/updateChecker')
//* Require Needed packages
const chalk = require("chalk")
//* Setup electron-config
const Config = require('electron-config');
const userSettings = new Config({
name: "userSettings"
});
//#endregion
app.setAppUserModelId("eu.Timeraa.yt-presence")
//* Set app user model id
app.setAppUserModelId("eu.Timeraa.premid")
//* Define Global Variables
global.PLATFORM = os.platform()
global.UPDATEAVAIABLE = ""
global.VERSION = config.version
global.VERSIONSTRING = VERSION + "-DEVBUILD"
global.VERSION = pjson.productVersion
if(pjson.devBuild)
global.VERSIONSTRING = VERSION + "-DEV";
else
global.VERSIONSTRING = VERSION;
global.BROWSERCONNECTIONSTATE = "NOT_CONNECTED"
global.EXTENSIONSOCKET = null
global.TRAY = null
global.CONSOLEPREFIX = chalk.bold(chalk.hex('#596cae')("PreMiD")) + chalk.hex('#ffffff')(": ")
//* YTM global vars
global.CURRENTSONGTITLE = ""
global.CURRENTSONGAUTHORS = []
global.CURRENTSONGAUTHORSSTRING = ""
global.CURRENTSONGSTARTTIME = ""
global.CURRENTSONGSTARTTIMESECONDS = ""
global.CURRENTSONGENDTIME = ""
global.CONSOLEPREFIX = chalk.bold(chalk.bgHex('#db0918')(chalk.hex('#000000')(" Y") + chalk.hex('#ffffff')("T "))) + chalk.cyan(" Presence") + chalk.hex('#ffffff')(": ")
//* Clear console
process.stdout.write("\u001b[2J\u001b[0;0H");
//* Single Instance Check
var iShouldQuit = app.makeSingleInstance(function(commandLine, workingDirectory) {
return true;
});
var iShouldQuit = app.makeSingleInstance(() => {return true});
if(iShouldQuit){
console.log(CONSOLEPREFIX + chalk.red("App already running, closing current instance..."))
@@ -46,62 +51,37 @@ if(iShouldQuit){
return;
}
//* Setup electron-config
const Config = require('electron-config');
const userSettings = new Config({
name: "userSettings"
});
//* Set default values for electon-config userSettings
if(userSettings.get('enabled') == undefined) userSettings.set('enabled', true)
if(userSettings.get('youTube') == undefined) userSettings.set('youTube', true)
if(userSettings.get('youTubeMusic') == undefined) userSettings.set('youTubeMusic', true)
if(userSettings.get('titleMenubar') == undefined) userSettings.set('titleMenubar', true)
if(userSettings.get('autoStart') == undefined) userSettings.set('autoStart', true)
if(userSettings.get('autoUpdateCheck') == undefined) userSettings.set('autoUpdateCheck', true)
if(userSettings.get('mediaControls') == undefined) userSettings.set('mediaControls', true)
//* Set dock Badge to version
if(constants.platform == "darwin") {
if(PLATFORM == "darwin") {
app.dock.setBadge("V" + VERSION)
}
console.log(CONSOLEPREFIX + chalk.yellow("Loading..."))
//* Setup MenuBar
require('./menubar/setup')
//* App ready
const appReady = () => {
if(userSettings.get('autoLaunch') == undefined) {
userSettings.set('autoLaunch', true)
//* Add App to AutoLaunch
console.log(CONSOLEPREFIX + chalk.yellow("Adding App to autostart..."))
let autoLaunch = new AutoLaunch({
name: 'YT Presence',
path: app.getPath('exe'),
isHidden: true
});
//* Enable AutoLaunch if disabled
autoLaunch.isEnabled().then((isEnabled) => {
if (!isEnabled) autoLaunch.enable();
console.log(CONSOLEPREFIX + chalk.green("Added App to autostart."))
})
//* Catch error
.catch(function(err) {
console.log(CONSOLEPREFIX + chalk.red("Error while adding App to autostart."))
})
}
if(userSettings.get('autoUpdateCheck') == true) {
//* Check for update
updater.checkForUpdate(true)
}
const appReady = async () => {
//* Setup MenuBar
require('./tray/createTray').run()
//* Require shortcuts
require('./util/shortcutHandler').register()
//* Include PresenceHandler
require('./presenceHandler.js')
//* Auto launch
require('./util/autoLaunch')
//* Automatically check for update
if(userSettings.get('autoUpdateCheck') == true)
updater.checkForUpdate(true)
//* hide Dock icon when everything running
if(PLATFORM == "darwin") app.dock.hide()
}
//* Register Handler

View File

@@ -1,93 +0,0 @@
const MenuBar = require('menubar')
const path = require('path')
const constants = require("../util/constants")
const os = require('os');
const updater = require('../util/updateChecker')
const {Menu, MenuItem, BrowserWindow} = require('electron')
var menuBarHeight;
//* Create MenuBar
constants.menuBar = MenuBar({
icon: path.join(__dirname, "../assets/images/icon.png"),
showOnAllWorkspaces: true,
enableLargerThanScreen: false,
resizable: false,
height: menuBarHeight,
width: 250,
backgroundColor: 'black',
})
constants.menuBar.on('ready', () => {
//* Create Menu for menuBar
setupMenu(constants.menuBar)
})
//* Create Menu for menuBar
function setupMenu(menuBar) {
constants.menuBarMenu = new Menu()
constants.menuBarMenu.append(new MenuItem({
label: `YT Presence | V${VERSIONSTRING}`,
enabled: false,
icon: path.join(__dirname, "../assets/images/icon.png")
}))
constants.menuBarMenu.append(new MenuItem({
click: checkForUpdate,
label: "Check for update"
}))
constants.menuBarMenu.append(new MenuItem({
type: "separator"
}))
constants.menuBarMenu.append(new MenuItem({
click: showSettingsPanel,
label: "Preferences"
}))
constants.menuBarMenu.append(new MenuItem({
type: "separator"
}))
constants.menuBarMenu.append(new MenuItem({
role: "quit",
}))
constants.menuBar.tray.setContextMenu(constants.menuBarMenu)
}
function checkForUpdate() {
updater.checkForUpdate(true, true)
}
function showSettingsPanel() {
switch(os.platform()) {
case "darwin":
menuBarHeight = 375;
break;
default:
menuBarHeight = 335;
break;
}
var settingsWindow = new BrowserWindow({
center: true,
maximizable: false,
resizable: false,
show: false,
height: menuBarHeight,
width: 400
})
settingsWindow.loadURL("file://" + path.join(__dirname, "../preferences.html"))
settingsWindow.on('ready-to-show', () => {
settingsWindow.show()
})
settingsWindow.on('blur', () => {
settingsWindow.close()
})
settingsWindow.on('close', () => {
settingsWindow = null;
})
}

5897
src/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

25
src/package.json Normal file
View File

@@ -0,0 +1,25 @@
{
"name": "premid",
"productName": "PreMiD",
"productVersion": "1.2",
"version": "1.2.0",
"description": "PreMiD adds cool Features to YouTube/YouTube Music. Like for example Discord Rich Presence integration, Media controls and much more.",
"main": "index.js",
"repository": "Timeraa/PreMiD",
"keywords": [],
"author": "Timeraa",
"license": "MIT",
"dependencies": {
"auto-launch": "^5.0.5",
"chalk": "^2.4.1",
"discord-rpc": "^3.0.1",
"electron-config": "^1.0.0",
"electron-squirrel-startup": "^1.0.0",
"express": "^4.16.4",
"request": "^2.88.0",
"socket.io": "^2.1.1"
},
"devDependencies": {
"electron-prebuilt-compile": "3.0.2"
}
}

View File

@@ -1,101 +0,0 @@
<html>
<head>
<title>Preferences | YT Presence</title>
<link rel="icon" type="image/png" href="assets/images/icon@2x.png">
<link href="assets/css/reset.css" rel="stylesheet">
<link href="assets/css/preferences.css" rel="stylesheet">
<link href="assets/css/inputs.css" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,700,800" rel="stylesheet">
<script>if (typeof module === 'object') { window.module = module; module = undefined; }</script>
<script src="assets/js/jquery-3.3.1.min.js"></script>
<script src="assets/js/preferences.js"></script>
<script>if (window.module) module = window.module;</script>
</head>
<body>
<div id="header">
<img id="logo" src="assets/images/icon@2x.png" draggable="false">
<h1 id="title">Preferences</h1>
</div>
<div id="content">
<table id="options">
<thead>
<tr>
<th></th>
<th></th>
</tr>
</thead>
<tbody>
<tr>
<td>Enabled</td>
<td>
<label class="switch">
<input class="togglePresence" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>YouTube</td>
<td>
<label class="switch">
<input class="toggleYouTube" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr class="ytmToggle">
<td>YouTube Music</td>
<td>
<label class="switch">
<input class="toggleYouTubeMusic" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>Launch on system startup</td>
<td>
<label class="switch">
<input class="toggleAutoLaunch" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>Automatically check for updates</td>
<td>
<label class="switch">
<input class="toggleAutoUpdate" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
<tr>
<td>Dark mode</td>
<td>
<label class="switch">
<input class="toggleDarkMode" type="checkbox">
<span class="slider round"></span>
</label>
</td>
</tr>
</tbody>
</table>
</div>
<div id="footer">
<input id="close-btn" type="button" value="Close">
</div>
</body>
<script>
document.getElementById("close-btn").addEventListener("click", function (e) {
var window = remote.getCurrentWindow();
window.close();
});
</script>
</html>

View File

@@ -1,94 +1,92 @@
//* Require needed packages
const chalk = require("chalk")
const express = require("express")
var constants = require('./util/constants.js')
let YTM = require('./presences/handleYTM.js');
let YT = require('./presences/handleYT.js');
const DiscordRPC = require('discord-rpc')
//* Require needed packages
const chalk = require("chalk"),
express = require("express")
//* Create server to listen for extension
var extension = express(),
http = require('http'),
socketServer = http.createServer(extension),
io = require('socket.io')(socketServer);
//* Load Config
const Config = require('electron-config');
const userSettings = new Config({
name: "userSettings"
});
//* Create APP
const app = express()
app.use(express.json());
let data
var keepAliveSwitch = 0
//* Define needed variables
var lastKeepAliveSwitch = 0
//* Keep alive check to automatically remove presence if browser not running/not using YT
setInterval(keepAliveCheck, 1000)
function keepAliveCheck() {
if(lastKeepAliveSwitch > keepAliveSwitch + 10) {
constants.menuBar.tray.setTitle("")
constants.ytmrpc.clearActivity()
async function keepAliveCheck() {
if (lastKeepAliveSwitch > 0) {
setupServices.forEach(service => {
service.rpc.destroy()
})
setupServices = []
serviceLogins = []
if(PLATFORM == "darwin") TRAY.setTitle("");
}
lastKeepAliveSwitch += 1
}
app.post("/", async (request, response) => {
constants.lastResponse = new Date().getTime();
data = request.body
if(data.connected === true) {
//* Check if presence is ready
if(constants.chromeConnected == false) {
constants.chromeConnected = true;
constants.menuBar.tray.setTitle("Chrome found!")
console.log(CONSOLEPREFIX + chalk.green("Chrome client connected."))
setTimeout(function() {
if(data.currentSongAuthor == undefined) {
constants.menuBar.tray.setTitle("")
}
constants.introRan = true
}, 5*1000)
}
if(data.service != "keepAlive" && data.service == "ytm") {
lastKeepAliveSwitch = 0
keepAliveSwitch = 0
if(userSettings.get('youTubeMusic') == true) {
if(constants.introRan && constants.chromeConnected && constants.presenceReady) {
if(serviceType(data.service) == "ytm") YTM.updatePresence(data)
}
} else {
constants.menuBar.tray.setTitle("")
constants.ytmrpc.clearActivity()
}
} else if(data.service != "keepAlive" && data.service == "yt") {
lastKeepAliveSwitch = 0
keepAliveSwitch = 0
if(userSettings.get('youTube') == true) {
if(constants.introRan && constants.chromeConnected && constants.presenceReady) {
if(serviceType(data.service) == "yt") YT.updatePresence(data)
}
} else {
constants.menuBar.tray.setTitle("")
constants.ytrpc.clearActivity()
}
} else {
if(keepAliveSwitch >= 3) {
constants.menuBar.tray.setTitle("")
constants.ytmrpc.clearActivity()
}
keepAliveSwitch += 1
}
}
return response.sendStatus(200);
//* Listen on port 3020
socketServer.listen(3020, () => {
console.log(CONSOLEPREFIX + chalk.green("Listening on Port 3020"))
});
//* Socket connection event
io.on('connection', function (socket) {
global.EXTENSIONSOCKET = socket
BROWSERCONNECTIONSTATE = "CONNECTED"
socket.on('playBackChange', updatePresence)
socket.on('updateData', updatePresence)
socket.on('settingsChange', require('./util/settingsHandler'))
})
function serviceType(service) {
switch(service) {
case "ytm":
return "ytm"
case "yt":
return "yt"
default:
return false
var setupServices = [],
serviceLogins = [],
presencePauseSwitch = 0
//* Updates the presence with the incomming data
async function updatePresence(data) {
lastKeepAliveSwitch = 0;
var setupService = setupServices.find(svice => svice.serviceName == data.service);
if(!data.playback) presencePauseSwitch++; else presencePauseSwitch = 0;
if(presencePauseSwitch >= 60) {
if(setupService != null) {
setupService.rpc.clearActivity()
if(PLATFORM == "darwin") TRAY.setTitle("");
}
} else {
if(setupService) {
if(userSettings.get('titleMenubar')) if(PLATFORM == "darwin" && data.playback) TRAY.setTitle(data.trayTitle); else TRAY.setTitle("");
setupService.rpc.setActivity(data.presenceData)
} else {
tryLogin(data.service, data.clientID)
serviceLogins.push({serviceName: data.service, intervalID: setInterval(() => tryLogin(data.service, data.clientID), 10 * 1000)})
}
}
}
//* Listen on port 3000
app.listen(3000, () => console.log(CONSOLEPREFIX + chalk.green("Listening on Port 3000")));
/**
* Try to login to RPC until connected
*/
async function tryLogin(service, clientID) {
setupServices.push({rpc: new DiscordRPC.Client({ transport: "ipc" }), serviceName: service, ready: false})
var serviceRPC = setupServices.find(svice => svice.serviceName == service)
serviceRPC.rpc.login({ clientId: clientID })
.catch(err => console.log(`${CONSOLEPREFIX}PreMiD - RPC: ${err.message}`))
serviceRPC.rpc.on("ready", () => {
clearInterval(serviceLogins.find(svice => svice.serviceName == service).intervalID)
serviceRPC.ready = true
})
}

View File

@@ -1,55 +0,0 @@
const constants = require("../util/constants.js");
const { yt_client_id } = require("../config.json");
const Entities = require("html-entities").AllHtmlEntities;
const entities = new Entities();
const Config = require("electron-config");
const userSettings = new Config({
name: 'userSettings'
})
let startTime = new Date(),
lastTitle
async function updatePresence(data) {
if(lastTitle != data.currentSongTitle) {
startTime = new Date()
}
if(data.url.includes("/watch?v")) {
lastTitle = data.currentSongTitle;
if (
(data.currentSongAuthor && data.currentSongTitle) != undefined &&
data.currentSongAuthor != "" &&
data.currentSongTitle != ""
) {
if(userSettings.get('titleMenubar')) {
constants.menuBar.tray.setTitle(entities.decode(data.currentSongTitle));
} else constants.menuBar.tray.setTitle("")
constants.ytrpc.setActivity({
details: entities.decode(data.currentSongTitle),
state: entities.decode(data.currentSongAuthor),
smallImageKey: "play",
smallImageText: "Playing back.",
startTimestamp: startTime,
largeImageKey: "yt_lg",
instance: true
});
}
} else {
constants.menuBar.tray.setTitle(entities.decode(data.currentSongTitle));
constants.ytrpc.setActivity({
details: "Searching",
state: "for a video...",
largeImageKey: "yt_lg",
instance: true
});
}
}
constants.ytrpc.on("ready", () => {
constants.presenceReady = true;
});
exports.updatePresence = updatePresence;
constants.ytrpc.login({clientId: yt_client_id}).catch(console.error);

View File

@@ -1,175 +0,0 @@
const constants = require("../util/constants.js");
const { ytm_client_id } = require("../config.json");
const Config = require("electron-config");
const chalk = require("chalk");
const userSettings = new Config({
name: 'userSettings'
})
const Entities = require("html-entities").AllHtmlEntities;
const entities = new Entities();
let startTime = new Date(),
endTime = new Date(),
lastStartingTime;
let lastSongTitle = null,
lastSongAuthors = [],
lastSongStartTime,
playbackWasPaused,
playbackPausedDebug = 0,
nextSongPauseDebug = 0,
rpcRemoveCountdown = 0,
ytPresenceVersionString = `YT Presence V${VERSIONSTRING}`;
async function updatePresence(data) {
var CURRENTSONGTITLE = data.currentSongTitle,
CURRENTSONGAUTHORS = data.currentSongAuthors,
CURRENTSONGSTARTTIME = data.currentSongStartTime,
CURRENTSONGSTARTTIMESECONDS = data.currentSongStartTimeSeconds,
CURRENTSONGENDTIME = data.currentSongEndTime
//* Create author string from author array
CURRENTSONGAUTHORS.forEach((author, index, authors) => {
if(index == 0) {
CURRENTSONGAUTHORSSTRING = author
} else if(index < authors.length - 2) {
CURRENTSONGAUTHORSSTRING = CURRENTSONGAUTHORSSTRING + ", " + author
} else if(index < authors.length - 1) {
CURRENTSONGAUTHORSSTRING = CURRENTSONGAUTHORSSTRING + " and " + author
} else {
CURRENTSONGAUTHORSSTRING = CURRENTSONGAUTHORSSTRING + " - " + author
}
});
//* Update songTitle if changed
if(lastSongTitle != CURRENTSONGTITLE) {
//* Only update if authors changed aswell (Debug for Presence)
if(lastSongAuthors.join() != CURRENTSONGAUTHORS.join()) {
if(CURRENTSONGTITLE != "" && CURRENTSONGAUTHORS.join() != "") {
CURRENTSONGSTARTTIME = Math.floor(CURRENTSONGSTARTTIME / 1000)
if(CURRENTSONGSTARTTIME != CURRENTSONGENDTIME) {
lastSongTitle = CURRENTSONGTITLE
lastSongAuthors = CURRENTSONGAUTHORS
lastSongStartTime = CURRENTSONGSTARTTIMESECONDS
rpcRemoveCountdown = 0
nextSongPauseDebug = 2
if(playbackWasPaused) playbackWasPaused = false
console.log(CONSOLEPREFIX + chalk.yellow('Song changed, now playing: ') + chalk.green(entities.decode(CURRENTSONGTITLE)) + chalk.yellow('.'))
//* Set menuBar title if enabled
if(userSettings.get('titleMenubar')) constants.menuBar.tray.setTitle(entities.decode(CURRENTSONGTITLE))
//* Update ytm presence
updateYTMPresence({
details: entities.decode(CURRENTSONGTITLE),
state: entities.decode(CURRENTSONGAUTHORSSTRING),
largeImageKey: "ytm_lg",
largeImageText: ytPresenceVersionString,
smallImageKey: "play",
smallImageText: "Playing back.",
startTimestamp: CURRENTSONGSTARTTIME,
endTimestamp: CURRENTSONGENDTIME,
instance: true
})
}
}
}
} else {
if(nextSongPauseDebug == 0) {
if(lastSongStartTime == CURRENTSONGSTARTTIMESECONDS) {
if(!playbackWasPaused) {
if(playbackPausedDebug == 1) {
playbackPausedDebug = 0;
playbackWasPaused = true
lastSongStartTime = CURRENTSONGSTARTTIMESECONDS
console.log(CONSOLEPREFIX + chalk.yellow('Song paused.'))
//* Update ytm presence
updateYTMPresence({
details: entities.decode(CURRENTSONGTITLE),
state: entities.decode(CURRENTSONGAUTHORSSTRING),
largeImageKey: "ytm_lg",
largeImageText: ytPresenceVersionString,
smallImageKey: "pause",
smallImageText: "Playing paused.",
instance: true
})
} else {
playbackPausedDebug++
}
}
if(rpcRemoveCountdown == 60) {
constants.ytmrpc.clearActivity()
//* Set menuBar title if enabled
if(userSettings.get('titleMenubar')) constants.menuBar.tray.setTitle("")
} else {
rpcRemoveCountdown++
}
} else if(playbackWasPaused) {
console.log(CONSOLEPREFIX + chalk.yellow('Song resumed.'))
//* Set menuBar title if enabled
if(userSettings.get('titleMenubar')) constants.menuBar.tray.setTitle(entities.decode(CURRENTSONGTITLE))
rpcRemoveCountdown = 0
//* Update ytm presence
updateYTMPresence({
details: entities.decode(CURRENTSONGTITLE),
state: entities.decode(CURRENTSONGAUTHORSSTRING),
largeImageKey: "ytm_lg",
largeImageText: ytPresenceVersionString,
smallImageKey: "play",
smallImageText: "Playing back.",
startTimestamp: Math.floor(CURRENTSONGSTARTTIME / 1000),
endTimestamp: CURRENTSONGENDTIME,
instance: true
})
playbackWasPaused = false
} else {
var difference = Math.abs(lastSongStartTime - CURRENTSONGSTARTTIMESECONDS +1);
if(difference != 0) {
console.log(CONSOLEPREFIX + chalk.yellow(`Song time changed. Difference: ${difference} seconds.`))
//* Update ytm presence
updateYTMPresence({
details: entities.decode(CURRENTSONGTITLE),
state: entities.decode(CURRENTSONGAUTHORSSTRING),
smallImageKey: "play",
smallImageText: "Playing back.",
largeImageKey: "ytm_lg",
startTimestamp: Math.floor(CURRENTSONGSTARTTIME / 1000),
endTimestamp: CURRENTSONGENDTIME,
instance: true
})
}
}
} else {
nextSongPauseDebug--
}
lastSongStartTime = CURRENTSONGSTARTTIMESECONDS
}
}
function updateYTMPresence(data) {
constants.ytmrpc.setActivity(data);
}
constants.ytmrpc.on("ready", () => {
constants.presenceReady = true;
});
exports.updatePresence = updatePresence;
constants.ytmrpc.login({clientId: ytm_client_id}).catch(console.error);
//* Catch Discord RPC errors

22
src/tray/createTray.js Normal file
View File

@@ -0,0 +1,22 @@
const path = require('path')
const {Tray, Menu, MenuItem} = require('electron')
exports.run = () => {
TRAY = new Tray(path.join(__dirname, "../assets/images/icon.png"))
TRAY.setToolTip(`PreMiD V${VERSIONSTRING}`)
var menuBarMenu = new Menu()
menuBarMenu.append(new MenuItem({
label: `PreMiD | V${VERSIONSTRING}`,
enabled: false,
icon: path.join(__dirname, "../assets/images/icon.png")
}))
menuBarMenu.append(new MenuItem({type: "separator"}))
menuBarMenu.append(new MenuItem({
click: cfu,
label: "Check for updates"
}))
menuBarMenu.append(new MenuItem({role: "quit"}))
TRAY.setContextMenu(menuBarMenu)
}
cfu = () => require('../util/updateChecker').checkForUpdate(true, true)

22
src/tray/showAbout.js Normal file
View File

@@ -0,0 +1,22 @@
const path = require('path')
const {BrowserWindow} = require('electron')
exports.run = () => {
var aboutWindow = new BrowserWindow({
center: true,
maximizable: false,
minimizable: false,
resizable: false,
width: 400,
height: 600,
alwaysOnTop: true
})
aboutWindow.setMenu(null)
aboutWindow.loadURL("file://" + path.join(__dirname, "../windows/about.html"))
aboutWindow.on('close', () => {
aboutWindow = null;
})
}

View File

@@ -0,0 +1,31 @@
const path = require('path')
const {BrowserWindow} = require('electron')
const os = require('os');
let menuBarHeight
exports.run = () => {
switch(os.platform()) {
case "darwin":
menuBarHeight = 440;
break;
default:
menuBarHeight = 410;
break;
}
var settingsWindow = new BrowserWindow({
center: true,
maximizable: false,
resizable: false,
height: menuBarHeight,
width: 400
})
settingsWindow.setMenu(null)
settingsWindow.loadURL("file://" + path.join(__dirname, "../windows/preferences.html"))
settingsWindow.on('close', () => {
settingsWindow = null;
})
}

31
src/util/autoLaunch.js Normal file
View File

@@ -0,0 +1,31 @@
//* Declare needed constants
const {app} = require('electron')
const chalk = require("chalk")
const AutoLaunch = require('auto-launch')
//* Setup electron-config
const Config = require('electron-config');
const userSettings = new Config({
name: "userSettings"
});
if(userSettings.get('autoLaunch') == undefined || userSettings.get('autoLaunch') == true) {
userSettings.set('autoLaunch', true)
//* Add App to AutoLaunch
console.log(CONSOLEPREFIX + chalk.yellow("Adding App to autostart..."))
let autoLaunch = new AutoLaunch({
name: 'PreMiD',
path: app.getPath('exe'),
isHidden: true
});
//* Enable AutoLaunch if disabled
autoLaunch.isEnabled().then(async (isEnabled) => {
if (!isEnabled) autoLaunch.enable();
console.log(CONSOLEPREFIX + chalk.green("Added App to autostart."))
})
//* Catch error
.catch(function(err) {
console.log(CONSOLEPREFIX + chalk.red("Error while adding App to autostart."))
})
}

View File

@@ -1,42 +0,0 @@
const chalk = require("chalk")
const DiscordRPC = require("discord-rpc")
let app,
consolePrefix,
win,
menuBar,
menuBarMenu,
chromeConnected,
presenceReady,
presence,
setup,
newVersion,
introRan,
lastResponse,
ytmrpc,
ytrpc,
platform,
data;
module.exports = {
app: "",
win: "",
menuBar: "",
menuBarMenu: "",
chromeConnected: false,
presenceReady: false,
setup: false,
presence: {
details: "Waiting for music",
state: "to start playing...",
largeImageKey: "ytm_lg",
instance: true
},
newVersion: false,
introRan: false,
lastResponse: false,
ytmrpc: new DiscordRPC.Client({ transport: "ipc" }),
ytrpc: new DiscordRPC.Client({ transport: "ipc" }),
platform: "",
data: ""
};

View File

@@ -1,64 +1,60 @@
var {app} = require('electron')
if (require('electron-squirrel-startup')) return;
module.exports = {
handleSquirrelEvent: function() {
if (process.argv.length === 1) {
return false;
}
const ChildProcess = require('child_process');
const path = require('path');
const appFolder = path.resolve(process.execPath, '..');
const rootAtomFolder = path.resolve(appFolder, '..');
const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
const exeName = path.basename(process.execPath);
const spawn = function(command, args) {
let spawnedProcess, error;
try {
spawnedProcess = ChildProcess.spawn(command, args, {detached: true});
} catch (error) {}
return spawnedProcess;
};
const spawnUpdate = function(args) {
return spawn(updateDotExe, args);
};
const squirrelEvent = process.argv[1];
const {app} = require('electron');
// this should be placed at top of main.js to handle setup events quickly
if (handleSquirrelEvent()) {
// squirrel event handled and app will exit in 1000ms, so don't do anything else
return;
}
function handleSquirrelEvent() {
if (process.argv.length === 1) {
return false;
}
const ChildProcess = require('child_process');
const path = require('path');
const appFolder = path.resolve(process.execPath, '..');
const rootAtomFolder = path.resolve(appFolder, '..');
const updateDotExe = path.resolve(path.join(rootAtomFolder, 'Update.exe'));
const exeName = path.basename(process.execPath);
const spawn = function(command, args) {
let spawnedProcess, error;
try {
spawnedProcess = ChildProcess.spawn(command, args, {detached: true});
} catch (error) {}
return spawnedProcess;
};
const spawnUpdate = function(args) {
return spawn(updateDotExe, args);
};
const squirrelEvent = process.argv[1];
switch (squirrelEvent) {
case '--squirrel-install':
case '--squirrel-updated':
// Optionally do things such as:
// - Add your .exe to the PATH
// - Write to the registry for things like file associations and
// explorer context menus
// Install desktop and start menu shortcuts
spawnUpdate(['--createShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-uninstall':
// Undo anything you did in the --squirrel-install and
// --squirrel-updated handlers
// Remove desktop and start menu shortcuts
spawnUpdate(['--removeShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-obsolete':
// This is called on the outgoing version of your app before
// we update to the new version - it's the opposite of
// --squirrel-updated
app.quit();
return true;
case '--squirrel-install':
case '--squirrel-updated':
// Install desktop and start menu shortcuts
spawnUpdate(['--createShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-uninstall':
// Remove desktop and start menu shortcuts
spawnUpdate(['--removeShortcut', exeName]);
setTimeout(app.quit, 1000);
return true;
case '--squirrel-obsolete':
app.quit();
return true;
}
}
}
};

View File

@@ -0,0 +1,51 @@
const Config = require('electron-config');
const userSettings = new Config({
name: "userSettings"
});
const {app} = require('electron')
const AutoLaunch = require('auto-launch')
let autoLaunch = new AutoLaunch({
name: 'PreMiD',
path: app.getPath('exe'),
isHidden: true
});
var mediaControls = require('./shortcutHandler');
module.exports = async (data) => {
if(userSettings.get('titleMenubar') != data.options.titleMenubar) {
userSettings.set('titleMenubar', data.options.titleMenubar)
if(PLATFORM == "darwin" && !data.options.titleMenubar) TRAY.setTitle("")
}
if(userSettings.get('autoUpdateCheck') != data.options.checkForUpdates)
userSettings.set('autoUpdateCheck', data.options.checkForUpdates)
if(userSettings.get('autoLaunch') != data.options.systemStartup) {
userSettings.set('autoLaunch', data.options.systemStartup)
if(data.options.systemStartup) {
autoLaunch.isEnabled().then(async (isEnabled) => {
if (!isEnabled) autoLaunch.enable();
})
} else {
autoLaunch.isEnabled().then(async (isEnabled) => {
if (isEnabled) autoLaunch.disable();
})
}
}
if(userSettings.get('mediaControls') != data.options.mediaControls) {
userSettings.set('mediaControls', data.options.mediaControls)
if(data.options.mediaControls) mediaControls.register(); else mediaControls.unregister();
}
if(userSettings.get('titleMenubar') != data.options.titleMenubar) {
userSettings.set('titleMenubar', data.options.titleMenubar)
if(!data.options.titleMenubar) TRAY.setTitle("")
}
//console.log(data.options)
}

View File

@@ -0,0 +1,49 @@
const Config = require('electron-config');
const userSettings = new Config({
name: "userSettings"
});
const chalk = require('chalk')
var { globalShortcut, app } = require('electron')
module.exports.register = async () => {
if(!userSettings.get('mediaControls')) return
console.log(CONSOLEPREFIX + chalk.yellow("Registering keyboard shortcuts..."))
globalShortcut.register('medianexttrack', () => {
if (EXTENSIONSOCKET != null) EXTENSIONSOCKET.emit('mediaKeyHandler', { playback: "nextTrack" })
})
var pauseSkipToggle = 0;
globalShortcut.register('mediaplaypause', () => {
pauseSkipToggle++
setTimeout(() => {
if (EXTENSIONSOCKET != null && pauseSkipToggle == 1) EXTENSIONSOCKET.emit('mediaKeyHandler', { playback: "pause" })
if (EXTENSIONSOCKET != null && pauseSkipToggle == 2) EXTENSIONSOCKET.emit('mediaKeyHandler', { playback: "nextTrack" })
if (EXTENSIONSOCKET != null && pauseSkipToggle == 3) EXTENSIONSOCKET.emit('mediaKeyHandler', { playback: "previousTrack" })
pauseSkipToggle = 0
}, 500)
})
globalShortcut.register('mediaprevioustrack', () => {
if (EXTENSIONSOCKET != null) EXTENSIONSOCKET.emit('mediaKeyHandler', { playback: "previousTrack" })
})
console.log(CONSOLEPREFIX + chalk.green("Successfully registered keyboard shortcuts."))
}
module.exports.unregister = async () => {
console.log(CONSOLEPREFIX + chalk.red("Unregistering keyboard shortcuts..."))
if(require('os').platform() == "darwin") {
app.relaunch()
app.exit(0)
} else
globalShortcut.unregisterAll()
console.log(CONSOLEPREFIX + chalk.green("Unregistered keyboard shortcuts"))
}
app.on('will-quit', () => {
console.log(CONSOLEPREFIX + chalk.red("Unregistering keyboard shortcuts..."))
globalShortcut.unregisterAll()
console.log(CONSOLEPREFIX + chalk.green("Unregistered keyboard shortcuts"))
})

View File

@@ -1,9 +1,9 @@
const { Notification } = require('electron');
const { Notification, BrowserWindow } = require('electron');
const path = require('path')
const request = require("request")
const chalk = require("chalk")
let constants = require('./constants')
let config = require('../config')
function checkForUpdate(sendNotification = false, sendNoUpdateInfo = false) {
@@ -14,20 +14,46 @@ function checkForUpdate(sendNotification = false, sendNoUpdateInfo = false) {
json: true,
headers: {'user-agent': 'node.js'}
}, function (error, response, body) {
if(error) {
console.log(CONSOLEPREFIX + chalk.red("Error while checking for update. " + error))
return
}
//* Remove v from version
var gitVersion = body.tag_name.replace('v', '')
//* Compare version
if(gitVersion > VERSION) {
global.UPDATEAVAIABLE = gitVersion
constants.newVersion = gitVersion
console.log(CONSOLEPREFIX + chalk.cyan("New version avaiable: ") + chalk.red(`V${VERSION}`) + chalk.blue(' > ') + chalk.yellow(`V${gitVersion}`))
var updateWindow = new BrowserWindow({
center: true,
maximizable: false,
minimizable: false,
height: 500,
minHeight: 500,
width: 400,
minWidth: 400,
alwaysOnTop: true
})
updateWindow.setMenu(null)
updateWindow.loadURL("file://" + path.join(__dirname, "../windows/update.html"))
updateWindow.webContents.on('did-finish-load', () => {
updateWindow.webContents.send('updateData', body);
});
updateWindow.on('close', () => {
updateWindow = null;
})
} else {
global.UPDATEAVAIABLE = false
console.log(CONSOLEPREFIX + chalk.cyan("Up to date! ") + chalk.yellow(`V${VERSION}`))
if(sendNoUpdateInfo) {
const noUpdateAvaiableNotification = new Notification({
title: 'Updater | YT Presence',
title: 'PreMiD',
body: `You are up to date! (V${VERSION})`,
silent: true
})
@@ -37,23 +63,7 @@ function checkForUpdate(sendNotification = false, sendNoUpdateInfo = false) {
}
})
//* If sendNotification
if(sendNotification && UPDATEAVAIABLE != false) {
const updateNotification = new Notification({
title: 'Updater | YT Presence',
body: `Update avaiable! (V${UPDATEAVAIABLE})\nClick here to download the newest version.`,
silent: true
})
updateNotification.show()
updateNotification.on('click', () => {
require("electron").shell.openExternal("https://github.com/Timeraa/YT-Presence/releases/latest")
})
return UPDATEAVAIABLE
} else {
return UPDATEAVAIABLE
}
return UPDATEAVAIABLE
}
module.exports.checkForUpdate = checkForUpdate

View File

@@ -60,12 +60,10 @@ input:focus + .slider {
}
input:hover + .slider {
transform: scale(1.25);
transform: scale(1.1);
}
input:checked + .slider:before {
-webkit-transform: translateX(20px);
-ms-transform: translateX(20px);
transform: translateX(20px);
}

47
src/windows/css/reset.css Normal file
View File

@@ -0,0 +1,47 @@
@font-face {
font-family: "Montserrat";
src: url("../fonts/Montserrat/Montserrat-Regular.ttf") format("truetype");
font-weight: normal;
font-style: normal;
}
@font-face {
font-family: "Montserrat";
src: url("../fonts/Montserrat/Montserrat-Medium.ttf") format("truetype");
font-weight: 500;
font-style: normal;
}
@font-face {
font-family: "Montserrat";
src: url("../fonts/Montserrat/Montserrat-Bold.ttf") format("truetype");
font-weight: bold;
font-style: normal;
}
@font-face {
font-family: "Montserrat";
src: url("../fonts/Montserrat/Montserrat-Black.ttf") format("truetype");
font-weight: 900;
font-style: normal;
}
@font-face {
font-family: "Montserrat";
src: url("../fonts/Montserrat/Montserrat-BlackItalic.ttf") format("truetype");
font-weight: 900;
font-style: italic;
}
* {
font-family: "Montserrat", sans-serif;
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
cursor: default;
}
html,
body {
margin: 0;
padding: 0;
}

Some files were not shown because too many files have changed in this diff Show More