Fix: Spotify OAuth RLS integration, profile mapping, and robust AI playlist generation bypass
This commit is contained in:
@@ -46,18 +46,39 @@ export default function NewTripScreen({ navigation }) {
|
||||
let generatedPlaylistUrl = null;
|
||||
|
||||
try {
|
||||
console.log("GENERATING_PLAYLIST_FOR_TRIP:", tripName);
|
||||
console.log("PLAYLIST_CREATE_START");
|
||||
|
||||
// Helper for robust parsing
|
||||
const safeParseJson = async (res: Response, label: string) => {
|
||||
const rawText = await res.text();
|
||||
console.log(`PLAYLIST_API_STATUS [${label}]:`, res.status);
|
||||
console.log(`PLAYLIST_API_CONTENT_TYPE [${label}]:`, res.headers.get("content-type"));
|
||||
console.log(`PLAYLIST_API_RAW_RESPONSE [${label}]:`, rawText.substring(0, 300) + (rawText.length > 300 ? "..." : ""));
|
||||
|
||||
try {
|
||||
return JSON.parse(rawText);
|
||||
} catch (e) {
|
||||
throw new Error(`Playlist API returned non-JSON response [${label}]: ${rawText}`);
|
||||
}
|
||||
};
|
||||
|
||||
// A. Get provider token
|
||||
const providerToken = await getSpotifyAccessToken();
|
||||
console.log("SPOTIFY_ACCESS_TOKEN_EXISTS:", !!providerToken);
|
||||
|
||||
if (!providerToken) {
|
||||
throw new Error("Spotify token missing. Please log in with Spotify again.");
|
||||
}
|
||||
|
||||
if (providerToken) {
|
||||
console.log("Spotify token missing, skipping playlist generation.");
|
||||
Alert.alert('Aviso', 'Spotify token missing, please login again');
|
||||
} else {
|
||||
// B. Fetch Spotify User ID
|
||||
const spotifyUserRes = await fetch('https://api.spotify.com/v1/me', {
|
||||
headers: { 'Authorization': `Bearer ${providerToken}` }
|
||||
headers: {
|
||||
'Authorization': `Bearer ${providerToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
const spotifyUserData = await spotifyUserRes.json();
|
||||
const spotifyUserData = await safeParseJson(spotifyUserRes, 'SpotifyUser');
|
||||
if (!spotifyUserData.id) throw new Error('Could not fetch Spotify User ID');
|
||||
const spotifyUserId = spotifyUserData.id;
|
||||
|
||||
@@ -71,8 +92,25 @@ export default function NewTripScreen({ navigation }) {
|
||||
stream: false
|
||||
})
|
||||
});
|
||||
const ollamaData = await ollamaRes.json();
|
||||
const seed_genres = ollamaData.message.content.trim().replace(/\s+/g, '').toLowerCase();
|
||||
|
||||
let seed_genres = "pop,road-trip,happy"; // Fallback genres
|
||||
try {
|
||||
const ollamaData = await safeParseJson(ollamaRes, 'Ollama');
|
||||
let rawAiText = ollamaData?.message?.content || "";
|
||||
|
||||
// Clean AI text
|
||||
rawAiText = rawAiText.replace(/```json/g, '').replace(/```/g, '').trim();
|
||||
|
||||
if (rawAiText.length > 0 && !rawAiText.toLowerCase().startsWith("a ")) {
|
||||
seed_genres = rawAiText.replace(/\s+/g, '').toLowerCase();
|
||||
// Spotify limits to 5 seed genres, let's keep it clean
|
||||
seed_genres = seed_genres.split(',').slice(0, 5).join(',');
|
||||
} else {
|
||||
console.log("AI returned plain text/error, using fallback genres:", rawAiText);
|
||||
}
|
||||
} catch (aiError) {
|
||||
console.log("AI parsing failed, using fallback genres.", aiError);
|
||||
}
|
||||
|
||||
// D. Create empty playlist
|
||||
const createPlaylistRes = await fetch(`https://api.spotify.com/v1/users/${spotifyUserId}/playlists`, {
|
||||
@@ -87,24 +125,45 @@ export default function NewTripScreen({ navigation }) {
|
||||
public: false
|
||||
})
|
||||
});
|
||||
const playlistData = await createPlaylistRes.json();
|
||||
const playlistData = await safeParseJson(createPlaylistRes, 'CreatePlaylist');
|
||||
if (!playlistData.id) throw new Error('Could not create playlist');
|
||||
const playlistId = playlistData.id;
|
||||
generatedPlaylistUrl = playlistData.external_urls.spotify;
|
||||
|
||||
// E. Fetch Spotify track recommendations
|
||||
// E. Fetch Spotify track recommendations via Search (does not require Premium)
|
||||
let accumulatedDurationMs = 0;
|
||||
let trackUris: string[] = [];
|
||||
let attempts = 0;
|
||||
const genresList = seed_genres.split(',');
|
||||
let genreIndex = 0;
|
||||
|
||||
while (accumulatedDurationMs < tripDurationMs && attempts < 10) {
|
||||
const recommendationsRes = await fetch(`https://api.spotify.com/v1/recommendations?seed_genres=${encodeURIComponent(seed_genres)}&limit=50`, {
|
||||
headers: { 'Authorization': `Bearer ${providerToken}` }
|
||||
const currentGenre = genresList[genreIndex % genresList.length] || 'pop';
|
||||
const query = encodeURIComponent(`genre:${currentGenre}`);
|
||||
const searchRes = await fetch(`https://api.spotify.com/v1/search?type=track&q=${query}&limit=50&offset=${attempts * 50}`, {
|
||||
headers: {
|
||||
'Authorization': `Bearer ${providerToken}`,
|
||||
'Content-Type': 'application/json'
|
||||
}
|
||||
});
|
||||
if (!recommendationsRes.ok) break;
|
||||
const recommendationsData = await recommendationsRes.json();
|
||||
if (!recommendationsData.tracks || recommendationsData.tracks.length === 0) break;
|
||||
|
||||
if (!searchRes.ok) {
|
||||
const errText = await searchRes.text();
|
||||
console.error("Search failed:", errText);
|
||||
Alert.alert('Erro Spotify', `Aviso ao adicionar músicas: ${errText.substring(0, 100)}`);
|
||||
break;
|
||||
}
|
||||
|
||||
const searchData = await safeParseJson(searchRes, 'SearchTracks');
|
||||
const tracks = searchData?.tracks?.items;
|
||||
|
||||
if (!tracks || tracks.length === 0) {
|
||||
genreIndex++;
|
||||
attempts++;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const track of recommendationsData.tracks) {
|
||||
for (const track of tracks) {
|
||||
if (!trackUris.includes(track.uri)) {
|
||||
trackUris.push(track.uri);
|
||||
accumulatedDurationMs += track.duration_ms;
|
||||
@@ -112,6 +171,7 @@ export default function NewTripScreen({ navigation }) {
|
||||
}
|
||||
}
|
||||
attempts++;
|
||||
genreIndex++;
|
||||
}
|
||||
|
||||
if (trackUris.length > 0) {
|
||||
@@ -128,16 +188,14 @@ export default function NewTripScreen({ navigation }) {
|
||||
body: JSON.stringify({ uris: chunk })
|
||||
});
|
||||
}
|
||||
console.log("PLAYLIST_CREATE_SUCCESS:", generatedPlaylistUrl);
|
||||
} else {
|
||||
console.error("No tracks found for genres:", seed_genres);
|
||||
}
|
||||
} else {
|
||||
console.error("Spotify token missing, skipping playlist generation.");
|
||||
Alert.alert('Aviso', 'Sessão Spotify não encontrada. A viagem será guardada sem playlist.');
|
||||
}
|
||||
} catch (playlistError) {
|
||||
console.error("Error generating playlist:", playlistError);
|
||||
Alert.alert('Erro Playlist', 'A viagem foi calculada, mas ocorreu um erro a criar a playlist.');
|
||||
} catch (playlistError: any) {
|
||||
console.warn("Expected failure generating playlist:", playlistError.message || playlistError);
|
||||
Alert.alert('Erro Playlist', `A viagem foi calculada, mas a playlist falhou: ${playlistError.message?.substring(0, 50) || 'Erro Desconhecido'}`);
|
||||
}
|
||||
|
||||
// G. Save to Supabase unconditionally if route is valid
|
||||
|
||||
Reference in New Issue
Block a user