Giter VIP home page Giter VIP logo

goofy's Introduction

Конструктор плейлистов Spotify. Сбор треков, фильтр, обновление по событиям. Бесплатно.

Выполните установку и создайте свой первый плейлист.

Чат

Возможности

  • отслеживает историю прослушиваний
  • повторяет функции Smarter Playlists и Playlist Miner
  • имеет большой набор фильтров
  • собирает рекомендации и новые релизы, включая Every Noise
  • импортирует FM-радио и Last.fm
  • поддерживает расширенный поиск
  • позволяет динамически менять очередь треков
  • работает по расписанию и событиям Tasker

goofy's People

Contributors

chimildic avatar vlalog avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

goofy's Issues

Troubleshooting help - Error 500

Every script I run for the last few weeks (possibly longer) gives the following error:

` Number: 500
Address: https://api.spotify.com/v1/me/tracks?offset=8000&limit=50&locale=AU
Response text: {
"error" : {
"status" : 500,
"message" : "Server error."
}
}

Description and resolution of errors: https://chimildic.github.io/goofy/#/errors`

The offset number changes after every attempt, my preliminaey investigating leads me to believe that this is an issue with my user token.

image

I'm not sure what steps to take to resolve this issue, could someone please point me in the right direction?

Сбор новых релизов

Описание

Создать публичную функцию по сбору новых релизов через расширенный поиск Spotify

Цель

  • Позволить собрать новые релизы при излишне большом количестве исполнителей (при малом периоде времени)
  • Уменьшить время выполнения по сравнению с аналогичным решением прямого перебора

Ограничение

  • Не использовать перебор всех доступных альбомов исполнителя

Вопрос

  • Расширенный поиск Spotify умеет искать по полной дате? (Нет)

Документация

Я бы вынес доки (Readme.md) в отдельный сайт (chimildic.github.io/goofy).

Это не должно вызвать проблем, учитывая, что вся документация уже в .md. Нужно только выбрать шаблон, и разделить доки под него.

Однако, если Вам все же понадобится помощь, Вы можете связаться со мной здесь, или с помощью контактов, указанных на vlalog.com

Goofy и Shazam

Есть такая хотелка... Оставлю здесь, получится или нет.
Создать функцию по получению списков треков из Shazam:

  • Discovery
  • Топы по жанрам

Задачи для сайта и форума

Сайт

  • Разделить документацию функций на отдельные страницы (частично готово)
  • Описать настройку goofy для нескольких аккаунтов Spotify на одном аккаунте Google
  • Актуализировать шаблоны
  • Проверить актуальность описания ограничений

Форум

  • Добавить шаг публикации для избежания частой авторизации #124

Отключение триггера по неизвестной причине

Описание

Системный триггер для функции runTasks_ может быть отключен платформой Apps Script по неизвестной причине.
В трекере ошибок периодически пишут о такой проблеме для триггеров, создаваемых из кода. Как такого решения не найдено.

Цель

  • Добавить пересоздание триггера, если он отключен

Заметки

  • У объекта триггера есть функция isDisabled

Ошибка Filter.rangeTracks

Ещё одна ошибка с фильтром Filter.rangeTracks (без фильтра функция работает).
Файл прилагаю:
rus.zip

  let tracks = Cache.read('rus.json');

  Filter.rangeTracks(tracks, {
    album: {
      release_date: { startDate: new Date('2022.01.01'), endDate: new Date('2022.12.31') },
    }
  });

  Playlist.saveWithReplace({
    name: 'testt',
    public: false,
    tracks: Selector.sliceRandom(tracks, 10),
  });

 Лог:
14:03:19	Примечание	Выполнение начато
14:03:32	Информация	Операция продолжится после паузы 2с.
14:03:39	Информация	Операция продолжится после паузы 4с.
14:03:50	Информация	Операция продолжится после паузы 11с.
14:04:18	Информация	Операция продолжится после паузы 14с.
14:04:50	Информация	Операция продолжится после паузы 13с.
14:05:12	Ошибка	
TypeError: Cannot read property 'id' of null
(функция без названия)	@ library.gs:2878
cacheToFullObj	@ library.gs:2878
cache	@ library.gs:2836
getCache	@ library.gs:2827
rangeTracks	@ library.gs:1003
myTestFunction	@ Без названия.gs:5

_Originally posted by @Bondian in https://github.com/Chimildic/goofy/discussions/168#discussioncomment-2565624_

ReferenceError: tracks is not defined (строка 1646, файл Library)

Исполняемый код:

function BigDailyMix() {
    let banTracks = Source.getPlaylistTracks('Banned', '2w4kXoYT1mmymY2dUHH1mR');
    let savedTracks = Source.getSavedTracks();
    Combiner.push(banTracks, savedTracks);

    let onlyForYouTracks = Source.getTracks([
        { name: 'Микс дня 1', id: '37i9dQZF1E35Rw9lXJezmd' },
        { name: 'Микс дня 2', id: '37i9dQZF1E38UFtVDcIo9c' },
        { name: 'Микс дня 3', id: '37i9dQZF1E3adpvqEe1FTy' },
        { name: 'Микс дня 4', id: '37i9dQZF1E38oJAmh1ZdKu' },
        { name: 'Микс дня 5', id: '37i9dQZF1E38bS1WqtspJi' },
        { name: 'Микс дня 6', id: '37i9dQZF1E380MTxhVBAq4' },
        { name: 'Радар новинок', id: '37i9dQZEVXbhGiCpjS9KHh' },
        { name: 'Открытия недели', id: '37i9dQZEVXcRrEFL8wsRER' },
    ]);
    
    Filter.dedupTracks(onlyForYouTracks);
    Filter.dedupArtists(onlyForYouTracks);
    Filter.removeTracks(onlyForYouTracks, banTracks);
    Filter.matchOriginalOnly(onlyForYouTracks);
    Filter.matchExceptRu(onlyForYouTracks);
    
    let updDate = new Date();
    let tracks = onlyForYouTracks;
    onlyForYouTracks = Order.sort(tracks, 'features.energy', 'desc');
      
    Playlist.saveWithReplace({
        id: '4Ystjry0PxwofnJiKaeVkp',
        name: "[vlalog's tech] daily mix",
        tracks: onlyForYouTracks,
        description: Playlist.getDescription(onlyForYouTracks) + '. Updated at ' + updDate,
        randomCover: 'update',
    });
}

Версия из этого коммита

Order.separateArtists does not preserve the track ordering

I have been using Order.separateArtists in a few programs, and did not notice this issue until now, That is because I did not examine the results. What I have found is that the function has unexpected results regarding the tracks ordering. I was expecting the first instance of a track by an artist to remain at the same place (or higher if other tracks were moved previously). This is not the case at all. In fact it seems the processing starts from the end of the tracklist, and has the side effect of causing the first instances to be removed if seperation cannot be achieved (as expected). Maybe it is even more unexpected than this, with what seems like randonmess thrown in (or maybe some processing goes one way, while other goes the other way).

For example: I am trying to produce a tracklist keeping only the most popular tracks, with only the most popular track of each artist. This is what I get without artist separation:

// popularity reverse sort (most popular first)
// keep first 10
	77: Aventura : Obsesion
	76: Aventura : Dile al Amor
	78: Romeo Santos : Eres Mía
	76: Romeo Santos : Sobredosis (feat. Ozuna)
	75: Romeo Santos : Odio (feat. Drake)
	75: Romeo Santos : Necio (feat. Carlos Santana)
	74: Romeo Santos : El Pañuelo
	74: Aventura : El Perdedor
	74: Natti Natasha : La Mejor Versión de Mi - Remix
	73: Prince Royce : Darte un Beso

(first column is popularity, second artist name, third track name)
As you can see, the source has many artist duplicates, which I need to remove. The easiest way to do it should be to apply artist separation, preserving the order, with a separation space of the desired size. This is what it produces:

// popularity reverse sort (most popular first)
// artist separation
// keep first 10
	0: Kiko Rodriguez : Ya Te Olvide
	0: Daniel Santacruz : Se Busca un Corazon
	0: Juan Manuel : Si Me Dejas No Vale
	0: Kewin Cosmos : Solo Quise Quererte
	0: Allendi : Te Mal Informaron (HD Digital Remastered)
	0: Manny Jhovanny : Lagrima de Amor
	0: Juan Luis Guerra y 440 : Burbujas de Amor
	0: Jhonny Evidence : Hoy Te Vas
	0: Prince Royce : Culpa al Corazón
	0: Luis Vargas : Loco De Amor

Those are actually the least popular tracks!

Reversing the processing improves results but is not quite right:

// popularity sort (least popular first)
// artist separation
// keep last 10
// popularity reverse sort (most popular first)
	75: Romeo Santos : Odio (feat. Drake)
	74: Natti Natasha : La Mejor Versión de Mi - Remix
	66: Ozuna : Señor Juez
	62: Aventura : Ciego De Amor - Featuring Anthony Santos
	53: C. Tangana : Bobo
	51: Christian Daniel : Ahora Que Te Vas (Versión Bachata)
	49: Johnny Sky : En Todo Fuiste la Mejor
	47: Chavi Leons : Otra Vez
	43: DJ Khalid : Perfecta - Bachata Version
	11: Joan Soriano : La Mamandela

Compared to the first result, you can see that the Romeo Santos and Aventura tracks are not the most popular. If I request more than 10 results, I can also see other tracks from other artists have disappeared altogether.

I think this is an incorrect logic in the separateArtists function. I wrote a similar function in Python a while ago, and I think it was doing it in the correct order. I will try to dig it up and see if I can help fix the code.

For reference, here is code I used to produce those results:

function zipdjClassicTracks() {

  let sourcePlaylist    = '7eufyawBpqQMvsIN4fgQB1'; // Bachata
  // let sourcePlaylist   = '7htbYn8f0q01n5br4XhQR9'; // Cumbia
  // let sourcePlaylist   = '3Bsz7QecNExg8bsDdW4iGW'; // Merengue
  // let sourcePlaylist   = 'playlist:0o2GXyncPfGLmGSiOqSINx'; // Salsa

  let numTracks         = 20;
  let archivePlaylist   = '1BQCyWrAkSLiDsra9TZgn8'; // [zipdj] all songs
  let targetPlaylist    = '1uLOtPdWnESn9zbgzzZDlh'; // [zipdj] workbench
  let targetName        = '[zipdj] workbench';

  // Load tracks already published on zipdj
  let publishedTracks = Source.getPlaylistTracks('', archivePlaylist);

  // Load tracks from source playlist
  let tracks = Source.getPlaylistTracks('', sourcePlaylist);

  // Remove published tracks from source playlist
  Filter.removeTracks(tracks, publishedTracks);

  // Sort tracks by decreasing popularity
  tracks.sort((a, b) => b.popularity - a.popularity);

  // Separate artists by the number of tracks to publish, to ensure artist uniqueness
  Order.separateArtists(tracks, numTracks, false);

  // Keep only the number of tracks desired
  Selector.keepFirst(tracks, numTracks);
  
  // DEBUG LOG
  for (let i = 0; i < tracks.length; i++) {
    Logger.log(tracks[i].popularity + ': ' + tracks[i].artists[0].name + ' : ' + tracks[i].name );
  };

  // Save tracks to workbench playlist, appending to the existing ones
  Playlist.saveWithAppend({
    name: targetName,
    id: targetPlaylist,
    tracks: tracks,
    public: false
  });

}

Кэширование любимых треков

Описание

Создать механизм накопления любимых треков на Google Диске

Цель

  • Уменьшить количество затрачиваемых запросов
  • Ускорить время выполнения (при большом количестве треков)

Ограничение

  • Сохранить расположение и внешнее поведение Source.getSavedTracks
  • Не создавать новую публичную функцию для чтения файла
  • Не занимать новый триггер

Заметки

  • Как часто обновлять файл из под триггера? (Раз в сутки)
  • Как совместить актуальность списка и не увеличить время выполнения из-за работы с Cache? (Тесты с console.time)
  • Попробовать выделить управляющий модуль, который будет читать и обновлять кэш по запросу за счет передачи способа получения новых элементов.

TypeError: Cannot read property 'length' of undefined

Возникает при попытке получить треки из плейлиста, найденного только по имени

TypeError: Cannot read property 'length' of undefined
    at [unknown function](Library:887:23)
    at push(Library:886:25)
    at [unknown function](Library:320:29)
    at getTrackItems(Library:313:30)
    at getTracks(Library:309:30)
    at getTracksByPlaylistName(actions:2:25)

В объекте с данными по плейлисту, tracks не содержит свойства items, которое требуется в Source.getItemsByPlaylistObject()
изображение

TypeError: Cannot read property 'id' of null (строка 1395, файл Library)

При выполнении скрипта, словил ошибку:
TypeError: Cannot read property 'id' of null
at unknown function
at cacheToFullObj(Library:1382:22)
at cache(Library:1352:9)
at getCache(Library:1343:9)
at rangeTracks(Library:596:29)
at createMySlowFlow(Main:113:10)

При выполнении скрипта без фрагмента кода фильтрации по энергии трека всё работает:

  Filter.rangeTracks(Flow, {
    features: {
        energy: { min: 0.0, max: 0.5 },
    }
  });

Сам скрипт:

function createMySlowFlow() {
  let Flow = Source.getTracks([
    { name: 'Jam', id: '123'}
    ]);
  let SavedTracks = Source.getSavedTracks();
  let BigMix = Source.getTracks([
    { name: 'BigMix by Goofy', id: '123'}
    ]);
  let RsntHistoryTracks = Source.getTracks([
    { name: 'History by Goofy', id: '123'}
    ]);
  let Ban = Source.getTracks([
    { name: 'Ban', id: '123'}
    ]);
//Flow
  Filter.removeTracks(Flow, SavedTracks);
  Filter.removeTracks(Flow, RsntHistoryTracks);
  Filter.removeArtists(Flow, Ban);
  Filter.rangeTracks(Flow, {
    features: {
        energy: { min: 0.0, max: 0.5 },
    }
  });
  Filter.dedupArtists(Flow);
  Selector.keepRandom(Flow, 100);
  Order.shuffle(Flow);
  console.log('Количество треков Flow', Flow.length);
//BigMix  
  Filter.removeTracks(BigMix, Flow);
  Filter.rangeTracks(BigMix, {
    features: {
        energy: { min: 0.0, max: 0.5 },
    }
  });  
  Filter.dedupArtists(BigMix);
  Selector.keepRandom(BigMix, 100);
  Order.shuffle(BigMix);
  console.log('Количество треков BigMix', BigMix.length);
//BigMix+Flow
  let BigMixFlow = Combiner.mixin(Flow, BigMix, 1, 1, true);
//+MySave  
  Filter.removeTracks(SavedTracks, RsntHistoryTracks);
  Order.shuffle(SavedTracks);
  Filter.rangeTracks(SavedTracks, {
    features: {
        energy: { min: 0.0, max: 0.5 },
    }
  });
  Filter.dedupArtists(SavedTracks);
  Selector.keepRandom(SavedTracks, 100)
  console.log('Количество треков MySave', SavedTracks.length);
//BigMixFlow+MySave
  let BigMixFlowSave = Combiner.mixin(BigMixFlow, SavedTracks, 1, 1, true);
 
  let UpdTime = new Date();
   Playlist.saveWithReplace({
    id: '123',
    name: 'My Slow Flow by Goofy',
    description: UpdTime,
    tracks: BigMixFlowSave,
  });
  console.log('Число запросов', Request.getCountRequest());
}


Изменение порядка локальных файлов в плейлисте

Порядок локальных файлов можно менять в плейлисте при помощи Spotify API. Можно ли это сделать через Goofy? В идеале получить список всех треков в плейлисте, включая локальные, поменять порядок, и сохранить. Логично было бы использовать для этого Playlist.saveWithUpdate, но как получить список локальных файлов через Goofy мне непонятно

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.