1<?php 2/* 3 * vim:set softtabstop=4 shiftwidth=4 expandtab: 4 * 5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later) 6 * Copyright 2001 - 2020 Ampache.org 7 * 8 * This program is free software: you can redistribute it and/or modify 9 * it under the terms of the GNU Affero General Public License as published by 10 * the Free Software Foundation, either version 3 of the License, or 11 * (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU Affero General Public License for more details. 17 * 18 * You should have received a copy of the GNU Affero General Public License 19 * along with this program. If not, see <https://www.gnu.org/licenses/>. 20 * 21 */ 22declare(strict_types=0); 23 24namespace Ampache\Plugin; 25 26use Ampache\Repository\Model\Album; 27use Ampache\Repository\Model\Artist; 28use Ampache\Repository\Model\Preference; 29use Ampache\Repository\Model\Song; 30use Ampache\Repository\Model\User; 31use Ampache\Module\Statistics\Stats; 32 33class Ampachelistenbrainz 34{ 35 public $name = 'ListenBrainz'; 36 public $categories = 'scrobbling'; 37 public $description = 'Records your played songs to your ListenBrainz Account'; 38 public $url; 39 public $version = '000001'; 40 public $min_ampache = '380004'; 41 public $max_ampache = '999999'; 42 43 // These are internal settings used by this class, run this->load to fill them out 44 private $token; 45 private $user_id; 46 private $scheme = 'https'; 47 private $host = 'listenbrainz.org'; 48 private $api_host = 'api.listenbrainz.org'; 49 50 /** 51 * Constructor 52 * This function does nothing... 53 */ 54 public function __construct() 55 { 56 $this->description = T_('Scrobble songs you play to your ListenBrainz Account'); 57 $this->url = $this->scheme . '://' . $this->host; 58 59 return true; 60 } // constructor 61 62 /** 63 * install 64 * This is a required plugin function. It inserts our preferences 65 * into Ampache 66 */ 67 public function install() 68 { 69 70 // Check and see if it's already installed (they've just hit refresh, those dorks) 71 if (Preference::exists('listenbrainz_token')) { 72 return false; 73 } 74 75 Preference::insert('listenbrainz_token', T_('ListenBrainz User Token'), '', 25, 'string', 'plugins', 76 $this->name); 77 78 return true; 79 } // install 80 81 /** 82 * uninstall 83 * This is a required plugin function. It removes our preferences from 84 * the database returning it to its original form 85 */ 86 public function uninstall() 87 { 88 Preference::delete('listenbrainz_token'); 89 } // uninstall 90 91 /** 92 * upgrade 93 * This is a recommended plugin function 94 */ 95 public function upgrade() 96 { 97 return true; 98 } // upgrade 99 100 /** 101 * save_mediaplay 102 * This takes care of queuing and then submitting the tracks. 103 * @param Song $song 104 * @return boolean 105 */ 106 public function save_mediaplay($song) 107 { 108 // Only support songs 109 if (get_class($song) != Song::class) { 110 return false; 111 } 112 113 // Make sure there's actually a token before we keep going 114 if (!$this->token) { 115 debug_event('listenbrainz.plugin', 'Token missing', 5); 116 117 return false; 118 } 119 if ($song->time < 30) { 120 debug_event('listenbrainz.plugin', 'Song less then 30 seconds not queueing', 3); 121 122 return false; 123 } 124 125 $album = new Album($song->album); 126 $artist = new Artist($song->artist); 127 128 $additional_info = array(); 129 if ($song->mbid) { 130 $additional_info['recording_mbid'] = $song->mbid; 131 } 132 if ($album->mbid) { 133 $additional_info['release_mbid'] = $album->mbid; 134 } 135 if ($artist->mbid) { 136 $additional_info['artist_mbid'] = $artist->mbid; 137 } 138 $track_metadata = array( 139 'additional_info' => $additional_info, 140 'artist_name' => $artist->name, 141 'track_name' => $song->title, 142 'release_name' => $album->f_name, 143 ); 144 if (empty($additional_info)) { 145 $track_metadata = array_splice($track_metadata, 1); 146 } 147 $json = json_encode(array( 148 'listen_type' => 'single', 149 'payload' => array( 150 array( 151 'listened_at' => time(), 152 'track_metadata' => $track_metadata 153 ) 154 ) 155 )); 156 debug_event('listenbrainz.plugin', 'Submission content: ' . $json, 5); 157 $response = $this->post_json_url('/1/submit-listens', $json); 158 159 if (!strpos($response, "ok")) { 160 debug_event('listenbrainz.plugin', "Submission Failed", 5); 161 162 return false; 163 } 164 debug_event('listenbrainz.plugin', "Submission Successful", 5); 165 166 return true; 167 } // submit 168 169 /** 170 * post_json_url 171 * This is a generic poster for HTTP requests 172 * @param string $url 173 * @param string $content 174 * @return false|string 175 */ 176 private function post_json_url($url, $content) 177 { 178 $opts = array( 179 'http' => array( 180 'method' => 'POST', 181 'header' => array( 182 'Authorization: token ' . $this->token, 183 'Content-type: application/json; charset=utf-8', 184 'Content-length: ' . strlen($content) 185 ), 186 'content' => $content 187 ) 188 ); 189 debug_event('listenbrainz.plugin', 'Submission option: ' . json_encode($opts), 5); 190 $context = stream_context_create($opts); 191 $target = $this->scheme . '://' . $this->api_host . $url; 192 193 return file_get_contents($target, false, $context); 194 } // call_url 195 196 /** 197 * set_flag 198 * This takes care of spreading your love on ListenBrainz 199 * @param Song $song 200 * @param boolean $flagged 201 * @return boolean 202 */ 203 public function set_flag($song, $flagged) 204 { 205 return true; 206 } // set_flag 207 208 /** 209 * load 210 * This loads up the data we need into this object, this stuff comes 211 * from the preferences. 212 * @param User $user 213 * @return boolean 214 */ 215 public function load($user) 216 { 217 $user->set_preferences(); 218 $data = $user->prefs; 219 $this->user_id = $user->id; 220 // check if user have a token 221 if (strlen(trim($data['listenbrainz_token']))) { 222 $this->token = trim($data['listenbrainz_token']); 223 } else { 224 debug_event('listenbrainz.plugin', 225 'No token, not scrobbling (need to add your ListenBrainz api key to ampache)', 4); 226 227 return false; 228 } 229 230 return true; 231 } // load 232} 233