Search in sources :

Example 1 with SpotifyRedirectIndex

use of net.robinfriedli.aiode.entities.SpotifyRedirectIndex in project aiode by robinfriedli.

the class SpotifyRedirectService method redirectTrack.

public void redirectTrack(HollowYouTubeVideo youTubeVideo) throws IOException {
    SpotifyTrack spotifyTrack = youTubeVideo.getRedirectedSpotifyTrack();
    if (spotifyTrack == null) {
        throw new IllegalArgumentException(youTubeVideo.toString() + " is not a placeholder for a redirected Spotify Track");
    }
    // early exit to avoid duplicate loading of Playables that have been loaded prioritised by invoking Playable#fetchNow
    if (youTubeVideo.isDone()) {
        return;
    }
    youTubeVideo.markLoading();
    String spotifyTrackId = spotifyTrack.getId();
    Optional<SpotifyRedirectIndex> persistedSpotifyRedirectIndex;
    if (!Strings.isNullOrEmpty(spotifyTrackId)) {
        persistedSpotifyRedirectIndex = queryExistingIndex(session, spotifyTrackId);
    } else {
        persistedSpotifyRedirectIndex = Optional.empty();
    }
    if (persistedSpotifyRedirectIndex.isPresent()) {
        SpotifyRedirectIndex spotifyRedirectIndex = persistedSpotifyRedirectIndex.get();
        YouTubeVideo video = youTubeService.getVideoForId(spotifyRedirectIndex.getYouTubeId());
        if (video != null) {
            try {
                youTubeVideo.setId(video.getVideoId());
                youTubeVideo.setDuration(video.getDuration());
            } catch (UnavailableResourceException e) {
                // never happens for YouTubeVideoImpl instances
                throw new RuntimeException(e);
            }
            youTubeVideo.setTitle(spotifyTrack.getDisplay());
            runUpdateTask(spotifyTrackId, (index, session) -> index.setLastUsed(LocalDate.now()));
            return;
        } else {
            runUpdateTask(spotifyTrackId, (index, session) -> session.delete(index));
        }
    }
    youTubeService.redirectSpotify(youTubeVideo);
    if (!youTubeVideo.isCanceled() && !Strings.isNullOrEmpty(spotifyTrack.getId())) {
        SINGE_THREAD_EXECUTOR_SERVICE.execute(() -> StaticSessionProvider.consumeSession(otherThreadSession -> {
            try {
                String videoId = youTubeVideo.getVideoId();
                SpotifyRedirectIndex spotifyRedirectIndex = new SpotifyRedirectIndex(spotifyTrack.getId(), videoId, spotifyTrack.getKind(), otherThreadSession);
                // check again if the index was not created by other thread
                if (queryExistingIndex(otherThreadSession, spotifyTrackId).isEmpty()) {
                    invoker.invoke(() -> otherThreadSession.persist(spotifyRedirectIndex));
                }
            } catch (UnavailableResourceException e) {
                logger.warn("Tried creating a SpotifyRedirectIndex for an unavailable Track");
            } catch (Exception e) {
                logger.error("Exception while creating SpotifyRedirectIndex", e);
            }
        }));
    }
}
Also used : Logger(org.slf4j.Logger) UnavailableResourceException(net.robinfriedli.aiode.exceptions.UnavailableResourceException) LoggerFactory(org.slf4j.LoggerFactory) Session(org.hibernate.Session) IOException(java.io.IOException) LoggingThreadFactory(net.robinfriedli.aiode.concurrent.LoggingThreadFactory) SpotifyRedirectIndex(net.robinfriedli.aiode.entities.SpotifyRedirectIndex) SpotifyRedirectIndexModificationLock(net.robinfriedli.aiode.entities.SpotifyRedirectIndexModificationLock) HibernateInvoker(net.robinfriedli.aiode.function.HibernateInvoker) Executors(java.util.concurrent.Executors) Aiode(net.robinfriedli.aiode.Aiode) Strings(com.google.common.base.Strings) HollowYouTubeVideo(net.robinfriedli.aiode.audio.youtube.HollowYouTubeVideo) LocalDate(java.time.LocalDate) BiConsumer(java.util.function.BiConsumer) Optional(java.util.Optional) YouTubeVideo(net.robinfriedli.aiode.audio.youtube.YouTubeVideo) StaticSessionProvider(net.robinfriedli.aiode.persist.StaticSessionProvider) ShutdownableExecutorService(net.robinfriedli.aiode.boot.ShutdownableExecutorService) ExecutorService(java.util.concurrent.ExecutorService) YouTubeService(net.robinfriedli.aiode.audio.youtube.YouTubeService) SpotifyRedirectIndex(net.robinfriedli.aiode.entities.SpotifyRedirectIndex) UnavailableResourceException(net.robinfriedli.aiode.exceptions.UnavailableResourceException) HollowYouTubeVideo(net.robinfriedli.aiode.audio.youtube.HollowYouTubeVideo) YouTubeVideo(net.robinfriedli.aiode.audio.youtube.YouTubeVideo) UnavailableResourceException(net.robinfriedli.aiode.exceptions.UnavailableResourceException) IOException(java.io.IOException)

Example 2 with SpotifyRedirectIndex

use of net.robinfriedli.aiode.entities.SpotifyRedirectIndex 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)

Aggregations

LocalDate (java.time.LocalDate)2 Aiode (net.robinfriedli.aiode.Aiode)2 YouTubeService (net.robinfriedli.aiode.audio.youtube.YouTubeService)2 SpotifyRedirectIndex (net.robinfriedli.aiode.entities.SpotifyRedirectIndex)2 SpotifyRedirectIndexModificationLock (net.robinfriedli.aiode.entities.SpotifyRedirectIndexModificationLock)2 Session (org.hibernate.Session)2 Stopwatch (com.google.common.base.Stopwatch)1 Strings (com.google.common.base.Strings)1 IOException (java.io.IOException)1 BigDecimal (java.math.BigDecimal)1 Optional (java.util.Optional)1 ExecutorService (java.util.concurrent.ExecutorService)1 Executors (java.util.concurrent.Executors)1 BiConsumer (java.util.function.BiConsumer)1 CriteriaBuilder (javax.persistence.criteria.CriteriaBuilder)1 SpotifyTrackBulkLoadingService (net.robinfriedli.aiode.audio.spotify.SpotifyTrackBulkLoadingService)1 SpotifyTrackKind (net.robinfriedli.aiode.audio.spotify.SpotifyTrackKind)1 HollowYouTubeVideo (net.robinfriedli.aiode.audio.youtube.HollowYouTubeVideo)1 YouTubeVideo (net.robinfriedli.aiode.audio.youtube.YouTubeVideo)1 ShutdownableExecutorService (net.robinfriedli.aiode.boot.ShutdownableExecutorService)1