mirror of
https://github.com/th-ch/youtube-music.git
synced 2026-01-11 18:41:47 +00:00
Compare commits
34 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| af02b60ce3 | |||
| fbdae0452c | |||
| d68d73eb4c | |||
| 2de27d2e24 | |||
| 15591e24d7 | |||
| 715d59e3d4 | |||
| f71e0e9da9 | |||
| ba3779db07 | |||
| d99aa0242f | |||
| 3ea859de09 | |||
| 7473677477 | |||
| c3e2c13808 | |||
| 5074ba2f48 | |||
| a8b8f1079f | |||
| e52987df92 | |||
| 01fc965170 | |||
| ff71f29206 | |||
| a47c5144ac | |||
| 9b979b2273 | |||
| 81198192bb | |||
| c03a08e76a | |||
| 807e21eabf | |||
| 36f9d640df | |||
| 39f30b143b | |||
| 49497d0efb | |||
| 79c795927a | |||
| 66c5ce46ca | |||
| 22c7f70c93 | |||
| 467171a17e | |||
| 3022facbea | |||
| a67bf5ea43 | |||
| 3a1a3d4241 | |||
| 9197f4a0e1 | |||
| d21220693b |
11
package.json
11
package.json
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "youtube-music",
|
"name": "youtube-music",
|
||||||
"productName": "YouTube Music",
|
"productName": "YouTube Music",
|
||||||
"version": "1.7.1",
|
"version": "1.8.0",
|
||||||
"description": "YouTube Music Desktop App - including custom plugins",
|
"description": "YouTube Music Desktop App - including custom plugins",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"repository": "th-ch/youtube-music",
|
"repository": "th-ch/youtube-music",
|
||||||
@ -22,7 +22,8 @@
|
|||||||
},
|
},
|
||||||
"linux": {
|
"linux": {
|
||||||
"icon": "assets/generated/icons/png",
|
"icon": "assets/generated/icons/png",
|
||||||
"category": "AudioVideo"
|
"category": "AudioVideo",
|
||||||
|
"target": ["AppImage", "snap", "freebsd", "deb", "rpm"]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
@ -48,9 +49,9 @@
|
|||||||
"npm": "Please use yarn and not npm"
|
"npm": "Please use yarn and not npm"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cliqz/adblocker-electron": "^1.18.6",
|
"@cliqz/adblocker-electron": "^1.18.8",
|
||||||
"@ffmpeg/core": "^0.8.4",
|
"@ffmpeg/core": "^0.8.5",
|
||||||
"@ffmpeg/ffmpeg": "^0.9.5",
|
"@ffmpeg/ffmpeg": "^0.9.6",
|
||||||
"YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.8.0",
|
"YoutubeNonStop": "git://github.com/lawfx/YoutubeNonStop.git#v0.8.0",
|
||||||
"downloads-folder": "^3.0.1",
|
"downloads-folder": "^3.0.1",
|
||||||
"electron-debug": "^3.1.0",
|
"electron-debug": "^3.1.0",
|
||||||
|
|||||||
@ -3,5 +3,6 @@ module.exports = (win, options) =>
|
|||||||
loadAdBlockerEngine(
|
loadAdBlockerEngine(
|
||||||
win.webContents.session,
|
win.webContents.session,
|
||||||
options.cache,
|
options.cache,
|
||||||
options.additionalBlockLists
|
options.additionalBlockLists,
|
||||||
|
options.disableDefaultLists
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
const { existsSync, promises, unlinkSync } = require("fs"); // used for caching
|
const { promises } = require("fs"); // used for caching
|
||||||
const path = require("path");
|
const path = require("path");
|
||||||
|
|
||||||
const { ElectronBlocker } = require("@cliqz/adblocker-electron");
|
const { ElectronBlocker } = require("@cliqz/adblocker-electron");
|
||||||
@ -6,31 +6,32 @@ const fetch = require("node-fetch");
|
|||||||
|
|
||||||
const SOURCES = [
|
const SOURCES = [
|
||||||
"https://raw.githubusercontent.com/kbinani/adblock-youtube-ads/master/signed.txt",
|
"https://raw.githubusercontent.com/kbinani/adblock-youtube-ads/master/signed.txt",
|
||||||
|
// uBlock Origin
|
||||||
|
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters.txt",
|
||||||
|
"https://raw.githubusercontent.com/uBlockOrigin/uAssets/master/filters/filters-2020.txt",
|
||||||
];
|
];
|
||||||
|
|
||||||
const loadAdBlockerEngine = (
|
const loadAdBlockerEngine = (
|
||||||
session = undefined,
|
session = undefined,
|
||||||
cache = true,
|
cache = true,
|
||||||
additionalBlockLists = []
|
additionalBlockLists = [],
|
||||||
|
disableDefaultLists = false
|
||||||
) => {
|
) => {
|
||||||
const adBlockerCache = path.resolve(__dirname, "ad-blocker-engine.bin");
|
// Only use cache if no additional blocklists are passed
|
||||||
if (!cache && existsSync(adBlockerCache)) {
|
const cachingOptions =
|
||||||
unlinkSync(adBlockerCache);
|
cache && additionalBlockLists.length === 0
|
||||||
}
|
? {
|
||||||
const cachingOptions = cache
|
path: path.resolve(__dirname, "ad-blocker-engine.bin"),
|
||||||
? {
|
read: promises.readFile,
|
||||||
path: adBlockerCache,
|
write: promises.writeFile,
|
||||||
read: promises.readFile,
|
}
|
||||||
write: promises.writeFile,
|
: undefined;
|
||||||
}
|
const lists = [
|
||||||
: undefined;
|
...(disableDefaultLists ? [] : SOURCES),
|
||||||
|
...additionalBlockLists,
|
||||||
|
];
|
||||||
|
|
||||||
ElectronBlocker.fromLists(
|
ElectronBlocker.fromLists(fetch, lists, {}, cachingOptions)
|
||||||
fetch,
|
|
||||||
[...SOURCES, ...additionalBlockLists],
|
|
||||||
{},
|
|
||||||
cachingOptions
|
|
||||||
)
|
|
||||||
.then((blocker) => {
|
.then((blocker) => {
|
||||||
if (session) {
|
if (session) {
|
||||||
blocker.enableBlockingInSession(session);
|
blocker.enableBlockingInSession(session);
|
||||||
|
|||||||
4
plugins/adblocker/front.js
Normal file
4
plugins/adblocker/front.js
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
module.exports = () => {
|
||||||
|
// Preload adblocker to inject scripts/styles
|
||||||
|
require("@cliqz/adblocker-electron-preload/dist/preload.cjs");
|
||||||
|
};
|
||||||
110
plugins/touchbar/back.js
Normal file
110
plugins/touchbar/back.js
Normal file
@ -0,0 +1,110 @@
|
|||||||
|
const {
|
||||||
|
TouchBar, nativeImage
|
||||||
|
} = require('electron');
|
||||||
|
const {
|
||||||
|
TouchBarButton,
|
||||||
|
TouchBarLabel,
|
||||||
|
TouchBarSpacer,
|
||||||
|
TouchBarSegmentedControl,
|
||||||
|
TouchBarScrubber
|
||||||
|
} = TouchBar;
|
||||||
|
const fetch = require('node-fetch');
|
||||||
|
|
||||||
|
// This selects the song title
|
||||||
|
const titleSelector = '.title.style-scope.ytmusic-player-bar';
|
||||||
|
|
||||||
|
// This selects the song image
|
||||||
|
const imageSelector = '#layout > ytmusic-player-bar > div.middle-controls.style-scope.ytmusic-player-bar > img';
|
||||||
|
|
||||||
|
// These keys will be used to go backwards, pause, skip songs, like songs, dislike songs
|
||||||
|
const keys = ['k', 'space', 'j', '_', '+'];
|
||||||
|
|
||||||
|
const presskey = (window, key) => {
|
||||||
|
window.webContents.sendInputEvent({
|
||||||
|
type: 'keydown',
|
||||||
|
keyCode: key
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab the title using the selector
|
||||||
|
const getTitle = win => {
|
||||||
|
return win.webContents.executeJavaScript(
|
||||||
|
'document.querySelector(\'' + titleSelector + '\').innerText'
|
||||||
|
).catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Grab the image src using the selector
|
||||||
|
const getImage = win => {
|
||||||
|
return win.webContents.executeJavaScript(
|
||||||
|
'document.querySelector(\'' + imageSelector + '\').src'
|
||||||
|
).catch(error => {
|
||||||
|
console.log(error);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = win => {
|
||||||
|
// Songtitle label
|
||||||
|
const songTitle = new TouchBarLabel({
|
||||||
|
label: ''
|
||||||
|
});
|
||||||
|
|
||||||
|
// This will store the song image once available
|
||||||
|
const songImage = {};
|
||||||
|
|
||||||
|
// The song control buttons (keys to press are in the same order)
|
||||||
|
const buttons = new TouchBarSegmentedControl({
|
||||||
|
mode: 'buttons',
|
||||||
|
segments: [
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '⏮'
|
||||||
|
}),
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '⏯️'
|
||||||
|
}),
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '⏭'
|
||||||
|
}),
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '👎'
|
||||||
|
}),
|
||||||
|
new TouchBarButton({
|
||||||
|
label: '👍'
|
||||||
|
})
|
||||||
|
],
|
||||||
|
change: i => presskey(win, keys[i])
|
||||||
|
});
|
||||||
|
|
||||||
|
// This is the touchbar object, this combines everything with proper layout
|
||||||
|
const touchBar = new TouchBar({
|
||||||
|
items: [
|
||||||
|
new TouchBarScrubber({
|
||||||
|
items: [songImage, songTitle],
|
||||||
|
continuous: false
|
||||||
|
}),
|
||||||
|
new TouchBarSpacer({
|
||||||
|
size: 'flexible'
|
||||||
|
}),
|
||||||
|
buttons
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
// If the page title changes, update touchbar and song title
|
||||||
|
win.on('page-title-updated', async () => {
|
||||||
|
// Set the song title
|
||||||
|
songTitle.label = await getTitle(win);
|
||||||
|
|
||||||
|
// Get image source
|
||||||
|
const imageSrc = await getImage(win);
|
||||||
|
|
||||||
|
// Fetch and set song image
|
||||||
|
await fetch(imageSrc)
|
||||||
|
.then(response => response.buffer())
|
||||||
|
.then(data => {
|
||||||
|
songImage.icon = nativeImage.createFromBuffer(data).resize({height: 23});
|
||||||
|
});
|
||||||
|
|
||||||
|
win.setTouchBar(touchBar);
|
||||||
|
});
|
||||||
|
};
|
||||||
28
readme.md
28
readme.md
@ -1,13 +1,24 @@
|
|||||||
# YouTube Music
|
# YouTube Music
|
||||||
|
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
<div align="center">
|
||||||
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
|
||||||
[](https://github.com/sindresorhus/xo)
|
|
||||||
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
|
||||||
[](https://snyk.io/test/github/th-ch/youtube-music)
|
|
||||||

|
|
||||||
|
|
||||||

|
[](https://github.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://github.com/th-ch/youtube-music/blob/master/LICENSE)
|
||||||
|
[](https://github.com/sindresorhus/xo)
|
||||||
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://snyk.io/test/github/th-ch/youtube-music)
|
||||||
|
[](https://GitHub.com/th-ch/youtube-music/releases/)
|
||||||
|
[](https://aur.archlinux.org/packages/youtube-music-bin)
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
<div align="center">
|
||||||
|
<a href="https://github.com/th-ch/youtube-music/releases/latest">
|
||||||
|
<img src="web/youtube-music.svg" width="400" height="100">
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
**Electron wrapper around YouTube Music featuring:**
|
**Electron wrapper around YouTube Music featuring:**
|
||||||
|
|
||||||
@ -18,7 +29,7 @@
|
|||||||
|
|
||||||
You can check out the [latest release](https://github.com/th-ch/youtube-music/releases/latest) to quickly find the latest version.
|
You can check out the [latest release](https://github.com/th-ch/youtube-music/releases/latest) to quickly find the latest version.
|
||||||
|
|
||||||
**Arch Linux**
|
### Arch Linux
|
||||||
|
|
||||||
Install the `youtube-music-bin` package from the AUR. For AUR installation instructions, take a look at this [wiki page](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
|
Install the `youtube-music-bin` package from the AUR. For AUR installation instructions, take a look at this [wiki page](https://wiki.archlinux.org/index.php/Arch_User_Repository#Installing_packages).
|
||||||
|
|
||||||
@ -32,6 +43,7 @@ Install the `youtube-music-bin` package from the AUR. For AUR installation instr
|
|||||||
- **Auto confirm when paused**: when the "Continue Watching?" modal appears, automatically click "Yes"
|
- **Auto confirm when paused**: when the "Continue Watching?" modal appears, automatically click "Yes"
|
||||||
- **Hide video player**: no video in the interface when playing music
|
- **Hide video player**: no video in the interface when playing music
|
||||||
- **Notifications**: display a notification when a song starts playing
|
- **Notifications**: display a notification when a song starts playing
|
||||||
|
- **Touchbar**: custom TouchBar layout for macOS
|
||||||
|
|
||||||
## Dev
|
## Dev
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 816 KiB After Width: | Height: | Size: 816 KiB |
379
web/youtube-music.svg
Normal file
379
web/youtube-music.svg
Normal file
@ -0,0 +1,379 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 800 300" width="800" height="300">
|
||||||
|
<foreignObject width="100%" height="100%">
|
||||||
|
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||||
|
<style>
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
position: relative;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
a {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
h1.main, p.demos {
|
||||||
|
-webkit-animation-delay: 18s;
|
||||||
|
-moz-animation-delay: 18s;
|
||||||
|
-ms-animation-delay: 18s;
|
||||||
|
animation-delay: 18s;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0px;
|
||||||
|
left: 0px;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: 0;
|
||||||
|
}
|
||||||
|
.content {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
left: 0px;
|
||||||
|
top: 0px;
|
||||||
|
z-index: 1000;
|
||||||
|
}
|
||||||
|
.container h2 {
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
line-height: 100px;
|
||||||
|
height: 90px;
|
||||||
|
margin-top: -90px;
|
||||||
|
font-size: 90px;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
color: transparent;
|
||||||
|
-webkit-animation: blurFadeInOut 3s ease-in backwards;
|
||||||
|
-moz-animation: blurFadeInOut 3s ease-in backwards;
|
||||||
|
-ms-animation: blurFadeInOut 3s ease-in backwards;
|
||||||
|
animation: blurFadeInOut 3s ease-in backwards;
|
||||||
|
}
|
||||||
|
.container h2.frame-1 {
|
||||||
|
-webkit-animation-delay: 0s;
|
||||||
|
-moz-animation-delay: 0s;
|
||||||
|
-ms-animation-delay: 0s;
|
||||||
|
animation-delay: 0s;
|
||||||
|
}
|
||||||
|
.container h2.frame-2 {
|
||||||
|
-webkit-animation-delay: 3s;
|
||||||
|
-moz-animation-delay: 3s;
|
||||||
|
-ms-animation-delay: 3s;
|
||||||
|
animation-delay: 3s;
|
||||||
|
}
|
||||||
|
.container h2.frame-3 {
|
||||||
|
-webkit-animation-delay: 6s;
|
||||||
|
-moz-animation-delay: 6s;
|
||||||
|
-ms-animation-delay: 6s;
|
||||||
|
animation-delay: 6s;
|
||||||
|
}
|
||||||
|
.container h2.frame-4 {
|
||||||
|
-webkit-animation-delay: 9s;
|
||||||
|
-moz-animation-delay: 9s;
|
||||||
|
-ms-animation-delay: 9s;
|
||||||
|
animation-delay: 9s;
|
||||||
|
}
|
||||||
|
.container h2.frame-5 {
|
||||||
|
-webkit-animation: none;
|
||||||
|
-moz-animation: none;
|
||||||
|
-ms-animation: none;
|
||||||
|
animation: none;
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
}
|
||||||
|
.container h2.frame-5 span {
|
||||||
|
-webkit-animation: blurFadeIn 3s ease-in 12s backwards;
|
||||||
|
-moz-animation: blurFadeIn 1s ease-in 12s backwards;
|
||||||
|
-ms-animation: blurFadeIn 3s ease-in 12s backwards;
|
||||||
|
animation: blurFadeIn 3s ease-in 12s backwards;
|
||||||
|
color: transparent;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
}
|
||||||
|
.container h2.frame-5 span:nth-child(2) {
|
||||||
|
-webkit-animation-delay: 13s;
|
||||||
|
-moz-animation-delay: 13s;
|
||||||
|
-ms-animation-delay: 13s;
|
||||||
|
animation-delay: 13s;
|
||||||
|
}
|
||||||
|
.container h2.frame-5 span:nth-child(3) {
|
||||||
|
-webkit-animation-delay: 14s;
|
||||||
|
-moz-animation-delay: 14s;
|
||||||
|
-ms-animation-delay: 14s;
|
||||||
|
animation-delay: 14s;
|
||||||
|
}
|
||||||
|
.circle-link {
|
||||||
|
position: absolute;
|
||||||
|
left: 50%;
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
bottom: 50px;
|
||||||
|
margin-left: -100px;
|
||||||
|
text-align: center;
|
||||||
|
line-height: 200px;
|
||||||
|
width: 200px;
|
||||||
|
height: 200px;
|
||||||
|
background: #cc0000;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 25px;
|
||||||
|
-webkit-border-radius: 50%;
|
||||||
|
-moz-border-radius: 50%;
|
||||||
|
border-radius: 50%;
|
||||||
|
box-shadow: 0px 8px 15px rgba(0, 0, 0, 0.1);
|
||||||
|
-webkit-animation: fadeInRotate 0.8s ease 16s backwards;
|
||||||
|
-moz-animation: fadeInRotate 0.8s ease 16s backwards;
|
||||||
|
-ms-animation: fadeInRotate 0.8s ease 16s backwards;
|
||||||
|
animation: fadeInRotate 0.8s ease 16s backwards;
|
||||||
|
-webkit-transform: scale(1) rotate(0deg);
|
||||||
|
-moz-transform: scale(1) rotate(0deg);
|
||||||
|
-o-transform: scale(1) rotate(0deg);
|
||||||
|
-ms-transform: scale(1) rotate(0deg);
|
||||||
|
transform: scale(1) rotate(0deg);
|
||||||
|
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: -250px -250px, 0 0;
|
||||||
|
|
||||||
|
background-image: -webkit-linear-gradient(
|
||||||
|
top left,
|
||||||
|
rgba(255, 255, 255, 0.2) 0%,
|
||||||
|
rgba(255, 255, 255, 0.2) 37%,
|
||||||
|
rgba(255, 255, 255, 0.8) 45%,
|
||||||
|
rgba(255, 255, 255, 0.0) 50%
|
||||||
|
);
|
||||||
|
background-image: -moz-linear-gradient(
|
||||||
|
0 0,
|
||||||
|
rgba(255, 255, 255, 0.2) 0%,
|
||||||
|
rgba(255, 255, 255, 0.2) 37%,
|
||||||
|
rgba(255, 255, 255, 0.8) 45%,
|
||||||
|
rgba(255, 255, 255, 0.0) 50%
|
||||||
|
);
|
||||||
|
background-image: -o-linear-gradient(
|
||||||
|
0 0,
|
||||||
|
rgba(255, 255, 255, 0.2) 0%,
|
||||||
|
rgba(255, 255, 255, 0.2) 37%,
|
||||||
|
rgba(255, 255, 255, 0.8) 45%,
|
||||||
|
rgba(255, 255, 255, 0.0) 50%
|
||||||
|
);
|
||||||
|
background-image: linear-gradient(
|
||||||
|
0 0,
|
||||||
|
rgba(255, 255, 255, 0.2) 0%,
|
||||||
|
rgba(255, 255, 255, 0.2) 37%,
|
||||||
|
rgba(255, 255, 255, 0.8) 45%,
|
||||||
|
rgba(255, 255, 255, 0.0) 50%
|
||||||
|
);
|
||||||
|
|
||||||
|
-moz-background-size: 250% 250%, 100% 100%;
|
||||||
|
background-size: 250% 250%, 100% 100%;
|
||||||
|
|
||||||
|
-webkit-transition: background-position 0s ease;
|
||||||
|
-moz-transition: background-position 0s ease;
|
||||||
|
-o-transition: background-position 0s ease;
|
||||||
|
transition: background-position 0s ease;
|
||||||
|
}
|
||||||
|
.circle-link:hover {
|
||||||
|
background-position: 0 0, 0 0;
|
||||||
|
|
||||||
|
-webkit-transition-duration: 0.5s;
|
||||||
|
-moz-transition-duration: 0.5s;
|
||||||
|
transition-duration: 0.5s;
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes blurFadeInOut {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 40px #fff;
|
||||||
|
-webkit-transform: scale(1.3);
|
||||||
|
}
|
||||||
|
20%, 75% {
|
||||||
|
opacity: 1;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
text-shadow: 0px 0px 50px #fff;
|
||||||
|
-webkit-transform: scale(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes blurFadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 40px #fff;
|
||||||
|
-webkit-transform: scale(1.3);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 10px #fff;
|
||||||
|
-webkit-transform: scale(1.1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
-webkit-transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes fadeInBack {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: scale(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.4;
|
||||||
|
-webkit-transform: scale(2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0.2;
|
||||||
|
-webkit-transform: scale(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-webkit-keyframes fadeInRotate {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
-webkit-transform: scale(0) rotate(360deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
-webkit-transform: scale(1) rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@-moz-keyframes blurFadeInOut {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 40px #fff;
|
||||||
|
-moz-transform: scale(1.3);
|
||||||
|
}
|
||||||
|
20%, 75% {
|
||||||
|
opacity: 1;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
-moz-transform: scale(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
text-shadow: 0px 0px 50px #fff;
|
||||||
|
-moz-transform: scale(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes blurFadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 40px #fff;
|
||||||
|
-moz-transform: scale(1.3);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
-moz-transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes fadeInBack {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
-moz-transform: scale(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.4;
|
||||||
|
-moz-transform: scale(2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0.2;
|
||||||
|
-moz-transform: scale(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@-moz-keyframes fadeInRotate {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
-moz-transform: scale(0) rotate(360deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
-moz-transform: scale(1) rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blurFadeInOut {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 40px #fff;
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
20%, 75% {
|
||||||
|
opacity: 1;
|
||||||
|
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0;
|
||||||
|
text-shadow: 0px 0px 50px #fff;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes blurFadeIn {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 40px #fff;
|
||||||
|
transform: scale(1.3);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.5;
|
||||||
|
color: #cc0000;
|
||||||
|
text-shadow: 0px 0px 10px #fff;
|
||||||
|
transform: scale(1.1);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
text-shadow: 0px 0px 1px #fff;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fadeInBack {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0);
|
||||||
|
}
|
||||||
|
50% {
|
||||||
|
opacity: 0.4;
|
||||||
|
transform: scale(2);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 0.2;
|
||||||
|
transform: scale(5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@keyframes fadeInRotate {
|
||||||
|
0% {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0) rotate(360deg);
|
||||||
|
}
|
||||||
|
100% {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1) rotate(0deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
<div class="container">
|
||||||
|
<div class="content">
|
||||||
|
<h2 class="frame-1">YouTube Music Desktop App</h2>
|
||||||
|
<h2 class="frame-2">With built-in ad blocker</h2>
|
||||||
|
<h2 class="frame-3">And built-in downloader</h2>
|
||||||
|
<h2 class="frame-4">Cross-platform</h2>
|
||||||
|
<h2 class="frame-5">
|
||||||
|
<span>Free,</span>
|
||||||
|
<span>Open source</span>
|
||||||
|
</h2>
|
||||||
|
<a class="circle-link" href="https://github.com/th-ch/youtube-music/releases/latest">
|
||||||
|
Download
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</foreignObject>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 9.2 KiB |
60
yarn.lock
60
yarn.lock
@ -372,31 +372,31 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
|
||||||
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==
|
||||||
|
|
||||||
"@cliqz/adblocker-content@^1.18.6":
|
"@cliqz/adblocker-content@^1.18.8":
|
||||||
version "1.18.6"
|
version "1.18.8"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-content/-/adblocker-content-1.18.6.tgz#a65dd518f3e6d1f2e9fee36ca5ae5615ba7b4cfd"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-content/-/adblocker-content-1.18.8.tgz#96473f14c098a20091298d34a6addcd430aceebd"
|
||||||
integrity sha512-OXrca20n+cMn9Ase+6oeX3fTmkauQMSb//lMLs56pHyra4foxN5o1rNiBG7qNIypdGQBFiTtGG7Vbp7YO5RQMw==
|
integrity sha512-YZ1xYBVG3LmxsdTYvTs/Bc7pzCw/Dy4HFo6N+oIuGP+Le/0aGSkACUl3ue5I2+Cx0WmL0Z8I4QonTKDc06HR+A==
|
||||||
|
|
||||||
"@cliqz/adblocker-electron-preload@^1.18.6":
|
"@cliqz/adblocker-electron-preload@^1.18.8":
|
||||||
version "1.18.6"
|
version "1.18.8"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron-preload/-/adblocker-electron-preload-1.18.6.tgz#57ec2dac09bbacb03b143609345638e98132f985"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron-preload/-/adblocker-electron-preload-1.18.8.tgz#c2058647e015b6f61c222e7d58040347324c63b0"
|
||||||
integrity sha512-cOK6ZuN3j0qLCZUj8oCf2PmPY837VTxtZM6bZl1x5xWLy/31x7186Wk0DP3C9MXU7gUhlqYxxKpbJDLZgFJ7Qw==
|
integrity sha512-/FAzyhNUj+8fwqSGth7ndaC+8huEANvVquYkDVmjM38uryxFgcJJI6Bij1l1zABIbskAaSN4G4RI3oERyd9/KQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cliqz/adblocker-content" "^1.18.6"
|
"@cliqz/adblocker-content" "^1.18.8"
|
||||||
|
|
||||||
"@cliqz/adblocker-electron@^1.18.6":
|
"@cliqz/adblocker-electron@^1.18.8":
|
||||||
version "1.18.6"
|
version "1.18.8"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron/-/adblocker-electron-1.18.6.tgz#e387a1dc6f3f4a4005d299b37723899be4f0967b"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker-electron/-/adblocker-electron-1.18.8.tgz#5f697c5dc65cd936b3908078a6e4516ec995567a"
|
||||||
integrity sha512-RGy003FHsvcLoGYaQIJVNWX8ZUQmK+Dbo0LeQAcsP96vOaTHHFOVj0Auhwkg7mZASiR9/XnoNepKIifO2zQVfw==
|
integrity sha512-CrsFjSwenWQogsAg4sHFaXZbu7hzs9dMdsZM5wxb+5QfZ3MSH3PBYAeAUnsmP3UOTZ423+6ErOUE1vzj3UrK9w==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cliqz/adblocker" "^1.18.6"
|
"@cliqz/adblocker" "^1.18.8"
|
||||||
"@cliqz/adblocker-electron-preload" "^1.18.6"
|
"@cliqz/adblocker-electron-preload" "^1.18.8"
|
||||||
tldts-experimental "^5.6.21"
|
tldts-experimental "^5.6.21"
|
||||||
|
|
||||||
"@cliqz/adblocker@^1.18.6":
|
"@cliqz/adblocker@^1.18.8":
|
||||||
version "1.18.6"
|
version "1.18.8"
|
||||||
resolved "https://registry.yarnpkg.com/@cliqz/adblocker/-/adblocker-1.18.6.tgz#07d075c45017db7cd2aff19afe466ad53217d318"
|
resolved "https://registry.yarnpkg.com/@cliqz/adblocker/-/adblocker-1.18.8.tgz#f6e5724fe6573c2e68f2545d90bcce3e1ecfbae9"
|
||||||
integrity sha512-+ro8DoqBaMt9nmfjJF+0Om03/9hdDhRx6NJKzwmW7Pfvd/XhqJ+NiDtdusABSERhCE3nUXCWdu5j09X9HiX6Vg==
|
integrity sha512-19m0GhlOcdSvQ/BqVuaMgbYkgQ4ys8koBRW4K7Ua4V5fFWL0t8ckdcZ/gBOqwECS2m8agXSpEbbyJjNmHBHpMQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@remusao/guess-url-type" "^1.1.2"
|
"@remusao/guess-url-type" "^1.1.2"
|
||||||
"@remusao/small" "^1.1.2"
|
"@remusao/small" "^1.1.2"
|
||||||
@ -469,15 +469,15 @@
|
|||||||
minimatch "^3.0.4"
|
minimatch "^3.0.4"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
"@ffmpeg/core@^0.8.4":
|
"@ffmpeg/core@^0.8.5":
|
||||||
version "0.8.4"
|
version "0.8.5"
|
||||||
resolved "https://registry.yarnpkg.com/@ffmpeg/core/-/core-0.8.4.tgz#69062a9b257792a9a8445e1f01e68c3e5e7fe58b"
|
resolved "https://registry.yarnpkg.com/@ffmpeg/core/-/core-0.8.5.tgz#2d0b7d4409a4348fa6a1888c247de706ffc0e63f"
|
||||||
integrity sha512-gEr4qXZpShZpIVUO3hc5Vz7bkk/jLYuzVVQtHluUwrui5eAooQwExOGiEovzLVkRwjJ707/qqfmTrK3r80UkWw==
|
integrity sha512-hemVFmhVLbD/VZaCG2BvCzFglKytMIMJ5aJfc12eXN4O4cG0wXnGTMVzlK1KKW/6viHhJMPkc9h4UDnJW8Uivg==
|
||||||
|
|
||||||
"@ffmpeg/ffmpeg@^0.9.5":
|
"@ffmpeg/ffmpeg@^0.9.6":
|
||||||
version "0.9.5"
|
version "0.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/@ffmpeg/ffmpeg/-/ffmpeg-0.9.5.tgz#6624747dc331632bc7c581e8d4f2046abc933798"
|
resolved "https://registry.yarnpkg.com/@ffmpeg/ffmpeg/-/ffmpeg-0.9.6.tgz#b44fa1ab34dd860785bb7c317dbfbe8b9ded7036"
|
||||||
integrity sha512-Vtxgi5C89n36pJ3I1/l6xd2qSwn+s1tAtLvFJ98N9P2ZorBvxXCEwTkt2yL7GuOUX9wpdG/vLFqp7iLso8LDwg==
|
integrity sha512-ov5FAV3dHRJ/+ZxQH9V5GvY/iczwq5vrKWeu4tpytxZewTSAhZ1aKD/sFBzd79nQNF+CTktxUp3LWuGECXBNeA==
|
||||||
dependencies:
|
dependencies:
|
||||||
is-url "^1.2.4"
|
is-url "^1.2.4"
|
||||||
node-fetch "^2.6.1"
|
node-fetch "^2.6.1"
|
||||||
@ -4544,9 +4544,9 @@ inherits@2.0.3:
|
|||||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||||
|
|
||||||
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
|
ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
|
||||||
version "1.3.5"
|
version "1.3.7"
|
||||||
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
|
resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.7.tgz#a09363e1911972ea16d7a8851005d84cf09a9a84"
|
||||||
integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
|
integrity sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==
|
||||||
|
|
||||||
interpret@^1.2.0:
|
interpret@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user