flowese / UdioWrapper

UdioWrapper is a Python package that enables the generation of music tracks using Udio's API through textual prompts. This package is based on the reverse engineering of the Udio API (https://www.udio.com/) and is not officially endorsed by Udio.
MIT License
136 stars 26 forks source link

500 Server Error - Auto Solve hcapcha #7

Open luoshangxuan1992 opened 7 months ago

luoshangxuan1992 commented 7 months ago

hi, Thanks for the code!

I got a 'Error making POST request to https://www.udio.com/api/generate-proxy: 500 Server Error: Internal Server Error for url: https://www.udio.com/api/generate-proxy' both in my local IDE and the colab you provided. Is this the server problem?


This repo is using Opire - what does it means? ๐Ÿ‘‡
๐Ÿ’ธEveryone can add rewards for this issue commenting /reward 100 (replace 100 with the amount)
๐Ÿ’ช If someone starts working on this issue to earn the rewards, they can comment /try to let everyone know!
๐Ÿ™Œ And when they open the PR, they can comment /claim #7 either in the PR description or in a PR's comment

๐Ÿ‘€ Also, everyone can tip any user commenting /tip 20 @luoshangxuan1992 (replace 20 with the amount, and @luoshangxuan1992 with the user to tip)

If you want to learn more, go to our documentation
jfarre20 commented 7 months ago

they added hcapcha, rip

Questscape commented 7 months ago

rip

jfarre20 commented 7 months ago

i rewrote my discord bot to use selenium/chromedriver and they're getting me there too. I guess it was fun while it lasted.

luoshangxuan1992 commented 7 months ago

i rewrote my discord bot to use selenium/chromedriver and they're getting me there too. I guess it was fun while it lasted.

Thanks, I'll try it!

flowese commented 7 months ago

Hello everyone!

Thank you all so much for the support and interest in this library. I am currently assessing how to address the 500 server error issue. Using Selenium might indeed be a temporary workaround to bypass this problem. Any collaboration on this repo would be greatly appreciated.

Thanks for the help and for continuing to contribute!

jfarre20 commented 7 months ago

I've been trying all day and I can't get it consistently to let me in with no captcha. I even tried hiding selenium. options.add_argument('--disable-blink-features=AutomationControlled') their capcha solution thing just knows.

even if I solve the captcha it just fails. Yet if I close chrome and open again outside of selenium, it works (after popping a capcha).

I had it work twice and then nothing.

I noticed their js is sending the chrome console logs to udio.com/monitoring?=blah

I was doing some JS injection to grab the song IDs when generate-proxy returns, and wrote to the console.

I blocked this but still.

jfarre20 commented 7 months ago

Here's some thrown together code to try selenium with, maybe someone will figure out this capcha thing - i give up:

import aiohttp
import asyncio
import json
import os
import string
import random
from aiohttp import ContentTypeError

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium_stealth import stealth

chrome_options = Options()
chrome_options.add_argument("start-maximized")
chrome_options.add_experimental_option("detach", True)

#set user data directory to the default Chrome profile
chrome_options.add_argument(r"--user-data-dir=C:\Users\Administrator\AppData\Local\Google\Chrome\User Data")
chrome_options.add_argument(r'--profile-directory=Default')
chrome_options.add_argument("--disable-blink-features")
chrome_options.add_argument('--remote-debugging-port=9222')
chrome_options.add_argument('--disable-blink-features=AutomationControlled')
chrome_options.add_argument('--user-agent=Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36')
chrome_options.add_experimental_option("excludeSwitches", ["enable-automation"])
chrome_options.add_experimental_option('useAutomationExtension', False)

url = ""
session_id = ""

def randtime():
    return random.uniform(0.45, 3.0)

def page_load_complete(driver):
    return driver.execute_script("return document.readyState") == "complete"

class UdioClient:
    def __init__(self, session_cookie):
        self.session_cookie = session_cookie
        print(f"Initialized udio session cookie: {self.session_cookie}")

    def update_cookies(self, session_cookie):
        self.session_cookie = session_cookie
        print(f"Updated udio session cookie: {self.session_cookie}")

    async def create_song(self, prompt, instrumental=False, lyrics=None):
        print("Creating webdriver")
        global url, session_id
        #connect to existing chrome if open
        try:
            driver = webdriver.Remote(command_executor=url, desired_capabilities={})
            driver.close()
            driver.session_id = session_id
            print("Reusing existing chrome session")
        except:
            driver = webdriver.Chrome(options=chrome_options)
            url = driver.command_executor._url
            session_id = driver.session_id
            print("Created new chrome session at " + url + " with session: " + session_id)
            #check if more than 1 chrome session is open
            if len(driver.window_handles) > 1:
                #close the extra window
                driver.switch_to.window(driver.window_handles[1])
                driver.close()
                #switch back to the main window
                driver.switch_to.window(driver.window_handles[0])

        # Selenium Stealth settings
        stealth(driver,
            languages=["en-US", "en"],
            vendor="Google Inc.",
            platform="Win32",
            webgl_vendor="Intel Inc.",
            renderer="Intel Iris OpenGL Engine",
            fix_hairline=True,
        )

        await asyncio.sleep(5+randtime())
        #soft navigate to udio.com if not already there
        if driver.current_url != "https://www.udio.com/" or driver.current_url != "https://www.udio.com/my-creations":
            print("Navigating to udio.com")
            driver.get("https://www.udio.com/")
            await asyncio.sleep(5+randtime())

        # Wait for the page to load until you can click on "my creations"
        WebDriverWait(driver, 12+randtime()).until(page_load_complete)
        #navigate to my creations by href="/my-creations"
        asyncio.sleep(randtime())
        driver.find_element(By.CSS_SELECTOR, 'a[href="/my-creations"]').click()

        await asyncio.sleep(randtime())

        driver.find_element(By.CSS_SELECTOR, 'input[type="prompt"]').click()
        await asyncio.sleep(randtime())

        #REMOVE ANY EMOJIS FROM PROMPT
        prompt = ''.join(filter(lambda x: x in string.printable, prompt))

        driver.find_element(By.CSS_SELECTOR, 'input[type="prompt"]').send_keys(prompt)
        await asyncio.sleep(randtime())

        if instrumental:
            driver.find_element(By.XPATH, '//div[text()="Instrumental"]').click()
            await asyncio.sleep(randtime())

        if lyrics:
            driver.find_element(By.XPATH, '//div[text()="Custom"]').click()
            element = driver.find_element(By.XPATH, '//textarea[@placeholder="Write custom lyrics here"]')
            lyrics = ''.join(filter(lambda x: x in string.printable, lyrics))
            element.send_keys(lyrics)
            #press return
            element.send_keys("\n")
            await asyncio.sleep(6+randtime())

        # Inject the JavaScript code to override the XMLHttpRequest
        driver.execute_script("""
            window.trackIds = [];
            var originalXHR = window.XMLHttpRequest;
            window.XMLHttpRequest = function() {
                var xhr = new originalXHR();
                xhr.addEventListener('load', function() {
                    if (this.responseURL.includes('/generate-proxy')) {
                        var responseText = this.responseText;
                        console.log('Response Text:', responseText);

                        if (responseText.includes('"track_ids":')) {
                            var startIndex = responseText.indexOf('"track_ids":') + '"track_ids":'.length;
                            var endIndex = responseText.indexOf(']', startIndex) + 1;
                            var trackIdsString = responseText.substring(startIndex, endIndex);
                            window.trackIds = JSON.parse(trackIdsString);
                            console.log('Track IDs:', window.trackIds);
                        } else {
                            console.log('Track IDs not found in the response');
                        }
                    }
                });
                return xhr;
            };
        """)

        driver.find_element(By.XPATH, '//button[text()="Create"]').click()

        #wait for capcha check
        await asyncio.sleep(12+randtime())

        # Wait for the track IDs to be populated
        track_ids = WebDriverWait(driver, randtime()).until(
            lambda driver: driver.execute_script("return window.trackIds;")
        )

        await asyncio.sleep(randtime())
        driver.quit()
        return track_ids

    async def get_song_info(self, track_ids):
        track_id_string = ','.join(track_ids)
        async with aiohttp.ClientSession() as session:
            while True:
                async with session.get(f'https://www.udio.com/api/songs?songIds={track_id_string}',
                                    headers={
                                        'Cookie': f'sb-api-auth-token={self.session_cookie}'
                                    }) as response:
                    if response.status == 200:
                        try:
                            result = await response.json()
                        except ContentTypeError:
                            result = await response.json(content_type=None)

                        songs = result.get('songs')

                        #check for moderation
                        if songs and any(song['error_type'] == 'MODERATION' for song in songs):
                            print("Song got moderated, sorry...")
                            return "Error", "song got moderated - stupid corpos..."

                        if songs and all(song['finished'] for song in songs):
                            return songs
                        await asyncio.sleep(5)
                    else:
                        print(f"Error getting song info: {response.status}")
                        return None

call it like this:

        from udio_client import UdioClient
        udio_client = UdioClient('your_session_cookie')

        track_ids = await udio_client.create_song(prompt, instrumental, lyrics)

        print(f"Track IDs: {track_ids}")

        #check if the track_ids is a tuple with an error message
        if isinstance(track_ids, tuple) and track_ids[0] == "Error":
            print(f"Failed to generate song: {track_ids[1]}")

        if track_ids:
            tracks = await udio_client.get_song_info(track_ids)
            if isinstance(tracks, tuple) and tracks[0] == "Error":
                print(f"Failed to generate song: {tracks[1]}")
                Udio_generating = False
                return
            elif tracks:
            #stuff to parse
jfarre20 commented 7 months ago

An update, I got it kind of working using 'undetected-chromedriver'. It still pops the captcha every time though, but once solved it works. Before it was failing even when manually solved. Now I need to figure out what's triggering hcaptcha, it doesn't pop every time when I browse the site regularly.

flowese commented 7 months ago

Hey jfarre20! Your progress with the captcha issue is super valuable. I've just gotten home and I'm going to review the steps you mentioned. I invite you to officially join this repo to continue contributing and ensure the continuity of the library. Your work is crucial and it would be great to have your expertise on board long-term!

katywilliams1121 commented 7 months ago

any update?

jfarre20 commented 7 months ago

the captcha sort of ruins this. I have it working to the degree where you need to do 2 captchas every time to get a generation out of it. image

basically outside of my specific use case, its useless.

we may be better off waiting for an official api.

katywilliams1121 commented 7 months ago

damm

flowese commented 7 months ago

Hi @jfarre20

I've noticed your skill in integrating music generation into your Discord bot, and I believe you could bring a unique perspective to our project. Could you share more details on how you achieved this integration? If your work is public, I would be delighted to link it in the README of our repository and give you the proper acknowledgment you deserve.

Additionally, if you are interested in a closer collaboration, I would like to offer you a contributor role in this repository. Your vision and technical skills would be tremendously valuable to us, and I believe we could achieve great advances together.

I look forward to the possibility of working more closely with you and referencing your work in this project.

jfarre20 commented 7 months ago

Hi @jfarre20

I've noticed your skill in integrating music generation into your Discord bot, and I believe you could bring a unique perspective to our project. Could you share more details on how you achieved this integration? If your work is public, I would be delighted to link it in the README of our repository and give you the proper acknowledgment you deserve.

Additionally, if you are interested in a closer collaboration, I would like to offer you a contributor role in this repository. Your vision and technical skills would be tremendously valuable to us, and I believe we could achieve great advances together.

I look forward to the possibility of working more closely with you and referencing your work in this project.

I've talked it over with my company and they feel me publicly contributing to something that bypasses an anti bot system (capcha) would not be something I should do if I value my job. Apologies.

romastra commented 7 months ago

they feel me publicly contributing to something

ps-s-st... Just blink twice if you're being held hostage. )) Kidding.... But still you can make another git account.

flowese commented 7 months ago

Hey, folks!

I wanted to let you know that @Pikachubolk has forked our library and implemented a paid service called Nopecha to automatically solve hcaptcha. Although I haven't personally tested this solution (since it's paid), here's the link in case anyone is interested in exploring it: Pikachubolk's UdioWrapper Fork.

While using this option could be a temporary fix for those in need of a quick solution, it does deviate a bit from our philosophy of open and free software. As we continue to work on finding more suitable alternatives, this might be an option for those who are pressed.

By the way, I was thinking about offering a symbolic reward to further motivate collaboration on our project. What do you think of the idea? This way, we can encourage more people to contribute and continue improving this tool that we all use.

I look forward to your comments and suggestions. Thanks for being such an active part of this community!

Cheers to everyone!

flowese commented 7 months ago

/reward 20

How to earn this $20.00 reward?
๐Ÿ’ช Comment /try and start working on solving the issue! ๐Ÿ™Œ And when you open the PR, comment /claim #7 either in the PR description or in a PR's comment

ashmitsharma commented 6 months ago

Did anyone find any solution to this problem ?

volkankahraman commented 6 months ago

Any update?

TintinSDev commented 4 months ago

/try

Check if you're the only one trying ๐Ÿ‘‡
Perfect! You're the first one to try to solve this issue, go for it! ๐Ÿ˜‰

opirebot[bot] commented 4 months ago

๐Ÿ”ฅ The user @TintinSDev has claimed all rewards for this issue. ๐ŸŽฏ You can see the PR here ๐Ÿ’ฐ @flowese you can pay the related rewards here