Search in sources :

Example 1 with SpotifyTrackKind

use of net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind in project aiode by robinfriedli.

the class Playlist method asTrackList.

/**
 * returns all Songs as Spotify tracks including all videos that are redirected Spotify tracks i.e. the attribute
 * redirectedSpotifyId is set. Mind that this method has to be invoked with client credentials
 */
public List<SpotifyTrack> asTrackList(SpotifyApi spotifyApi) {
    SpotifyTrackBulkLoadingService service = new SpotifyTrackBulkLoadingService(spotifyApi);
    List<SpotifyTrack> tracks = Lists.newArrayList();
    for (PlaylistItem item : getItemsSorted()) {
        if (item instanceof Song) {
            String id = ((Song) item).getId();
            service.add(createItem(id, TRACK), tracks::add);
        } else if (item instanceof Episode) {
            String id = ((Episode) item).getId();
            service.add(createItem(id, EPISODE), tracks::add);
        } else if (item instanceof Video && ((Video) item).getRedirectedSpotifyId() != null) {
            Video video = (Video) item;
            String redirectedSpotifyId = video.getRedirectedSpotifyId();
            SpotifyItemKind kindEntity = video.getRedirectedSpotifyKind();
            SpotifyTrackKind kind = kindEntity != null ? kindEntity.asEnum() : TRACK;
            service.add(createItem(redirectedSpotifyId, kind), tracks::add);
        }
    }
    service.perform();
    return tracks;
}
Also used : SpotifyTrackBulkLoadingService(net.robinfriedli.aiode.audio.spotify.SpotifyTrackBulkLoadingService) SpotifyTrack(net.robinfriedli.aiode.audio.spotify.SpotifyTrack) YouTubeVideo(net.robinfriedli.aiode.audio.youtube.YouTubeVideo) SpotifyTrackKind(net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind)

Example 2 with SpotifyTrackKind

use of net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind in project aiode by robinfriedli.

the class Playlist method getTracks.

/**
 * Returns the items in this playlist as objects supported by the {@link PlayableFactory} class. Note that getting the
 * Spotify track for a Song requires this method to be invoked with client credentials
 */
public List<Object> getTracks(SpotifyApi spotifyApi) {
    List<PlaylistItem> playlistItems = getItemsSorted();
    SpotifyTrackBulkLoadingService service = new SpotifyTrackBulkLoadingService(spotifyApi);
    Map<Object, Integer> itemsWithIndex = new HashMap<>();
    for (int i = 0; i < playlistItems.size(); i++) {
        PlaylistItem item = playlistItems.get(i);
        if (item instanceof Song) {
            String id = ((Song) item).getId();
            int finalI = i;
            service.add(createItem(id, TRACK), track -> itemsWithIndex.put(track, finalI));
        } else if (item instanceof Episode) {
            String id = ((Episode) item).getId();
            int finalI = i;
            service.add(createItem(id, EPISODE), track -> itemsWithIndex.put(track, finalI));
        } else if (item instanceof Video) {
            Video video = (Video) item;
            YouTubeVideo youtubeVideo = video.asYouTubeVideo();
            itemsWithIndex.put(youtubeVideo, i);
            String spotifyId = video.getRedirectedSpotifyId();
            if (!Strings.isNullOrEmpty(spotifyId)) {
                SpotifyItemKind kindEntity = video.getRedirectedSpotifyKind();
                SpotifyTrackKind kind = kindEntity != null ? kindEntity.asEnum() : TRACK;
                service.add(createItem(spotifyId, kind), youtubeVideo::setRedirectedSpotifyTrack);
            }
        } else if (item instanceof UrlTrack) {
            itemsWithIndex.put(item, i);
        }
    }
    service.perform();
    return itemsWithIndex.keySet().stream().sorted(Comparator.comparing(itemsWithIndex::get)).collect(Collectors.toList());
}
Also used : Size(javax.validation.constraints.Size) PlayableFactory(net.robinfriedli.aiode.audio.PlayableFactory) SpotifyTrack(net.robinfriedli.aiode.audio.spotify.SpotifyTrack) HashMap(java.util.HashMap) User(net.dv8tion.jda.api.entities.User) Strings(com.google.common.base.Strings) Table(javax.persistence.Table) Lists(com.google.common.collect.Lists) Guild(net.dv8tion.jda.api.entities.Guild) Map(java.util.Map) YouTubeVideo(net.robinfriedli.aiode.audio.youtube.YouTubeVideo) Id(javax.persistence.Id) Entity(javax.persistence.Entity) Collection(java.util.Collection) OneToMany(javax.persistence.OneToMany) Set(java.util.Set) Collectors(java.util.stream.Collectors) SpotifyTrackKind(net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind) SpotifyTrackBulkLoadingService(net.robinfriedli.aiode.audio.spotify.SpotifyTrackBulkLoadingService) Serializable(java.io.Serializable) Objects(java.util.Objects) SpotifyApi(se.michaelthelin.spotify.SpotifyApi) Column(javax.persistence.Column) GenerationType(javax.persistence.GenerationType) List(java.util.List) Stream(java.util.stream.Stream) GeneratedValue(javax.persistence.GeneratedValue) SpringPropertiesConfig(net.robinfriedli.aiode.boot.SpringPropertiesConfig) Comparator(java.util.Comparator) Sets(com.google.api.client.util.Sets) HashMap(java.util.HashMap) SpotifyTrackBulkLoadingService(net.robinfriedli.aiode.audio.spotify.SpotifyTrackBulkLoadingService) YouTubeVideo(net.robinfriedli.aiode.audio.youtube.YouTubeVideo) SpotifyTrackKind(net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind) YouTubeVideo(net.robinfriedli.aiode.audio.youtube.YouTubeVideo)

Example 3 with SpotifyTrackKind

use of net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind in project aiode by robinfriedli.

the class ChartsCommand method getTrackForRecord.

private Playable getTrackForRecord(Object[] record, Session session) throws Exception {
    long sourceEntityPk = (Long) record[0];
    PlaybackHistorySource sourceEntity = session.load(PlaybackHistorySource.class, sourceEntityPk);
    Playable.Source source = sourceEntity.asEnum();
    String id = (String) record[1];
    Long spotifyItemKindPk = (Long) record[3];
    SpotifyItemKind spotifyItemKind = spotifyItemKindPk != null ? session.load(SpotifyItemKind.class, spotifyItemKindPk) : null;
    switch(source) {
        case SPOTIFY:
            return runWithCredentials(() -> {
                if (spotifyItemKind == null) {
                    throw new IllegalStateException("spotifyItemKind cannot be null for PlaybackHistory entries of source SPOTIFY");
                }
                SpotifyTrackKind kind = spotifyItemKind.asEnum();
                SpotifyService spotifyService = getSpotifyService();
                SpotifyTrack track = kind.loadSingleItem(spotifyService, id);
                if (track == null) {
                    return null;
                }
                return new PlayableTrackWrapper(track);
            });
        case YOUTUBE:
            YouTubeService youTubeService = Aiode.get().getAudioManager().getYouTubeService();
            try {
                return youTubeService.getVideoForId(id);
            } catch (FriendlyException e) {
                return null;
            }
        case URL:
            return playableFactory.createPlayable(id, getContext().getSpotifyApi(), false);
    }
    throw new UnsupportedOperationException("Unsupported source " + sourceEntity);
}
Also used : SpotifyItemKind(net.robinfriedli.aiode.entities.SpotifyItemKind) SpotifyService(net.robinfriedli.aiode.audio.spotify.SpotifyService) YouTubeService(net.robinfriedli.aiode.audio.youtube.YouTubeService) FriendlyException(com.sedmelluq.discord.lavaplayer.tools.FriendlyException) PlayableTrackWrapper(net.robinfriedli.aiode.audio.spotify.PlayableTrackWrapper) Playable(net.robinfriedli.aiode.audio.Playable) SpotifyTrackKind(net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind) SpotifyTrack(net.robinfriedli.aiode.audio.spotify.SpotifyTrack) PlaybackHistorySource(net.robinfriedli.aiode.entities.PlaybackHistorySource)

Example 4 with SpotifyTrackKind

use of net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind in project aiode by robinfriedli.

the class RefreshSpotifyRedirectIndicesTask method run.

@Override
protected void run(JobExecutionContext jobExecutionContext) {
    logger.info("Starting SpotifyRedirectIndex refresh");
    SessionFactory sessionFactory = StaticSessionProvider.getSessionFactory();
    SpotifyRedirectIndexModificationLock spotifyRedirectIndexModificationLock = new SpotifyRedirectIndexModificationLock();
    spotifyRedirectIndexModificationLock.setCreationTimeStamp(LocalDateTime.now());
    try (Session session = sessionFactory.openSession()) {
        Transaction transaction = session.beginTransaction();
        session.persist(spotifyRedirectIndexModificationLock);
        transaction.commit();
    }
    try {
        Aiode aiode = Aiode.get();
        Stopwatch stopwatch = Stopwatch.createStarted();
        YouTubeService youTubeService = aiode.getAudioManager().getYouTubeService();
        SpotifyTrackBulkLoadingService spotifyTrackBulkLoadingService = new SpotifyTrackBulkLoadingService(spotifyApi, true);
        LocalDate currentDate = LocalDate.now();
        LocalDate date4WeeksAgo = currentDate.minusDays(28);
        StaticSessionProvider.consumeSession(session -> {
            CriteriaBuilder cb = session.getCriteriaBuilder();
            CriteriaQuery<SpotifyRedirectIndex> query = cb.createQuery(SpotifyRedirectIndex.class);
            Root<SpotifyRedirectIndex> root = query.from(SpotifyRedirectIndex.class);
            query.where(cb.lessThan(root.get("lastUpdated"), date4WeeksAgo));
            query.orderBy(cb.asc(root.get("lastUpdated")));
            List<SpotifyRedirectIndex> indices = session.createQuery(query).setLockOptions(new LockOptions(LockMode.PESSIMISTIC_WRITE)).getResultList();
            if (indices.isEmpty()) {
                return;
            }
            BigDecimal averageDailyIndices = (BigDecimal) session.createSQLQuery("select avg(count) from (select count(*) as count from spotify_redirect_index group by last_updated) as sub").uniqueResult();
            int average = averageDailyIndices.setScale(0, RoundingMode.CEILING).intValue();
            int updateCount = 0;
            for (SpotifyRedirectIndex index : indices) {
                SpotifyTrackKind kind = index.getSpotifyItemKind().asEnum();
                RefreshTrackIndexTask task = new RefreshTrackIndexTask(session, index, youTubeService);
                String spotifyId = index.getSpotifyId();
                if (!Strings.isNullOrEmpty(spotifyId)) {
                    spotifyTrackBulkLoadingService.add(createItem(spotifyId, kind), task);
                } else {
                    session.delete(index);
                }
                ++updateCount;
                if (updateCount == average) {
                    break;
                }
            }
            spotifyTrackBulkLoadingService.perform();
            stopwatch.stop();
            logger.info(String.format("Regenerated %d spotify redirect indices in %d seconds", updateCount, stopwatch.elapsed(TimeUnit.SECONDS)));
        });
    } finally {
        Transaction transaction = null;
        try (Session session = sessionFactory.openSession()) {
            transaction = session.beginTransaction();
            // since hibernate is now bootstrapped by JPA rather than native after implementing spring boot
            // the entity has the be merged because JPA does not allow the deletion of detached entities
            Object merge = session.merge(spotifyRedirectIndexModificationLock);
            session.delete(merge);
            transaction.commit();
        } catch (Throwable e) {
            // catch exceptions thrown in the finally block so as to not override exceptions thrown in the try block
            logger.error("Exception thrown while deleting SpotifyRedirectIndexModificationLock", e);
            if (transaction != null) {
                transaction.rollback();
            }
        }
    }
}
Also used : SessionFactory(org.hibernate.SessionFactory) CriteriaBuilder(javax.persistence.criteria.CriteriaBuilder) LockOptions(org.hibernate.LockOptions) SpotifyRedirectIndex(net.robinfriedli.aiode.entities.SpotifyRedirectIndex) Stopwatch(com.google.common.base.Stopwatch) SpotifyRedirectIndexModificationLock(net.robinfriedli.aiode.entities.SpotifyRedirectIndexModificationLock) Aiode(net.robinfriedli.aiode.Aiode) LocalDate(java.time.LocalDate) YouTubeService(net.robinfriedli.aiode.audio.youtube.YouTubeService) BigDecimal(java.math.BigDecimal) Transaction(org.hibernate.Transaction) SpotifyTrackBulkLoadingService(net.robinfriedli.aiode.audio.spotify.SpotifyTrackBulkLoadingService) SpotifyTrackKind(net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind) Session(org.hibernate.Session)

Example 5 with SpotifyTrackKind

use of net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind in project aiode by robinfriedli.

the class PlayableFactory method createPlayable.

/**
 * Create a single playable for any url. If the url is either an open.spotify or YouTube URL this extracts the ID
 * and uses the familiar methods to load the Playables, otherwise this method uses the {@link AudioTrackLoader}
 * to load the {@link AudioTrack}s using lavaplayer and wraps them in {@link UrlPlayable}s
 */
@Nullable
public Playable createPlayable(String url, SpotifyApi spotifyApi, boolean redirectSpotify) throws IOException {
    URI uri;
    try {
        uri = URI.create(url);
    } catch (IllegalArgumentException e) {
        throw new InvalidCommandException("'" + url + "' is not a valid URL");
    }
    if (uri.getHost().contains("youtube.com")) {
        Map<String, String> parameterMap = getParameterMap(uri);
        String videoId = parameterMap.get("v");
        if (videoId != null) {
            return youTubeService.getVideoForId(videoId);
        } else {
            throw new IllegalArgumentException("Detected YouTube URL but no video id provided");
        }
    } else if (uri.getHost().equals("youtu.be")) {
        String[] parts = uri.getPath().split("/");
        return youTubeService.requireVideoForId(parts[parts.length - 1]);
    } else if (uri.getHost().equals("open.spotify.com")) {
        StringList pathFragments = StringList.createWithRegex(uri.getPath(), "/");
        SpotifyTrackKind kind;
        String trackId;
        if (pathFragments.contains("track")) {
            trackId = pathFragments.tryGet(pathFragments.indexOf("track") + 1);
            kind = SpotifyTrackKind.TRACK;
        } else if (pathFragments.contains("episode")) {
            trackId = pathFragments.tryGet(pathFragments.indexOf("episode") + 1);
            kind = SpotifyTrackKind.EPISODE;
        } else {
            throw new IllegalArgumentException("Detected Spotify URL but no track id provided");
        }
        if (trackId == null) {
            throw new InvalidCommandException("No track id provided");
        }
        try {
            String accessToken = spotifyApi.clientCredentials().build().execute().getAccessToken();
            spotifyApi.setAccessToken(accessToken);
            if (kind == SpotifyTrackKind.TRACK) {
                Track track = spotifyService.getTrack(trackId);
                return createPlayable(redirectSpotify, track);
            } else // noinspection ConstantConditions
            if (kind == SpotifyTrackKind.EPISODE) {
                Episode episode = spotifyService.getEpisode(trackId);
                return createPlayable(redirectSpotify, episode);
            } else {
                throw new UnsupportedOperationException("unsupported open.spotify URL kind: " + kind);
            }
        } catch (IOException | SpotifyWebApiException | ParseException e) {
            throw new RuntimeException("Exception during Spotify request", e);
        } finally {
            spotifyApi.setAccessToken(null);
        }
    } else {
        AudioItem audioItem = audioTrackLoader.loadByIdentifier(uri.toString());
        if (audioItem instanceof AudioTrack) {
            return new UrlPlayable((AudioTrack) audioItem);
        } else if (audioItem != null) {
            throw new IllegalArgumentException("Loading provided url did not result in an AudioTrack but " + audioItem.getClass().toString());
        } else {
            return null;
        }
    }
}
Also used : StringList(net.robinfriedli.stringlist.StringList) IOException(java.io.IOException) URI(java.net.URI) AudioItem(com.sedmelluq.discord.lavaplayer.track.AudioItem) SpotifyWebApiException(se.michaelthelin.spotify.exceptions.SpotifyWebApiException) Episode(se.michaelthelin.spotify.model_objects.specification.Episode) InvalidCommandException(net.robinfriedli.aiode.exceptions.InvalidCommandException) SpotifyTrackKind(net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind) AudioTrack(com.sedmelluq.discord.lavaplayer.track.AudioTrack) ParseException(org.apache.hc.core5.http.ParseException) SpotifyTrack(net.robinfriedli.aiode.audio.spotify.SpotifyTrack) Track(se.michaelthelin.spotify.model_objects.specification.Track) AudioTrack(com.sedmelluq.discord.lavaplayer.track.AudioTrack) UrlTrack(net.robinfriedli.aiode.entities.UrlTrack) Nullable(javax.annotation.Nullable)

Aggregations

SpotifyTrackKind (net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind)5 SpotifyTrack (net.robinfriedli.aiode.audio.spotify.SpotifyTrack)4 SpotifyTrackBulkLoadingService (net.robinfriedli.aiode.audio.spotify.SpotifyTrackBulkLoadingService)3 YouTubeService (net.robinfriedli.aiode.audio.youtube.YouTubeService)2 YouTubeVideo (net.robinfriedli.aiode.audio.youtube.YouTubeVideo)2 Sets (com.google.api.client.util.Sets)1 Stopwatch (com.google.common.base.Stopwatch)1 Strings (com.google.common.base.Strings)1 Lists (com.google.common.collect.Lists)1 FriendlyException (com.sedmelluq.discord.lavaplayer.tools.FriendlyException)1 AudioItem (com.sedmelluq.discord.lavaplayer.track.AudioItem)1 AudioTrack (com.sedmelluq.discord.lavaplayer.track.AudioTrack)1 IOException (java.io.IOException)1 Serializable (java.io.Serializable)1 BigDecimal (java.math.BigDecimal)1 URI (java.net.URI)1 LocalDate (java.time.LocalDate)1 Collection (java.util.Collection)1 Comparator (java.util.Comparator)1 HashMap (java.util.HashMap)1