Read details at
Browse files- app.py +7 -2
- index.html +28 -15
app.py
CHANGED
@@ -1,10 +1,15 @@
|
|
1 |
"""Shazam Playlist to Youtube Playlist"""
|
2 |
|
3 |
from typing import Optional
|
|
|
4 |
import pandas as pd
|
5 |
from pytube import Search, YouTube
|
6 |
from flask import Flask, request, send_from_directory
|
7 |
|
|
|
|
|
|
|
|
|
8 |
app = Flask(__name__)
|
9 |
|
10 |
@app.route('/')
|
@@ -21,7 +26,7 @@ def video_id() -> str:
|
|
21 |
try:
|
22 |
title: str = request.json.get('title')
|
23 |
artist: str = request.json.get('artist')
|
24 |
-
youtube: YouTube =
|
25 |
return youtube.video_id
|
26 |
except Exception as e:
|
27 |
return str(e)
|
@@ -38,7 +43,7 @@ def parse_csv():
|
|
38 |
except Exception as e:
|
39 |
return str(e)
|
40 |
|
41 |
-
def
|
42 |
"""Searches for a YouTube video based on the given title and artist"""
|
43 |
search_result = Search(f'{title} by {artist}')
|
44 |
return search_result.results[0] if search_result.results else None
|
|
|
1 |
"""Shazam Playlist to Youtube Playlist"""
|
2 |
|
3 |
from typing import Optional
|
4 |
+
import logging
|
5 |
import pandas as pd
|
6 |
from pytube import Search, YouTube
|
7 |
from flask import Flask, request, send_from_directory
|
8 |
|
9 |
+
# https://github.com/pytube/pytube/issues/1270#issuecomment-2100372834
|
10 |
+
pytube_logger = logging.getLogger('pytube')
|
11 |
+
pytube_logger.setLevel(logging.ERROR)
|
12 |
+
|
13 |
app = Flask(__name__)
|
14 |
|
15 |
@app.route('/')
|
|
|
26 |
try:
|
27 |
title: str = request.json.get('title')
|
28 |
artist: str = request.json.get('artist')
|
29 |
+
youtube: YouTube = get_youtube_song(title, artist)
|
30 |
return youtube.video_id
|
31 |
except Exception as e:
|
32 |
return str(e)
|
|
|
43 |
except Exception as e:
|
44 |
return str(e)
|
45 |
|
46 |
+
def get_youtube_song(title: str, artist: str) -> Optional[YouTube]:
|
47 |
"""Searches for a YouTube video based on the given title and artist"""
|
48 |
search_result = Search(f'{title} by {artist}')
|
49 |
return search_result.results[0] if search_result.results else None
|
index.html
CHANGED
@@ -15,20 +15,19 @@
|
|
15 |
height: 100%;
|
16 |
}
|
17 |
|
18 |
-
.playlist tbody tr {
|
19 |
-
cursor: pointer;
|
20 |
}
|
21 |
</style>
|
22 |
</head>
|
23 |
|
24 |
<body>
|
25 |
<div class="container my-4">
|
26 |
-
<h1 class="text-center">Shazam Playlist to
|
27 |
-
<em>
|
28 |
<i>
|
29 |
-
|
30 |
-
<a href="https://toknow.ai/posts/shazam-playlist-to-youtube-playlist/">blog post</a>.
|
31 |
-
This service is free of charge and does not require any payment or subscription to use.
|
32 |
</i>
|
33 |
</em>
|
34 |
<p class="text-center">
|
@@ -60,7 +59,8 @@
|
|
60 |
const playlistTable = document.querySelector('.playlist');
|
61 |
const uploaForm = document.querySelector('.upload-form');
|
62 |
let songsPlaylist = []
|
63 |
-
let videoIndex =
|
|
|
64 |
|
65 |
uploaForm.addEventListener('input', e => {
|
66 |
e.preventDefault();
|
@@ -87,7 +87,13 @@
|
|
87 |
}
|
88 |
})
|
89 |
}
|
90 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
91 |
async function getVideoId(song) {
|
92 |
const response = await fetch(
|
93 |
'/video_id',
|
@@ -99,7 +105,7 @@
|
|
99 |
return await response.text()
|
100 |
}
|
101 |
async function nextVideo(callback, newIndex = undefined) {
|
102 |
-
newIndex =
|
103 |
videoIndex = newIndex < songsPlaylist.length ? newIndex : 0;
|
104 |
let video_id = await getVideoId(songsPlaylist[videoIndex]);
|
105 |
callback(video_id);
|
@@ -117,7 +123,7 @@
|
|
117 |
<th>${i.Title}</th>
|
118 |
<th>${i.Artist}</th>
|
119 |
</tr>`
|
120 |
-
|
121 |
playlistTable.innerHTML = `
|
122 |
<table class="table table-striped table-hover table-bordered rounded">
|
123 |
<thead>
|
@@ -133,7 +139,6 @@
|
|
133 |
playlistTable.innerHTML = error;
|
134 |
}
|
135 |
}
|
136 |
-
let youtubePlayer;
|
137 |
function onYouTubeIframeAPIReady() {
|
138 |
const youtubePlayerElement = document.querySelector('.youtube-player');
|
139 |
youtubePlayer = window.youtubePlayer = new YT.Player(youtubePlayerElement, {
|
@@ -149,7 +154,8 @@
|
|
149 |
onContinue(event?.target);
|
150 |
}
|
151 |
},
|
152 |
-
'onError': function(event) {
|
|
|
153 |
onContinue(event?.target);
|
154 |
}
|
155 |
}
|
@@ -162,13 +168,20 @@
|
|
162 |
}
|
163 |
}, 500);
|
164 |
};
|
165 |
-
|
166 |
function onContinue(player = undefined, newIndex = undefined) {
|
167 |
if (songsPlaylist.length > 0) {
|
168 |
nextVideo((value) => {
|
169 |
player = player || youtubePlayer
|
170 |
player.loadVideoById(value);
|
171 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
172 |
}, newIndex);
|
173 |
}
|
174 |
}
|
|
|
15 |
height: 100%;
|
16 |
}
|
17 |
|
18 |
+
.playlist tbody tr {
|
19 |
+
cursor: pointer;
|
20 |
}
|
21 |
</style>
|
22 |
</head>
|
23 |
|
24 |
<body>
|
25 |
<div class="container my-4">
|
26 |
+
<h1 class="text-center">Convert Your Shazam Playlist to YouTube Playlist</h1>
|
27 |
+
<em class="text-center">
|
28 |
<i>
|
29 |
+
Read details at
|
30 |
+
<a href="https://toknow.ai/posts/shazam-playlist-to-youtube-playlist/"><b>ToKnow.ai</b> blog post</a>.
|
|
|
31 |
</i>
|
32 |
</em>
|
33 |
<p class="text-center">
|
|
|
59 |
const playlistTable = document.querySelector('.playlist');
|
60 |
const uploaForm = document.querySelector('.upload-form');
|
61 |
let songsPlaylist = []
|
62 |
+
let videoIndex = -1;
|
63 |
+
let youtubePlayer;
|
64 |
|
65 |
uploaForm.addEventListener('input', e => {
|
66 |
e.preventDefault();
|
|
|
87 |
}
|
88 |
})
|
89 |
}
|
90 |
+
function addErrorToCurrentIndex() {
|
91 |
+
playlistTable.querySelectorAll('tbody tr').forEach(row => {
|
92 |
+
if (Number(row.dataset.index) == videoIndex) {
|
93 |
+
row.classList.add('bg-danger');
|
94 |
+
}
|
95 |
+
})
|
96 |
+
}
|
97 |
async function getVideoId(song) {
|
98 |
const response = await fetch(
|
99 |
'/video_id',
|
|
|
105 |
return await response.text()
|
106 |
}
|
107 |
async function nextVideo(callback, newIndex = undefined) {
|
108 |
+
newIndex = newIndex >= 0 ? newIndex : (videoIndex + 1)
|
109 |
videoIndex = newIndex < songsPlaylist.length ? newIndex : 0;
|
110 |
let video_id = await getVideoId(songsPlaylist[videoIndex]);
|
111 |
callback(video_id);
|
|
|
123 |
<th>${i.Title}</th>
|
124 |
<th>${i.Artist}</th>
|
125 |
</tr>`
|
126 |
+
).join('')
|
127 |
playlistTable.innerHTML = `
|
128 |
<table class="table table-striped table-hover table-bordered rounded">
|
129 |
<thead>
|
|
|
139 |
playlistTable.innerHTML = error;
|
140 |
}
|
141 |
}
|
|
|
142 |
function onYouTubeIframeAPIReady() {
|
143 |
const youtubePlayerElement = document.querySelector('.youtube-player');
|
144 |
youtubePlayer = window.youtubePlayer = new YT.Player(youtubePlayerElement, {
|
|
|
154 |
onContinue(event?.target);
|
155 |
}
|
156 |
},
|
157 |
+
'onError': function (event) {
|
158 |
+
addErrorToCurrentIndex();
|
159 |
onContinue(event?.target);
|
160 |
}
|
161 |
}
|
|
|
168 |
}
|
169 |
}, 500);
|
170 |
};
|
|
|
171 |
function onContinue(player = undefined, newIndex = undefined) {
|
172 |
if (songsPlaylist.length > 0) {
|
173 |
nextVideo((value) => {
|
174 |
player = player || youtubePlayer
|
175 |
player.loadVideoById(value);
|
176 |
+
setTimeout(() => {
|
177 |
+
player.playVideo();
|
178 |
+
|
179 |
+
setTimeout(() => {
|
180 |
+
if (player.getPlayerState() != YT.PlayerState.PLAYING) {
|
181 |
+
player.playVideo();
|
182 |
+
}
|
183 |
+
}, 10);
|
184 |
+
}, 10);
|
185 |
}, newIndex);
|
186 |
}
|
187 |
}
|