Code Monkey home page Code Monkey logo

Comments (7)

snuffyDev avatar snuffyDev commented on May 27, 2024 2

@ArjixWasTaken Don't worry! I got you covered. Originally, I was going to just respond with the basic flow of data through Beatbump, along with anything else that would've possibly helped. But, since I realized all of the useless info wouldn't have helped much, I figured I'd help you out on this. I have no userscript writing experience, so I just modified yours. In the end, I realized it was essentially impossible to get the URL from a userscript, so I ended up creating an object on the window to share it along with the title. The part I tacked on is pretty hacky though, since it opens the audio file in a new tab -- requiring a right click and 'Save Audio As' in order to actually download the track.

// ==UserScript==
// @name         Download song btn
// @namespace    https://github.com/ArjixWasTaken
// @version      0.1
// @description  Adds a download button to the context menu of songs at beatbump.ml
// @author       Arjix
// @match        https://beatbump.ml/*
// @icon         https://www.google.com/s2/favicons?domain=beatbump.ml
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @grant        none
// ==/UserScript==



const downloadButtonHTML = `
<div class="dd-item download-btn" tabindex="0">
    <?xml version="1.0" encoding="iso-8859-1"?>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="31" height="23">
    <!-- https://www.svgrepo.com/svg/152538/download --!>

        <g transform="matrix(0.4893617 0 0 0.4893617 4.000001 -0)">
	    <g>
            <path d="M22.792 34.706C 22.883999 34.799 22.994999 34.872 23.118 34.923C 23.24 34.973 23.37 35 23.5 35C 23.63 35 23.76 34.973 23.882 34.923C 24.005 34.872 24.115 34.799 24.208 34.706L24.208 34.706L36.207 22.707C 36.598 22.316 36.598 21.684 36.207 21.293001C 35.816 20.902002 35.184002 20.902 34.793 21.293001L34.793 21.293001L24.5 31.586L24.5 1C 24.5 0.44700003 24.052 0 23.5 0C 22.948 0 22.5 0.447 22.5 1L22.5 1L22.5 31.586L12.207 21.293C 11.816 20.901999 11.184 20.901999 10.792999 21.293C 10.4019985 21.684 10.401999 22.316 10.792999 22.706999L10.792999 22.706999L22.792 34.706z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
            <path d="M1.5 43L45.5 43C 46.053 43 46.5 42.553 46.5 42C 46.5 41.447 46.053 41 45.5 41L45.5 41L1.5 41C 0.948 41 0.5 41.447 0.5 42C 0.5 42.553 0.948 43 1.5 43z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
            <path d="M45.5 45L1.5 45C 0.948 45 0.5 45.447 0.5 46C 0.5 46.553 0.948 47 1.5 47L1.5 47L45.5 47C 46.053 47 46.5 46.553 46.5 46C 46.5 45.447 46.053 45 45.5 45z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
	    </g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g>
    </svg>
    <div class="dd-text">Download</div>
</div>
`
const contextMenuSelector = `.dd-menu > .dd-item:last-of-type, .dd-player > .dd-item:last-of-type`

const globalInfo = {
    isCtxMenuOpen: false
}
const onContextMenuOpen = async (callback) => {
    setInterval(() => {
        let ctxMenu = $(contextMenuSelector)
        if (ctxMenu.length != 0) {
            if (!globalInfo.isCtxMenuOpen) {
                globalInfo.isCtxMenuOpen = true
                callback(ctxMenu)
            }
        } else {
            globalInfo.isCtxMenuOpen = false
        }
    }, 200)
}


onContextMenuOpen(async (menu) => {
    menu.after(downloadButtonHTML)
    $(".download-btn").on("click", downloadCallback)
})


const downloadCallback = () => {
    alert(`Downloading ${window.bbPlayer.title}\nThe audio file will open up in a new tab, to download, right click and press 'Save Audio As'.`)
    const link = document.createElement('a');
    link.href=window.bbPlayer.src;
    link.rel = "noopener noreferrer"
    link.target = "_blank"
    link.download = `${window.bbPlayer.title}`;
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link)
}

Hopefully you don't mind me doing the download part! Let me know what you think.

from beatbump.

snuffyDev avatar snuffyDev commented on May 27, 2024 1

I've contemplated this in the past. It's a hard decision just because of the potential legal problems it could cause. While the feature itself wouldn't be more than 15-20 lines of code (since Beatbump already as the file URL in memory because of how it retrieves the media), it's a touch choice to make.

For the time being, although the audio isn't stored locally, Beatbump does have custom playlists. Right now, I'm experimenting with caching audio in the browser, which potentially could be done for any song you choose. Through the cache, it'll then be possible to have offline playback for audio. Just waiting ~6 hours to see if the YouTube audio I just cached expires, since it has an 'Expires' query param of 1638718181.

Will report back with my findings!

from beatbump.

snuffyDev avatar snuffyDev commented on May 27, 2024 1

Hello! My bad for the time it took to get a conclusive answer. As far as I’ve been able to find, caching works up until the “expires” URL parameter. I’ve only been able to test it minimally, but today I’ll keep experimenting with it. Depending on what the outcomes of the experiments could be, I might add in offline caching

from beatbump.

ArjixWasTaken avatar ArjixWasTaken commented on May 27, 2024 1

@snuffyDev are you against the idea of a userscript implementing this? (that way it's not your responsibility if google doesn't like it)
if not, then is this open for discussion?

my code so far (only adds the button and alerts "hi" when clicked)

// ==UserScript==
// @name         Download song btn
// @namespace    https://github.com/ArjixWasTaken
// @version      0.1
// @description  Adds a download button to the context menu of songs at beatbump.ml
// @author       Arjix
// @match        https://beatbump.ml/*
// @icon         https://www.google.com/s2/favicons?domain=beatbump.ml
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @grant        none
// ==/UserScript==



const downloadButtonHTML = `
<div class="dd-item download-btn" tabindex="0">
    <?xml version="1.0" encoding="iso-8859-1"?>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="31" height="23">
    <!-- https://www.svgrepo.com/svg/152538/download --!>

        <g transform="matrix(0.4893617 0 0 0.4893617 4.000001 -0)">
	    <g>
            <path d="M22.792 34.706C 22.883999 34.799 22.994999 34.872 23.118 34.923C 23.24 34.973 23.37 35 23.5 35C 23.63 35 23.76 34.973 23.882 34.923C 24.005 34.872 24.115 34.799 24.208 34.706L24.208 34.706L36.207 22.707C 36.598 22.316 36.598 21.684 36.207 21.293001C 35.816 20.902002 35.184002 20.902 34.793 21.293001L34.793 21.293001L24.5 31.586L24.5 1C 24.5 0.44700003 24.052 0 23.5 0C 22.948 0 22.5 0.447 22.5 1L22.5 1L22.5 31.586L12.207 21.293C 11.816 20.901999 11.184 20.901999 10.792999 21.293C 10.4019985 21.684 10.401999 22.316 10.792999 22.706999L10.792999 22.706999L22.792 34.706z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
            <path d="M1.5 43L45.5 43C 46.053 43 46.5 42.553 46.5 42C 46.5 41.447 46.053 41 45.5 41L45.5 41L1.5 41C 0.948 41 0.5 41.447 0.5 42C 0.5 42.553 0.948 43 1.5 43z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
            <path d="M45.5 45L1.5 45C 0.948 45 0.5 45.447 0.5 46C 0.5 46.553 0.948 47 1.5 47L1.5 47L45.5 47C 46.053 47 46.5 46.553 46.5 46C 46.5 45.447 46.053 45 45.5 45z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
	    </g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g>
    </svg>
    <div class="dd-text">Download</div>
</div>
`
const contextMenuSelector = `.dd-menu > .dd-item:last-of-type, .dd-player > .dd-item:last-of-type`

const globalInfo = {
    isCtxMenuOpen: false
}
const onContextMenuOpen = async (callback) => {
    setInterval(() => {
        let ctxMenu = $(contextMenuSelector)
        if (ctxMenu.length != 0) {
            if (!globalInfo.isCtxMenuOpen) {
                globalInfo.isCtxMenuOpen = true
                callback(ctxMenu)
            }
        } else {
            globalInfo.isCtxMenuOpen = false
        }
    }, 200)
}


onContextMenuOpen(async (menu) => {
    menu.after(downloadButtonHTML)
    $(".download-btn").on("click", downloadCallback)
})


const downloadCallback = () => {
    alert("hi")
}

All that's left for me to implement are the following:

  • Detect what the fuck triggered the context menu (like, what song or playlist)
  • Find out how the fuck do I get that download link, since I for my life can't find the player instance

Anyways, if you are against the idea of a userscript then I'll drop this
I just thought it would be fun to make a userscript

PS: I wrote this with extensibility in mind, so other userscript devs can add more buttons to the ctx menu.

from beatbump.

ArjixWasTaken avatar ArjixWasTaken commented on May 27, 2024 1

Great!

Actually for the downloading part Tampermonkey (and GreasyMonkey) provide an API to start a download (you know, like any normal download)

When I'm free I'll do just that!

Thanks for the cooperation.

from beatbump.

ArjixWasTaken avatar ArjixWasTaken commented on May 27, 2024 1

Done:

// ==UserScript==
// @name         Download song btn
// @namespace    https://github.com/ArjixWasTaken
// @version      0.1
// @description  Adds a download button to the context menu of songs at beatbump.ml
// @author       Arjix
// @match        https://beatbump.ml/*
// @icon         https://www.google.com/s2/favicons?domain=beatbump.ml
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.min.js
// @grant        unsafeWindow
// @grant        GM_download
// ==/UserScript==



const downloadButtonHTML = `
<div class="dd-item download-btn" tabindex="0">
    <?xml version="1.0" encoding="iso-8859-1"?>
    <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" id="body_1" width="31" height="23">
    <!-- https://www.svgrepo.com/svg/152538/download --!>

        <g transform="matrix(0.4893617 0 0 0.4893617 4.000001 -0)">
	    <g>
            <path d="M22.792 34.706C 22.883999 34.799 22.994999 34.872 23.118 34.923C 23.24 34.973 23.37 35 23.5 35C 23.63 35 23.76 34.973 23.882 34.923C 24.005 34.872 24.115 34.799 24.208 34.706L24.208 34.706L36.207 22.707C 36.598 22.316 36.598 21.684 36.207 21.293001C 35.816 20.902002 35.184002 20.902 34.793 21.293001L34.793 21.293001L24.5 31.586L24.5 1C 24.5 0.44700003 24.052 0 23.5 0C 22.948 0 22.5 0.447 22.5 1L22.5 1L22.5 31.586L12.207 21.293C 11.816 20.901999 11.184 20.901999 10.792999 21.293C 10.4019985 21.684 10.401999 22.316 10.792999 22.706999L10.792999 22.706999L22.792 34.706z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
            <path d="M1.5 43L45.5 43C 46.053 43 46.5 42.553 46.5 42C 46.5 41.447 46.053 41 45.5 41L45.5 41L1.5 41C 0.948 41 0.5 41.447 0.5 42C 0.5 42.553 0.948 43 1.5 43z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
            <path d="M45.5 45L1.5 45C 0.948 45 0.5 45.447 0.5 46C 0.5 46.553 0.948 47 1.5 47L1.5 47L45.5 47C 46.053 47 46.5 46.553 46.5 46C 46.5 45.447 46.053 45 45.5 45z" stroke="currentColor" fill="currentColor" fill-rule="nonzero" />
	    </g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g><g></g></g>
    </svg>
    <div class="dd-text">Download</div>
</div>
`
const contextMenuSelector = `.dd-menu > .dd-item:last-of-type, .dd-player > .dd-item:last-of-type`

const globalInfo = {
    isCtxMenuOpen: false
}
const onContextMenuOpen = async (callback) => {
    setInterval(() => {
        let ctxMenu = $(contextMenuSelector)
        if (ctxMenu.length != 0) {
            if (!globalInfo.isCtxMenuOpen) {
                globalInfo.isCtxMenuOpen = true
                callback(ctxMenu)
            }
        } else {
            globalInfo.isCtxMenuOpen = false
        }
    }, 200)
}


onContextMenuOpen(async (menu) => {
    menu.after(downloadButtonHTML)
    $(".download-btn").on("click", downloadCallback)
})


const downloadCallback = () => {
    try {
        GM_download(unsafeWindow.bbPlayer.src, unsafeWindow.bbPlayer.title + ".mp3")
    } catch {
    }
    // alert(`Downloading ${window.bbPlayer.title}\nThe audio file will open up in a new tab, to download, right click and press 'Save Audio As'.`)
}

Only works with tampermonkey since uhh, GreasyMonkey does not have a download API.

install from GreasyFork

from beatbump.

snuffyDev avatar snuffyDev commented on May 27, 2024 1

Very nice 😎😎 glad it wasn’t a hassle to put together! Assuming that this satisfies the issue filed, I’m going mark it as closed. Appreciate the feedback guys, and once again great job on the userscript!

from beatbump.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.