Exemplo n.º 1
0
 def test_setup(self):
     headers = YTMusic.setup(config['auth']['headers_file'], config['auth']['headers_raw'])
     self.assertGreaterEqual(len(headers), 2)
     headers_raw = config['auth']['headers_raw'].split('\n')
     with unittest.mock.patch('builtins.input', side_effect=(headers_raw + [EOFError()])):
         headers = YTMusic.setup(config['auth']['headers_file'])
         self.assertGreaterEqual(len(headers), 2)
Exemplo n.º 2
0
    def on_start(self):
        if self.auth:
            self.api = YTMusic(self._ytmusicapi_auth_json)
        else:
            self.api = YTMusic()

        if self._auto_playlist_refresh_rate:
            self._auto_playlist_refresh_timer = RepeatingTimer(
                self._refresh_auto_playlists, self._auto_playlist_refresh_rate)
            self._auto_playlist_refresh_timer.start()

        self._youtube_player_refresh_timer = RepeatingTimer(
            self._refresh_youtube_player, self._youtube_player_refresh_rate)
        self._youtube_player_refresh_timer.start()
Exemplo n.º 3
0
    def run(self, args, config):
        from ytmusicapi.ytmusic import YTMusic

        filepath = input(
            "Enter the path where you want to save auth.json [default=current dir]: "
        )
        if not filepath:
            filepath = os.getcwd()
        path = Path(filepath + '/auth.json')
        print('Using "' + str(path) + '"')
        if (path.exists()):
            print("File already exists!")
            return 1
        print(
            "Open Youtube Music, open developer tools (F12), go to Network tab,"
        )
        print(
            "right click on a POST request and choose \"Copy request headers\"."
        )
        print("Then paste (CTRL+SHIFT+V) them here and press CTRL+D.")
        try:
            print(YTMusic.setup(filepath=str(path)))
        except Exception:
            logger.exception("YoutubeMusic setup failed")
            return 1
        print("Authentication JSON data saved to {}".format(str(path)))
        print('')
        print('Update your mopidy.conf to reflect the new auth file:')
        print('   [youtubemusic]')
        print('   enabled=true')
        print('   auth_json=' + str(path))
        return 0
Exemplo n.º 4
0
 def test_setup(self):
     headers = YTMusic.setup(config['auth']['headers_file'],
                             config['auth']['headers_raw'])
     self.assertGreaterEqual(len(headers), 2)
     with unittest.mock.patch('builtins.input',
                              return_value=config['auth']['headers_raw']):
         self.assertGreaterEqual(len(headers), 2)
Exemplo n.º 5
0
    def __init__(self, config, audio):
        super().__init__()
        self.config = config
        self.audio = audio
        self.uri_schemes = ["ytmusic"]
        self.auth = False

        self._auto_playlist_refresh_rate = (
            config["ytmusic"]["auto_playlist_refresh"] * 60
        )
        self._auto_playlist_refresh_timer = None

        self._youtube_player_refresh_rate = (
            config["ytmusic"]["youtube_player_refresh"] * 60
        )
        self._youtube_player_refresh_timer = None

        self.playlist_item_limit = config["ytmusic"]["playlist_item_limit"]
        self.subscribed_artist_limit = config["ytmusic"][
            "subscribed_artist_limit"
        ]
        self.history = config["ytmusic"]["enable_history"]
        self.liked_songs = config["ytmusic"]["enable_liked_songs"]
        self.mood_genre = config["ytmusic"]["enable_mood_genre"]
        self.stream_preference = config["ytmusic"]["stream_preference"]
        self.verify_track_url = config["ytmusic"]["verify_track_url"]

        if config["ytmusic"]["auth_json"]:
            self._ytmusicapi_auth_json = config["ytmusic"]["auth_json"]
            self.auth = True

        if self.auth:
            self.api = YTMusic(self._ytmusicapi_auth_json)
        else:
            self.api = YTMusic()

        self.playback = YTMusicPlaybackProvider(audio=audio, backend=self)
        self.library = YTMusicLibraryProvider(backend=self)
        if self.auth:
            self.playlists = YTMusicPlaylistsProvider(backend=self)
Exemplo n.º 6
0
    def next(self) -> MusicSource:
        """Loads up the next song in the queue"""
        try:
            music_source = self.queue.next()
        except IndexError:
            if self.radio and self.watch_playlist:
                if len(self.watch_playlist["tracks"]) < 3:
                    current_music = self.queue.current()
                    logging.warning(
                        f"Regenerating malformed watch_playlist using id {current_music.info['id']}"
                    )
                    ytmusic = YTMusic()
                    self.watch_playlist = ytmusic.get_watch_playlist(
                        videoId=current_music.info["id"]
                    )

                if 2 <= len(self.watch_playlist["tracks"]) - 1:
                    track_no = random.randint(
                        2, len(self.watch_playlist["tracks"]) - 1
                    )
                    track = self.watch_playlist["tracks"][track_no]
                    base_url = "https://www.youtube.com/watch?v="
                    normalized_url = base_url + track["videoId"]
                    asyncio.run_coroutine_threadsafe(
                        self.play_youtube(normalized_url), self.client.loop
                    )
                    return
                else:
                    logging.error(
                        "Watch playlist is empty or malformed after second try, stopping radio mode."
                    )

            logging.info("No more music to play. Stopping...")
            self.stop()
            return None
        else:
            asyncio.run_coroutine_threadsafe(
                self.play(music_source), self.client.loop
            )
            return music_source
Exemplo n.º 7
0
    def run(self, args, config):
        from ytmusicapi.ytmusic import YTMusic

        path = config["ytmusic"]["auth_json"]
        if not path:
            logger.error("auth_json path not defined in config")
            return 1
        print('Updating credentials in  "' + str(path) + '"')
        print(
            "Open Youtube Music, open developer tools (F12), go to Network tab,"
        )
        print(
            'right click on a POST request and choose "Copy request headers".')
        print("Then paste (CTRL+SHIFT+V) them here and press CTRL+D.")
        try:
            print(YTMusic.setup(filepath=str(path)))
        except Exception:
            logger.exception("YTMusic setup failed")
            return 1
        print("Authentication JSON data saved to {}".format(str(path)))
        return 0
Exemplo n.º 8
0
    def __init__(self, config, audio):
        super().__init__()
        self.config = config
        self.audio = audio
        self.uri_schemes = ["ytm"]

        from youtube_dl import YoutubeDL
        from ytmusicapi.ytmusic import YTMusic

        global YDL
        YDL = YoutubeDL({
            "format": "bestaudio/m4a/mp3/ogg/best",
            "proxy": httpclient.format_proxy(self.config["proxy"]),
            "nocheckcertificate": True,
            "cachedir": False,
        })
        global API
        API = YTMusic(config["ytmusic"]["auth_json"])

        self.playback = YouTubePlaybackProvider(audio=audio, backend=self)
        self.library = YouTubeLibraryProvider(backend=self)
        self.playlists = YouTubePlaylistsProvider(backend=self)
Exemplo n.º 9
0
    def run(self, args, config):
        from ytmusicapi.ytmusic import YTMusic

        filepath = input("Enter the path where you want to save auth.json:")
        path = Path(filepath)
        if (path.exists()):
            print("File already exists!")
            return 1
        print(
            "Open Youtube Music, open developer tools (F12), go to Network tab,"
        )
        print(
            "right click on a POST request and choose \"Copy request headers\"."
        )
        print("Then paste (CTRL+SHIFT+V) them here and press CTRL+D.")
        try:
            print(YTMusic.setup(filepath=str(path)))
        except Exception:
            logger.exception("YTMusic setup failed")
            return 1
        print("auth.json saved to {}".format(str(path)))
        return 0
Exemplo n.º 10
0
 def test_setup(self):
     YTMusic.setup(config['auth']['headers_file'],
                   config['auth']['headers_raw'])
Exemplo n.º 11
0
import unittest
import configparser
import sys
sys.path.insert(0, '..')
from ytmusicapi.ytmusic import YTMusic  # noqa: E402

config = configparser.RawConfigParser()
config.read('./test.cfg', 'utf-8')

youtube = YTMusic()
youtube_auth = YTMusic(config['auth']['headers_file'])
youtube_brand = YTMusic(config['auth']['headers'],
                        config['auth']['brand_account'])


class TestYTMusic(unittest.TestCase):
    def test_init(self):
        self.assertRaises(Exception, YTMusic, "{}")

    def test_setup(self):
        YTMusic.setup(config['auth']['headers_file'],
                      config['auth']['headers_raw'])

    ###############
    # BROWSING
    ###############

    def test_search(self):
        query = "Oasis Wonderwall"
        self.assertRaises(Exception, youtube_auth.search, query, "song")
        results = youtube.search(query)
Exemplo n.º 12
0
class YTMusicBackend(pykka.ThreadingActor, backend.Backend,
                     YTMusicScrobbleListener):
    def __init__(self, config, audio):
        super().__init__()
        self.config = config
        self.audio = audio
        self.uri_schemes = ["ytmusic"]
        self.auth = False

        self._auto_playlist_refresh_rate = (
            config["ytmusic"]["auto_playlist_refresh"] * 60)
        self._auto_playlist_refresh_timer = None

        self._youtube_player_refresh_rate = (
            config["ytmusic"]["youtube_player_refresh"] * 60)
        self._youtube_player_refresh_timer = None

        self.playlist_item_limit = config["ytmusic"]["playlist_item_limit"]
        self.subscribed_artist_limit = config["ytmusic"][
            "subscribed_artist_limit"]
        self.history = config["ytmusic"]["enable_history"]
        self.liked_songs = config["ytmusic"]["enable_liked_songs"]
        self.mood_genre = config["ytmusic"]["enable_mood_genre"]
        self.stream_preference = config["ytmusic"]["stream_preference"]
        self.verify_track_url = config["ytmusic"]["verify_track_url"]

        if config["ytmusic"]["auth_json"]:
            self._ytmusicapi_auth_json = config["ytmusic"]["auth_json"]
            self.auth = True

        if self.auth:
            self.api = YTMusic(self._ytmusicapi_auth_json)
        else:
            self.api = YTMusic()

        self.playback = YTMusicPlaybackProvider(audio=audio, backend=self)
        self.library = YTMusicLibraryProvider(backend=self)
        if self.auth:
            self.playlists = YTMusicPlaylistsProvider(backend=self)

    def on_start(self):
        if self._auto_playlist_refresh_rate:
            self._auto_playlist_refresh_timer = RepeatingTimer(
                self._refresh_auto_playlists, self._auto_playlist_refresh_rate)
            self._auto_playlist_refresh_timer.start()

        self._youtube_player_refresh_timer = RepeatingTimer(
            self._refresh_youtube_player, self._youtube_player_refresh_rate)
        self._youtube_player_refresh_timer.start()

    def on_stop(self):
        if self._auto_playlist_refresh_timer:
            self._auto_playlist_refresh_timer.cancel()
            self._auto_playlist_refresh_timer = None
        if self._youtube_player_refresh_timer:
            self._youtube_player_refresh_timer.cancel()
            self._youtube_player_refresh_timer = None

    def _refresh_youtube_player(self):
        t0 = time.time()
        self.playback.Youtube_Player_URL = self._get_youtube_player()
        t = time.time() - t0
        logger.debug("YTMusic Player URL refreshed in %.2fs", t)

    def _get_youtube_player(self):
        # Refresh our js player URL so YDL can decode the signature correctly.
        response = requests.get(
            "https://music.youtube.com",
            headers=self.api.headers,
            proxies=self.api.proxies,
        )
        m = re.search(r'jsUrl"\s*:\s*"([^"]+)"', response.text)
        if m:
            url = m.group(1)
            logger.info("YTMusic updated player URL to %s", url)
            return url
        else:
            logger.error("YTMusic unable to extract player URL.")
            return None

    def _refresh_auto_playlists(self):
        t0 = time.time()
        self._get_auto_playlists()
        t = time.time() - t0
        logger.info("YTMusic Auto Playlists refreshed in %.2fs", t)

    def _get_auto_playlists(self):
        try:
            logger.debug("YTMusic loading auto playlists")
            response = self.api._send_request("browse", {})
            tab = nav(response, SINGLE_COLUMN_TAB)
            browse = parse_auto_playlists(nav(tab, SECTION_LIST))
            if "continuations" in tab["sectionListRenderer"]:
                request_func = lambda additionalParams: self.api._send_request(
                    "browse", {}, additionalParams)
                parse_func = lambda contents: parse_auto_playlists(contents)
                browse.extend(
                    get_continuations(
                        tab["sectionListRenderer"],
                        "sectionListContinuation",
                        100,
                        request_func,
                        parse_func,
                    ))
            # Delete empty sections
            for i in range(len(browse) - 1, 0, -1):
                if len(browse[i]["items"]) == 0:
                    browse.pop(i)
            logger.info("YTMusic loaded %d auto playlists sections",
                        len(browse))
            self.library.ytbrowse = browse
        except Exception:
            logger.exception("YTMusic failed to load auto playlists")
        return None

    def scrobble_track(self, bId):
        # Called through YTMusicScrobbleListener
        # Let YTMusic know we're playing this track so it will be added to our history.
        endpoint = "https://www.youtube.com/get_video_info"
        params = {
            "video_id": bId,
            "hl": self.api.language,
            "el": "detailpage",
            "c": "WEB_REMIX",
            "cver": "0.1",
        }
        response = requests.get(endpoint,
                                params,
                                headers=self.api.headers,
                                proxies=self.api.proxies)
        text = parse_qs(response.text)
        player_response = json.loads(text["player_response"][0])
        trackurl = re.sub(
            r"plid=",
            "list=",
            player_response["playbackTracking"]["videostatsPlaybackUrl"]
            ["baseUrl"],
        )
        CPN_ALPHABET = (
            "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")
        params = {
            "cpn":
            "".join((CPN_ALPHABET[random.randint(0, 256) & 63]
                     for _ in range(0, 16))),
            "referrer":
            "https://music.youtube.com",
            "cbr":
            text["cbr"][0],
            "cbrver":
            text["cbrver"][0],
            "c":
            text["c"][0],
            "cver":
            text["cver"][0],
            "cos":
            text["cos"][0],
            "cosver":
            text["cosver"][0],
            "cr":
            text["cr"][0],
            "ver":
            2,
        }
        tr = requests.get(
            trackurl,
            params=params,
            headers=self.api.headers,
            proxies=self.api.proxies,
        )
        logger.debug("%d code from '%s'", tr.status_code, tr.url)
Exemplo n.º 13
0
import unittest
import configparser
import sys
sys.path.insert(0, '..')
from ytmusicapi.ytmusic import YTMusic  # noqa: E402

config = configparser.RawConfigParser()
config.read('./test.cfg', 'utf-8')

youtube = YTMusic(requests_session=False)
youtube_auth = YTMusic(config['auth']['headers_file'])
youtube_brand = YTMusic(config['auth']['headers'],
                        config['auth']['brand_account'])


class TestYTMusic(unittest.TestCase):
    def test_init(self):
        self.assertRaises(Exception, YTMusic, "{}")

    def test_setup(self):
        YTMusic.setup(config['auth']['headers_file'],
                      config['auth']['headers_raw'])

    ###############
    # BROWSING
    ###############

    def test_search(self):
        query = "Oasis Wonderwall"
        self.assertRaises(Exception, youtube_auth.search, query, "song")
        results = youtube.search(query)
def download_playlist(dir, link, list_name, append_pl=False):
    
    if list_name is None:
        list_name = "playlist"
    if list_name == "":
        list_name = "playlist"

    dir_base = dir
    folder = 'mp3-songs'
    directory = '{}/{}'.format(dir_base, folder)
    exists = os.path.exists(directory)
    i = -1
    while exists:
        i += 1
        exists = os.path.exists(directory + str(i))
    if i >= 0:
        folder += str(i)
        directory += str(i)

    os.mkdir(directory)

    print("Beginning download for playlist: {}\nDownloading from link: {}".format(list_name, link))

    if link.find("music.") < 0:
        proc = Process(target=download_yt_direct, args=(link, directory, dir_base, folder, list_name, append_pl))
        proc.start()
        return proc

    playlistId = link[link.find("list=")+5:]
    playlistId_find = playlistId.find("&")
    if playlistId_find > 0:
        playlistId = playlistId[:playlistId_find]
    
    youtube = YTMusic()
    playlist_for_count = youtube.get_playlist(playlistId=playlistId, limit=1)
    playlist = youtube.get_playlist(playlistId=playlistId, limit=playlist_for_count['trackCount'])

    log_str = "--- WHILE OBTAINING PLAYLIST ---\n"
    log_str_orig_len = len(log_str)
    for track in playlist['tracks']:
        videoId = track['videoId']
        if videoId is None:
            log_str += "NOT FOUND: {}.\n".format(track['artists'][0]['name'] + " - " + track['title'])
            query = ""
            for artist in track['artists']:
                query += artist['name'] + " "
            query += track['title']
            search_list = youtube.search(query=query, filter='songs', limit=1, ignore_spelling=True)
            if len(search_list) == 0 or search_list[0]['videoId'] is None:
                query = track['artists'][0]['name'] + " " + track['title']
                search_list = youtube.search(query=query, filter='songs', limit=1, ignore_spelling=True)
                if len(search_list) == 0 or search_list[0]['videoId'] is None:
                    query = track['title']
                    search_list = youtube.search(query=query, filter='songs', limit=1, ignore_spelling=True)
                    if len(search_list) == 0 or search_list[0]['videoId'] is None:
                        search_list = youtube.search(query=query, filter='songs', limit=1, ignore_spelling=False)
            if len(search_list) > 0 and search_list[0]['videoId'] is not None:
                track['videoId'] = search_list[0]['videoId']
                track['artists'] = search_list[0]['artists']
                track['title'] = search_list[0]['title']
                videoId = track['videoId']
                log_str += "REPLACEMENT FOUND: {}.\n".format(track['artists'][0]['name'] + " - " + track['title'])
            else:
                log_str += "NO REPLACEMENT FOUND.\n"

    if len(log_str) == log_str_orig_len:
        log_str = ""
    
    proc = Process(target=download_tracks, args=(playlist, directory, dir_base, folder, list_name, log_str, append_pl))
    proc.start()
    return proc
Exemplo n.º 15
0
#!/usr/bin/env python

from ytmusicapi.ytmusic import YTMusic

songLimit = 100000

ytm = YTMusic('headers_auth.json')

songList = ytm.get_library_upload_songs(limit=songLimit)

for sl in songList:
    print(str(sl))
Exemplo n.º 16
0
import unittest
from ytmusicapi.ytmusic import YTMusic

youtube = YTMusic()
youtube_auth = YTMusic('../headers_auth.json')


class TestYTMusic(unittest.TestCase):
    def test_setup(self):
        YTMusic.setup()

    def test_get_playlists(self):
        playlists = youtube_auth.get_playlists()
        self.assertGreater(len(playlists), 0)

    def test_get_foreign_playlist(self):
        songs = youtube.get_playlist_items("PLw-VjHDlEOgs658kAHR_LAaILBXb-s6Q5")
        self.assertEqual(len(songs), 200)

    def test_get_owned_playlist(self):
        songs = youtube_auth.get_playlist_items('PLQwVIlKxHM6oCeKLTsUx_w9CmWjHKdg68')
        self.assertEqual(len(songs), 64)

    def test_get_history(self):
        songs = youtube_auth.get_history()
        self.assertGreater(len(songs), 0)

    def test_search(self):
        results = youtube_auth.search("Oasis Wonderwall")
        self.assertGreater(len(results), 0)
Exemplo n.º 17
0
 def test_setup(self):
     YTMusic.setup()
Exemplo n.º 18
0
 def setUpClass(cls):
     cls.yt = YTMusic(requests_session=False)
     cls.yt_auth = YTMusic(config['auth']['headers_file'])
     cls.yt_brand = YTMusic(config['auth']['headers'],
                            config['auth']['brand_account'])
Exemplo n.º 19
0
        songDict['album'] = normalizeUnicode(songDict['album'])
    songDict['filename'] = normalizeUnicode(songFile)

    return songDict


###

###################

### Main ###

playlist_file = sys.argv[1]

# authenticate w Youtube Music
ytm = YTMusic('headers_auth.json')

# figure out which playlist files we need to create
(need_to_create_name, need_to_read_file) = getPlayListFiles(playlist_file)

### find each song in each new playlist, lookup song_ids in Youtube Music, add them to list, create new playlist
cnt = 0
while (cnt <= len(need_to_read_file)) and (need_to_read_file[cnt] != 0
                                           and os.path.isfile(
                                               need_to_read_file[cnt])):
    songCount = 0
    pl_songs = []
    # read local playlist
    print("reading playlist : " + str(need_to_read_file[cnt]))
    with open(need_to_read_file[cnt], 'r', errors='replace') as f:
        line = f.readline()
Exemplo n.º 20
0
from ytmusicapi.ytmusic import YTMusic

ytm = YTMusic('headers_auth.json')

#results = ytm.search('kind', filter='uploads', limit=20)
results = ytm.get_library_playlists()

print(results)
Exemplo n.º 21
0
#!/usr/bin/env python

from ytmusicapi.ytmusic import YTMusic


ytm = YTMusic('headers_auth.json')

searchList = list()

searchList.append("Lee Moses - Hey Joe")
searchList.append("Joe Bataan - CALL MY NAME")
searchList.append("Creep")
searchList.append("H.E.R. - Fight For You")
searchList.append("Ugly Casanova - Barnacles")


for searchFor in searchList:
   
    print("Querying YTMusic for : " + searchFor)
    songDict = ytm.search(searchFor, 'uploads', limit=40)

    print("Result : ")
    print(str(songDict))