ciricc / easyvk

This app helps you create an apps with vk api easy!
MIT License
101 stars 10 forks source link

Ещё пачка методов к AudioAPI #12

Closed PurpleHorrorRus closed 4 years ago

PurpleHorrorRus commented 5 years ago

Знаю, ты не успел добавить ещё все предыдущие, но я тут ещё кое-чего наделал. Качество кода, как обычно, оставляет желать лучшего, хех Ну, по порядку. Для начала я загрузил и воспользовался node-html-parser для парса HTML. Может быть можно как-то это сделать другим способом во избежание различных проблем, но по крайней мере это работает.

var HTMLParser = require('../../../node-html-parser');

Самое интересное - плейлисты из вкладки "рекомендации". Там где рэп, рок, поп, подборки и прочее. Они получаются с помощью оффсетов, кратным 4. В моём случае: 0 - новые альбомы, 4 - рэп, рок, поп, 8 - музыка под настроение, 12 - выбор редакции и музыкальные подборки.

async getRecomsPlaylistsByOffset (params = {}) {
    String.prototype.replaceAll = function(search, replace){
      return this.split(search).join(replace);
    }
    let self = this;
    let res = await self._request({
      act: "recoms_blocks",
      al: 1,
      offset: params.offset
    });
    res.body = encoding.convert(res.body, 'utf-8', 'windows-1251').toString()
    res.body = res.body.match(/<!json>\["(.*)"\]/)[1];
    res.body = res.body.replaceAll("\\", "");
    return await new Promise(async resolve => {
      let playlists = [];
      let root = HTMLParser.parse(res.body);
      let pl_objects = root.querySelectorAll('.audio_pl_item2');
      let type = "";
      for(let playlist of pl_objects) {   
        let raw = playlist.childNodes[1].rawAttrs;
        let match = raw.match(/showAudioPlaylist\((.*),/)[1];
        let split = match.split(", ");
        let owner_id = split[0];
        let playlist_id = split[1];
        let subtitle = playlist.childNodes[3].childNodes[3].childNodes[0].childNodes[0].rawText;
        let title = playlist.childNodes[3].childNodes[1].childNodes[1].rawText;
        let cover = playlist.childNodes[1].rawAttrs.match(/background-image: url\(\'(.*)\'\)/)[1];

        let access_hash = split[2];
        if(access_hash.length) access_hash = access_hash.replaceAll("'", "");

        let genre = split[3];
        genre = genre.replace("genre_", "");
        genre = genre.replaceAll("'", "");
        genre = genre.charAt(0).toUpperCase() + genre.substring(1, genre.length);

        type = playlist.parentNode.parentNode.parentNode.childNodes[1].rawAttrs;
        type = type.match(/type=(.*)" /)[1];

        if(!playlists[genre]) playlists[genre] = [ type ];
        let _playlist = { access_hash, owner_id, playlist_id, cover, title, subtitle, genre, raw_id: `${owner_id}_${playlist_id}` };
        playlists[genre] = [...playlists[genre], _playlist];
      }

      return resolve({
        vk: this._vk,
        vkr: playlists
      })
    });
  }

Следующий метод раскрывает список плейлистов по их типу, то есть кнопка "посмотреть всё" (тип это type=PUkLGlpXAD....., то есть то, что в адресной строке. В предыдущем методе эти типы приписываются к жанру. Нужно поменять структуру резолва для лучшего понимания для пользователя):

async getPlaylistsByType (params = {}) {
    String.prototype.replaceAll = function(search, replace){
      return this.split(search).join(replace);
    }
    let self = this;
    let res = await self._request({
      section: "recoms_block",
      type: params.type
    }, true);
    res.body = encoding.convert(res.body, 'utf-8', 'windows-1251').toString();
    return await new Promise(async resolve => {
      let playlists = [];
      let root = HTMLParser.parse(res.body);
      let pl_objects = root.querySelectorAll('.audio_pl_item2');
      for(let playlist of pl_objects) {   
        let raw = playlist.childNodes[1].rawAttrs;
        let match = raw.match(/showAudioPlaylist\((.*),/)[1];
        let split = match.split(", ");
        let owner_id = split[0];
        let playlist_id = split[1];
        let subtitle = playlist.childNodes[3].childNodes[3].childNodes[0].childNodes[0].rawText;
        let title = playlist.childNodes[3].childNodes[1].childNodes[1].rawText;
        let cover = playlist.childNodes[1].rawAttrs.match(/background-image: url\(\'(.*)\'\)/)[1];

        let access_hash = split[2];
        if(access_hash.length) access_hash = access_hash.replaceAll("'", "");

        let genre = split[3];
        genre = genre.replace("genre_", "");
        genre = genre.replaceAll("'", "");
        genre = genre.charAt(0).toUpperCase() + genre.substring(1, genre.length);

        let _playlist = { access_hash, owner_id, playlist_id, cover, title, subtitle, genre, raw_id: `${owner_id}_${playlist_id}` };
        playlists = [...playlists, _playlist];

      }
      return resolve({
        vk: this._vk,
        vkr: playlists
      })
    });
  }

Поиск плейлистов:

async searchPlaylists (params = {}) {
    String.prototype.replaceAll = function(search, replace){
      return this.split(search).join(replace);
    }
    let self = this;
    let uid = self._vk.session.user_id
    let res = await self._request({
      act: "section",
      al: 1,
      claim: 0,
      is_layer: 0,
      owner_id: uid,
      q: params.q,
      section: "search"
    }, true);
    res.body = encoding.convert(res.body, 'utf-8', 'windows-1251').toString();
    return await new Promise(async resolve => {
      let playlists = [];
      let root = HTMLParser.parse(res.body);
      let pl_objects = root.querySelectorAll('.audio_pl_item2');
      for(let playlist of pl_objects) {   
        let raw = playlist.childNodes[1].rawAttrs;
        let match = raw.match(/showAudioPlaylist\((.*),/)[1];
        let split = match.split(", ");
        let owner_id = split[0];
        let playlist_id = split[1];

        let title = playlist.childNodes[3].childNodes[1].childNodes[1].rawText;
        let cover = playlist.childNodes[1].rawAttrs.match(/background-image: url\(\'(.*)\'\)/)[1];

        let access_hash = split[2];
        if(access_hash.length) access_hash = access_hash.replaceAll("'", "");

        let genre = split[3];
        genre = genre.replace("genre_", "");
        genre = genre.replaceAll("'", "");
        genre = genre.charAt(0).toUpperCase() + genre.substring(1, genre.length);

        let _playlist = { access_hash, owner_id, playlist_id, cover, title, genre, raw_id: `${owner_id}_${playlist_id}` };
        playlists = [...playlists, _playlist];

      }
      return resolve({
        vk: this._vk,
        vkr: playlists
      })
    });
  }

Поделиться треком с другом:

shareAudio (audio, params = {}) {
    let self = this;

    return new Promise((resolve, reject) => {
      self._http.request("like.php", {
        act: "publish_box",
        al: 1,
        list: audio.action_hash,
        object: `audio${audio.full_id}`,
        to: "mail"
      }, true).then(res => {
        let chas = res.body.match(/imHash: '(.*)'/)[1];
        self._http.request("al_im.php", {
          Message: params.Message,
          act: "a_send_box",
          ajax: 1,
          al: 1,
          chas,
          entrypoint: "share",
          from: "box",
          media: `audio${audio.full_id}/${audio.action_hash}`,
          ret_data: 1,
          title: null,
          to_ids: params.to_ids
        }, true).then(() => {
          return resolve({
            vk: self._vk,
            vkr: VKResponse(staticMethods, {
              response: true
            })
          });
        }).catch(e => reject(e));
      }).catch(e => reject(e));
    });
  }

Фикс для текстов песен. В методе _getAudioAsObject lyrics_id получается правильный для всех аудиозаписей, старых и новых.

if (audio[9]) {
    audio_.lyrics_id = audio[9]
 }

Поделиться плейлистом (в общем, всё то же самое, что и предыдущее. Наверное, их можно объединить)

sharePlaylist (playlist, params = {}) {
    let self = this;

    return new Promise((resolve, reject) => {
      self._http.request("like.php", {
        act: "publish_box",
        al: 1,
        list: playlist.action_hash,
        object: `audio_playlist${playlist.owner_id}_${playlist.playlist_id}`,
        to: "mail"
      }, true).then(res => {
        let chas = res.body.match(/imHash: '(.*)'/)[1];
        self._http.request("al_im.php", {
          Message: params.Message,
          act: "a_send_box",
          ajax: 1,
          al: 1,
          chas,
          entrypoint: "share",
          from: "box",
          media: `audio_playlist${playlist.owner_id}_${playlist.playlist_id}`,
          ret_data: 1,
          title: null,
          to_ids: params.to_ids
        }, true).then(() => {
          return resolve({
            vk: self._vk,
            vkr: VKResponse(staticMethods, {
              response: true
            })
          });
        }).catch(e => reject(e));
      }).catch(e => reject(e));
    });
  }
ciricc commented 4 years ago

Безумно благодарен тебе за это, но ВК не стоит на месте, а библиотеку не получается своевременно обновлять. Поэтому с 2.6 версии Audio API будет удален. HTTP клиент по прежнему останется, даже будет улучшен, поэтому плеер можно будет продолжать поддерживать без особых напрягов. Тебе еще кстати плюшка к нему, будет поддержка капчи :)