Commit ce5cdfbc authored by onny's avatar onny

some change

parents 4b80e8e8 5a7e80e9
Pipeline #223 canceled with stages
## 1.0.0 - 2020-11
### Added
- Complete new rewrite in VueJS
Many bugs fixed and some features added.
- Dashboard integration
- Unified search support
- Show recent played stations
- Show sidebar with further infos
- Improved performance and stability
## 0.6.6 - 2020-02
### Added
- French translation
......
Copyright 2018 Jonas Heinrich
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
MIT License
Copyright (c) 2020 Jonas Heinrich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
......@@ -50,3 +50,5 @@ clean:
clean-dev:
rm -rf node_modules
appstore:
krankerl package
......@@ -5,7 +5,7 @@
<name>Radio</name>
<summary>Radio listening app</summary>
<description>Listening to your favorite radio stations in Nextcloud</description>
<version>1.0</version>
<version>1.0.0</version>
<licence>MIT</licence>
<author mail="onny@project-insanity.org" >Jonas Heinrich</author>
<namespace>Radio</namespace>
......
<?php
/**
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
return [
'resources' => [
......
.icon-mail {
.icon-radio {
background-image: url(./../img/radio-trans.svg);
}
body.theme--dark .icon-mail {
body.theme--dark .icon-radio {
background-image: url(./../img/radio.svg);
}
/**
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
@include icon-black-white('recent', 'radio', 1);
@include icon-black-white('radio', 'radio', 1);
@include icon-black-white('radio-trans', 'radio', 1);
[package]
before_cmds = [
"composer install --no-dev -o",
"npm install --deps",
"npm run build",
]
......@@ -4,6 +4,7 @@ declare(strict_types=1);
namespace OCA\Radio\AppInfo;
use OC\Security\CSP\ContentSecurityPolicy;
use OCA\Radio\Search\SearchProvider;
use OCP\AppFramework\App;
use OCP\AppFramework\Bootstrap\IBootContext;
......@@ -30,8 +31,24 @@ class Application extends App implements IBootstrap {
return $c->get(IRequest::class);
});
$this->registerCsp();
}
public function boot(IBootContext $context): void {
}
/**
* Allow radio-browser hosts in the csp
*
* @throws \OCP\AppFramework\QueryException
*/
public function registerCsp() {
$manager = $this->getContainer()->getServer()->getContentSecurityPolicyManager();
$policy = new ContentSecurityPolicy();
$policy->addAllowedConnectDomain('https://de1.api.radio-browser.info');
$policy->addAllowedImageDomain('*');
$policy->addAllowedMediaDomain('*');
$manager->addDefaultPolicy($policy);
}
}
......@@ -44,20 +44,29 @@ class FavoriteController extends Controller {
/**
* @NoAdminRequired
*/
public function create(string $stationuuid, string $name, string $favicon, string $urlresolved): DataResponse {
return new DataResponse($this->service->create($stationuuid, $name,
$favicon, $urlresolved, $this->userId));
}
public function create(string $stationuuid, string $name, string $favicon, string $urlresolved,
string $bitrate, string $country, string $language, string $homepage,
string $codec, string $tags): DataResponse {
return new DataResponse($this->service->create($stationuuid, $name,
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
$tags, $this->userId));
}
/**
* @NoAdminRequired
*/
public function update(int $id, string $stationuuid,
string $name, string $favicon, string $urlresolved): DataResponse {
return $this->handleNotFound(function () use ($id, $stationuuid, $name, $favicon, $urlresolved) {
return $this->service->update($id, $stationuuid, $name, $favicon, $urlresolved, $this->userId);
});
}
public function update(int $id, string $stationuuid,
string $name, string $favicon, string $urlresolved,
string $bitrate, string $country, string $language, string $homepage,
string $codec, string $tags): DataResponse {
return $this->handleNotFound(function () use ($id, $stationuuid, $name,
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
$tags) {
return $this->service->update($id, $stationuuid, $name, $favicon,
$urlresolved, $bitrate, $country, $language, $homepage, $codec,
$tags, $this->userId);
});
}
/**
* @NoAdminRequired
......
<?php
declare(strict_types=1);
/**
* @copyright Copyright (c) 2019 John Molakvoæ <skjnldsv@protonmail.com>
*
* @author John Molakvoæ <skjnldsv@protonmail.com>
*
* @license GNU AGPL version 3 or any later version
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
namespace OCA\Radio\Controller;
......
......@@ -44,18 +44,26 @@ class RecentController extends Controller {
/**
* @NoAdminRequired
*/
public function create(string $stationuuid, string $name, string $favicon, string $urlresolved): DataResponse {
public function create(string $stationuuid, string $name, string $favicon, string $urlresolved,
string $bitrate, string $country, string $language, string $homepage,
string $codec, string $tags): DataResponse {
return new DataResponse($this->service->create($stationuuid, $name,
$favicon, $urlresolved, $this->userId));
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
$tags, $this->userId));
}
/**
* @NoAdminRequired
*/
public function update(int $id, string $stationuuid,
string $name, string $favicon, string $urlresolved): DataResponse {
return $this->handleNotFound(function () use ($id, $stationuuid, $name, $favicon, $urlresolved) {
return $this->service->update($id, $stationuuid, $name, $favicon, $urlresolved, $this->userId);
public function update(int $id, string $stationuuid, string $name,
string $favicon, string $urlresolved, string $bitrate, string $country,
string $language, string $homepage, string $codec, string $tags): DataResponse {
return $this->handleNotFound(function () use ($id, $stationuuid, $name,
$favicon, $urlresolved, $bitrate, $country, $language, $homepage, $codec,
$tags) {
return $this->service->update($id, $stationuuid, $name, $favicon,
$urlresolved, $bitrate, $country, $language, $homepage, $codec,
$tags, $this->userId);
});
}
......
......@@ -79,7 +79,7 @@ class SettingsController extends ApiController {
*/
public function setMenuState($menuState = ""): JSONResponse {
if ($menuState == 'SEARCH') {
return true;
return new JSONResponse(['status' => 'success'], Http::STATUS_OK);
};
$legalArguments = ['TOP', 'RECENT', 'NEW', 'FAVORITES', 'CATEGORIES'];
if (!in_array($menuState, $legalArguments)) {
......
......@@ -4,6 +4,8 @@ namespace OCA\Radio\Dashboard;
use OCP\Dashboard\IWidget;
use OCP\IL10N;
use OCP\IURLGenerator;
use OCP\Util;
use OCA\Radio\AppInfo\Application;
......@@ -12,24 +14,29 @@ class RadioWidget implements IWidget {
/** @var IL10N */
private $l10n;
/** @var IURLGenerator */
private $urlGenerator;
public function __construct(
IL10N $l10n
IL10N $l10n,
IURLGenerator $urlGenerator
) {
$this->l10n = $l10n;
$this->urlGenerator = $urlGenerator;
}
/**
* @inheritDoc
*/
public function getId(): string {
return 'radio';
return Application::APP_ID;
}
/**
* @inheritDoc
*/
public function getTitle(): string {
return $this->l10n->t('Favorite Radio stations');
return $this->l10n->t('Radio stations');
}
/**
......@@ -50,14 +57,14 @@ class RadioWidget implements IWidget {
* @inheritDoc
*/
public function getUrl(): ?string {
return \OC::$server->getURLGenerator()->linkToRoute('settings.PersonalSettings.index', ['section' => 'connected-accounts']);
return $this->urlGenerator->getAbsoluteURL($this->urlGenerator->linkToRoute('radio.page.index'));
}
/**
* @inheritDoc
*/
public function load(): void {
\OC_Util::addScript(Application::APP_ID, Application::APP_ID . '-dashboard');
\OC_Util::addStyle(Application::APP_ID, 'dashboard');
}
Util::addScript(Application::APP_ID, 'radio-dashboard');
Util::addStyle(Application::APP_ID, 'dashboard');
}
}
......@@ -27,6 +27,15 @@ class RecentMapper extends QBMapper {
->addSelect('name')
->addSelect('favicon')
->addSelect('urlresolved')
<<<<<<< HEAD
=======
->addSelect('bitrate')
->addSelect('country')
->addSelect('language')
->addSelect('homepage')
->addSelect('codec')
->addSelect('tags')
>>>>>>> nc20
->from('recent')
->orderBy('id', 'DESC')
->where($qb->expr()->eq('id', $qb->createNamedParameter($id, IQueryBuilder::PARAM_INT)))
......@@ -45,6 +54,15 @@ class RecentMapper extends QBMapper {
->addSelect('name')
->addSelect('favicon')
->addSelect('urlresolved')
<<<<<<< HEAD
=======
->addSelect('bitrate')
->addSelect('country')
->addSelect('language')
->addSelect('homepage')
->addSelect('codec')
->addSelect('tags')
>>>>>>> nc20
->from('recent')
->orderBy('id', 'DESC')
->where($qb->expr()->eq('user_id', $qb->createNamedParameter($userId)));
......
......@@ -11,6 +11,12 @@ class Station extends Entity implements JsonSerializable {
protected $name;
protected $favicon;
protected $urlresolved;
protected $bitrate;
protected $country;
protected $language;
protected $homepage;
protected $codec;
protected $tags;
protected $userId;
public function jsonSerialize(): array {
......@@ -19,7 +25,13 @@ class Station extends Entity implements JsonSerializable {
'stationuuid' => $this->stationuuid,
'name' => $this->name,
'favicon' => $this->favicon,
'urlresolved' => $this->urlresolved
'urlresolved' => $this->urlresolved,
'bitrate' => $this->bitrate,
'country' => $this->country,
'language' => $this->language,
'homepage' => $this->homepage,
'codec' => $this->codec,
'tags' => $this->tags
];
}
}
......@@ -38,6 +38,12 @@ class Version000000Date20181013124731 extends SimpleMigrationStep {
]);
$table->addColumn('favicon', 'text');
$table->addColumn('urlresolved', 'text');
$table->addColumn('bitrate', 'text');
$table->addColumn('country', 'text');
$table->addColumn('language', 'text');
$table->addColumn('homepage', 'text');
$table->addColumn('codec', 'text');
$table->addColumn('tags', 'text');
$table->setPrimaryKey(['id']);
$table->addIndex(['user_id'], 'favorites_user_id_index');
......@@ -60,6 +66,12 @@ class Version000000Date20181013124731 extends SimpleMigrationStep {
]);
$table->addColumn('favicon', 'text');
$table->addColumn('urlresolved', 'text');
$table->addColumn('bitrate', 'text');
$table->addColumn('country', 'text');
$table->addColumn('language', 'text');
$table->addColumn('homepage', 'text');
$table->addColumn('codec', 'text');
$table->addColumn('tags', 'text');
$table->setPrimaryKey(['id']);
$table->addIndex(['user_id'], 'recent_user_id_index');
......
......@@ -45,23 +45,37 @@ class FavoriteService {
}
}
public function create($stationuuid, $name, $favicon, $urlresolved, $userId) {
public function create($stationuuid, $name, $favicon, $urlresolved,
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
$station = new Station();
$station->setStationuuid($stationuuid);
$station->setName($name);
$station->setFavicon($favicon);
$station->setUrlresolved($urlresolved);
$station->setBitrate($bitrate);
$station->setCountry($country);
$station->setLanguage($language);
$station->setHomepage($homepage);
$station->setCodec($codec);
$station->setTags($tags);
$station->setUserId($userId);
return $this->mapper->insert($station);
}
public function update($id, $stationuuid, $name, $favicon, $urlresolved, $userId) {
public function update($id, $stationuuid, $name, $favicon, $urlresolved,
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
try {
$station = $this->mapper->find($id, $userId);
$station->setStationuuid($stationuuid);
$station->setName($name);
$station->setFavicon($favicon);
$station->setUrlresolved($urlresolved);
$station->setBitrate($bitrate);
$station->setCountry($country);
$station->setLanguage($language);
$station->setHomepage($homepage);
$station->setCodec($codec);
$station->setTags($tags);
return $this->mapper->update($station);
} catch (Exception $e) {
$this->handleException($e);
......
......@@ -45,23 +45,37 @@ class RecentService {
}
}
public function create($stationuuid, $name, $favicon, $urlresolved, $userId) {
public function create($stationuuid, $name, $favicon, $urlresolved,
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
$station = new Station();
$station->setStationuuid($stationuuid);
$station->setName($name);
$station->setFavicon($favicon);
$station->setUrlresolved($urlresolved);
$station->setBitrate($bitrate);
$station->setCountry($country);
$station->setLanguage($language);
$station->setHomepage($homepage);
$station->setCodec($codec);
$station->setTags($tags);
$station->setUserId($userId);
return $this->mapper->insert($station);
}
public function update($id, $stationuuid, $name, $favicon, $urlresolved, $userId) {
public function update($id, $stationuuid, $name, $favicon, $urlresolved,
$bitrate, $country, $language, $homepage, $codec, $tags, $userId) {
try {
$station = $this->mapper->find($id, $userId);
$station->setStationuuid($stationuuid);
$station->setName($name);
$station->setFavicon($favicon);
$station->setUrlresolved($urlresolved);
$station->setBitrate($bitrate);
$station->setCountry($country);
$station->setLanguage($language);
$station->setHomepage($homepage);
$station->setCodec($codec);
$station->setTags($tags);
return $this->mapper->update($station);
} catch (Exception $e) {
$this->handleException($e);
......
This diff is collapsed.
......@@ -30,16 +30,22 @@
"stylelint:fix": "stylelint src --fix"
},
"dependencies": {
"@nextcloud/axios": "^1.4.0",
"@nextcloud/dialogs": "^3.0.0",
"@nextcloud/axios": "^1.5.0",
"@nextcloud/dialogs": "^3.1.1",
"@nextcloud/l10n": "^1.4.1",
"@nextcloud/moment": "^1.1.1",
"@nextcloud/router": "^1.2.0",
"@nextcloud/vue": "^2.7.0",
"@nextcloud/vue": "^2.9.0",
"@nextcloud/vue-dashboard": "^1.0.1",
"axios": "^0.21.0",
"howler": "^2.2.1",
"music-metadata": "^7.4.1",
"music-metadata": "^7.5.0",
"style-loader": "^2.0.0",
"vue": "^2.6.12",
"vue-blurhash": "^0.1.2",
"vue-router": "^3.4.7",
"vue-clipboard2": "^0.3.1",
"vue-resize-observer": "^1.0.32",
"vue-router": "^3.4.9",
"vuex": "^3.5.1"
},
"browserslist": [
......@@ -49,38 +55,38 @@
"node": ">=10.0.0"
},
"devDependencies": {
"@babel/core": "^7.11.6",
"@babel/core": "^7.12.3",
"@babel/plugin-syntax-dynamic-import": "^7.8.3",
"@babel/preset-env": "^7.11.5",
"@babel/preset-env": "^7.12.1",
"@nextcloud/browserslist-config": "^1.0.0",
"@nextcloud/eslint-config": "^2.2.0",
"@nextcloud/eslint-plugin": "^1.5.0",
"@nextcloud/webpack-vue-config": "^1.1.0",
"@vue/test-utils": "^1.1.0",
"@nextcloud/webpack-vue-config": "^1.4.1",
"@vue/test-utils": "^1.1.1",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.1.0",
"babel-loader": "^8.2.1",
"css-loader": "^3.6.0",
"eslint": "^6.8.0",
"eslint-config-standard": "^14.1.1",
"eslint-import-resolver-webpack": "^0.13.0",
"eslint-loader": "^4.0.2",
"eslint-plugin-html": "^6.1.0",
"eslint-plugin-html": "^6.1.1",
"eslint-plugin-import": "^2.22.1",
"eslint-plugin-node": "^11.1.0",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
"eslint-plugin-standard": "^4.1.0",
"eslint-plugin-vue": "^6.2.2",
"file-loader": "^6.1.1",
"file-loader": "^6.2.0",
"node-sass": "^4.14.1",
"sass-loader": "^8.0.2",
"stylelint": "^13.7.2",
"stylelint": "^13.8.0",
"stylelint-config-recommended-scss": "^4.2.0",
"stylelint-scss": "^3.18.0",
"stylelint-webpack-plugin": "^2.1.0",
"vue-loader": "^15.9.3",
"stylelint-webpack-plugin": "^2.1.1",
"vue-loader": "^15.9.5",
"vue-template-compiler": "^2.6.12",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-merge": "^5.2.0"
"webpack-merge": "^5.4.0"
}
}
<template>
<DashboardWidget :items="items"
:show-more-url="showMoreUrl"
:show-more-text="title"
:loading="state === 'loading'">
<template #empty-content>
<EmptyContent