zen_MAKE easy reading + www webapps
This commit is contained in:
parent
88e006bcdb
commit
a04bdf4ae2
|
@ -0,0 +1,147 @@
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
display: grid;
|
||||||
|
height: 97%;
|
||||||
|
grid-template:
|
||||||
|
"search qr" 2em
|
||||||
|
"list main" auto
|
||||||
|
/ 20em auto;
|
||||||
|
grid-gap: .5em;
|
||||||
|
}
|
||||||
|
body:before {
|
||||||
|
content: "";
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
height: 2em;
|
||||||
|
/* background: red; */
|
||||||
|
z-index: 2;
|
||||||
|
padding: .5em;
|
||||||
|
box-shadow: 0 0 11px #0000004d;
|
||||||
|
}
|
||||||
|
|
||||||
|
body > input { grid-area: search; z-index: 3; }
|
||||||
|
body > ul { grid-area: list; z-index: 1; }
|
||||||
|
body > qr { grid-area: qr; z-index: 3; }
|
||||||
|
body > img { grid-area: main; z-index: 1; }
|
||||||
|
|
||||||
|
ul {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
li {
|
||||||
|
list-style: none;
|
||||||
|
padding: .3em .5em;
|
||||||
|
}
|
||||||
|
li:hover { background: lightgrey }
|
||||||
|
uid { display: block; }
|
||||||
|
pubkey { display: block; color: grey; }
|
||||||
|
|
||||||
|
qr {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-around;
|
||||||
|
}
|
||||||
|
qr label:after {
|
||||||
|
content: " :";
|
||||||
|
}
|
||||||
|
qr input {
|
||||||
|
max-width: 70px;
|
||||||
|
}
|
||||||
|
qr input[name=data] {
|
||||||
|
height: 32px;
|
||||||
|
width: 350px;
|
||||||
|
max-width: initial;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<input type="text" name="search"/>
|
||||||
|
<ul></ul>
|
||||||
|
<qr><input type="text" name="data"/></qr>
|
||||||
|
<img />
|
||||||
|
|
||||||
|
<!--<script src="./wot.membres.json.js"></script>-->
|
||||||
|
|
||||||
|
<script>
|
||||||
|
const ss_pp = (ss,...pp)=> ss.map( (s,i)=> s + (pp[i] || '') ).join('')
|
||||||
|
const $ = (ss,...pp)=> [...document.querySelectorAll( ss_pp(ss,...pp) )]
|
||||||
|
const DOM = (ss,...pp)=> (new DOMParser).parseFromString( ss_pp(ss,...pp), 'text/html' ).body.children
|
||||||
|
|
||||||
|
const search = $`input`[0]
|
||||||
|
const members = $`ul`[0]
|
||||||
|
const QRform = $`qr`[0]
|
||||||
|
const QRimg = $`img`[0]
|
||||||
|
|
||||||
|
search.onkeyup = e=> [...members.children]
|
||||||
|
.map( li=> (li.style.display = 'block',li) )
|
||||||
|
.filter( li=> !(new RegExp(search.value,'i')).test( li.querySelector('uid').textContent ) )
|
||||||
|
.map( li=> li.style.display = 'none' )
|
||||||
|
|
||||||
|
|
||||||
|
const QR = {
|
||||||
|
api: "https://api.qrserver.com/v1/create-qr-code/",
|
||||||
|
config: {
|
||||||
|
format: ["svg","png","gif","jpeg","jpg","eps"],
|
||||||
|
size: "300x300",
|
||||||
|
color: "#000",
|
||||||
|
bgcolor: "#ffffff",
|
||||||
|
qzone: 1,
|
||||||
|
ecc: ["Q","H","M","L"]
|
||||||
|
/*
|
||||||
|
"L (low, ~7% destroyed data may be corrected)",
|
||||||
|
"M (middle, ~15% destroyed data may be corrected)",
|
||||||
|
"Q (quality, ~25% destroyed data may be corrected)",
|
||||||
|
"H (high, ~30% destroyed data may be corrected)"
|
||||||
|
]
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QRform.append( ...
|
||||||
|
Object.keys( QR.config )
|
||||||
|
.map( opt=> DOM`<label for="">${opt}</label>${
|
||||||
|
Array.isArray(QR.config[opt]) ?
|
||||||
|
`<select name="${opt}">${QR.config[opt].map(item=>`<option value="${item}">${item}</option>`).join('')}</select>`
|
||||||
|
: QR.config[opt][0] == "#" ?
|
||||||
|
`<input type="color" name="${opt}" value="${QR.config[opt]}" />`
|
||||||
|
: `<input type="text" name="${opt}" value="${QR.config[opt]}" />`
|
||||||
|
}`
|
||||||
|
)
|
||||||
|
.reduce((a,o)=>a.concat(...o), [])
|
||||||
|
)
|
||||||
|
|
||||||
|
const QRnames = $`qr [name]`
|
||||||
|
QRnames.map( n=>
|
||||||
|
n.onchange = e=>
|
||||||
|
QRimg.src = QR.api + QRnames.reduce( (s,n)=> s + n.name + "=" + n.value.replace(/^#/,'') + "&", "?")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;(
|
||||||
|
typeof wot != 'undefined' &&
|
||||||
|
Promise.resolve( wot.members )
|
||||||
|
||
|
||||||
|
fetch('https://g1.duniter.org/wot/members')
|
||||||
|
.then( res=> res.json() )
|
||||||
|
)
|
||||||
|
.then( json=> json.results.map(o=>DOM`<li><uid>${o.uid}</uid><pubkey>${o.pubkey}</pubkey></li>`[0]) )
|
||||||
|
.then( items=> items.map( li=>
|
||||||
|
(li.onclick = e=> {
|
||||||
|
$`qr [name=data]`[0].value = e.currentTarget.querySelector('pubkey').textContent
|
||||||
|
$`qr [name=data]`[0].dispatchEvent(new Event('change'))
|
||||||
|
}
|
||||||
|
/*$`img`[0].src = `https://api.qrserver.com/v1/create-qr-code/?
|
||||||
|
format=svg&size=300x300&
|
||||||
|
data=${e.currentTarget.querySelector('pubkey').textContent}&qzone=1&
|
||||||
|
ecc=H`
|
||||||
|
.replace(/\s* /mg,'')*/
|
||||||
|
,li)
|
||||||
|
) )
|
||||||
|
.then( items=> members.append(...items) )
|
||||||
|
|
||||||
|
|
||||||
|
</script>
|
|
@ -0,0 +1,26 @@
|
||||||
|
server {
|
||||||
|
listen 9980;
|
||||||
|
server_name rock64.p2p.legal g1sms.local localhost 127.0.0.1;
|
||||||
|
|
||||||
|
index index.php index.html;
|
||||||
|
root /var/www/g1billet;
|
||||||
|
|
||||||
|
# set expiration of assets to MAX for caching
|
||||||
|
location ~* \.(ico|css|js|gif|jpe?g|png)(\?[0-9]+)?$ {
|
||||||
|
expires max;
|
||||||
|
log_not_found off;
|
||||||
|
}
|
||||||
|
|
||||||
|
# php parsing
|
||||||
|
location ~ \.php$ {
|
||||||
|
include fastcgi_params;
|
||||||
|
fastcgi_pass unix:/var/run/php/php7.3-fpm.sock;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
error_log /var/log/nginx/g1billet_error.log;
|
||||||
|
access_log /var/log/nginx/g1billet_access.log;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
server {
|
||||||
|
|
||||||
|
listen 80 default_server;
|
||||||
|
listen [::]:80 default_server;
|
||||||
|
|
||||||
|
root /var/www/rompr;
|
||||||
|
index index.php index.html index.htm;
|
||||||
|
|
||||||
|
server_name copylaradio;
|
||||||
|
|
||||||
|
# This section can be copied into an existing default setup
|
||||||
|
location / {
|
||||||
|
allow all;
|
||||||
|
index index.php;
|
||||||
|
location ~ \.php {
|
||||||
|
try_files $uri index.php =404;
|
||||||
|
fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;
|
||||||
|
fastcgi_index index.php;
|
||||||
|
fastcgi_param SCRIPT_FILENAME $request_filename;
|
||||||
|
include /etc/nginx/fastcgi_params;
|
||||||
|
fastcgi_read_timeout 1800;
|
||||||
|
}
|
||||||
|
error_page 404 = /404.php;
|
||||||
|
try_files $uri $uri/ =404;
|
||||||
|
location ~ /albumart/* {
|
||||||
|
expires -1s;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
# IPFS GATEWAY PROXY
|
||||||
|
location /ipfs {
|
||||||
|
proxy_pass http://127.0.0.1:8080;
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
proxy_set_header X-Forwarded-For $remote_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
<?php
|
||||||
|
include('includes/vars.php');
|
||||||
|
include("includes/functions.php");
|
||||||
|
$base_url = get_base_url();
|
||||||
|
$request = $_SERVER['REQUEST_URI'];
|
||||||
|
logger::log('REDIRECT','Uri is',$_SERVER['REQUEST_URI']);
|
||||||
|
if (preg_match('#prefs/userstreams/.*\.jpg#', $request)) {
|
||||||
|
$redirect = $base_url.'/newimages/broadcast.svg';
|
||||||
|
logger::log("404", "Request for missing userstream image. Redirecting to ".$redirect);
|
||||||
|
header("HTTP/1.1 307 Temporary Redirect");
|
||||||
|
header("Location: ".$redirect);
|
||||||
|
} else if (preg_match('#prefs/podcasts/.*\.jpg#', $request) ||
|
||||||
|
preg_match('#prefs/podcasts/.*\.png#', $request)) {
|
||||||
|
$redirect = $base_url.'/newimages/podcast-logo.svg';
|
||||||
|
logger::log("404", "Request for missing podcast image. Redirecting to ".$redirect);
|
||||||
|
header("HTTP/1.1 307 Temporary Redirect");
|
||||||
|
header("Location: ".$redirect);
|
||||||
|
} else {
|
||||||
|
header("HTTP/1.1 404 Not Found");
|
||||||
|
?>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/layout-january.css" />
|
||||||
|
<link rel="stylesheet" type="text/css" href="themes/Darkness.css" />
|
||||||
|
<title>Badgers!</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<br><br><br>
|
||||||
|
<table align="center"><tr><td><img src="newimages/favicon-196.png"></td></tr></table>
|
||||||
|
<h2 align="center">404 Error!</h2>
|
||||||
|
<br><br>
|
||||||
|
<h2 align="center">It's all gone horribly wrong</h2>
|
||||||
|
<br><br>
|
||||||
|
<?php
|
||||||
|
print '<h3 align="center">The document "'.$request."" doesn't exist. Are you sure you know what you're doing?</h3>";
|
||||||
|
?>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
<?php
|
||||||
|
}
|
||||||
|
?>
|
|
@ -0,0 +1,22 @@
|
||||||
|
==================
|
||||||
|
= Installing RompR
|
||||||
|
==================
|
||||||
|
Please read the installation instructions here:
|
||||||
|
|
||||||
|
http://sourceforge.net/p/rompr/wiki/Installation/
|
||||||
|
|
||||||
|
MacOS X Users
|
||||||
|
=============
|
||||||
|
|
||||||
|
Please read the instructions here:
|
||||||
|
|
||||||
|
http://sourceforge.net/p/rompr/wiki/Installation%20on%20Mac%20OS%20X/
|
||||||
|
|
||||||
|
Windows Users
|
||||||
|
=============
|
||||||
|
|
||||||
|
First, install a better operating system, then read this file again :)
|
||||||
|
Actually, it may well be possible to get this to run on Windows, if mpd or mopidy can be got
|
||||||
|
to work then there's probably a LAMP stack for Windows that will run apache and php
|
||||||
|
OK. But I don't intend to go buy a Windows computer just to find out.
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
|
||||||
|
# (C) Fat German Productions/Mark Greenwood 2017
|
||||||
|
|
||||||
|
SEE includes/license.html
|
||||||
|
|
||||||
|
CREDITS
|
||||||
|
=======
|
||||||
|
|
||||||
|
This program makes use of lots of other stuff which are all released
|
||||||
|
under their own licenses, just to make it complicated.
|
||||||
|
|
||||||
|
The original inspiration came from phpMP, and the original core of this app was lifted
|
||||||
|
directly from there. It's grown quite a lot since then.
|
||||||
|
|
||||||
|
jquery (http://jquery.com) and the jquery UI framework (http://jqueryui.com)
|
||||||
|
are probably released under the GPL or something. I dunno, their websites aren't
|
||||||
|
very clear on that point.
|
||||||
|
|
||||||
|
The md5 hashing algorithm code was taken from http://pajhome.org.uk/crypt/md5
|
||||||
|
and is released under a BSD license
|
||||||
|
|
||||||
|
The jquery form plugin comes from http://malsup.com/jquery/form/
|
||||||
|
and also has two licenses.
|
|
@ -0,0 +1,23 @@
|
||||||
|
# RompЯ
|
||||||
|
This is a browser-based client for Mopidy and MPD, which are both music players.
|
||||||
|
|
||||||
|
You can use RompЯ to control a music player on another device or on your computer. Because it runs in a web browser you can run it ony any device - your laptop,tablet, or phone can all be used to control your music player.
|
||||||
|
It has a rich and beautiful interface which is intended to sort your music, manage radio stations, browse and subscribe to podcasts.
|
||||||
|
When used with Mopidy you can listen to Spotify and make use of RompЯ's incredible music discovery features which will help to introduce you to new music.
|
||||||
|
|
||||||
|
## Installation from GitHub
|
||||||
|
Please see the [New Project Homepage](https://fatg3erman.github.io/RompR/)
|
||||||
|
|
||||||
|
![](docs/images/rompr-1.png)
|
||||||
|
|
||||||
|
![](docs/images/rompr-on-a-phone.png)
|
||||||
|
|
||||||
|
### What people are saying about RompЯ
|
||||||
|
|
||||||
|
* “Best interface to mpd / mopidy ever. A real must!”
|
||||||
|
* “Best browser based frontend to mpd I've ever seen!! Thank you!”
|
||||||
|
* “Rompr is a wonderful web based interface client to mpd.”
|
||||||
|
* “Great Project! I use it everyday already. I hope for VK-support soon. Thanks!”
|
||||||
|
* “I tired now a fiew clients to control my mopidy server running on Raspberry. rompr is far the best one, easy to install, very fast, good design and useful features.”
|
||||||
|
* “This application is amazing and easy to setup. I love it.”
|
||||||
|
* “Wow! Great stuff! I was searching for something like that for months!”
|
|
@ -0,0 +1,13 @@
|
||||||
|
# RompЯ
|
||||||
|
Это браузерный клиент для музыкальных проигрывателей Mopidy и MPD.
|
||||||
|
|
||||||
|
RompЯ можно использовать для управления музыкальным проигрывателем на удалённом или локальном компьютере. Поскольку он работает в веб-браузере, вы можете запускать его на любом устройстве - ноутбуке, планшете или телефоне для управления вашим музыкальным проигрывателем..
|
||||||
|
Он имеет богатый и красивый интерфейс, который предназначен для сортировки музыки, управления радиостанциями, просмотра и подписки на подкасты.
|
||||||
|
При использовании с Mopidy вы можете слушать Spotify, которые помогут вам познакомиться с новой музыкой.
|
||||||
|
|
||||||
|
## Установка с GitHub
|
||||||
|
Инструкция [Новая Страница проекта](https://fatg3erman.github.io/RompR/)
|
||||||
|
|
||||||
|
![](docs/images/rompr-1.png)
|
||||||
|
|
||||||
|
![](docs/images/rompr-on-a-phone.png)
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,450 @@
|
||||||
|
/*! normalize.css v7.0.0 | MIT License | github.com/necolas/normalize.css */
|
||||||
|
|
||||||
|
/* Document
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the line height in all browsers.
|
||||||
|
* 2. Prevent adjustments of font size after orientation changes in
|
||||||
|
* IE on Windows Phone and in iOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
html {
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
-ms-text-size-adjust: 100%; /* 2 */
|
||||||
|
-webkit-text-size-adjust: 100%; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the margin in all browsers (opinionated).
|
||||||
|
margin: 0;
|
||||||
|
*/
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin-left:auto;
|
||||||
|
margin-right:auto;
|
||||||
|
width:98%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
article,
|
||||||
|
aside,
|
||||||
|
footer,
|
||||||
|
header,
|
||||||
|
nav,
|
||||||
|
section {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the font size and margin on `h1` elements within `section` and
|
||||||
|
* `article` contexts in Chrome, Firefox, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Grouping content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
* 1. Add the correct display in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figcaption,
|
||||||
|
figure,
|
||||||
|
main { /* 1 */
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct margin in IE 8.
|
||||||
|
*/
|
||||||
|
|
||||||
|
figure {
|
||||||
|
margin: 1em 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in Firefox.
|
||||||
|
* 2. Show the overflow in Edge and IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
hr {
|
||||||
|
box-sizing: content-box; /* 1 */
|
||||||
|
height: 0; /* 1 */
|
||||||
|
overflow: visible; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
pre {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Text-level semantics
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the gray background on active links in IE 10.
|
||||||
|
* 2. Remove gaps in links underline in iOS 8+ and Safari 8+.
|
||||||
|
*/
|
||||||
|
|
||||||
|
a {
|
||||||
|
background-color: transparent; /* 1 */
|
||||||
|
-webkit-text-decoration-skip: objects; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Remove the bottom border in Chrome 57- and Firefox 39-.
|
||||||
|
* 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
abbr[title] {
|
||||||
|
border-bottom: none; /* 1 */
|
||||||
|
text-decoration: underline; /* 2 */
|
||||||
|
text-decoration: underline dotted; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent the duplicate application of `bolder` by the next rule in Safari 6.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font weight in Chrome, Edge, and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
b,
|
||||||
|
strong {
|
||||||
|
font-weight: bolder;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inheritance and scaling of font size in all browsers.
|
||||||
|
* 2. Correct the odd `em` font sizing in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
code,
|
||||||
|
kbd,
|
||||||
|
samp {
|
||||||
|
font-family: monospace, monospace; /* 1 */
|
||||||
|
font-size: 1em; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font style in Android 4.3-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
dfn {
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct background and color in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
mark {
|
||||||
|
background-color: #ff0;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct font size in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
small {
|
||||||
|
font-size: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Prevent `sub` and `sup` elements from affecting the line height in
|
||||||
|
* all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sub,
|
||||||
|
sup {
|
||||||
|
font-size: 75%;
|
||||||
|
line-height: 0;
|
||||||
|
position: relative;
|
||||||
|
vertical-align: baseline;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub {
|
||||||
|
bottom: -0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
|
sup {
|
||||||
|
top: -0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Embedded content
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio,
|
||||||
|
video {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in iOS 4-7.
|
||||||
|
*/
|
||||||
|
|
||||||
|
audio:not([controls]) {
|
||||||
|
display: none;
|
||||||
|
height: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the border on images inside links in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hide the overflow in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
svg:not(:root) {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Forms
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Change the font styles in all browsers (opinionated).
|
||||||
|
* 2. Remove the margin in Firefox and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input,
|
||||||
|
optgroup,
|
||||||
|
select,
|
||||||
|
textarea {
|
||||||
|
font-family: sans-serif; /* 1 */
|
||||||
|
font-size: 100%; /* 1 */
|
||||||
|
line-height: 1.15; /* 1 */
|
||||||
|
margin: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Show the overflow in IE.
|
||||||
|
* 1. Show the overflow in Edge.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
input { /* 1 */
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inheritance of text transform in Edge, Firefox, and IE.
|
||||||
|
* 1. Remove the inheritance of text transform in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
select { /* 1 */
|
||||||
|
text-transform: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Prevent a WebKit bug where (2) destroys native `audio` and `video`
|
||||||
|
* controls in Android 4.
|
||||||
|
* 2. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button,
|
||||||
|
html [type="button"], /* 1 */
|
||||||
|
[type="reset"],
|
||||||
|
[type="submit"] {
|
||||||
|
-webkit-appearance: button; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner border and padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button::-moz-focus-inner,
|
||||||
|
[type="button"]::-moz-focus-inner,
|
||||||
|
[type="reset"]::-moz-focus-inner,
|
||||||
|
[type="submit"]::-moz-focus-inner {
|
||||||
|
border-style: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restore the focus styles unset by the previous rule.
|
||||||
|
*/
|
||||||
|
|
||||||
|
button:-moz-focusring,
|
||||||
|
[type="button"]:-moz-focusring,
|
||||||
|
[type="reset"]:-moz-focusring,
|
||||||
|
[type="submit"]:-moz-focusring {
|
||||||
|
outline: 1px dotted ButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the padding in Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
fieldset {
|
||||||
|
padding: 0.35em 0.75em 0.625em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the text wrapping in Edge and IE.
|
||||||
|
* 2. Correct the color inheritance from `fieldset` elements in IE.
|
||||||
|
* 3. Remove the padding so developers are not caught out when they zero out
|
||||||
|
* `fieldset` elements in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
legend {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
color: inherit; /* 2 */
|
||||||
|
display: table; /* 1 */
|
||||||
|
max-width: 100%; /* 1 */
|
||||||
|
padding: 0; /* 3 */
|
||||||
|
white-space: normal; /* 1 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct display in IE 9-.
|
||||||
|
* 2. Add the correct vertical alignment in Chrome, Firefox, and Opera.
|
||||||
|
*/
|
||||||
|
|
||||||
|
progress {
|
||||||
|
display: inline-block; /* 1 */
|
||||||
|
vertical-align: baseline; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the default vertical scrollbar in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Add the correct box sizing in IE 10-.
|
||||||
|
* 2. Remove the padding in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="checkbox"],
|
||||||
|
[type="radio"] {
|
||||||
|
box-sizing: border-box; /* 1 */
|
||||||
|
padding: 0; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Correct the cursor style of increment and decrement buttons in Chrome.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="number"]::-webkit-inner-spin-button,
|
||||||
|
[type="number"]::-webkit-outer-spin-button {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the odd appearance in Chrome and Safari.
|
||||||
|
* 2. Correct the outline style in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"] {
|
||||||
|
-webkit-appearance: textfield; /* 1 */
|
||||||
|
outline-offset: -2px; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the inner padding and cancel buttons in Chrome and Safari on macOS.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[type="search"]::-webkit-search-cancel-button,
|
||||||
|
[type="search"]::-webkit-search-decoration {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 1. Correct the inability to style clickable types in iOS and Safari.
|
||||||
|
* 2. Change font properties to `inherit` in Safari.
|
||||||
|
*/
|
||||||
|
|
||||||
|
::-webkit-file-upload-button {
|
||||||
|
-webkit-appearance: button; /* 1 */
|
||||||
|
font: inherit; /* 2 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Interactive
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
* 1. Add the correct display in Edge, IE, and Firefox.
|
||||||
|
*/
|
||||||
|
|
||||||
|
details, /* 1 */
|
||||||
|
menu {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Add the correct display in all browsers.
|
||||||
|
*/
|
||||||
|
|
||||||
|
summary {
|
||||||
|
display: list-item;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Scripting
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 9-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
template {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hidden
|
||||||
|
========================================================================== */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the correct display in IE 10-.
|
||||||
|
*/
|
||||||
|
|
||||||
|
[hidden] {
|
||||||
|
display: none;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 382 KiB |
|
@ -0,0 +1,128 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
DONE!!!? WRITE THAT CODE IN infobar2.js : arrount line 158 before "return lines;"
|
||||||
|
// ZEEBOX HACK ZONE
|
||||||
|
var reclink = '/REC/youtube-dl.php?q=REC&artist=' + escape(encodeURIComponent(npinfo.Artist)) + '&title=' + escape(encodeURIComponent(npinfo.Title)) + '&radio='+ escape(encodeURIComponent(npinfo.stream)) +'&maxResults=1';
|
||||||
|
var zcopylink = ' <a id="REC" title="Enregistrer sur Youtube" href="#" onclick=\'javascript:window.open("'+ reclink +'","REC","menubar=no, scrollbars=no, top=10, left=10, width=384, height=546");return false;\'>[REC]</a>';
|
||||||
|
zcopylink += ' <a title="RECHERCHE LIBRE" href="/REC/youtube-dl.php" target="youtube">*</a>';
|
||||||
|
lines[0].text += zcopylink;
|
||||||
|
// ZEEBOX HACK ZONE
|
||||||
|
*/
|
||||||
|
// RUN CLI if($argc>1) parse_str(implode('&',array_slice($argv, 1)), $_REQUEST);
|
||||||
|
$search=$radio=$artist=$title=$lnk=$lnkform=$cmd=$len="";
|
||||||
|
$search = trim(urldecode($_REQUEST['q']));
|
||||||
|
|
||||||
|
$radio = urldecode($_REQUEST['radio']);
|
||||||
|
$artist = urldecode($_REQUEST['artist']);
|
||||||
|
$title = urldecode($_REQUEST['title']);
|
||||||
|
$lnk = trim(urldecode($_REQUEST['lnk']));
|
||||||
|
$cmd="$radio|$artist|$title";
|
||||||
|
$len=strlen($artist.$title);
|
||||||
|
|
||||||
|
//$result='<a href="#null" onclick="javascript:window.close();"><img src="/REC/REC.png"></a><br>';
|
||||||
|
$result='<a href="https://www.copylaradio.com" target="copylaradio"><img src="/REC/REC.png"></a><br>';
|
||||||
|
if( $radio == "" ) { $radio = "CopyLaRadio"; }
|
||||||
|
if( $radio == "Nova zz" ) {
|
||||||
|
$artist = "undefined";
|
||||||
|
$title = "undefined";
|
||||||
|
}
|
||||||
|
// Write request for copy.sh triggering
|
||||||
|
if( $search == "REC" ) {
|
||||||
|
///////////////////
|
||||||
|
$result.='<h2>♫ '.$radio.' ♫</h2>';
|
||||||
|
// LINK RECEIVED
|
||||||
|
if ($lnk) {
|
||||||
|
$artist="";
|
||||||
|
shell_exec('/home/pi/G1sms+/_CopyLaRadio/parle.sh "Lien reçu."');
|
||||||
|
// Not making double request
|
||||||
|
if( ! exec('grep '.escapeshellarg($lnk).' /tmp/ytdl.list') ) {
|
||||||
|
file_put_contents("/tmp/ytdl.list","CopyLibre||$lnk\n", FILE_APPEND);
|
||||||
|
}
|
||||||
|
$result.='<p><a href="'.$lnk.'" target="check">LIEN: '.$lnk.'</a></p>';
|
||||||
|
///////////////////
|
||||||
|
// TRACK COPY (not for undefined or local file)
|
||||||
|
} else if ($radio && $artist != $title && $artist != "undefined" && $title != "undefined" && strlen(explode(".", $title)[1]) != 3 && explode(".", $title)[1] != "opus" ) {
|
||||||
|
// Not making double request
|
||||||
|
if( ! exec('grep '.escapeshellarg($cmd).' /tmp/ytdl.list') ) {
|
||||||
|
shell_exec('/home/pi/G1sms+/_CopyLaRadio/parle.sh "Enregistrement ajouté."');
|
||||||
|
file_put_contents("/tmp/ytdl.list","$cmd\n", FILE_APPEND);
|
||||||
|
} else {
|
||||||
|
shell_exec('/home/pi/G1sms+/_CopyLaRadio/parle.sh "Copie déjà lancée"');
|
||||||
|
}
|
||||||
|
$result.='<a style="color:#FFFFFF" href="https://www.youtube.com/results?search_query='.urlencode($artist).'%20'.urlencode($title).'" target="check">
|
||||||
|
<h4>'.$artist.' / '.$title.'</h4>
|
||||||
|
</a>';
|
||||||
|
///////////////////
|
||||||
|
// RADIO EXTERNAL TRACK SCRAPER
|
||||||
|
} else if($radio != "" && $artist == "undefined" && $title == "undefined" ){
|
||||||
|
shell_exec('/home/pi/G1sms+/_CopyLaRadio/parle.sh "Recherche externe pour '.$radio.'"');
|
||||||
|
file_put_contents("/tmp/youtube-dl.log", "/home/pi/G1sms+/_CopyLaRadio/libradio/".escapeshellcmd($radio).".php".PHP_EOL, FILE_APPEND);
|
||||||
|
if ( file_exists("/home/pi/G1sms+/_CopyLaRadio/libradio/".escapeshellcmd($radio).".php") ) {
|
||||||
|
file_put_contents("/tmp/ytdl.list","$radio||".PHP_EOL, FILE_APPEND);
|
||||||
|
} else {
|
||||||
|
shell_exec('/home/pi/G1sms+/_CopyLaRadio/parle.sh "Aucun module"');
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
shell_exec('/home/pi/G1sms+/_CopyLaRadio/parle.sh "Identification imprécise. Podcast? Fichier local?"');
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
$ytform = '<form action="/REC/youtube-dl.php" method="GET">
|
||||||
|
<div>
|
||||||
|
<h3>ARTISTE: <input type="search" id="artist" name="artist" size="17" placeholder="Indiquez un artiste" value="'.$artist.'"></h3>
|
||||||
|
<h3>TITRE: <input type="search" id="title" name="title" size="20" placeholder="Titre de la chanson" value="'.$title.'"></h3>
|
||||||
|
</div>
|
||||||
|
<input type="hidden" id="radio" name="radio" value="'.$radio.'">
|
||||||
|
<input type="hidden" id="q" name="q" value="REC">
|
||||||
|
<br>
|
||||||
|
<input type="submit" value="♫ Copie Youtube ♫">
|
||||||
|
</form>
|
||||||
|
';
|
||||||
|
|
||||||
|
$lnkform.='<form action="/REC/youtube-dl.php" method="GET">
|
||||||
|
<a href="https://youtube.com" target="search"><img src="/REC/youtube.png"></a>
|
||||||
|
<p><h1>youtube-dl</h1>
|
||||||
|
<a style="color:#FFFFFF" href="https://ytdl-org.github.io/youtube-dl/supportedsites.html" target="_blank">- Sites compatibles -</a>
|
||||||
|
<input type="search" id="lnk" name="lnk" placeholder="Inscrivez le lien à copier" value="" size="40">
|
||||||
|
<input type="hidden" id="q" name="q" value="REC">
|
||||||
|
</p>
|
||||||
|
<div>
|
||||||
|
<input type="submit" value="Copie du Lien">
|
||||||
|
</div>
|
||||||
|
</form>';
|
||||||
|
|
||||||
|
?>
|
||||||
|
<!doctype html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="author" content="fred" >
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" >
|
||||||
|
<title><?php echo $search;?> - Recherche YouTube & Copie privée</title>
|
||||||
|
<link href="/REC/bootstrap.css" rel="stylesheet">
|
||||||
|
</head>
|
||||||
|
<body style='background: url("/REC/fond.jpg") no-repeat scroll center center / cover rgb(0, 0, 0); color:#FFFFFF;'>
|
||||||
|
<section class="content-section text-center">
|
||||||
|
<div class="container-fluid">
|
||||||
|
<div class="container" id="result" >
|
||||||
|
<div class="col-lg-8 col-lg-offset-2 page-scroll">
|
||||||
|
<ul>
|
||||||
|
<?php echo $result; ?>
|
||||||
|
<hr>
|
||||||
|
</ul>
|
||||||
|
<ul>
|
||||||
|
<?php echo $ytform; ?>
|
||||||
|
<hr>
|
||||||
|
<?php echo $lnkform; ?>
|
||||||
|
<hr>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</body>
|
||||||
|
</html>
|
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
|
@ -0,0 +1,9 @@
|
||||||
|
## Pages On This website
|
||||||
|
|
||||||
|
[Home](https://fatg3erman.github.io/RompR/)
|
||||||
|
|
||||||
|
[Recommended Linux Installation - with Nginx](https://fatg3erman.github.io/RompR/Recommended-Installation-on-Linux)
|
||||||
|
|
||||||
|
[Alternative Linux Installation - with Apache](https://fatg3erman.github.io/RompR/Installation-on-Linux-Alternative-Method)
|
||||||
|
|
||||||
|
[Troubleshooting](https://fatg3erman.github.io/RompR/Troubleshooting)
|
|
@ -0,0 +1,266 @@
|
||||||
|
<?php
|
||||||
|
define('ROMPR_IS_LOADING', true);
|
||||||
|
require_once ("includes/vars.php");
|
||||||
|
require_once ("includes/functions.php");
|
||||||
|
require_once ("international.php");
|
||||||
|
require_once ('utils/imagefunctions.php');
|
||||||
|
require_once ("backends/sql/backend.php");
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
$only_plugins_on_menu = false;
|
||||||
|
$skin = "desktop";
|
||||||
|
set_version_string();
|
||||||
|
?>
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||||
|
<head>
|
||||||
|
<title>RompЯ Album Art</title>
|
||||||
|
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate" />
|
||||||
|
<meta http-equiv="Pragma" content="no-cache" />
|
||||||
|
<meta http-equiv="Expires" content="0" />
|
||||||
|
<?php
|
||||||
|
print '<script type="application/json" name="translations">'."\n".json_encode($translations)."\n</script>\n";
|
||||||
|
print '<script type="application/json" name="prefs">'."\n".json_encode($prefs)."\n</script>\n";
|
||||||
|
print '<link rel="stylesheet" type="text/css" href="css/layout-january.css?version=?'.ROMPR_VERSION.'" />'."\n";
|
||||||
|
print '<link rel="stylesheet" type="text/css" href="skins/desktop/skin.css?version=='.ROMPR_VERSION.'" />'."\n";
|
||||||
|
print '<link rel="stylesheet" type="text/css" href="css/albumart.css?version=?'.ROMPR_VERSION.'" />'."\n";
|
||||||
|
?>
|
||||||
|
<link rel="stylesheet" id="theme" type="text/css" />
|
||||||
|
<link type="text/css" href="css/jquery.mCustomScrollbar.css" rel="stylesheet" />
|
||||||
|
<?php
|
||||||
|
$scripts = array(
|
||||||
|
"jquery/jquery-3.3.1.min.js",
|
||||||
|
"jquery/jquery-migrate-3.0.1.js",
|
||||||
|
"ui/functions.js",
|
||||||
|
"ui/prefs.js",
|
||||||
|
"ui/language.js",
|
||||||
|
"jquery/jquery-ui.min-19.1.18.js",
|
||||||
|
"jquery/jquery.mCustomScrollbar.concat.min-3.1.5.js",
|
||||||
|
"includes/globals.js",
|
||||||
|
"ui/uifunctions.js",
|
||||||
|
"ui/metahandlers.js",
|
||||||
|
"ui/widgets.js",
|
||||||
|
"ui/debug.js",
|
||||||
|
"ui/coverscraper.js",
|
||||||
|
"ui/albumart.js"
|
||||||
|
);
|
||||||
|
foreach ($scripts as $i) {
|
||||||
|
logger::mark("INIT", "Loading ".$i);
|
||||||
|
print '<script type="text/javascript" src="'.$i.'?version='.ROMPR_VERSION.'"></script>'."\n";
|
||||||
|
}
|
||||||
|
include ("includes/globals.php");
|
||||||
|
?>
|
||||||
|
</head>
|
||||||
|
<body class="desktop">
|
||||||
|
<div id="pset" class="invisible"></div>
|
||||||
|
<div id="pmaxset" class="invisible"></div>
|
||||||
|
<div id="pbgset" class="invisible"></div>
|
||||||
|
<div class="albumcovers">
|
||||||
|
<div class="infosection">
|
||||||
|
<table width="100%">
|
||||||
|
<?php
|
||||||
|
print '<tr>
|
||||||
|
<td colspan="4"><h2>'.get_int_text("albumart_title").'</h2></td>
|
||||||
|
<td class="outer" align="right" colspan="1"><button id="finklestein">'.get_int_text("albumart_onlyempty").'</button></td>
|
||||||
|
</tr>';
|
||||||
|
print '<tr>
|
||||||
|
<td class="outer" id="totaltext"></td>
|
||||||
|
<td colspan="3"><div class="invisible" id="progress"></div></td>
|
||||||
|
<td class="outer" align="right"><button id="harold">'.get_int_text("albumart_getmissing").'</button></td>
|
||||||
|
</tr>';
|
||||||
|
// <td class="outer" align="right"><button id="doobag">'.get_int_text("albumart_findsmall").'</button></td>
|
||||||
|
print '<tr>
|
||||||
|
<td class="outer" id="infotext"></td>
|
||||||
|
<td colspan="3" align="center"><div class="inner" id="status">'.get_int_text('label_loading').'</div></td>
|
||||||
|
<td class="outer styledinputs" align="right"><input type="checkbox" class="topcheck" id="dinkytoys"><label for="dinkytoys" onclick="toggleLocal()">Ignore Local Images</label></td>
|
||||||
|
</tr>';
|
||||||
|
|
||||||
|
print '<tr>
|
||||||
|
<td colspan="4"></td>
|
||||||
|
<td class="outer styledinputs" align="right"><input type="checkbox" class="topcheck" id="poobag"><label for="poobag" onclick="toggleScrolling()">Follow Progress</label></td>
|
||||||
|
</tr>';
|
||||||
|
?>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="wobblebottom">
|
||||||
|
|
||||||
|
<div id="artistcoverslist" class="tleft noborder">
|
||||||
|
<div class="noselection fullwidth">
|
||||||
|
<?php
|
||||||
|
if ($mysqlc) {
|
||||||
|
print '<div class="containerbox menuitem clickable clickselectartist selected" id="allartists"><div class="expand" class="artistrow">'.get_int_text("albumart_allartists").'</div></div>';
|
||||||
|
print '<div class="containerbox menuitem clickable clickselectartist" id="savedplaylists"><div class="expand" class="artistrow">Saved Playlists</div></div>';
|
||||||
|
print '<div class="containerbox menuitem clickable clickselectartist" id="radio"><div class="expand" class="artistrow">'.get_int_text("label_yourradio").'</div></div>';
|
||||||
|
do_artists_db_style();
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div id="coverslist" class="tleft noborder">
|
||||||
|
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Do Local Albums
|
||||||
|
$count = 0;
|
||||||
|
$albums_without_cover = 0;
|
||||||
|
do_covers_db_style();
|
||||||
|
do_playlists();
|
||||||
|
do_radio_stations();
|
||||||
|
|
||||||
|
print '</div>';
|
||||||
|
|
||||||
|
print "</div>\n";
|
||||||
|
print "</div>\n";
|
||||||
|
print '<script language="JavaScript">'."\n";
|
||||||
|
print 'var numcovers = '.$count.";\n";
|
||||||
|
print 'var albums_without_cover = '.$albums_without_cover.";\n";
|
||||||
|
print "</script>\n";
|
||||||
|
print "</body>\n";
|
||||||
|
print "</html>\n";
|
||||||
|
|
||||||
|
function do_artists_db_style() {
|
||||||
|
$alist = get_list_of_artists();
|
||||||
|
foreach ($alist as $artist) {
|
||||||
|
print '<div class="containerbox menuitem clickable clickselectartist';
|
||||||
|
print '" id="artistname'.$artist['Artistindex'].'">';
|
||||||
|
print '<div class="expand" class="artistrow">'.$artist['Artistname'].'</div>';
|
||||||
|
print '</div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_covers_db_style() {
|
||||||
|
global $count;
|
||||||
|
global $albums_without_cover;
|
||||||
|
$alist = get_list_of_artists();
|
||||||
|
foreach ($alist as $artist) {
|
||||||
|
print '<div class="cheesegrater" name="artistname'.$artist['Artistindex'].'">';
|
||||||
|
print '<div class="albumsection">';
|
||||||
|
print '<div class="tleft"><h2>'.$artist['Artistname'].'</h2></div><div class="tright rightpad"><button class="invisible" onclick="getNewAlbumArt(\'#album'.$count.'\')">'.get_int_text("albumart_getthese").'</button></div>';
|
||||||
|
print "</div>\n";
|
||||||
|
print '<div id="album'.$count.'" class="containerbox fullwidth bigholder wrap">';
|
||||||
|
$blist = get_list_of_albums($artist['Artistindex']);
|
||||||
|
foreach ($blist as $album) {
|
||||||
|
print '<div class="fixed albumimg closet">';
|
||||||
|
print '<div class="covercontainer">';
|
||||||
|
$class = "clickable clickicon clickalbumcover droppable";
|
||||||
|
$src = "";
|
||||||
|
if ($album['Image'] && $album['Image'] !== "") {
|
||||||
|
$src = $album['Image'];
|
||||||
|
} else {
|
||||||
|
$class = $class . " notexist";
|
||||||
|
$albums_without_cover++;
|
||||||
|
}
|
||||||
|
print '<input name="albumpath" type="hidden" value="'.get_album_directory($album['Albumindex'], $album['AlbumUri']).'" />';
|
||||||
|
print '<input name="searchterm" type="hidden" value="'.rawurlencode($artist['Artistname']." ".munge_album_name($album['Albumname'])).'" />';
|
||||||
|
print '<img class="'.$class.'" name="'.$album['ImgKey'].'"';
|
||||||
|
if ($src != "") {
|
||||||
|
print ' src="'.$src.'" ';
|
||||||
|
}
|
||||||
|
print '/>';
|
||||||
|
|
||||||
|
print '<div>'.$album['Albumname'].'</div>';
|
||||||
|
print '</div>';
|
||||||
|
print '</div>';
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
print "</div>\n";
|
||||||
|
print "</div>\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_radio_stations() {
|
||||||
|
|
||||||
|
global $count;
|
||||||
|
global $albums_without_cover;
|
||||||
|
|
||||||
|
$playlists = get_user_radio_streams();
|
||||||
|
if (count($playlists) > 0) {
|
||||||
|
print '<div class="cheesegrater" name="radio">';
|
||||||
|
print '<div class="albumsection">';
|
||||||
|
print '<div class="tleft"><h2>Radio Stations</h2></div><div class="tright rightpad"><button class="invisible" onclick="getNewAlbumArt(\'#album'.$count.'\')">'.get_int_text("albumart_getthese").'</button></div>';
|
||||||
|
print "</div>\n";
|
||||||
|
print '<div id="album'.$count.'" class="containerbox fullwidth bigholder wrap">';
|
||||||
|
foreach ($playlists as $file) {
|
||||||
|
print '<div class="fixed albumimg closet">';
|
||||||
|
print '<div class="covercontainer">';
|
||||||
|
$class = "";
|
||||||
|
$src = "";
|
||||||
|
if ($file['Image']) {
|
||||||
|
$src = $file['Image'];
|
||||||
|
} else {
|
||||||
|
$class = " notexist";
|
||||||
|
$albums_without_cover++;
|
||||||
|
}
|
||||||
|
print '<input name="searchterm" type="hidden" value="'.rawurlencode($file['StationName']).'" />';
|
||||||
|
print '<input name="artist" type="hidden" value="STREAM" />';
|
||||||
|
print '<input name="album" type="hidden" value="'.rawurlencode($file['StationName']).'" />';
|
||||||
|
$albumimage = new baseAlbumImage(array('artist' => 'STREAM', 'album' => $file['StationName']));
|
||||||
|
print '<img class="clickable clickicon clickalbumcover droppable'.$class.'" name="'.$albumimage->get_image_key().'"';
|
||||||
|
if ($src != "") {
|
||||||
|
print ' src="'.$src.'" ';
|
||||||
|
}
|
||||||
|
print '/>';
|
||||||
|
print '<div>'.htmlentities($file['StationName']).'</div>';
|
||||||
|
print '</div>';
|
||||||
|
print '</div>';
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
print "</div>\n";
|
||||||
|
print "</div>\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function do_playlists() {
|
||||||
|
|
||||||
|
global $count;
|
||||||
|
global $albums_without_cover;
|
||||||
|
global $PLAYER_TYPE;
|
||||||
|
logger::log("PLAYLISTART", "Player type is", $PLAYER_TYPE);
|
||||||
|
$player = new $PLAYER_TYPE();
|
||||||
|
|
||||||
|
$playlists = $player->get_stored_playlists(false);
|
||||||
|
if (!is_array($playlists)) {
|
||||||
|
$playlists = array();
|
||||||
|
}
|
||||||
|
$plfiles = glob('prefs/userplaylists/*');
|
||||||
|
foreach ($plfiles as $f) {
|
||||||
|
$playlists[] = basename($f);
|
||||||
|
}
|
||||||
|
print '<div class="cheesegrater" name="savedplaylists">';
|
||||||
|
print '<div class="albumsection">';
|
||||||
|
print '<div class="tleft"><h2>Saved Playlists</h2></div>';
|
||||||
|
print "</div>\n";
|
||||||
|
print '<div id="album'.$count.'" class="containerbox fullwidth bigholder wrap">';
|
||||||
|
sort($playlists, SORT_STRING);
|
||||||
|
foreach ($playlists as $pl) {
|
||||||
|
logger::log("PLAYLISTART", "Playlist",$pl);
|
||||||
|
print '<div class="fixed albumimg closet">';
|
||||||
|
print '<div class="covercontainer">';
|
||||||
|
$class = "";
|
||||||
|
$albumimage = new baseAlbumImage(array('artist' => 'PLAYLIST', 'album' => $pl));
|
||||||
|
$src = $albumimage->get_image_if_exists();
|
||||||
|
if ($src === null) {
|
||||||
|
$class = " plimage notfound";
|
||||||
|
$src = '';
|
||||||
|
$albums_without_cover++;
|
||||||
|
}
|
||||||
|
$plsearch = preg_replace('/ \(by .*?\)$/', '', $pl);
|
||||||
|
print '<input name = "searchterm" type="hidden" value="'.rawurlencode($plsearch).'" />';
|
||||||
|
print '<input name="artist" type="hidden" value="PLAYLIST" />';
|
||||||
|
print '<input name="album" type="hidden" value="'.rawurlencode($pl).'" />';
|
||||||
|
print '<img class="clickable clickicon clickalbumcover droppable playlistimage'.$class.'" name="'.$albumimage->get_image_key().'"';
|
||||||
|
if ($src != "") {
|
||||||
|
print ' src="'.$src.'" ';
|
||||||
|
}
|
||||||
|
print '/>';
|
||||||
|
print '<div>'.htmlentities($pl).'</div>';
|
||||||
|
print '</div>';
|
||||||
|
print '</div>';
|
||||||
|
$count++;
|
||||||
|
}
|
||||||
|
print "</div>\n";
|
||||||
|
print "</div>\n";
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,331 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// Automatic Collection Updates can be performed using cURL:
|
||||||
|
// curl -b "currenthost=Default;player_backend=mpd" http://localhost/rompr/albums.php?rebuild > /dev/null
|
||||||
|
// where currenthost is the name of one of the Players defined in the Configuration menu
|
||||||
|
// and player_backend MUST be mpd or mopidy, depending on what your player is.
|
||||||
|
// You can also use eg -b "debug_enabled=8;currenthost=MPD;player_backend=mpd"
|
||||||
|
// to get more debug info in the webserver error log.
|
||||||
|
|
||||||
|
require_once ("includes/vars.php");
|
||||||
|
require_once ("includes/functions.php");
|
||||||
|
require_once ("utils/imagefunctions.php");
|
||||||
|
require_once ("international.php");
|
||||||
|
require_once ("backends/sql/backend.php");
|
||||||
|
$error = 0;
|
||||||
|
|
||||||
|
logger::trace("TIMINGS", "======================================================================");
|
||||||
|
$initmem = memory_get_usage();
|
||||||
|
logger::trace("COLLECTION", "Memory Used is ".$initmem);
|
||||||
|
$now2 = time();
|
||||||
|
|
||||||
|
switch (true) {
|
||||||
|
|
||||||
|
case array_key_exists('item', $_REQUEST):
|
||||||
|
logit('item');
|
||||||
|
// Populate a dropdown in the collection or search results
|
||||||
|
dumpAlbums($_REQUEST['item']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case array_key_exists('mpdsearch', $_REQUEST):
|
||||||
|
logit('mpdsearch');
|
||||||
|
// Handle an mpd-style search request
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
require_once ("collection/collection.php");
|
||||||
|
$trackbytrack = true;
|
||||||
|
$doing_search = true;
|
||||||
|
mpd_search();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case array_key_exists('browsealbum', $_REQUEST):
|
||||||
|
logit('browsealbum');
|
||||||
|
// Populate a spotify album in mopidy's search results - as spotify doesn't return all tracks
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
require_once ("collection/collection.php");
|
||||||
|
$trackbytrack = true;
|
||||||
|
$doing_search = true;
|
||||||
|
browse_album();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case array_key_exists("rawterms", $_REQUEST):
|
||||||
|
logit('rawterms');
|
||||||
|
// Handle an mpd-style search request requiring tl_track format results
|
||||||
|
// Note that raw_search uses the collection models but not the database
|
||||||
|
// hence $trackbytrack must be false
|
||||||
|
logger::log("MPD SEARCH", "Doing RAW search");
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
require_once ("collection/collection.php");
|
||||||
|
require_once ("collection/dbsearch.php");
|
||||||
|
$doing_search = true;
|
||||||
|
raw_search();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case array_key_exists('terms', $_REQUEST):
|
||||||
|
logit('terms');
|
||||||
|
// SQL database search request
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
require_once ("collection/collection.php");
|
||||||
|
require_once ("collection/dbsearch.php");
|
||||||
|
$doing_search = true;
|
||||||
|
database_search();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case array_key_exists('rebuild', $_REQUEST):
|
||||||
|
logit('rebuild');
|
||||||
|
// This is a request to rebuild the music collection
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
require_once ("collection/collection.php");
|
||||||
|
$trackbytrack = true;
|
||||||
|
update_collection();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger::fail("ALBUMS", "Couldn't figure out what to do!");
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
logger::trace("TIMINGS", "== Collection Update And Send took ".format_time(time() - $now2));
|
||||||
|
$peakmem = memory_get_peak_usage();
|
||||||
|
$ourmem = $peakmem - $initmem;
|
||||||
|
logger::trace("TIMINGS", "Peak Memory Used Was ".number_format($peakmem)." bytes - meaning we used ".number_format($ourmem)." bytes.");
|
||||||
|
logger::trace("TIMINGS", "======================================================================");
|
||||||
|
|
||||||
|
function logit($key) {
|
||||||
|
logger::log("COLLECTION", "Request is",$key,"=",$_REQUEST[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkDomains($d) {
|
||||||
|
if (array_key_exists('domains', $d)) {
|
||||||
|
return $d['domains'];
|
||||||
|
}
|
||||||
|
logger::debug("SEARCH", "No search domains in use");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mpd_search() {
|
||||||
|
global $dbterms, $skin, $PLAYER_TYPE;
|
||||||
|
// If we're searching for tags or ratings it would seem sensible to only search the database
|
||||||
|
// HOWEVER - we could be searching for genre or performer or composer - which will not match in the database
|
||||||
|
// For those cases ONLY, controller.js will call into this instead of database_search, and we set $dbterms
|
||||||
|
// to make the collection check everything it finds against the database
|
||||||
|
$cmd = $_REQUEST['command'];
|
||||||
|
$domains = checkDomains($_REQUEST);
|
||||||
|
foreach ($_REQUEST['mpdsearch'] as $key => $term) {
|
||||||
|
switch ($key) {
|
||||||
|
case 'tag':
|
||||||
|
case 'rating':
|
||||||
|
$dbterms[$key] = $term;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'any':
|
||||||
|
// This makes a search term of 'Madness My Girl' into
|
||||||
|
// search any Madness any My any Girl
|
||||||
|
// which seems to produce better results with Spotify. But probably doesn't with Google Play, which
|
||||||
|
// only uses the first term. Soundcloud concatenates them all back into one term again. What does MPD do?
|
||||||
|
foreach ($term as $t) {
|
||||||
|
$terms = explode(' ',$t);
|
||||||
|
foreach ($terms as $tom) {
|
||||||
|
$cmd .= " ".$key.' "'.format_for_mpd(html_entity_decode(trim($tom))).'"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
foreach ($term as $t) {
|
||||||
|
$cmd .= " ".$key.' "'.format_for_mpd(html_entity_decode(trim($t))).'"';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger::log("MPD SEARCH", "Search command : ".$cmd);
|
||||||
|
if ($_REQUEST['resultstype'] == "tree") {
|
||||||
|
require_once ("player/mpd/filetree.php");
|
||||||
|
require_once ("skins/".$skin."/ui_elements.php");
|
||||||
|
$player = new fileCollector();
|
||||||
|
$player->doFileSearch($cmd, $domains);
|
||||||
|
} else {
|
||||||
|
cleanSearchTables();
|
||||||
|
prepareCollectionUpdate();
|
||||||
|
$collection = new musicCollection();
|
||||||
|
$player = new $PLAYER_TYPE();
|
||||||
|
$player->populate_collection($cmd, $domains, $collection);
|
||||||
|
$collection->tracks_to_database();
|
||||||
|
close_transaction();
|
||||||
|
dumpAlbums($_REQUEST['dump']);
|
||||||
|
remove_findtracks();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function browse_album() {
|
||||||
|
global $PLAYER_TYPE, $skin;
|
||||||
|
$a = preg_match('/(a|b)(.*?)(\d+|root)/', $_REQUEST['browsealbum'], $matches);
|
||||||
|
if (!$a) {
|
||||||
|
print '<h3>'.get_int_text("label_general_error").'</h3>';
|
||||||
|
logger::error("DUMPALBUMS", "Browse Album Failed - regexp failed to match", $_REQUEST['browsealbum']);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$why = $matches[1];
|
||||||
|
$what = $matches[2];
|
||||||
|
$who = $matches[3];
|
||||||
|
$albumlink = get_albumlink($who);
|
||||||
|
if (substr($albumlink, 0, 8) == 'podcast+') {
|
||||||
|
require_once ('includes/podcastfunctions.php');
|
||||||
|
logger::log("ALBUMS", "Browsing For Podcast ".substr($albumlink, 9));
|
||||||
|
$podid = getNewPodcast(substr($albumlink, 8), 0, false);
|
||||||
|
logger::trace("ALBUMS", "Ouputting Podcast ID ".$podid);
|
||||||
|
outputPodcast($podid, false);
|
||||||
|
} else {
|
||||||
|
if (preg_match('/^.+?:artist:/', $albumlink)) {
|
||||||
|
remove_album_from_database($who);
|
||||||
|
}
|
||||||
|
$player = new $PLAYER_TYPE();
|
||||||
|
$collection = new musicCollection();
|
||||||
|
$cmd = 'find file "'.$albumlink.'"';
|
||||||
|
logger::log("MPD", "Doing Album Browse : ".$cmd);
|
||||||
|
prepareCollectionUpdate();
|
||||||
|
$player->populate_collection($cmd, false, $collection);
|
||||||
|
$collection->tracks_to_database(true);
|
||||||
|
close_transaction();
|
||||||
|
remove_findtracks();
|
||||||
|
if (preg_match('/^.+?:album:/', $albumlink)) {
|
||||||
|
// Just occasionally, the spotify album originally returned by search has an incorrect AlbumArtist
|
||||||
|
// When we browse the album the new tracks therefore get added to a new album, while the original tracks
|
||||||
|
// remain attached to the old one. This is where we use do_tracks_from_database with an array of albumids
|
||||||
|
// which joins them together into a virtual album, with the track ordering correct
|
||||||
|
print do_tracks_from_database($why, $what, find_justadded_albums(), true);
|
||||||
|
} else {
|
||||||
|
$artistarray = find_justadded_artists();
|
||||||
|
$do_controlheader = true;
|
||||||
|
foreach ($artistarray as $artistid) {
|
||||||
|
do_albums_from_database($why, 'album', $artistid, false, false, true, $do_controlheader);
|
||||||
|
$do_controlheader = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function raw_search() {
|
||||||
|
global $PLAYER_TYPE, $doing_search;
|
||||||
|
$domains = checkDomains($_REQUEST);
|
||||||
|
$collection = new musicCollection();
|
||||||
|
$found = 0;
|
||||||
|
logger::trace("MPD SEARCH", "checkdb is ".$_REQUEST['checkdb']);
|
||||||
|
if ($_REQUEST['checkdb'] !== 'false') {
|
||||||
|
logger::trace("MPD SEARCH", " ... checking database first ");
|
||||||
|
$found = doDbCollection($_REQUEST['rawterms'], $domains, "RAW", $collection);
|
||||||
|
if ($found > 0) {
|
||||||
|
logger::log("MPD SEARCH", " ... found ".$found." matches in database");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($found == 0) {
|
||||||
|
$cmd = $_REQUEST['command'];
|
||||||
|
foreach ($_REQUEST['rawterms'] as $key => $term) {
|
||||||
|
$cmd .= " ".$key.' "'.format_for_mpd(html_entity_decode($term[0])).'"';
|
||||||
|
}
|
||||||
|
logger::log("MPD SEARCH", "Search command : ".$cmd);
|
||||||
|
$doing_search = true;
|
||||||
|
$player = new $PLAYER_TYPE();
|
||||||
|
$player->populate_collection($cmd, $domains, $collection);
|
||||||
|
|
||||||
|
// For backends that don't support multiple parameters (Google Play)
|
||||||
|
// This'll return nothing for Spotify, so it's OK. It might help SoundCloud too.
|
||||||
|
|
||||||
|
$cmd = $_REQUEST['command'].' any ';
|
||||||
|
$parms = array();
|
||||||
|
if (array_key_exists('artist', $_REQUEST['rawterms'])) {
|
||||||
|
$parms[] = format_for_mpd(html_entity_decode($_REQUEST['rawterms']['artist'][0]));
|
||||||
|
}
|
||||||
|
if (array_key_exists('title', $_REQUEST['rawterms'])) {
|
||||||
|
$parms[] = format_for_mpd(html_entity_decode($_REQUEST['rawterms']['title'][0]));
|
||||||
|
}
|
||||||
|
if (count($parms) > 0) {
|
||||||
|
$cmd .= '"'.implode(' ',$parms).'"';
|
||||||
|
logger::log("MPD SEARCH", "Search command : ".$cmd);
|
||||||
|
$doing_search = true;
|
||||||
|
$collection->filter_duplicate_tracks();
|
||||||
|
$player->populate_collection($cmd, $domains, $collection);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
print json_encode($collection->tracks_as_array());
|
||||||
|
}
|
||||||
|
|
||||||
|
function database_search() {
|
||||||
|
$tree = null;
|
||||||
|
$domains = checkDomains($_REQUEST);
|
||||||
|
if ($_REQUEST['resultstype'] == "tree") {
|
||||||
|
$tree = new mpdlistthing(null);
|
||||||
|
} else {
|
||||||
|
cleanSearchTables();
|
||||||
|
open_transaction();
|
||||||
|
}
|
||||||
|
$fcount = doDbCollection($_REQUEST['terms'], $domains, $_REQUEST['resultstype'], $tree);
|
||||||
|
if ($_REQUEST['resultstype'] == "tree") {
|
||||||
|
printFileSearch($tree, $fcount);
|
||||||
|
} else {
|
||||||
|
close_transaction();
|
||||||
|
dumpAlbums($_REQUEST['dump']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function update_collection() {
|
||||||
|
global $PLAYER_TYPE;
|
||||||
|
|
||||||
|
// Check that an update is not currently in progress
|
||||||
|
// and create the update lock if not
|
||||||
|
if (collectionUpdateRunning()) {
|
||||||
|
header('HTTP/1.1 500 Internal Server Error');
|
||||||
|
print get_int_text('error_nocol');
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file_exists('prefs/monitor')) {
|
||||||
|
unlink('prefs/monitor');
|
||||||
|
}
|
||||||
|
// Send some dummy data back to the browser, then close the connection
|
||||||
|
// so that the browser doesn't time out and retry
|
||||||
|
$sapi_type = php_sapi_name();
|
||||||
|
logger::log('COLLECTION','SAPI Name is',$sapi_type);
|
||||||
|
if (preg_match('/fpm/', $sapi_type) || preg_match('/fcgi/', $sapi_type)) {
|
||||||
|
logger::mark('COLLECTION', 'Closing Request The FastCGI Way');
|
||||||
|
print('<html></html>');
|
||||||
|
fastcgi_finish_request();
|
||||||
|
} else {
|
||||||
|
logger::mark('COLLECTION', 'Closing Request The Apache Way');
|
||||||
|
ob_end_clean();
|
||||||
|
ignore_user_abort(true); // just to be safe
|
||||||
|
ob_start();
|
||||||
|
print('<html></html>');
|
||||||
|
$size = ob_get_length();
|
||||||
|
header("Content-Length: $size");
|
||||||
|
header("Content-Encoding: none");
|
||||||
|
header("Connection: close");
|
||||||
|
ob_end_flush();
|
||||||
|
ob_flush();
|
||||||
|
flush();
|
||||||
|
if (ob_get_contents()) {
|
||||||
|
ob_end_clean();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (session_id()) {
|
||||||
|
session_write_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Browser is now happy. Now we can do our work in peace.
|
||||||
|
cleanSearchTables();
|
||||||
|
prepareCollectionUpdate();
|
||||||
|
$player = new $PLAYER_TYPE();
|
||||||
|
$player->musicCollectionUpdate();
|
||||||
|
tidy_database();
|
||||||
|
remove_findtracks();
|
||||||
|
// Add a marker to the monitor file to say we've finished
|
||||||
|
$player->collectionUpdateDone();
|
||||||
|
// Clear the update lock
|
||||||
|
clearUpdateLock();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,301 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$mysqlc = null;
|
||||||
|
if (array_key_exists('collection_type', $prefs)) {
|
||||||
|
include("backends/sql/".$prefs['collection_type']."/specifics.php");
|
||||||
|
}
|
||||||
|
|
||||||
|
function probe_database() {
|
||||||
|
// In the case where collection_type is not set, probe to see which type of DB to use
|
||||||
|
// This keeps the behaviour the same as previous versions which auto-detected
|
||||||
|
// the database type. This does mean we get some duplicate code but this is
|
||||||
|
// so much better for the user.
|
||||||
|
global $mysqlc, $prefs;
|
||||||
|
logger::mark("SQL_CONNECT", "Probing Database Type");
|
||||||
|
logger::log("SQL_CONNECT", "Attempting to connect to MYSQL Server");
|
||||||
|
try {
|
||||||
|
if (is_numeric($prefs['mysql_port'])) {
|
||||||
|
logger::trace("SQL_CONNECT", "Connecting using hostname and port");
|
||||||
|
$dsn = "mysql:host=".$prefs['mysql_host'].";port=".$prefs['mysql_port'].";dbname=".$prefs['mysql_database'];
|
||||||
|
} else {
|
||||||
|
logger::trace("SQL_CONNECT", "Connecting using unix socket");
|
||||||
|
$dsn = "mysql:unix_socket=".$prefs['mysql_port'].";dbname=".$prefs['mysql_database'];
|
||||||
|
}
|
||||||
|
$mysqlc = new PDO($dsn, $prefs['mysql_user'], $prefs['mysql_password']);
|
||||||
|
logger::mark("SQL_CONNECT", "Connected to MySQL");
|
||||||
|
$prefs['collection_type'] = 'mysql';
|
||||||
|
} catch (Exception $e) {
|
||||||
|
logger::warn("SQL_CONNECT", "Couldn't connect to MySQL - ".$e);
|
||||||
|
$mysqlc = null;
|
||||||
|
}
|
||||||
|
if ($mysqlc == null) {
|
||||||
|
logger::log("SQL_CONNECT", "Attempting to use SQLite Database");
|
||||||
|
try {
|
||||||
|
$dsn = "sqlite:prefs/collection.sq3";
|
||||||
|
$mysqlc = new PDO($dsn);
|
||||||
|
logger::mark("MYSQL", "Connected to SQLite");
|
||||||
|
$prefs['collection_type'] = 'sqlite';
|
||||||
|
} catch (Exception $e) {
|
||||||
|
logger::fail("MYSQL", "Couldn't use SQLite Either - ".$e);
|
||||||
|
$mysqlc = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Initialisation
|
||||||
|
//
|
||||||
|
|
||||||
|
function show_sql_error($text = "", $stmt = null) {
|
||||||
|
global $mysqlc;
|
||||||
|
logger::error("MYSQL ERROR", $text,":",$mysqlc->errorInfo()[1],":",$mysqlc->errorInfo()[2]);
|
||||||
|
if ($stmt !== null) {
|
||||||
|
logger::error("STMT ERROR", $text,":",$stmt->errorInfo()[1],":",$stmt->errorInfo()[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Queries
|
||||||
|
//
|
||||||
|
|
||||||
|
function generic_sql_query($qstring, $return_boolean = false, $return_type = PDO::FETCH_ASSOC, $return_value = null, $value_default = null, $return_rowcount = false ) {
|
||||||
|
global $mysqlc;
|
||||||
|
logger::debug("GENERIC_SQL", $qstring);
|
||||||
|
$retval = true;
|
||||||
|
if (($result = @$mysqlc->query($qstring)) !== false) {
|
||||||
|
logger::debug("GENERIC_SQL", "Done : ".($result->rowCount())." rows affected");
|
||||||
|
if ($return_value !== null) {
|
||||||
|
$arr = $result->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$retval = ($arr) ? $arr[$return_value] : $value_default;
|
||||||
|
} else if ($return_boolean) {
|
||||||
|
$retval = true;
|
||||||
|
} else if ($return_rowcount) {
|
||||||
|
return $result->rowCount();
|
||||||
|
} else {
|
||||||
|
$retval = $result->fetchAll($return_type);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::warn("GENERIC_SQL", "Command Failed :",$qstring);
|
||||||
|
show_sql_error();
|
||||||
|
if ($return_value !== null) {
|
||||||
|
$retval = $value_default;
|
||||||
|
} else if ($return_boolean) {
|
||||||
|
$retval = false;
|
||||||
|
} else {
|
||||||
|
$retval = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$result = null;
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_get_column($qstring, $column) {
|
||||||
|
global $mysqlc;
|
||||||
|
logger::debug("SQL_GET_COLUMN", "Get column",$column,"from",$qstring);
|
||||||
|
$retval = array();
|
||||||
|
if (($result = $mysqlc->query($qstring)) !== false) {
|
||||||
|
$retval = $result->fetchAll(PDO::FETCH_COLUMN, $column);
|
||||||
|
}
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function simple_query($select, $from, $where, $item, $default) {
|
||||||
|
$retval = $default;
|
||||||
|
$qstring = "SELECT ".$select." AS TheThingToFind FROM ".$from;
|
||||||
|
if ($where != null) {
|
||||||
|
$qstring .= " WHERE ".$where." = ?";
|
||||||
|
}
|
||||||
|
$retval = sql_prepare_query(false, null, 'TheThingToFind', $default, $qstring, $item);
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_prepare_query() {
|
||||||
|
// Variable arguments but at least 5 are required:
|
||||||
|
// 1. flag for whether to just return a boolean
|
||||||
|
// 2. return type
|
||||||
|
// 3. field name
|
||||||
|
// 4. default value for field name
|
||||||
|
// 5. query string
|
||||||
|
// ... parameters for query
|
||||||
|
// return type of PDO::FETCH_COLUMN returns an array of the values
|
||||||
|
// from the column identified by field name
|
||||||
|
// --**-- NO PARAMETER CHECKING IS DONE BY THIS FUNCTION! --**--
|
||||||
|
// because we want to make it fast, so make sure you call it right!
|
||||||
|
|
||||||
|
// This doesn't appear to work with MySQL when one of the args has to be an integer
|
||||||
|
// eg LIMIT ? doesn't work.
|
||||||
|
|
||||||
|
global $mysqlc;
|
||||||
|
$allargs = func_get_args();
|
||||||
|
logger::debug("SQL_PREPARE",$allargs);
|
||||||
|
$return_boolean = $allargs[0];
|
||||||
|
$return_type = $allargs[1];
|
||||||
|
$return_value = $allargs[2];
|
||||||
|
$value_default = $allargs[3];
|
||||||
|
$query = $allargs[4];
|
||||||
|
if (is_array($allargs[5])) {
|
||||||
|
$args = $allargs[5];
|
||||||
|
} else {
|
||||||
|
$args = array_slice($allargs, 5);
|
||||||
|
}
|
||||||
|
|
||||||
|
$stmt = $mysqlc->prepare($query);
|
||||||
|
if ($stmt !== false) {
|
||||||
|
if ($stmt->execute($args)) {
|
||||||
|
if ($return_type == PDO::FETCH_COLUMN) {
|
||||||
|
$retval = $stmt->fetchAll(PDO::FETCH_COLUMN, $return_value);
|
||||||
|
} else if ($return_value !== null) {
|
||||||
|
$arr = $stmt->fetch(PDO::FETCH_ASSOC);
|
||||||
|
$retval = ($arr) ? $arr[$return_value] : $value_default;
|
||||||
|
} else if ($return_boolean) {
|
||||||
|
$retval = true;
|
||||||
|
} else {
|
||||||
|
$retval = $stmt->fetchAll($return_type);
|
||||||
|
}
|
||||||
|
$stmt = null;
|
||||||
|
return $retval;
|
||||||
|
} else {
|
||||||
|
show_sql_error("SQL Statement Error for",$stmt);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
show_sql_error();
|
||||||
|
}
|
||||||
|
if ($return_value !== null) {
|
||||||
|
$retval = $value_default;
|
||||||
|
} else if ($return_boolean) {
|
||||||
|
$retval = false;
|
||||||
|
} else {
|
||||||
|
$retval = array();
|
||||||
|
}
|
||||||
|
$stmt = null;
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_prepare_query_later($query) {
|
||||||
|
global $mysqlc;
|
||||||
|
$stmt = $mysqlc->prepare($query);
|
||||||
|
if ($stmt === FALSE) {
|
||||||
|
show_sql_error();
|
||||||
|
}
|
||||||
|
return $stmt;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Debug function for prepared statement
|
||||||
|
function dbg_params($string,$data) {
|
||||||
|
$indexed = $data==array_values($data);
|
||||||
|
|
||||||
|
foreach($data as $k=>$v) {
|
||||||
|
if (is_string($v)) {
|
||||||
|
$v = "'$v'";
|
||||||
|
}
|
||||||
|
if($indexed) {
|
||||||
|
$string = preg_replace('/\?/', $v, $string, 1);
|
||||||
|
} else {
|
||||||
|
$string=str_replace(":$k", $v, $string);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $string;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkCollectionStatus() {
|
||||||
|
$lv = generic_sql_query("SELECT Value FROM Statstable WHERE Item = 'ListVersion'", false, null, 'Value', null);
|
||||||
|
if ($lv == ROMPR_COLLECTION_VERSION) {
|
||||||
|
logger::log("MYSQL", "Collection version is correct");
|
||||||
|
return "0";
|
||||||
|
} else {
|
||||||
|
if ($lv > 0) {
|
||||||
|
logger::warn("MYSQL", "Collection version is outdated - ".$lv);
|
||||||
|
return "1";
|
||||||
|
} else {
|
||||||
|
logger::shout("MYSQL", "Collection has not been built".$lv);
|
||||||
|
return "2";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkAlbumArt() {
|
||||||
|
$oa = generic_sql_query("SELECT COUNT(ImgVersion) AS NumOldAlbums FROM Albumtable WHERE Image LIKE 'albumart/small/%' AND ImgVersion < ".ROMPR_IMAGE_VERSION, false, null, 'NumOldAlbums', 0);
|
||||||
|
logger::log("INIT", "There are ".$oa." albums with old-style album art");
|
||||||
|
return $oa;
|
||||||
|
}
|
||||||
|
|
||||||
|
function open_transaction() {
|
||||||
|
global $transaction_open, $mysqlc;
|
||||||
|
if (!$transaction_open) {
|
||||||
|
if ($mysqlc->beginTransaction()) {
|
||||||
|
$transaction_open = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_transaction() {
|
||||||
|
global $numdone, $transaction_open;
|
||||||
|
if ($transaction_open) {
|
||||||
|
if ($numdone >= ROMPR_MAX_TRACKS_PER_TRANSACTION) {
|
||||||
|
close_transaction();
|
||||||
|
open_transaction();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::warn("BACKEND", "WARNING! check_transaction called when transaction not open!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close_transaction() {
|
||||||
|
global $transaction_open, $numdone, $mysqlc;
|
||||||
|
if ($transaction_open) {
|
||||||
|
if ($mysqlc->commit()) {
|
||||||
|
$transaction_open = false;
|
||||||
|
$numdone = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::warn("BACKEND", "WARNING! close_transaction called when transaction not open!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function saveCollectionPlayer($type) {
|
||||||
|
global $prefs;
|
||||||
|
logger::mark("COLLECTION", "Setting Collection Type to",$type);
|
||||||
|
switch ($type) {
|
||||||
|
case 'mopidy':
|
||||||
|
sql_prepare_query(true, null, null, null,
|
||||||
|
"UPDATE Statstable SET Value = ? WHERE Item = 'CollType'", 1);
|
||||||
|
$prefs['collection_player'] = 'mopidy';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'mpd':
|
||||||
|
sql_prepare_query(true, null, null, null,
|
||||||
|
"UPDATE Statstable SET Value = ? WHERE Item = 'CollType'", 0);
|
||||||
|
$prefs['collection_player'] = 'mpd';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
savePrefs();
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCollectionPlayer($sp = treu) {
|
||||||
|
global $prefs;
|
||||||
|
$c = simple_query('Value', 'Statstable', 'Item', 'CollType', 999);
|
||||||
|
switch ($c) {
|
||||||
|
case 999:
|
||||||
|
logger::trace("COLLECTION", "Collection type from database is not set");
|
||||||
|
logger::trace("COLLECTION", "Prefs collection_player is currently",$prefs['collection_player']);
|
||||||
|
$prefs['collection_player'] = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
logger::debug("COLLECTION", "Collection type from database is mopidy");
|
||||||
|
$prefs['collection_player'] = 'mopidy';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0:
|
||||||
|
logger::debug("COLLECTION", "Collection type from database is mpd");
|
||||||
|
$prefs['collection_player'] = 'mpd';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ($sp) {
|
||||||
|
savePrefs();
|
||||||
|
}
|
||||||
|
return $c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,878 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class romprmetadata {
|
||||||
|
|
||||||
|
public static function sanitise_data(&$data) {
|
||||||
|
|
||||||
|
foreach (array( 'action',
|
||||||
|
'title',
|
||||||
|
'artist',
|
||||||
|
'trackno',
|
||||||
|
'duration',
|
||||||
|
'albumuri',
|
||||||
|
'image',
|
||||||
|
'album',
|
||||||
|
'uri',
|
||||||
|
'trackai',
|
||||||
|
'albumai',
|
||||||
|
'albumindex',
|
||||||
|
'searched',
|
||||||
|
'lastmodified',
|
||||||
|
'streamname',
|
||||||
|
'streamimage',
|
||||||
|
'streamuri',
|
||||||
|
'type',
|
||||||
|
'ambid',
|
||||||
|
'isaudiobook',
|
||||||
|
'attributes',
|
||||||
|
'imagekey',
|
||||||
|
'which',
|
||||||
|
'wltrack',
|
||||||
|
'reqid') as $key) {
|
||||||
|
if (!array_key_exists($key, $data)) {
|
||||||
|
$data[$key] = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach (array( 'trackno', 'duration', 'isaudiobook') as $key) {
|
||||||
|
if ($data[$key] == null) {
|
||||||
|
$data[$key] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$data['albumartist'] = array_key_exists('albumartist', $data) ? $data['albumartist'] : $data['artist'];
|
||||||
|
$data['date'] = (array_key_exists('date', $data) && $data['date'] != 0) ? getYear($data['date']) : null;
|
||||||
|
$data['urionly'] = array_key_exists('urionly', $data) ? true : false;
|
||||||
|
$data['disc'] = array_key_exists('disc', $data) ? $data['disc'] : 1;
|
||||||
|
$data['domain'] = array_key_exists('domain', $data) ? $data['domain'] : ($data['uri'] === null ? "local" : getDomain($data['uri']));
|
||||||
|
$data['hidden'] = 0;
|
||||||
|
$data['searchflag'] = 0;
|
||||||
|
if (substr($data['image'],0,4) == "http") {
|
||||||
|
$data['image'] = "getRemoteImage.php?url=".$data['image'];
|
||||||
|
}
|
||||||
|
if ($data['imagekey'] === null) {
|
||||||
|
$albumimage = new baseAlbumImage(array(
|
||||||
|
'artist' => artist_for_image($data['type'], $data['albumartist']),
|
||||||
|
'album' => $data['album']
|
||||||
|
));
|
||||||
|
$data['imagekey'] = $albumimage->get_image_key();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function set($data, $keep_wishlist = false) {
|
||||||
|
global $returninfo;
|
||||||
|
if ($data['artist'] === null ||
|
||||||
|
$data['title'] === null ||
|
||||||
|
$data['attributes'] == null) {
|
||||||
|
logger::error("USERRATING", "Something is not set", $data);
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
print json_encode(array('error' => 'Artist or Title or Attributes not set'));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($data['artist']) {
|
||||||
|
case 'geturisfordir':
|
||||||
|
$ttids = romprmetadata::geturisfordir($data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'geturis':
|
||||||
|
$ttids = romprmetadata::geturis($data);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$ttids = romprmetadata::find_item($data, forcedUriOnly($data['urionly'], getDomain($data['uri'])));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newttids = array();
|
||||||
|
foreach ($ttids as $ttid) {
|
||||||
|
if ($keep_wishlist || !track_is_wishlist($ttid)) {
|
||||||
|
$newttids[] = $ttid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$ttids = $newttids;
|
||||||
|
|
||||||
|
if (count($ttids) == 0) {
|
||||||
|
$ttids[0] = create_new_track($data);
|
||||||
|
logger::log("USERRATINGS", "Created New Track with TTindex ".$ttids[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($ttids) > 0) {
|
||||||
|
if (romprmetadata::doTheSetting($ttids, $data['attributes'], $data['uri'])) {
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 417 Expectation Failed');
|
||||||
|
$returninfo['error'] = 'Setting attributes failed';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::fail("USERRATING", "TTID Not Found");
|
||||||
|
header('HTTP/1.1 417 Expectation Failed');
|
||||||
|
$returninfo['error'] = 'TTindex not found';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function add($data, $urionly = true) {
|
||||||
|
// This is used for adding specific tracks so we need urionly to be true
|
||||||
|
// We don't simply call into this using 'set' with urionly set to true
|
||||||
|
// because that might result in the rating being changed
|
||||||
|
|
||||||
|
// The only time we call inot this with $urionly set to false is when we're restoring a metadata
|
||||||
|
// backup. In that case we might be copying data from one setup to another and we might have
|
||||||
|
// the track already in local, so we don't want to add duplicates. Neither way is perfect but
|
||||||
|
// this makes most sense I think.
|
||||||
|
|
||||||
|
global $returninfo;
|
||||||
|
$ttids = romprmetadata::find_item($data, $urionly);
|
||||||
|
|
||||||
|
// As we check by URI we can only have one result.
|
||||||
|
$ttid = null;
|
||||||
|
if (count($ttids) > 0) {
|
||||||
|
$ttid = $ttids[0];
|
||||||
|
if (track_is_hidden($ttid) || track_is_searchresult($ttid)) {
|
||||||
|
logger::mark("USERRATINGS", "Track ".$ttid." being added is a search result or a hidden track");
|
||||||
|
// Setting attributes (Rating: 0) will unhide/un-searchify it. Ratings of 0 are got rid of
|
||||||
|
// by remove_cruft at the end, because they're meaningless
|
||||||
|
if ($data['attributes'] == null) {
|
||||||
|
$data['attributes'] = array(array('attribute' => 'Rating', 'value'=> 0));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::warn("USERRATINGS", "Track being added already exists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
check_for_wishlist_track($data);
|
||||||
|
|
||||||
|
if ($ttid == null) {
|
||||||
|
logger::log("USERRATINGS", "Creating Track being added");
|
||||||
|
$ttid = create_new_track($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
romprmetadata::doTheSetting(array($ttid), $data['attributes'], $data['uri']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function inc($data) {
|
||||||
|
global $returninfo;
|
||||||
|
// NOTE : 'inc' does not do what you might expect.
|
||||||
|
// This is not an 'increment' function, it still does a SET but it will create a hidden track
|
||||||
|
// if the track can't be found, compare to SET which creates a new unhidden track.
|
||||||
|
if ($data['artist'] === null ||
|
||||||
|
$data['title'] === null ||
|
||||||
|
$data['attributes'] == null) {
|
||||||
|
logger::error("USERRATING", "Something is not set",$data);
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
print json_encode(array('error' => 'Artist or Title or Attributes not set'));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
$ttids = romprmetadata::find_item($data, forcedUriOnly(false,getDomain($data['uri'])));
|
||||||
|
if (count($ttids) == 0) {
|
||||||
|
logger::log("USERRATING", "Doing an INCREMENT action - Found NOTHING so creating hidden track");
|
||||||
|
$data['hidden'] = 1;
|
||||||
|
$ttids[0] = create_new_track($data);
|
||||||
|
}
|
||||||
|
|
||||||
|
romprmetadata::checkLastPlayed($data);
|
||||||
|
|
||||||
|
if (count($ttids) > 0) {
|
||||||
|
foreach ($ttids as $ttid) {
|
||||||
|
logger::trace("USERRATING", "Doing an INCREMENT action - Found TTID ",$ttid);
|
||||||
|
foreach ($data['attributes'] as $pair) {
|
||||||
|
logger::log("USERRATING", "(Increment) Setting",$pair["attribute"],"to",$pair["value"],"on",$ttid);
|
||||||
|
romprmetadata::increment_value($ttid, $pair["attribute"], $pair["value"], $data['lastplayed']);
|
||||||
|
}
|
||||||
|
$returninfo['metadata'] = get_all_data($ttid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $ttids;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function checkLastPlayed(&$data) {
|
||||||
|
if (array_key_exists('lastplayed', $data)) {
|
||||||
|
if (is_numeric($data['lastplayed'])) {
|
||||||
|
// Convert timestamp from LastFM into MySQL TIMESTAMP format
|
||||||
|
$data['lastplayed'] = date('Y-m-d H:i:s', $data['lastplayed']);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$data['lastplayed'] = date('Y-m-d H:i:s');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function syncinc($data) {
|
||||||
|
global $returninfo;
|
||||||
|
if ($data['artist'] === null ||
|
||||||
|
$data['title'] === null ||
|
||||||
|
$data['attributes'] == null) {
|
||||||
|
logger::error("SYNCINC", "Something is not set", $data);
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
print json_encode(array('error' => 'Artist or Title or Attributes not set'));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$ttids = romprmetadata::find_item($data, forcedUriOnly(false,getDomain($data['uri'])));
|
||||||
|
if (count($ttids) == 0) {
|
||||||
|
$ttids = romprmetadata::inc($data);
|
||||||
|
romprmetadata::resetSyncCounts($ttids);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
romprmetadata::checkLastPlayed($data);
|
||||||
|
logger::log("SYNCINC", "LastPlayed is ".$data['lastplayed']);
|
||||||
|
foreach ($ttids as $ttid) {
|
||||||
|
logger::log("SYNCINC", "Doing a SYNC action on TTID ".$ttid);
|
||||||
|
$rowcount = generic_sql_query("UPDATE Playcounttable SET SyncCount = SyncCount - 1, LastPlayed = '".$data['lastplayed']."' WHERE TTindex = ".$ttid." AND SyncCount > 0",
|
||||||
|
false, null, null, null, true);
|
||||||
|
if ($rowcount > 0) {
|
||||||
|
logger::log("SYNCINC", " Decremented sync counter for this track");
|
||||||
|
} else {
|
||||||
|
$rowcount = generic_sql_query("UPDATE Playcounttable SET Playcount = Playcount + 1, LastPlayed = '".$data['lastplayed']."' WHERE TTindex = ".$ttid,
|
||||||
|
false, null, null, null, true);
|
||||||
|
if ($rowcount > 0) {
|
||||||
|
logger::log("SYNCINC", " Incremented Playcount for this track");
|
||||||
|
// At this point, SyncCount must have been zero but the update will have incremented it again,
|
||||||
|
// because of the trigger. resetSyncCounts takes care of this;
|
||||||
|
} else {
|
||||||
|
logger::log("SYNCINC", " Track not found in Playcounttable");
|
||||||
|
$metadata = get_all_data($ttid);
|
||||||
|
romprmetadata::increment_value($ttid, 'Playcount', $metadata['Playcount'] + 1, $data['lastplayed']);
|
||||||
|
// At this point, SyncCount must have been zero but the update will have incremented it again,
|
||||||
|
// because of the trigger. resetSyncCounts takes care of this;
|
||||||
|
}
|
||||||
|
romprmetadata::resetSyncCounts(array($ttid));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function resetSyncCounts($ttids) {
|
||||||
|
foreach ($ttids as $ttid) {
|
||||||
|
generic_sql_query("UPDATE Playcounttable SET SyncCount = 0 WHERE TTindex = ".$ttid, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function resetallsyncdata() {
|
||||||
|
generic_sql_query('UPDATE Playcounttable SET SyncCount = 0 WHERE TTindex > 0', true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function remove($data) {
|
||||||
|
global $returninfo;
|
||||||
|
if ($data['artist'] === null || $data['title'] === null) {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
print json_encode(array('error' => 'Artist or Title not set'));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
$ttids = romprmetadata::find_item($data, forcedUriOnly($data['urionly'], getDomain($data['uri'])));
|
||||||
|
if (count($ttids) > 0) {
|
||||||
|
foreach ($ttids as $ttid) {
|
||||||
|
$result = true;
|
||||||
|
foreach ($data['attributes'] as $pair) {
|
||||||
|
logger::trace("USERRATING", "Removing",$pair);
|
||||||
|
$r = romprmetadata::remove_tag($ttid, $pair["value"]);
|
||||||
|
if ($r == false) {
|
||||||
|
logger::fail("USERRATING", "FAILED Removing",$pair);
|
||||||
|
$result = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($result) {
|
||||||
|
$returninfo['metadata'] = get_all_data($ttid);
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 417 Expectation Failed');
|
||||||
|
$returninfo['error'] = 'Removing attributes failed';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::fail("USERRATING", "TTID Not Found");
|
||||||
|
header('HTTP/1.1 417 Expectation Failed');
|
||||||
|
$returninfo['error'] = 'TTindex not found';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get($data) {
|
||||||
|
global $returninfo, $nodata;
|
||||||
|
if ($data['artist'] === null || $data['title'] === null) {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
print json_encode(array('error' => 'Artist or Title not set'));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
$ttids = romprmetadata::find_item($data, forcedUriOnly(false, getDomain($data['uri'])));
|
||||||
|
if (count($ttids) > 0) {
|
||||||
|
$ttid = array_shift($ttids);
|
||||||
|
$returninfo = get_all_data($ttid);
|
||||||
|
} else {
|
||||||
|
$returninfo = $nodata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function setalbummbid($data) {
|
||||||
|
global $returninfo, $nodata;
|
||||||
|
$ttids = romprmetadata::find_item($data, forcedUriOnly(false, getDomain($data['uri'])));
|
||||||
|
if (count($ttids) > 0) {
|
||||||
|
foreach ($ttids as $ttid) {
|
||||||
|
logger::log("BACKEND", "Updating album MBID ".$data['attributes']." from TTindex ".$ttid);
|
||||||
|
$albumindex = simple_query('Albumindex', 'Tracktable', 'TTindex', $ttid, null);
|
||||||
|
logger::trace("BACKEND", " .. album index is ".$albumindex);
|
||||||
|
sql_prepare_query(true, null, null, null, "UPDATE Albumtable SET mbid = ? WHERE Albumindex = ? AND mbid IS NULL",$data['attributes'],$albumindex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$returninfo = $nodata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function cleanup($data) {
|
||||||
|
logger::log("SQL", "Doing Database Cleanup And Stats Update");
|
||||||
|
remove_cruft();
|
||||||
|
update_track_stats();
|
||||||
|
doCollectionHeader();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function amendalbum($data) {
|
||||||
|
if ($data['albumindex'] !== null && romprmetadata::amend_album($data['albumindex'], $data['albumartist'], $data['date'])) {
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
$returninfo['error'] = 'That just did not work';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function deletetag($data) {
|
||||||
|
if (romprmetadata::remove_tag_from_db($data['value'])) {
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
$returninfo['error'] = 'Well, that went well';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function delete($data) {
|
||||||
|
$ttids = romprmetadata::find_item($data, true);
|
||||||
|
if (count($ttids) == 0) {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
$returninfo['error'] = 'TTindex not found';
|
||||||
|
} else {
|
||||||
|
romprmetadata::delete_track(array_shift($ttids));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function deletewl($data) {
|
||||||
|
romprmetadata::delete_track($data['wltrack']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function deleteid($data) {
|
||||||
|
romprmetadata::delete_track($data['ttid']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getcharts($data) {
|
||||||
|
global $returninfo;
|
||||||
|
$returninfo['Artists'] = get_artist_charts();
|
||||||
|
$returninfo['Albums'] = get_album_charts();
|
||||||
|
$returninfo['Tracks'] = get_track_charts();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function clearwishlist() {
|
||||||
|
logger::log("MONKEYS", "Removing Wishlist Tracks");
|
||||||
|
if (clear_wishlist()) {
|
||||||
|
logger::log("MONKEYS", " ... Success!");
|
||||||
|
} else {
|
||||||
|
logger::warn("MONKEYS", "Failed removing wishlist tracks");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Private Functions
|
||||||
|
|
||||||
|
static function geturisfordir($data) {
|
||||||
|
global $PLAYER_TYPE;
|
||||||
|
$player = new $PLAYER_TYPE();
|
||||||
|
$uris = $player->get_uris_for_directory($data['uri']);
|
||||||
|
$ttids = array();
|
||||||
|
foreach ($uris as $uri) {
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null, "SELECT TTindex FROM Tracktable WHERE Uri = ?", $uri);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
return $ttids;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function geturis($data) {
|
||||||
|
$uris = getItemsToAdd($data['uri'], "");
|
||||||
|
$ttids = array();
|
||||||
|
foreach ($uris as $uri) {
|
||||||
|
$uri = trim(substr($uri, strpos($uri, ' ')+1, strlen($uri)), '"');
|
||||||
|
$r = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null, "SELECT TTindex FROM Tracktable WHERE Uri = ?", $uri);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
return $ttids;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function print_debug_ttids($ttids, $s) {
|
||||||
|
$time = time() - $s;
|
||||||
|
if (count($ttids) > 0) {
|
||||||
|
logger::log("TIMINGS", " Found TTindex(es)",$ttids,"in",$time,"seconds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function find_item($data,$urionly) {
|
||||||
|
|
||||||
|
// romprmetadata::find_item
|
||||||
|
// Looks for a track in the database based on uri, title, artist, album, and albumartist or
|
||||||
|
// combinations of those
|
||||||
|
// Returns: Array of TTindex
|
||||||
|
|
||||||
|
// romprmetadata::find_item is used by userRatings to find tracks on which to update or display metadata.
|
||||||
|
// It is NOT used when the collection is created
|
||||||
|
|
||||||
|
// When Setting Metadata we do not use a URI because we might have mutliple versions of the
|
||||||
|
// track in the database or someone might be rating a track from Spotify that they already have
|
||||||
|
// in Local. So in this case we check using an increasingly wider check to find the track,
|
||||||
|
// returning as soon as one of these produces matches.
|
||||||
|
// First by Title, TrackNo, AlbumArtist and Album
|
||||||
|
// Third by Track, Album Artist, and Album
|
||||||
|
// Then by Track, Track Artist, and Album
|
||||||
|
// Then by Track, Artist, and Album NULL (meaning wishlist)
|
||||||
|
// We return ALL tracks found, because you might have the same track on multiple backends,
|
||||||
|
// and set metadata on them all.
|
||||||
|
// This means that when getting metadata it doesn't matter which one we match on.
|
||||||
|
// When we Get Metadata we do supply a URI BUT we don't use it if we have one, just because.
|
||||||
|
// $urionly can be set to force looking up only by URI. This is used by when we need to import a
|
||||||
|
// specific version of the track - currently from either the Last.FM importer or when we add a
|
||||||
|
// spotify album to the collection
|
||||||
|
|
||||||
|
// If we don't supply an album to this function that's because we're listening to the radio.
|
||||||
|
// In that case we look for a match where there is something in the album field and then for
|
||||||
|
// where album is NULL
|
||||||
|
|
||||||
|
// FIXME! There is one scenario where the above fails.
|
||||||
|
// If you tag or rate a track, and then add it to the collection again from another backend
|
||||||
|
// later on, the rating doesn't get picked up by the new copy.
|
||||||
|
// Looking everything up by name/album/artist (i.e. ignoring the URI in romprmetadata::find_item)
|
||||||
|
// doesn't fix this because the collection display still doesn't show the rating as that's
|
||||||
|
// looked up by TTindex
|
||||||
|
|
||||||
|
$start_time = time();
|
||||||
|
logger::shout("FIND ITEM", "Looking for item ".$data['title']);
|
||||||
|
$ttids = array();
|
||||||
|
if ($urionly && $data['uri']) {
|
||||||
|
logger::mark("FIND ITEM", " Trying by URI ".$data['uri']);
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null, "SELECT TTindex FROM Tracktable WHERE Uri = ?", $data['uri']);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($data['artist'] == null || $data['title'] == null || ($urionly && $data['uri'])) {
|
||||||
|
romprmetadata::print_debug_ttids($ttids, $start_time);
|
||||||
|
return $ttids;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($ttids) == 0) {
|
||||||
|
if ($data['album']) {
|
||||||
|
if ($data['albumartist'] !== null && $data['trackno'] != 0) {
|
||||||
|
logger::mark("FIND ITEM", " Trying by albumartist",$data['albumartist'],"album",$data['album'],"title",$data['title'],"track number",$data['trackno']);
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null,
|
||||||
|
"SELECT
|
||||||
|
TTindex
|
||||||
|
FROM
|
||||||
|
Tracktable JOIN Albumtable USING (Albumindex)
|
||||||
|
JOIN Artisttable ON Albumtable.AlbumArtistindex = Artisttable.Artistindex
|
||||||
|
WHERE
|
||||||
|
LOWER(Title) = LOWER(?)
|
||||||
|
AND LOWER(Artistname) = LOWER(?)
|
||||||
|
AND LOWER(Albumname) = LOWER(?)
|
||||||
|
AND TrackNo = ?",
|
||||||
|
$data['title'], $data['albumartist'], $data['album'], $data['trackno']);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($ttids) == 0 && $data['albumartist'] !== null) {
|
||||||
|
logger::mark("FIND ITEM", " Trying by albumartist",$data['albumartist'],"album",$data['album'],"and title",$data['title']);
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null,
|
||||||
|
"SELECT
|
||||||
|
TTindex
|
||||||
|
FROM
|
||||||
|
Tracktable JOIN Albumtable USING (Albumindex)
|
||||||
|
JOIN Artisttable ON Albumtable.AlbumArtistindex = Artisttable.Artistindex
|
||||||
|
WHERE
|
||||||
|
LOWER(Title) = LOWER(?)
|
||||||
|
AND LOWER(Artistname) = LOWER(?)
|
||||||
|
AND LOWER(Albumname) = LOWER(?)",
|
||||||
|
$data['title'], $data['albumartist'], $data['album']);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($ttids) == 0 && ($data['albumartist'] == null || $data['albumartist'] == $data['artist'])) {
|
||||||
|
logger::mark("FIND ITEM", " Trying by artist",$data['artist'],",album",$data['album'],"and title",$data['title']);
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null,
|
||||||
|
"SELECT
|
||||||
|
TTindex
|
||||||
|
FROM
|
||||||
|
Tracktable JOIN Artisttable USING (Artistindex)
|
||||||
|
JOIN Albumtable USING (Albumindex)
|
||||||
|
WHERE
|
||||||
|
LOWER(Title) = LOWER(?)
|
||||||
|
AND LOWER(Artistname) = LOWER(?)
|
||||||
|
AND LOWER(Albumname) = LOWER(?)", $data['title'], $data['artist'], $data['album']);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally look for Uri NULL which will be a wishlist item added via a radio station
|
||||||
|
if (count($ttids) == 0) {
|
||||||
|
logger::mark("FIND ITEM", " Trying by (wishlist) artist",$data['artist'],"and title",$data['title']);
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null,
|
||||||
|
"SELECT
|
||||||
|
TTindex
|
||||||
|
FROM
|
||||||
|
Tracktable JOIN Artisttable USING (Artistindex)
|
||||||
|
WHERE
|
||||||
|
LOWER(Title) = LOWER(?)
|
||||||
|
AND LOWER(Artistname) = LOWER(?)
|
||||||
|
AND Uri IS NULL",
|
||||||
|
$data['title'], $data['artist']);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// No album supplied - ie this is from a radio stream. First look for a match where
|
||||||
|
// there is something in the album field
|
||||||
|
logger::mark("FIND ITEM", " Trying by artist",$data['artist'],"Uri NOT NULL and title",$data['title']);
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null,
|
||||||
|
"SELECT
|
||||||
|
TTindex
|
||||||
|
FROM
|
||||||
|
Tracktable JOIN Artisttable USING (Artistindex)
|
||||||
|
WHERE
|
||||||
|
LOWER(Title) = LOWER(?)
|
||||||
|
AND LOWER(Artistname) = LOWER(?)
|
||||||
|
AND Uri IS NOT NULL", $data['title'], $data['artist']);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
|
||||||
|
if (count($ttids) == 0) {
|
||||||
|
logger::mark("FIND ITEM", " Trying by (wishlist) artist",$data['artist'],"and title",$data['title']);
|
||||||
|
$t = sql_prepare_query(false, PDO::FETCH_COLUMN, 'TTindex', null,
|
||||||
|
"SELECT
|
||||||
|
TTindex
|
||||||
|
FROM
|
||||||
|
Tracktable JOIN Artisttable USING (Artistindex)
|
||||||
|
WHERE
|
||||||
|
LOWER(Title) = LOWER(?)
|
||||||
|
AND LOWER(Artistname) = LOWER(?)
|
||||||
|
AND Uri IS NULL", $data['title'], $data['artist']);
|
||||||
|
$ttids = array_merge($ttids, $t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
romprmetadata::print_debug_ttids($ttids, $start_time);
|
||||||
|
return $ttids;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function increment_value($ttid, $attribute, $value, $lp) {
|
||||||
|
|
||||||
|
// Increment_value doesn't 'increment' as such - it's used for setting values on tracks without
|
||||||
|
// unhiding them. It's used for Playcount, which was originally an 'increment' type function but
|
||||||
|
// that changed because multiple rompr instances cause multiple increments
|
||||||
|
|
||||||
|
logger::mark("INCREMENT", "Setting",$attribute,"to",$value,"for TTID",$ttid);
|
||||||
|
if (sql_prepare_query(true, null, null, null, "REPLACE INTO ".$attribute."table (TTindex, ".$attribute.", LastPlayed) VALUES (?, ?, ?)", $ttid, $value, $lp)) {
|
||||||
|
logger::trace("INCREMENT", " .. success");
|
||||||
|
} else {
|
||||||
|
logger::fail("INCREMENT", "FAILED Setting",$attribute,"to",$value,"for TTID",$ttid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static function set_attribute($ttid, $attribute, $value) {
|
||||||
|
|
||||||
|
// set_attribute
|
||||||
|
// Sets an attribute (Rating, Tag etc) on a TTindex.
|
||||||
|
logger::mark("ATTRIBUTE", "Setting",$attribute,"to",$value,"on",$ttid);
|
||||||
|
if (sql_prepare_query(true, null, null, null, "REPLACE INTO ".$attribute."table (TTindex, ".$attribute.") VALUES (?, ?)", $ttid, $value)) {
|
||||||
|
logger::trace("ATTRIBUTE", " .. success");
|
||||||
|
} else {
|
||||||
|
logger::fail("ATTRIBUTE", "FAILED Setting",$attribute,"to",$value,"on",$ttid);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function doTheSetting($ttids, $attributes, $uri) {
|
||||||
|
global $returninfo;
|
||||||
|
$result = true;
|
||||||
|
logger::trace("USERRATING", "Checking For attributes");
|
||||||
|
if ($attributes !== null) {
|
||||||
|
logger::trace("USERRATING", "Setting attributes");
|
||||||
|
foreach($ttids as $ttid) {
|
||||||
|
logger::debug("USERRATING", "TTid ".$ttid);
|
||||||
|
foreach ($attributes as $pair) {
|
||||||
|
logger::log("USERRATING", "Setting",$pair["attribute"],"to",$pair['value'],"on TTindex",$ttid);
|
||||||
|
switch ($pair['attribute']) {
|
||||||
|
case 'Tags':
|
||||||
|
$result = romprmetadata::addTags($ttid, $pair['value']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
$result = romprmetadata::set_attribute($ttid, $pair["attribute"], $pair["value"]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!$result) { break; }
|
||||||
|
}
|
||||||
|
if ($uri) {
|
||||||
|
$returninfo['metadata'] = get_all_data($ttid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function addTags($ttid, $tags) {
|
||||||
|
|
||||||
|
// addTags
|
||||||
|
// Add a list of tags to a TTindex
|
||||||
|
|
||||||
|
foreach ($tags as $tag) {
|
||||||
|
$t = trim($tag);
|
||||||
|
if ($t == '') continue;
|
||||||
|
logger::mark("ADD TAGS", "Adding Tag",$t,"to TTindex",$ttid);
|
||||||
|
$tagindex = sql_prepare_query(false, null, 'Tagindex', null, "SELECT Tagindex FROM Tagtable WHERE Name=?", $t);
|
||||||
|
if ($tagindex == null) $tagindex = romprmetadata::create_new_tag($t);
|
||||||
|
if ($tagindex == null) {
|
||||||
|
logger::fail("ADD TAGS", " Could not create tag",$t);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($result = generic_sql_query("INSERT INTO TagListtable (TTindex, Tagindex) VALUES ('".$ttid."', '".$tagindex."')", true)) {
|
||||||
|
logger::trace("ADD TAGS", "Success");
|
||||||
|
} else {
|
||||||
|
// Doesn't matter, we have a UNIQUE constraint on both columns to prevent us adding the same tag twice
|
||||||
|
logger::debug("ADD TAGS", " .. Failed but that's OK if it's because of a duplicate entry or UNQIUE constraint");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function create_new_tag($tag) {
|
||||||
|
|
||||||
|
// create_new_tags
|
||||||
|
// Creates a new entry in Tagtable
|
||||||
|
// Returns: Tagindex
|
||||||
|
|
||||||
|
global $mysqlc;
|
||||||
|
logger::mark("CREATE TAG", "Creating new tag",$tag);
|
||||||
|
$tagindex = null;
|
||||||
|
if (sql_prepare_query(true, null, null, null, "INSERT INTO Tagtable (Name) VALUES (?)", $tag)) {
|
||||||
|
$tagindex = $mysqlc->lastInsertId();
|
||||||
|
}
|
||||||
|
return $tagindex;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function remove_tag($ttid, $tag) {
|
||||||
|
|
||||||
|
// remove_tags
|
||||||
|
// Removes a tag relation from a TTindex
|
||||||
|
|
||||||
|
logger::mark("REMOVE TAG", "Removing Tag",$tag,"from TTindex",$ttid);
|
||||||
|
$retval = false;
|
||||||
|
if ($tagindex = simple_query('Tagindex', 'Tagtable', 'Name', $tag, false)) {
|
||||||
|
$retval = generic_sql_query("DELETE FROM TagListtable WHERE TTindex = '".$ttid."' AND Tagindex = '".$tagindex."'", true);
|
||||||
|
} else {
|
||||||
|
logger::fail("REMOVE TAG", " .. Could not find tag",$tag);
|
||||||
|
}
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
static function remove_tag_from_db($tag) {
|
||||||
|
logger::mark("REMOVE TAG", "Removing Tag",$tag,",from database");
|
||||||
|
return sql_prepare_query(true, null, null, null, "DELETE FROM Tagtable WHERE Name=?", $tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
static function delete_track($ttid) {
|
||||||
|
if (remove_ttid($ttid)) {
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static function amend_album($albumindex, $newartist, $date) {
|
||||||
|
logger::mark("AMEND ALBUM", "Updating Album index",$albumindex,"with new artist",$newartist,"and new date",$date);
|
||||||
|
$artistindex = ($newartist == null) ? null : check_artist($newartist);
|
||||||
|
$result = sql_prepare_query(false, PDO::FETCH_OBJ, null, null, "SELECT * FROM Albumtable WHERE Albumindex = ?", $albumindex);
|
||||||
|
$obj = array_shift($result);
|
||||||
|
if ($obj) {
|
||||||
|
$params = array(
|
||||||
|
'album' => $obj->Albumname,
|
||||||
|
'albumai' => ($artistindex == null) ? $obj->AlbumArtistindex : $artistindex,
|
||||||
|
'albumuri' => $obj->AlbumUri,
|
||||||
|
'image' => $obj->Image,
|
||||||
|
'date' => ($date == null) ? $obj->Year : $date,
|
||||||
|
'searched' => $obj->Searched,
|
||||||
|
'imagekey' => $obj->ImgKey,
|
||||||
|
'ambid' => $obj->mbid,
|
||||||
|
'domain' => $obj->Domain);
|
||||||
|
$newalbumindex = check_album($params);
|
||||||
|
if ($albumindex != $newalbumindex) {
|
||||||
|
logger::log("AMEND ALBUM", "Moving all tracks from album",$albumindex,"to album",$newalbumindex);
|
||||||
|
if (sql_prepare_query(true, null, null, null, "UPDATE Tracktable SET Albumindex = ? WHERE Albumindex = ?", $newalbumindex, $albumindex)) {
|
||||||
|
logger::trace("AMEND ALBUM", "...Success");
|
||||||
|
} else {
|
||||||
|
logger::fail("AMEND ALBUM", "Track move Failed!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::error("AMEND ALBUM", "Failed to find album to update!");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function forcedUriOnly($u,$d) {
|
||||||
|
|
||||||
|
// Some mopidy backends - YouTube and SoundCloud - can return the same artist/album/track info
|
||||||
|
// for multiple different tracks.
|
||||||
|
// This gives us a problem because romprmetadata::find_item will think they're the same.
|
||||||
|
// So for those backends we always force urionly to be true
|
||||||
|
logger::debug("USERRATINGS", "Checking domain : ".$d);
|
||||||
|
|
||||||
|
if ($u || $d == "youtube" || $d == "soundcloud") {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function preparePlaylist() {
|
||||||
|
generic_sql_query("DROP TABLE IF EXISTS pltable", true);
|
||||||
|
generic_sql_query("CREATE TABLE pltable(TTindex INT UNSIGNED NOT NULL UNIQUE)", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function preparePlTrackTable() {
|
||||||
|
generic_sql_query("DROP TABLE IF EXISTS pltracktable", true);
|
||||||
|
generic_sql_query("CREATE TABLE pltracktable(TTindex INT UNSIGNED NOT NULL UNIQUE)", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doPlaylist($playlist, $limit) {
|
||||||
|
global $prefs;
|
||||||
|
logger::blurt("SMARTRADIO", "Loading Playlist",$playlist,'limit',$limit);
|
||||||
|
$sqlstring = "";
|
||||||
|
$tags = null;
|
||||||
|
$random = true;
|
||||||
|
switch($playlist) {
|
||||||
|
case "1stars":
|
||||||
|
$sqlstring = "SELECT TTindex FROM Tracktable JOIN Ratingtable USING (TTindex) WHERE Uri
|
||||||
|
IS NOT NULL AND Hidden=0 AND isSearchResult < 2 AND Rating > 0";
|
||||||
|
break;
|
||||||
|
case "2stars":
|
||||||
|
$sqlstring = "SELECT TTindex FROM Tracktable JOIN Ratingtable USING (TTindex) WHERE Uri
|
||||||
|
IS NOT NULL AND Hidden=0 AND isSearchResult < 2 AND Rating > 1";
|
||||||
|
break;
|
||||||
|
case "3stars":
|
||||||
|
$sqlstring = "SELECT TTindex FROM Tracktable JOIN Ratingtable USING (TTindex) WHERE Uri
|
||||||
|
IS NOT NULL AND Hidden=0 AND isSearchResult < 2 AND Rating > 2";
|
||||||
|
break;
|
||||||
|
case "4stars":
|
||||||
|
$sqlstring = "SELECT TTindex FROM Tracktable JOIN Ratingtable USING (TTindex) WHERE Uri
|
||||||
|
IS NOT NULL AND Hidden=0 AND isSearchResult < 2 AND Rating > 3";
|
||||||
|
break;
|
||||||
|
case "5stars":
|
||||||
|
$sqlstring = "SELECT TTindex FROM Tracktable JOIN Ratingtable USING (TTindex) WHERE Uri
|
||||||
|
IS NOT NULL AND Hidden=0 AND isSearchResult < 2 AND Rating > 4";
|
||||||
|
break;
|
||||||
|
case "favealbums":
|
||||||
|
case "recentlyadded_byalbum":
|
||||||
|
// This is a rather odd SQL query but it needs a WHERE clause and a JOIN with Tracktable
|
||||||
|
// in order to work with the generic track dumping functions
|
||||||
|
$sqlstring = "SELECT TTindex FROM pltracktable JOIN Tracktable USING (TTindex) WHERE TTindex > 0";
|
||||||
|
$random = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "recentlyadded_random":
|
||||||
|
$sqlstring = "SELECT TTindex FROM pltracktable JOIN Tracktable USING (TTindex) WHERE TTindex > 0";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "mostplayed":
|
||||||
|
// Used to be tracks with above average playcount, now also includes any rated tracks.
|
||||||
|
// Still called mostplayed :)
|
||||||
|
$avgplays = getAveragePlays();
|
||||||
|
$sqlstring = "SELECT TTindex FROM Tracktable JOIN Playcounttable USING (TTindex)
|
||||||
|
LEFT JOIN Ratingtable USING (TTindex) WHERE Uri IS NOT NULL AND Hidden = 0 AND
|
||||||
|
isSearchResult < 2 AND (Playcount > ".$avgplays." OR Rating IS NOT NULL)";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "allrandom":
|
||||||
|
$sqlstring = "SELECT TTindex FROM Tracktable WHERE Uri IS NOT NULL AND Hidden=0 AND
|
||||||
|
isSearchResult < 2";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "neverplayed":
|
||||||
|
// LEFT JOIN (used here and above) means that the right-hand side of the JOIN will be
|
||||||
|
// NULL if TTindex doesn't exist on that side. Very handy.
|
||||||
|
$sqlstring = "SELECT Tracktable.TTindex FROM Tracktable LEFT JOIN Playcounttable ON
|
||||||
|
Tracktable.TTindex = Playcounttable.TTindex WHERE Playcounttable.TTindex IS NULL";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "recentlyplayed":
|
||||||
|
$sqlstring = recently_played_playlist();
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
if (preg_match('/tag\+(.*)/', $playlist, $matches)) {
|
||||||
|
$taglist = explode(',', $matches[1]);
|
||||||
|
$sqlstring = 'SELECT DISTINCT TTindex FROM Tracktable JOIN TagListtable USING (TTindex) JOIN Tagtable USING (Tagindex) WHERE ';
|
||||||
|
// Concatenate this bracket here otherwise Atom's syntax colouring goes haywire
|
||||||
|
$sqlstring .= '(';
|
||||||
|
$tags = array();
|
||||||
|
foreach ($taglist as $i => $tag) {
|
||||||
|
logger::mark("SMART RADIO", "Getting tag playlist for",$tag);
|
||||||
|
$tags[] = trim($tag);
|
||||||
|
if ($i > 0) {
|
||||||
|
$sqlstring .= " OR ";
|
||||||
|
}
|
||||||
|
$sqlstring .= "Tagtable.Name = ?";
|
||||||
|
}
|
||||||
|
$sqlstring .= ") AND Tracktable.Uri IS NOT NULL AND Tracktable.Hidden = 0 AND
|
||||||
|
Tracktable.isSearchResult < 2 ";
|
||||||
|
} else {
|
||||||
|
logger::fail("SMART RADIO", "Unrecognised playlist",$playlist);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$sqlstring .= ' AND (LinkChecked = 0 OR LinkChecked = 2) AND isAudiobook = 0';
|
||||||
|
if ($prefs['collection_player'] == 'mopidy' && $prefs['player_backend'] == 'mpd') {
|
||||||
|
$sqlstring .= ' AND Uri LIKE "local:%"';
|
||||||
|
}
|
||||||
|
$uris = getAllURIs($sqlstring, $limit, $tags, $random);
|
||||||
|
$json = array();
|
||||||
|
foreach ($uris as $u) {
|
||||||
|
$json[] = array( 'type' => 'uri', 'name' => $u);
|
||||||
|
}
|
||||||
|
return $json;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAllURIs($sqlstring, $limit, $tags, $random = true) {
|
||||||
|
|
||||||
|
// Get all track URIs using a supplied SQL string. For playlist generators
|
||||||
|
$uris = array();
|
||||||
|
$tries = 0;
|
||||||
|
do {
|
||||||
|
if ($tries == 1) {
|
||||||
|
logger::log("SMART PLAYLIST", "No URIs found. Resetting history table");
|
||||||
|
preparePlaylist();
|
||||||
|
}
|
||||||
|
generic_sql_query("CREATE TEMPORARY TABLE IF NOT EXISTS pltemptable(TTindex INT UNSIGNED NOT NULL UNIQUE)", true);
|
||||||
|
theBabyDumper($sqlstring, $limit, $tags, $random);
|
||||||
|
$uris = sql_get_column("SELECT Uri FROM Tracktable WHERE TTindex IN (SELECT TTindex FROM pltemptable)", 0);
|
||||||
|
$tries++;
|
||||||
|
} while (count($uris) == 0 && $tries < 2);
|
||||||
|
generic_sql_query("INSERT INTO pltable (TTindex) SELECT TTindex FROM pltemptable", true);
|
||||||
|
return $uris;
|
||||||
|
}
|
||||||
|
|
||||||
|
function theBabyDumper($sqlstring, $limit, $tags, $random) {
|
||||||
|
logger::trace("SMART PLAYLIST", "Selector is ".$sqlstring);
|
||||||
|
$rndstr = $random ? " ORDER BY ".SQL_RANDOM_SORT : " ORDER BY Albumindex, TrackNo";
|
||||||
|
if ($tags) {
|
||||||
|
sql_prepare_query(true, null, null, null,
|
||||||
|
"INSERT INTO pltemptable(TTindex) ".$sqlstring.
|
||||||
|
" AND NOT Tracktable.TTindex IN (SELECT TTindex FROM pltable)".$rndstr." LIMIT ".$limit, $tags);
|
||||||
|
} else {
|
||||||
|
generic_sql_query(
|
||||||
|
"INSERT INTO pltemptable(TTindex) ".$sqlstring.
|
||||||
|
" AND NOT Tracktable.TTindex IN (SELECT TTindex FROM pltable)".$rndstr." LIMIT ".$limit, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAveragePlays() {
|
||||||
|
$avgplays = simple_query('avg(Playcount)', 'Playcounttable', null, null, 0);
|
||||||
|
return round($avgplays, 0, PHP_ROUND_HALF_DOWN);
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,960 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
define('SQL_RANDOM_SORT', 'RAND()');
|
||||||
|
define('SQL_TAG_CONCAT', "GROUP_CONCAT(t.Name SEPARATOR ', ') ");
|
||||||
|
|
||||||
|
function connect_to_database($sp = true) {
|
||||||
|
global $mysqlc, $prefs;
|
||||||
|
if ($mysqlc !== null) {
|
||||||
|
logger::error("MYSQL", "AWOOOGA! ATTEMPTING MULTIPLE DATABASE CONNECTIONS!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if (is_numeric($prefs['mysql_port'])) {
|
||||||
|
logger::debug("SQL_CONNECT", "Connecting using hostname and port");
|
||||||
|
$dsn = "mysql:host=".$prefs['mysql_host'].";port=".$prefs['mysql_port'].";dbname=".$prefs['mysql_database'];
|
||||||
|
} else {
|
||||||
|
logger::debug("SQL_CONNECT", "Connecting using unix socket");
|
||||||
|
$dsn = "mysql:unix_socket=".$prefs['mysql_port'].";dbname=".$prefs['mysql_database'];
|
||||||
|
}
|
||||||
|
$mysqlc = new PDO($dsn, $prefs['mysql_user'], $prefs['mysql_password']);
|
||||||
|
logger::debug("SQL_CONNECT", "Connected to MySQL");
|
||||||
|
generic_sql_query("SET NAMES utf8", true);
|
||||||
|
generic_sql_query('SET SESSION sql_mode="STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION"', true);
|
||||||
|
readCollectionPlayer($sp);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
logger::fail("SQL_CONNECT", "Database connect failure - ".$e);
|
||||||
|
sql_init_fail($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close_database() {
|
||||||
|
global $mysqlc;
|
||||||
|
$mysqlc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_sql_tables() {
|
||||||
|
global $mysqlc, $prefs;
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Tracktable(".
|
||||||
|
"TTindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"PRIMARY KEY(TTindex), ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Albumindex INT UNSIGNED, ".
|
||||||
|
"TrackNo SMALLINT UNSIGNED, ".
|
||||||
|
"Duration INT UNSIGNED, ".
|
||||||
|
"Artistindex INT UNSIGNED, ".
|
||||||
|
"Disc TINYINT(3) UNSIGNED, ".
|
||||||
|
"Uri VARCHAR(2000), ".
|
||||||
|
"LastModified CHAR(32), ".
|
||||||
|
"Hidden TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"DateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ".
|
||||||
|
"isSearchResult TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"justAdded TINYINT(1) UNSIGNED DEFAULT 1, ".
|
||||||
|
"Sourceindex INT UNSIGNED DEFAULT NULL, ".
|
||||||
|
"LinkChecked TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"isAudiobook TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"INDEX(Albumindex), ".
|
||||||
|
"INDEX(Title), ".
|
||||||
|
"INDEX(TrackNo)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Tracktable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tracktable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Albumtable(".
|
||||||
|
"Albumindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"PRIMARY KEY(Albumindex), ".
|
||||||
|
"Albumname VARCHAR(255), ".
|
||||||
|
"AlbumArtistindex INT UNSIGNED, ".
|
||||||
|
"AlbumUri VARCHAR(255), ".
|
||||||
|
"Year YEAR, ".
|
||||||
|
"Searched TINYINT(1) UNSIGNED, ".
|
||||||
|
"ImgKey CHAR(32), ".
|
||||||
|
"mbid CHAR(40), ".
|
||||||
|
"ImgVersion INT UNSIGNED DEFAULT ".ROMPR_IMAGE_VERSION.", ".
|
||||||
|
"Domain CHAR(32), ".
|
||||||
|
"Image VARCHAR(255), ".
|
||||||
|
"justUpdated TINYINT(1) UNSIGNED DEFAULT 1, ".
|
||||||
|
"INDEX(Albumname), ".
|
||||||
|
"INDEX(AlbumArtistindex), ".
|
||||||
|
"INDEX(Domain), ".
|
||||||
|
"INDEX(ImgKey)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Albumtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Albumtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Artisttable(".
|
||||||
|
"Artistindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"PRIMARY KEY(Artistindex), ".
|
||||||
|
"Artistname VARCHAR(255), ".
|
||||||
|
"INDEX(Artistname)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Artisttable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Artisttable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Ratingtable(".
|
||||||
|
"TTindex INT UNSIGNED, ".
|
||||||
|
"PRIMARY KEY(TTindex), ".
|
||||||
|
"Rating TINYINT(1) UNSIGNED) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Ratingtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Ratingtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Progresstable(".
|
||||||
|
"TTindex INT UNSIGNED, ".
|
||||||
|
"PRIMARY KEY(TTindex), ".
|
||||||
|
"Progress INT UNSIGNED) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Progresstable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Progresstable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Tagtable(".
|
||||||
|
"Tagindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"PRIMARY KEY(Tagindex), ".
|
||||||
|
"Name VARCHAR(255)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Tagtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tagtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS TagListtable(".
|
||||||
|
"Tagindex INT UNSIGNED NOT NULL REFERENCES Tagtable(Tagindex), ".
|
||||||
|
"TTindex INT UNSIGNED NOT NULL REFERENCES Tracktable(TTindex), ".
|
||||||
|
"PRIMARY KEY (Tagindex, TTindex)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " TagListtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking TagListtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Playcounttable(".
|
||||||
|
"TTindex INT UNSIGNED NOT NULL REFERENCES Tracktable(TTindex), ".
|
||||||
|
"Playcount INT UNSIGNED NOT NULL, ".
|
||||||
|
"SyncCount INT UNSIGNED DEFAULT 0, ".
|
||||||
|
"LastPlayed TIMESTAMP, ".
|
||||||
|
"PRIMARY KEY (TTindex)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Playcounttable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Playcounttable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Podcasttable(".
|
||||||
|
"PODindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"FeedURL TEXT, ".
|
||||||
|
"LastUpdate INT UNSIGNED, ".
|
||||||
|
"Image VARCHAR(255), ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Artist VARCHAR(255), ".
|
||||||
|
"RefreshOption TINYINT(2) UNSIGNED DEFAULT 0, ".
|
||||||
|
"SortMode TINYINT(2) UNSIGNED DEFAULT 0, ".
|
||||||
|
"HideDescriptions TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"DisplayMode TINYINT(2) UNSIGNED DEFAULT 0, ".
|
||||||
|
"DaysToKeep INT UNSIGNED DEFAULT 0, ".
|
||||||
|
"NumToKeep INT UNSIGNED DEFAULT 0, ".
|
||||||
|
"KeepDownloaded TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"AutoDownload TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"DaysLive INT, ".
|
||||||
|
"Version TINYINT(2), ".
|
||||||
|
"Subscribed TINYINT(1) NOT NULL DEFAULT 1, ".
|
||||||
|
"Description TEXT, ".
|
||||||
|
"LastPubDate INT UNSIGNED DEFAULT NULL, ".
|
||||||
|
"Category VARCHAR(255) NOT NULL, ".
|
||||||
|
"PRIMARY KEY (PODindex)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " Podcasttable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Podcasttable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS PodcastTracktable(".
|
||||||
|
"PODTrackindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"JustUpdated TINYINT(1), ".
|
||||||
|
"PODindex INT UNSIGNED, ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Artist VARCHAR(255), ".
|
||||||
|
"Duration INT UNSIGNED, ".
|
||||||
|
"PubDate INT, ".
|
||||||
|
"FileSize INT UNSIGNED, ".
|
||||||
|
"Description TEXT, ".
|
||||||
|
"Link TEXT, ".
|
||||||
|
"Guid TEXT, ".
|
||||||
|
"Localfilename VARCHAR(255), ".
|
||||||
|
"Downloaded TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"Listened TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"New TINYINT(1) UNSIGNED DEFAULT 1, ".
|
||||||
|
"Deleted TINYINT(1) UNSIGNED DEFAULT 0, ".
|
||||||
|
"Progress INT UNSIGNED DEFAULT 0, ".
|
||||||
|
"INDEX (PODindex), ".
|
||||||
|
"PRIMARY KEY (PODTrackindex), ".
|
||||||
|
"INDEX (Title)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " PodcastTracktable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking PodcastTracktable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS RadioStationtable(".
|
||||||
|
"Stationindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"Number SMALLINT UNSIGNED DEFAULT 65535, ".
|
||||||
|
"IsFave TINYINT(1), ".
|
||||||
|
"StationName VARCHAR(255), ".
|
||||||
|
"PlaylistUrl TEXT, ".
|
||||||
|
"Image VARCHAR(255), ".
|
||||||
|
"PRIMARY KEY (Stationindex)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " RadioStationtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking RadioStationtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS RadioTracktable(".
|
||||||
|
"Trackindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"Stationindex INT UNSIGNED REFERENCES RadioStationtable(Stationindex), ".
|
||||||
|
"TrackUri TEXT, ".
|
||||||
|
"PrettyStream TEXT, ".
|
||||||
|
"PRIMARY KEY (Trackindex)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " RadioTracktable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking RadioTracktable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS WishlistSourcetable(".
|
||||||
|
"Sourceindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"SourceName VARCHAR(255), ".
|
||||||
|
"SourceImage VARCHAR(255), ".
|
||||||
|
"SourceUri TEXT, ".
|
||||||
|
"PRIMARY KEY (Sourceindex)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " WishlistSourcetable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking WishlistSourcetable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS AlbumsToListenTotable(".
|
||||||
|
"Listenindex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"JsonData TEXT, ".
|
||||||
|
"PRIMARY KEY (Listenindex)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " AlbumsToListenTotabletable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking AlbumsToListenTotable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS BackgroundImageTable(".
|
||||||
|
"BgImageIndex INT UNSIGNED NOT NULL AUTO_INCREMENT UNIQUE, ".
|
||||||
|
"Skin VARCHAR(255), ".
|
||||||
|
"BrowserID VARCHAR(20) DEFAULT NULL, ".
|
||||||
|
"Filename VARCHAR(255), ".
|
||||||
|
"Orientation TINYINT(2), ".
|
||||||
|
"PRIMARY KEY (BgImageIndex), ".
|
||||||
|
"INDEX (Skin), ".
|
||||||
|
"INDEX (BrowserID)) ENGINE=InnoDB", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " BackgounrdImageTable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking BackgroundImageTable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!generic_sql_query("CREATE TABLE IF NOT EXISTS Statstable(Item CHAR(11), PRIMARY KEY(Item), Value INT UNSIGNED) ENGINE=InnoDB", true)) {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Statstable : ".$err);
|
||||||
|
}
|
||||||
|
// Check schema version and update tables as necessary
|
||||||
|
$sv = simple_query('Value', 'Statstable', 'Item', 'SchemaVer', 0);
|
||||||
|
if ($sv == 0) {
|
||||||
|
logger::log("SQL_CONNECT", "No Schema Version Found - initialising table");
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('ListVersion', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('ArtistCount', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('AlbumCount', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('TrackCount', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('TotalTime', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('CollType', '999')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('SchemaVer', '".ROMPR_SCHEMA_VERSION."')", true);
|
||||||
|
$sv = ROMPR_SCHEMA_VERSION;
|
||||||
|
logger::log("MYSQL_CONNECT", "Statstable populated");
|
||||||
|
create_update_triggers();
|
||||||
|
create_conditional_triggers();
|
||||||
|
create_playcount_triggers();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sv > ROMPR_SCHEMA_VERSION) {
|
||||||
|
logger::log("MYSQL_CONNECT", "Schema Mismatch! We are version ".ROMPR_SCHEMA_VERSION." but database is version ".$sv);
|
||||||
|
return array(false, "Your database has version number ".$sv." but this version of rompr only handles version ".ROMPR_SCHEMA_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($sv < ROMPR_SCHEMA_VERSION) {
|
||||||
|
switch ($sv) {
|
||||||
|
case 0:
|
||||||
|
logger::error("SQL", "BIG ERROR! No Schema Version found!!");
|
||||||
|
return array(false, "Database Error - could not read schema version. Cannot continue.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 1 TO Schema version 2");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable DROP Directory", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 2 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 2:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 2 TO Schema version 3");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD Hidden TINYINT(1) UNSIGNED DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Hidden = 0 WHERE Hidden IS NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 3 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 3:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 3 TO Schema version 4");
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Disc = 1 WHERE Disc IS NULL OR Disc = 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 4 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 4:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 4 TO Schema version 5");
|
||||||
|
generic_sql_query("UPDATE Albumtable SET Searched = 0 WHERE Image NOT LIKE 'albumart%'", true);
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable DROP Image", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 5 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 5:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 5 TO Schema version 6");
|
||||||
|
generic_sql_query("DROP INDEX Disc on Tracktable", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 6 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 6:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 6 TO Schema version 7");
|
||||||
|
// This was going to be a nice datestamp but newer versions of mysql don't work that way
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD DateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", true);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET DateAdded = FROM_UNIXTIME(LastModified) WHERE LastModified IS NOT NULL AND LastModified > 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 7 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 7:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 7 TO Schema version 8");
|
||||||
|
// Since we've changed the way we're joining artist names together,
|
||||||
|
// rather than force the database to be recreated and screw up everyone's
|
||||||
|
// tags and rating, just modify the artist data.
|
||||||
|
$stmt = sql_prepare_query_later("UPDATE Artisttable SET Artistname = ? WHERE Artistindex = ?");
|
||||||
|
if ($stmt !== FALSE) {
|
||||||
|
$result = generic_sql_query("SELECT * FROM Artisttable", false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
$artist = (string) $obj->Artistname;
|
||||||
|
$art = explode(' & ', $artist);
|
||||||
|
if (count($art) > 2) {
|
||||||
|
$f = array_slice($art, 0, count($art) - 1);
|
||||||
|
$newname = implode($f, ", ")." & ".$art[count($art) - 1];
|
||||||
|
logger::log("UPGRADE_SCHEMA", "Updating artist name from ".$artist." to ".$newname);
|
||||||
|
$stmt->execute(array($newname, $obj->Artistindex));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 8 WHERE Item = 'SchemaVer'", true);
|
||||||
|
$stmt = null;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 8:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 8 TO Schema version 9");
|
||||||
|
// We removed the image column earlier, but I've decided we need it again
|
||||||
|
// because some mopidy backends supply images and archiving them all makes
|
||||||
|
// creating the collection take waaaaay too long.
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable ADD Image VARCHAR(255)", true);
|
||||||
|
// So we now need to recreate the image database. Sadly this means that people using Beets will lose their album images.
|
||||||
|
$result = generic_sql_query("SELECT Albumindex, ImgKey FROM Albumtable", false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
if (file_exists('albumart/small/'.$obj->ImgKey.'.jpg')) {
|
||||||
|
generic_sql_query("UPDATE Albumtable SET Image = 'albumart/small/".$obj->ImgKey.".jpg', Searched = 1 WHERE Albumindex = ".$obj->Albumindex, true);
|
||||||
|
} else {
|
||||||
|
generic_sql_query("UPDATE Albumtable SET Image = '', Searched = 0 WHERE Albumindex = ".$obj->Albumindex, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 9 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 9:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 9 TO Schema version 10");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable DROP NumDiscs", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 10 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 10:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 10 TO Schema version 11");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable DROP IsOneFile", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 11 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 11 TO Scheme version 12");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD isSearchResult TINYINT(1) UNSIGNED DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 12 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 12 TO Scheme version 13");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable CHANGE Spotilink AlbumUri VARCHAR(255)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 13 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 13 TO Scheme version 14");
|
||||||
|
// Nothing to do here, this is for SQLite only.
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 14 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 14 TO Scheme version 15");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable MODIFY LastModified CHAR(32)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 15 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 15 TO Schema version 16");
|
||||||
|
albumImageBuggery();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 16 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 16 TO Schema version 17");
|
||||||
|
// Early MPD versions had LastModified as an integer value. They changed it to a datestamp some time ago but I didn't notice
|
||||||
|
$r = generic_sql_query("SELECT DATA_TYPE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Tracktable' AND COLUMN_NAME = 'LastModified'");
|
||||||
|
foreach ($r as $obj) {
|
||||||
|
logger::log("MYSQL_INIT", "Data Type of LastModified is ".$obj['DATA_TYPE']);
|
||||||
|
if ($obj['DATA_TYPE'] == 'int') {
|
||||||
|
logger::log("MYSQL_INIT", "Modifying Tracktable");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD LM CHAR(32)", true);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET LM = LastModified", true);
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable DROP LastModified", true);
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable CHANGE LM LastModified CHAR(32)", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 17 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 17:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 17 TO Schema version 18");
|
||||||
|
include("utils/podcastupgrade.php");
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 18 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 18:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 18 TO Schema version 19");
|
||||||
|
$result = generic_sql_query('SELECT Tracktable.Uri AS uri, Tracktable.TTindex, Tracktable.Title AS ttit, Albumtable.*, Trackimagetable.Image AS ti FROM Tracktable JOIN Albumtable USING (Albumindex) LEFT JOIN Trackimagetable USING (TTindex) WHERE Tracktable.Uri LIKE "soundcloud:%"', false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
logger::log("SQL", " Creating new Album ".$obj->ttit." Image ".$obj->ti);
|
||||||
|
$ti = $obj->ti;
|
||||||
|
if (preg_match('/^http/', $ti)) {
|
||||||
|
$ti = 'getRemoteImage.php?url='.$ti;
|
||||||
|
}
|
||||||
|
if (sql_prepare_query(true, null, null, null,
|
||||||
|
"INSERT INTO Albumtable
|
||||||
|
(Albumname, AlbumArtistindex, AlbumUri, Year, Searched, ImgKey, mbid, Domain, Image)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
$obj->ttit, $obj->AlbumArtistindex, $obj->uri, $obj->Year, $obj->Searched, $obj->ImgKey, $obj->mbid, $obj->Domain, $ti
|
||||||
|
)) {
|
||||||
|
$retval = $mysqlc->lastInsertId();
|
||||||
|
logger::log("SQL", " .. success, Albumindex ".$retval);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Albumindex = ".$retval." WHERE TTindex = ".$obj->TTindex, true);
|
||||||
|
} else {
|
||||||
|
logger::log("SQL", " .. ERROR!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 19 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 19:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 19 TO Schema version 20");
|
||||||
|
$result = generic_sql_query('SELECT Tracktable.Uri AS uri, Tracktable.TTindex, Tracktable.Title AS ttit, Albumtable.*, Trackimagetable.Image AS ti FROM Tracktable JOIN Albumtable USING (Albumindex) LEFT JOIN Trackimagetable USING (TTindex) WHERE Tracktable.Uri LIKE "youtube:%"', false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
logger::log("SQL", " Creating new Album ".$obj->ttit." Image ".$obj->ti);
|
||||||
|
$ti = $obj->ti;
|
||||||
|
if (preg_match('/^http/', $ti)) {
|
||||||
|
$ti = 'getRemoteImage.php?url='.$ti;
|
||||||
|
}
|
||||||
|
if (sql_prepare_query(true, null, null, null,
|
||||||
|
"INSERT INTO Albumtable
|
||||||
|
(Albumname, AlbumArtistindex, AlbumUri, Year, Searched, ImgKey, mbid, Domain, Image)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
$obj->ttit, $obj->AlbumArtistindex, $obj->uri, $obj->Year, $obj->Searched, $obj->ImgKey, $obj->mbid, $obj->Domain, $ti
|
||||||
|
)) {
|
||||||
|
$retval = $mysqlc->lastInsertId();
|
||||||
|
logger::log("SQL", " .. success, Albumindex ".$retval);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Albumindex = ".$retval." WHERE TTindex = ".$obj->TTindex, true);
|
||||||
|
} else {
|
||||||
|
logger::error("SQL", " .. ERROR!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 20 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 20:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 20 TO Schema version 21");
|
||||||
|
generic_sql_query("DROP TABLE Trackimagetable", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 21 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 21:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 21 TO Schema version 22");
|
||||||
|
generic_sql_query("ALTER TABLE Playcounttable ADD LastPlayed TIMESTAMP NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 22 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 22:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 22 TO Schema version 23");
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable ADD Version TINYINT(2)", true);
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable ADD Guid VARCHAR(2000)", true);
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable ADD Localfilename VARCHAR(255)", true);
|
||||||
|
generic_sql_query("UPDATE Podcasttable SET Version = 1 WHERE PODindex IS NOT NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 23 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 23:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 23 TO Schema version 24");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable CHANGE DateAdded DateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 24 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 24:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 24 TO Schema version 25");
|
||||||
|
generic_sql_query("ALTER DATABASE romprdb CHARACTER SET utf8 COLLATE utf8_unicode_ci", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 25 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 25:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 25 TO Schema version 26");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD justAdded TINYINT(1) UNSIGNED DEFAULT 1", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 26 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 26:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 26 TO Schema version 27");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable ADD justUpdated TINYINT(1) UNSIGNED DEFAULT 1", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 27 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 27:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 27 TO Schema version 28");
|
||||||
|
rejig_wishlist_tracks();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 28 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 28:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 28 TO Schema version 29");
|
||||||
|
create_update_triggers();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 29 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 29:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 29 TO Schema version 30");
|
||||||
|
include('utils/radioupgrade.php');
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 30 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 30:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 30 TO Schema version 31");
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable CHANGE Description Description TEXT", true);
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable CHANGE Link Link TEXT", true);
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable CHANGE Guid Guid TEXT", true);
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable CHANGE FeedURL FeedURL TEXT", true);
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable CHANGE Description Description TEXT", true);
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable CHANGE Uri Uri TEXT", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 31 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 31:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 31 TO Schema version 32");
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable ADD Subscribed TINYINT(1) NOT NULL DEFAULT 1", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 32 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 32 TO Schema version 33");
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS track_insert_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS track_update_trigger", true);
|
||||||
|
create_conditional_triggers();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 33 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 33:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 33 TO Schema version 34");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable ADD ImgVersion INT UNSIGNED DEFAULT ".ROMPR_IMAGE_VERSION, true);
|
||||||
|
generic_sql_query("UPDATE Albumtable SET ImgVersion = 1",true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 34 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 34:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 34 TO Schema version 35");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD Sourceindex INT UNSIGNED DEFAULT NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 35 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 35:
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 36 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 36:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 35 TO Schema version 37");
|
||||||
|
$localpods = generic_sql_query("SELECT PODTrackindex, PODindex, LocalFilename FROM PodcastTracktable WHERE LocalFilename IS NOT NULL");
|
||||||
|
foreach ($localpods as $pod) {
|
||||||
|
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET LocalFilename = ? WHERE PODTrackindex = ?", '/prefs/podcasts/'.$pod['PODindex'].'/'.$pod['PODTrackindex'].'/'.$pod['LocalFilename'], $pod['PODTrackindex']);
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 37 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 37:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 37 TO Schema version 38");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable MODIFY ImgVersion INT UNSIGNED DEFAULT ".ROMPR_IMAGE_VERSION, true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 38 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 38:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 38 TO Schema version 39");
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable ADD LastPubDate INT UNSIGNED DEFAULT NULL", true);
|
||||||
|
generic_sql_query("CREATE INDEX ptt ON PodcastTracktable (Title)", true);
|
||||||
|
require_once('includes/podcastfunctions.php');
|
||||||
|
upgrade_podcasts_to_version();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 39 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 39:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 39 TO Schema version 40");
|
||||||
|
// Takes too long. It'll happen when they get refreshed anyway.
|
||||||
|
// require_once('includes/podcastfunctions.php');
|
||||||
|
// upgrade_podcast_images();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 40 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 40:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 40 TO Schema version 41");
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable ADD Category VARCHAR(255) NOT NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 41 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 41:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 41 TO Schema version 42");
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable ADD Progress INT UNSIGNED DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 42 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 42:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 42 TO Schema version 43");
|
||||||
|
update_stream_images(43);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 43 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 43:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 43 TO Schema version 44");
|
||||||
|
empty_modified_cache_dirs(44);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 44 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 44:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 44 TO Schema version 45");
|
||||||
|
upgrade_host_defs(45);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 45 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 45:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 45 TO Schema version 46");
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 46 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 46:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 46 TO Schema version 47");
|
||||||
|
generic_sql_query("ALTER TABLE Playcounttable ADD SyncCount INT UNSIGNED DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 47 WHERE Item = 'SchemaVer'", true);
|
||||||
|
create_playcount_triggers();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 47:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 47 TO Schema version 48");
|
||||||
|
// Some versions had a default value and an on update for LastPlayed, which is WRONG and fucks things up
|
||||||
|
generic_sql_query("ALTER TABLE Playcounttable ALTER LastPlayed DROP DEFAULT", true);
|
||||||
|
generic_sql_query("ALTER TABLE Playcounttable CHANGE LastPlayed LastPlayed TIMESTAMP NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 48 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 48:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 48 TO Schema version 49");
|
||||||
|
upgrade_host_defs(49);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 49 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 49:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 49 TO Schema version 50");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD LinkChecked TINYINT(1) UNSIGNED DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 50 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 50:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 50 TO Schema version 51");
|
||||||
|
// Something wierd happened and I lost half my triggers. In case it happens to anyone else...
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS track_insert_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS track_update_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS rating_update_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS rating_insert_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS tag_delete_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS tag_insert_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS tag_remove_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS track_delete_trigger", true);
|
||||||
|
create_conditional_triggers();
|
||||||
|
create_update_triggers();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 51 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 51:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 51 TO Schema version 52");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD isAudiobook TINYINT(1) UNSIGNED DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 52 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 52:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 52 TO Schema version 53");
|
||||||
|
create_progress_triggers();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 53 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 53:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 53 TO Schema version 54");
|
||||||
|
require_once ('utils/backgroundimages.php');
|
||||||
|
first_upgrade_of_user_backgrounds();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 54 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 54:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 54 TO Schema version 55");
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('PodUpPid', 0)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 55 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 55:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 55 TO Schema version 56");
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('Updating', '0')", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 56 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
$sv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(true, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_oldtracks() {
|
||||||
|
// generic_sql_query("DELETE Tracktable FROM Tracktable JOIN Playcounttable USING (TTindex) WHERE Hidden = 1 AND DATE_SUB(CURDATE(), INTERVAL 6 MONTH) > DateAdded AND Playcount < 2", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_orphaned_artists() {
|
||||||
|
generic_sql_query("DROP TABLE IF EXISTS Croft", true);
|
||||||
|
generic_sql_query("DROP TABLE IF EXISTS Cruft", true);
|
||||||
|
generic_sql_query("CREATE TEMPORARY TABLE Croft(Artistindex INT UNSIGNED NOT NULL UNIQUE, PRIMARY KEY(Artistindex)) AS SELECT Artistindex FROM Tracktable UNION SELECT AlbumArtistindex FROM Albumtable", true);
|
||||||
|
generic_sql_query("CREATE TEMPORARY TABLE Cruft(Artistindex INT UNSIGNED NOT NULL UNIQUE, PRIMARY KEY(Artistindex)) AS SELECT Artistindex FROM Artisttable WHERE Artistindex NOT IN (SELECT Artistindex FROM Croft)", true);
|
||||||
|
generic_sql_query("DELETE Artisttable FROM Artisttable INNER JOIN Cruft ON Artisttable.Artistindex = Cruft.Artistindex", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_played_tracks() {
|
||||||
|
generic_sql_query("CREATE TEMPORARY TABLE Fluff(TTindex INT UNSIGNED NOT NULL UNIQUE, PRIMARY KEY(TTindex)) AS SELECT TTindex FROM Tracktable JOIN Playcounttable USING (TTindex) WHERE isSearchResult = 2", true);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Hidden = 1, isSearchResult = 0 WHERE TTindex IN (SELECT TTindex FROM Fluff)", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_recent_tracks() {
|
||||||
|
global $prefs;
|
||||||
|
$qstring = "SELECT TTindex FROM Tracktable WHERE (DATE_SUB(CURDATE(),INTERVAL 60 DAY) <= DateAdded) AND Hidden = 0 AND isSearchResult < 2 AND isAudiobook = 0 AND Uri IS NOT NULL";
|
||||||
|
if ($prefs['collection_player'] == 'mopidy' && $prefs['player_backend'] == 'mpd') {
|
||||||
|
$qstring .= ' AND Uri LIKE "local:%"';
|
||||||
|
}
|
||||||
|
return $qstring." ORDER BY RAND()";
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_recent_albums() {
|
||||||
|
global $prefs;
|
||||||
|
$qstring = "SELECT TTindex, Albumindex, TrackNo FROM Tracktable WHERE DATE_SUB(CURDATE(),INTERVAL 60 DAY) <= DateAdded AND Hidden = 0 AND isSearchResult < 2 AND isAudiobook = 0 AND Uri IS NOT NULL";
|
||||||
|
if ($prefs['collection_player'] == 'mopidy' && $prefs['player_backend'] == 'mpd') {
|
||||||
|
$qstring .= ' AND Uri LIKE "local:%"';
|
||||||
|
}
|
||||||
|
return $qstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_recently_played() {
|
||||||
|
return "SELECT t.Uri, t.Title, a.Artistname, al.Albumname, al.Image, al.ImgKey, UNIX_TIMESTAMP(p.LastPlayed) AS unixtime FROM Tracktable AS t JOIN Playcounttable AS p USING (TTindex) JOIN Albumtable AS al USING (albumindex) JOIN Artisttable AS a ON (a.Artistindex = al.AlbumArtistindex) WHERE DATE_SUB(CURDATE(),INTERVAL 14 DAY) <= p.LastPlayed AND p.LastPlayed IS NOT NULL ORDER BY p.LastPlayed DESC";
|
||||||
|
}
|
||||||
|
|
||||||
|
function recently_played_playlist() {
|
||||||
|
$qstring = "SELECT TTindex FROM Playcounttable JOIN Tracktable USING (TTindex) WHERE DATE_SUB(CURDATE(),INTERVAL 14 DAY) <= LastPlayed AND LastPlayed IS NOT NULL AND isAudiobook = 0 AND Hidden = 0";
|
||||||
|
return $qstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_two_weeks() {
|
||||||
|
return "DATE_SUB(CURDATE(),INTERVAL 14 DAY) > LastPlayed";
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_two_weeks_include($days) {
|
||||||
|
return "DATE_SUB(CURDATE(),INTERVAL ".$days." DAY) <= LastPlayed AND LastPlayed IS NOT NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_to_unixtime($s) {
|
||||||
|
return "UNIX_TIMESTAMP(".$s.")";
|
||||||
|
}
|
||||||
|
|
||||||
|
function track_date_check($range, $flag) {
|
||||||
|
if ($flag == 'b') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
switch ($range) {
|
||||||
|
case ADDED_ALL_TIME:
|
||||||
|
return '';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_TODAY:
|
||||||
|
return 'AND DATE_SUB(CURDATE(), INTERVAL 1 DAY) <= DateAdded';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_THIS_WEEK:
|
||||||
|
return 'AND DATE_SUB(CURDATE(), INTERVAL 7 DAY) <= DateAdded';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_THIS_MONTH:
|
||||||
|
return 'AND DATE_SUB(CURDATE(), INTERVAL 1 MONTH) <= DateAdded';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_THIS_YEAR:
|
||||||
|
return 'AND DATE_SUB(CURDATE(), INTERVAL 1 YEAR) <= DateAdded';
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger::warn("SQL", "ERROR! Unknown Collection Range ".$range);
|
||||||
|
return '';
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_conditional_triggers() {
|
||||||
|
generic_sql_query("CREATE TRIGGER track_insert_trigger AFTER INSERT ON Tracktable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
IF (NEW.Hidden=0)
|
||||||
|
THEN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = NEW.Albumindex;
|
||||||
|
END IF;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER track_update_trigger AFTER UPDATE ON Tracktable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
IF (NEW.Hidden=0)
|
||||||
|
THEN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = NEW.Albumindex;
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = OLD.Albumindex;
|
||||||
|
END IF;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_playcount_triggers() {
|
||||||
|
generic_sql_query("CREATE TRIGGER syncupdatetrigger BEFORE UPDATE ON Playcounttable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
IF (NEW.Playcount > OLD.Playcount)
|
||||||
|
THEN
|
||||||
|
SET NEW.SyncCount = OLD.SyncCount + 1;
|
||||||
|
END IF;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER syncinserttrigger BEFORE INSERT ON Playcounttable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
SET NEW.SyncCount = 1;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_update_triggers() {
|
||||||
|
|
||||||
|
logger::debug("MYSQL", "Creating Triggers for update operation");
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER rating_update_trigger AFTER UPDATE ON Ratingtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
UPDATE Tracktable SET Hidden = 0, justAdded = 1 WHERE Hidden = 1 AND TTindex = NEW.TTindex;
|
||||||
|
UPDATE Tracktable SET isSearchResult = 1, LastModified = NULL, justAdded = 1 WHERE isSearchResult > 1 AND TTindex = NEW.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER rating_insert_trigger AFTER INSERT ON Ratingtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
UPDATE Tracktable SET Hidden = 0, justAdded = 1 WHERE Hidden = 1 AND TTindex = NEW.TTindex;
|
||||||
|
UPDATE Tracktable SET isSearchResult = 1, LastModified = NULL, justAdded = 1 WHERE isSearchResult > 1 AND TTindex = NEW.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER tag_delete_trigger AFTER DELETE ON Tagtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM TagListtable WHERE Tagindex = OLD.Tagindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER tag_insert_trigger AFTER INSERT ON TagListtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
UPDATE Tracktable SET Hidden = 0, justAdded = 1 WHERE Hidden = 1 AND TTindex = NEW.TTindex;
|
||||||
|
UPDATE Tracktable SET isSearchResult = 1, LastModified = NULL, justAdded = 1 WHERE isSearchResult > 1 AND TTindex = NEW.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER tag_remove_trigger AFTER DELETE ON TagListtable
|
||||||
|
FOR EACH ROW
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = OLD.TTindex);", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER track_delete_trigger AFTER DELETE ON Tracktable
|
||||||
|
FOR EACH ROW
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = OLD.Albumindex;", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_progress_triggers() {
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER progress_update_trigger AFTER UPDATE ON Progresstable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER progress_insert_trigger AFTER INSERT ON Progresstable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("backends/sql/backend.php");
|
||||||
|
|
||||||
|
print '<table align="center" style="border-collapse:collapse;width:90%">';
|
||||||
|
$date = '';
|
||||||
|
$result = generic_sql_query(sql_recently_played(), false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
$thisdate = date('l, jS F Y', $obj->unixtime);
|
||||||
|
if ($thisdate != $date) {
|
||||||
|
$date = $thisdate;
|
||||||
|
print '<tr class="tagh datetag"><th colspan="3">'.$date.'</th></tr>';
|
||||||
|
}
|
||||||
|
print '<tr class="draggable clicktrack playable spacerboogie" name="'.rawurlencode($obj->Uri).'">';
|
||||||
|
print '<td width="40px"><img class="smallcover';
|
||||||
|
if ($obj->Image) {
|
||||||
|
print '" src="'.$obj->Image;
|
||||||
|
} else {
|
||||||
|
print ' notfound';
|
||||||
|
}
|
||||||
|
print '" /></td>';
|
||||||
|
print '<td class="dan"><b>'.$obj->Title.'</b><br><i>by</i> <b>'.$obj->Artistname.'</b><br><i>on</i> <b>'.$obj->Albumname.'</b></td>';
|
||||||
|
print '<td class="dan">'.date('H:i', $obj->unixtime).'</td>';
|
||||||
|
print '</tr>';
|
||||||
|
}
|
||||||
|
print '</table>';
|
||||||
|
?>
|
|
@ -0,0 +1,15 @@
|
||||||
|
# These are the settings that I found made a MASSIVE difference to
|
||||||
|
# performance. Make them as high as you dare, except for
|
||||||
|
# innodb_flush_log_at_trx_commit, which should be 0.
|
||||||
|
# NOTE that the last setting can cause you to lose one second's worth
|
||||||
|
# of data on a crash. If this is important, then don't enable this setting
|
||||||
|
# put these in /etc/mysql/conf.d/rompr-tweaks.cnf
|
||||||
|
|
||||||
|
[mysqld]
|
||||||
|
query_cache_limit = 16M
|
||||||
|
query_cache_size = 64M
|
||||||
|
|
||||||
|
binlog_ignore_db = romprdb
|
||||||
|
|
||||||
|
innodb_buffer_pool_size = 64M
|
||||||
|
innodb_flush_log_at_trx_commit = 0
|
|
@ -0,0 +1,984 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
define('SQL_RANDOM_SORT', 'RANDOM()');
|
||||||
|
define('SQL_TAG_CONCAT', "GROUP_CONCAT(t.Name,', ') ");
|
||||||
|
|
||||||
|
function connect_to_database($sp = true) {
|
||||||
|
global $mysqlc, $prefs;
|
||||||
|
if ($mysqlc !== null) {
|
||||||
|
logger::error("SQLITE", "AWOOOGA! ATTEMPTING MULTIPLE DATABASE CONNECTIONS!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$dsn = "sqlite:prefs/collection.sq3";
|
||||||
|
logger::trace('SQLITE','Opening collection',$dsn);
|
||||||
|
$mysqlc = new PDO($dsn);
|
||||||
|
logger::debug("MYSQL", "Connected to SQLite");
|
||||||
|
// This increases performance
|
||||||
|
generic_sql_query('PRAGMA journal_mode=DELETE', true);
|
||||||
|
generic_sql_query('PRAGMA cache_size=-4000', true);
|
||||||
|
generic_sql_query('PRAGMA synchronous=OFF', true);
|
||||||
|
generic_sql_query('PRAGMA threads=4', true);
|
||||||
|
readCollectionPlayer($sp);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
logger::error("MYSQL", "Couldn't Connect To SQLite - ".$e);
|
||||||
|
sql_init_fail($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function close_database() {
|
||||||
|
global $mysqlc;
|
||||||
|
$mysqlc = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_sql_tables() {
|
||||||
|
global $mysqlc, $prefs;
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Tracktable(".
|
||||||
|
"TTindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Albumindex INTEGER, ".
|
||||||
|
"TrackNo SMALLINT, ".
|
||||||
|
"Duration INTEGER, ".
|
||||||
|
"Artistindex INTEGER, ".
|
||||||
|
"Disc TINYINT(3), ".
|
||||||
|
"Uri TEXT,".
|
||||||
|
"LastModified CHAR(32), ".
|
||||||
|
"Hidden TINYINT(1) DEFAULT 0, ".
|
||||||
|
"DateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ".
|
||||||
|
"isSearchResult TINYINT(1) DEFAULT 0, ".
|
||||||
|
"Sourceindex INTEGER DEFAULT NULL, ".
|
||||||
|
"LinkChecked TINYINT(1) DEFAULT 0, ".
|
||||||
|
"isAudiobook TINYINT(1) DEFAULT 0, ".
|
||||||
|
"justAdded TINYINT(1) DEFAULT 1)", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Tracktable OK");
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS ai ON Tracktable (Albumindex)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tracktable : ".$err);
|
||||||
|
}
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS ti ON Tracktable (Title)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tracktable : ".$err);
|
||||||
|
}
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS tn ON Tracktable (TrackNo)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tracktable : ".$err);
|
||||||
|
}
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS di ON Tracktable (Disc)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tracktable : ".$err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tracktable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Albumtable(".
|
||||||
|
"Albumindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Albumname VARCHAR(255), ".
|
||||||
|
"AlbumArtistindex INTEGER, ".
|
||||||
|
"AlbumUri VARCHAR(255), ".
|
||||||
|
"Year YEAR, ".
|
||||||
|
"Searched TINYINT(1), ".
|
||||||
|
"ImgKey CHAR(32), ".
|
||||||
|
"mbid CHAR(40), ".
|
||||||
|
"ImgVersion INTEGER DEFAULT ".ROMPR_IMAGE_VERSION.", ".
|
||||||
|
"Domain CHAR(32), ".
|
||||||
|
"Image VARCHAR(255), ".
|
||||||
|
"justUpdated TINYINT(1) DEFAULT 0)", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Albumtable OK");
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS ni ON Albumtable (Albumname)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Albumtable : ".$err);
|
||||||
|
}
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS aai ON Albumtable (AlbumArtistindex)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Albumtable : ".$err);
|
||||||
|
}
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS di ON Albumtable (Domain)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Albumtable : ".$err);
|
||||||
|
}
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS ii ON Albumtable (ImgKey)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Albumtable : ".$err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Albumtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Artisttable(".
|
||||||
|
"Artistindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Artistname VARCHAR(255))", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Artisttable OK");
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS ni ON Artisttable (Artistname)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Artisttable : ".$err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Artisttable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Ratingtable(".
|
||||||
|
"TTindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Rating TINYINT(1))", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Ratingtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Ratingtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Progresstable(".
|
||||||
|
"TTindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Progress INTEGER)", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Progresstable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Progresstable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Tagtable(".
|
||||||
|
"Tagindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Name VARCHAR(255))", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Tagtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Tagtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS TagListtable(".
|
||||||
|
"Tagindex INTEGER NOT NULL REFERENCES Tagtable(Tagindex), ".
|
||||||
|
"TTindex INTEGER NOT NULL REFERENCES Tracktable(TTindex), ".
|
||||||
|
"PRIMARY KEY (Tagindex, TTindex))", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " TagListtable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking TagListtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Playcounttable(".
|
||||||
|
"TTindex INTEGER PRIMARY KEY NOT NULL UNIQUE REFERENCES Tracktable(TTindex), ".
|
||||||
|
"Playcount INT UNSIGNED NOT NULL, ".
|
||||||
|
"SyncCount INT UNSIGNED DEFAULT 0, ".
|
||||||
|
"LastPlayed TIMESTAMP DEFAULT NULL)", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Playcounttable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Playcounttable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!generic_sql_query("CREATE TABLE IF NOT EXISTS Statstable(Item CHAR(11), Value INTEGER, PRIMARY KEY(Item))", true)) {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Statstable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS Podcasttable(".
|
||||||
|
"PODindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"FeedURL TEXT, ".
|
||||||
|
"LastUpdate INTEGER, ".
|
||||||
|
"Image VARCHAR(255), ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Artist VARCHAR(255), ".
|
||||||
|
"RefreshOption TINYINT(2) DEFAULT 0, ".
|
||||||
|
"SortMode TINYINT(2) DEFAULT 0, ".
|
||||||
|
"HideDescriptions TINYINT(1) DEFAULT 0, ".
|
||||||
|
"DisplayMode TINYINT(2) DEFAULT 0, ".
|
||||||
|
"DaysToKeep INTEGER DEFAULT 0, ".
|
||||||
|
"NumToKeep INTEGER DEFAULT 0, ".
|
||||||
|
"KeepDownloaded TINYINT(1) DEFAULT 0, ".
|
||||||
|
"AutoDownload TINYINT(1) DEFAULT 0, ".
|
||||||
|
"DaysLive INTEGER, ".
|
||||||
|
"Version TINYINT(2), ".
|
||||||
|
"Subscribed TINYINT(1) NOT NULL DEFAULT 1, ".
|
||||||
|
"Description TEXT, ".
|
||||||
|
"LastPubDate INTEGER DEFAULT NULL, ".
|
||||||
|
"Category VARCHAR(255))", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " Podcasttable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking Podcasttable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS PodcastTracktable(".
|
||||||
|
"PODTrackindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"JustUpdated TINYINT(1), ".
|
||||||
|
"PODindex INTEGER, ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Artist VARCHAR(255), ".
|
||||||
|
"Duration INTEGER, ".
|
||||||
|
"PubDate INTEGER, ".
|
||||||
|
"FileSize INTEGER, ".
|
||||||
|
"Description TEXT, ".
|
||||||
|
"Link TEXT, ".
|
||||||
|
"Guid TEXT, ".
|
||||||
|
"Localfilename VARCHAR(255), ".
|
||||||
|
"Downloaded TINYINT(1) DEFAULT 0, ".
|
||||||
|
"Listened TINYINT(1) DEFAULT 0, ".
|
||||||
|
"New TINYINT(1) DEFAULT 1, ".
|
||||||
|
"Progress INTEGER DEFAULT 0, ".
|
||||||
|
"Deleted TINYINT(1) DEFAULT 0)", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " PodcastTracktable OK");
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS ptt ON PodcastTracktable (Title)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking PodcastTracktable : ".$err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking PodcastTracktable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS RadioStationtable(".
|
||||||
|
"Stationindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Number SMALLINT DEFAULT 65535, ".
|
||||||
|
"IsFave TINYINT(1), ".
|
||||||
|
"StationName VARCHAR(255), ".
|
||||||
|
"PlaylistUrl TEXT, ".
|
||||||
|
"Image VARCHAR(255))", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " RadioStationtable OK");
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS ui ON RadioStationtable (PlaylistUrl)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking RadioStationtable : ".$err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking RadioStationtable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS RadioTracktable(".
|
||||||
|
"Trackindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Stationindex INTEGER REFERENCES RadioStationtable(Stationindex), ".
|
||||||
|
"TrackUri TEXT, ".
|
||||||
|
"PrettyStream TEXT)", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " RadioTracktable OK");
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS uri ON RadioTracktable (TrackUri)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking RadioTracktable : ".$err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking RadioTracktable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS WishlistSourcetable(".
|
||||||
|
"Sourceindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"SourceName VARCHAR(255), ".
|
||||||
|
"SourceImage VARCHAR(255), ".
|
||||||
|
"SourceUri TEXT)", true))
|
||||||
|
{
|
||||||
|
logger::log("SQLITE_CONNECT", " WishlistSourcetable OK");
|
||||||
|
if (generic_sql_query("CREATE INDEX IF NOT EXISTS suri ON WishlistSourcetable (SourceUri)", true)) {
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking WishlistSourcetable : ".$err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking WishlistSourcetable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS AlbumsToListenTotable(".
|
||||||
|
"Listenindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"JsonData TEXT)", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " AlbumsToListenTotabletable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking AlbumsToListenTotable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (generic_sql_query("CREATE TABLE IF NOT EXISTS BackgroundImageTable(".
|
||||||
|
"BgImageIndex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Skin VARCHAR(255), ".
|
||||||
|
"BrowserID VARCHAR(20) DEFAULT NULL, ".
|
||||||
|
"Filename VARCHAR(255), ".
|
||||||
|
"Orientation TINYINT(2))", true))
|
||||||
|
{
|
||||||
|
logger::log("MYSQL_CONNECT", " BackgounrdImageTable OK");
|
||||||
|
} else {
|
||||||
|
$err = $mysqlc->errorInfo()[2];
|
||||||
|
return array(false, "Error While Checking BackgroundImageTable : ".$err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check schema version and update tables as necessary
|
||||||
|
$sv = simple_query('Value', 'Statstable', 'Item', 'SchemaVer', 0);
|
||||||
|
if ($sv == 0) {
|
||||||
|
logger::log("SQLITE_CONNECT", "No Schema Version Found - initialising table");
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('ListVersion', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('ArtistCount', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('AlbumCount', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('TrackCount', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('TotalTime', '0')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('CollType', '999')", true);
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('SchemaVer', '".ROMPR_SCHEMA_VERSION."')", true);
|
||||||
|
$sv = ROMPR_SCHEMA_VERSION;
|
||||||
|
logger::log("SQLITE_CONNECT", "Statstable populated");
|
||||||
|
create_update_triggers();
|
||||||
|
create_conditional_triggers();
|
||||||
|
create_playcount_triggers();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($sv > ROMPR_SCHEMA_VERSION) {
|
||||||
|
logger::log("SQLITE_CONNECT", "Schema Mismatch! We are version ".ROMPR_SCHEMA_VERSION." but database is version ".$sv);
|
||||||
|
return array(false, "Your database has version number ".$sv." but this version of rompr only handles version ".ROMPR_SCHEMA_VERSION);
|
||||||
|
}
|
||||||
|
|
||||||
|
while ($sv < ROMPR_SCHEMA_VERSION) {
|
||||||
|
switch ($sv) {
|
||||||
|
case 0:
|
||||||
|
logger::log("SQL", "BIG ERROR! No Schema Version found!!");
|
||||||
|
return array(false, "Database Error - could not read schema version. Cannot continue.");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 11:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 11 TO Scheme version 12");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD isSearchResult TINYINT(1) DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 12 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 12;
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 12 TO Scheme version 13");
|
||||||
|
// First attempt didn't work
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 13 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 13:
|
||||||
|
// SQLite doesn't let you rename or remove a column. Holy Shitting heck.
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 13 TO Schema version 14");
|
||||||
|
generic_sql_query("CREATE TABLE Albumtable_New(".
|
||||||
|
"Albumindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Albumname VARCHAR(255), ".
|
||||||
|
"AlbumArtistindex INTEGER, ".
|
||||||
|
"AlbumUri VARCHAR(255), ".
|
||||||
|
"Year YEAR, ".
|
||||||
|
"Searched TINYINT(1), ".
|
||||||
|
"ImgKey CHAR(32), ".
|
||||||
|
"mbid CHAR(40), ".
|
||||||
|
"Domain CHAR(32), ".
|
||||||
|
"Image VARCHAR(255))", true);
|
||||||
|
generic_sql_query("INSERT INTO Albumtable_New SELECT Albumindex, Albumname,
|
||||||
|
AlbumArtistindex, Spotilink AS AlbumUri, Year, Searched, ImgKey, mbid, Domain, Image
|
||||||
|
FROM Albumtable", true);
|
||||||
|
generic_sql_query("DROP TABLE Albumtable", true);
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable_New RENAME TO Albumtable", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS ni ON Albumtable (Albumname)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS aai ON Albumtable (AlbumArtistindex)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS di ON Albumtable (Domain)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS ii ON Albumtable (ImgKey)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 14 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 14:
|
||||||
|
// SQLite doesn't let you rename or remove a column. Holy Shitting heck.
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 14 TO Schema version 15");
|
||||||
|
generic_sql_query("CREATE TABLE Tracktable_New(".
|
||||||
|
"TTindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Albumindex INTEGER, ".
|
||||||
|
"TrackNo SMALLINT, ".
|
||||||
|
"Duration INTEGER, ".
|
||||||
|
"Artistindex INTEGER, ".
|
||||||
|
"Disc TINYINT(3), ".
|
||||||
|
"Uri VARCHAR(2000) ,".
|
||||||
|
"LastModified CHAR(32), ".
|
||||||
|
"Hidden TINYINT(1) DEFAULT 0, ".
|
||||||
|
"DateAdded TIMESTAMP DEFAULT CURRENT_TIMESTAMP, ".
|
||||||
|
"isSearchResult TINYINT(1) DEFAULT 0)", true);
|
||||||
|
generic_sql_query("INSERT INTO Tracktable_New SELECT TTindex, Title, Albumindex,
|
||||||
|
TrackNo, Duration, Artistindex, Disc, Uri, LastModified, Hidden, DateAdded, isSearchResult
|
||||||
|
FROM Tracktable", true);
|
||||||
|
generic_sql_query("DROP TABLE Tracktable", true);
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable_New RENAME TO Tracktable", true);
|
||||||
|
generic_sql_query("CREATE TRIGGER IF NOT EXISTS updatetime AFTER UPDATE ON Tracktable BEGIN UPDATE Tracktable SET DateAdded = CURRENT_TIMESTAMP WHERE TTindex = old.TTindex; END", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS ai ON Tracktable (Albumindex)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS ti ON Tracktable (Title)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS tn ON Tracktable (TrackNo)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS di ON Tracktable (Disc)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 15 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 15:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 15 TO Schema version 16");
|
||||||
|
albumImageBuggery();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 16 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 16:
|
||||||
|
//Nothing to do here
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 16 TO Schema version 17");
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 17 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 17:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 17 TO Schema version 18");
|
||||||
|
include("utils/podcastupgrade.php");
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 18 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 18:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 18 TO Schema version 19");
|
||||||
|
$result = generic_sql_query('SELECT Tracktable.Uri AS uri, Tracktable.TTindex, Tracktable.Title AS ttit, Albumtable.*, Trackimagetable.Image AS ti FROM Tracktable JOIN Albumtable USING (Albumindex) LEFT JOIN Trackimagetable USING (TTindex) WHERE Tracktable.Uri LIKE "soundcloud:%"', false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
logger::log("SQL", " Creating new Album ".$obj->ttit." Image ".$obj->ti);
|
||||||
|
$ti = $obj->ti;
|
||||||
|
if (preg_match('/^http/', $ti)) {
|
||||||
|
$ti = 'getRemoteImage.php?url='.$ti;
|
||||||
|
}
|
||||||
|
if (sql_prepare_query(true, null, null, null,
|
||||||
|
"INSERT INTO Albumtable
|
||||||
|
(Albumname, AlbumArtistindex, AlbumUri, Year, Searched, ImgKey, mbid, Domain, Image)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
$obj->ttit, $obj->AlbumArtistindex, $obj->uri, $obj->Year, $obj->Searched, $obj->ImgKey, $obj->mbid, $obj->Domain, $ti
|
||||||
|
)) {
|
||||||
|
$retval = $mysqlc->lastInsertId();
|
||||||
|
logger::log("SQL", " .. success, Albumindex ".$retval);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Albumindex = ".$retval." WHERE TTindex = ".$obj->TTindex, true);
|
||||||
|
} else {
|
||||||
|
logger::log("SQL", " .. ERROR!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 19 WHERE Item = 'SchemaVer'");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 19:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 19 TO Schema version 20");
|
||||||
|
$result = generic_sql_query('SELECT Tracktable.Uri AS uri, Tracktable.TTindex, Tracktable.Title AS ttit, Albumtable.*, Trackimagetable.Image AS ti FROM Tracktable JOIN Albumtable USING (Albumindex) LEFT JOIN Trackimagetable USING (TTindex) WHERE Tracktable.Uri LIKE "youtube:%"', false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
logger::log("SQL", " Creating new Album ".$obj->ttit." Image ".$obj->ti);
|
||||||
|
$ti = $obj->ti;
|
||||||
|
if (preg_match('/^http/', $ti)) {
|
||||||
|
$ti = 'getRemoteImage.php?url='.$ti;
|
||||||
|
}
|
||||||
|
if (sql_prepare_query(true, null, null, null,
|
||||||
|
"INSERT INTO Albumtable
|
||||||
|
(Albumname, AlbumArtistindex, AlbumUri, Year, Searched, ImgKey, mbid, Domain, Image)
|
||||||
|
VALUES
|
||||||
|
(?, ?, ?, ?, ?, ?, ?, ?, ?)",
|
||||||
|
$obj->ttit, $obj->AlbumArtistindex, $obj->uri, $obj->Year, $obj->Searched, $obj->ImgKey, $obj->mbid, $obj->Domain, $ti
|
||||||
|
)) {
|
||||||
|
$retval = $mysqlc->lastInsertId();
|
||||||
|
logger::log("SQL", " .. success, Albumindex ".$retval);
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Albumindex = ".$retval." WHERE TTindex = ".$obj->TTindex, true);
|
||||||
|
} else {
|
||||||
|
logger::log("SQL", " .. ERROR!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 20 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 20:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 20 TO Schema version 21");
|
||||||
|
generic_sql_query("DROP TABLE Trackimagetable", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 21 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 21:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 21 TO Schema version 22");
|
||||||
|
generic_sql_query("ALTER TABLE Playcounttable ADD COLUMN LastPlayed TIMESTAMP DEFAULT NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 22 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 22:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 22 TO Schema version 23");
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable ADD COLUMN Version TINYINT(2)", true);
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable ADD COLUMN Guid VARCHAR(2000)", true);
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable ADD COLUMN Localfilename VARCHAR(255)", true);
|
||||||
|
generic_sql_query("UPDATE Podcasttable SET Version = 1 WHERE PODindex IS NOT NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 23 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 23:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 23 TO Schema version 24");
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS updatetime", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 24 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 24:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 24 TO Schema version 25");
|
||||||
|
// Nothing to do here
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 25 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 25:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 25 TO Schema version 26");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD justAdded TINYINT(1) DEFAULT 1", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 26 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 26:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 26 TO Schema version 27");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable ADD justUpdated TINYINT(1) DEFAULT 1", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 27 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 27:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 27 TO Schema version 28");
|
||||||
|
rejig_wishlist_tracks();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 28 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 28:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 28 TO Schema version 29");
|
||||||
|
create_update_triggers();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 29 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 29:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 29 TO Schema version 30");
|
||||||
|
include('utils/radioupgrade.php');
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 30 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 30:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 30 TO Schema version 31");
|
||||||
|
// No need to do anything here
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 31 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 31:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 31 TO Schema version 32");
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable ADD Subscribed TINYINT(1) NOT NULL DEFAULT 1", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 32 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 32:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 32 TO Schema version 33");
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS track_insert_trigger", true);
|
||||||
|
generic_sql_query("DROP TRIGGER IF EXISTS track_update_trigger", true);
|
||||||
|
create_conditional_triggers();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 33 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 33:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 33 TO Schema version 34");
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable ADD COLUMN ImgVersion INTEGER DEFAULT ".ROMPR_IMAGE_VERSION, true);
|
||||||
|
generic_sql_query("UPDATE Albumtable SET ImgVersion = 1",true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 34 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 34:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 34 TO Schema version 35");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD COLUMN Sourceindex INTEGER DEFAULT NULL", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 35 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 35:
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 36 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 36:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 35 TO Schema version 37");
|
||||||
|
$localpods = generic_sql_query("SELECT PODTrackindex, PODindex, LocalFilename FROM PodcastTracktable WHERE LocalFilename IS NOT NULL");
|
||||||
|
foreach ($localpods as $pod) {
|
||||||
|
sql_prepare_query(true, null, null, null, "UPDATE PodcastTracktable SET LocalFilename = ? WHERE PODTrackindex = ?", '/prefs/podcasts/'.$pod['PODindex'].'/'.$pod['PODTrackindex'].'/'.$pod['LocalFilename'], $pod['PODTrackindex']);
|
||||||
|
}
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 37 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 37:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 37 TO Schema version 38");
|
||||||
|
generic_sql_query("CREATE TABLE IF NOT EXISTS Albumtable_New(".
|
||||||
|
"Albumindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"Albumname VARCHAR(255), ".
|
||||||
|
"AlbumArtistindex INTEGER, ".
|
||||||
|
"AlbumUri VARCHAR(255), ".
|
||||||
|
"Year YEAR, ".
|
||||||
|
"Searched TINYINT(1), ".
|
||||||
|
"ImgKey CHAR(32), ".
|
||||||
|
"mbid CHAR(40), ".
|
||||||
|
"ImgVersion INTEGER DEFAULT ".ROMPR_IMAGE_VERSION.", ".
|
||||||
|
"Domain CHAR(32), ".
|
||||||
|
"Image VARCHAR(255), ".
|
||||||
|
"justUpdated TINYINT(1) DEFAULT 0)", true);
|
||||||
|
generic_sql_query("INSERT INTO Albumtable_New SELECT Albumindex, Albumname, AlbumArtistindex,
|
||||||
|
AlbumUri, Year, Searched, ImgKey, mbid, ImgVersion, Domain, Image, justUpdated
|
||||||
|
FROM Albumtable", true);
|
||||||
|
generic_sql_query("DROP TABLE Albumtable", true);
|
||||||
|
generic_sql_query("ALTER TABLE Albumtable_New RENAME TO Albumtable", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS ni ON Albumtable (Albumname)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS aai ON Albumtable (AlbumArtistindex)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS di ON Albumtable (Domain)", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS ii ON Albumtable (ImgKey)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 38 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 38:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 38 TO Schema version 39");
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable ADD LastPubDate INTEGER DEFAULT NULL", true);
|
||||||
|
require_once('includes/podcastfunctions.php');
|
||||||
|
upgrade_podcasts_to_version();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 39 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 39:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 39 TO Schema version 40");
|
||||||
|
// Takes too long. It'll happen when they get refreshed anyway.
|
||||||
|
// require_once('includes/podcastfunctions.php');
|
||||||
|
// upgrade_podcast_images();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 40 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 40:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 40 TO Schema version 41");
|
||||||
|
generic_sql_query("CREATE TABLE IF NOT EXISTS Podcasttable_New(".
|
||||||
|
"PODindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"FeedURL TEXT, ".
|
||||||
|
"LastUpdate INTEGER, ".
|
||||||
|
"Image VARCHAR(255), ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Artist VARCHAR(255), ".
|
||||||
|
"RefreshOption TINYINT(2) DEFAULT 0, ".
|
||||||
|
"SortMode TINYINT(2) DEFAULT 0, ".
|
||||||
|
"HideDescriptions TINYINT(1) DEFAULT 0, ".
|
||||||
|
"DisplayMode TINYINT(2) DEFAULT 0, ".
|
||||||
|
"DaysToKeep INTEGER DEFAULT 0, ".
|
||||||
|
"NumToKeep INTEGER DEFAULT 0, ".
|
||||||
|
"KeepDownloaded TINYINT(1) DEFAULT 0, ".
|
||||||
|
"AutoDownload TINYINT(1) DEFAULT 0, ".
|
||||||
|
"DaysLive INTEGER, ".
|
||||||
|
"Version TINYINT(2), ".
|
||||||
|
"Subscribed TINYINT(1) NOT NULL DEFAULT 1, ".
|
||||||
|
"Description TEXT, ".
|
||||||
|
"LastPubDate INTEGER DEFAULT NULL, ".
|
||||||
|
"Category VARCHAR(255))", true);
|
||||||
|
generic_sql_query("INSERT INTO Podcasttable_New SELECT PODindex, FeedURL, LastUpdate, Image, Title, Artist,
|
||||||
|
RefreshOption, SortMode, HideDescriptions, DisplayMode, DaysToKeep, NumToKeep, KeepDownloaded, AutoDownload,
|
||||||
|
DaysLive, Version, Subscribed, Description, LastPubDate, '' AS Category
|
||||||
|
FROM Podcasttable", true);
|
||||||
|
generic_sql_query("DROP TABLE Podcasttable", true);
|
||||||
|
generic_sql_query("ALTER TABLE Podcasttable_New RENAME TO Podcasttable", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 41 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 41:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 41 TO Schema version 42");
|
||||||
|
generic_sql_query("CREATE TABLE IF NOT EXISTS PodcastTracktable_New(".
|
||||||
|
"PODTrackindex INTEGER PRIMARY KEY NOT NULL UNIQUE, ".
|
||||||
|
"JustUpdated TINYINT(1), ".
|
||||||
|
"PODindex INTEGER, ".
|
||||||
|
"Title VARCHAR(255), ".
|
||||||
|
"Artist VARCHAR(255), ".
|
||||||
|
"Duration INTEGER, ".
|
||||||
|
"PubDate INTEGER, ".
|
||||||
|
"FileSize INTEGER, ".
|
||||||
|
"Description TEXT, ".
|
||||||
|
"Link TEXT, ".
|
||||||
|
"Guid TEXT, ".
|
||||||
|
"Localfilename VARCHAR(255), ".
|
||||||
|
"Downloaded TINYINT(1) DEFAULT 0, ".
|
||||||
|
"Listened TINYINT(1) DEFAULT 0, ".
|
||||||
|
"New TINYINT(1) DEFAULT 1, ".
|
||||||
|
"Progress INTEGER DEFAULT 0, ".
|
||||||
|
"Deleted TINYINT(1) DEFAULT 0)", true);
|
||||||
|
generic_sql_query("INSERT INTO PodcastTracktable_New SELECT PODTrackindex, JustUpdated, PODindex, Title, Artist,
|
||||||
|
Duration, PubDate, FileSize, Description, Link, Guid, Localfilename, Downloaded, Listened, New, 0 AS Progress, Deleted
|
||||||
|
FROM PodcastTracktable", true);
|
||||||
|
generic_sql_query("DROP TABLE PodcastTracktable", true);
|
||||||
|
generic_sql_query("ALTER TABLE PodcastTracktable_New RENAME TO PodcastTracktable", true);
|
||||||
|
generic_sql_query("CREATE INDEX IF NOT EXISTS ptt ON PodcastTracktable (Title)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 42 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 42:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 42 TO Schema version 43");
|
||||||
|
update_stream_images(43);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 43 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 43:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 43 TO Schema version 44");
|
||||||
|
empty_modified_cache_dirs(44);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 44 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 44:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 44 TO Schema version 45");
|
||||||
|
upgrade_host_defs(45);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 45 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 45:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 45 TO Schema version 46");
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 46 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 46:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 46 TO Schema version 47");
|
||||||
|
generic_sql_query("ALTER TABLE Playcounttable ADD COLUMN SyncCount INT UNSIGNED DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 47 WHERE Item = 'SchemaVer'", true);
|
||||||
|
create_playcount_triggers();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 47:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 47 TO Schema version 48");
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 48 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 48:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 48 TO Schema version 49");
|
||||||
|
upgrade_host_defs(49);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 49 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 49:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 49 TO Schema version 50");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD COLUMN LinkChecked TINYINT(1) DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 50 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 50:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 50 TO Schema version 51");
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 51 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 51:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 51 TO Schema version 52");
|
||||||
|
generic_sql_query("ALTER TABLE Tracktable ADD COLUMN isAudiobook TINYINT(1) DEFAULT 0", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 52 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 52:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 52 TO Schema version 53");
|
||||||
|
create_progress_triggers();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 53 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 53:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 53 TO Schema version 54");
|
||||||
|
require_once ('utils/backgroundimages.php');
|
||||||
|
first_upgrade_of_user_backgrounds();
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 54 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 54:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 54 TO Schema version 55");
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('PodUpPid', 0)", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 55 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 55:
|
||||||
|
logger::log("SQL", "Updating FROM Schema version 55 TO Schema version 56");
|
||||||
|
generic_sql_query("INSERT INTO Statstable (Item, Value) VALUES ('Updating', '0')", true);
|
||||||
|
generic_sql_query("UPDATE Statstable SET Value = 56 WHERE Item = 'SchemaVer'", true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
$sv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return array(true, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_oldtracks() {
|
||||||
|
// generic_sql_query("DROP TABLE IF EXISTS OldTracks", true);
|
||||||
|
// generic_sql_query("CREATE TEMPORARY TABLE OldTracks AS SELECT TTindex FROM Tracktable JOIN Playcounttable USING (TTindex) WHERE Hidden = 1 AND DATETIME('now', '-6 MONTH') > DateAdded AND Playcount < 2", true);
|
||||||
|
// generic_sql_query("DELETE FROM Tracktable WHERE TTindex IN (SELECT TTindex FROM OldTracks)", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_orphaned_artists() {
|
||||||
|
generic_sql_query("DROP TABLE IF EXISTS Croft", true);
|
||||||
|
generic_sql_query("CREATE TEMPORARY TABLE Croft AS SELECT Artistindex FROM Tracktable UNION SELECT AlbumArtistindex FROM Albumtable", true);
|
||||||
|
generic_sql_query("DELETE FROM Artisttable WHERE Artistindex NOT IN (SELECT Artistindex FROM Croft)", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function hide_played_tracks() {
|
||||||
|
generic_sql_query("UPDATE Tracktable SET Hidden = 1, isSearchResult = 0 WHERE TTindex IN (SELECT TTindex FROM Tracktable JOIN Playcounttable USING (TTindex) WHERE isSearchResult = 2)", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_recent_tracks() {
|
||||||
|
global $prefs;
|
||||||
|
$qstring = "SELECT TTindex FROM Tracktable WHERE DATETIME('now', '-2 MONTH') <= DATETIME(DateAdded) AND Hidden = 0 AND isSearchResult < 2 AND isAudiobook = 0 AND Uri IS NOT NULL";
|
||||||
|
if ($prefs['collection_player'] == 'mopidy' && $prefs['player_backend'] == 'mpd') {
|
||||||
|
$qstring .= ' AND Uri LIKE "local:%"';
|
||||||
|
}
|
||||||
|
return $qstring . " ORDER BY RANDOM()";
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_recent_albums() {
|
||||||
|
global $prefs;
|
||||||
|
$qstring = "SELECT TTindex, Albumindex, TrackNo FROM Tracktable WHERE DATETIME('now', '-2 MONTH') <= DATETIME(DateAdded) AND Hidden = 0 AND isSearchResult < 2 AND isAudiobook = 0 AND Uri IS NOT NULL";
|
||||||
|
if ($prefs['collection_player'] == 'mopidy' && $prefs['player_backend'] == 'mpd') {
|
||||||
|
$qstring .= ' AND Uri LIKE "local:%"';
|
||||||
|
}
|
||||||
|
return $qstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_recently_played() {
|
||||||
|
return "SELECT t.Uri, t.Title, a.Artistname, al.Albumname, al.Image, al.ImgKey, CAST(strftime('%s', p.LastPlayed) AS INT) AS unixtime FROM Tracktable AS t JOIN Playcounttable AS p USING (TTindex) JOIN Albumtable AS al USING (albumindex) JOIN Artisttable AS a ON (a.Artistindex = al.AlbumArtistindex) WHERE DATETIME('now', '-14 DAYS') <= DATETIME(p.LastPlayed) AND p.LastPlayed IS NOT NULL ORDER BY p.LastPlayed DESC";
|
||||||
|
}
|
||||||
|
|
||||||
|
function recently_played_playlist() {
|
||||||
|
$qstring = "SELECT TTindex FROM Playcounttable JOIN Tracktable USING (TTindex) WHERE DATETIME('now', '-14 DAYS') <= DATETIME(LastPlayed) AND LastPlayed IS NOT NULL AND isAudiobook = 0 AND Hidden = 0";
|
||||||
|
return $qstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_two_weeks() {
|
||||||
|
return "DATETIME('now', '-14 DAYS') > DATETIME(LastPlayed)";
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_two_weeks_include($days) {
|
||||||
|
return "DATETIME('now', '-".$days." DAYS') <= DATETIME(LastPlayed) AND LastPlayed IS NOT NULL";
|
||||||
|
}
|
||||||
|
|
||||||
|
function sql_to_unixtime($s) {
|
||||||
|
return "CAST(strftime('%s', ".$s.") AS INT)";
|
||||||
|
}
|
||||||
|
|
||||||
|
function track_date_check($range, $flag) {
|
||||||
|
if ($flag == 'b') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
switch ($range) {
|
||||||
|
case ADDED_ALL_TIME:
|
||||||
|
return '';
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_TODAY:
|
||||||
|
return "AND DATETIME('now', '-1 DAYS') <= DateAdded";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_THIS_WEEK:
|
||||||
|
return "AND DATETIME('now', '-7 DAYS') <= DateAdded";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_THIS_MONTH:
|
||||||
|
return "AND DATETIME('now', '-1 MONTHS') <= DateAdded";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ADDED_THIS_YEAR:
|
||||||
|
return "AND DATETIME('now', '-1 YEAR') <= DateAdded";
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger::error("SQL", "ERROR! Unknown Collection Range ".$range);
|
||||||
|
return '';
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_conditional_triggers() {
|
||||||
|
generic_sql_query("CREATE TRIGGER track_insert_trigger AFTER INSERT ON Tracktable
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN NEW.Hidden=0
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = NEW.Albumindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER track_update_trigger AFTER UPDATE ON Tracktable
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN NEW.Hidden=0
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = NEW.Albumindex;
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = OLD.Albumindex;
|
||||||
|
END;", true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_playcount_triggers() {
|
||||||
|
generic_sql_query("CREATE TRIGGER syncupdatetrigger AFTER UPDATE ON Playcounttable
|
||||||
|
FOR EACH ROW
|
||||||
|
WHEN NEW.Playcount > OLD.Playcount
|
||||||
|
BEGIN
|
||||||
|
UPDATE Playcounttable SET SyncCount = OLD.SyncCount + 1 WHERE TTindex = New.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER syncinserttrigger AFTER INSERT ON Playcounttable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Playcounttable SET SyncCount = 1 WHERE TTindex = NEW.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_update_triggers() {
|
||||||
|
|
||||||
|
logger::trace("SQLITE", "Creating Triggers for update operation");
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER rating_update_trigger AFTER UPDATE ON Ratingtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
UPDATE Tracktable SET Hidden = 0, justAdded = 1 WHERE Hidden = 1 AND TTindex = NEW.TTindex;
|
||||||
|
UPDATE Tracktable SET isSearchResult = 1, LastModified = NULL, justAdded = 1 WHERE isSearchResult > 1 AND TTindex = NEW.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER rating_insert_trigger AFTER INSERT ON Ratingtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
UPDATE Tracktable SET Hidden = 0, justAdded = 1 WHERE Hidden = 1 AND TTindex = NEW.TTindex;
|
||||||
|
UPDATE Tracktable SET isSearchResult = 1, LastModified = NULL, justAdded = 1 WHERE isSearchResult > 1 AND TTindex = NEW.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER tag_delete_trigger AFTER DELETE ON Tagtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
DELETE FROM TagListtable WHERE Tagindex = OLD.Tagindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER tag_insert_trigger AFTER INSERT ON TagListtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
UPDATE Tracktable SET Hidden = 0, justAdded = 1 WHERE Hidden = 1 AND TTindex = NEW.TTindex;
|
||||||
|
UPDATE Tracktable SET isSearchResult = 1, LastModified = NULL, justAdded = 1 WHERE isSearchResult > 1 AND TTindex = NEW.TTindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER tag_remove_trigger AFTER DELETE ON TagListtable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = OLD.TTindex);
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER track_delete_trigger AFTER DELETE ON Tracktable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = OLD.Albumindex;
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function create_progress_triggers() {
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER progress_update_trigger AFTER UPDATE ON Progresstable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
generic_sql_query("CREATE TRIGGER progress_insert_trigger AFTER INSERT ON Progresstable
|
||||||
|
FOR EACH ROW
|
||||||
|
BEGIN
|
||||||
|
UPDATE Albumtable SET justUpdated = 1 WHERE Albumindex = (SELECT Albumindex FROM Tracktable WHERE TTindex = NEW.TTindex);
|
||||||
|
END;", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,631 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
require_once ("includes/vars.php");
|
||||||
|
require_once ("includes/functions.php");
|
||||||
|
require_once ("utils/imagefunctions.php");
|
||||||
|
require_once ("international.php");
|
||||||
|
logger::blurt("USERRATING", "--------------------------START---------------------");
|
||||||
|
require_once ("backends/sql/backend.php");
|
||||||
|
require_once ("backends/sql/metadatafunctions.php");
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
|
||||||
|
$error = 0;
|
||||||
|
$count = 1;
|
||||||
|
$divtype = "album1";
|
||||||
|
$returninfo = array();
|
||||||
|
$download_file = "";
|
||||||
|
$dummydata = array('dummy' => 'baby');
|
||||||
|
|
||||||
|
if ($mysqlc == null) {
|
||||||
|
logger::error("RATINGS", "Can't Do ratings stuff as no SQL connection!");
|
||||||
|
header('HTTP/1.0 403 Forbidden');
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
$start = time();
|
||||||
|
open_transaction();
|
||||||
|
create_foundtracks();
|
||||||
|
$took = time() - $start;
|
||||||
|
logger::debug("TIMINGS", "Creating FoundTracks took ".$took." seconds");
|
||||||
|
|
||||||
|
$params = json_decode(file_get_contents('php://input'), true);
|
||||||
|
|
||||||
|
// If you add new actions remember to update actions_requring_cleanup in metahandlers.js
|
||||||
|
|
||||||
|
foreach($params as $p) {
|
||||||
|
|
||||||
|
romprmetadata::sanitise_data($p);
|
||||||
|
|
||||||
|
logger::mark("USERRATING", "Doing action",strtoupper($p['action']));
|
||||||
|
foreach ($p as $i => $v) {
|
||||||
|
if ($i != 'action' && $v) {
|
||||||
|
logger::log(" Parameter", $i,':',$v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
switch ($p['action']) {
|
||||||
|
|
||||||
|
case 'dummy':
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getplaylist':
|
||||||
|
preparePlaylist();
|
||||||
|
case 'repopulate':
|
||||||
|
$returninfo = doPlaylist($p['playlist'], $p['numtracks']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ratlist':
|
||||||
|
$returninfo = get_rating_headers($p['sortby']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'ratentries':
|
||||||
|
$returninfo = get_rating_info($p['sortby'], $p['value']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'metabackup':
|
||||||
|
backup_unrecoverable_data();
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getbackupdata':
|
||||||
|
$returninfo = analyse_backups();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'backupremove':
|
||||||
|
removeBackup($p['which']);
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'backuprestore':
|
||||||
|
restoreBackup($p['which']);
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'gettags':
|
||||||
|
$returninfo = list_tags();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getfaveartists':
|
||||||
|
$returninfo = get_fave_artists();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getrecommendationseeds';
|
||||||
|
$returninfo = get_recommendation_seeds($p['days'], $p['limit'], $p['top']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'addtolistenlater':
|
||||||
|
addToListenLater($p['json']);
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getlistenlater':
|
||||||
|
$returninfo = getListenLater();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'removelistenlater':
|
||||||
|
removeListenLater($p['index']);
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'getlinktocheck':
|
||||||
|
$returninfo = getLinkToCheck();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'updatelinkcheck':
|
||||||
|
updateCheckedLink($p['ttindex'], $p['uri'], $p['status']);
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'resetlinkcheck':
|
||||||
|
resetLinkCheck();
|
||||||
|
$returninfo = $dummydata;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'get':
|
||||||
|
case 'inc':
|
||||||
|
case "add":
|
||||||
|
case 'set':
|
||||||
|
case 'remove':
|
||||||
|
case 'cleanup':
|
||||||
|
case 'amendalbum':
|
||||||
|
case 'deletetag':
|
||||||
|
case 'delete':
|
||||||
|
case 'deletewl':
|
||||||
|
case 'getcharts':
|
||||||
|
case 'clearwishlist':
|
||||||
|
case 'setalbummbid':
|
||||||
|
case 'syncinc':
|
||||||
|
case 'resetallsyncdata':
|
||||||
|
case 'deleteid':
|
||||||
|
romprmetadata::{$p['action']}($p);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
logger::fail("USERRATINGS", "Unknown Request",$p['action']);
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
break;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
check_transaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($returninfo) == 0 || array_key_exists('metadata', $returninfo)) {
|
||||||
|
// We don't do a database cleanup here. It can take a long time and this
|
||||||
|
// really slows the GUI down. Cleanups and stats updates are done out-of-band
|
||||||
|
// by the frontend DB Queue manager by calling into here with action = cleanup
|
||||||
|
prepare_returninfo();
|
||||||
|
}
|
||||||
|
print json_encode($returninfo);
|
||||||
|
close_transaction();
|
||||||
|
|
||||||
|
logger::blurt("USERRATING", "---------------------------END----------------------");
|
||||||
|
|
||||||
|
function prepare_returninfo() {
|
||||||
|
logger::log("USERRATINGS", "Preparing Return Info");
|
||||||
|
global $returninfo, $prefs;
|
||||||
|
$t = microtime(true);
|
||||||
|
$result = generic_sql_query('SELECT DISTINCT AlbumArtistindex FROM Albumtable WHERE justUpdated = 1');
|
||||||
|
foreach ($result as $mod) {
|
||||||
|
if (artist_albumcount($mod['AlbumArtistindex']) == 0) {
|
||||||
|
$returninfo['deletedartists'][] = $mod['AlbumArtistindex'];
|
||||||
|
logger::mark("USERRATINGS", " Artist ".$mod['AlbumArtistindex']." has no visible albums");
|
||||||
|
} else {
|
||||||
|
logger::mark("USERRATINGS", " Artist ".$mod['AlbumArtistindex']." has modified albums");
|
||||||
|
switch ($prefs['sortcollectionby']) {
|
||||||
|
case 'album':
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'artist':
|
||||||
|
logger::trace("USERRATINGS", " Creating Artist Header");
|
||||||
|
$returninfo['modifiedartists'][] = do_artists_from_database('a', $prefs['sortcollectionby'], $mod['AlbumArtistindex']);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'albumbyartist':
|
||||||
|
if ($prefs['showartistbanners']) {
|
||||||
|
logger::trace("USERRATINGS", " Creating Artist Banner");
|
||||||
|
$returninfo['modifiedartists'][] = do_artist_banner('a','album',$mod['AlbumArtistindex']);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$at = microtime(true) - $t;
|
||||||
|
logger::debug("TIMINGS", " -- Finding modified artists took ".$at." seconds");
|
||||||
|
|
||||||
|
$t = microtime(true);
|
||||||
|
$result = generic_sql_query('SELECT Albumindex, AlbumArtistindex FROM Albumtable WHERE justUpdated = 1');
|
||||||
|
foreach ($result as $mod) {
|
||||||
|
if (album_trackcount($mod['Albumindex']) == 0) {
|
||||||
|
logger::mark("USERRATINGS", " Album ".$mod['Albumindex']." has no visible tracks");
|
||||||
|
$returninfo['deletedalbums'][] = $mod['Albumindex'];
|
||||||
|
} else {
|
||||||
|
logger::mark("USERRATINGS", " Album ".$mod['Albumindex']." was modified");
|
||||||
|
$prefix = check_album_is_album($mod['Albumindex']);
|
||||||
|
switch ($prefs['sortcollectionby']) {
|
||||||
|
case 'album':
|
||||||
|
case 'albumbyartist':
|
||||||
|
$r = do_albums_from_database($prefix, 'album', 'root', $mod['Albumindex'], false, false);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'artist':
|
||||||
|
$r = do_albums_from_database($prefix, 'album', $mod['AlbumArtistindex'], $mod['Albumindex'], false, false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$r['tracklist'] = do_tracks_from_database($prefix, 'album', $mod['Albumindex'], true);
|
||||||
|
$returninfo['modifiedalbums'][] = $r;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$at = microtime(true) - $t;
|
||||||
|
logger::debug("TIMINGS", " -- Finding modified albums took ".$at." seconds");
|
||||||
|
|
||||||
|
$t = microtime(true);
|
||||||
|
$result = generic_sql_query('SELECT Albumindex, AlbumArtistindex, Uri, TTindex FROM Tracktable JOIN Albumtable USING (Albumindex) WHERE justAdded = 1 AND Hidden = 0');
|
||||||
|
foreach ($result as $mod) {
|
||||||
|
logger::log("USERRATING", " New Track in album ".$mod['Albumindex'].' has TTindex '.$mod['TTindex']);
|
||||||
|
$returninfo['addedtracks'][] = array('artistindex' => $mod['AlbumArtistindex'], 'albumindex' => $mod['Albumindex'], 'trackuri' => rawurlencode($mod['Uri']));
|
||||||
|
}
|
||||||
|
$at = microtime(true) - $t;
|
||||||
|
logger::debug("TIMINGS", " -- Finding added tracks took ".$at." seconds");
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_album_is_album($albumindex) {
|
||||||
|
// See if the album is an album or an audiobook
|
||||||
|
$c = simple_query('COUNT(TTindex)', 'Tracktable', 'isAudiobook = 1 AND Albumindex', $albumindex, 0);
|
||||||
|
if ($c > 0) {
|
||||||
|
logger::trace("USERRATINGS", " This is an audiobook");
|
||||||
|
return 'z';
|
||||||
|
} else {
|
||||||
|
return 'a';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function artist_albumcount($artistindex) {
|
||||||
|
return generic_sql_query(
|
||||||
|
"SELECT
|
||||||
|
COUNT(Albumindex) AS num
|
||||||
|
FROM
|
||||||
|
Albumtable LEFT JOIN Tracktable USING (Albumindex)
|
||||||
|
WHERE
|
||||||
|
AlbumArtistindex = ".$artistindex.
|
||||||
|
" AND Hidden = 0
|
||||||
|
AND isSearchResult < 2
|
||||||
|
AND Uri IS NOT NULL", false, null, 'num', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function album_trackcount($albumindex) {
|
||||||
|
return generic_sql_query(
|
||||||
|
"SELECT
|
||||||
|
COUNT(TTindex) AS num
|
||||||
|
FROM
|
||||||
|
Tracktable
|
||||||
|
WHERE
|
||||||
|
Albumindex = ".$albumindex.
|
||||||
|
" AND Hidden = 0
|
||||||
|
AND isSearchResult < 2
|
||||||
|
AND Uri IS NOT NULL", false, null, 'num', 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doCollectionHeader() {
|
||||||
|
global $returninfo;
|
||||||
|
$returninfo['stats'] = collectionStats();
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_backup_dir() {
|
||||||
|
$dirname = date('Y-m-d-H-i');
|
||||||
|
if (is_dir('prefs/databackups/'.$dirname)) {
|
||||||
|
rrmdir('prefs/databackups/'.$dirname);
|
||||||
|
}
|
||||||
|
mkdir('prefs/databackups/'.$dirname, 0755);
|
||||||
|
return 'prefs/databackups/'.$dirname;
|
||||||
|
}
|
||||||
|
|
||||||
|
function backup_unrecoverable_data() {
|
||||||
|
|
||||||
|
// This makes a backup of all manually added tracks and all
|
||||||
|
// rating, tag, and playcount data. This can be used to restore it
|
||||||
|
// or transfer it to another machine
|
||||||
|
|
||||||
|
$dirname = check_backup_dir();
|
||||||
|
|
||||||
|
logger::log("BACKEND", "Backing up manually added tracks");
|
||||||
|
$tracks = get_manually_added_tracks();
|
||||||
|
file_put_contents($dirname.'/tracks.json',json_encode($tracks));
|
||||||
|
|
||||||
|
logger::log("BACKEND", "Backing up ratings");
|
||||||
|
$tracks = get_ratings();
|
||||||
|
file_put_contents($dirname.'/ratings.json',json_encode($tracks));
|
||||||
|
|
||||||
|
logger::log("BACKEND", "Backing up Playcounts");
|
||||||
|
$tracks = get_playcounts();
|
||||||
|
file_put_contents($dirname.'/playcounts.json',json_encode($tracks));
|
||||||
|
|
||||||
|
logger::log("BACKEND", "Backing up Tags");
|
||||||
|
$tracks = get_tags();
|
||||||
|
file_put_contents($dirname.'/tags.json',json_encode($tracks));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function analyse_backups() {
|
||||||
|
$data = array();
|
||||||
|
$bs = glob('prefs/databackups/*');
|
||||||
|
rsort($bs);
|
||||||
|
foreach ($bs as $backup) {
|
||||||
|
// This is nice data to have, but it takes a very long time on a moderate computer
|
||||||
|
// FIXME: We should create these numbers when we create the backup and save them so we can read them in
|
||||||
|
// $tracks = count(json_decode(file_get_contents($backup.'/tracks.json')));
|
||||||
|
// $ratings = count(json_decode(file_get_contents($backup.'/ratings.json')));
|
||||||
|
// $playcounts = count(json_decode(file_get_contents($backup.'/playcounts.json')));
|
||||||
|
// $tags = count(json_decode(file_get_contents($backup.'/tags.json')));
|
||||||
|
$data[] = array(
|
||||||
|
'dir' => basename($backup),
|
||||||
|
'name' => strftime('%c', DateTime::createFromFormat('Y-m-d-H-i', basename($backup))->getTimestamp()),
|
||||||
|
'stats' => array(
|
||||||
|
'Manually Added Tracks' => file_exists($backup.'/tracks.json') ? 'OK' : 'Missing!',
|
||||||
|
'Playcounts' => file_exists($backup.'/playcounts.json') ? 'OK' : 'Missing!',
|
||||||
|
'Tracks With Ratings' => file_exists($backup.'/ratings.json') ? 'OK' : 'Missing!',
|
||||||
|
'Tracks With Tags' => file_exists($backup.'/tags.json') ? 'OK' : 'Missing!',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeBackup($which) {
|
||||||
|
rrmdir('prefs/databackups/'.$which);
|
||||||
|
}
|
||||||
|
|
||||||
|
function restoreBackup($backup) {
|
||||||
|
global $prefs;
|
||||||
|
if (file_exists('prefs/backupmonitor')) {
|
||||||
|
unlink('prefs/backupmonitor');
|
||||||
|
}
|
||||||
|
$monitor = fopen('prefs/backupmonitor', 'w');
|
||||||
|
if (file_exists('prefs/databackups/'.$backup.'/tracks.json')) {
|
||||||
|
logger::mark("BACKUPS", "Restoring Manually Added Tracks");
|
||||||
|
$tracks = json_decode(file_get_contents('prefs/databackups/'.$backup.'/tracks.json'), true);
|
||||||
|
foreach ($tracks as $i => $trackdata) {
|
||||||
|
romprmetadata::sanitise_data($trackdata);
|
||||||
|
romprmetadata::add($trackdata, false);
|
||||||
|
$progress = round(($i/count($tracks))*100);
|
||||||
|
fwrite($monitor, "\n<b>Restoring Manually Added Tracks : </b>".$progress."%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file_exists('prefs/databackups/'.$backup.'/ratings.json')) {
|
||||||
|
logger::mark("BACKUPS", "Restoring Ratings");
|
||||||
|
$tracks = json_decode(file_get_contents('prefs/databackups/'.$backup.'/ratings.json'), true);
|
||||||
|
foreach ($tracks as $i => $trackdata) {
|
||||||
|
romprmetadata::sanitise_data($trackdata);
|
||||||
|
$trackdata['attributes'] = array(array('attribute' => 'Rating', 'value' => $trackdata['rating']));
|
||||||
|
romprmetadata::set($trackdata, true);
|
||||||
|
$progress = round(($i/count($tracks))*100);
|
||||||
|
fwrite($monitor, "\n<b>Restoring Ratings : </b>".$progress."%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file_exists('prefs/databackups/'.$backup.'/tags.json')) {
|
||||||
|
logger::mark("BACKUPS", "Restoring Tags");
|
||||||
|
$tracks = json_decode(file_get_contents('prefs/databackups/'.$backup.'/tags.json'), true);
|
||||||
|
foreach ($tracks as $i => $trackdata) {
|
||||||
|
romprmetadata::sanitise_data($trackdata);
|
||||||
|
$trackdata['attributes'] = array(array('attribute' => 'Tags', 'value' => explode(',',$trackdata['tag'])));
|
||||||
|
romprmetadata::set($trackdata, true);
|
||||||
|
$progress = round(($i/count($tracks))*100);
|
||||||
|
fwrite($monitor, "\n<b>Restoring Tags : </b>".$progress."%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file_exists('prefs/databackups/'.$backup.'/playcounts.json')) {
|
||||||
|
logger::mark("BACKUPS", "Restoring Playcounts");
|
||||||
|
$tracks = json_decode(file_get_contents('prefs/databackups/'.$backup.'/playcounts.json'), true);
|
||||||
|
foreach ($tracks as $i => $trackdata) {
|
||||||
|
romprmetadata::sanitise_data($trackdata);
|
||||||
|
$trackdata['attributes'] = array(array('attribute' => 'Playcount', 'value' => $trackdata['playcount']));
|
||||||
|
if (!array_key_exists('lastplayed', $trackdata)) {
|
||||||
|
// Sanitise backups made before lastplayed was added
|
||||||
|
$trackdata['lastplayed'] = null;
|
||||||
|
}
|
||||||
|
romprmetadata::inc($trackdata);
|
||||||
|
$progress = round(($i/count($tracks))*100);
|
||||||
|
fwrite($monitor, "\n<b>Restoring Playcounts : </b>".$progress."%");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fwrite($monitor, "\n<b>Cleaning Up...</b>");
|
||||||
|
// Now... we may have restored data on tracks that were previously local and now aren't there any more.
|
||||||
|
// If they're local tracks that have been removed, then we don't want them or care about their data
|
||||||
|
if ($prefs['player_backend'] == "mpd") {
|
||||||
|
generic_sql_query("DELETE FROM Tracktable WHERE Uri IS NOT NULL AND LastModified IS NULL AND Hidden = 0", true);
|
||||||
|
} else {
|
||||||
|
generic_sql_query("DELETE FROM Tracktable WHERE Uri LIKE 'local:%' AND LastModified IS NULL AND Hidden = 0", true);
|
||||||
|
}
|
||||||
|
romprmetadata::resetallsyncdata();
|
||||||
|
remove_cruft();
|
||||||
|
update_track_stats();
|
||||||
|
fclose($monitor);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_manually_added_tracks() {
|
||||||
|
|
||||||
|
// get_manually_added_tracks
|
||||||
|
// Creates data for backup
|
||||||
|
|
||||||
|
return generic_sql_query(
|
||||||
|
"SELECT
|
||||||
|
Tracktable.Title AS title,
|
||||||
|
Tracktable.TrackNo AS trackno,
|
||||||
|
Tracktable.Duration AS duration,
|
||||||
|
Tracktable.Disc AS disc,
|
||||||
|
Tracktable.Uri AS uri,
|
||||||
|
Albumtable.Albumname AS album,
|
||||||
|
Albumtable.AlbumUri AS albumuri,
|
||||||
|
Albumtable.Year AS date,
|
||||||
|
ta.Artistname AS artist,
|
||||||
|
aat.Artistname AS albumartist
|
||||||
|
FROM
|
||||||
|
Tracktable
|
||||||
|
JOIN Artisttable AS ta USING (Artistindex)
|
||||||
|
JOIN Albumtable ON Tracktable.Albumindex = Albumtable.Albumindex
|
||||||
|
JOIN Artisttable AS aat ON Albumtable.AlbumArtistindex = aat.Artistindex
|
||||||
|
WHERE Tracktable.LastModified IS NULL AND Tracktable.Hidden = 0 AND Tracktable.isSearchResult < 2 AND uri IS NOT NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_ratings() {
|
||||||
|
|
||||||
|
// get_ratings
|
||||||
|
// Creates data for backup
|
||||||
|
|
||||||
|
return generic_sql_query(
|
||||||
|
"SELECT
|
||||||
|
r.Rating AS rating,
|
||||||
|
tr.Title AS title,
|
||||||
|
tr.TrackNo AS trackno,
|
||||||
|
tr.Duration AS duration,
|
||||||
|
tr.Disc AS disc,
|
||||||
|
tr.Uri AS uri,
|
||||||
|
al.Albumname AS album,
|
||||||
|
al.AlbumUri AS albumuri,
|
||||||
|
al.Year AS date,
|
||||||
|
ta.Artistname AS artist,
|
||||||
|
aat.Artistname AS albumartist
|
||||||
|
FROM
|
||||||
|
Ratingtable AS r
|
||||||
|
JOIN Tracktable AS tr USING (TTindex)
|
||||||
|
JOIN Artisttable AS ta USING (Artistindex)
|
||||||
|
JOIN Albumtable AS al ON tr.Albumindex = al.Albumindex
|
||||||
|
JOIN Artisttable AS aat ON al.AlbumArtistindex = aat.Artistindex
|
||||||
|
WHERE rating > 0 AND tr.Hidden = 0 AND tr.isSearchResult < 2
|
||||||
|
ORDER BY rating, albumartist, album, trackno");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_playcounts() {
|
||||||
|
|
||||||
|
// get_playcounts
|
||||||
|
// Creates data for backup
|
||||||
|
|
||||||
|
return generic_sql_query(
|
||||||
|
"SELECT
|
||||||
|
p.Playcount AS playcount,
|
||||||
|
p.LastPlayed AS lastplayed,
|
||||||
|
tr.Title AS title,
|
||||||
|
tr.TrackNo AS trackno,
|
||||||
|
tr.Duration AS duration,
|
||||||
|
tr.Disc AS disc,
|
||||||
|
tr.Uri AS uri,
|
||||||
|
al.Albumname AS album,
|
||||||
|
al.AlbumUri AS albumuri,
|
||||||
|
al.Year AS date,
|
||||||
|
ta.Artistname AS artist,
|
||||||
|
aat.Artistname AS albumartist
|
||||||
|
FROM
|
||||||
|
Playcounttable AS p
|
||||||
|
JOIN Tracktable AS tr USING (TTindex)
|
||||||
|
JOIN Artisttable AS ta USING (Artistindex)
|
||||||
|
JOIN Albumtable AS al ON tr.Albumindex = al.Albumindex
|
||||||
|
JOIN Artisttable AS aat ON al.AlbumArtistindex = aat.Artistindex
|
||||||
|
WHERE playcount > 0
|
||||||
|
ORDER BY playcount, albumartist, album, trackno");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_tags() {
|
||||||
|
|
||||||
|
// get_tags
|
||||||
|
// Creates data for backup
|
||||||
|
|
||||||
|
return generic_sql_query(
|
||||||
|
"SELECT
|
||||||
|
".SQL_TAG_CONCAT."AS tag,
|
||||||
|
tr.Title AS title,
|
||||||
|
tr.TrackNo AS trackno,
|
||||||
|
tr.Duration AS duration,
|
||||||
|
tr.Disc AS disc,
|
||||||
|
tr.Uri AS uri,
|
||||||
|
al.Albumname AS album,
|
||||||
|
al.AlbumUri AS albumuri,
|
||||||
|
al.Year AS date,
|
||||||
|
ta.Artistname AS artist,
|
||||||
|
aat.Artistname AS albumartist
|
||||||
|
FROM
|
||||||
|
Tagtable AS t
|
||||||
|
JOIN TagListtable AS tl USING (Tagindex)
|
||||||
|
JOIN Tracktable AS tr ON tl.TTindex = tr.TTindex
|
||||||
|
JOIN Artisttable AS ta USING (Artistindex)
|
||||||
|
JOIN Albumtable AS al ON tr.Albumindex = al.Albumindex
|
||||||
|
JOIN Artisttable AS aat ON al.AlbumArtistindex = aat.Artistindex
|
||||||
|
WHERE tr.Hidden = 0 AND tr.isSearchResult < 2
|
||||||
|
GROUP BY tr.TTindex");
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_recommendation_seeds($days, $limit, $top) {
|
||||||
|
|
||||||
|
// 1. Get a list of tracks played in the last $days days, sorted by their OVERALL popularity
|
||||||
|
$resultset = generic_sql_query(
|
||||||
|
"SELECT SUM(Playcount) AS playtotal, Artistname, Title, Uri
|
||||||
|
FROM Playcounttable JOIN Tracktable USING (TTindex)
|
||||||
|
JOIN Artisttable USING (Artistindex)
|
||||||
|
WHERE ".sql_two_weeks_include($days).
|
||||||
|
" AND Uri IS NOT NULL GROUP BY Artistindex ORDER BY playtotal DESC LIMIT ".$limit);
|
||||||
|
|
||||||
|
// 2. Get a list of recently played tracks, ignoring popularity
|
||||||
|
// $result = generic_sql_query(
|
||||||
|
// "SELECT 0 AS playtotal, Artistname, Title, Uri
|
||||||
|
// FROM Playcounttable JOIN Tracktable USING (TTindex)
|
||||||
|
// JOIN Artisttable USING (Artistindex)
|
||||||
|
// WHERE ".sql_two_weeks_include(intval($days/2)).
|
||||||
|
// " AND Uri IS NOT NULL GROUP BY Artistindex ORDER BY ".SQL_RANDOM_SORT." LIMIT ".intval($limit/2));
|
||||||
|
// $resultset = array_merge($resultset, $result);
|
||||||
|
|
||||||
|
// 3. Get the top tracks overall
|
||||||
|
$tracks = get_track_charts(intval($limit/2));
|
||||||
|
foreach ($tracks as $track) {
|
||||||
|
if ($track['uri']) {
|
||||||
|
$resultset[] = array('playtotal' => $track['soundcloud_plays'],
|
||||||
|
'Artistname' => $track['label_artist'],
|
||||||
|
'Title' => $track['label_track'],
|
||||||
|
'Uri' => $track['uri']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Randomise that list and return the first $top.
|
||||||
|
shuffle($resultset);
|
||||||
|
return array_slice($resultset,0,$top);
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_fave_artists() {
|
||||||
|
// Can we have a tuning slider to increase the 'Playcount > x' value?
|
||||||
|
generic_sql_query(
|
||||||
|
"CREATE TEMPORARY TABLE aplaytable AS SELECT SUM(Playcount) AS playtotal, Artistindex FROM
|
||||||
|
(SELECT Playcount, Artistindex FROM Playcounttable JOIN Tracktable USING (TTindex) WHERE
|
||||||
|
Playcount > 10) AS derived GROUP BY Artistindex", true);
|
||||||
|
|
||||||
|
$artists = array();
|
||||||
|
$result = generic_sql_query(
|
||||||
|
"SELECT playtot, Artistname FROM (SELECT SUM(Playcount) AS playtot, Artistindex FROM
|
||||||
|
(SELECT Playcount, Artistindex FROM Playcounttable JOIN Tracktable USING (TTindex)) AS
|
||||||
|
derived GROUP BY Artistindex) AS alias JOIN Artisttable USING (Artistindex) WHERE
|
||||||
|
playtot > (SELECT AVG(playtotal) FROM aplaytable) ORDER BY ".SQL_RANDOM_SORT, false, PDO::FETCH_OBJ);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
logger::log("FAVEARTISTS", "Artist :",$obj->Artistname);
|
||||||
|
$artists[] = array( 'name' => $obj->Artistname, 'plays' => $obj->playtot);
|
||||||
|
}
|
||||||
|
return $artists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addToListenLater($album) {
|
||||||
|
$newid = spotifyAlbumId($album);
|
||||||
|
$result = generic_sql_query("SELECT * FROM AlbumsToListenTotable");
|
||||||
|
foreach ($result as $r) {
|
||||||
|
$d = json_decode($r['JsonData'], true);
|
||||||
|
$thisid = spotifyAlbumId($d);
|
||||||
|
if ($thisid == $newid) {
|
||||||
|
logger::warn("LISTENLATER", "Trying to add duplicate album to Listen Later");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$d = json_encode($album);
|
||||||
|
sql_prepare_query(true, null, null, null, "INSERT INTO AlbumsToListenTotable (JsonData) VALUES (?)", $d);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getListenLater() {
|
||||||
|
$result = generic_sql_query("SELECT * FROM AlbumsToListenTotable");
|
||||||
|
$retval = array();
|
||||||
|
foreach ($result as $r) {
|
||||||
|
$d = json_decode($r['JsonData']);
|
||||||
|
$d->rompr_index = $r['Listenindex'];
|
||||||
|
$retval[] = $d;
|
||||||
|
}
|
||||||
|
return $retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeListenLater($id) {
|
||||||
|
generic_sql_query("DELETE FROM AlbumsToListenTotable WHERE Listenindex = ".$id, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
function spotifyAlbumId($album) {
|
||||||
|
if (array_key_exists('album', $album)) {
|
||||||
|
return $album['album']['id'];
|
||||||
|
} else {
|
||||||
|
return $album['id'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getLinkToCheck() {
|
||||||
|
// LinkChecked:
|
||||||
|
// 0 = Not Checked, Assumed Playable or Playable at last check
|
||||||
|
// 1 = Not Checked, Unplayable at last check
|
||||||
|
// 2 = Checked, Playable
|
||||||
|
// 3 = Checked, Unplayable
|
||||||
|
return generic_sql_query("SELECT TTindex, Uri, LinkChecked FROM Tracktable WHERE Uri LIKE 'spotify:%' AND Hidden = 0 AND isSearchResult < 2 AND LinkChecked < 2 ORDER BY TTindex ASC LIMIT 25");
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCheckedLink($ttindex, $uri, $status) {
|
||||||
|
logger::log("METADATA", "Updating Link Check For TTindex",$ttindex,$uri);
|
||||||
|
sql_prepare_query(true, null, null, null,
|
||||||
|
"UPDATE Tracktable SET LinkChecked = ?, Uri = ? WHERE TTindex = ?", $status, $uri, $ttindex);
|
||||||
|
}
|
||||||
|
|
||||||
|
function resetLinkCheck() {
|
||||||
|
generic_sql_query("UPDATE Tracktable SET LinkChecked = 0 WHERE LinkChecked = 2");
|
||||||
|
generic_sql_query("UPDATE Tracktable SET LinkChecked = 1 WHERE LinkChecked = 3");
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,133 @@
|
||||||
|
<?php
|
||||||
|
ob_start();
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("utils/backgroundimages.php");
|
||||||
|
include ("backends/sql/backend.php");
|
||||||
|
|
||||||
|
foreach($_REQUEST as $i => $r) {
|
||||||
|
logger::log("BACKIMAGE", $i,'=',$r);
|
||||||
|
}
|
||||||
|
|
||||||
|
$retval = array();
|
||||||
|
|
||||||
|
if (array_key_exists('getbackground', $_REQUEST)) {
|
||||||
|
|
||||||
|
$images = sql_prepare_query(false, PDO::FETCH_ASSOC, null, null, 'SELECT * FROM BackgroundImageTable WHERE Skin = ? AND BrowserID = ?', $_REQUEST['getbackground'], $_REQUEST['browser_id']);
|
||||||
|
$thisbrowseronly = true;
|
||||||
|
if (count($images) == 0) {
|
||||||
|
logger::log("BACKIMAGE", "No Custom Backgrounds Exist for",$_REQUEST['getbackground'],$_REQUEST['browser_id']);
|
||||||
|
$images = sql_prepare_query(false, PDO::FETCH_ASSOC, null, null, 'SELECT * FROM BackgroundImageTable WHERE Skin = ? AND BrowserID IS NULL', $_REQUEST['getbackground']);
|
||||||
|
$thisbrowseronly = false;
|
||||||
|
} else {
|
||||||
|
logger::log("BACKIMAGE", "Custom Backgrounds Exist for",$_REQUEST['getbackground'],$_REQUEST['browser_id']);
|
||||||
|
}
|
||||||
|
if (count($images) > 0) {
|
||||||
|
logger::log("BACKIMAGE", "Custom Backgrounds Exist for",$_REQUEST['getbackground']);
|
||||||
|
$retval = array('images' => array('portrait' => array(), 'landscape' => array()), 'thisbrowseronly' => $thisbrowseronly);
|
||||||
|
foreach ($images as $image) {
|
||||||
|
if ($image['Orientation'] == ORIENTATION_PORTRAIT) {
|
||||||
|
$retval['images']['portrait'][] = $image['Filename'];
|
||||||
|
} else {
|
||||||
|
$retval['images']['landscape'][] = $image['Filename'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (array_key_exists('clearbackground', $_REQUEST)) {
|
||||||
|
|
||||||
|
sql_prepare_query(true, null, null, null, 'DELETE FROM BackgroundImageTable WHERE Filename = ?', $_REQUEST['clearbackground']);
|
||||||
|
unlink($_REQUEST['clearbackground']);
|
||||||
|
if (is_numeric(basename(dirname($_REQUEST['clearbackground'])))) {
|
||||||
|
check_empty_directory(dirname('clearbackground'));
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (array_key_exists('clearallbackgrounds', $_REQUEST)) {
|
||||||
|
|
||||||
|
// Remove these here, just in case the folder has been deleted for some reason
|
||||||
|
sql_prepare_query(true, null, null, null, 'DELETE FROM BackgroundImageTable WHERE Skin = ? AND BrowserID = ?', $_REQUEST['clearallbackgrounds'], $_REQUEST['browser_id']);
|
||||||
|
if (is_dir('prefs/userbackgrounds/'.$_REQUEST['clearallbackgrounds'].'/'.$_REQUEST['browser_id'])) {
|
||||||
|
logger::log("BACKIMAGE", "Removing All Backgrounds For ".$_REQUEST['clearallbackgrounds'].'/'.$_REQUEST['browser_id']);
|
||||||
|
delete_files('prefs/userbackgrounds/'.$_REQUEST['clearallbackgrounds'].'/'.$_REQUEST['browser_id']);
|
||||||
|
check_empty_directory('prefs/userbackgrounds/'.$_REQUEST['clearallbackgrounds'].'/'.$_REQUEST['browser_id']);
|
||||||
|
} else if (is_dir('prefs/userbackgrounds/'.$_REQUEST['clearallbackgrounds'])) {
|
||||||
|
logger::log("BACKIMAGE", "Removing All Backgrounds For ".$_REQUEST['clearallbackgrounds']);
|
||||||
|
delete_files('prefs/userbackgrounds/'.$_REQUEST['clearallbackgrounds']);
|
||||||
|
sql_prepare_query(true, null, null, null, 'DELETE FROM BackgroundImageTable WHERE Skin = ? AND BrowserID IS NULL', $_REQUEST['clearallbackgrounds']);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
|
||||||
|
if (!array_key_exists('currbackground', $_REQUEST) || !array_key_exists('imagefile', $_FILES)) {
|
||||||
|
if (isset($_SERVER["CONTENT_LENGTH"])) {
|
||||||
|
if ($_SERVER["CONTENT_LENGTH"] > ((int) ini_get('post_max_size')*1024*1024)) {
|
||||||
|
logger::warn("BACKIMAGE", "Content Length Error");
|
||||||
|
header("HTTP/1.1 400 Bad Request", 'BACKIMAGE');
|
||||||
|
ob_flush();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
logger::warn("BACKIMAGE", "Some kind of upload error");
|
||||||
|
header("HTTP/1.1 500 Internal Server Error");
|
||||||
|
ob_flush();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
$skin = $_REQUEST['currbackground'];
|
||||||
|
$base = $skin;
|
||||||
|
$browserid = null;
|
||||||
|
if (array_key_exists('thisbrowseronly', $_REQUEST)) {
|
||||||
|
$base .= '/'.$_REQUEST['browser_id'];
|
||||||
|
$browserid = $_REQUEST['browser_id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$files = make_files_useful($_FILES['imagefile']);
|
||||||
|
foreach ($files as $filedata) {
|
||||||
|
$file = $filedata['name'];
|
||||||
|
logger::log("BACKIMAGE", "Uploading File ".$file);
|
||||||
|
$fname = format_for_url(format_for_disc(basename($file)));
|
||||||
|
$download_file = get_user_file($file, $fname, $filedata['tmp_name']);
|
||||||
|
if (!is_dir('prefs/userbackgrounds/'.$base)) {
|
||||||
|
mkdir('prefs/userbackgrounds/'.$base, 0755, true);
|
||||||
|
}
|
||||||
|
$file = 'prefs/userbackgrounds/'.$base.'/'.$fname;
|
||||||
|
if (file_exists($file)) {
|
||||||
|
logger::trace("BACKIMAGE", "Image",$file,"already exists");
|
||||||
|
unlink($download_file);
|
||||||
|
} else {
|
||||||
|
rename($download_file, $file);
|
||||||
|
$orientation = analyze_background_image($file);
|
||||||
|
sql_prepare_query(true, null, null, null, 'INSERT INTO BackgroundImageTable (Skin, BrowserID, Filename, Orientation) VALUES (?, ?, ?, ?)', $skin, $browserid, $file, $orientation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
print json_encode($retval);
|
||||||
|
|
||||||
|
ob_flush();
|
||||||
|
|
||||||
|
function check_empty_directory($dir) {
|
||||||
|
if (is_dir($dir) && !(new FilesystemIterator($dir))->valid()) {
|
||||||
|
rmdir($dir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function delete_files($path, $expr = '*.*') {
|
||||||
|
// Prevents file not found or could not stat errors
|
||||||
|
$f = glob($path.'/'.$expr);
|
||||||
|
foreach ($f as $file) {
|
||||||
|
unlink($file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function make_files_useful($arr) {
|
||||||
|
$new = array();
|
||||||
|
foreach ($arr as $key => $all) {
|
||||||
|
foreach ($all as $i => $val) {
|
||||||
|
$new[$i][$key] = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $new;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,14 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
$uri = rawurldecode($_REQUEST['uri']);
|
||||||
|
$uri = 'http://'.$prefs['beets_server_location'].'/item/'.$uri;
|
||||||
|
logger::log("GETBEETSINFO", "Getting",$uri);
|
||||||
|
$d = new url_downloader(array('url' => $uri));
|
||||||
|
if ($d->get_data_to_string()) {
|
||||||
|
print $d->get_data();
|
||||||
|
} else {
|
||||||
|
header("HTTP/1.1 404 Not Found");
|
||||||
|
}
|
||||||
|
?>
|
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
include ("getid3/getid3.php");
|
||||||
|
|
||||||
|
$fname = $_POST['file'];
|
||||||
|
$fname = preg_replace('/local:track:/','',$fname);
|
||||||
|
$fname = preg_replace('#file://#','',$fname);
|
||||||
|
$fname = 'prefs/MusicFolders/'.$fname;
|
||||||
|
$artist = $_POST['artist'];
|
||||||
|
$song = $_POST['song'];
|
||||||
|
|
||||||
|
$getID3 = new getID3;
|
||||||
|
$output = null;
|
||||||
|
logger::mark("LYRICS", "Looking for lyrics in",$fname);
|
||||||
|
logger::log("LYRICS", " Artist is",$artist);
|
||||||
|
logger::log("LYRICS", " Song is",$artist);
|
||||||
|
|
||||||
|
if (file_exists($fname)) {
|
||||||
|
logger::log("LYRICS", " File Exists");
|
||||||
|
$tags = $getID3->analyze($fname);
|
||||||
|
getid3_lib::CopyTagsToComments($tags);
|
||||||
|
|
||||||
|
if (array_key_exists('comments', $tags) &&
|
||||||
|
array_key_exists('lyrics', $tags['comments'])) {
|
||||||
|
$output = $tags['comments']['lyrics'][0];
|
||||||
|
} else if (array_key_exists('comments', $tags) &&
|
||||||
|
array_key_exists('unsynchronised_lyric', $tags['comments'])) {
|
||||||
|
$output = $tags['comments']['unsynchronised_lyric'][0];
|
||||||
|
} else if (array_key_exists('quicktime', $tags) &&
|
||||||
|
array_key_exists('moov', $tags['quicktime']) &&
|
||||||
|
array_key_exists('subatoms', $tags['quicktime']['moov'])) {
|
||||||
|
read_apple_awfulness($tags['quicktime']['moov']['subatoms']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($output == null) {
|
||||||
|
$uri = "http://lyrics.wikia.com/api.php?func=getSong&artist=".urlencode($artist)."&song=".urlencode($song)."&fmt=xml";
|
||||||
|
logger::mark("LYRICS", "Trying",$uri);
|
||||||
|
$d = new url_downloader(array(
|
||||||
|
'url' => $uri,
|
||||||
|
'cache' => 'lyrics',
|
||||||
|
'return_data' => true
|
||||||
|
));
|
||||||
|
if ($d->get_data_to_file()) {
|
||||||
|
$l = simplexml_load_string($d->get_data());
|
||||||
|
if ($l->url) {
|
||||||
|
logger::log("LYRICS", " Now Getting",html_entity_decode($l->url));
|
||||||
|
$d2 = new url_downloader(array(
|
||||||
|
'url' => html_entity_decode($l->url),
|
||||||
|
'cache' => 'lyrics',
|
||||||
|
'return_data' => true
|
||||||
|
));
|
||||||
|
if ($d2->get_data_to_file()) {
|
||||||
|
if (preg_match('/\<div class=\'lyricbox\'\>\<script\>.*?\<\/script\>(.*?)\<\!--/', $d2->get_data(), $matches)) {
|
||||||
|
$output = html_entity_decode($matches[1]);
|
||||||
|
} else if (preg_match('/\<div class=\'lyricbox\'\>(.*?)\<div class=\'lyricsbreak\'\>/', $d2->get_data(), $matches)) {
|
||||||
|
$output = html_entity_decode($matches[1]);
|
||||||
|
} else {
|
||||||
|
logger::mark("LYRICS", " Could Not Find Lyrics");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::mark("LYRICS", " Nope, nothing there");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger::mark("LYRICS", " Got lyrics from file");
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($output == null) {
|
||||||
|
$output = '<h3 align=center>'.get_int_text("lyrics_nonefound").'</h3><p>'.get_int_text("lyrics_info").'</p>';
|
||||||
|
}
|
||||||
|
|
||||||
|
print $output;
|
||||||
|
|
||||||
|
function read_apple_awfulness($a) {
|
||||||
|
// Whoever came up with this was on something.
|
||||||
|
// All we want to do is read some metadata...
|
||||||
|
// why do you have to store it in such a horrible, horrible, way?
|
||||||
|
global $output;
|
||||||
|
foreach ($a as $atom) {
|
||||||
|
if (array_key_exists('name', $atom)) {
|
||||||
|
if (preg_match('/lyr$/', $atom['name'])) {
|
||||||
|
$output = preg_replace( '/^.*?data/', '', $atom['data']);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (array_key_exists('subatoms', $atom)) {
|
||||||
|
read_apple_awfulness($atom['subatoms']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,84 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
ob_start();
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
|
||||||
|
if(array_key_exists("url", $_POST)) {
|
||||||
|
$link = get_bio_link($_POST['url']);
|
||||||
|
if ($link !== false) {
|
||||||
|
get_allmusic_page($link);
|
||||||
|
} else {
|
||||||
|
print '<p></p>';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
}
|
||||||
|
ob_flush();
|
||||||
|
|
||||||
|
function get_bio_link($url) {
|
||||||
|
$html = '';
|
||||||
|
$d = new url_downloader(array(
|
||||||
|
'url' => $url,
|
||||||
|
'cache' => 'allmusic',
|
||||||
|
'return_data' => true
|
||||||
|
));
|
||||||
|
if ($d->get_data_to_file()) {
|
||||||
|
$DOM = new DOMDocument;
|
||||||
|
@$DOM->loadHTML($d->get_data());
|
||||||
|
$els = getElementsByClass($DOM, 'li', 'biography');
|
||||||
|
if (count($els) > 0) {
|
||||||
|
$e = $els[0];
|
||||||
|
$links = $e->GetElementsByTagName('a');
|
||||||
|
for ($i = 0; $i < $links->length; $i++) {
|
||||||
|
$link = $links->item($i)->getAttribute('href');
|
||||||
|
logger::log("AMBIO", "Found Bio Link",$link);
|
||||||
|
}
|
||||||
|
return 'http://www.allmusic.com'.$link;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_allmusic_page($url) {
|
||||||
|
logger::log("AMBIO", "Getting allmusic Page",$url);
|
||||||
|
$r = '<p></p>';
|
||||||
|
$d = new url_downloader(array(
|
||||||
|
'url' => $url,
|
||||||
|
'cache' => 'allmusic',
|
||||||
|
'return_data' => true
|
||||||
|
));
|
||||||
|
if ($d->get_data_to_file()) {
|
||||||
|
$DOM = new DOMDocument;
|
||||||
|
@$DOM->loadHTML($d->get_data());
|
||||||
|
$els = getElementsByClass($DOM, 'div', 'text');
|
||||||
|
foreach ($els as $el) {
|
||||||
|
$a = $el->getAttribute('itemprop');
|
||||||
|
if ($a == 'reviewBody') {
|
||||||
|
logger::trace("AMBIO", "Found Review Body");
|
||||||
|
$r = $el->nodeValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$r = '<p>'.$r.'</p><p>Biography courtesy of AllMusic</p>';
|
||||||
|
}
|
||||||
|
print preg_replace('/\n/', '</p><p>',$r);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElementsByClass(&$parentNode, $tagName, $className) {
|
||||||
|
$nodes=array();
|
||||||
|
|
||||||
|
$childNodeList = $parentNode->getElementsByTagName($tagName);
|
||||||
|
for ($i = 0; $i < $childNodeList->length; $i++) {
|
||||||
|
$temp = $childNodeList->item($i);
|
||||||
|
if (stripos($temp->getAttribute('class'), $className) !== false) {
|
||||||
|
$nodes[]=$temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,60 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
ob_start();
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
|
||||||
|
if(array_key_exists("url", $_POST)) {
|
||||||
|
$link = get_bio_link($_POST['url']);
|
||||||
|
if ($link !== false) {
|
||||||
|
print $link;
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 400 Bad Request');
|
||||||
|
}
|
||||||
|
ob_flush();
|
||||||
|
|
||||||
|
function get_bio_link($url) {
|
||||||
|
$html = '';
|
||||||
|
$d = new url_downloader(array(
|
||||||
|
'url' => $url,
|
||||||
|
'cache' => 'allmusic',
|
||||||
|
'return_data' => true
|
||||||
|
));
|
||||||
|
if ($d->get_data_to_file()) {
|
||||||
|
$DOM = new DOMDocument;
|
||||||
|
@$DOM->loadHTML($d->get_data());
|
||||||
|
$els = getElementsByClass($DOM, 'div', 'artist-contain');
|
||||||
|
if (count($els) > 0) {
|
||||||
|
$e = $els[0];
|
||||||
|
$links = $e->GetElementsByTagName('img');
|
||||||
|
for ($i = 0; $i < $links->length; $i++) {
|
||||||
|
$link = $links->item($i)->getAttribute('src');
|
||||||
|
logger::log("AMIMAGE", "Found Image",$link);
|
||||||
|
}
|
||||||
|
return $link;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getElementsByClass(&$parentNode, $tagName, $className) {
|
||||||
|
$nodes=array();
|
||||||
|
|
||||||
|
$childNodeList = $parentNode->getElementsByTagName($tagName);
|
||||||
|
for ($i = 0; $i < $childNodeList->length; $i++) {
|
||||||
|
$temp = $childNodeList->item($i);
|
||||||
|
if (stripos($temp->getAttribute('class'), $className) !== false) {
|
||||||
|
$nodes[]=$temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
|
||||||
|
$uri = $_POST['url'];
|
||||||
|
$params = array();
|
||||||
|
foreach ($_POST as $k => $v) {
|
||||||
|
if ($k != 'url') {
|
||||||
|
$params[] = $k.'='.rawurlencode($v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$params[] = 'key=qmBviLdmIHhnxXkzWLHR';
|
||||||
|
$params[] = 'secret=KAtjSjsJJlfQjdCXUrnbyXAltXDfelaV';
|
||||||
|
if (count($params) > 0) {
|
||||||
|
$uri .= "?".implode('&', $params);
|
||||||
|
}
|
||||||
|
|
||||||
|
getCacheData($uri, 'discogs');
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,18 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
|
||||||
|
$use_cache = $_POST['cache'] == 'true' ? true : false;
|
||||||
|
$params = array();
|
||||||
|
foreach ($_POST as $k => $v) {
|
||||||
|
if ($k != 'cache') {
|
||||||
|
$params[] = $k.'='.rawurlencode($v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$url = "https://ws.audioscrobbler.com/2.0/?";
|
||||||
|
$url .= implode('&', $params);
|
||||||
|
getCacheData($url, 'lastfm', $use_cache);
|
||||||
|
?>
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
|
||||||
|
$uri = $_POST['url'];
|
||||||
|
$params = array();
|
||||||
|
foreach ($_POST as $k => $v) {
|
||||||
|
if ($k != 'url') {
|
||||||
|
$params[] = $k.'='.$v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($params) > 0) {
|
||||||
|
$uri .= "?".implode('&', $params);
|
||||||
|
}
|
||||||
|
getCacheData($uri, 'musicbrainz');
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
$clientid = "6f43d0d67acd6635273ffd6eeed302aa";
|
||||||
|
$uri = $_POST['url'];
|
||||||
|
getCacheData('https://api.soundcloud.com/'.$uri.'?client_id='.$clientid, 'soundcloud', true);
|
||||||
|
?>
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
include ("includes/spotifyauth.php");
|
||||||
|
|
||||||
|
$uri = $_POST['url'];
|
||||||
|
$cache = array_key_exists('cache', $_POST) ? true : false;
|
||||||
|
logger::mark("SPOTIFY", "Downloading",$uri);
|
||||||
|
logger::trace("SPOTIFY", " Cache is",$cache);
|
||||||
|
$filename = 'prefs/jsoncache/spotify/'.md5($uri);
|
||||||
|
if ($cache && file_exists($filename)) {
|
||||||
|
logger::log("SPOTIFY", "Returning cached data");
|
||||||
|
header("Pragma: From Cache");
|
||||||
|
print file_get_contents($filename);
|
||||||
|
} else {
|
||||||
|
list($success, $content, $status) = get_spotify_data($uri);
|
||||||
|
if ($success) {
|
||||||
|
file_put_contents($filename, $content);
|
||||||
|
header("Pragma: Not Cached");
|
||||||
|
print $content;
|
||||||
|
} else {
|
||||||
|
header('HTTP/1.1 '.$status.' '.http_status_code_string($status));
|
||||||
|
$r = array('error' => $status, 'message' => $content);
|
||||||
|
print json_encode($r);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
|
@ -0,0 +1,10 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
|
||||||
|
$uri = rawurldecode($_REQUEST['uri']);
|
||||||
|
logger::mark("GOOGLE", "Getting",$uri);
|
||||||
|
getCacheData($uri, 'google', true);
|
||||||
|
?>
|
|
@ -0,0 +1,761 @@
|
||||||
|
<?php
|
||||||
|
chdir('../..');
|
||||||
|
include ("includes/vars.php");
|
||||||
|
include ("includes/functions.php");
|
||||||
|
include ("international.php");
|
||||||
|
$domain = "en";
|
||||||
|
$userdomain = false;
|
||||||
|
$mobile = (array_key_exists('layout', $_POST) && ($_POST['layout'] == 'phone' || $_POST['layout'] == 'tablet')) ? true : false;
|
||||||
|
// Switch off error reporting prevents us from having to repeatedly check
|
||||||
|
// that the objects we're foreaching on actually exist. Errors get dumped
|
||||||
|
// to stdout and mess up the xml response. We don't wanna see them.
|
||||||
|
// Remember to switch this off if debugging this script.
|
||||||
|
error_reporting(0);
|
||||||
|
|
||||||
|
if (array_key_exists("lang", $_POST)) {
|
||||||
|
$domain = $_POST["lang"];
|
||||||
|
}
|
||||||
|
logger::trace("WIKIPEDIA", "Using Language",$domain);
|
||||||
|
|
||||||
|
if (array_key_exists("wiki", $_POST)) {
|
||||||
|
// An intra-wiki link from a page we're displaying
|
||||||
|
$a = preg_match('#(.*?)/(.*)#', $_POST['wiki'], $matches);
|
||||||
|
send_result(get_wikipedia_page( $matches[2], $matches[1].".wikipedia.org", false ));
|
||||||
|
|
||||||
|
} else if (array_key_exists("uri", $_POST)) {
|
||||||
|
// Full URI to get - eg this will be a link found from musicbrainz
|
||||||
|
$uri = $_POST['uri'];
|
||||||
|
logger::log("WIKIPEDIA", "URI request ".$uri);
|
||||||
|
$a = preg_match('#https*://(.*?)/#', $uri, $matches);
|
||||||
|
$xml_response = get_wikipedia_page(basename($uri), $matches[1], true);
|
||||||
|
if ($userdomain == false) {
|
||||||
|
// Found a page, but not in the user's chosen domain
|
||||||
|
if (array_key_exists('term', $_POST)) {
|
||||||
|
logger::log("WIKIPEDIA", "Page was retreieved but not in user's chosen language. Checking via a search");
|
||||||
|
$upage = wikipedia_find_exact($_POST['term'], $domain);
|
||||||
|
if ($upage != '') {
|
||||||
|
$xml_response = $upage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
send_result($xml_response);
|
||||||
|
|
||||||
|
} else if (array_key_exists("artist", $_POST)) {
|
||||||
|
// Search for an artist
|
||||||
|
$xml_response = getArtistWiki($_POST['artist'], $_POST['disambiguation']);
|
||||||
|
if ($xml_response == null) {
|
||||||
|
send_failure($_POST['artist']);
|
||||||
|
} else {
|
||||||
|
send_result($xml_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (array_key_exists("album", $_POST)) {
|
||||||
|
// Search for an album
|
||||||
|
logger::log("WIKIPEDIA", "Doing album ".$_POST['album']);
|
||||||
|
$xml_response = getAlbumWiki($_POST['album'], $_POST['albumartist']);
|
||||||
|
if ($xml_response == null) {
|
||||||
|
send_failure($_POST['album']);
|
||||||
|
} else {
|
||||||
|
send_result($xml_response);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (array_key_exists("track", $_POST)) {
|
||||||
|
// Search for a track
|
||||||
|
logger::log("WIKIPEDIA", "Doing track ".$_POST['track']);
|
||||||
|
$xml_response = getTrackWiki($_POST['track'], $_POST['trackartist']);
|
||||||
|
if ($xml_response == null) {
|
||||||
|
send_failure($_POST['track']);
|
||||||
|
} else {
|
||||||
|
send_result($xml_response);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
//
|
||||||
|
// Getting stuff from wikipedia, including language munging
|
||||||
|
//
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
function wikipedia_request($url) {
|
||||||
|
logger::trace("WIKIPEDIA", "Getting : ".$url);
|
||||||
|
$d = new url_downloader(array(
|
||||||
|
'url' => $url,
|
||||||
|
'cache' => 'wikipedia',
|
||||||
|
'return_data' => true
|
||||||
|
));
|
||||||
|
if ($d->get_data_to_file()) {
|
||||||
|
return $d->get_data();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function get_wikipedia_page($page, $site, $langsearch) {
|
||||||
|
|
||||||
|
// $page will be eg 'Air_(French_band)'
|
||||||
|
// $site will be eg 'en.wikipedia.org'
|
||||||
|
// $langsearch is true if we want to find a page in the user's language
|
||||||
|
|
||||||
|
// $domain is the language the user wants to use - eg 'fr'
|
||||||
|
global $domain;
|
||||||
|
global $userdomain;
|
||||||
|
global $mobile;
|
||||||
|
|
||||||
|
// $request_domain is the language of the page we've been asked to get
|
||||||
|
$r = preg_match("#(.*?)\.#", $site, $matches);
|
||||||
|
$request_domain = $matches[1];
|
||||||
|
$format_domain = $request_domain;
|
||||||
|
$req = "";
|
||||||
|
|
||||||
|
if ($langsearch) {
|
||||||
|
|
||||||
|
logger::log("WIKIPEDIA", "Request for page ".$page." from ".$site.". Domain is ".$request_domain." and user domain is ".$domain);
|
||||||
|
|
||||||
|
$user_link = ($request_domain == $domain) ? $page : null;
|
||||||
|
$english_link = ($site == "en.wikipedia.org") ? $page : null;
|
||||||
|
|
||||||
|
logger::log("WIKIPEDIA", "User Link is ".$user_link." and english link is ".$english_link);
|
||||||
|
|
||||||
|
if ($domain != $request_domain) {
|
||||||
|
logger::log("WIKIPEDIA", "Asked for page ".$page." from site ".$site." but user wants domain ".$domain);
|
||||||
|
// Find language links for the requested page
|
||||||
|
$langlinks = wikipedia_request("http://".$site."/w/api.php?action=query&prop=langlinks&titles=".$page."&format=xml");
|
||||||
|
if ($langlinks !== null) {
|
||||||
|
$langs = simplexml_load_string($langlinks);
|
||||||
|
if ($langs->query->pages->page->langlinks) {
|
||||||
|
foreach($langs->query->pages->page->langlinks->ll as $ll) {
|
||||||
|
$l = $ll['lang'];
|
||||||
|
$t = dom_import_simplexml($ll)->textContent;
|
||||||
|
logger::log("WIKIPEDIA", "Found language link ".$l." title ".$t);
|
||||||
|
if ($l == $domain) {
|
||||||
|
$user_link = preg_replace('/ /', '_', $t);
|
||||||
|
}
|
||||||
|
if ($l == "en" && $english_link == null) {
|
||||||
|
$english_link = preg_replace('/ /', '_', $t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
logger::log("WIKIPEDIA", "Language Scan Complete for ".$page);
|
||||||
|
logger::log("WIKIPEDIA", "User Link is ".$user_link." and english link is ".$english_link);
|
||||||
|
|
||||||
|
if ($user_link !== null) {
|
||||||
|
$format_domain = $domain;
|
||||||
|
$userdomain = true;
|
||||||
|
$page = $user_link;
|
||||||
|
$site = $domain.'.wikipedia.org';
|
||||||
|
} else if ($english_link !== null) {
|
||||||
|
$page = $english_link;
|
||||||
|
$site = "en.wikipedia.org";
|
||||||
|
$format_domain = "en";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mobile) {
|
||||||
|
$req = 'http://'.$site.'/w/api.php?action=mobileview§ions=all&prop=text&page='.$page.'&format=xml';
|
||||||
|
} else {
|
||||||
|
$req = 'http://'.$site.'/w/api.php?action=parse&prop=text&page='.$page.'&format=xml';
|
||||||
|
}
|
||||||
|
|
||||||
|
$xml = wikipedia_request($req);
|
||||||
|
if ($xml !== null) {
|
||||||
|
$info = "";
|
||||||
|
if ($mobile) {
|
||||||
|
$info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
$reformat = '<?xml version="1.0" encoding="UTF-8"?><api><parse><text xml:space="preserve">';
|
||||||
|
foreach($info->mobileview->sections->section as $section) {
|
||||||
|
$reformat .= htmlspecialchars($section, ENT_QUOTES);
|
||||||
|
}
|
||||||
|
$reformat .= '</text></parse><rompr><domain>'.$format_domain.'</domain><page>'.$page.'</page></rompr></api>';
|
||||||
|
return $reformat;
|
||||||
|
} else {
|
||||||
|
$info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
$html = $info->parse->text;
|
||||||
|
$matches = array();
|
||||||
|
if (preg_match( '/REDIRECT <a href="\/wiki\/(.*?)"/', $html, $matches )) {
|
||||||
|
$xml = wikipedia_request('http://'.$format_domain.'.wikipedia.org/w/api.php?action=parse&prop=text&page='.$matches[1].'&format=xml');
|
||||||
|
$info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
} else if (preg_match( '/<ul class="redirectText"><li><a href=\"(.*?)\/w\/index.php\?title=(.*?)(\&.+)*\"/', $html, $matches)) {
|
||||||
|
logger::log("WIKIPEDIA", "Getting redirect page for ".$matches[2]." from ".$matches[1]);
|
||||||
|
// Wierd. $matches[1] always == "". WTF?
|
||||||
|
$xml = wikipedia_request('http://'.$format_domain.'.wikipedia.org/w/api.php?action=parse&prop=text&page='.$matches[2].'&format=xml');
|
||||||
|
$info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
}
|
||||||
|
return wrap_response($info, $format_domain, $page);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function wrap_response($xml, $domain, $page) {
|
||||||
|
$meta = $xml->addChild('rompr');
|
||||||
|
$meta->addChild('domain', $domain);
|
||||||
|
$meta->addChild('page', $page);
|
||||||
|
return $xml->asXML();
|
||||||
|
}
|
||||||
|
|
||||||
|
function join_responses($bits) {
|
||||||
|
$t = "";
|
||||||
|
$d = "";
|
||||||
|
$p = "";
|
||||||
|
foreach ($bits as $b) {
|
||||||
|
$info = simplexml_load_string($b, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
$t .= htmlspecialchars($info->parse->text, ENT_QUOTES);
|
||||||
|
$d = $info->rompr->domain;
|
||||||
|
$p = $info->rompr->page;
|
||||||
|
}
|
||||||
|
$reformat = '<?xml version="1.0" encoding="UTF-8"?><api><parse><text xml:space="preserve">'.$t.'</text></parse><rompr><domain>'.$d.'</domain><page>'.$p.'</page></rompr></api>';
|
||||||
|
return $reformat;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_result($xml) {
|
||||||
|
header('Content-Type: text/xml');
|
||||||
|
print $xml;
|
||||||
|
}
|
||||||
|
|
||||||
|
function send_failure($term) {
|
||||||
|
$xml = '<?xml version="1.0" encoding="UTF-8"?><api><parse><text xml:space="preserve">';
|
||||||
|
$xml .= htmlspecialchars('<h3 align="center">', ENT_QUOTES).get_int_text("wiki_fail", array($term)).htmlspecialchars('</h3>', ENT_QUOTES);
|
||||||
|
$xml .= '</text></parse>';
|
||||||
|
$xml .= '<rompr><domain>null</domain><page>null</page></rompr></api>';
|
||||||
|
send_result($xml);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
//
|
||||||
|
// Utility Functions
|
||||||
|
//
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
function prepare_string($searchstring) {
|
||||||
|
// Escape naughty characters
|
||||||
|
$searchstring = preg_replace( '/(\(|\)|\^|\$|\\\\|\/)/', '\\\\$1', $searchstring );
|
||||||
|
return $searchstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
function wikipedia_find_exact($searchfor, $domain) {
|
||||||
|
|
||||||
|
$xml = wikipedia_request('http://'.$domain.'.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($searchfor) . '&srprop=score&format=xml');
|
||||||
|
if ($xml == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
$info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
$page = null;
|
||||||
|
|
||||||
|
// This is international, so we only look for an exact match (we can't possibly translate every possibility that's in artist_search, etc)
|
||||||
|
foreach ($info->query->search->p as $id) {
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $searchfor)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
return '';
|
||||||
|
} else {
|
||||||
|
return get_wikipedia_page(preg_replace('/ /', '_', $page), $domain.".wikipedia.org", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function find_dismbiguation_page($page) {
|
||||||
|
|
||||||
|
$searchfor = $page.' (disambiguation)';
|
||||||
|
logger::log("WIKIPEDIA", "Searching Wikipedia for ".$searchfor);
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($searchfor) . '&srprop=score&format=xml');
|
||||||
|
$results = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
|
||||||
|
foreach ($results->query->search->p as $id) {
|
||||||
|
if ($id['title'] == $searchfor) {
|
||||||
|
logger::log("WIKIPEDIA", "returning disambiguation page for ".$page);
|
||||||
|
return get_wikipedia_page(preg_replace('/ /', '_', $id['title']), "en.wikipedia.org", true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function wikipedia_get_list_of_suggestions($term) {
|
||||||
|
|
||||||
|
global $domain;
|
||||||
|
logger::log("WIKIPEDIA", "Getting list of suggestions for ".$term." from ".$domain.".wikipedia.org");
|
||||||
|
$xml = wikipedia_request('http://'.$domain.'.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($term) . '&srprop=score&format=xml');
|
||||||
|
if ($xml != "") {
|
||||||
|
$html = '<?xml version="1.0" encoding="UTF-8"?><api><parse><text xml:space="preserve">';
|
||||||
|
$xml = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
|
||||||
|
if (count($xml->query->search->p) == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$html .= htmlspecialchars('<h3 align="center">', ENT_QUOTES).get_int_text("wiki_suggest", array($term)).htmlspecialchars('</h3>', ENT_QUOTES);
|
||||||
|
$html .= htmlspecialchars('<h3 align="center">', ENT_QUOTES).get_int_text("wiki_suggest2").htmlspecialchars('</h3>', ENT_QUOTES);
|
||||||
|
$html .= htmlspecialchars('<ul>', ENT_QUOTES);
|
||||||
|
foreach ($xml->query->search->p as $id) {
|
||||||
|
$link = preg_replace('/\s/', '_', $id['title']);
|
||||||
|
$html .= htmlspecialchars('<li><a href="#" name="', ENT_QUOTES).$domain.'/'.htmlspecialchars($link, ENT_QUOTES).htmlspecialchars('" class="infoclick clickwikilink">'.$id['title'].'</a></li>', ENT_QUOTES);
|
||||||
|
}
|
||||||
|
$html .= htmlspecialchars("</ul>", ENT_QUOTES);
|
||||||
|
$html .= '</text></parse>';
|
||||||
|
$html .= '<rompr><domain>'.$domain.'</domain><page>'.htmlspecialchars($term, ENT_QUOTES).'</page></rompr></api>';
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
//
|
||||||
|
// Artist Search
|
||||||
|
//
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
|
||||||
|
function getArtistWiki($artist_name, $disambig) {
|
||||||
|
|
||||||
|
global $domain;
|
||||||
|
|
||||||
|
// First, try a search and exact match in the user's chosen language.
|
||||||
|
// This is to catch the case where a page exists on that user's wikipedia
|
||||||
|
// domain and it has no language links to the en site
|
||||||
|
if ($domain != "en") {
|
||||||
|
$h = wikipedia_find_exact($artist_name, $domain);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now try a search on the english site. We can be more wide-ranging in this search
|
||||||
|
// we do this in English because (a) it has the most stuff and (b) I can speak it.
|
||||||
|
// We can find translation links later.
|
||||||
|
$h = wikipedia_artist_search($artist_name, $disambig);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No results returned. If there's an '&' or 'and' or '+' in the name - such as 'Fruitbat & Umbrella'
|
||||||
|
// try querying for 'Fruitbat' and 'Umbrella' separately and if there are any results, display them all
|
||||||
|
$artist = preg_replace('/ and /', ' & ', $artist_name);
|
||||||
|
$artist = preg_replace('/\+/', '&', $artist);
|
||||||
|
$jhtml = array();
|
||||||
|
if (preg_match('/ & /', $artist) > 0) {
|
||||||
|
$alist = explode(' & ', $artist);
|
||||||
|
foreach ($alist as $artistname) {
|
||||||
|
$j = wikipedia_artist_search($artistname, "");
|
||||||
|
if ($j != '') {
|
||||||
|
$jhtml[] = $j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} elseif (preg_match('/,/', $artist) > 0) {
|
||||||
|
$alist = explode(',', $artist);
|
||||||
|
$jhtml = array();
|
||||||
|
foreach ($alist as $artistname) {
|
||||||
|
$j = wikipedia_artist_search($artistname, "");
|
||||||
|
if ($j != '') {
|
||||||
|
$jhtml[] = $j;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($jhtml) > 0) {
|
||||||
|
return join_responses($jhtml);
|
||||||
|
}
|
||||||
|
|
||||||
|
$h = find_dismbiguation_page($artist_name);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wikipedia_get_list_of_suggestions($artist_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wikipedia_artist_search($artist, $disambig) {
|
||||||
|
|
||||||
|
$page = null;
|
||||||
|
if ($disambig != "") {
|
||||||
|
$searchfor = $artist.' ('.$disambig.')';
|
||||||
|
logger::log("WIKIPEDIA ARTIST", "Searching Wikipedia for ".$searchfor);
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($searchfor) . '&srprop=score&format=xml');
|
||||||
|
$artistinfo = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
|
||||||
|
// First look for exact match
|
||||||
|
foreach ($artistinfo->query->search->p as $id) {
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $searchfor)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
$poss = array();
|
||||||
|
foreach ($artistinfo->query->search->p as $id) {
|
||||||
|
if (preg_match('/\(.*?band\)|\(.*?musician\)|\(.*?singer\)/i', $id['title'])) {
|
||||||
|
$poss[] = $id['title'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (count($poss) == 1) {
|
||||||
|
$page = array_shift($poss);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
logger::log("WIKIPEDIA ARTIST", "Searching Wikipedia for ".$artist);
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($artist) . '&srprop=score&format=xml');
|
||||||
|
$artist2info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
foreach ($artist2info->query->search->p as $id) {
|
||||||
|
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$poss = array();
|
||||||
|
if (preg_match('/\(.*?band\)|\(.*?musician\)|\(.*?singer\)/i', $id['title'])) {
|
||||||
|
$poss[] = $id['title'];
|
||||||
|
}
|
||||||
|
if (count($poss) == 1) {
|
||||||
|
$page = array_shift($poss);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', "The " . $artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*The ' . $searchstring . '\s*$/i', $artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/&/', $id['title'])) {
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = preg_replace( '/&/', 'and', $searchstring );
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (preg_match('/and/', $id['title'])) {
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = preg_replace( '/and/', '&', $searchstring );
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Any '.'? Let's remove them (both ways round)
|
||||||
|
if (preg_match('/\./', $id['title'])) {
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = preg_replace( '/\./', '', $searchstring );
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (preg_match('/\./', $artist)) {
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$t = preg_replace( '/\./', '', $artist );
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $t)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Words for numbers, numbers for words.
|
||||||
|
$numbers = array('/1/','/2/','/3/','/4/','/5/','/6/','/7/','/8/','/9/');
|
||||||
|
$words = array("one", "two", "three", "four", "five", "six", "seven", "eight", "nine");
|
||||||
|
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = preg_replace( $numbers, $words, $searchstring);
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $artist) ||
|
||||||
|
preg_match('/^\s*' . $searchstring . '\s*$/i', "The ".$artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$numbers = array('1','2','3','4','5','6','7','8','9');
|
||||||
|
$words = array("/one/", "/two/", "/three/", "/four/", "/five/", "/six/", "/seven/", "/eight/", "/nine/");
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = preg_replace( $words, $numbers, $searchstring);
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $artist) ||
|
||||||
|
preg_match('/^\s*' . $searchstring . '\s*$/i', "The ".$artist)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null && preg_match('/.*\(.*\).*/', $artist)) {
|
||||||
|
$sf = trim(preg_replace('/\(.*?\)/','',$artist));;
|
||||||
|
logger::log("WIKIPEDIA ARTIST", "Searching Wikipedia for ".$sf);
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($sf) . '&srprop=score&format=xml');
|
||||||
|
$artist3info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
foreach ($artist3info->query->search->p as $id) {
|
||||||
|
$searchstring = $id['title'];
|
||||||
|
$searchstring = prepare_string($searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $sf)) {
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
logger::log("WIKIPEDIA ARTIST", "Artist search found page ".$page);
|
||||||
|
return get_wikipedia_page(preg_replace('/ /', '_', $page), "en.wikipedia.org", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
//
|
||||||
|
// Album Search
|
||||||
|
//
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
|
||||||
|
function getAlbumWiki($album_name, $artist_name) {
|
||||||
|
|
||||||
|
global $domain;
|
||||||
|
// First, try a search and exact match in the user's chosen language.
|
||||||
|
// This is to catch the case where a page exists on that user's wikipedia
|
||||||
|
// domain and it has no language links to the en site
|
||||||
|
if ($domain != "en") {
|
||||||
|
$h = wikipedia_find_exact($album_name, $domain);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now try a search on the english site. We can be more wide-ranging in this search
|
||||||
|
// we do this in English because (a) it has the most stuff and (b) I can speak it.
|
||||||
|
// We can find translation links later.
|
||||||
|
$h = wikipedia_album_search($album_name, $artist_name);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
|
||||||
|
$h = find_dismbiguation_page($album_name);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wikipedia_get_list_of_suggestions($album_name);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function wikipedia_album_search($album, $artist) {
|
||||||
|
|
||||||
|
$album = munge_album_name($album);
|
||||||
|
logger::log("WIKIPEDIA ALBUM", "Searching Wikipedia for ".$album." (album)");
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($album." (album)") . '&srprop=score&format=xml');
|
||||||
|
$albuminfo = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
|
||||||
|
$page = null;
|
||||||
|
|
||||||
|
foreach ($albuminfo->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($album).'\s+\('.prepare_string($artist).' album\)';
|
||||||
|
// logger::log("WIKIDEBUG", "1. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
foreach ($albuminfo->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($album).'\s+\(album\)';
|
||||||
|
// logger::log("WIKIDEBUG", "2. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
foreach ($albuminfo->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($album).'\s+\(\d+ album\)';
|
||||||
|
// logger::log("WIKIDEBUG", "2. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
foreach ($albuminfo->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($album);
|
||||||
|
// logger::log("WIKIDEBUG", "3. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
logger::log("WIKIPEDIA ALBUM", "Searching Wikipedia for ".$album);
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($album) . '&srprop=score&format=xml');
|
||||||
|
$album2info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
foreach ($album2info->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($album);
|
||||||
|
// logger::log("WIKIDEBUG", "3. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
logger::log("WIKIPEDIA ALBUM", "Album search found page ".$page);
|
||||||
|
return get_wikipedia_page(preg_replace('/ /', '_', $page), "en.wikipedia.org", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// ==========================================================================
|
||||||
|
//
|
||||||
|
// Track Search
|
||||||
|
//
|
||||||
|
// ==========================================================================
|
||||||
|
|
||||||
|
|
||||||
|
function getTrackWiki($track_name, $artist_name) {
|
||||||
|
|
||||||
|
global $domain;
|
||||||
|
// First, try a search and exact match in the user's chosen language.
|
||||||
|
// This is to catch the case where a page exists on that user's wikipedia
|
||||||
|
// domain and it has no language links to the en site
|
||||||
|
if ($domain != "en") {
|
||||||
|
$h = wikipedia_find_exact($track_name, $domain);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now try a search on the english site. We can be more wide-ranging in this search
|
||||||
|
// we do this in English because (a) it has the most stuff and (b) I can speak it.
|
||||||
|
// We can find translation links later.
|
||||||
|
$h = wikipedia_track_search($track_name, $artist_name);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
|
||||||
|
$h = find_dismbiguation_page($track_name);
|
||||||
|
if ($h != '') {
|
||||||
|
return $h;
|
||||||
|
}
|
||||||
|
|
||||||
|
return wikipedia_get_list_of_suggestions($track_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
function wikipedia_track_search($track, $trackartist) {
|
||||||
|
|
||||||
|
logger::log("WIKIPEDIA TRACK", "Searching Wikipedia for ".$track." (song) by ".$trackartist);
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($track." (song)") . '&srprop=score&format=xml');
|
||||||
|
$albuminfo = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
|
||||||
|
// Comments assume the following:
|
||||||
|
// track is 'A Track'
|
||||||
|
// artist is 'An Artist'
|
||||||
|
|
||||||
|
$page = null;
|
||||||
|
|
||||||
|
// Look for 'A Track (An Artist song)'
|
||||||
|
foreach ($albuminfo->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($track).'\s+\('.prepare_string($trackartist).' song\)';
|
||||||
|
// logger::log("WIKIDEBUG", "1. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for 'A Track (song)'
|
||||||
|
if ($page == null) {
|
||||||
|
foreach ($albuminfo->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($track).'\s+\(song\)';
|
||||||
|
// logger::log("WIKIDEBUG", "2. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look for 'A Track'
|
||||||
|
if ($page == null) {
|
||||||
|
foreach ($albuminfo->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($track);
|
||||||
|
// logger::log("WIKIDEBUG", "3. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
logger::log("WIKIPEDIA TRACK", "Searching Wikipedia for ".$track);
|
||||||
|
$xml = wikipedia_request('http://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=' . rawurlencode($track) . '&srprop=score&format=xml');
|
||||||
|
$album2info = simplexml_load_string($xml, 'SimpleXMLElement', LIBXML_NOCDATA);
|
||||||
|
foreach ($album2info->query->search->p as $id) {
|
||||||
|
$searchstring = prepare_string($track);
|
||||||
|
// logger::log("WIKIDEBUG", "3. Checking page ".$id['title']." against ".$searchstring);
|
||||||
|
if (preg_match('/^\s*' . $searchstring . '\s*$/i', $id['title'])) {
|
||||||
|
logger::log("WIKIPEDIA", "Found Page : ".$id['title']);
|
||||||
|
$page = $id['title'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($page == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger::log("WIKIPEDIA TRACK", "Track search found page ".$page);
|
||||||
|
return get_wikipedia_page(preg_replace('/ /', '_', $page), "en.wikipedia.org", true);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,157 @@
|
||||||
|
var discogs = function() {
|
||||||
|
|
||||||
|
var baseURL = 'https://api.discogs.com/';
|
||||||
|
var queue = new Array();
|
||||||
|
var throttle = null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
request: function(reqid, data, success, fail) {
|
||||||
|
|
||||||
|
queue.push( {flag: false, reqid: reqid, data: data, success: success, fail: fail } );
|
||||||
|
debug.debug("DISCOGS","New request",data.url,"throttle is",throttle,"length is",queue.length);
|
||||||
|
if (throttle == null && queue.length == 1) {
|
||||||
|
discogs.getrequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getrequest: function() {
|
||||||
|
|
||||||
|
var req = queue[0];
|
||||||
|
clearTimeout(throttle);
|
||||||
|
|
||||||
|
if (req !== undefined) {
|
||||||
|
if (req.flag) {
|
||||||
|
debug.error("DISCOGS","Request just pulled from queue is already being handled",req.data.url);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queue[0].flag = true;
|
||||||
|
debug.debug("DISCOGS","Taking next request from queue",req.data);
|
||||||
|
var getit = $.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: "browser/backends/getdidata.php",
|
||||||
|
data: req.data,
|
||||||
|
dataType: "json"
|
||||||
|
})
|
||||||
|
.done(function(data) {
|
||||||
|
var c = getit.getResponseHeader('Pragma');
|
||||||
|
debug.debug("DISCOGS", "Request Success",c,data);
|
||||||
|
if (c == "From Cache") {
|
||||||
|
throttle = setTimeout(discogs.getrequest, 100);
|
||||||
|
} else {
|
||||||
|
throttle = setTimeout(discogs.getrequest, 1500);
|
||||||
|
}
|
||||||
|
req = queue.shift();
|
||||||
|
if (data === null) {
|
||||||
|
data = {error: language.gettext("discogs_error")}
|
||||||
|
} else if (!data.error) {
|
||||||
|
// info_discogs.js was written to accept jsonp data passed back from $.jsonp
|
||||||
|
// However as Discogs now seem to be refusing to respond to those requests
|
||||||
|
// we're using a php script to get it instead. So here we bodge the response
|
||||||
|
// into the form that info_discogs.js is expecting.
|
||||||
|
data = {data: data};
|
||||||
|
}
|
||||||
|
if (req.reqid != '') {
|
||||||
|
data.id = req.reqid;
|
||||||
|
}
|
||||||
|
if (data.error) {
|
||||||
|
req.fail(data);
|
||||||
|
} else {
|
||||||
|
req.success(data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function(xhr,status,err) {
|
||||||
|
throttle = setTimeout(discogs.getrequest, 1500);
|
||||||
|
req = queue.shift();
|
||||||
|
debug.warn("DISCOGS","Request failed",req,xhr);
|
||||||
|
data = {error: language.gettext("discogs_error") + ' ('+xhr.status+' '+err+')'};
|
||||||
|
if (req.reqid != '') {
|
||||||
|
data.id = req.reqid;
|
||||||
|
}
|
||||||
|
req.fail(data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throttle = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
artist: {
|
||||||
|
|
||||||
|
search: function(name, success, fail) {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'database/search',
|
||||||
|
type: 'artist',
|
||||||
|
q: name
|
||||||
|
}
|
||||||
|
discogs.request('', data, success, fail);
|
||||||
|
},
|
||||||
|
|
||||||
|
getInfo: function(reqid, id, success, fail) {
|
||||||
|
var data = {url: baseURL+'artists/'+id};
|
||||||
|
discogs.request(reqid, data, success, fail);
|
||||||
|
},
|
||||||
|
|
||||||
|
getReleases: function(name, page, reqid, success, fail) {
|
||||||
|
debug.log("DISCOGS","Get Artist Releases",name,page);
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'artists/'+name+'/releases',
|
||||||
|
per_page: 25,
|
||||||
|
page: page
|
||||||
|
};
|
||||||
|
discogs.request(reqid, data, success, fail);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
album: {
|
||||||
|
|
||||||
|
getInfo: function(reqid, id, success, fail) {
|
||||||
|
// NOTE id must be either releases/id or masters/id
|
||||||
|
var data = {url: baseURL+id};
|
||||||
|
discogs.request(reqid, data, success, fail);
|
||||||
|
},
|
||||||
|
|
||||||
|
search: function(artist, album, success, fail) {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'database/search',
|
||||||
|
type: 'release',
|
||||||
|
artist: artist,
|
||||||
|
release_title: album
|
||||||
|
};
|
||||||
|
discogs.request('', data, success, fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
track: {
|
||||||
|
|
||||||
|
getInfo: function(reqid, id, success, fail) {
|
||||||
|
// NOTE id must be either releases/id or masters/id
|
||||||
|
var data = {url: baseURL+id};
|
||||||
|
discogs.request(reqid, data, success, fail);
|
||||||
|
},
|
||||||
|
|
||||||
|
search: function(artist, track, success, fail) {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'database/search',
|
||||||
|
type: 'release',
|
||||||
|
artist: artist,
|
||||||
|
track: track
|
||||||
|
};
|
||||||
|
discogs.request('', data, success, fail);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
label: {
|
||||||
|
|
||||||
|
getInfo: function(reqid, id, success, fail) {
|
||||||
|
// NOTE id must be either releases/id or masters/id
|
||||||
|
var data = {url: baseURL+'labels/'+id};
|
||||||
|
discogs.request(reqid, data, success, fail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
|
@ -0,0 +1,199 @@
|
||||||
|
var musicbrainz = function() {
|
||||||
|
|
||||||
|
var baseURL = 'http://musicbrainz.org/ws/2/';
|
||||||
|
var coverURL = 'http://coverartarchive.org/release/';
|
||||||
|
var queue = new Array();
|
||||||
|
var throttle = null;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
request: function(reqid, data, success, fail) {
|
||||||
|
|
||||||
|
queue.push( {flag: false, reqid: reqid, data: data, success: success, fail: fail } );
|
||||||
|
debug.debug("MUSICBRAINZ","New request",data.url);
|
||||||
|
if (throttle == null && queue.length == 1) {
|
||||||
|
musicbrainz.getrequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getrequest: function() {
|
||||||
|
|
||||||
|
var req = queue[0];
|
||||||
|
clearTimeout(throttle);
|
||||||
|
|
||||||
|
if (req) {
|
||||||
|
if (req.flag) {
|
||||||
|
debug.error("MUSICBRAINZ","Request just pulled from queue is already being handled");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queue[0].flag = true;
|
||||||
|
debug.debug("MUSICBRAINZ","Taking next request from queue",req.data);
|
||||||
|
var getit = $.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
url: "browser/backends/getmbdata.php",
|
||||||
|
data: req.data,
|
||||||
|
dataType: "json",
|
||||||
|
})
|
||||||
|
.done(function(data) {
|
||||||
|
var c = getit.getResponseHeader('Pragma');
|
||||||
|
debug.debug("MUSICBRAINZ","Request success",c,data);
|
||||||
|
if (c == "From Cache") {
|
||||||
|
throttle = setTimeout(musicbrainz.getrequest, 100);
|
||||||
|
} else {
|
||||||
|
throttle = setTimeout(musicbrainz.getrequest, 1500);
|
||||||
|
}
|
||||||
|
req = queue.shift();
|
||||||
|
if (data === null) {
|
||||||
|
data = {error: language.gettext("musicbrainz_error")};
|
||||||
|
}
|
||||||
|
if (req.reqid != '') {
|
||||||
|
data.id = req.reqid;
|
||||||
|
}
|
||||||
|
if (data.error) {
|
||||||
|
req.fail(data);
|
||||||
|
} else {
|
||||||
|
req.success(data);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.fail(function(xhr,status,err) {
|
||||||
|
throttle = setTimeout(musicbrainz.getrequest, 1500);
|
||||||
|
req = queue.shift();
|
||||||
|
debug.warn("MUSICBRAINZ","Request failed",req,xhr);
|
||||||
|
data = {error: language.gettext("musicbrainz_noinfo") + ' ('+xhr.status+' '+err+')'};
|
||||||
|
if (req.reqid != '') {
|
||||||
|
data.id = req.reqid;
|
||||||
|
}
|
||||||
|
req.fail(data);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throttle = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
artist: {
|
||||||
|
|
||||||
|
getInfo: function(mbid, success, fail) {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'artist/'+mbid,
|
||||||
|
inc: 'aliases+tags+ratings+release-groups+artist-rels+label-rels+url-rels+release-group-rels+annotation',
|
||||||
|
fmt: 'json'
|
||||||
|
};
|
||||||
|
musicbrainz.request('', data, success, fail);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getReleases: function(mbid, reqid, success, fail) {
|
||||||
|
var result = { id: reqid };
|
||||||
|
result['release-groups'] = new Array();
|
||||||
|
(function getAllReleaseGroups() {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'release-group',
|
||||||
|
artist: mbid,
|
||||||
|
limit: 100,
|
||||||
|
fmt: 'json',
|
||||||
|
inc: 'artist-credits+tags+ratings+url-rels+annotation',
|
||||||
|
offset: result['release-groups'].length
|
||||||
|
};
|
||||||
|
musicbrainz.request(reqid, data, function(data) {
|
||||||
|
debug.debug("MUSICBRAINZ","Release group data:",data);
|
||||||
|
if (data.error) {
|
||||||
|
if (result['release-groups'].length > 0) {
|
||||||
|
success(result);
|
||||||
|
} else {
|
||||||
|
fail(data);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (var i in data['release-groups']) {
|
||||||
|
result['release-groups'].push(data['release-groups'][i]);
|
||||||
|
}
|
||||||
|
if (result['release-groups'].length == data['release-group-count']) {
|
||||||
|
success(result);
|
||||||
|
} else {
|
||||||
|
getAllReleaseGroups();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}, fail);
|
||||||
|
})();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
album: {
|
||||||
|
|
||||||
|
getInfo: function(mbid, success, fail) {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'release/'+mbid,
|
||||||
|
inc: 'annotation+tags+ratings+artists+labels+recordings+release-groups+artist-credits+url-rels+release-group-rels+recording-rels+artist-rels',
|
||||||
|
fmt: 'json'
|
||||||
|
};
|
||||||
|
musicbrainz.request('', data, success, fail);
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
getCoverArt: function(id, success, fail) {
|
||||||
|
var data = {url: coverURL + id + "/" };
|
||||||
|
musicbrainz.request('', data, success, fail);
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
releasegroup: {
|
||||||
|
|
||||||
|
getInfo: function(mbid, reqid, success, fail) {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'release-group/'+mbid,
|
||||||
|
inc: 'artists+releases+artist-rels+label-rels+url-rels',
|
||||||
|
fmt: 'json'
|
||||||
|
};
|
||||||
|
musicbrainz.request(reqid, data, success, fail);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
track: {
|
||||||
|
|
||||||
|
getInfo: function(mbid, success, fail) {
|
||||||
|
var data = {
|
||||||
|
url: baseURL+'recording/'+mbid,
|
||||||
|
inc: 'annotation+tags+ratings+releases+url-rels+work-rels+release-rels+release-group-rels+artist-rels+label-rels+recording-rels',
|
||||||
|
fmt: 'json'
|
||||||
|
};
|
||||||
|
var result = {};
|
||||||
|
// For a track, although there might be some good stuff in the recording data, what we really want
|
||||||
|
// is the associated work, if there is one, because that's where the wiki and discogs links will probably be.
|
||||||
|
musicbrainz.request('', data,
|
||||||
|
function(data) {
|
||||||
|
result.recording = data;
|
||||||
|
debug.debug("MUSICBRAINZ","Scanning recording for work data");
|
||||||
|
for (var i in data.relations) {
|
||||||
|
if (data.relations[i].work) {
|
||||||
|
debug.debug("MUSICBRAINZ","Found work data",data.relations[i].work.id);
|
||||||
|
var newdata = {
|
||||||
|
url: baseURL+'work/'+data.relations[i].work.id,
|
||||||
|
inc: 'annotation+tags+ratings+url-rels+artist-rels',
|
||||||
|
fmt: 'json'
|
||||||
|
};
|
||||||
|
musicbrainz.request('', newdata,
|
||||||
|
function(workdata) {
|
||||||
|
debug.debug("MUSICBRAINZ","Got work data",workdata);
|
||||||
|
result.work = workdata;
|
||||||
|
success(result);
|
||||||
|
},
|
||||||
|
function(workdata) {
|
||||||
|
debug.debug("MUSICBRAINZ","Got NO work data",workdata);
|
||||||
|
success(result);
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
success(result);
|
||||||
|
},
|
||||||
|
fail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
|
@ -0,0 +1,40 @@
|
||||||
|
var soundcloud = function() {
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
|
||||||
|
return {
|
||||||
|
getTrackInfo: function(mopidyURI, callback) {
|
||||||
|
// "soundcloud:song/King Tubby meets Soul Rebel Uptown.92868852"
|
||||||
|
debug.log("SOUNDCLOUD","Trying to get track info from",mopidyURI);
|
||||||
|
var a = mopidyURI.match(/(\d+)$/);
|
||||||
|
var tracknum = a[1];
|
||||||
|
debug.log("SOUNDCLOUD","Getting soundcloud info for track",tracknum);
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
url: 'browser/backends/getscdata.php',
|
||||||
|
data: {url: 'tracks/'+tracknum+'.json'}
|
||||||
|
})
|
||||||
|
.done(callback)
|
||||||
|
.fail(function(xhr,status,err) {
|
||||||
|
debug.warn("SOUNDCLOUD","SoundCloud Error",xhr);
|
||||||
|
callback(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserInfo: function(userid, callback) {
|
||||||
|
debug.log("SOUNDCLOUD","Getting soundcloud info for user",userid);
|
||||||
|
$.ajax({
|
||||||
|
method: 'POST',
|
||||||
|
dataType: 'json',
|
||||||
|
url: 'browser/backends/getscdata.php',
|
||||||
|
data: {url: 'users/'+userid+'.json'}
|
||||||
|
})
|
||||||
|
.done(callback)
|
||||||
|
.fail(function(xhr,status,err) {
|
||||||
|
debug.warn("SOUNDCLOUD","SoundCloud Error",xhr);
|
||||||
|
callback(xhr.responseJSON);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
|
@ -0,0 +1,216 @@
|
||||||
|
var spotify = function() {
|
||||||
|
|
||||||
|
var baseURL = 'https://api.spotify.com';
|
||||||
|
var queue = new Array();
|
||||||
|
var throttle = null;
|
||||||
|
var collectedobj = null;
|
||||||
|
var getit;
|
||||||
|
var rate = 500;
|
||||||
|
var backofftimer;
|
||||||
|
|
||||||
|
function objFirst(obj) {
|
||||||
|
for (var a in obj) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
request: function(reqid, url, success, fail, prio, cache) {
|
||||||
|
|
||||||
|
if (prio && queue.length > 1) {
|
||||||
|
queue.splice(1, 0, {flag: false, reqid: reqid, url: url, success: success, fail: fail, cache: cache } );
|
||||||
|
} else {
|
||||||
|
queue.push( {flag: false, reqid: reqid, url: url, success: success, fail: fail, cache: cache } );
|
||||||
|
}
|
||||||
|
debug.debug("SPOTIFY","New request",url,throttle,queue.length,cache);
|
||||||
|
if (throttle == null && queue.length == 1) {
|
||||||
|
spotify.getrequest();
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
requestSuccess: function(data) {
|
||||||
|
var c = getit.getResponseHeader('Pragma');
|
||||||
|
debug.debug("SPOTIFY","Request success",c,data);
|
||||||
|
req = queue.shift();
|
||||||
|
if (data === null) {
|
||||||
|
debug.warn("SPOTIFY","No data in response",req);
|
||||||
|
data = {error: language.gettext("spotify_error")};
|
||||||
|
}
|
||||||
|
if (req.reqid != '') {
|
||||||
|
data.reqid = req.reqid;
|
||||||
|
}
|
||||||
|
var root = objFirst(data);
|
||||||
|
if (data[root].next) {
|
||||||
|
debug.log("SPOTIFY","Got a response with a next page!");
|
||||||
|
if (data[root].previous == null) {
|
||||||
|
collectedobj = data;
|
||||||
|
} else {
|
||||||
|
collectedobj[root].items = collectedobj[root].items.concat(data[root].items);
|
||||||
|
}
|
||||||
|
queue.unshift({flag: false, reqid: '', url: data[root].next, success: req.success, fail: req.fail});
|
||||||
|
} else if (data[root].previous) {
|
||||||
|
collectedobj[root].items = collectedobj[root].items.concat(data[root].items);
|
||||||
|
debug.log("SPOTIFY","Returning concatenated multi-page result");
|
||||||
|
req.success(collectedobj);
|
||||||
|
} else if (data.next) {
|
||||||
|
debug.log("SPOTIFY","Got a response with a next page!");
|
||||||
|
if (data.previous == null) {
|
||||||
|
collectedobj = data;
|
||||||
|
} else {
|
||||||
|
collectedobj.items = collectedobj.items.concat(data.items);
|
||||||
|
}
|
||||||
|
queue.unshift({flag: false, reqid: '', url: data.next, success: req.success, fail: req.fail});
|
||||||
|
} else if (data.previous) {
|
||||||
|
collectedobj.items = collectedobj.items.concat(data.items);
|
||||||
|
debug.log("SPOTIFY","Returning concatenated multi-page result");
|
||||||
|
req.success(collectedobj);
|
||||||
|
} else {
|
||||||
|
req.success(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (c == "From Cache") {
|
||||||
|
throttle = setTimeout(spotify.getrequest, 100);
|
||||||
|
} else {
|
||||||
|
throttle = setTimeout(spotify.getrequest, rate);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
requestFail: function(xhr,status,err) {
|
||||||
|
if (xhr.responseJSON.error == 429) {
|
||||||
|
debug.warn("SPOTIFY","Too Many Requests. Slowing Request Rate");
|
||||||
|
rate += rate;
|
||||||
|
clearTimeout(backofftimer);
|
||||||
|
backofftimer = setTimeout(spotify.speedBackUp, 90000);
|
||||||
|
}
|
||||||
|
throttle = setTimeout(spotify.getrequest, rate);
|
||||||
|
req = queue.shift();
|
||||||
|
debug.warn("SPOTIFY","Request failed",req,xhr,status,err);
|
||||||
|
data = {error: language.gettext("spotify_noinfo") + ' ('+xhr.responseJSON.error+' '+xhr.responseJSON.message+')'}
|
||||||
|
if (req.reqid != '') {
|
||||||
|
data.reqid = req.reqid;
|
||||||
|
}
|
||||||
|
req.fail(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
speedBackUp: function() {
|
||||||
|
rate = 500;
|
||||||
|
},
|
||||||
|
|
||||||
|
getrequest: function() {
|
||||||
|
|
||||||
|
var req = queue[0];
|
||||||
|
clearTimeout(throttle);
|
||||||
|
|
||||||
|
if (req) {
|
||||||
|
if (req.flag) {
|
||||||
|
debug.warn("SPOTIFY","Request just pulled from queue is already being handled",req,throttle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
queue[0].flag = true;
|
||||||
|
debug.debug("SPOTIFY","Taking next request from queue",req.url);
|
||||||
|
getit = $.ajax({
|
||||||
|
type: 'POST',
|
||||||
|
url: "browser/backends/getspdata.php",
|
||||||
|
dataType: "json",
|
||||||
|
data: {
|
||||||
|
url: req.url,
|
||||||
|
cache: req.cache
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.done(spotify.requestSuccess)
|
||||||
|
.fail(spotify.requestFail);
|
||||||
|
} else {
|
||||||
|
throttle = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
track: {
|
||||||
|
|
||||||
|
getInfo: function(id, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/tracks/' + id;
|
||||||
|
spotify.request('', url, success, fail, prio, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
checkLinking: function(id, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/tracks/' + id + '?market='+prefs.lastfm_country_code;
|
||||||
|
spotify.request('', url, success, fail, prio, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
tracks: {
|
||||||
|
|
||||||
|
checkLinking: function(ids, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/tracks?ids='+ids.join(',')+'&market='+prefs.lastfm_country_code;
|
||||||
|
spotify.request('', url, success, fail, prio, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
album: {
|
||||||
|
|
||||||
|
getInfo: function(id, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/albums/' + id;
|
||||||
|
spotify.request(id, url, success, fail, prio, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
getMultiInfo: function(ids, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/albums/?ids=' + ids.join();
|
||||||
|
spotify.request('', url, success, fail, prio, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
artist: {
|
||||||
|
|
||||||
|
getInfo: function(id, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/artists/' + id;
|
||||||
|
spotify.request('', url, success, fail, prio, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
getRelatedArtists: function(id, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/artists/' + id + '/related-artists'
|
||||||
|
spotify.request('', url, success, fail, prio, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
getTopTracks: function(id, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/artists/' + id + '/top-tracks'
|
||||||
|
spotify.request('', url, success, fail, prio, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
getAlbums: function(id, types, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/artists/'+id+'/albums?album_type='+types+'&market='+prefs.lastfm_country_code+'&limit=50';
|
||||||
|
spotify.request(id, url, success, fail, prio, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
search: function(name, success, fail, prio) {
|
||||||
|
var url = baseURL + '/v1/search?q='+name.replace(/&|%|@|:|\+|'|\\|\*|"|\?|\//g,'').replace(/\s+/g,'+')+'&type=artist';
|
||||||
|
spotify.request('', url, success, fail, prio, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
recommendations: {
|
||||||
|
|
||||||
|
getGenreSeeds: function(success, fail) {
|
||||||
|
var url = baseURL + '/v1/recommendations/available-genre-seeds';
|
||||||
|
spotify.request('', url, success, fail, true, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
getRecommendations: function(param, success, fail) {
|
||||||
|
var p = new Array();
|
||||||
|
for (var i in param) {
|
||||||
|
p.push(i+'='+encodeURIComponent(param[i]));
|
||||||
|
}
|
||||||
|
var paramstring = p.join('&');
|
||||||
|
var url = baseURL + '/v1/recommendations?'+paramstring;
|
||||||
|
spotify.request('', url, success, fail, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}();
|
|
@ -0,0 +1,77 @@
|
||||||
|
var wikipedia = function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
getLanguage: function() {
|
||||||
|
if (lastfm.getLanguage()) {
|
||||||
|
return lastfm.getLanguage();
|
||||||
|
} else {
|
||||||
|
return "en";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
search: function(terms, successCallback, failCallback) {
|
||||||
|
terms.lang = wikipedia.getLanguage();
|
||||||
|
terms.layout = skin;
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: "browser/backends/info_wikipedia.php",
|
||||||
|
data: terms,
|
||||||
|
dataType: "xml"
|
||||||
|
})
|
||||||
|
.done(successCallback)
|
||||||
|
.fail(failCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
getFullUri: function(terms, successCallback, failCallback) {
|
||||||
|
terms.lang = wikipedia.getLanguage();
|
||||||
|
terms.layout = skin;
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: "browser/backends/info_wikipedia.php",
|
||||||
|
data: terms,
|
||||||
|
dataType: "xml"
|
||||||
|
})
|
||||||
|
.done(successCallback)
|
||||||
|
.fail(failCallback);
|
||||||
|
},
|
||||||
|
|
||||||
|
wikiMediaPopup: function(element, event) {
|
||||||
|
var thing = element.attr("name");
|
||||||
|
debug.log("WIKIPEDIA","Clicked element has name",thing);
|
||||||
|
var a = thing.match(/(.*?)\/(.*)/);
|
||||||
|
if (a && a[1] && a[2]) {
|
||||||
|
var fname = a[2];
|
||||||
|
if (fname.match(/jpg$/i) || fname.match(/gif$/i) || fname.match(/png$/i) || fname.match(/jpeg$/i) || fname.match(/svg$/i) || fname.match(/bmp$/i)) {
|
||||||
|
imagePopup.create(element, event);
|
||||||
|
var url = "http://"+a[1]+"/w/api.php?action=query&iiprop=url|size&prop=imageinfo&titles=" + a[2] + "&format=json&callback=?";
|
||||||
|
$.getJSON(url, function(data) {
|
||||||
|
$.each(data.query.pages, function(index, value) {
|
||||||
|
imagePopup.create(element, event, 'getRemoteImage.php?url='+value.imageinfo[0].url);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
}).fail( function() { imagePopup.close() });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
getWiki: function(link, successCallback, failCallback) {
|
||||||
|
$("#infopane").css({cursor:'wait'});
|
||||||
|
$("#infopane a").css({cursor:'wait'});
|
||||||
|
$.ajax({
|
||||||
|
type: "POST",
|
||||||
|
url: "browser/backends/info_wikipedia.php",
|
||||||
|
data: {wiki: link, layout: skin},
|
||||||
|
dataType: "xml"
|
||||||
|
})
|
||||||
|
.done(successCallback)
|
||||||
|
.fail(failCallback)
|
||||||
|
.always(function() {
|
||||||
|
$("#infopane").css({cursor:'auto'});
|
||||||
|
$("#infopane a").css({cursor:'auto'});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
|
@ -0,0 +1,573 @@
|
||||||
|
var browser = function() {
|
||||||
|
|
||||||
|
var history = [{
|
||||||
|
source: "",
|
||||||
|
artist: {
|
||||||
|
name: "",
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
name: "",
|
||||||
|
artist: "",
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
name: "",
|
||||||
|
}
|
||||||
|
}];
|
||||||
|
var displaypointer = 0;
|
||||||
|
var panelclosed = {artist: false, album: false, track: false};
|
||||||
|
var waitingon = {artist: false, album: false, track: false, index: -1, source: null};
|
||||||
|
var extraPlugins = [];
|
||||||
|
var maxhistorylength = 20;
|
||||||
|
var sources = nowplaying.getAllPlugins();
|
||||||
|
var doneone = false;
|
||||||
|
|
||||||
|
function displayTheData(ptr, showartist, showalbum, showtrack) {
|
||||||
|
var a = waitingon.artist;
|
||||||
|
var b = waitingon.album;
|
||||||
|
var c = waitingon.track;
|
||||||
|
waitingon = { artist: a || showartist,
|
||||||
|
album: b || showalbum,
|
||||||
|
track: c || showtrack,
|
||||||
|
index: history[ptr].mastercollection.nowplayingindex,
|
||||||
|
source: history[ptr].source
|
||||||
|
};
|
||||||
|
debug.log("BROWSER", "Waiting on source",waitingon.source,"for index", waitingon.index);
|
||||||
|
if (waitingon.source != prefs.infosource) {
|
||||||
|
// Need to do this here rather than in switchsource otherwise it prevents
|
||||||
|
// the browser from accepting the update
|
||||||
|
$("#button_source"+prefs.infosource).removeClass("currentbun");
|
||||||
|
prefs.save({infosource: waitingon.source});
|
||||||
|
debug.log("BROWSER", "Source switched to",prefs.infosource);
|
||||||
|
$("#button_source"+prefs.infosource).addClass("currentbun");
|
||||||
|
}
|
||||||
|
for (var i in waitingon) {
|
||||||
|
if (waitingon[i] === true) {
|
||||||
|
$("#"+i+"information").html(waitingBanner(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i = 1; i < history.length-1; i++) {
|
||||||
|
history[i].mastercollection.stopDisplaying();
|
||||||
|
}
|
||||||
|
// Remember, here we tell artist, album, and track to display even if we only want one of them.
|
||||||
|
// This is because we need the new collections to handle clicks and other stuff,
|
||||||
|
// as otherwise it all gets very out of hand and impossible to follow,
|
||||||
|
// mainly because it's super tricky to keep the stopDisplaying/displayData displaying flags
|
||||||
|
// all in sync since they're global to one dataCollection and not individual for artist,
|
||||||
|
// album, and track. (This was tried before and got stupid).
|
||||||
|
history[ptr].mastercollection.sendDataToBrowser(waitingon);
|
||||||
|
if (displaypointer == history.length-1) {
|
||||||
|
// We only allow artist switching on the current playing track.
|
||||||
|
// It's not that it doesn't work, but it means the artist switch gets added to
|
||||||
|
// the end of history and then you have to go back to get to the current track,
|
||||||
|
// which means things stop auto-updating.
|
||||||
|
// Also it makes truncating the history really hard.
|
||||||
|
// TODO perhaps artist switches should be spliced in?
|
||||||
|
history[ptr].mastercollection.doArtistChoices();
|
||||||
|
} else {
|
||||||
|
if ($("#artistchooser").is(':visible')) {
|
||||||
|
$("#artistchooser").slideUp('fast');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function waitingBanner(which) {
|
||||||
|
var html = '<div class="containerbox infosection menuitem">';
|
||||||
|
html += '<h2 class="expand"><span class="ucfirst">'+language.gettext("label_"+which)+
|
||||||
|
'</span> : '+language.gettext("info_gettinginfo")+'</h2>';
|
||||||
|
html += '<div class="fixed alignmid"><i class="icon-spin6 svg-square spinner"></i></div>';
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function banner(data, title, hidden, source, close) {
|
||||||
|
var html = '<div class="containerbox infosection menuitem">';
|
||||||
|
if (source) {
|
||||||
|
html += '<h2 class="expand"><span class="ucfirst">'+
|
||||||
|
language.gettext("label_"+title)+'</span> : ' + data.name + '</h2>';
|
||||||
|
} else {
|
||||||
|
html += '<h2 class="expand">' + data.name + '</h2>';
|
||||||
|
}
|
||||||
|
html += '<div class="fixed alignmid">';
|
||||||
|
html += '<i class="icon-menu svg-square infoclick clickicon frog tooltip" title="'+language.gettext('label_hidepanel')+'"></i>';
|
||||||
|
html += '</div>';
|
||||||
|
if (data.help) {
|
||||||
|
html += '<div class="fixed alignmid"><a href="'+data.help+'" target="_blank">'+
|
||||||
|
'<i class="icon-info-circled svg-square tooltip" title="'+language.gettext('label_gethelp')+'"></i></a></div>';
|
||||||
|
}
|
||||||
|
if (source) {
|
||||||
|
if (data.link) {
|
||||||
|
html += '<div class="fixed alignmid"><a href="'+data.link+'" target="_blank">'+
|
||||||
|
'<i class="'+sources[source].icon+' svg-square tooltip" title="'+language.gettext("info_newtab")+'"></i></a></div>';
|
||||||
|
} else {
|
||||||
|
html += '<div class="fixed alignmid"><i class="'+sources[source].icon+' svg-square"></i></div>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (close) {
|
||||||
|
html += '<div class="fixed alignmid padright"><i class="icon-cancel-circled svg-square infoclick clickicon tadpole tooltip" title="'+language.gettext('label_closepanel')+'"></i></div>';
|
||||||
|
}
|
||||||
|
html += '</div>';
|
||||||
|
html += '<div class="foldup" id="'+title+'foldup"';
|
||||||
|
if (hidden) {
|
||||||
|
html += ' style="display:none"';
|
||||||
|
}
|
||||||
|
html += '>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function toggleSection(element) {
|
||||||
|
var foldup = element.parent().parent().next();
|
||||||
|
var section = element.parent().parent().parent().attr("id");
|
||||||
|
$(foldup).slideToggle('slow', function() {
|
||||||
|
if ($(this).is(':visible')) {
|
||||||
|
browser.rePoint();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
section = section.replace(/information/,'');
|
||||||
|
panelclosed[section] = !panelclosed[section];
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateHistory() {
|
||||||
|
$('#historypanel').off('click').empty().html('<div class="configtitle textcentre"><b>'
|
||||||
|
+language.gettext("button_history")
|
||||||
|
+'</b><i class="icon-cancel-circled clickicon playlisticonr tright mobonly" onclick="showHistory()"></i></div>'
|
||||||
|
);
|
||||||
|
if (displaypointer == 1) {
|
||||||
|
$("#backbutton").off('click').addClass('button-disabled');
|
||||||
|
}
|
||||||
|
if (displaypointer > 1 && $("#backbutton").hasClass('button-disabled')) {
|
||||||
|
$("#backbutton").on('click', browser.back );
|
||||||
|
$("#backbutton").removeClass('button-disabled');
|
||||||
|
}
|
||||||
|
if (displaypointer == (history.length)-1) {
|
||||||
|
$("#forwardbutton").off('click').addClass('button-disabled');
|
||||||
|
}
|
||||||
|
if (displaypointer < (history.length)-1 && $("#forwardbutton").hasClass('button-disabled')) {
|
||||||
|
$("#forwardbutton").on('click', browser.forward );
|
||||||
|
$("#forwardbutton").removeClass('button-disabled');
|
||||||
|
}
|
||||||
|
|
||||||
|
var bits = ["artist","album","track"];
|
||||||
|
var t = $('<table>', {class: 'histable', width: '100%'}).appendTo('#historypanel');
|
||||||
|
|
||||||
|
for (var i = 1; i < history.length; i++) {
|
||||||
|
var clas = "top clickable clickicon";
|
||||||
|
if (i == displaypointer) {
|
||||||
|
clas = clas + " current";
|
||||||
|
}
|
||||||
|
var r = $('<tr>', {class: clas, name: i}).appendTo(t);
|
||||||
|
r.append('<td><i class="'+sources[history[i].source].icon+' medicon"></i></td>');
|
||||||
|
var td = $('<td>').appendTo(r);
|
||||||
|
var html = '';
|
||||||
|
bits.forEach(function(n) {
|
||||||
|
if (history[i][n].collection) {
|
||||||
|
html += history[i][n].collection.bannername()+'<br />';
|
||||||
|
} else {
|
||||||
|
html += language.gettext("label_"+n)+' : '+history[i][n].name+'<br>';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
td.html(html);
|
||||||
|
}
|
||||||
|
$('#historypanel').on('click', browser.historyClicked);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeSection(section) {
|
||||||
|
extraPlugins[section].parent.close();
|
||||||
|
extraPlugins[section].div.fadeOut('fast', function() {
|
||||||
|
extraPlugins[section].div.empty();
|
||||||
|
extraPlugins[section].div.remove();
|
||||||
|
extraPlugins[section].div = null;
|
||||||
|
if ($('#pluginholder').length > 0 && openPlugins() == 0) {
|
||||||
|
layoutProcessor.sourceControl('specialplugins');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function openPlugins() {
|
||||||
|
var c = 0;
|
||||||
|
for (var i in extraPlugins) {
|
||||||
|
if (extraPlugins[i].div !== null) {
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
function checkHistoryLength() {
|
||||||
|
if (history.length > maxhistorylength) {
|
||||||
|
debug.shout("BROWSER", "Truncating History");
|
||||||
|
var np = history[1].mastercollection.nowplayingindex;
|
||||||
|
history.splice(1,1);
|
||||||
|
displaypointer--;
|
||||||
|
for (var i = 1; i < history.length; i++) {
|
||||||
|
// Scan our history to see if this nowplayingindex is being used anywhere else
|
||||||
|
if (history[i].mastercollection.nowplayingindex == np) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug.log("BROWSER","Telling nowplaying to remove nowplayingindex",np);
|
||||||
|
nowplaying.remove(np);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
historyClicked: function(event) {
|
||||||
|
var clickedRow = $(event.target);
|
||||||
|
while (!clickedRow.hasClass('clickable') && !clickedRow.is('#historypanel')) {
|
||||||
|
clickedRow = clickedRow.parent();
|
||||||
|
}
|
||||||
|
if (clickedRow.hasAttr('name')) {
|
||||||
|
browser.doHistory(clickedRow.attr('name'));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
areweatfront: function() {
|
||||||
|
debug.log("BROWSER","displaypointer:",displaypointer,"historylength",history.length);
|
||||||
|
return (displaypointer == history.length - 1);
|
||||||
|
},
|
||||||
|
|
||||||
|
createButtons: function() {
|
||||||
|
for (var i in sources) {
|
||||||
|
if (sources[i].icon !== null) {
|
||||||
|
debug.log("BROWSER", "Found plugin", i,sources[i].icon);
|
||||||
|
layoutProcessor.addInfoSource(i, sources[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
layoutProcessor.setupInfoButtons();
|
||||||
|
},
|
||||||
|
|
||||||
|
nextSource: function(direction) {
|
||||||
|
var s = new Array();
|
||||||
|
for (var i in sources) {
|
||||||
|
if (sources[i].icon !== null) {
|
||||||
|
s.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var cursourceidx = s.indexOf(prefs.infosource);
|
||||||
|
var newsourceidx = cursourceidx+direction;
|
||||||
|
if (newsourceidx >= s.length) newsourceidx = 0;
|
||||||
|
if (newsourceidx < 0) newsourceidx = s.length-1;
|
||||||
|
browser.switchsource(s[newsourceidx]);
|
||||||
|
},
|
||||||
|
|
||||||
|
dataIsComing: function(mastercollection, isartistswitch, nowplayingindex, source, trackartist, artist, albumartist, album, track) {
|
||||||
|
debug.log("BROWSER","Data is coming",isartistswitch, nowplayingindex, source, artist, albumartist, album, track)
|
||||||
|
if (prefs.hidebrowser) {
|
||||||
|
debug.log("BROWSER","Browser is hidden. Ignoring Data");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var showalbum = (album != history[displaypointer].album.name || albumartist != history[displaypointer].album.artist || source != prefs.infosource);
|
||||||
|
var showartist = (isartistswitch || artist != history[displaypointer].artist.name || source != prefs.infosource ||
|
||||||
|
(showalbum && artist != history[displaypointer].artist.name));
|
||||||
|
var showtrack = (track != history[displaypointer].track.name || showalbum || source != prefs.infosource);
|
||||||
|
|
||||||
|
checkHistoryLength();
|
||||||
|
|
||||||
|
history.push( {
|
||||||
|
mastercollection: mastercollection,
|
||||||
|
source: source,
|
||||||
|
trackartist: trackartist,
|
||||||
|
artist: {
|
||||||
|
name: artist,
|
||||||
|
collection: null
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
name: album,
|
||||||
|
artist: albumartist,
|
||||||
|
collection: null
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
name: track,
|
||||||
|
collection: null
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display the new data only if either:
|
||||||
|
// We are currently displaying the most recent track (ie continuous updates)
|
||||||
|
// This is an artist switch request
|
||||||
|
// This is a source switch request
|
||||||
|
// History has been truncated such that the currently displayed info needs to be removed
|
||||||
|
if (displaypointer == history.length - 2 || isartistswitch || source != prefs.infosource || displaypointer < 1) {
|
||||||
|
displaypointer = history.length - 1;
|
||||||
|
// Hack timeout to get around a problem where Masonry doesn't layout properly
|
||||||
|
// during page load.
|
||||||
|
if (doneone) {
|
||||||
|
displayTheData( displaypointer, showartist, showalbum, showtrack );
|
||||||
|
} else {
|
||||||
|
setTimeout(function() {
|
||||||
|
displayTheData( displaypointer, showartist, showalbum, showtrack );
|
||||||
|
doneone = true;
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
updateHistory();
|
||||||
|
},
|
||||||
|
|
||||||
|
Update: function(collection, type, source, nowplayingindex, data, scrollto, force) {
|
||||||
|
if (prefs.hidebrowser) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
debug.mark("BROWSER", "Got",type,"info from",source,"for index",nowplayingindex,force,waitingon);
|
||||||
|
if (force === true || (source == waitingon.source && nowplayingindex == waitingon.index)) {
|
||||||
|
if (force === true || waitingon[type]) {
|
||||||
|
debug.trace("BROWSER", " .. and we are going to display it");
|
||||||
|
if (data.data !== null && (source == "file" || data.name !== "")) {
|
||||||
|
if ($("#"+type+"information").is(':hidden')) {
|
||||||
|
$("#"+type+"information").show();
|
||||||
|
}
|
||||||
|
$("#"+type+"information").html(banner(data, (collection === null) ? type : collection.bannertitle(), panelclosed[type], source)+data.data);
|
||||||
|
} else {
|
||||||
|
$("#"+type+"information").empty();
|
||||||
|
if ($("#"+type+"information").is(':visible')) {
|
||||||
|
$("#"+type+"information").hide();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
waitingon[type] = false;
|
||||||
|
if (scrollto) {
|
||||||
|
layoutProcessor.goToBrowserPanel(type);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
reDo: function(index, source) {
|
||||||
|
if (history[displaypointer].mastercollection && index == history[displaypointer].mastercollection.nowplayingindex && source == prefs.infosource) {
|
||||||
|
debug.log("BROWSER","Re-displaying data for",source,"index",index);
|
||||||
|
displayTheData(displaypointer, true, true, true);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
switchsource: function(src) {
|
||||||
|
debug.log("BROWSER","Switching to",src);
|
||||||
|
if (displaypointer >= 1) {
|
||||||
|
displaypointer = history.length - 1;
|
||||||
|
history[displaypointer].mastercollection.populate(src, true);
|
||||||
|
updateHistory();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
handleClick: function(source, element, event) {
|
||||||
|
debug.log("BROWSER","Was clicked on",source,element);
|
||||||
|
if (element.hasClass('frog')) {
|
||||||
|
toggleSection(element);
|
||||||
|
} else if (element.hasClass('tadpole')) {
|
||||||
|
removeSection(source);
|
||||||
|
} else if (element.hasClass('plugclickable')) {
|
||||||
|
extraPlugins[source].parent.handleClick(element, event);
|
||||||
|
} else if (element.hasClass('clickartistchoose')) {
|
||||||
|
nowplaying.switchArtist(history[displaypointer].source, element.next().val());
|
||||||
|
} else {
|
||||||
|
history[displaypointer].mastercollection.handleClick(history[displaypointer].source, source, element, event);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
// This function is for links which are followed internally by one of the panels
|
||||||
|
// eg wikipedia
|
||||||
|
speciaUpdate: function(source, panel, data) {
|
||||||
|
debug.mark("BROWSER","Special Update from",source,"for",panel);
|
||||||
|
var n = new specialUpdateCollection(source, panel, data);
|
||||||
|
|
||||||
|
history.splice(displaypointer+1,0, {
|
||||||
|
mastercollection: history[displaypointer].mastercollection,
|
||||||
|
source: source,
|
||||||
|
trackartist: history[displaypointer].trackartist,
|
||||||
|
artist: {
|
||||||
|
name: history[displaypointer].artist.name,
|
||||||
|
collection: (panel == "artist") ? n : history[displaypointer].artist.collection
|
||||||
|
},
|
||||||
|
album: {
|
||||||
|
name: history[displaypointer].album.name,
|
||||||
|
albumartist: history[displaypointer].albumartist,
|
||||||
|
collection: (panel == "album") ? n : history[displaypointer].album.collection
|
||||||
|
},
|
||||||
|
track: {
|
||||||
|
name: history[displaypointer].track.name,
|
||||||
|
collection: (panel == "track") ? n : history[displaypointer].track.collection
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
waitingon[panel] = true;
|
||||||
|
waitingon.source = source;
|
||||||
|
waitingon.index = history[displaypointer].mastercollection.nowplayingindex;
|
||||||
|
displaypointer++;
|
||||||
|
updateHistory();
|
||||||
|
browser.Update(n, panel, source, waitingon.index, data, true);
|
||||||
|
},
|
||||||
|
|
||||||
|
doHistory: function(index) {
|
||||||
|
debug.log("BROWSER", "Doing history, index is",index);
|
||||||
|
|
||||||
|
var showartist = (history[index].artist.collection === null &&
|
||||||
|
(history[index].artist.name != history[displaypointer].artist.name ||
|
||||||
|
history[index].source != history[displaypointer].source ||
|
||||||
|
history[displaypointer].artist.collection !== null));
|
||||||
|
|
||||||
|
var showalbum = (history[index].album.collection === null &&
|
||||||
|
(history[index].album.name != history[displaypointer].album.name ||
|
||||||
|
history[index].album.artist != history[displaypointer].album.artist ||
|
||||||
|
history[index].source != history[displaypointer].source ||
|
||||||
|
history[displaypointer].album.collection !== null));
|
||||||
|
|
||||||
|
var showtrack = (history[index].track.collection === null &&
|
||||||
|
(history[index].track.name != history[displaypointer].track.name ||
|
||||||
|
history[index].album.name != history[displaypointer].album.name ||
|
||||||
|
history[index].album.artist != history[displaypointer].album.artist ||
|
||||||
|
history[index].source != history[displaypointer].source ||
|
||||||
|
history[displaypointer].track.collection !== null));
|
||||||
|
|
||||||
|
displaypointer = index;
|
||||||
|
debug.log("BROWSER","History flags are",showartist,showalbum,showtrack);
|
||||||
|
// Calling displayTheData is important even if all the showxxx flags are false
|
||||||
|
// since it makes sure the correct trackDataCollection gets its displaying flag set.
|
||||||
|
displayTheData(displaypointer, showartist, showalbum, showtrack);
|
||||||
|
updateHistory();
|
||||||
|
|
||||||
|
var bits = ["artist","album","track"];
|
||||||
|
bits.forEach(function(n) {
|
||||||
|
debug.log("BROWSER","Updating",n);
|
||||||
|
if (history[index][n].collection) {
|
||||||
|
waitingon[n] = true;
|
||||||
|
waitingon.source = history[index].source;
|
||||||
|
waitingon.index = history[index].mastercollection.nowplayingindex;
|
||||||
|
browser.Update(history[index][n].collection, n, waitingon.source, waitingon.index, history[index][n].collection.getData());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
layoutProcessor.afterHistory();
|
||||||
|
},
|
||||||
|
|
||||||
|
forward: function() {
|
||||||
|
browser.doHistory(displaypointer+1);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
back: function() {
|
||||||
|
browser.doHistory(displaypointer-1);
|
||||||
|
return false;
|
||||||
|
},
|
||||||
|
|
||||||
|
registerExtraPlugin: function(id, name, parent, help) {
|
||||||
|
var displayer;
|
||||||
|
if (prefs.hidebrowser) {
|
||||||
|
$("#hidebrowser").prop("checked", !$("#hidebrowser").is(':checked'));
|
||||||
|
prefs.save({hidebrowser: $("#hidebrowser").is(':checked')}, hideBrowser);
|
||||||
|
}
|
||||||
|
if ($('#pluginholder').length > 0 && !($('#pluginholder').is(':visible'))) {
|
||||||
|
displayer = $('<div>', {id: id+"information", class: "infotext invisible"}).appendTo('#pluginholder');
|
||||||
|
} else {
|
||||||
|
displayer = $('<div>', {id: id+"information", class: "infotext invisible"}).insertBefore('#artistchooser');
|
||||||
|
}
|
||||||
|
var opts = {name: name};
|
||||||
|
if (help) {
|
||||||
|
opts.help = help;
|
||||||
|
}
|
||||||
|
displayer.html(banner(opts, id, false, false, true));
|
||||||
|
panelclosed[id] = false;
|
||||||
|
displayer.off('click');
|
||||||
|
extraPlugins[id] = { div: displayer, parent: parent };
|
||||||
|
displayer.on('click', '.infoclick', onBrowserClicked);
|
||||||
|
return displayer;
|
||||||
|
},
|
||||||
|
|
||||||
|
goToPlugin: function(id) {
|
||||||
|
layoutProcessor.goToBrowserPlugin(id);
|
||||||
|
},
|
||||||
|
|
||||||
|
rePoint: function(panel, params) {
|
||||||
|
if (prefs.hidebrowser || $('#infopane').width() == 0) { return }
|
||||||
|
|
||||||
|
debug.debug("BROWSER","Repointing");
|
||||||
|
layoutProcessor.updateInfopaneScrollbars();
|
||||||
|
|
||||||
|
$('#infopane .masonified:visible').each(function() {
|
||||||
|
var h = $(this);
|
||||||
|
var width = calcPercentWidth(h, '.tagholder', 500, h.width());
|
||||||
|
h.find(".tagholder").css('width', width.toString()+'%');
|
||||||
|
// Check if it is being handled by Masonry, prevents early init with no paramerts
|
||||||
|
if (typeof(params) == 'undefined' && h.css('position') == 'relative') {
|
||||||
|
h.masonry();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#infopane .masonified5.filled:visible').each(function() {
|
||||||
|
var h = $(this);
|
||||||
|
var width = calcPercentWidth(h, '.tagholder5', 260, h.width());
|
||||||
|
h.find(".tagholder5").css('width', width.toString()+'%');
|
||||||
|
h.find(".sizer").css('width', width.toString()+'%');
|
||||||
|
if (typeof(params) == 'undefined' && h.css('position') == 'relative') {
|
||||||
|
h.masonry();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#infopane .masonified2:visible').each(function() {
|
||||||
|
var h = $(this);
|
||||||
|
var width = calcPercentWidth(h, '.tagholder2', 260, h.width());
|
||||||
|
h.find(".tagholder2").css('width', width.toString()+'%');
|
||||||
|
h.find(".sizer").css('width', width.toString()+'%');
|
||||||
|
h.find(".tagholder_wide").css("width", "100%");
|
||||||
|
h.find(".brick_wide").css("width", "100%");
|
||||||
|
if (typeof(params) == 'undefined' && h.css('position') == 'relative') {
|
||||||
|
h.masonry();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#infopane .masonified7:visible').each(function() {
|
||||||
|
var h = $(this);
|
||||||
|
if (h.width() > 800) {
|
||||||
|
var width = 48;
|
||||||
|
} else {
|
||||||
|
var width = 99;
|
||||||
|
}
|
||||||
|
h.find(".tagholder2").css('width', width.toString()+'%');
|
||||||
|
h.find(".tagholder_wode").css("width", "100%");
|
||||||
|
if (typeof(params) == 'undefined' && h.css('position') == 'relative') {
|
||||||
|
h.masonry();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#infopane .masonified4:visible').each(function() {
|
||||||
|
var h = $(this);
|
||||||
|
var width = calcPercentWidth(h, '.tagholder4', 140, h.width());
|
||||||
|
h.find(".tagholder4").css('width', width.toString()+'%');
|
||||||
|
if (typeof(params) == 'undefined' && h.css('position') == 'relative') {
|
||||||
|
h.masonry();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$('#infopane .mixcontainer:visible').each(function() {
|
||||||
|
var h = $(this);
|
||||||
|
var w = h.width();
|
||||||
|
var m = h.children('.mixbox');
|
||||||
|
if (m.length == 1 || w < 700) {
|
||||||
|
m.css('width', '100%');
|
||||||
|
} else {
|
||||||
|
m.css('width', '50%');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (typeof(params) != 'undefined') {
|
||||||
|
params.gutter = masonry_gutter;
|
||||||
|
panel.masonry(params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
function specialUpdateCollection(source, panel, data) {
|
||||||
|
|
||||||
|
this.bannertitle = function() {
|
||||||
|
return source;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.bannername = function() {
|
||||||
|
return data.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getData = function() {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,310 @@
|
||||||
|
var info_file = function() {
|
||||||
|
|
||||||
|
var me = "file";
|
||||||
|
|
||||||
|
function podComment(parent) {
|
||||||
|
if (parent.playlistinfo.type == 'podcast' && parent.playlistinfo.Comment) {
|
||||||
|
return '<div class="brick tagholder_wode tagholder"><table class="fileinfotable" style="width:100%"><tr><th>'+
|
||||||
|
language.gettext("info_comment").replace(':','')+'</th></tr><tr><td class="notbold">'+parent.playlistinfo.Comment+'</td></tr></table></div>';
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
function createInfoFromPlayerInfo(info, parent) {
|
||||||
|
|
||||||
|
var html = "";
|
||||||
|
var file = decodeURI(info.file);
|
||||||
|
debug.log("FILE INFO","Decoded File Name is",file);
|
||||||
|
file = file.replace(/^file:\/\//, '');
|
||||||
|
var filetype = "";
|
||||||
|
if (file) {
|
||||||
|
var n = file.match(/.*\.(.*?)$/);
|
||||||
|
if (n) {
|
||||||
|
filetype = n[n.length-1];
|
||||||
|
filetype = filetype.toLowerCase();
|
||||||
|
if (filetype.match(/\/|\?|\=/)) {
|
||||||
|
filetype = "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (file == "null" || file == "undefined") file = "";
|
||||||
|
html += '<table class="fileinfotable" style="width:100%">';
|
||||||
|
html += '<tr><th colspan="2">Format Information</th></tr>';
|
||||||
|
html += '<tr><td>'+language.gettext("info_file")+'</td><td>'+file;
|
||||||
|
if (file.match(/^http:\/\/.*item\/\d+\/file/)) html += ' <i>'+language.gettext("info_from_beets")+'</i>';
|
||||||
|
if (info.file) {
|
||||||
|
var f = info.file.match(/^podcast[\:|\+](http.*?)\#/);
|
||||||
|
if (f && f[1]) {
|
||||||
|
html += '<button onclick="podcasts.doPodcast(\'filepodiput\')">'+language.gettext('button_subscribe')+'</button>'+
|
||||||
|
'<input type="hidden" id="filepodiput" value="'+f[1]+'" />';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += '</td></tr>';
|
||||||
|
if (filetype != "" && !file.match(/^http/)) {
|
||||||
|
html += '<tr><td>'+language.gettext("info_format")+'</td><td>'+filetype+'</td></tr>';
|
||||||
|
}
|
||||||
|
if (info.bitrate && info.bitrate != 'None' && info.bitrate != 0) {
|
||||||
|
html += '<tr><td>'+language.gettext("info_bitrate")+'</td><td>'+info.bitrate+'</td></tr>';
|
||||||
|
}
|
||||||
|
var ai = info.audio;
|
||||||
|
if (ai) {
|
||||||
|
var p = ai.split(":");
|
||||||
|
html += '<tr><td>'+language.gettext("info_samplerate")+'</td><td>'+p[0]+' Hz, '+p[1]+' Bit, ';
|
||||||
|
if (p[2] == 1) {
|
||||||
|
html += language.gettext("info_mono");
|
||||||
|
} else if (p[2] == 2) {
|
||||||
|
html += language.gettext("info_stereo");
|
||||||
|
} else {
|
||||||
|
html += p[2]+' '+language.gettext("info_channels");
|
||||||
|
}
|
||||||
|
'</td></tr>';
|
||||||
|
}
|
||||||
|
if (info.Date) {
|
||||||
|
if (typeof info.Date == "string") {
|
||||||
|
info.Date = info.Date.split(';');
|
||||||
|
}
|
||||||
|
html += '<tr><td>'+language.gettext("info_date")+'</td><td>'+info.Date[0]+'</td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.Genre) {
|
||||||
|
if (typeof info.Genre == "string") {
|
||||||
|
info.Genre = info.Genre.split(';');
|
||||||
|
}
|
||||||
|
html += '<tr><td>'+language.gettext("info_genre")+'</td><td>'+info.Genre.join(', ')+'</td></tr>';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info.Performer) {
|
||||||
|
if (typeof info.Performer == "object") {
|
||||||
|
info.Performer = info.Performer.join(';');
|
||||||
|
}
|
||||||
|
html += '<tr><td>'+language.gettext("info_performers")+'</td><td>'+concatenate_artist_names(info.Performer.split(';'))+'</td></tr>';
|
||||||
|
}
|
||||||
|
if (info.Composer) {
|
||||||
|
if (typeof info.Composer == "object") {
|
||||||
|
info.Composer = info.Composer.join(';');
|
||||||
|
}
|
||||||
|
html += '<tr><td>'+language.gettext("info_composers")+'</td><td>'+concatenate_artist_names(info.Composer.split(';'))+'</td></tr>';
|
||||||
|
}
|
||||||
|
if (info.Comment) {
|
||||||
|
if (typeof info.Comment == "object") {
|
||||||
|
info.Comment = info.Comment.join('<br>');
|
||||||
|
}
|
||||||
|
html += '<tr><td>'+language.gettext("info_comment")+'</td><td>'+info.Comment+'</td></tr>';
|
||||||
|
}
|
||||||
|
if (parent.playlistinfo.type == 'stream' && parent.playlistinfo.stream) {
|
||||||
|
html += '<tr><td>'+language.gettext("info_comment")+'</td><td>'+parent.playlistinfo.stream+'</td></tr>';
|
||||||
|
}
|
||||||
|
html += '</table>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function createInfoFromBeetsInfo(data) {
|
||||||
|
|
||||||
|
var html = "";
|
||||||
|
debug.log("FILE PLUGIN","Doing info from Beets server");
|
||||||
|
var file = decodeURIComponent(player.status.file);
|
||||||
|
var gibbons = [ 'year', 'genre', 'label', 'disctitle', 'encoder'];
|
||||||
|
if (!file) { return "" }
|
||||||
|
html += '<table class="motherfucker" style="width:100%">';
|
||||||
|
html += '<tr><th colspan="2">Format Information</th></tr>';
|
||||||
|
html += '<tr><td class="fil">'+language.gettext("info_file")+'</td><td>'+file;
|
||||||
|
html += ' <i>'+language.gettext("info_from_beets")+'</i>';
|
||||||
|
html = html +'</td></tr>';
|
||||||
|
html += '<tr><td class="fil">'+language.gettext("info_format")+'</td><td>'+data.format+'</td></tr>';
|
||||||
|
if (data.bitrate) html += '<tr><td class="fil">'+language.gettext("info_bitrate")+'</td><td>'+data.bitrate+'</td></tr>';
|
||||||
|
html += '<tr><td class="fil">'+language.gettext("info_samplerate")+'</td><td>'+data.samplerate+' Hz, '+data.bitdepth+' Bit, ';
|
||||||
|
if (data.channels == 1) {
|
||||||
|
html += language.gettext("info_mono");
|
||||||
|
} else if (data.channels == 2) {
|
||||||
|
html = html +language.gettext("info_stereo");
|
||||||
|
} else {
|
||||||
|
html += data.channels +' '+language.gettext("info_channels");
|
||||||
|
}
|
||||||
|
html += '</td></tr>';
|
||||||
|
$.each(gibbons, function (i,g) {
|
||||||
|
if (data[g]) html += '<tr><td class="fil">'+language.gettext("info_"+g)+'</td><td>'+data[g]+'</td></tr>';
|
||||||
|
});
|
||||||
|
if (data.composer) html += '<tr><td class="fil">'+language.gettext("info_composers")+'</td><td>'+data.composer+'</td></tr>';
|
||||||
|
if (data.comments) html += '<tr><td class="fil">'+language.gettext("info_comment")+'</td><td>'+data.comments+'</td></tr>';
|
||||||
|
html += '</table>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
|
||||||
|
debug.trace("FILE PLUGIN", "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var displaying = false;
|
||||||
|
|
||||||
|
this.displayData = function() {
|
||||||
|
displaying = true;
|
||||||
|
self.doBrowserUpdate();
|
||||||
|
browser.Update(null, 'album', me, parent.nowplayingindex,
|
||||||
|
{ name: "", link: "", data: null }
|
||||||
|
);
|
||||||
|
browser.Update(null, 'artist', me, parent.nowplayingindex,
|
||||||
|
{ name: "", link: "", data: null }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function() {
|
||||||
|
displaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleClick = function(source, element, event) {
|
||||||
|
if (element.hasClass("clicksetrating")) {
|
||||||
|
nowplaying.setRating(event);
|
||||||
|
} else if (element.hasClass("clickaddtocollection")) {
|
||||||
|
nowplaying.addTrackToCollection(event, parent.nowplayingindex);
|
||||||
|
} else if (element.hasClass("clickremtag")) {
|
||||||
|
nowplaying.removeTag(event, parent.nowplayingindex);
|
||||||
|
} else if (element.hasClass("clickaddtags")) {
|
||||||
|
tagAdder.show(event, parent.nowplayingindex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
if (trackmeta.fileinfo === undefined) {
|
||||||
|
var file = parent.playlistinfo.file;
|
||||||
|
var m = file.match(/^beets:library:track(:|;)(\d+)/)
|
||||||
|
if (m && m[2] && prefs.beets_server_location != '') {
|
||||||
|
debug.trace("FILE PLUGIN","File is from beets server",m[2]);
|
||||||
|
self.updateBeetsInformation(m[2]);
|
||||||
|
} else {
|
||||||
|
setTimeout(function() {
|
||||||
|
player.controller.do_command_list([], self.updateFileInformation)
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug.mark("FILE PLUGIN",parent.nowplayingindex,"is already populated");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateFileInformation = function() {
|
||||||
|
trackmeta.fileinfo = {beets: null, player: cloneObject(player.status)};
|
||||||
|
debug.log("FILE PLUGIN","Doing update from",trackmeta);
|
||||||
|
trackmeta.lyrics = null;
|
||||||
|
player.controller.checkProgress();
|
||||||
|
self.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateBeetsInformation = function(thing) {
|
||||||
|
// Get around possible same origin policy restriction by using a php script
|
||||||
|
$.getJSON('browser/backends/getBeetsInfo.php', 'uri='+thing)
|
||||||
|
.done(function(data) {
|
||||||
|
debug.trace("FILE PLUGIN",'Got info from beets server',data);
|
||||||
|
trackmeta.fileinfo = {beets: data, player: null};
|
||||||
|
if (data.lyrics) {
|
||||||
|
debug.shout("FILE PLUGIN","Got lyrics from Beets Server");
|
||||||
|
trackmeta.lyrics = data.lyrics;
|
||||||
|
} else {
|
||||||
|
trackmeta.lyrics = null;
|
||||||
|
}
|
||||||
|
self.doBrowserUpdate();
|
||||||
|
|
||||||
|
})
|
||||||
|
.fail( function() {
|
||||||
|
debug.error("FILE PLUGIN", "Error getting info from beets server");
|
||||||
|
self.updateFileInformation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.ratingsInfo = function() {
|
||||||
|
var html = "";
|
||||||
|
debug.shout("FILE PLUGIN","Doing the monkey spanner",trackmeta);
|
||||||
|
if (trackmeta.usermeta) {
|
||||||
|
html += '<table class="fileinfotable" style="width:100%">';
|
||||||
|
html += '<tr><th colspan="2">Collection Information</th></tr>';
|
||||||
|
if (typeof trackmeta.usermeta.Playcount != 'undefined') {
|
||||||
|
html += '<tr><td colspan="2" class="notbold">';
|
||||||
|
switch (trackmeta.usermeta.Playcount) {
|
||||||
|
case '0':
|
||||||
|
html += language.gettext('played_never');
|
||||||
|
break
|
||||||
|
case '1':
|
||||||
|
html += language.gettext('played_once');
|
||||||
|
break
|
||||||
|
case '2':
|
||||||
|
html += language.gettext('played_twice');
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
html += language.gettext('played_n',[trackmeta.usermeta.Playcount]);
|
||||||
|
break
|
||||||
|
}
|
||||||
|
html += '</td></tr>';
|
||||||
|
}
|
||||||
|
if (typeof trackmeta.usermeta.Last != 'undefined' && trackmeta.usermeta.Last != 0) {
|
||||||
|
var t = parseInt(trackmeta.usermeta.Last) * 1000;
|
||||||
|
var d = new Date(t);
|
||||||
|
var s = d.toLocaleTimeString(getLocale(), { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||||
|
html += '<tr><td colspan="2" class="notbold">'+language.gettext('played_last',[s]);
|
||||||
|
html += '</td></tr>';
|
||||||
|
}
|
||||||
|
if (prefs.player_backend == 'mopidy') {
|
||||||
|
html += '<tr><td colspan="2" class="notbold">';
|
||||||
|
if (trackmeta.usermeta.isSearchResult < 2 && trackmeta.usermeta.Hidden == 0) {
|
||||||
|
html += 'This track is in the Music Collection';
|
||||||
|
} else {
|
||||||
|
html += '<span class="infoclick clickaddtocollection">This track is not in the Music Collection. Click to add it</span>';
|
||||||
|
}
|
||||||
|
html += '</td></tr>';
|
||||||
|
}
|
||||||
|
if (trackmeta.usermeta.isSearchResult < 2 && trackmeta.usermeta.Hidden == 0) {
|
||||||
|
var t = parseInt(trackmeta.usermeta.DateAdded) * 1000;
|
||||||
|
var d = new Date(t);
|
||||||
|
var s = d.toLocaleDateString(getLocale(), { weekday: 'long', year: 'numeric', month: 'long', day: 'numeric' });
|
||||||
|
html += '<tr><td colspan="2" class="notbold">'+language.gettext('added_on',[s]);
|
||||||
|
html += '</td></tr>';
|
||||||
|
}
|
||||||
|
html += '<tr><td>Rating:</td><td>';
|
||||||
|
html += '<i class="icon-'+trackmeta.usermeta.Rating+'-stars rating-icon-big infoclick clicksetrating"></i>';
|
||||||
|
html += '<input type="hidden" value="'+parent.nowplayingindex+'" />';
|
||||||
|
html += '</td></tr>';
|
||||||
|
html += '<tr><td style="vertical-align:top">'+language.gettext("musicbrainz_tags")+'<i class="icon-plus infoclick smallicon clickaddtags"></i></td><td>';
|
||||||
|
for(var i = 0; i < trackmeta.usermeta.Tags.length; i++) {
|
||||||
|
if (trackmeta.usermeta.Tags[i] != '') {
|
||||||
|
html += '<span class="tag">'+trackmeta.usermeta.Tags[i]+'<i class="icon-cancel-circled clickicon tagremover playlisticon"></i></span> ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += '</td></tr>';
|
||||||
|
}
|
||||||
|
html += '</table>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doBrowserUpdate = function() {
|
||||||
|
if (displaying && trackmeta.fileinfo !== undefined) {
|
||||||
|
var data = '<div id="tinfobox" class="holdingcell masonified7 helpfulholder fullwidth">';
|
||||||
|
// data += '<div class="sizer"></div>';
|
||||||
|
data += '<div class="brick dingo tagholder2 tagholder">';
|
||||||
|
data += (trackmeta.fileinfo.player !== null) ? createInfoFromPlayerInfo(trackmeta.fileinfo.player, parent) : createInfoFromBeetsInfo(trackmeta.fileinfo.beets);
|
||||||
|
data += '</div>';
|
||||||
|
data += '<div class="brick dingo tagholder2 tagholder">';
|
||||||
|
data += self.ratingsInfo();
|
||||||
|
data += '</div>';
|
||||||
|
data += podComment(parent);
|
||||||
|
data += '</div>';
|
||||||
|
browser.Update(
|
||||||
|
null,
|
||||||
|
'track',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: trackmeta.name,
|
||||||
|
link: "",
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
);
|
||||||
|
browser.rePoint($('#tinfobox'), { itemSelector: '.brick', columnWidth: '.dingo', percentPosition: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("file", info_file, "icon-library", "button_fileinfo");
|
|
@ -0,0 +1,829 @@
|
||||||
|
var info_lastfm = function() {
|
||||||
|
|
||||||
|
var me = "lastfm";
|
||||||
|
var medebug = "LASTFM PLUGIN";
|
||||||
|
|
||||||
|
function formatLastFmError(lfmdata, type) {
|
||||||
|
if (lfmdata.errorcode() == 6) {
|
||||||
|
return '<h3 align="center">'+language.gettext('label_no'+type+'info')+'</h3>';
|
||||||
|
} else {
|
||||||
|
return '<h3 align="center">'+lfmdata.error()+'</h3>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sectionHeader(data) {
|
||||||
|
var html = '<div class="holdingcell">';
|
||||||
|
html += '<div class="standout stleft statsbox"><ul>';
|
||||||
|
html += '<li><b>'+language.gettext("lastfm_listeners")+'</b> '+data.listeners()+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("lastfm_plays")+'</b> '+data.playcount()+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("lastfm_yourplays")+'</b> '+data.userplaycount()+'</li>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doTags(taglist) {
|
||||||
|
debug.trace(medebug," Doing Tags");
|
||||||
|
var html = '<ul><li><b>'+language.gettext("lastfm_toptags")+'</b></li><li><table class="fullwidth">';
|
||||||
|
for(var i in taglist) {
|
||||||
|
if (taglist[i].name) {
|
||||||
|
html += '<tr><td><a href="'+taglist[i].url+'" target="_blank">'+taglist[i].name+'</a></td>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += '</table></li></ul>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function tagsInput(type) {
|
||||||
|
var html = '<ul class="holdingcell"><li><b>'+language.gettext("lastfm_addtags")+'</b></li>';
|
||||||
|
html += '<li class="tiny">'+language.gettext("lastfm_addtagslabel")+'</li>';
|
||||||
|
html += '<li><input class="enter tiny inbrowser" type="text"></input>';
|
||||||
|
html += '<button class="infoclick clickaddtags tiny">'+language.gettext("button_add")+'</button>'+
|
||||||
|
'<i class="smallicon tright" id="tagadd'+type+'"></i></li></ul>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doUserTags(name) {
|
||||||
|
var html = '<ul><li><b>'+language.gettext("lastfm_yourtags")+'</b></li><li><table class="fullwidth" name="'+name+'tagtable">';
|
||||||
|
html += '</table></li></ul>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findTag(name, taglist) {
|
||||||
|
for(var i in taglist) {
|
||||||
|
if (name == taglist[i].name) {
|
||||||
|
debug.debug("FINDTAG", "Found tag",name);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function findTag2(name, table) {
|
||||||
|
var retval = false;
|
||||||
|
table.find('tr').each( function() {
|
||||||
|
var n = $(this).find('a').text();
|
||||||
|
if (n.toLowerCase() == name.toLowerCase()) {
|
||||||
|
debug.debug("FINDTAG 2",'Found Tag',name);
|
||||||
|
retval = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return retval;
|
||||||
|
}
|
||||||
|
|
||||||
|
function appendTag(table, name, url) {
|
||||||
|
var html = '<tr class="newtag invisible"><td><a href="'+url+'" target="_blank">'+name+'</a></td>';
|
||||||
|
html += '<td><i class="icon-cancel-circled playlisticon infoclick clickremovetag tooltip" title="'+language.gettext("lastfm_removetag")+'"></i></td>';
|
||||||
|
$('table[name="'+table+'tagtable"]').append(html);
|
||||||
|
$(".newtag").fadeIn('fast', function(){
|
||||||
|
$(this).removeClass('newtag');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArtistHTML(lfmdata, parent, artistmeta) {
|
||||||
|
if (lfmdata.error()) {
|
||||||
|
return formatLastFmError(lfmdata, 'artist');
|
||||||
|
}
|
||||||
|
var html = sectionHeader(lfmdata);
|
||||||
|
html += '</ul><br>';
|
||||||
|
|
||||||
|
html += doTags(lfmdata.tags());
|
||||||
|
if (lastfm.isLoggedIn()) {
|
||||||
|
html += tagsInput("artist");
|
||||||
|
html += doUserTags("artist");
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</div><div class="statsbox">';
|
||||||
|
|
||||||
|
html += '<div id="artistbio" class="minwidthed">';
|
||||||
|
html += lastfm.formatBio(lfmdata.bio(), lfmdata.url());
|
||||||
|
html += '</div></div>';
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
var similies = lfmdata.similar();
|
||||||
|
if (similies.length > 0 && typeof similies[0].name != 'undefined') {
|
||||||
|
html += '<div id="similarartists" class="bordered"><h3 align="center">'+language.gettext("lastfm_simar")+'</h3>';
|
||||||
|
html += '<table width="100%" cellspacing="0" cellpadding="0"><tr><td align="center"><div class="smlrtst">';
|
||||||
|
for(var i in similies) {
|
||||||
|
html += '<div class="simar">';
|
||||||
|
html += '<table><tr><td align="center">';
|
||||||
|
html += '</td></tr>';
|
||||||
|
html += '<tr><td align="center"><a href="'+similies[i].url+'" target="_blank">'+similies[i].name+'</a></td></tr>';
|
||||||
|
html += '</table>';
|
||||||
|
html += '</div>';
|
||||||
|
}
|
||||||
|
html += '</div></td></tr></table></div>';
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAlbumHTML(lfmdata) {
|
||||||
|
if (lfmdata.error()) {
|
||||||
|
return formatLastFmError(lfmdata, 'album');
|
||||||
|
}
|
||||||
|
var html = sectionHeader(lfmdata);
|
||||||
|
html += '</ul><br>';
|
||||||
|
|
||||||
|
html += doTags(lfmdata.tags());
|
||||||
|
if (lastfm.isLoggedIn()) {
|
||||||
|
html += tagsInput("album");
|
||||||
|
html += doUserTags("album");
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</div><div class="statsbox">';
|
||||||
|
var imageurl = lfmdata.image("large");
|
||||||
|
var bigurl = lfmdata.image("mega");
|
||||||
|
if (imageurl != '') {
|
||||||
|
html += '<img class="stright standout'
|
||||||
|
if (bigurl && bigurl != imageurl) {
|
||||||
|
html += ' infoclick clickzoomimage';
|
||||||
|
}
|
||||||
|
html += ' cshrinker" src="getRemoteImage.php?url=' + imageurl + '" />';
|
||||||
|
if (bigurl && bigurl != imageurl) {
|
||||||
|
html += '<input type="hidden" value="getRemoteImage.php?url='+bigurl+'" />';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (lfmdata.releasedate() != 'Unknown') {
|
||||||
|
html += '<p class="minwidthed">';
|
||||||
|
html += '<b>'+language.gettext("lastfm_releasedate")+' : </b>'+lfmdata.releasedate();
|
||||||
|
html += '</p>';
|
||||||
|
}
|
||||||
|
html += '<p class="minwidthed">'+lastfm.formatBio(lfmdata.bio())+'</p>';
|
||||||
|
var tracks = lfmdata.tracklisting();
|
||||||
|
debug.trace(medebug,"Track Listing",tracks);
|
||||||
|
if (tracks && tracks.length > 0) {
|
||||||
|
var dh = false;
|
||||||
|
for(var i in tracks) {
|
||||||
|
if (tracks[i].name) {
|
||||||
|
if (!dh) {
|
||||||
|
html += '<table><tr><th colspan="3">'+language.gettext("discogs_tracklisting")+'</th></tr>';
|
||||||
|
dh = true;
|
||||||
|
}
|
||||||
|
html += '<tr><td>';
|
||||||
|
if (tracks[i]['@attr']) { html += tracks[i]['@attr'].rank+':'; }
|
||||||
|
html += '</td><td>'+tracks[i].name+'</td><td>'+formatTimeString(tracks[i].duration)+'</td>';
|
||||||
|
html += '<td align="right"><a target="_blank" href="'+tracks[i].url+'"><i class="icon-lastfm-1 smallicon tooltip" title="'+language.gettext("lastfm_viewtrack")+'"></i></a></td><td align="right">';
|
||||||
|
html += '</td></tr>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
html += '</table>';
|
||||||
|
}
|
||||||
|
html += '</div>'
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getTrackHTML(lfmdata) {
|
||||||
|
if (lfmdata.error()) {
|
||||||
|
return formatLastFmError(lfmdata, 'track');
|
||||||
|
}
|
||||||
|
var html = sectionHeader(lfmdata);
|
||||||
|
html += '<li name="userloved">';
|
||||||
|
html = html +'</li>';
|
||||||
|
html += '</ul><br>';
|
||||||
|
|
||||||
|
html += doTags(lfmdata.tags());
|
||||||
|
if (lastfm.isLoggedIn()) {
|
||||||
|
html += tagsInput("track");
|
||||||
|
html += doUserTags("track");
|
||||||
|
}
|
||||||
|
html += '</div>';
|
||||||
|
html += '<p>'+lastfm.formatBio(lfmdata.bio())+'</p>';
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return ['musicbrainz'];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
|
||||||
|
debug.trace(medebug, "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var displaying = false;
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
$('#love').addClass('notloved').makeSpinner();
|
||||||
|
self.artist.populate();
|
||||||
|
self.album.populate();
|
||||||
|
self.track.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayData = function() {
|
||||||
|
displaying = true;
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function() {
|
||||||
|
$('#love').stopSpinner();
|
||||||
|
displaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleClick = function(source, element, event) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,source,"is handling a click event");
|
||||||
|
if (element.hasClass('clickremovetag')) {
|
||||||
|
var tagname = element.parent().prev().children().text();
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,source,"wants to remove tag",tagname);
|
||||||
|
self[source].removetags(tagname);
|
||||||
|
if (prefs.synctags) {
|
||||||
|
parent.setMeta('remove', 'Tags', tagname);
|
||||||
|
}
|
||||||
|
} else if (element.hasClass('clickaddtags')) {
|
||||||
|
var tagname = element.prev().val();
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,source,"wants to add tags",tagname);
|
||||||
|
self[source].addtags(tagname);
|
||||||
|
if (prefs.synctags) {
|
||||||
|
parent.setMeta('set', 'Tags', tagname.split(','));
|
||||||
|
}
|
||||||
|
} else if (element.hasClass('clickzoomimage')) {
|
||||||
|
imagePopup.create(element, event, element.next().val());
|
||||||
|
} else if (element.hasClass('clickunlove')) {
|
||||||
|
self[source].unlove();
|
||||||
|
if (prefs.synclove) {
|
||||||
|
parent.setMeta('set', 'Rating', '0');
|
||||||
|
}
|
||||||
|
} else if (element.hasClass('clicklove')) {
|
||||||
|
self[source].love();
|
||||||
|
if (prefs.synclove) {
|
||||||
|
parent.setMeta('set', 'Rating', prefs.synclovevalue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.somethingfailed = function(data) {
|
||||||
|
debug.warn(medebug,"Something went wrong",data);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.justaddedtags = function(type, tags) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"Just added or removed tags",tags,"on",type);
|
||||||
|
self[type].resetUserTags();
|
||||||
|
self[type].getUserTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tagAddFailed = function(type, tags) {
|
||||||
|
$("#tagadd"+type).stopSpinner();
|
||||||
|
infobar.error(language.gettext("lastfm_tagerror"));
|
||||||
|
debug.warn(medebug,"Failed to modify tags",type,tags);
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatUserTagData(name, taglist, displaying) {
|
||||||
|
if (displaying) {
|
||||||
|
debug.trace("FUTD","Doing",name,"tags");
|
||||||
|
var toAdd = new Array();
|
||||||
|
var toRemove = new Array();
|
||||||
|
$('table[name="'+name+'tagtable"]').find("tr").each( function() {
|
||||||
|
if (!(findTag($(this).find('a').text(), taglist))) {
|
||||||
|
debug.trace("FUTD","Marking tag",$(this).find('a').text(),"for removal");
|
||||||
|
toRemove.push($(this));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
for(var i in taglist) {
|
||||||
|
debug.trace("FUTD","Checking for addition",taglist[i].name);
|
||||||
|
if (!(findTag2(taglist[i].name, $('table[name="'+name+'tagtable"]')))) {
|
||||||
|
debug.trace("FUTD","Marking Tag",taglist[i].name,"for addition");
|
||||||
|
toAdd.push(taglist[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (var i in toRemove) {
|
||||||
|
toRemove[i].fadeOut('fast', function() { $(this).remove() });
|
||||||
|
}
|
||||||
|
for (var i in toAdd) {
|
||||||
|
appendTag(name, toAdd[i].name, toAdd[i].url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doUserLoved(flag) {
|
||||||
|
debug.log("LASTFM","Doing UserLoved With Flags at",flag);
|
||||||
|
if (parent.isCurrentTrack()) {
|
||||||
|
$('#love').stopSpinner();
|
||||||
|
if (flag) {
|
||||||
|
$('#love').removeClass('notloved').attr('title', language.gettext("lastfm_unlove")).off('click').on('click', nowplaying.unlove);
|
||||||
|
} else {
|
||||||
|
$('#love').removeClass('notloved').addClass('notloved').attr('title', language.gettext("lastfm_lovethis")).off('click').on('click', nowplaying.love);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (displaying) {
|
||||||
|
var li = $('li[name="userloved"]');
|
||||||
|
li.empty();
|
||||||
|
if (flag) {
|
||||||
|
li.append($('<b>').html(language.gettext("lastfm_loved")+': ')).append(language.gettext("label_yes")+' ')
|
||||||
|
li.append($('<i>', {
|
||||||
|
title: language.gettext("lastfm_unlove"),
|
||||||
|
class: "icon-heart-broken smallicon infoclick clickunlove tooltip"
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
li.append($('<b>').html(language.gettext("lastfm_loved")+': ')).append(language.gettext("label_no")+' ')
|
||||||
|
li.append($('<i>', {
|
||||||
|
title: language.gettext("lastfm_lovethis"),
|
||||||
|
class: "icon-heart smallicon infoclick clicklove tooltip notloved"
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSearchArtist() {
|
||||||
|
return (albummeta.artist && albummeta.artist != "" && parent.playlistinfo.type != 'stream') ? albummeta.artist : parent.playlistinfo.trackartist;
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendLastFMCorrections() {
|
||||||
|
try {
|
||||||
|
var updates = { trackartist: (parent.playlistinfo.metadata.artists.length == 1) ? self.artist.name() : parent.playlistinfo.trackartist,
|
||||||
|
album: self.album.name(),
|
||||||
|
title: self.track.name(),
|
||||||
|
image: self.album.image('mega') ? self.album.image('mega') : self.album.image('medium')
|
||||||
|
};
|
||||||
|
nowplaying.setLastFMCorrections(parent.currenttrack, updates);
|
||||||
|
} catch(err) {
|
||||||
|
debug.fail(medebug,"Not enough information to send corrections");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function sendMetadataUpdates(de) {
|
||||||
|
var lfmdata = new lfmDataExtractor(trackmeta.lastfm.track);
|
||||||
|
nowplaying.setMetadataFromLastFM(parent.nowplayingindex, {Playcount: lfmdata.userplaycount()});
|
||||||
|
}
|
||||||
|
|
||||||
|
this.artist = function() {
|
||||||
|
|
||||||
|
var retries = 10;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (artistmeta.lastfm === undefined) {
|
||||||
|
debug.mark(medebug,parent.nowplayingindex,"artist is populating",artistmeta.name);
|
||||||
|
lastfm.artist.getInfo( {artist: artistmeta.name},
|
||||||
|
this.lfmResponseHandler,
|
||||||
|
this.lfmResponseHandler
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"artist is already populated",artistmeta.name);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
lfmResponseHandler: function(data) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"got artist data for",artistmeta.name);
|
||||||
|
debug.trace(medebug,data);
|
||||||
|
var de = new lfmDataExtractor(data);
|
||||||
|
artistmeta.lastfm = de.getCheckedData('artist');
|
||||||
|
if (artistmeta.musicbrainz_id == "") {
|
||||||
|
var mbid = null;
|
||||||
|
try {
|
||||||
|
mbid = data.artist.mbid || null;
|
||||||
|
} catch(err) {
|
||||||
|
mbid = null;
|
||||||
|
}
|
||||||
|
debug.log(medebug,parent.nowplayingindex,"has found a musicbrainz artist ID",mbid);
|
||||||
|
artistmeta.musicbrainz_id = mbid;
|
||||||
|
}
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
tryForAllmusicImage: function() {
|
||||||
|
if (typeof artistmeta.allmusic == 'undefined' || typeof artistmeta.allmusic.artistlink === 'undefined') {
|
||||||
|
debug.shout(medebug,"Allmusic artist link not back yet");
|
||||||
|
retries--;
|
||||||
|
if (retries > 0) {
|
||||||
|
setTimeout(self.artist.tryForAllmusicImage, 2000);
|
||||||
|
} else {
|
||||||
|
debug.shout(medebug,"Artist giving up waiting for musicbrainz");
|
||||||
|
}
|
||||||
|
} else if (artistmeta.allmusic.artistlink === null) {
|
||||||
|
debug.shout(medebug,"No Allmusic artist bio link found");
|
||||||
|
} else {
|
||||||
|
debug.shout(medebug,"Getting allmusic bio from",artistmeta.allmusic.artistlink);
|
||||||
|
$.post('browser/backends/getamimage.php', {url: artistmeta.allmusic.artistlink})
|
||||||
|
.done( function(data) {
|
||||||
|
debug.log(medebug,"Got Allmusic Image", data);
|
||||||
|
if (displaying) {
|
||||||
|
var image = $('<img>', {class: "stright standout infoclick clickzoomimage cshrinker", src: "getRemoteImage.php?url="+data}).insertBefore('#artistbio');
|
||||||
|
var input = $('<input>', {type: "hidden", value: "getRemoteImage.php?url="+data});
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.fail( function() {
|
||||||
|
debug.log(medebug,"Didn't Get Allmusic Image");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && artistmeta.lastfm !== undefined) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"artist was asked to display");
|
||||||
|
var lfmdata = new lfmDataExtractor(artistmeta.lastfm.artist);
|
||||||
|
var accepted = browser.Update(
|
||||||
|
null,
|
||||||
|
'artist',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: self.artist.name(),
|
||||||
|
link: lfmdata.url(),
|
||||||
|
data: getArtistHTML(lfmdata, parent, artistmeta)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (accepted && lastfm.isLoggedIn() && !lfmdata.error()) {
|
||||||
|
self.artist.getUserTags();
|
||||||
|
self.artist.tryForAllmusicImage();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
name: function() {
|
||||||
|
try {
|
||||||
|
return artistmeta.lastfm.artist.name || artistmeta.name;
|
||||||
|
} catch(err) {
|
||||||
|
return artistmeta.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
getFullBio: function(callback, failcallback) {
|
||||||
|
debug.shout(medebug,parent.nowplayingindex,"Not Getting Bio URL:", artistmeta.lastfm.artist.url);
|
||||||
|
},
|
||||||
|
|
||||||
|
updateBio: function(data) {
|
||||||
|
if (displaying) {
|
||||||
|
$("#artistbio").html(lastfm.formatBio(data, null));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resetUserTags: function() {
|
||||||
|
artistmeta.lastfm.usertags = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserTags: function() {
|
||||||
|
debug.debug(medebug,parent.nowplayingindex,"Getting Artist User Tags");
|
||||||
|
if (artistmeta.lastfm.usertags) {
|
||||||
|
formatUserTagData('artist', artistmeta.lastfm.usertags, displaying);
|
||||||
|
} else {
|
||||||
|
var options = { artist: self.artist.name() };
|
||||||
|
if (artistmeta.musicbrainz_id != "") {
|
||||||
|
options.mbid = artistmeta.musicbrainz_id;
|
||||||
|
}
|
||||||
|
lastfm.artist.getTags(
|
||||||
|
options,
|
||||||
|
self.artist.gotUserTags,
|
||||||
|
self.artist.somethingfailed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
somethingfailed: function(data) {
|
||||||
|
$("#tagaddartist").stopSpinner();
|
||||||
|
debug.warn(medebug,"Something went wrong getting artist user tags",data);
|
||||||
|
},
|
||||||
|
|
||||||
|
gotUserTags: function(data) {
|
||||||
|
$("#tagaddartist").stopSpinner();
|
||||||
|
var de = new lfmDataExtractor(data);
|
||||||
|
artistmeta.lastfm.usertags = de.tags();
|
||||||
|
formatUserTagData('artist', artistmeta.lastfm.usertags, displaying);
|
||||||
|
},
|
||||||
|
|
||||||
|
addtags: function(tags) {
|
||||||
|
$("#tagaddartist").makeSpinner();
|
||||||
|
lastfm.artist.addTags({ artist: self.artist.name(),
|
||||||
|
tags: tags},
|
||||||
|
self.justaddedtags,
|
||||||
|
self.tagAddFailed
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
removetags: function(tags) {
|
||||||
|
$("#tagaddartist").makeSpinner();
|
||||||
|
lastfm.artist.removeTag({artist: self.artist.name(),
|
||||||
|
tag: tags},
|
||||||
|
self.justaddedtags,
|
||||||
|
self.tagAddFailed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
|
this.album = function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (albummeta.lastfm === undefined) {
|
||||||
|
debug.mark(medebug,"Getting last.fm data for album",albummeta.name);
|
||||||
|
if (parent.playlistinfo.type == 'stream') {
|
||||||
|
lastfm.artist.getInfo({ artist: albummeta.name },
|
||||||
|
this.lfmArtistResponseHandler,
|
||||||
|
this.lfmArtistResponseHandler );
|
||||||
|
|
||||||
|
} else {
|
||||||
|
lastfm.album.getInfo({ artist: getSearchArtist(),
|
||||||
|
album: albummeta.name},
|
||||||
|
this.lfmResponseHandler,
|
||||||
|
this.lfmResponseHandler );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug.trace(medebug,"Album is already populated",albummeta.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
lfmResponseHandler: function(data) {
|
||||||
|
debug.trace(medebug,"Got Album Info for",albummeta.name);
|
||||||
|
debug.debug(medebug, data);
|
||||||
|
var de = new lfmDataExtractor(data);
|
||||||
|
albummeta.lastfm = de.getCheckedData('album');
|
||||||
|
if (albummeta.musicbrainz_id == "") {
|
||||||
|
var mbid = null;
|
||||||
|
try {
|
||||||
|
mbid = data.album.mbid || null;
|
||||||
|
} catch(err) {
|
||||||
|
mbid = null;
|
||||||
|
}
|
||||||
|
if (mbid !== null) {
|
||||||
|
debug.log(medebug,parent.nowplayingindex,"has found a musicbrainz album ID",mbid);
|
||||||
|
nowplaying.updateAlbumMBID(parent.nowplayingindex,mbid);
|
||||||
|
}
|
||||||
|
albummeta.musicbrainz_id = mbid;
|
||||||
|
}
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
lfmArtistResponseHandler: function(data) {
|
||||||
|
debug.trace(medebug,"Got Album/Artist Info for",albummeta.name);
|
||||||
|
debug.debug(medebug, data);
|
||||||
|
var de = new lfmDataExtractor(data);
|
||||||
|
albummeta.lastfm = de.getCheckedData('artist');
|
||||||
|
albummeta.musicbrainz_id = null;
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && albummeta.lastfm !== undefined) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"album was asked to display");
|
||||||
|
var lfmdata = (parent.playlistinfo.type == 'stream') ? new lfmDataExtractor(albummeta.lastfm.artist) : new lfmDataExtractor(albummeta.lastfm.album);
|
||||||
|
var accepted = browser.Update(
|
||||||
|
null,
|
||||||
|
'album',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: lfmdata.name() || albummeta.name,
|
||||||
|
link: lfmdata.url(),
|
||||||
|
data: (parent.playlistinfo.type == 'stream') ? getArtistHTML(lfmdata) : getAlbumHTML(lfmdata)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (accepted && lastfm.isLoggedIn() && !lfmdata.error()) {
|
||||||
|
self.album.getUserTags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
name: function() {
|
||||||
|
try {
|
||||||
|
return albummeta.lastfm.album.name || albummeta.name;
|
||||||
|
} catch(err) {
|
||||||
|
return albummeta.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
image: function(size) {
|
||||||
|
if (albummeta.lastfm.album) {
|
||||||
|
var lfmdata = new lfmDataExtractor(albummeta.lastfm.album);
|
||||||
|
return lfmdata.image(size);
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
},
|
||||||
|
|
||||||
|
resetUserTags: function() {
|
||||||
|
albummeta.lastfm.usertags = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserTags: function() {
|
||||||
|
debug.debug(medebug,parent.nowplayingindex,"Getting Album User Tags");
|
||||||
|
if (albummeta.lastfm.usertags) {
|
||||||
|
formatUserTagData('album', albummeta.lastfm.usertags, displaying);
|
||||||
|
} else {
|
||||||
|
var options = { artist: getSearchArtist(), album: self.album.name() };
|
||||||
|
if (albummeta.musicbrainz_id != "" && albummeta.musicbrainz_id != null) {
|
||||||
|
options.mbid = albummeta.musicbrainz_id;
|
||||||
|
}
|
||||||
|
lastfm.album.getTags(
|
||||||
|
options,
|
||||||
|
self.album.gotUserTags,
|
||||||
|
self.album.somethingfailed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
somethingfailed: function(data) {
|
||||||
|
$("#tagaddalbum").stopSpinner();
|
||||||
|
debug.warn(medebug,"Something went wrong getting album user tags",data);
|
||||||
|
},
|
||||||
|
|
||||||
|
gotUserTags: function(data) {
|
||||||
|
$("#tagaddalbum").stopSpinner();
|
||||||
|
var de = new lfmDataExtractor(data);
|
||||||
|
albummeta.lastfm.usertags = de.tags();
|
||||||
|
formatUserTagData('album', albummeta.lastfm.usertags, displaying);
|
||||||
|
},
|
||||||
|
|
||||||
|
addtags: function(tags) {
|
||||||
|
$("#tagaddalbum").makeSpinner();
|
||||||
|
lastfm.album.addTags({ artist: getSearchArtist(),
|
||||||
|
album: self.album.name(),
|
||||||
|
tags: tags},
|
||||||
|
self.justaddedtags,
|
||||||
|
self.tagAddFailed
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
removetags: function(tags) {
|
||||||
|
$("#tagaddalbum").makeSpinner();
|
||||||
|
lastfm.album.removeTag({ artist: getSearchArtist(),
|
||||||
|
album: self.album.name(),
|
||||||
|
tag: tags},
|
||||||
|
self.justaddedtags,
|
||||||
|
self.tagAddFailed
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
this.track = function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (trackmeta.lastfm === undefined) {
|
||||||
|
debug.mark(medebug,parent.nowplayingindex,"Getting last.fm data for track",trackmeta.name);
|
||||||
|
lastfm.track.getInfo( { artist: getSearchArtist(), track: trackmeta.name },
|
||||||
|
this.lfmResponseHandler,
|
||||||
|
this.lfmResponseHandler );
|
||||||
|
} else {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"Track is already populated",trackmeta.name);
|
||||||
|
sendLastFMCorrections();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
lfmResponseHandler: function(data) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"Got Track Info for",trackmeta.name);
|
||||||
|
debug.debug(medebug, data);
|
||||||
|
var de = new lfmDataExtractor(data);
|
||||||
|
trackmeta.lastfm = de.getCheckedData('track');
|
||||||
|
if (trackmeta.musicbrainz_id == "") {
|
||||||
|
var mbid = null;
|
||||||
|
try {
|
||||||
|
mbid = data.track.mbid || null;
|
||||||
|
} catch(err) {
|
||||||
|
mbid = null;
|
||||||
|
}
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"has found a musicbrainz track ID",mbid);
|
||||||
|
trackmeta.musicbrainz_id = mbid;
|
||||||
|
}
|
||||||
|
sendLastFMCorrections();
|
||||||
|
sendMetadataUpdates();
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && trackmeta.lastfm !== undefined) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"track was asked to display");
|
||||||
|
var lfmdata = new lfmDataExtractor(trackmeta.lastfm.track);
|
||||||
|
var accepted = browser.Update(
|
||||||
|
null,
|
||||||
|
'track',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: self.track.name(),
|
||||||
|
link: lfmdata.url(),
|
||||||
|
data: getTrackHTML(lfmdata)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (accepted && lastfm.isLoggedIn() && !lfmdata.error()) {
|
||||||
|
self.track.getUserTags();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (trackmeta.lastfm !== undefined) {
|
||||||
|
var lfmdata = new lfmDataExtractor(trackmeta.lastfm.track);
|
||||||
|
doUserLoved(lfmdata.userloved());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
name: function() {
|
||||||
|
try {
|
||||||
|
return trackmeta.lastfm.track.name || trackmeta.name;
|
||||||
|
} catch(err) {
|
||||||
|
return trackmeta.name;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
resetUserTags: function() {
|
||||||
|
trackmeta.lastfm.usertags = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserTags: function() {
|
||||||
|
debug.debug(medebug,parent.nowplayingindex,"Getting Track User Tags");
|
||||||
|
if (trackmeta.lastfm.usertags) {
|
||||||
|
formatUserTagData('track', trackmeta.lastfm.usertags, displaying);
|
||||||
|
} else {
|
||||||
|
var options = { artist: self.artist.name(), track: self.track.name() };
|
||||||
|
if (trackmeta.musicbrainz_id != "" && trackmeta.musicbrainz_id != null) {
|
||||||
|
options.mbid = trackmeta.musicbrainz_id;
|
||||||
|
}
|
||||||
|
lastfm.track.getTags(
|
||||||
|
options,
|
||||||
|
self.track.gotUserTags,
|
||||||
|
self.track.somethingfailed,
|
||||||
|
0
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
|
||||||
|
somethingfailed: function(data) {
|
||||||
|
$("#tagaddtrack").stopSpinner();
|
||||||
|
debug.warn(medebug,"Something went wrong getting track user tags",data);
|
||||||
|
},
|
||||||
|
|
||||||
|
gotUserTags: function(data) {
|
||||||
|
$("#tagaddtrack").stopSpinner();
|
||||||
|
var de = new lfmDataExtractor(data);
|
||||||
|
trackmeta.lastfm.usertags = de.tags();
|
||||||
|
formatUserTagData('track', trackmeta.lastfm.usertags, displaying);
|
||||||
|
},
|
||||||
|
|
||||||
|
addtags: function(tags) {
|
||||||
|
$("#tagaddtrack").makeSpinner();
|
||||||
|
lastfm.track.addTags({ artist: self.artist.name(),
|
||||||
|
track: self.track.name(),
|
||||||
|
tags: tags},
|
||||||
|
self.justaddedtags,
|
||||||
|
self.tagAddFailed
|
||||||
|
);
|
||||||
|
},
|
||||||
|
|
||||||
|
removetags: function(tags) {
|
||||||
|
if (findTag2(tags, $('table[name="tracktagtable"]'))) {
|
||||||
|
$("#tagaddtrack").makeSpinner();
|
||||||
|
lastfm.track.removeTag({ artist: self.artist.name(),
|
||||||
|
track: self.track.name(),
|
||||||
|
tag: tags},
|
||||||
|
self.justaddedtags,
|
||||||
|
self.tagAddFailed
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
debug.warn(medebug, "Tag",tags,"not found on track");
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
love: function() {
|
||||||
|
lastfm.track.love({ track: self.track.name(), artist: self.artist.name() }, self.track.donelove);
|
||||||
|
},
|
||||||
|
|
||||||
|
unlove: function(callback) {
|
||||||
|
lastfm.track.unlove({ track: self.track.name(), artist: self.artist.name() }, self.track.donelove);
|
||||||
|
},
|
||||||
|
|
||||||
|
unloveifloved: function() {
|
||||||
|
if (trackmeta.lastfm.track.userloved == 1) {
|
||||||
|
self.track.unlove();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
donelove: function(loved) {
|
||||||
|
if (loved) {
|
||||||
|
// Rather than re-get all the details, we can just edit the track data directly.
|
||||||
|
trackmeta.lastfm.track.userloved = 1;
|
||||||
|
if (prefs.autotagname != '') {
|
||||||
|
self.track.addtags(prefs.autotagname);
|
||||||
|
if (prefs.synctags && prefs.synclove) {
|
||||||
|
parent.setMeta('set', 'Tags', [prefs.autotagname]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doUserLoved(true)
|
||||||
|
} else {
|
||||||
|
trackmeta.lastfm.track.userloved = 0;
|
||||||
|
if (prefs.autotagname != '') {
|
||||||
|
self.track.removetags(prefs.autotagname);
|
||||||
|
if (prefs.synctags && prefs.synclove) {
|
||||||
|
parent.setMeta('remove', 'Tags', prefs.autotagname);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
doUserLoved(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("lastfm", info_lastfm, "icon-lastfm-1", "button_infolastfm");
|
|
@ -0,0 +1,420 @@
|
||||||
|
var info_wikipedia = function() {
|
||||||
|
|
||||||
|
var me = "wikipedia";
|
||||||
|
|
||||||
|
function formatWiki(xml) {
|
||||||
|
var xml_node = $(xml);
|
||||||
|
var html = xml_node.find('parse > text').text();
|
||||||
|
var domain = xml_node.find('rompr > domain').text();
|
||||||
|
|
||||||
|
var jq = $('<div>'+html+'</div>');
|
||||||
|
|
||||||
|
// Remove unwanted edit links
|
||||||
|
jq.find("span.editsection").remove();
|
||||||
|
jq.find("a.edit-page").remove();
|
||||||
|
|
||||||
|
// Make external links open in a new tab
|
||||||
|
jq.find("a[href^='http:']").attr("target", "_blank");
|
||||||
|
jq.find("a[href^='//']").attr("target", "_blank");
|
||||||
|
jq.find("a[href^='/w/']").each( function() {
|
||||||
|
var ref = $(this).attr('href');
|
||||||
|
$(this).attr('href', 'http://'+domain+'.wikipedia.org'+ref);
|
||||||
|
$(this).attr("target", "_blank");
|
||||||
|
});
|
||||||
|
|
||||||
|
// Make the contents table links work
|
||||||
|
jq.find("a[href^='#']").each( function() {
|
||||||
|
if (!$(this).hasClass('infoclick')) {
|
||||||
|
var ref = $(this).attr('href');
|
||||||
|
$(this).attr('name', ref);
|
||||||
|
$(this).attr("href", "#");
|
||||||
|
$(this).addClass("infoclick clickwikicontents");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Redirect wiki image links so they go to our function to be displayed
|
||||||
|
jq.find("a.image[href^='/wiki/']").each( function() {
|
||||||
|
var ref = $(this).attr('href');
|
||||||
|
$(this).attr('href', '#');
|
||||||
|
$(this).attr('name', domain+'.wikipedia.org/'+ref.replace(/\/wiki\//,''));
|
||||||
|
$(this).addClass('infoclick clickwikimedia');
|
||||||
|
});
|
||||||
|
jq.find("a.image[href^='//commons.wikimedia.org/']").each( function() {
|
||||||
|
var ref = $(this).attr('href');
|
||||||
|
$(this).attr('href', '#');
|
||||||
|
$(this).attr('name', 'commons.wikimedia.org/'+ref.replace(/\/\/commons\.wikimedia\.org\/wiki\//,''));
|
||||||
|
$(this).addClass('infoclick clickwikimedia');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Redirect intra-wikipedia links so they go to our function
|
||||||
|
jq.find("a[href^='/wiki/']").each( function() {
|
||||||
|
var ref = $(this).attr('href');
|
||||||
|
$(this).attr('href', '#');
|
||||||
|
$(this).attr('name', domain+'/'+ref.replace(/\/wiki\//,''));
|
||||||
|
$(this).addClass('infoclick clickwikilink');
|
||||||
|
});
|
||||||
|
|
||||||
|
// Remove inline colour styles on elements.
|
||||||
|
// We do background color twice because some elements have been found
|
||||||
|
// to have 2 background color styles applied.
|
||||||
|
// if (prefs.theme == "Darkness.css" || prefs.theme == "TheBlues.css" || prefs.theme == "DarknessHiDPI.css" ) {
|
||||||
|
jq.find('[style*=background-color]').removeInlineCss('background-color');
|
||||||
|
jq.find('[style*=background-color]').removeInlineCss('background-color');
|
||||||
|
jq.find('[style*=background]').removeInlineCss('background');
|
||||||
|
jq.find('[style*=color]').removeInlineCss('color');
|
||||||
|
// }
|
||||||
|
// Remove these bits because they're a pain in the arse
|
||||||
|
jq.find("li[class|='nv']").remove();
|
||||||
|
|
||||||
|
return jq.html();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatLink(xml) {
|
||||||
|
var xml_node = $('api',xml);
|
||||||
|
return 'http://'+xml_node.find('rompr > domain').text()+'.wikipedia.org/wiki/'+xml_node.find('rompr > page').text();
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatPage(xml) {
|
||||||
|
var xml_node = $('api',xml);
|
||||||
|
var page = xml_node.find('rompr > page').text();
|
||||||
|
return page.replace(/_/g, ' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return ["musicbrainz"];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
|
||||||
|
debug.trace("WIKI PLUGIN", "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var displaying = false;
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
self.artist.populate();
|
||||||
|
self.album.populate();
|
||||||
|
self.track.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayData = function() {
|
||||||
|
displaying = true;
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function(waitingon) {
|
||||||
|
displaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
this.handleClick = function(source, element, event) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,source,"is handling a click event");
|
||||||
|
if (element.hasClass('clickwikimedia')) {
|
||||||
|
wikipedia.wikiMediaPopup(element, event);
|
||||||
|
} else if (element.hasClass('clickwikilink')) {
|
||||||
|
var link = decodeURIComponent(element.attr('name'));
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,source,"clicked a wiki link",link);
|
||||||
|
self[source].followLink(link);
|
||||||
|
} else if (element.hasClass('clickwikicontents')) {
|
||||||
|
var section = element.attr('name');
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,source,"clicked a contents link",section);
|
||||||
|
layoutProcessor.goToBrowserSection(section);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.wikiGotFailed = function(data) {
|
||||||
|
debug.warn("WIKI PLUGIN", "Failed to get Wiki Link",data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSearchArtist() {
|
||||||
|
return (albummeta.artist && albummeta.artist != "") ? albummeta.artist : parent.playlistinfo.trackartist;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.artist = function() {
|
||||||
|
|
||||||
|
var retries = 10;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (artistmeta.wikipedia === undefined) {
|
||||||
|
artistmeta.wikipedia = {};
|
||||||
|
}
|
||||||
|
if (artistmeta.wikipedia.artistinfo === undefined) {
|
||||||
|
if (artistmeta.wikipedia.artistlink === undefined) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"Artist asked to populate but no link yet");
|
||||||
|
retries--;
|
||||||
|
if (retries == 0) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"Artist giving up waiting for poxy musicbrainz");
|
||||||
|
artistmeta.wikipedia.artistlink = null;
|
||||||
|
setTimeout(self.artist.populate, 200);
|
||||||
|
} else {
|
||||||
|
setTimeout(self.artist.populate, 2000);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (artistmeta.wikipedia.artistlink === null) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"Artist asked to populate but no link could be found. Trying a search");
|
||||||
|
wikipedia.search({ artist: artistmeta.name,
|
||||||
|
disambiguation: artistmeta.disambiguation || ""
|
||||||
|
},
|
||||||
|
self.artist.wikiResponseHandler,
|
||||||
|
self.artist.wikiResponseHandler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"artist is populating",artistmeta.wikipedia.artistlink);
|
||||||
|
wikipedia.getFullUri({ uri: artistmeta.wikipedia.artistlink,
|
||||||
|
term: artistmeta.name
|
||||||
|
},
|
||||||
|
self.artist.wikiResponseHandler,
|
||||||
|
self.artist.wikiResponseHandler);
|
||||||
|
} else {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"artist is already populated",artistmeta.wikipedia.artistlink);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
wikiResponseHandler: function(data) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"got artist data for",artistmeta.name,data);
|
||||||
|
if (data) {
|
||||||
|
artistmeta.wikipedia.artistinfo = formatWiki(data);
|
||||||
|
artistmeta.wikipedia.artistlink = formatLink(data);
|
||||||
|
} else {
|
||||||
|
artistmeta.wikipedia.artistinfo = '<h3 align="center">'+language.gettext("wiki_nothing")+'</h3>';
|
||||||
|
artistmeta.wikipedia.artistlink = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && artistmeta.wikipedia.artistinfo !== undefined) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"artist was asked to display");
|
||||||
|
browser.Update(
|
||||||
|
null,
|
||||||
|
'artist',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: artistmeta.name,
|
||||||
|
link: artistmeta.wikipedia.artistlink,
|
||||||
|
data: artistmeta.wikipedia.artistinfo
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
followLink: function(link) {
|
||||||
|
wikipedia.getWiki(link, self.artist.gotWikiLink, self.wikiGotFailed);
|
||||||
|
},
|
||||||
|
|
||||||
|
gotWikiLink: function(data) {
|
||||||
|
browser.speciaUpdate(
|
||||||
|
me,
|
||||||
|
'artist',
|
||||||
|
{ name: formatPage(data),
|
||||||
|
link: formatLink(data),
|
||||||
|
data: formatWiki(data)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
this.album = function() {
|
||||||
|
|
||||||
|
var retries = 12;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (albummeta.wikipedia === undefined) {
|
||||||
|
albummeta.wikipedia = {};
|
||||||
|
}
|
||||||
|
if (albummeta.wikipedia.albumdata === undefined) {
|
||||||
|
if (albummeta.wikipedia.albumlink === undefined) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"Album asked to populate but no link yet");
|
||||||
|
retries--;
|
||||||
|
if (retries == 0) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"Album giving up waiting for poxy musicbrainz");
|
||||||
|
albummeta.wikipedia.albumlink = null;
|
||||||
|
setTimeout(self.album.populate, 200);
|
||||||
|
} else {
|
||||||
|
setTimeout(self.album.populate, 2000);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (albummeta.wikipedia.albumlink === null) {
|
||||||
|
if (albummeta.musicbrainz.album_releasegroupid !== null) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"No album link found ... trying the album release group");
|
||||||
|
musicbrainz.releasegroup.getInfo(albummeta.musicbrainz.album_releasegroupid, '', self.album.mbRgHandler, self.album.mbRgHandler);
|
||||||
|
} else {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"No album link or release group link ... trying a search");
|
||||||
|
wikipedia.search({album: albummeta.name, albumartist: getSearchArtist()}, self.album.wikiResponseHandler, self.album.wikiResponseHandler);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"album is populating",albummeta.wikipedia.albumlink);
|
||||||
|
wikipedia.getFullUri({ uri: albummeta.wikipedia.albumlink,
|
||||||
|
term: albummeta.name
|
||||||
|
},
|
||||||
|
self.album.wikiResponseHandler,
|
||||||
|
self.album.wikiResponseHandler
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"album is already populated",albummeta.wikipedia.albumlink);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
wikiResponseHandler: function(data) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"got album data for",albummeta.name);
|
||||||
|
if (data) {
|
||||||
|
albummeta.wikipedia.albumdata = formatWiki(data);
|
||||||
|
albummeta.wikipedia.albumlink = formatLink(data);
|
||||||
|
} else {
|
||||||
|
albummeta.wikipedia.albumdata = '<h3 align="center">'+language.gettext("wiki_nothing")+'</h3>';
|
||||||
|
albummeta.wikipedia.albumlink = null;
|
||||||
|
}
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
mbRgHandler: function(data) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"got musicbrainz release group data for",albummeta.name, data);
|
||||||
|
if (data.error) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex," ... MB error",data);
|
||||||
|
} else {
|
||||||
|
for (var i in data.relations) {
|
||||||
|
if (data.relations[i].type == "wikipedia") {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"has found a Wikipedia album link",data.relations[i].url.resource);
|
||||||
|
albummeta.wikipedia.albumlink = data.relations[i].url.resource;
|
||||||
|
self.album.populate();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
albummeta.wikipedia.albumlink = null;
|
||||||
|
albummeta.musicbrainz.album_releasegroupid = null;
|
||||||
|
self.album.populate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && albummeta.wikipedia.albumdata !== undefined) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"album was asked to display");
|
||||||
|
browser.Update(
|
||||||
|
null,
|
||||||
|
'album',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: albummeta.name,
|
||||||
|
link: albummeta.wikipedia.albumlink,
|
||||||
|
data: albummeta.wikipedia.albumdata
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
followLink: function(link) {
|
||||||
|
wikipedia.getWiki(link, self.album.gotWikiLink, self.wikiGotFailed);
|
||||||
|
},
|
||||||
|
|
||||||
|
gotWikiLink: function(data) {
|
||||||
|
browser.speciaUpdate(me, 'album', { name: formatPage(data),
|
||||||
|
link: formatLink(data),
|
||||||
|
data: formatWiki(data)});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
this.track = function() {
|
||||||
|
|
||||||
|
var retries = 15;
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (trackmeta.wikipedia === undefined) {
|
||||||
|
trackmeta.wikipedia = {};
|
||||||
|
}
|
||||||
|
if (trackmeta.wikipedia.trackdata === undefined) {
|
||||||
|
if (trackmeta.wikipedia.tracklink === undefined) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"track asked to populate but no link yet");
|
||||||
|
retries--;
|
||||||
|
if (retries == 0) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"Track giving up waiting for poxy musicbrainz");
|
||||||
|
trackmeta.wikipedia.tracklink = null;
|
||||||
|
setTimeout(self.track.populate, 200);
|
||||||
|
} else {
|
||||||
|
setTimeout(self.track.populate, 2000);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (trackmeta.wikipedia.tracklink === null) {
|
||||||
|
debug.shout("WIKI PLUGIN",parent.nowplayingindex,"track asked to populate but no link could be found. Trying a search");
|
||||||
|
wikipedia.search({track: trackmeta.name, trackartist: parent.playlistinfo.trackartist}, self.track.wikiResponseHandler, self.track.wikiResponseHandler);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"track is populating",trackmeta.wikipedia.tracklink);
|
||||||
|
wikipedia.getFullUri({ uri: trackmeta.wikipedia.tracklink,
|
||||||
|
term: trackmeta.name
|
||||||
|
},
|
||||||
|
self.track.wikiResponseHandler,
|
||||||
|
self.track.wikiResponseHandler
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"track is already populated",trackmeta.wikipedia.tracklink);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
wikiResponseHandler: function(data) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"got track data for",trackmeta.name);
|
||||||
|
if (data) {
|
||||||
|
trackmeta.wikipedia.trackdata = formatWiki(data);
|
||||||
|
trackmeta.wikipedia.tracklink = formatLink(data);
|
||||||
|
} else {
|
||||||
|
trackmeta.wikipedia.trackdata = '<h3 align="center">'+language.gettext("wiki_nothing")+'</h3>';
|
||||||
|
trackmeta.wikipedia.tracklink = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && trackmeta.wikipedia.trackdata !== undefined) {
|
||||||
|
debug.trace("WIKI PLUGIN",parent.nowplayingindex,"track was asked to display");
|
||||||
|
browser.Update(
|
||||||
|
null,
|
||||||
|
'track',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: trackmeta.name,
|
||||||
|
link: trackmeta.wikipedia.tracklink,
|
||||||
|
data: trackmeta.wikipedia.trackdata
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
followLink: function(link) {
|
||||||
|
wikipedia.getWiki(link, self.track.gotWikiLink, self.wikiGotFailed);
|
||||||
|
},
|
||||||
|
|
||||||
|
gotWikiLink: function(data) {
|
||||||
|
browser.speciaUpdate( me, 'track',
|
||||||
|
{ name: formatPage(data),
|
||||||
|
link: formatLink(data),
|
||||||
|
data: formatWiki(data)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("wikipedia", info_wikipedia, "icon-wikipedia", "button_wikipedia");
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,97 @@
|
||||||
|
var info_lyrics = function() {
|
||||||
|
|
||||||
|
var me = "lyrics";
|
||||||
|
|
||||||
|
return {
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return ['file'];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
|
||||||
|
debug.trace("LYRICS PLUGIN", "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var displaying = false;
|
||||||
|
|
||||||
|
function formatLyrics(data) {
|
||||||
|
debug.trace("LYRICS PLUGIN","Formatting Lyrics");
|
||||||
|
if (data) {
|
||||||
|
data = data.replace(/^(\w)/, '<font size="120%">$1</font>')
|
||||||
|
data = data.replace(/\n/g, '<br>');
|
||||||
|
}
|
||||||
|
return '<div class="lyrics"><h2 align="center">'+language.gettext("lyrics_lyrics")+'</h2><p>'+data+'</p></div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSearchArtist() {
|
||||||
|
return (albummeta.artist && albummeta.artist != "") ? albummeta.artist : parent.playlistinfo.trackartist;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayData = function() {
|
||||||
|
displaying = true;
|
||||||
|
browser.Update(null, 'album', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
browser.Update(null, 'artist', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
self.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function() {
|
||||||
|
displaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.startAfterSpecial = function() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tryReadingTags = function() {
|
||||||
|
if (prefs.music_directory_albumart == "") {
|
||||||
|
trackmeta.lyrics = '<h3 align=center>'+language.gettext("lyrics_nonefound")+'</h3><p>'+language.gettext("lyrics_nopath")+'</p>';
|
||||||
|
self.doBrowserUpdate();
|
||||||
|
} else {
|
||||||
|
$.post("browser/backends/getLyrics.php", {file: player.status.file, artist: getSearchArtist(), song: trackmeta.name})
|
||||||
|
.done(function(data) {
|
||||||
|
debug.trace("LYRICS",data);
|
||||||
|
trackmeta.lyrics = data;
|
||||||
|
self.doBrowserUpdate();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
if (trackmeta.lyrics === undefined) {
|
||||||
|
debug.trace("LYRICS PLUGIN",parent.nowplayingindex,"No lyrics yet, trying again in 1 second");
|
||||||
|
setTimeout(self.populate, 1000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (trackmeta.lyrics === null) {
|
||||||
|
self.tryReadingTags();
|
||||||
|
} else {
|
||||||
|
self.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
this.doBrowserUpdate = function() {
|
||||||
|
if (displaying && trackmeta.lyrics !== undefined && trackmeta.lyrics !== null) {
|
||||||
|
browser.Update(null, 'track', me, parent.nowplayingindex, { name: trackmeta.name,
|
||||||
|
link: "",
|
||||||
|
data: formatLyrics(trackmeta.lyrics)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("lyrics", info_lyrics, "icon-doc-text-1", "button_lyrics");
|
|
@ -0,0 +1,297 @@
|
||||||
|
var info_soundcloud = function() {
|
||||||
|
|
||||||
|
var me = "soundcloud";
|
||||||
|
var tempcanvas = document.createElement('canvas');
|
||||||
|
var scImg = new Image();
|
||||||
|
|
||||||
|
function getTrackHTML(data) {
|
||||||
|
|
||||||
|
debug.trace("SOUNDCLOUD PLUGIN","Creating track HTML from",data);
|
||||||
|
var html = '<div class="containerbox info-detail-layout">';
|
||||||
|
html += '<div class="info-box-fixed info-border-right info-box-list">';
|
||||||
|
|
||||||
|
if (data.artwork_url) {
|
||||||
|
html += '<img src="' + data.artwork_url + '" class="clrboth" style="margin:8px" />';
|
||||||
|
}
|
||||||
|
html += '<ul><li><h3>'+language.gettext("soundcloud_trackinfo")+':</h3></li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_plays")+':</b> '+formatSCMessyBits(data.playback_count)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_downloads")+':</b> '+formatSCMessyBits(data.download_count)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_faves")+':</b> '+formatSCMessyBits(data.favoritings_count)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_state")+'</b> '+formatSCMessyBits(data.state)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("info_genre")+'</b> '+formatSCMessyBits(data.genre)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("info_label")+'</b> '+formatSCMessyBits(data.label_name)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_license")+':</b> '+formatSCMessyBits(data.license)+'</li>';
|
||||||
|
if (data.purchase_url) {
|
||||||
|
html += '<li><b><a href="' + data.purchase_url + '" target="_blank">'+language.gettext("soundcloud_buy")+'</a></b></li>';
|
||||||
|
}
|
||||||
|
html += '<li><a href="' + data.permalink_url + '" title="View In New Tab" target="_blank"><b>'+language.gettext("soundcloud_view")+'</b></a></li>';
|
||||||
|
html += '</ul>';
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
html += '<div class="info-box-expand stumpy">';
|
||||||
|
html += '<div id="similarartists" class="bordered" style="position:relative">'+
|
||||||
|
'<div id="scprog"></div>'+
|
||||||
|
'<img id="gosblin" />'+
|
||||||
|
'</div>';
|
||||||
|
var d = formatSCMessyBits(data.description);
|
||||||
|
d = d.replace(/\n/g, "</p><p>");
|
||||||
|
html += '<p>'+d+'</p>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArtistHTML(data) {
|
||||||
|
debug.trace("SOUNDCLOUD PLUGIN","Creating artist HTML from",data);
|
||||||
|
var html = '<div class="containerbox info-detail-layout">';
|
||||||
|
html += '<div class="info-box-fixed info-border-right info-box-list">';
|
||||||
|
|
||||||
|
if (data.avatar_url) {
|
||||||
|
html += '<img src="' + data.avatar_url + '" class="clrboth" style="margin:8px" />';
|
||||||
|
}
|
||||||
|
html += '<ul><li><h3>'+language.gettext("soundcloud_user")+':</h3></li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_fullname")+':</b> '+formatSCMessyBits(data.full_name)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_Country")+':</b> '+formatSCMessyBits(data.country)+'</li>';
|
||||||
|
html += '<li><b>'+language.gettext("soundcloud_city")+':</b> '+formatSCMessyBits(data.city)+'</li>';
|
||||||
|
if (data.website) {
|
||||||
|
html += '<li><b><a href="' + data.website + '" target="_blank">'+language.gettext("soundcloud_website")+'</a></b></li>';
|
||||||
|
}
|
||||||
|
html += '</ul>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '<div class="info-box-expand stumpy">';
|
||||||
|
var f = formatSCMessyBits(data.description)
|
||||||
|
f = f.replace(/\n/g, "</p><p>");
|
||||||
|
html += '<p>'+ f +'</p>';
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatSCMessyBits(bits) {
|
||||||
|
try {
|
||||||
|
if (bits) {
|
||||||
|
return bits.fixDodgyLinks();
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
} catch(err) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
debug.log("SOUNDCLOUD PLUGIN", "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var wi = 0;
|
||||||
|
var displaying = false;
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
self.track.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayData = function(waitingon) {
|
||||||
|
displaying = true;
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function(waitingon) {
|
||||||
|
displaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.progressUpdate = function(percent) {
|
||||||
|
self.track.updateProgress(percent);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.artist = function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (trackmeta.soundcloud.track.error) {
|
||||||
|
browser.Update(null, 'artist', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
if (artistmeta.soundcloud.artist === undefined) {
|
||||||
|
debug.log("SOUNDCLOUD PLUGIN","Artist is populating");
|
||||||
|
soundcloud.getUserInfo(artistmeta.soundcloud.id, self.artist.scResponseHandler);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
scResponseHandler: function(data) {
|
||||||
|
artistmeta.soundcloud.artist = data;
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && trackmeta.soundcloud.track !== undefined) {
|
||||||
|
if (trackmeta.soundcloud.track.error) {
|
||||||
|
browser.Update(null, 'artist', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (artistmeta.soundcloud !== undefined &&
|
||||||
|
artistmeta.soundcloud.artist !== undefined) {
|
||||||
|
if (artistmeta.soundcloud.artist.error) {
|
||||||
|
browser.Update(null, 'artist', me, parent.nowplayingindex, {name: artistmeta.name,
|
||||||
|
link: "",
|
||||||
|
data: '<h3 align="center">'+artistmeta.soundcloud.artist.error+'</h3>'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
var accepted = browser.Update(null, 'artist', me, parent.nowplayingindex, { name: artistmeta.soundcloud.artist.username,
|
||||||
|
link: artistmeta.soundcloud.artist.permalink_url,
|
||||||
|
data: getArtistHTML(artistmeta.soundcloud.artist)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
this.album = function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying) {
|
||||||
|
browser.Update(null, 'album', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
// I do not have a pet alligator
|
||||||
|
|
||||||
|
this.track = function() {
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (artistmeta.soundcloud === undefined) {
|
||||||
|
artistmeta.soundcloud = {};
|
||||||
|
}
|
||||||
|
if (trackmeta.soundcloud === undefined) {
|
||||||
|
trackmeta.soundcloud = {};
|
||||||
|
var t = parent.playlistinfo.file;
|
||||||
|
if (t.substring(0,11) == 'soundcloud:') {
|
||||||
|
soundcloud.getTrackInfo(parent.playlistinfo.file, self.track.scResponseHandler);
|
||||||
|
} else if (t.match(/api\.soundcloud\.com\/tracks\/(\d+)\//)) {
|
||||||
|
var sc = t.match(/api\.soundcloud\.com\/tracks\/(\d+)\//);
|
||||||
|
soundcloud.getTrackInfo(sc[1], self.track.scResponseHandler);
|
||||||
|
} else if (t.match(/feeds\.soundcloud\.com\/stream\/(\d+)/)) {
|
||||||
|
var sc = t.match(/feeds\.soundcloud\.com\/stream\/(\d+)/);
|
||||||
|
soundcloud.getTrackInfo(sc[1], self.track.scResponseHandler);
|
||||||
|
} else {
|
||||||
|
trackmeta.soundcloud.track = {error: language.gettext("soundcloud_not")};
|
||||||
|
self.artist.populate();
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.artist.populate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
scResponseHandler: function(data) {
|
||||||
|
debug.log("SOUNDCLOUD PLUGIN","Got SoundCloud Track Data:",data);
|
||||||
|
trackmeta.soundcloud.track = data;
|
||||||
|
artistmeta.soundcloud.id = data.user_id;
|
||||||
|
self.artist.populate();
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && trackmeta.soundcloud.track !== undefined) {
|
||||||
|
debug.log("SOUNDCLOUD PLUGIN","Track was asked to display");
|
||||||
|
if (trackmeta.soundcloud.track.error) {
|
||||||
|
browser.Update(null, 'track', me, parent.nowplayingindex, { name: trackmeta.name,
|
||||||
|
link: "",
|
||||||
|
data: '<h3 align="center">'+trackmeta.soundcloud.track.error+'</h3>'
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
var accepted = browser.Update(null, 'track', me, parent.nowplayingindex, { name: trackmeta.name,
|
||||||
|
link: trackmeta.soundcloud.track.permalink_url,
|
||||||
|
data: getTrackHTML(trackmeta.soundcloud.track)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if (accepted) {
|
||||||
|
debug.log("SOUNDCLOUD PLUGIN","Getting Track Waveform",formatSCMessyBits(trackmeta.soundcloud.track.waveform_url));
|
||||||
|
scImg.onload = self.track.doSCImageStuff;
|
||||||
|
scImg.src = "getRemoteImage.php?url="+formatSCMessyBits(trackmeta.soundcloud.track.waveform_url);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
doSCImageStuff: function() {
|
||||||
|
// The soundcloud waveform is a png where the waveform itself is transparent
|
||||||
|
// and has a grey-ish border. We want an image with a gradient for the waveform
|
||||||
|
// and a transparent border.
|
||||||
|
tempcanvas.width = scImg.width;
|
||||||
|
tempcanvas.height = scImg.height;
|
||||||
|
var ctx = tempcanvas.getContext("2d");
|
||||||
|
ctx.clearRect(0,0,tempcanvas.width,tempcanvas.height);
|
||||||
|
|
||||||
|
// Fill tempcanvas with a linear gradient
|
||||||
|
var gradient = ctx.createLinearGradient(0,0,0,tempcanvas.height);
|
||||||
|
gradient.addColorStop(0,'rgba(255,82,0,1)');
|
||||||
|
gradient.addColorStop(0.6,'rgba(150, 48, 0, 1)');
|
||||||
|
gradient.addColorStop(1,'rgba(100, 25, 0, 0.1)');
|
||||||
|
ctx.fillStyle = gradient;
|
||||||
|
ctx.fillRect(0,0,tempcanvas.width,tempcanvas.height);
|
||||||
|
|
||||||
|
// Plop the image over the top.
|
||||||
|
ctx.drawImage(scImg,0,0,tempcanvas.width,tempcanvas.height);
|
||||||
|
|
||||||
|
// Now translate all the grey pixels into transparent ones
|
||||||
|
var pixels = ctx.getImageData(0,0,tempcanvas.width,tempcanvas.height);
|
||||||
|
var data = pixels.data;
|
||||||
|
for (var i = 0; i<data.length; i += 4) {
|
||||||
|
if (data[i] == data[i+1] && data[i+1] == data[i+2]) {
|
||||||
|
data[i+3] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.clearRect(0,0,tempcanvas.width,tempcanvas.height);
|
||||||
|
ctx.putImageData(pixels,0,0);
|
||||||
|
$("#gosblin").attr("src", tempcanvas.toDataURL());
|
||||||
|
},
|
||||||
|
|
||||||
|
updateProgress: function(percent) {
|
||||||
|
if (displaying) {
|
||||||
|
var w = Math.round($("#similarartists").width()*percent/100);
|
||||||
|
if (percent == 0) {
|
||||||
|
var h = 0;
|
||||||
|
} else {
|
||||||
|
var h = $("#similarartists").height() - 8;
|
||||||
|
}
|
||||||
|
$("#scprog").css({left: w+"px", height: h+"px"});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("soundcloud", info_soundcloud, "icon-soundcloud-circled", "button_soundcloud");
|
|
@ -0,0 +1,703 @@
|
||||||
|
var info_spotify = function() {
|
||||||
|
|
||||||
|
var me = "spotify";
|
||||||
|
var medebug = "SPOTIFY PLUGIN";
|
||||||
|
var maxwidth = 300;
|
||||||
|
|
||||||
|
function getTrackHTML(data) {
|
||||||
|
|
||||||
|
debug.trace(medebug,"Making Track Info From",data);
|
||||||
|
if (data.error) {
|
||||||
|
return '<h3 align="center">'+data.error+'</h3>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var h = '<div class="holdingcell">';
|
||||||
|
h += '<div class="standout stleft statsbox">';
|
||||||
|
h += '<ul>';
|
||||||
|
h += '<li><b>'+language.gettext("label_pop")+': </b>'+data.popularity+'</li>';
|
||||||
|
if (player.canPlay('spotify')) {
|
||||||
|
h += '<li>'+
|
||||||
|
'<div class="containerbox menuitem infoclick clickstarttrackradio" style="padding-left:0px">'+
|
||||||
|
'<div class="fixed alignmid"><i class="icon-wifi smallicon"></i></div>'+
|
||||||
|
'<div class="expand">'+language.gettext('label_radio_recommend',['Track'])+'</div>'+
|
||||||
|
'</div></li>';
|
||||||
|
}
|
||||||
|
h += '</ul>';
|
||||||
|
h += '</div>';
|
||||||
|
if (data.explicit) {
|
||||||
|
h += '<i class="icon-explicit stright standout"></i>';
|
||||||
|
}
|
||||||
|
h += '</div>';
|
||||||
|
h += '<div id="helpful_title"></div>';
|
||||||
|
h += '<div id="helpful_tracks" class="holdingcell selecotron masonified4"></div>';
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAlbumHTML(data) {
|
||||||
|
|
||||||
|
debug.trace(medebug,"Making Album Info From",data);
|
||||||
|
if (data.error) {
|
||||||
|
return '<h3 align="center">'+data.error+'</h3>';
|
||||||
|
}
|
||||||
|
var html = '<div class="containerbox standout info-detail-layout">';
|
||||||
|
html += '<div class="info-box-expand info-box-list info-border-right">';
|
||||||
|
html += '<ul>';
|
||||||
|
html += '<li>'+language.gettext("label_pop")+': '+data.popularity+'</li>';
|
||||||
|
html += '<li>'+language.gettext("lastfm_releasedate")+': '+data.release_date+'</li>';
|
||||||
|
|
||||||
|
if (player.canPlay('spotify')) {
|
||||||
|
|
||||||
|
html += '<li><div class="containerbox menuitem infoclick clickaddtolistenlater" style="padding-left:0px">'+
|
||||||
|
'<div class="fixed alignmid">'+
|
||||||
|
'<i class="icon-headphones smallicon"></i></div>'+
|
||||||
|
'<div class="expand">'+language.gettext("label_addtolistenlater")+'</div>'+
|
||||||
|
'</div></li>';
|
||||||
|
|
||||||
|
html += '<li><div class="containerbox menuitem infoclick clickaddtocollection" style="padding-left:0px">'+
|
||||||
|
'<div class="fixed alignmid">'+
|
||||||
|
'<i class="icon-music smallicon"></i></div>'+
|
||||||
|
'<div class="expand">'+language.gettext("label_addtocollection")+'</div>'+
|
||||||
|
'</div></li>';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
html += '</ul>';
|
||||||
|
html += '</div>';
|
||||||
|
|
||||||
|
html += '<div class="stumpy selecotron widermiddle">';
|
||||||
|
html += spotifyTrackListing(data)+'</div>';
|
||||||
|
html += '<div class="cleft narrowright">';
|
||||||
|
if (data.images && data.images[0]) {
|
||||||
|
html += '<img class="cnotshrinker infoclick clickzoomimage" src="getRemoteImage.php?url='+
|
||||||
|
data.images[0].url+'" />';
|
||||||
|
}
|
||||||
|
html += '</div>';
|
||||||
|
html += '</div>';
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArtistHTML(data, parent, artistmeta) {
|
||||||
|
|
||||||
|
debug.trace(medebug,"Making Artist Info From",data);
|
||||||
|
if (data.error) {
|
||||||
|
return '<h3 align="center">'+data.error+'</h3>';
|
||||||
|
}
|
||||||
|
|
||||||
|
var h = "";
|
||||||
|
|
||||||
|
if (artistmeta.spotify.possibilities && artistmeta.spotify.possibilities.length > 1) {
|
||||||
|
h += '<div class="spotchoices clearfix">'+
|
||||||
|
'<table><tr><td>'+
|
||||||
|
'<div class="bleft tleft spotthing"><span class="spotpossname">All possibilities for "'+
|
||||||
|
artistmeta.spotify.artist.name+'"</span></div>'+
|
||||||
|
'</td><td>';
|
||||||
|
for (var i in artistmeta.spotify.possibilities) {
|
||||||
|
h += '<div class="tleft infoclick bleft ';
|
||||||
|
if (i == artistmeta.spotify.currentposs) {
|
||||||
|
h += 'bsel ';
|
||||||
|
}
|
||||||
|
h += 'clickchooseposs" name="'+i+'">';
|
||||||
|
if (artistmeta.spotify.possibilities[i].image) {
|
||||||
|
h += '<img class="spotpossimg title-menu" src="getRemoteImage.php?url='+
|
||||||
|
artistmeta.spotify.possibilities[i].image+'" />';
|
||||||
|
} else {
|
||||||
|
h += '<img class="spotpossimg title-menu" src="newimages/artist-icon.png" />';
|
||||||
|
}
|
||||||
|
h += '<span class="spotpossname">'+artistmeta.spotify.possibilities[i].name+'</span>';
|
||||||
|
h += '</div>';
|
||||||
|
}
|
||||||
|
h += '</td></tr></table>';
|
||||||
|
h += '</div>';
|
||||||
|
}
|
||||||
|
|
||||||
|
h += '<div class="holdingcell">';
|
||||||
|
h += '<div class="standout stleft statsbox"><ul><li><b>'+language.gettext("label_pop")+
|
||||||
|
': </b>'+data.popularity+'</li>';
|
||||||
|
h += '<li><div class="containerbox menuitem infoclick clickstartsingleradio" style="padding-left:0px">'+
|
||||||
|
'<div class="fixed alignmid">'+
|
||||||
|
'<i class="icon-wifi smallicon"></i></div>'+
|
||||||
|
'<div class="expand">'+language.gettext("label_singleartistradio")+'</div>'+
|
||||||
|
'</div></li>';
|
||||||
|
if (player.canPlay('spotify')) {
|
||||||
|
h += '<li>'+
|
||||||
|
'<div class="containerbox menuitem infoclick clickstartradio" style="padding-left:0px">'+
|
||||||
|
'<div class="fixed alignmid">'+
|
||||||
|
'<i class="icon-wifi smallicon"></i></div>'+
|
||||||
|
'<div class="expand">'+language.gettext("lastfm_simar")+'</div>'+
|
||||||
|
'</div></li>';
|
||||||
|
h += '<li>'+
|
||||||
|
'<div class="containerbox menuitem infoclick clickstartartistradio" style="padding-left:0px">'+
|
||||||
|
'<div class="fixed alignmid">'+
|
||||||
|
'<i class="icon-wifi smallicon"></i></div>'+
|
||||||
|
'<div class="expand">'+language.gettext('label_radio_recommend',['Artist'])+'</div>'+
|
||||||
|
'</div></li>';
|
||||||
|
}
|
||||||
|
h += '</ul></div>';
|
||||||
|
if (data.images && data.images[0]) {
|
||||||
|
h += '<img class="stright standout cshrinker infoclick clickzoomimage" '+
|
||||||
|
'src="getRemoteImage.php?url='+data.images[0].url+'" />';
|
||||||
|
}
|
||||||
|
|
||||||
|
h += '<div id="artistbio" class="minwidthed"></div>';
|
||||||
|
h += '</div>';
|
||||||
|
h += '<div class="containerbox textunderline" id="bumhole"><div class="fixed infoclick clickshowalbums bleft';
|
||||||
|
if (artistmeta.spotify.showing == "albums") {
|
||||||
|
h += ' bsel';
|
||||||
|
}
|
||||||
|
h += '">'+language.gettext("label_albumsby") + '</div>' +
|
||||||
|
'<div class="fixed infoclick clickshowartists bleft bmid';
|
||||||
|
if (artistmeta.spotify.showing == "artists") {
|
||||||
|
h += ' bsel';
|
||||||
|
}
|
||||||
|
|
||||||
|
h += '">'+language.gettext("lastfm_simar")+'</div>' +
|
||||||
|
'<div class="fixed"><i id="hibbert" class="svg-square title-menu invisible">'+
|
||||||
|
'</i></div></div>' +
|
||||||
|
'<div class="fullwidth masonified2" id="artistalbums"></div>';
|
||||||
|
return h;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function findDisplayPanel(element) {
|
||||||
|
var c = element;
|
||||||
|
while (!c.hasClass('nobwobbler')) {
|
||||||
|
c = c.parent();
|
||||||
|
}
|
||||||
|
if (c.hasClass('nobalbum')) {
|
||||||
|
debug.log(medebug,"Opening Album Panel Via Widget");
|
||||||
|
$('#artistalbums').spotifyAlbumThing('handleClick', element);
|
||||||
|
return true;
|
||||||
|
} else if (c.hasClass('nobartist')) {
|
||||||
|
debug.log(medebug,"Opening Artist Panel Via Widget");
|
||||||
|
$('#artistalbums').spotifyArtistThing('handleClick', element);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
debug.error(medebug,"Click On Unknown Element!",element);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return ["musicbrainz"];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
|
||||||
|
debug.trace(medebug, "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var displaying = false;
|
||||||
|
if (artistmeta.spotify === undefined) {
|
||||||
|
artistmeta.spotify = {};
|
||||||
|
}
|
||||||
|
if (artistmeta.spotify.showing === undefined) {
|
||||||
|
artistmeta.spotify.showing = "albums";
|
||||||
|
}
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
self.track.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayData = function() {
|
||||||
|
displaying = true;
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function() {
|
||||||
|
displaying = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.handleClick = function(source, element, event) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,source,"is handling a click event");
|
||||||
|
if (element.hasClass('clickzoomimage')) {
|
||||||
|
imagePopup.create(element, event, element.attr("src"));
|
||||||
|
} else if (element.hasClass('clickspotifywidget')) {
|
||||||
|
findDisplayPanel(element);
|
||||||
|
} else if (element.hasClass('clickchooseposs')) {
|
||||||
|
var poss = element.attr("name");
|
||||||
|
if (poss != artistmeta.spotify.currentposs) {
|
||||||
|
artistmeta.spotify = {
|
||||||
|
currentposs: poss,
|
||||||
|
possibilities: artistmeta.spotify.possibilities,
|
||||||
|
id: artistmeta.spotify.possibilities[poss].id,
|
||||||
|
showing: "albums"
|
||||||
|
}
|
||||||
|
self.artist.force = true;
|
||||||
|
self.artist.populate();
|
||||||
|
}
|
||||||
|
} else if (element.hasClass('clickshowalbums') && artistmeta.spotify.showing != "albums") {
|
||||||
|
$('#artistalbums').spotifyArtistThing('destroy');
|
||||||
|
artistmeta.spotify.showing = "albums";
|
||||||
|
$("#bumhole .bsel").removeClass("bsel");
|
||||||
|
element.addClass("bsel");
|
||||||
|
getAlbums();
|
||||||
|
} else if (element.hasClass('clickshowartists') && artistmeta.spotify.showing != "artists") {
|
||||||
|
$('#artistalbums').spotifyAlbumThing('destroy');
|
||||||
|
artistmeta.spotify.showing = "artists";
|
||||||
|
$("#bumhole .bsel").removeClass("bsel");
|
||||||
|
element.addClass("bsel");
|
||||||
|
getArtists();
|
||||||
|
} else if (element.hasClass('clickaddtolistenlater')) {
|
||||||
|
metaHandlers.addToListenLater(albummeta.spotify.album);
|
||||||
|
} else if (element.hasClass('clickaddtocollection')) {
|
||||||
|
metaHandlers.fromSpotifyData.addAlbumTracksToCollection(albummeta.spotify.album, artistmeta.spotify.artist.name);
|
||||||
|
} else if (element.hasClass('clickstartradio')) {
|
||||||
|
playlist.radioManager.load("artistRadio", 'spotify:artist:'+artistmeta.spotify.id);
|
||||||
|
} else if (element.hasClass('clickstartsingleradio')) {
|
||||||
|
playlist.radioManager.load("singleArtistRadio", artistmeta.name);
|
||||||
|
} else if (element.hasClass('clickstarttrackradio')) {
|
||||||
|
debug.log("SPOTIFY","Starting Track Recommendations With",trackmeta.spotify.id);
|
||||||
|
playlist.radioManager.load("spotiTrackRadio", {seed_tracks: trackmeta.spotify.id, name: trackmeta.spotify.track.name});
|
||||||
|
} else if (element.hasClass('clickstartartistradio')) {
|
||||||
|
debug.log("SPOTIFY","Starting Artist Recommendations With",artistmeta.spotify.id);
|
||||||
|
playlist.radioManager.load("spotiTrackRadio", {seed_artists: artistmeta.spotify.id, name: artistmeta.spotify.artist.name});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getAlbums() {
|
||||||
|
$("#hibbert").makeSpinner();
|
||||||
|
if (artistmeta.spotify.albums === undefined) {
|
||||||
|
spotify.artist.getAlbums(artistmeta.spotify.id, 'album,single', storeAlbums, self.artist.spotifyError, true)
|
||||||
|
} else {
|
||||||
|
doAlbums(artistmeta.spotify.albums);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function getArtists() {
|
||||||
|
$("#hibbert").makeSpinner()
|
||||||
|
if (artistmeta.spotify.related === undefined) {
|
||||||
|
spotify.artist.getRelatedArtists(artistmeta.spotify.id, storeArtists, self.artist.spotifyError, true)
|
||||||
|
} else {
|
||||||
|
doArtists(artistmeta.spotify.related);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeAlbums(data) {
|
||||||
|
artistmeta.spotify.albums = data;
|
||||||
|
doAlbums(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function storeArtists(data) {
|
||||||
|
artistmeta.spotify.related = data;
|
||||||
|
doArtists(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doAlbums(data) {
|
||||||
|
debug.trace(medebug,"DoAlbums",artistmeta.spotify.showing, displaying);
|
||||||
|
if (artistmeta.spotify.showing == "albums" && displaying && data) {
|
||||||
|
debug.trace(medebug,"Doing Albums For Artist",data);
|
||||||
|
$('#artistalbums').spotifyAlbumThing({
|
||||||
|
classes: 'nobwobbler nobalbum tagholder2 selecotron',
|
||||||
|
itemselector: 'nobwobbler',
|
||||||
|
sub: null,
|
||||||
|
showbiogs: false,
|
||||||
|
layoutcallback: function() { $("#hibbert").stopSpinner(); browser.rePoint() },
|
||||||
|
maxwidth: maxwidth,
|
||||||
|
is_plugin: false,
|
||||||
|
imageclass: 'masochist',
|
||||||
|
data: data.items
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doArtists(data) {
|
||||||
|
if (artistmeta.spotify.showing == "artists" && displaying && data) {
|
||||||
|
debug.trace(medebug,"Doing Related Artists",data);
|
||||||
|
$('#artistalbums').spotifyArtistThing({
|
||||||
|
classes: 'nobwobbler nobartist tagholder2',
|
||||||
|
itemselector: 'nobwobbler',
|
||||||
|
sub: null,
|
||||||
|
layoutcallback: function() { $("#hibbert").stopSpinner(); browser.rePoint() },
|
||||||
|
is_plugin: false,
|
||||||
|
imageclass: 'jalopy',
|
||||||
|
maxalbumwidth: maxwidth,
|
||||||
|
data: data.artists
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.track = function() {
|
||||||
|
|
||||||
|
function spotifyResponse(data) {
|
||||||
|
debug.trace(medebug, "Got Spotify Track Data");
|
||||||
|
debug.trace(medebug, data);
|
||||||
|
if (trackmeta.spotify.track === undefined) {
|
||||||
|
trackmeta.spotify.track = data;
|
||||||
|
}
|
||||||
|
if (albummeta.spotify === undefined) {
|
||||||
|
albummeta.spotify = {id: data.album.id};
|
||||||
|
}
|
||||||
|
for(var i in data.artists) {
|
||||||
|
if (data.artists[i].name == artistmeta.name) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"Found Spotify ID for", artistmeta.name);
|
||||||
|
artistmeta.spotify.id = data.artists[i].id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
debug.trace(medebug,"Spotify Data now looks like",artistmeta, albummeta, trackmeta);
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
self.artist.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function gotTrackRecommendations(data) {
|
||||||
|
trackmeta.spotify.recommendations = data;
|
||||||
|
doRecommendations(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
function doRecommendations(data) {
|
||||||
|
$('#helpful_title').html('<div class="textunderline notthere"><h3>'+language.gettext('discover_now', [trackmeta.spotify.track.name])+'</h3></div>');
|
||||||
|
for (var i in data.tracks) {
|
||||||
|
var x = $('<div>', {class: 'arsecandle tagholder4 clickable draggable clicktrack playable notthere', name: data.tracks[i].uri}).appendTo($('#helpful_tracks'));
|
||||||
|
var a = data.tracks[i].album;
|
||||||
|
var img = '';
|
||||||
|
if (a.images && a.images[0]) {
|
||||||
|
img = 'getRemoteImage.php?url='+a.images[0].url
|
||||||
|
for (var j in a.images) {
|
||||||
|
if (a.images[j].width <= maxwidth) {
|
||||||
|
img = 'getRemoteImage.php?url='+a.images[j].url;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
img += '&rompr_resize_size=smallish';
|
||||||
|
} else {
|
||||||
|
img = 'newimages/spotify-icon.png';
|
||||||
|
}
|
||||||
|
x.append('<img class="cheeseandfish" src="'+img+'" /></div>');
|
||||||
|
|
||||||
|
var an = new Array();
|
||||||
|
for (var j in data.tracks[i].artists) {
|
||||||
|
an.push(data.tracks[i].artists[j].name);
|
||||||
|
}
|
||||||
|
|
||||||
|
x.append('<div>'+concatenate_artist_names(an)+'<br />'+data.tracks[i].name+'</div>');
|
||||||
|
}
|
||||||
|
$('#helpful_tracks').imagesLoaded(doBlockLayout);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function doBlockLayout() {
|
||||||
|
debug.shout(medebug,"Track Images Have Loaded");
|
||||||
|
browser.rePoint($('#helpful_tracks'),{ itemSelector: '.arsecandle', columnWidth: '.arsecandle', percentPosition: true});
|
||||||
|
donetheother = true;
|
||||||
|
setDraggable('#helpful_tracks');
|
||||||
|
$('#helpful_title').find('.notthere').removeClass('notthere');
|
||||||
|
$('#helpful_tracks').find('.notthere').removeClass('notthere');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (trackmeta.spotify === undefined || artistmeta.spotify.id === undefined) {
|
||||||
|
if (parent.playlistinfo.file.substring(0,8) !== 'spotify:') {
|
||||||
|
self.track.doBrowserUpdate()
|
||||||
|
self.artist.populate();
|
||||||
|
self.album.populate();
|
||||||
|
} else {
|
||||||
|
if (trackmeta.spotify === undefined) {
|
||||||
|
trackmeta.spotify = {id: parent.playlistinfo.file.substr(14, parent.playlistinfo.file.length) };
|
||||||
|
}
|
||||||
|
spotify.track.getInfo(trackmeta.spotify.id, spotifyResponse, self.track.spotifyError, true);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.artist.populate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
spotifyError: function(data) {
|
||||||
|
debug.warn(medebug, "Spotify Error!", data);
|
||||||
|
data.name = parent.playlistinfo.Title;
|
||||||
|
data.external_urls = {spotify: ''};
|
||||||
|
trackmeta.spotify.track = data;
|
||||||
|
if (albummeta.spotify === undefined) {
|
||||||
|
albummeta.spotify = {};
|
||||||
|
}
|
||||||
|
self.track.doBrowserUpdate()
|
||||||
|
self.artist.populate();
|
||||||
|
},
|
||||||
|
|
||||||
|
spotifyRecError: function(data) {
|
||||||
|
debug.warn(medebug,"Error getting track reccomendations",data);
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
var accepted = false;
|
||||||
|
if (displaying && trackmeta.spotify !== undefined && trackmeta.spotify.track !== undefined) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"track was asked to display");
|
||||||
|
accepted = browser.Update(
|
||||||
|
null,
|
||||||
|
'track',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: trackmeta.spotify.track.name,
|
||||||
|
link: trackmeta.spotify.track.external_urls.spotify,
|
||||||
|
data: getTrackHTML(trackmeta.spotify.track)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (parent.playlistinfo.file.substring(0,8) !== 'spotify:') {
|
||||||
|
browser.Update(null, 'track', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (accepted && !trackmeta.spotify.track.error) {
|
||||||
|
if (trackmeta.spotify.recommendations) {
|
||||||
|
doRecommendations(trackmeta.spotify.recommendations);
|
||||||
|
} else {
|
||||||
|
var params = { limit: 8 }
|
||||||
|
if (prefs.lastfm_country_code) {
|
||||||
|
params.market = prefs.lastfm_country_code;
|
||||||
|
}
|
||||||
|
params.seed_tracks = trackmeta.spotify.id;
|
||||||
|
spotify.recommendations.getRecommendations(params, gotTrackRecommendations, self.track.spotifyRecError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
|
this.album = function() {
|
||||||
|
|
||||||
|
function spotifyResponse(data) {
|
||||||
|
debug.trace(medebug, "Got Spotify Album Data");
|
||||||
|
debug.trace(medebug, data);
|
||||||
|
albummeta.spotify.album = data;
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (albummeta.spotify === undefined || albummeta.spotify.album === undefined ) {
|
||||||
|
if (parent.playlistinfo.file.substring(0,8) !== 'spotify:') {
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
} else {
|
||||||
|
spotify.album.getInfo(albummeta.spotify.id, spotifyResponse, self.album.spotifyError, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
spotifyError: function(data) {
|
||||||
|
debug.error(medebug, "Spotify Error!");
|
||||||
|
data.name = parent.playlistinfo.Album;
|
||||||
|
data.external_urls = {spotify: ''};
|
||||||
|
albummeta.spotify.album = data;
|
||||||
|
self.album.doBrowserUpdate();
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && albummeta.spotify !== undefined && albummeta.spotify.album !== undefined) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"album was asked to display");
|
||||||
|
var accepted = browser.Update(
|
||||||
|
null,
|
||||||
|
'album',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: albummeta.spotify.album.name,
|
||||||
|
link: albummeta.spotify.album.external_urls.spotify,
|
||||||
|
data: getAlbumHTML(albummeta.spotify.album)
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else if (parent.playlistinfo.file.substring(0,8) !== 'spotify:') {
|
||||||
|
browser.Update(null, 'album', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
infobar.markCurrentTrack();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
|
this.artist = function() {
|
||||||
|
|
||||||
|
var triedWithoutBrackets = 0;
|
||||||
|
var retries = 10;
|
||||||
|
var searchingfor = artistmeta.name;
|
||||||
|
|
||||||
|
function spotifyResponse(data) {
|
||||||
|
debug.trace(medebug, "Got Spotify Artist Data");
|
||||||
|
debug.trace(medebug, data);
|
||||||
|
artistmeta.spotify.artist = data;
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
self.album.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
function search(aname) {
|
||||||
|
if (parent.playlistinfo.type == "stream" && artistmeta.name == "" && trackmeta.name == "") {
|
||||||
|
debug.shout(medebug, "Searching Spotify for artist",albummeta.name)
|
||||||
|
spotify.artist.search(albummeta.name, searchResponse, searchFail, true);
|
||||||
|
} else {
|
||||||
|
debug.shout(medebug, "Searching Spotify for artist",aname)
|
||||||
|
spotify.artist.search(aname, searchResponse, searchFail, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchResponse(data) {
|
||||||
|
debug.trace(medebug,"Got Spotify Search Data",data);
|
||||||
|
var match = searchingfor.toLowerCase();
|
||||||
|
artistmeta.spotify.possibilities = new Array();
|
||||||
|
for (var i in data.artists.items) {
|
||||||
|
if (data.artists.items[i].name.toLowerCase() == match) {
|
||||||
|
artistmeta.spotify.possibilities.push({
|
||||||
|
name: data.artists.items[i].name,
|
||||||
|
id: data.artists.items[i].id,
|
||||||
|
image: (data.artists.items[i].images &&
|
||||||
|
data.artists.items[i].images.length > 0) ?
|
||||||
|
data.artists.items[i].images[data.artists.items[i].images.length-1].url : null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (artistmeta.spotify.possibilities.length == 0 && data.artists.items.length == 1) {
|
||||||
|
// only one match returned, it wasn't an exact match, but use it anyway
|
||||||
|
artistmeta.spotify.possibilities.push({
|
||||||
|
name: data.artists.items[0].name,
|
||||||
|
id: data.artists.items[0].id,
|
||||||
|
image: (data.artists.items[0].images &&
|
||||||
|
data.artists.items[0].images.length > 0) ?
|
||||||
|
data.artists.items[0].images[data.artists.items[0].images.length-1].url : null
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if (artistmeta.spotify.possibilities.length > 0) {
|
||||||
|
artistmeta.spotify.currentposs = 0;
|
||||||
|
artistmeta.spotify.id = artistmeta.spotify.possibilities[0].id;
|
||||||
|
artistmeta.spotify.showing = "albums";
|
||||||
|
}
|
||||||
|
if (artistmeta.spotify.id === undefined) {
|
||||||
|
searchFail();
|
||||||
|
} else {
|
||||||
|
self.artist.populate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function searchFail() {
|
||||||
|
debug.trace("SPOTIFY PLUGIN","Couldn't find anything for",artistmeta.name);
|
||||||
|
var test;
|
||||||
|
switch (triedWithoutBrackets) {
|
||||||
|
case 0:
|
||||||
|
triedWithoutBrackets = 1;
|
||||||
|
test = artistmeta.name.replace(/ \(+.+?\)+$/, '');
|
||||||
|
if (test != artistmeta.name) {
|
||||||
|
searchingfor = test;
|
||||||
|
debug.trace("SPOTIFY PLUGIN","Searching instead for",test);
|
||||||
|
search(test);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Fall Through
|
||||||
|
|
||||||
|
case 1:
|
||||||
|
triedWithoutBrackets = 2;
|
||||||
|
test = artistmeta.name.split(/ & | and /)[0];
|
||||||
|
if (test != artistmeta.name) {
|
||||||
|
searchingfor = test;
|
||||||
|
debug.trace("SPOTIFY PLUGIN","Searching instead for",test);
|
||||||
|
search(test);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Fall Through
|
||||||
|
|
||||||
|
default:
|
||||||
|
artistmeta.spotify = { artist: { error: '<h3 align="center">'+
|
||||||
|
language.gettext("label_noartistinfo")+
|
||||||
|
'</h3>',
|
||||||
|
name: artistmeta.name,
|
||||||
|
external_urls: { spotify: '' }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
force: false,
|
||||||
|
|
||||||
|
populate: function() {
|
||||||
|
if (artistmeta.spotify.id === undefined) {
|
||||||
|
search(artistmeta.name);
|
||||||
|
} else {
|
||||||
|
if (artistmeta.spotify.artist === undefined) {
|
||||||
|
spotify.artist.getInfo(artistmeta.spotify.id, spotifyResponse, self.artist.spotifyError, true);
|
||||||
|
} else {
|
||||||
|
self.album.populate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
spotifyError: function(data) {
|
||||||
|
debug.error(medebug, "Spotify Error!");
|
||||||
|
data.external_urls = {spotify: ''};
|
||||||
|
data.name = artistmeta.name;
|
||||||
|
artistmeta.spotify.artist = data;
|
||||||
|
self.artist.doBrowserUpdate();
|
||||||
|
self.album.populate();
|
||||||
|
},
|
||||||
|
|
||||||
|
tryForAllmusicBio: function() {
|
||||||
|
if (typeof artistmeta.allmusic == 'undefined' || typeof artistmeta.allmusic.artistlink === 'undefined') {
|
||||||
|
debug.shout(medebug,"Allmusic artist link not back yet");
|
||||||
|
retries--;
|
||||||
|
if (retries > 0) {
|
||||||
|
setTimeout(self.artist.tryForAllmusicBio, 2000);
|
||||||
|
} else {
|
||||||
|
debug.shout(medebug,"Artist giving up waiting for musicbrainz");
|
||||||
|
}
|
||||||
|
} else if (artistmeta.allmusic.artistlink === null) {
|
||||||
|
debug.shout(medebug,"No Allmusic artist bio link found");
|
||||||
|
} else {
|
||||||
|
debug.shout(medebug,"Getting allmusic bio from",artistmeta.allmusic.artistlink);
|
||||||
|
$.post('browser/backends/getambio.php', {url: artistmeta.allmusic.artistlink})
|
||||||
|
.done( function(data) {
|
||||||
|
debug.log(medebug,"Got Allmusic Bio");
|
||||||
|
if (displaying) $("#artistbio").html(data);
|
||||||
|
})
|
||||||
|
.fail( function() {
|
||||||
|
debug.log(medebug,"Didn't Get Allmusic Bio");
|
||||||
|
if (displaying) $("#artistbio").html("");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && artistmeta.spotify !== undefined && artistmeta.spotify.artist !== undefined) {
|
||||||
|
debug.trace(medebug,parent.nowplayingindex,"artist was asked to display");
|
||||||
|
var accepted = browser.Update(
|
||||||
|
null,
|
||||||
|
'artist',
|
||||||
|
me,
|
||||||
|
parent.nowplayingindex,
|
||||||
|
{ name: artistmeta.spotify.artist.name,
|
||||||
|
link: artistmeta.spotify.artist.external_urls.spotify,
|
||||||
|
data: getArtistHTML(artistmeta.spotify.artist, parent, artistmeta)
|
||||||
|
},
|
||||||
|
false,
|
||||||
|
self.artist.force
|
||||||
|
);
|
||||||
|
if (accepted && artistmeta.spotify.artist.error == undefined) {
|
||||||
|
debug.trace(medebug,"Update was accepted by browser");
|
||||||
|
self.artist.tryForAllmusicBio();
|
||||||
|
if (artistmeta.spotify.showing == "albums") {
|
||||||
|
getAlbums();
|
||||||
|
} else {
|
||||||
|
getArtists();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("spotify", info_spotify, "icon-spotify-circled", "button_infospotify");
|
|
@ -0,0 +1,125 @@
|
||||||
|
var info_videos = function() {
|
||||||
|
|
||||||
|
var me = "videos";
|
||||||
|
|
||||||
|
return {
|
||||||
|
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return ['discogs'];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
|
||||||
|
debug.trace("VIDEOS PLUGIN", "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var displaying = false;
|
||||||
|
var ids = [];
|
||||||
|
var retrytimer;
|
||||||
|
|
||||||
|
function mungeDiscogsData(videos) {
|
||||||
|
debug.trace("VIDEOS PLUGIN","Doing Videos From Discogs Data",videos);
|
||||||
|
for (var i in videos) {
|
||||||
|
var u = videos[i].uri;
|
||||||
|
if (videos[i].embed == true && u.match(/youtube\.com/)) {
|
||||||
|
var d = u.match(/\/\/www\.youtube\.com\/watch\?v=(.+)$/);
|
||||||
|
if (d && d[1] && ids.indexOf(d[1]) == -1) {
|
||||||
|
ids.push(d[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doVideos() {
|
||||||
|
var html = '';
|
||||||
|
if (ids.length == 0) {
|
||||||
|
return '<h3 align="center">No Videos Found</h3>';
|
||||||
|
}
|
||||||
|
for (var i in ids) {
|
||||||
|
html += '<div class="video"><iframe class="youtubevid" src="http://www.youtube.com/embed/'+ids[i]+'"></iframe></div>';
|
||||||
|
}
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getVideosHtml() {
|
||||||
|
if (albummeta.discogs.album.master && parent.playlistinfo.type != 'stream') {
|
||||||
|
debug.debug('VIDEOS', 'Doing videos from album master');
|
||||||
|
mungeDiscogsData(albummeta.discogs.album.master.data.videos);
|
||||||
|
}
|
||||||
|
if (albummeta.discogs.album.release && parent.playlistinfo.type != 'stream') {
|
||||||
|
debug.debug('VIDEOS', 'Doing videos from album release');
|
||||||
|
mungeDiscogsData(albummeta.discogs.album.release.data.videos);
|
||||||
|
}
|
||||||
|
if (trackmeta.discogs.track.master) {
|
||||||
|
debug.debug('VIDEOS', 'Doing videos from track master');
|
||||||
|
mungeDiscogsData(trackmeta.discogs.track.master.data.videos);
|
||||||
|
}
|
||||||
|
if (trackmeta.discogs.track.release) {
|
||||||
|
debug.debug('VIDEOS', 'Doing videos from track release');
|
||||||
|
mungeDiscogsData(trackmeta.discogs.track.release.data.videos);
|
||||||
|
}
|
||||||
|
return doVideos();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
self.track.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayData = function() {
|
||||||
|
displaying = true;
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
browser.Update(null, 'album', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
browser.Update(null, 'artist', me, parent.nowplayingindex, { name: "",
|
||||||
|
link: "",
|
||||||
|
data: null
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function() {
|
||||||
|
displaying = false;
|
||||||
|
clearTimeout(retrytimer);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.track = function() {
|
||||||
|
return {
|
||||||
|
populate: function() {
|
||||||
|
debug.trace('VIDEOS','album master', albummeta.discogs.album.master);
|
||||||
|
debug.trace('VIDEOS','track master', trackmeta.discogs.track.master);
|
||||||
|
debug.trace('VIDEOS','album error', albummeta.discogs.album.error);
|
||||||
|
debug.trace('VIDEOS','track error', trackmeta.discogs.track.error);
|
||||||
|
if ((trackmeta.discogs.track.master && albummeta.discogs.album.master) ||
|
||||||
|
(trackmeta.discogs.track.master && albummeta.discogs.album.error) ||
|
||||||
|
(trackmeta.discogs.track.error && albummeta.discogs.album.master) ||
|
||||||
|
(trackmeta.discogs.track.error && albummeta.discogs.album.error)) {
|
||||||
|
self.track.doBrowserUpdate();
|
||||||
|
} else {
|
||||||
|
debug.trace("VIDEOS PLUGIN",parent.nowplayingindex,"No data yet, trying again in 1 second");
|
||||||
|
retrytimer = setTimeout(self.track.populate, 2000);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
doBrowserUpdate: function() {
|
||||||
|
if (displaying && albummeta.discogs.album !== undefined && trackmeta.discogs.track !== undefined &&
|
||||||
|
(albummeta.discogs.album.error !== undefined || albummeta.discogs.album.master !== undefined) &&
|
||||||
|
(trackmeta.discogs.track.error !== undefined || trackmeta.discogs.track.master !== undefined)) {
|
||||||
|
debug.mark("VIDEOS PLUGIN",parent.nowplayingindex,"track was asked to display");
|
||||||
|
browser.Update(null, 'track', me, parent.nowplayingindex, { name: artistmeta.name+' / '+trackmeta.name,
|
||||||
|
link: "",
|
||||||
|
data: getVideosHtml()
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("videos", info_videos, "icon-video", "button_videos");
|
|
@ -0,0 +1,189 @@
|
||||||
|
var info_ratings = function() {
|
||||||
|
|
||||||
|
var me = "ratings";
|
||||||
|
var trackFinder = new faveFinder(false);
|
||||||
|
var update_wishlist = false;
|
||||||
|
|
||||||
|
return {
|
||||||
|
getRequirements: function(parent) {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
|
||||||
|
collection: function(parent, artistmeta, albummeta, trackmeta) {
|
||||||
|
|
||||||
|
debug.log("RATINGS PLUGIN", "Creating data collection");
|
||||||
|
|
||||||
|
var self = this;
|
||||||
|
var displaying = false;
|
||||||
|
var lfmupdates = null;
|
||||||
|
|
||||||
|
function doThingsWithData() {
|
||||||
|
if (parent.isCurrentTrack() && trackmeta.usermeta) {
|
||||||
|
if (prefs.sync_lastfm_playcounts && lfmupdates !== null) {
|
||||||
|
$.each(lfmupdates, function(i, v) {
|
||||||
|
switch (i) {
|
||||||
|
case 'Playcount':
|
||||||
|
if (parseInt(trackmeta.usermeta[i]) < parseInt(v)) {
|
||||||
|
debug.log("RATINGS PLUGIN","Update :",i,"is now",v);
|
||||||
|
trackmeta.usermeta[i] = v;
|
||||||
|
} else {
|
||||||
|
debug.log("RATINGS PLUGIN","Not using update for",i,"as",v,"is less than",trackmeta.usermeta[i]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
var playtext = '';
|
||||||
|
if (trackmeta.usermeta.Playcount && trackmeta.usermeta.Playcount > 0) {
|
||||||
|
playtext = '<span class="playspan"><b>PLAYS </b> '+trackmeta.usermeta.Playcount+'</span>';
|
||||||
|
if (uiHelper.showTagButton()) {
|
||||||
|
$("#playcount").html(playtext);
|
||||||
|
}
|
||||||
|
if (typeof charts != 'undefined') {
|
||||||
|
charts.reloadAll();
|
||||||
|
}
|
||||||
|
if (typeof recentlyPlayed != 'undefined') {
|
||||||
|
recentlyPlayed.reloadAll();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$("#playcount").empty();
|
||||||
|
}
|
||||||
|
displayRating("#ratingimage", trackmeta.usermeta.Rating);
|
||||||
|
if (uiHelper.showTagButton()) {
|
||||||
|
$("#dbtags").html('<span><b>'+language.gettext("musicbrainz_tags")+
|
||||||
|
'</b></span><i class="icon-plus clickicon playlisticon" '+
|
||||||
|
'onclick="tagAdder.show(event)" style="margin-left:2px;margin-top:0px;margin-right:1em;"></i>');
|
||||||
|
} else {
|
||||||
|
$('#dbtags').html(playtext);
|
||||||
|
if (trackmeta.usermeta.Tags.length > 0) {
|
||||||
|
debug.log('INFOBAR', 'Tags are',trackmeta.usermeta.Tags.length);
|
||||||
|
$('#dbtags').append('<span><b>'+language.gettext("musicbrainz_tags")+' </b></span>');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for(var i = 0; i < trackmeta.usermeta.Tags.length; i++) {
|
||||||
|
$("#dbtags").append('<span class="tag">'+trackmeta.usermeta.Tags[i]+
|
||||||
|
'<i class="icon-cancel-circled clickicon tagremover playlisticon" style="display:none"></i></span> ');
|
||||||
|
}
|
||||||
|
layoutProcessor.adjustLayout();
|
||||||
|
}
|
||||||
|
// Make sure the browser updates the file info display
|
||||||
|
browser.reDo(parent.nowplayingindex, 'file');
|
||||||
|
}
|
||||||
|
|
||||||
|
function hideTheInputs() {
|
||||||
|
if (parent.isCurrentTrack()) {
|
||||||
|
displayRating("#ratingimage", false);
|
||||||
|
$("#dbtags").html('');
|
||||||
|
$("#playcount").html('');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setSuccess(rdata) {
|
||||||
|
debug.log("RATING PLUGIN","Success");
|
||||||
|
if (rdata) {
|
||||||
|
trackmeta.usermeta = rdata.metadata;
|
||||||
|
doThingsWithData();
|
||||||
|
collectionHelper.updateCollectionDisplay(rdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function findSuccess(rdata) {
|
||||||
|
debug.log("RATING PLUGIN","Success");
|
||||||
|
if (rdata) {
|
||||||
|
trackmeta.usermeta = rdata.metadata;
|
||||||
|
doThingsWithData();
|
||||||
|
collectionHelper.updateCollectionDisplay(rdata);
|
||||||
|
if (!rdata.hasOwnProperty('addedtracks')) {
|
||||||
|
infobar.error(language.gettext('error_trackexists'));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (update_wishlist && typeof(wishlistViewer) != 'undefined') {
|
||||||
|
wishlistViewer.update();
|
||||||
|
}
|
||||||
|
update_wishlist = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function setFail(rdata) {
|
||||||
|
debug.warn("RATING PLUGIN","Failure");
|
||||||
|
// infobar.error("Failed! Have you read the Wiki?");
|
||||||
|
doThingsWithData();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.displayData = function() {
|
||||||
|
debug.error("RATINGS PLUGIN", "Was asked to display data!");
|
||||||
|
}
|
||||||
|
|
||||||
|
this.stopDisplaying = function() {
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateMeta = function(updates) {
|
||||||
|
lfmupdates = updates;
|
||||||
|
doThingsWithData();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.refresh = function() {
|
||||||
|
trackmeta.usermeta = undefined;
|
||||||
|
self.populate();
|
||||||
|
}
|
||||||
|
|
||||||
|
this.populate = function() {
|
||||||
|
if (trackmeta.usermeta === undefined) {
|
||||||
|
metaHandlers.fromPlaylistInfo.getMeta(
|
||||||
|
parent.playlistinfo,
|
||||||
|
function(data) {
|
||||||
|
trackmeta.usermeta = data;
|
||||||
|
doThingsWithData();
|
||||||
|
},
|
||||||
|
function(data) {
|
||||||
|
trackmeta.usermeta = null;
|
||||||
|
hideTheInputs();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
debug.mark("RATINGS PLUGIN",parent.nowplayingindex,"is already populated");
|
||||||
|
doThingsWithData();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setMeta = function(action, type, value) {
|
||||||
|
debug.log("RATINGS PLUGIN",parent.nowplayingindex,"Doing",action,type,value);
|
||||||
|
if (parent.playlistinfo.type == 'stream') {
|
||||||
|
infobar.notify(language.gettext('label_searching'));
|
||||||
|
trackFinder.findThisOne(metaHandlers.fromPlaylistInfo.mapData(parent.playlistinfo, action, [{attribute: type, value: value}]),
|
||||||
|
self.updateDatabase
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
metaHandlers.fromPlaylistInfo.setMeta(parent.playlistinfo, action, [{attribute: type, value: value}], setSuccess, setFail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.setAlbumMBID = function(mbid) {
|
||||||
|
debug.log("RATINGS PLUGIN",parent.nowplayingindex," Updating backend album MBID");
|
||||||
|
metaHandlers.fromPlaylistInfo.setMeta(parent.playlistinfo, 'setalbummbid', mbid, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getMeta = function(meta) {
|
||||||
|
if (trackmeta.usermeta) {
|
||||||
|
if (trackmeta.usermeta[meta]) {
|
||||||
|
return trackmeta.usermeta[meta];
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.updateDatabase = function(data) {
|
||||||
|
debug.log("RATINGS","Update Database Function Called",data);
|
||||||
|
if (!data.uri) {
|
||||||
|
infobar.notify(language.gettext("label_addtow"));
|
||||||
|
update_wishlist = true;
|
||||||
|
}
|
||||||
|
dbQueue.request([data], findSuccess, setFail);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}();
|
||||||
|
|
||||||
|
nowplaying.registerPlugin("ratings", info_ratings, null, null);
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
|
||||||
|
<head>
|
||||||
|
<title>RompЯ</title>
|
||||||
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=0" />
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes" />
|
||||||
|
<script type="text/javascript" src="jquery/jquery-3.3.1.min.js"></script>
|
||||||
|
<script type="text/javascript" src="ui/functions.js"></script>
|
||||||
|
<script language="javascript">
|
||||||
|
$(document).ready(function() {
|
||||||
|
var ws = getWindowSize();
|
||||||
|
if ((ws.x < 600 && ws.x < ws.y) || (ws.x < 800 && ws.x > ws.y)) {
|
||||||
|
setCookie('skin','phone',3650);
|
||||||
|
} else if ((ws.x < 1024 && ws.x < ws.y) || (ws.x < 600 && ws.x > ws.y)) {
|
||||||
|
setCookie('skin','tablet',3650);
|
||||||
|
} else {
|
||||||
|
setCookie('skin','desktop',3650);
|
||||||
|
}
|
||||||
|
location.reload(true);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,362 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once ("includes/spotifyauth.php");
|
||||||
|
|
||||||
|
$numtracks = 0;
|
||||||
|
$numalbums = 0;
|
||||||
|
$numartists = 0;
|
||||||
|
$totaltime = 0;
|
||||||
|
$count = 1;
|
||||||
|
$divtype = "album1";
|
||||||
|
$dbterms = array( 'tags' => null, 'rating' => null );
|
||||||
|
$trackbytrack = false;
|
||||||
|
|
||||||
|
define('ROMPR_MIN_TRACKS_TO_DETERMINE_COMPILATION', 3);
|
||||||
|
define('ROMPR_MIN_NOT_COMPILATION_THRESHOLD', 0.6);
|
||||||
|
|
||||||
|
class musicCollection {
|
||||||
|
|
||||||
|
public function __construct() {
|
||||||
|
$this->albums = array();
|
||||||
|
$this->filter_duplicates = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newTrack(&$filedata) {
|
||||||
|
|
||||||
|
global $trackbytrack, $doing_search;
|
||||||
|
|
||||||
|
if ($doing_search) {
|
||||||
|
// If we're doing a search, we check to see if that track is in the database
|
||||||
|
// because the user might have set the AlbumArtist to something different
|
||||||
|
$filedata = array_replace($filedata, get_extra_track_info($filedata));
|
||||||
|
}
|
||||||
|
|
||||||
|
$track = new track($filedata);
|
||||||
|
if ($trackbytrack && $filedata['AlbumArtist'] && $filedata['Disc'] !== null) {
|
||||||
|
do_track_by_track( $track );
|
||||||
|
} else {
|
||||||
|
$albumkey = md5($track->tags['folder'].strtolower($track->tags['Album']).strtolower($track->get_sort_artist(true)));
|
||||||
|
if (array_key_exists($albumkey, $this->albums)) {
|
||||||
|
if (!$this->filter_duplicates || !$this->albums[$albumkey]->checkForDuplicate($track)) {
|
||||||
|
$this->albums[$albumkey]->newTrack($track);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$this->albums[$albumkey] = new album($track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllTracks($cmd) {
|
||||||
|
$tracks = array();
|
||||||
|
foreach($this->albums as $album) {
|
||||||
|
$tracks = array_merge($album->getAllTracks($cmd), $tracks);
|
||||||
|
}
|
||||||
|
return $tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tracks_to_database() {
|
||||||
|
// Fluch the previous albumobj from track_by_track
|
||||||
|
do_track_by_track(null);
|
||||||
|
foreach ($this->albums as $album) {
|
||||||
|
$album->sortTracks();
|
||||||
|
$album->check_database();
|
||||||
|
}
|
||||||
|
$this->albums = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_albumartist_by_folder($f) {
|
||||||
|
foreach ($this->albums as $album) {
|
||||||
|
if ($album->folder == $f) {
|
||||||
|
logger::trace("COLLECTION", " Found albumartist by folder",$album->artist);
|
||||||
|
return $album->artist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filter_duplicate_tracks() {
|
||||||
|
$this->filter_duplicates = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function tracks_as_array() {
|
||||||
|
$results = array();
|
||||||
|
foreach($this->albums as $album) {
|
||||||
|
logger::log("COLLECTION", "Doing Album",$album->name);
|
||||||
|
$album->sortTracks();
|
||||||
|
foreach($album->tracks as $trackobj) {
|
||||||
|
$track = array(
|
||||||
|
"uri" => $trackobj->tags['file'],
|
||||||
|
"album" => $album->name,
|
||||||
|
"title" => $trackobj->tags['Title'],
|
||||||
|
"artist" => $trackobj->get_artist_string(),
|
||||||
|
"albumartist" => $album->artist,
|
||||||
|
"trackno" => $trackobj->tags['Track'],
|
||||||
|
"disc" => $trackobj->tags['Disc'],
|
||||||
|
"albumuri" => $album->uri,
|
||||||
|
"image" => $album->getImage('asdownloaded'),
|
||||||
|
"duration" => $trackobj->tags['Time'],
|
||||||
|
"date" => $album->datestamp
|
||||||
|
);
|
||||||
|
logger::log("COLLECTION", "Title - ".$trackobj->tags['Title']);
|
||||||
|
// A lot of code that depends on this was written to handle mopidy model search results.
|
||||||
|
// The above is not mopidy model, so friggicate it into just such a thing
|
||||||
|
$d = getDomain($track['uri']);
|
||||||
|
if (!array_key_exists($d, $results)) {
|
||||||
|
logger::log("COLLECTION", "Creating Results Set For ".$d);
|
||||||
|
$results[$d] = array(
|
||||||
|
"tracks" => array(),
|
||||||
|
"uri" => $d.':bodgehack'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
array_push($results[$d]['tracks'], $track);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $results;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class album {
|
||||||
|
|
||||||
|
public function __construct(&$track) {
|
||||||
|
global $numalbums;
|
||||||
|
$numalbums++;
|
||||||
|
$this->tracks = array($track);
|
||||||
|
// Sets album artist to composer (if set and required) or albumartist but NOT trackartist
|
||||||
|
// therefore may still be null at this point.
|
||||||
|
$this->artist = $track->get_sort_artist(true);
|
||||||
|
$this->name = trim($track->tags['Album']);
|
||||||
|
$this->folder = $track->tags['folder'];
|
||||||
|
$this->musicbrainz_albumid = $track->tags['MUSICBRAINZ_ALBUMID'];
|
||||||
|
$this->datestamp = $track->tags['Date'];
|
||||||
|
$this->uri = $track->tags['X-AlbumUri'];
|
||||||
|
$this->numOfDiscs = $track->tags['Disc'];
|
||||||
|
$this->image = $track->tags['X-AlbumImage'];
|
||||||
|
$this->key = $track->tags['ImgKey'];
|
||||||
|
$this->numOfDiscs = $track->tags['Disc'];
|
||||||
|
$this->numOfTrackOnes = $track->tags['Track'] == 1 ? 1 : 0;
|
||||||
|
$this->domain = $track->tags['domain'];
|
||||||
|
$this->albumartistindex = null;
|
||||||
|
$this->albumindex = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function newTrack(&$track) {
|
||||||
|
$this->tracks[] = $track;
|
||||||
|
if ($this->artist == null) {
|
||||||
|
$this->artist = $track->get_sort_artist(true);
|
||||||
|
}
|
||||||
|
if ($this->image == null) {
|
||||||
|
$this->image = $track->tags['X-AlbumImage'];
|
||||||
|
}
|
||||||
|
if ($this->datestamp == null) {
|
||||||
|
$this->datestamp = $track->tags['Date'];
|
||||||
|
}
|
||||||
|
if ($this->musicbrainz_albumid == '') {
|
||||||
|
$this->musicbrainz_albumid = $track->tags['MUSICBRAINZ_ALBUMID'];
|
||||||
|
}
|
||||||
|
if ($track->tags['Disc'] !== null && $this->numOfDiscs < $track->tags['Disc']) {
|
||||||
|
$this->numOfDiscs = $track->tags['Disc'];
|
||||||
|
}
|
||||||
|
if ($track->tags['Track'] == 1) {
|
||||||
|
$this->numOfTrackOnes++;
|
||||||
|
}
|
||||||
|
if ($this->uri == null) {
|
||||||
|
$this->uri = $track->tags['X-AlbumUri'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function check_database() {
|
||||||
|
if ($this->albumartistindex == null) {
|
||||||
|
$this->albumartistindex = check_artist($this->artist);
|
||||||
|
}
|
||||||
|
if ($this->albumindex == null) {
|
||||||
|
$album = array(
|
||||||
|
'album' => $this->name,
|
||||||
|
'albumai' => $this->albumartistindex,
|
||||||
|
'albumuri' => $this->uri,
|
||||||
|
'image' => $this->getImage('small'),
|
||||||
|
'date' => $this->getDate(),
|
||||||
|
'searched' => "0",
|
||||||
|
'imagekey' => $this->getKey(),
|
||||||
|
'ambid' => $this->musicbrainz_albumid,
|
||||||
|
'domain' => $this->domain
|
||||||
|
);
|
||||||
|
$this->albumindex = check_album($album);
|
||||||
|
}
|
||||||
|
foreach ($this->tracks as $trackobj) {
|
||||||
|
check_and_update_track($trackobj, $this->albumindex, $this->albumartistindex, $this->artist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getKey() {
|
||||||
|
return $this->key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getImage($size) {
|
||||||
|
$albumimage = new baseAlbumImage(array(
|
||||||
|
'baseimage' => ($this->image) ? $this->image : '',
|
||||||
|
'artist' => artist_for_image($this->tracks[0]->tags['type'], $this->artist),
|
||||||
|
'album' => $this->name
|
||||||
|
));
|
||||||
|
$albumimage->check_image($this->domain, $this->tracks[0]->tags['type']);
|
||||||
|
$images = $albumimage->get_images();
|
||||||
|
$this->key = $albumimage->get_image_key();
|
||||||
|
return $images[$size];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function trackCount() {
|
||||||
|
return count($this->tracks);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDate() {
|
||||||
|
return getYear($this->datestamp);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getAllTracks($cmd) {
|
||||||
|
$tracks = array();
|
||||||
|
foreach ($this->tracks as $track) {
|
||||||
|
if (preg_match('/:track:/', $track->tags['file'])) {
|
||||||
|
$tracks[] = $cmd.' "'.format_for_mpd($track->tags['file']).'"';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $tracks;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function sortTracks($always = false) {
|
||||||
|
|
||||||
|
// NB. BLOODY WELL CALL THIS FUNCTION
|
||||||
|
// Unless you're so sure you know how all this works and you really don't need it.
|
||||||
|
// Collection updates might be one such area but if you're not sure CALL IT ANYWAY and see what happens.
|
||||||
|
|
||||||
|
// Some Mopidy backends don't send disc numbers. If we're using the sql backend
|
||||||
|
// we don't really need to pre-sort tracks because we can do it on the fly.
|
||||||
|
// However, when there are no disc numbers multi-disc albums don't sort properly.
|
||||||
|
// Hence we do a little check that we have have the same number of 'Track 1's
|
||||||
|
// as discs and only do the sort if they're not the same. This'll also
|
||||||
|
// sort out badly tagged local files. It's essential that disc numbers are set
|
||||||
|
// because the database will not find the tracks otherwise.
|
||||||
|
|
||||||
|
// Also here, because ths gets called always, we try to set our albumartist
|
||||||
|
// to something sensible. So far it has been set to Composer tags if required by the
|
||||||
|
// user, or to the AlbumArtist setting, which will be null if no AlbumArtist tag is present -
|
||||||
|
// as is the case with many mopidy backends
|
||||||
|
|
||||||
|
if ($this->artist == null) {
|
||||||
|
logger::mark("COLLECTION", "Finding AlbumArtist for album ".$this->name);
|
||||||
|
if (count($this->tracks) < ROMPR_MIN_TRACKS_TO_DETERMINE_COMPILATION) {
|
||||||
|
logger::log("COLLECTION", " Album ".$this->name." has too few tracks to determine album artist");
|
||||||
|
$this->decideOnArtist($this->tracks[0]->get_sort_artist());
|
||||||
|
} else {
|
||||||
|
$artists = array();
|
||||||
|
foreach ($this->tracks as $track) {
|
||||||
|
$a = $track->get_sort_artist();
|
||||||
|
if (!array_key_exists($a, $artists)) {
|
||||||
|
$artists[$a] = 0;
|
||||||
|
}
|
||||||
|
$artists[$a]++;
|
||||||
|
}
|
||||||
|
$q = array_flip($artists);
|
||||||
|
rsort($q);
|
||||||
|
$candidate_artist = $q[0];
|
||||||
|
$fraction = $artists[$candidate_artist]/count($this->tracks);
|
||||||
|
logger::log("COLLECTION", " Artist ".$candidate_artist." has ".$artists[$candidate_artist]." tracks out of ".count($this->tracks));
|
||||||
|
if ($fraction > ROMPR_MIN_NOT_COMPILATION_THRESHOLD) {
|
||||||
|
logger::log("COLLECTION", " ... which is good enough. Album ".$this->name." is by ".$candidate_artist);
|
||||||
|
$this->artist = $candidate_artist;
|
||||||
|
} else {
|
||||||
|
logger::log("COLLECTION", " ... which is not enough");
|
||||||
|
$this->decideOnArtist("Various Artists");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->tracks as $track) {
|
||||||
|
$track->tags['AlbumArtist'] = $this->artist;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($always == false && $this->numOfDiscs > 0 && ($this->numOfTrackOnes <= 1 || $this->numOfTrackOnes == $this->numOfDiscs)) {
|
||||||
|
return $this->numOfDiscs;
|
||||||
|
}
|
||||||
|
|
||||||
|
$discs = array();
|
||||||
|
$number = 1;
|
||||||
|
foreach ($this->tracks as $ob) {
|
||||||
|
if ($ob->tags['Track'] !== '') {
|
||||||
|
$track_no = intval($ob->tags['Track']);
|
||||||
|
} else {
|
||||||
|
$track_no = $number;
|
||||||
|
}
|
||||||
|
# Just in case we have a multiple disc album with no disc number tags
|
||||||
|
$discno = intval($ob->tags['Disc']);
|
||||||
|
if ($discno == '' || $discno == null || $discno == 0) {
|
||||||
|
$discno = 1;
|
||||||
|
}
|
||||||
|
if (!array_key_exists($discno, $discs)) {
|
||||||
|
$discs[$discno] = array();
|
||||||
|
}
|
||||||
|
while(array_key_exists($track_no, $discs[$discno])) {
|
||||||
|
$discno++;
|
||||||
|
if (!array_key_exists($discno, $discs)) {
|
||||||
|
$discs[$discno] = array();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$discs[$discno][$track_no] = $ob;
|
||||||
|
$ob->updateTrackInfo(array('Disc' => $discno));
|
||||||
|
$number++;
|
||||||
|
}
|
||||||
|
$numdiscs = count($discs);
|
||||||
|
|
||||||
|
$this->tracks = array();
|
||||||
|
ksort($discs, SORT_NUMERIC);
|
||||||
|
foreach ($discs as $disc) {
|
||||||
|
ksort($disc, SORT_NUMERIC);
|
||||||
|
$this->tracks = array_merge($this->tracks, $disc);
|
||||||
|
}
|
||||||
|
$this->numOfDiscs = $numdiscs;
|
||||||
|
|
||||||
|
return $numdiscs;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function checkForDuplicate($t) {
|
||||||
|
foreach ($this->tracks as $track) {
|
||||||
|
if ($t->tags['file'] == $track->tags['file']) {
|
||||||
|
logger::trace("COLLECTION", "Filtering Duplicate Track ".$t->tags['file']);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decideOnArtist($candidate) {
|
||||||
|
if ($this->artist == null) {
|
||||||
|
logger::log("COLLECTION", " ... Setting artist to ".$candidate);
|
||||||
|
$this->artist = $candidate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class track {
|
||||||
|
|
||||||
|
public $tags;
|
||||||
|
|
||||||
|
public function __construct(&$filedata) {
|
||||||
|
$this->tags = $filedata;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function updateTrackInfo($info) {
|
||||||
|
$this->tags = array_replace($this->tags, $info);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_artist_string() {
|
||||||
|
return format_artist($this->tags['Artist']);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function get_sort_artist($return_albumartist = false) {
|
||||||
|
return format_sortartist($this->tags, $return_albumartist);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,156 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
require_once ('player/mpd/filetree.php');
|
||||||
|
|
||||||
|
function doDbCollection($terms, $domains, $resultstype, &$collection) {
|
||||||
|
|
||||||
|
// This can actually be used to search the database for title, album, artist, anything, rating, and tag
|
||||||
|
// But it isn't because we let Mopidy/MPD search for anything they support because otherwise we
|
||||||
|
// have to duplicate their entire database, which is daft.
|
||||||
|
// This function was written before I realised that... :)
|
||||||
|
// It's still used for searches where we're only looking for tags and/or ratings in conjunction with
|
||||||
|
// any of the above terms, because mopidy often returns incomplete search results.
|
||||||
|
|
||||||
|
$parameters = array();
|
||||||
|
$qstring = "SELECT t.*, al.*, a1.*, a2.Artistname AS AlbumArtistName ";
|
||||||
|
if (array_key_exists('rating', $terms)) {
|
||||||
|
$qstring .= ",rat.Rating ";
|
||||||
|
}
|
||||||
|
$qstring .= "FROM Tracktable AS t ";
|
||||||
|
if (array_key_exists('tag', $terms)) {
|
||||||
|
$qstring .= "JOIN (SELECT DISTINCT TTindex FROM TagListtable JOIN Tagtable AS tag USING (Tagindex) WHERE";
|
||||||
|
$tagterms = array();
|
||||||
|
foreach ($terms['tag'] as $tag) {
|
||||||
|
$parameters[] = trim($tag);
|
||||||
|
$tagterms[] = " tag.Name LIKE ?";
|
||||||
|
}
|
||||||
|
$qstring .= implode(" OR",$tagterms);
|
||||||
|
$qstring .=") AS j ON j.TTindex = t.TTindex ";
|
||||||
|
}
|
||||||
|
if (array_key_exists('rating', $terms)) {
|
||||||
|
$qstring .= "JOIN (SELECT * FROM Ratingtable WHERE Rating >= ".
|
||||||
|
$terms['rating'].") AS rat ON rat.TTindex = t.TTindex ";
|
||||||
|
}
|
||||||
|
$qstring .= "JOIN Artisttable AS a1 ON a1.Artistindex = t.Artistindex ";
|
||||||
|
$qstring .= "JOIN Albumtable AS al ON al.Albumindex = t.Albumindex ";
|
||||||
|
$qstring .= "JOIN Artisttable AS a2 ON al.AlbumArtistindex = a2.Artistindex ";
|
||||||
|
if (array_key_exists('wishlist', $terms)) {
|
||||||
|
$qstring .= "WHERE t.Uri IS NULL";
|
||||||
|
} else {
|
||||||
|
$qstring .= "WHERE t.Uri IS NOT NULL ";
|
||||||
|
}
|
||||||
|
$qstring .= "AND t.Hidden = 0 AND t.isSearchResult < 2 ";
|
||||||
|
|
||||||
|
// Map search parameters to database tables
|
||||||
|
$searchmap = array(
|
||||||
|
'artist' => 'a1.Artistname',
|
||||||
|
'album' => 'al.Albumname',
|
||||||
|
'title' => 't.Title',
|
||||||
|
'file' => 't.Uri',
|
||||||
|
'albumartist' => 'a2.Artistname'
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($searchmap as $t => $d) {
|
||||||
|
if (array_key_exists($t, $terms)) {
|
||||||
|
$qstring .= 'AND (';
|
||||||
|
$qstring .= format_for_search($terms[$t],$d, $parameters);
|
||||||
|
$qstring .= ' OR '.format_for_search2($terms[$t],$d, $parameters);
|
||||||
|
$qstring .= ') ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('any', $terms)) {
|
||||||
|
$qstring .= ' AND (';
|
||||||
|
$bunga = array();
|
||||||
|
foreach ($terms['any'] as $tim) {
|
||||||
|
$t = explode(' ',$tim);
|
||||||
|
foreach ($t as $tom) {
|
||||||
|
foreach ($searchmap AS $d) {
|
||||||
|
$bunga[] = format_for_search(array($tom), $d, $parameters);
|
||||||
|
$bunga[] = format_for_search2(array($tom), $d, $parameters);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$qstring .= implode(' OR ', $bunga);
|
||||||
|
$qstring .= ')';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (array_key_exists('date', $terms)) {
|
||||||
|
$qstring .= "AND ";
|
||||||
|
$parameters[] = trim($terms['date'][0]);
|
||||||
|
$qstring .= "al.Year = ? ";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_array($domains)) {
|
||||||
|
$qstring .= "AND (";
|
||||||
|
$domainterms = array();
|
||||||
|
foreach ($domains as $dom) {
|
||||||
|
$parameters[] = trim($dom)."%";
|
||||||
|
$domainterms[] = "t.Uri LIKE ?";
|
||||||
|
}
|
||||||
|
$qstring .= implode(" OR ",$domainterms);
|
||||||
|
$qstring .= ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
logger::log("DB SEARCH", "Parameters", $parameters);
|
||||||
|
|
||||||
|
$result = sql_prepare_query(false, PDO::FETCH_OBJ, null, null, $qstring, $parameters);
|
||||||
|
$fcount = count($result);
|
||||||
|
foreach ($result as $obj) {
|
||||||
|
$filedata = array(
|
||||||
|
'Artist' => array($obj->Artistname),
|
||||||
|
'Album' => $obj->Albumname,
|
||||||
|
'AlbumArtist' => array($obj->AlbumArtistName),
|
||||||
|
'file' => $obj->Uri,
|
||||||
|
'Title' => $obj->Title,
|
||||||
|
'Track' => $obj->TrackNo,
|
||||||
|
'X-AlbumImage' => $obj->Image,
|
||||||
|
'Time' => $obj->Duration,
|
||||||
|
'X-AlbumUri' => $obj->AlbumUri,
|
||||||
|
'Date' => $obj->Year,
|
||||||
|
'Last-Modified' => $obj->LastModified
|
||||||
|
);
|
||||||
|
$filedata = array_merge(MPD_FILE_MODEL, $filedata);
|
||||||
|
logger::log("DB SEARCH", "Found :",$obj->Title,$obj->Uri);
|
||||||
|
if ($resultstype == "tree") {
|
||||||
|
$collection->newItem($filedata);
|
||||||
|
} else if ($resultstype == "RAW") {
|
||||||
|
$collection->newTrack($filedata);
|
||||||
|
} else {
|
||||||
|
generic_sql_query("UPDATE Tracktable SET isSearchResult = 1 WHERE TTindex = ".$obj->TTindex, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $fcount;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_for_search($terms, $s, &$parameters) {
|
||||||
|
// Make things a little more searchable
|
||||||
|
$a = array();
|
||||||
|
foreach ($terms as $i => $term) {
|
||||||
|
$t = trim($term);
|
||||||
|
$t = preg_replace('/[\(\)\/\[\]\&\*\+\'\"\,\/]/','%',$t);
|
||||||
|
$a[] = $s.' LIKE ?';
|
||||||
|
$parameters[] = '% '.$t. '%';
|
||||||
|
$a[] = $s.' LIKE ?';
|
||||||
|
$parameters[] = '%'.$t. ' %';
|
||||||
|
}
|
||||||
|
$ret = implode(' OR ',$a);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
function format_for_search2($terms, $s, &$parameters) {
|
||||||
|
// Make things a little more searchable
|
||||||
|
$a = array();
|
||||||
|
foreach ($terms as $i => $term) {
|
||||||
|
$t = trim($term);
|
||||||
|
$t = preg_replace('/[\(\)\/\[\]\&\*\+\'\"\,\/]/','%',$t);
|
||||||
|
$a[] = $s.' = ?';
|
||||||
|
$parameters[] = $t;
|
||||||
|
}
|
||||||
|
$ret = implode(' OR ',$a);
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,199 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class playlistCollection {
|
||||||
|
|
||||||
|
private $foundartists;
|
||||||
|
|
||||||
|
public function doNewPlaylistFile(&$filedata) {
|
||||||
|
|
||||||
|
global $prefs;
|
||||||
|
|
||||||
|
// Translate from MPD_FILE_MODEL to ROMPR_FILE_MODEL
|
||||||
|
$info = array_replace(ROMPR_FILE_MODEL, $filedata);
|
||||||
|
if ($info['Title'] === null) {
|
||||||
|
$info['Title'] = '';
|
||||||
|
}
|
||||||
|
$albumartist = format_sortartist($filedata);
|
||||||
|
// Bloody spotify often returns album artist = A & B but track artists 'B' and 'A'.
|
||||||
|
// This screws up the playcount stats. They're also not consistent with
|
||||||
|
// capitalisation of articles in Album Artists
|
||||||
|
$tartist = format_artist($filedata['Artist'],'');
|
||||||
|
$tartist_reversed = is_array($filedata['Artist']) ? format_artist(array_reverse($filedata['Artist']),'') : '';
|
||||||
|
|
||||||
|
if (strtolower($tartist_reversed) == strtolower($albumartist)) {
|
||||||
|
$info['Artist'] = array_reverse($info['Artist']);
|
||||||
|
$tartist = $tartist_reversed;
|
||||||
|
$albumartist = $tartist_reversed;
|
||||||
|
}
|
||||||
|
|
||||||
|
$albumimage = new baseAlbumImage(array(
|
||||||
|
'baseimage' => $filedata['X-AlbumImage'],
|
||||||
|
'artist' => artist_for_image($filedata['type'], $albumartist),
|
||||||
|
'album' => $filedata['Album']
|
||||||
|
));
|
||||||
|
$albumimage->check_image($filedata['domain'], $filedata['type'], true);
|
||||||
|
|
||||||
|
$info['Id'] = (int) $filedata['Id'];
|
||||||
|
$info['ImgKey'] = $albumimage->get_image_key();
|
||||||
|
$info['images'] = $albumimage->get_images();
|
||||||
|
$info['trackartist'] = $tartist;
|
||||||
|
$info['albumartist'] = $albumartist;
|
||||||
|
$info['metadata']['track']['name'] = trim($filedata['Title']);
|
||||||
|
$info['metadata']['track']['musicbrainz_id'] = trim($filedata['MUSICBRAINZ_TRACKID']);
|
||||||
|
$info['metadata']['album']['name'] = trim($filedata['Album']);
|
||||||
|
$info['metadata']['album']['artist'] = trim($albumartist);
|
||||||
|
$info['metadata']['album']['musicbrainz_id'] = trim($filedata['MUSICBRAINZ_ALBUMID']);
|
||||||
|
$info['metadata']['album']['uri'] = $filedata['X-AlbumUri'];
|
||||||
|
if ($info['X-AlbumUri'] && getDomain($filedata['X-AlbumUri']) == 'spotify') {
|
||||||
|
$info['metadata']['album']['spotify'] = array(
|
||||||
|
'id' => substr($filedata['X-AlbumUri'], 14)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->foundartists = array();
|
||||||
|
|
||||||
|
// All kinds of places we get artist names from:
|
||||||
|
// Composer, Performer, Track Artist, Album Artist
|
||||||
|
// Note that we filter duplicates
|
||||||
|
// This creates the metadata array used by the info panel and nowplaying -
|
||||||
|
// Metadata such as scrobbles and ratings will still use the Album Artist
|
||||||
|
|
||||||
|
if ($prefs['displaycomposer']) {
|
||||||
|
// The user has chosen to display Composer/Perfomer information
|
||||||
|
// Here check:
|
||||||
|
// a) There is composer/performer information AND
|
||||||
|
// bi) Specific Genre Selected, Track Has Genre, Genre Matches Specific Genre OR
|
||||||
|
// bii) No Specific Genre Selected, Track Has Genre
|
||||||
|
if (($info['Composer'] !== null || $info['Performer'] !== null) &&
|
||||||
|
(($prefs['composergenre'] && $info['Genre'] &&
|
||||||
|
checkComposerGenre($info['Genre'], $prefs['composergenrename'])) ||
|
||||||
|
(!$prefs['composergenre'] && $info['Genre'])))
|
||||||
|
{
|
||||||
|
// Track Genre matches selected 'Sort By Composer' Genre
|
||||||
|
// Display Compoer - Performer - AlbumArtist
|
||||||
|
$this->do_composers($info);
|
||||||
|
$this->do_performers($info);
|
||||||
|
// The album artist probably won't be required in this case, but use it just in case
|
||||||
|
$this->do_albumartist($info);
|
||||||
|
// Don't do track artist as with things tagged like this this is usually rubbish
|
||||||
|
} else {
|
||||||
|
// Track Genre Does Not Match Selected 'Sort By Composer' Genre
|
||||||
|
// Or there is no composer/performer info
|
||||||
|
// Do Track Artist - Album Artist - Composer - Performer
|
||||||
|
$this->do_track_artists($info);
|
||||||
|
$this->do_albumartist($info);
|
||||||
|
$this->do_performers($info);
|
||||||
|
$this->do_composers($info);
|
||||||
|
}
|
||||||
|
if ($info['Composer'] !== null || $info['Performer'] !== null) {
|
||||||
|
$info['metadata']['iscomposer'] = 'true';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The user does not want Composer/Performer information
|
||||||
|
$this->do_track_artists($info, $albumartist);
|
||||||
|
$this->do_albumartist($info, $albumartist);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (count($info['metadata']['artists']) == 0) {
|
||||||
|
array_push($info['metadata']['artists'], array( "name" => "", "musicbrainz_id" => ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $info;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function do_composers(&$info) {
|
||||||
|
if ($info['Composer'] == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach ($info['Composer'] as $comp) {
|
||||||
|
if ($this->artist_not_found_yet($comp)) {
|
||||||
|
array_push($info['metadata']['artists'], array( "name" => trim($comp), "musicbrainz_id" => "", "type" => "composer", "ignore" => "false"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function do_performers(&$info) {
|
||||||
|
if ($info['Performer'] == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
foreach ($info['Performer'] as $comp) {
|
||||||
|
$toremove = null;
|
||||||
|
foreach($info['metadata']['artists'] as $i => $artist) {
|
||||||
|
if ($artist['type'] == "albumartist" || $artist['type'] == "artist") {
|
||||||
|
if (strtolower($artist['name'] == strtolower($comp))) {
|
||||||
|
$toremove = $i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ($toremove !== null) {
|
||||||
|
array_splice($info['metadata']['artists'], $toremove, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($toremove !== null || $this->artist_not_found_yet($comp)) {
|
||||||
|
array_push($info['metadata']['artists'], array( "name" => trim($comp), "musicbrainz_id" => "", "type" => "performer", "ignore" => "false"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function do_albumartist(&$info) {
|
||||||
|
$aartist = null;
|
||||||
|
if (!($info['type'] == "stream" && $info['albumartist'] == "Radio") &&
|
||||||
|
strtolower($info['albumartist']) != "various artists" &&
|
||||||
|
strtolower($info['albumartist']) != "various")
|
||||||
|
{
|
||||||
|
$aartist = $info['albumartist'];
|
||||||
|
}
|
||||||
|
if ($aartist !== null && $this->artist_not_found_yet($aartist)) {
|
||||||
|
array_push($info['metadata']['artists'], array( "name" => trim($aartist), "musicbrainz_id" => trim($info['MUSICBRAINZ_ALBUMARTISTID']), "type" => "albumartist", "ignore" => "false"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function do_track_artists(&$info) {
|
||||||
|
if ($info['Artist'] == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$artists = getArray($info['Artist']);
|
||||||
|
$mbids = $info['MUSICBRAINZ_ARTISTID'];
|
||||||
|
if (count($mbids) > count($artists)) {
|
||||||
|
// More MBIDs that Artists. This might be one of those daft things where MBIDs are semicolon-separated
|
||||||
|
// but artists are comma-separated.
|
||||||
|
// You can even get artists = ['artist1, artist2', 'artist3']. Sigh. Hence the first implode.
|
||||||
|
$astring = implode(', ',$artists);
|
||||||
|
$newartists = explode(',', $astring);
|
||||||
|
if (count($newartists) == count($mbids)) {
|
||||||
|
logger::trace("Trying splitting comma-separated artist string", "GETPLAYLIST");
|
||||||
|
// In case AlbumArtist has that format too
|
||||||
|
$this->artist_not_found_yet($astring);
|
||||||
|
$artists = $newartists;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (count($mbids) < count($artists)) {
|
||||||
|
$mbids[] = "";
|
||||||
|
}
|
||||||
|
$a = array();
|
||||||
|
foreach ($artists as $i => $comp) {
|
||||||
|
if ($comp != "") {
|
||||||
|
if ($this->artist_not_found_yet($comp)) {
|
||||||
|
array_push($info['metadata']['artists'], array( "name" => trim($comp), "musicbrainz_id" => trim($mbids[$i]), "type" => "artist", "ignore" => "false"));
|
||||||
|
$a[] = $comp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// This is to try and prevent repeated names - eg artists = [Pete, Dud] and albumartist = Pete & Dud or Dud & Pete
|
||||||
|
$this->artist_not_found_yet(concatenate_artist_names($a));
|
||||||
|
$this->artist_not_found_yet(concatenate_artist_names(array_reverse($a)));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function artist_not_found_yet($a) {
|
||||||
|
$s = strtolower($a);
|
||||||
|
if (in_array($s, $this->foundartists)) {
|
||||||
|
return false;
|
||||||
|
} else {
|
||||||
|
$this->foundartists[] = $s;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
|
@ -0,0 +1,13 @@
|
||||||
|
.smallcover
|
||||||
|
{
|
||||||
|
width:24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smallcover-svg {
|
||||||
|
height:24px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.notexist,img.notfound {
|
||||||
|
width:24px;
|
||||||
|
height:24px;
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
.smallcover
|
||||||
|
{
|
||||||
|
width:32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smallcover-svg {
|
||||||
|
height:32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.notexist,img.notfound {
|
||||||
|
width:32px;
|
||||||
|
height:32px;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
.smallcover
|
||||||
|
{
|
||||||
|
width:48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smallcover-svg {
|
||||||
|
height:48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.notexist,img.notfound {
|
||||||
|
width:48px;
|
||||||
|
height:48px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.desktop .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:32px;
|
||||||
|
}
|
|
@ -0,0 +1,24 @@
|
||||||
|
.smallcover
|
||||||
|
{
|
||||||
|
width:64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smallcover-svg {
|
||||||
|
height:64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.notexist,img.notfound {
|
||||||
|
width:64px;
|
||||||
|
height:64px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.desktop .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:42px;
|
||||||
|
margin-right:18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:32px;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
.smallcover
|
||||||
|
{
|
||||||
|
width:82px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smallcover-svg {
|
||||||
|
height:82px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.notexist,img.notfound {
|
||||||
|
width:82px;
|
||||||
|
height:82px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.desktop .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:42px;
|
||||||
|
margin-right:28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:32px;
|
||||||
|
margin-right:16px;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
.smallcover
|
||||||
|
{
|
||||||
|
width:100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.smallcover-svg {
|
||||||
|
height:100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img.notexist,img.notfound {
|
||||||
|
width:100px;
|
||||||
|
height:100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.desktop .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:42px;
|
||||||
|
margin-right:28px;
|
||||||
|
}
|
||||||
|
|
||||||
|
body.mobile .smallcover.svg-square.noindent
|
||||||
|
{
|
||||||
|
width:32px;
|
||||||
|
margin-right:16px;
|
||||||
|
}
|
|
@ -0,0 +1,148 @@
|
||||||
|
#imageeditor {
|
||||||
|
min-height:400px;
|
||||||
|
box-sizing:border-box;
|
||||||
|
position: relative;
|
||||||
|
z-index:100;
|
||||||
|
}
|
||||||
|
|
||||||
|
#origimage {
|
||||||
|
flex-grow: 1;
|
||||||
|
flex-shrink: 0;
|
||||||
|
flex-basis: auto;
|
||||||
|
max-width:40%;
|
||||||
|
border-left: 1px solid #fe6500;
|
||||||
|
margin-right:8px;
|
||||||
|
margin-bottom:8px;
|
||||||
|
padding-right: 8px;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
margin-top:8px;
|
||||||
|
transition: width 0.5s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
#browns {
|
||||||
|
transition: opacity 0.5s ease;
|
||||||
|
opacity: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumcovers .infosection {
|
||||||
|
margin-bottom:0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.gimage {
|
||||||
|
float:left;
|
||||||
|
padding:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.outer {
|
||||||
|
width:20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.closet {
|
||||||
|
position:relative;
|
||||||
|
width:160px;
|
||||||
|
text-align:center;
|
||||||
|
overflow:visible;
|
||||||
|
}
|
||||||
|
|
||||||
|
.covercontainer
|
||||||
|
{
|
||||||
|
position: relative;
|
||||||
|
padding-left:4px;
|
||||||
|
padding-right:4px;
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.covercontainer div {
|
||||||
|
z-index:1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.covercontainer.highlighted
|
||||||
|
{
|
||||||
|
z-index:150;
|
||||||
|
box-sizing:border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rightpad {
|
||||||
|
padding-right:16px;
|
||||||
|
margin-right:16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img#browns {
|
||||||
|
max-width:100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#searchcontent {
|
||||||
|
flex-grow: 2;
|
||||||
|
flex-shrink: 1;
|
||||||
|
flex-basis: auto;
|
||||||
|
padding:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumimg {
|
||||||
|
padding-top:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumimg img {
|
||||||
|
padding:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumimg .covercontainer img {
|
||||||
|
width: 100px;
|
||||||
|
height:auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumimg .covercontainer img.notfound, .albumimg .covercontainer img.notexist {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#brian {
|
||||||
|
padding-left:8px;
|
||||||
|
padding-right:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#editcontrols {
|
||||||
|
padding-top:2px;
|
||||||
|
padding-bottom:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#artistcoverslist {
|
||||||
|
overflow-y:auto;
|
||||||
|
height:100%;
|
||||||
|
width:20%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#coverslist {
|
||||||
|
overflow-y:auto;
|
||||||
|
height:100%;
|
||||||
|
width:80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
#progress {
|
||||||
|
font-size:12pt;
|
||||||
|
}
|
||||||
|
|
||||||
|
.artistrow {
|
||||||
|
padding-top:2px;
|
||||||
|
padding-bottom:2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumsection {
|
||||||
|
padding-top:4px;
|
||||||
|
padding-bottom:4px;
|
||||||
|
display:table;
|
||||||
|
width:100%;
|
||||||
|
margin-left:4px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumsection .tleft h2 {
|
||||||
|
margin:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.albumsection .tleft button {
|
||||||
|
margin-top:8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#morebutton {
|
||||||
|
text-align:center;
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,109 @@
|
||||||
|
/* TipTip CSS - Version 1.2 */
|
||||||
|
|
||||||
|
#tiptip_holder {
|
||||||
|
display: none;
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
z-index: 99999;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_top {
|
||||||
|
padding-bottom: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_bottom {
|
||||||
|
padding-top: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_right {
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_left {
|
||||||
|
padding-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_content {
|
||||||
|
font-size: 11px;
|
||||||
|
color: #fff;
|
||||||
|
text-shadow: 0 0 2px #000;
|
||||||
|
padding: 4px 8px;
|
||||||
|
border: 1px solid rgba(255,255,255,0.25);
|
||||||
|
background-color: rgb(25,25,25);
|
||||||
|
background-color: rgba(25,25,25,0.92);
|
||||||
|
background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(transparent), to(#000));
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 0 3px #555;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_arrow, #tiptip_arrow_inner {
|
||||||
|
position: absolute;
|
||||||
|
border-color: transparent;
|
||||||
|
border-style: solid;
|
||||||
|
border-width: 6px;
|
||||||
|
height: 0;
|
||||||
|
width: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_top #tiptip_arrow {
|
||||||
|
border-top-color: #fff;
|
||||||
|
border-top-color: rgba(255,255,255,0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_bottom #tiptip_arrow {
|
||||||
|
border-bottom-color: #fff;
|
||||||
|
border-bottom-color: rgba(255,255,255,0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_right #tiptip_arrow {
|
||||||
|
border-right-color: #fff;
|
||||||
|
border-right-color: rgba(255,255,255,0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_left #tiptip_arrow {
|
||||||
|
border-left-color: #fff;
|
||||||
|
border-left-color: rgba(255,255,255,0.35);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_top #tiptip_arrow_inner {
|
||||||
|
margin-top: -7px;
|
||||||
|
margin-left: -6px;
|
||||||
|
border-top-color: rgb(25,25,25);
|
||||||
|
border-top-color: rgba(25,25,25,0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
|
||||||
|
margin-top: -5px;
|
||||||
|
margin-left: -6px;
|
||||||
|
border-bottom-color: rgb(25,25,25);
|
||||||
|
border-bottom-color: rgba(25,25,25,0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_right #tiptip_arrow_inner {
|
||||||
|
margin-top: -6px;
|
||||||
|
margin-left: -5px;
|
||||||
|
border-right-color: rgb(25,25,25);
|
||||||
|
border-right-color: rgba(25,25,25,0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
#tiptip_holder.tip_left #tiptip_arrow_inner {
|
||||||
|
margin-top: -6px;
|
||||||
|
margin-left: -7px;
|
||||||
|
border-left-color: rgb(25,25,25);
|
||||||
|
border-left-color: rgba(25,25,25,0.92);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Webkit Hacks */
|
||||||
|
@media screen and (-webkit-min-device-pixel-ratio:0) {
|
||||||
|
#tiptip_content {
|
||||||
|
padding: 4px 8px 5px 8px;
|
||||||
|
background-color: rgba(45,45,45,0.88);
|
||||||
|
}
|
||||||
|
#tiptip_holder.tip_bottom #tiptip_arrow_inner {
|
||||||
|
border-bottom-color: rgba(45,45,45,0.88);
|
||||||
|
}
|
||||||
|
#tiptip_holder.tip_top #tiptip_arrow_inner {
|
||||||
|
border-top-color: rgba(20,20,20,0.92);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
// These are the functions for building the dropdowns in the file browser
|
||||||
|
|
||||||
|
require_once ("includes/vars.php");
|
||||||
|
require_once ("includes/functions.php");
|
||||||
|
require_once ("international.php");
|
||||||
|
require_once ("player/".$prefs['player_backend']."/player.php");
|
||||||
|
require_once ("player/mpd/filetree.php");
|
||||||
|
require_once ("skins/".$skin."/ui_elements.php");
|
||||||
|
$error = 0;
|
||||||
|
$dbterms = array( 'tags' => null, 'rating' => null );
|
||||||
|
|
||||||
|
$path = (array_key_exists('path', $_REQUEST)) ? $_REQUEST['path'] : "";
|
||||||
|
$prefix = (array_key_exists('prefix', $_REQUEST)) ? $_REQUEST['prefix'].'_' : "dirholder";
|
||||||
|
|
||||||
|
$player = new fileCollector();
|
||||||
|
if ($player->is_connected()) {
|
||||||
|
if ($path == "") {
|
||||||
|
// print '<div class="configtitle textcentre expand" style="margin-left:8px"><b>'.get_int_text('button_file_browser').'</b></div>';
|
||||||
|
} else {
|
||||||
|
directoryControlHeader($prefix);
|
||||||
|
}
|
||||||
|
$player->doFileBrowse($path, $prefix);
|
||||||
|
} else {
|
||||||
|
header("HTTP/1.1 500 Internal Server Error");
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
Binary file not shown.
After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,5 @@
|
||||||
|
@import url("https://fonts.googleapis.com/css?family=Alegreya:400,400i,700,700i&subset=cyrillic,cyrillic-ext,greek,greek-ext,latin-ext,vietnamese");
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Alegreya", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "AppleGothic", "Gothic Uralic", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Arima+Madurai:400,700');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Arima Madurai", cursive;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: Baskerville, "Baskerville Old Face", "Hoefler Text", Garamond, "Times New Roman", serif;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Cabin:400,400i,700,700i&subset=latin-ext');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Cabin", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: Calibri, Candara, Segoe, "Segoe UI", Optima, BetecknaLowerCase, Arial, sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Calisto MT", "Bookman Old Style", Bookman, "Goudy Old Style", Garamond, "Hoefler Text", "Bitstream Charter", Georgia, serif;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Comfortaa:400,700&subset=cyrillic,cyrillic-ext,greek,latin-ext,vietnamese');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Comfortaa", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: Copperplate, "Copperplate Gothic Light", "Libris ADF Std", fantasy;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Cormorant+Garamond:400,400i,700,700i&subset=cyrillic,latin-ext');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Cormorant Garamond", serif;
|
||||||
|
line-height: 140%;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Crimson+Text:400,400i,700,700i');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Crimson Text", serif;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Darker+Grotesque:400,700&display=swap&subset=latin-ext');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Darker Grotesque", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Dosis:400,700&subset=latin-ext');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Dosis", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url("https://fonts.googleapis.com/css?family=Fahkwang:400,400i,700,700i&subset=latin-ext,thai,vietnamese");
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Fahkwang", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family:CupolaUnicode,fantasy;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: Futura, "Trebuchet MS", Arial, sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: Garamond, Baskerville, "Baskerville Old Face", "Hoefler Text", "Times New Roman", serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: Geneva, "URW Gothic L", Tahoma, Verdana, sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family:Georgia, serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Gill Sans", "Droid Sans", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family:breip,UnPilgia,cursive;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: Herculanum, "Licorice Strings BRK", fantasy;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=IBM+Plex+Sans:400,400i,700,700i&subset=cyrillic,cyrillic-ext,latin-ext,vietnamese');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "IBM Plex Sans", sans-serif;
|
||||||
|
line-height: 140%;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=IBM+Plex+Serif:400,400i,700,700i&subset=cyrillic,cyrillic-ext,latin-ext,vietnamese');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "IBM Plex Serif", serif;
|
||||||
|
line-height: 140%;
|
||||||
|
}
|
|
@ -0,0 +1,6 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Josefin+Sans:400,400i,700,700i&subset=latin-ext,vietnamese');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Josefin Sans", sans-serif;
|
||||||
|
line-height: 140%;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Josefin+Slab:400,400i,700,700i');body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Josefin Slab", serif;
|
||||||
|
line-height: 140%;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Libre+Franklin:400,400i,700,700i&subset=latin-ext');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Libre Franklin", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@import url('https://fonts.googleapis.com/css?family=Lora:400,400i,700,700i&subset=cyrillic,cyrillic-ext,latin-ext,vietnamese');
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Lora", serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family:"Lucida Grande", "Lucida Sans Unicode", "Linux Biolinum O", sans-serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Luminari", "Mathematica6", "eufm10", serif;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
body,p,h1,h2,h3,h4,table,td,th,ul,ol,textarea,input,button,select,option
|
||||||
|
{
|
||||||
|
font-family: "Marker Felt", "Backlash BRK", fantasy;
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue