]> _ Git - songbook.git/commitdiff
.
authorVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 6 Jan 2023 09:44:57 +0000 (10:44 +0100)
committerVincent Vanwaelscappel <vincent@cubedesigners.com>
Fri, 6 Jan 2023 09:44:57 +0000 (10:44 +0100)
19 files changed:
app/Console/Kernel.php
app/Http/Controllers/FrontController.php
app/Jobs/DownloadAudioTracks.php
app/Jobs/OptimizeMP3.php
app/Jobs/PitchShiftAudio.php
app/Jobs/SyncNotion.php [new file with mode: 0644]
app/Models/Collection.php
app/Notion/Song.php [new file with mode: 0644]
composer.json
resources/css/app.sass
resources/css/fonts/dancing-script-v24-latin-regular.woff2 [new file with mode: 0644]
resources/js/mmenu.js
resources/js/player.js
resources/views/layout.blade.php
resources/views/notion_collection.blade.php [new file with mode: 0644]
resources/views/notion_collection_song.blade.php [new file with mode: 0644]
resources/views/notion_menu.blade.php [new file with mode: 0644]
resources/views/notion_menu_song.blade.php [new file with mode: 0644]
resources/views/notion_song.blade.php [new file with mode: 0644]

index 7fa65705440350d65c813764b413b8da7ef39526..2bf8bf2fd0953284b1ae56995af39b556aa5a4ef 100644 (file)
@@ -5,8 +5,7 @@ namespace App\Console;
 use Illuminate\Console\Scheduling\Schedule;
 use Illuminate\Foundation\Console\Kernel as ConsoleKernel;
 
-class Kernel extends ConsoleKernel
-{
+class Kernel extends ConsoleKernel {
     /**
      * The Artisan commands provided by your application.
      *
@@ -19,12 +18,12 @@ class Kernel extends ConsoleKernel
     /**
      * Define the application's command schedule.
      *
-     * @param  \Illuminate\Console\Scheduling\Schedule  $schedule
+     * @param \Illuminate\Console\Scheduling\Schedule $schedule
      * @return void
      */
-    protected function schedule(Schedule $schedule)
-    {
+    protected function schedule(Schedule $schedule) {
         $schedule->command('job:dispatchNow PitchShiftAudio')->hourly();
+        $schedule->command('job:dispatchNow SyncNotion')->everyTenMinutes();
     }
 
     /**
@@ -32,9 +31,8 @@ class Kernel extends ConsoleKernel
      *
      * @return void
      */
-    protected function commands()
-    {
-        $this->load(__DIR__.'/Commands');
+    protected function commands() {
+        $this->load(__DIR__ . '/Commands');
 
         require base_path('routes/console.php');
     }
index 39a7413fa01ea025113bdbe00948e000901d5077..5df42fd81bc108f140df24b02b719f74866f8a8d 100644 (file)
@@ -8,17 +8,20 @@ use App\Models\Song;
 use Cubist\Backpack\Http\Controllers\CubistPWAController;
 use Cubist\Util\Files\Files;
 use Illuminate\Support\Facades\Session;
+use Notion\Blocks\BlockInterface;
+use Notion\Blocks\Paragraph;
+use Notion\Common\RichText;
+use Notion\Notion;
+use Notion\Pages\Properties\RichTextProperty;
+use Notion\Pages\Properties\Title;
 
 
-class FrontController extends Controller
-{
-    public static function defaultCollection()
-    {
+class FrontController extends Controller {
+    public static function defaultCollection() {
         return redirect('/' . Collection::withoutGlobalScope('ownerclause')->find(1)->slug);
     }
 
-    public function collection($name)
-    {
+    public function collection($name) {
         $collection = Collection::withoutGlobalScope('ownerclause')->where('slug', $name)->first();
         if (null === $collection) {
             return self::defaultCollection();
@@ -26,14 +29,27 @@ class FrontController extends Controller
         if ($p = $this->checkPassword($collection)) {
             return $p;
         }
+
+        if ($collection->notion_key && $collection->notion_database) {
+            return $this->notionCollection($collection);
+        }
+
         $lists = CollectionList::withoutGlobalScope('ownerclause')->where('collection', $collection->id)->get();
         $songs = $this->_getSongsOfCollection($collection->id, $lists);
 
         return view('collection', ['menu' => true, 'songs' => $songs, 'collection' => $collection, 'collection_songs' => $songs, 'collection_lists' => $lists]);
     }
 
-    public function checkPassword(Collection $collection)
-    {
+    /**
+     * @throws \Exception
+     */
+    public function notionCollection($collection) {
+        $songs = self::getSongsOfNotionCollection($collection);
+        return view('notion_collection', ['menu' => true, 'notion' => true, 'songs' => $songs, 'collection' => $collection, 'collection_songs' => $songs]);
+    }
+
+
+    public function checkPassword(Collection $collection) {
         if (!$collection->password) {
             return false;
         }
@@ -51,13 +67,15 @@ class FrontController extends Controller
         return view('login', ['menu' => false, 'collection' => $collection, 'error' => $error]);
     }
 
-    public function song($collection, $song)
-    {
+    public function song($collection, $song) {
         /** @var Collection $collection */
         $collection = Collection::withoutGlobalScope('ownerclause')->where('slug', $collection)->first();
         if (null === $collection) {
             abort(404);
         }
+        if ($collection->notion_key && $collection->notion_database) {
+            return $this->notionSong($collection, $song);
+        }
         /** @var Song $song */
         $song = Song::withoutGlobalScope('ownerclause')->where('slug', $song)->first();
         if (null === $song) {
@@ -66,6 +84,8 @@ class FrontController extends Controller
         if ($p = $this->checkPassword($collection)) {
             return $p;
         }
+
+
         $lists = CollectionList::withoutGlobalScope('ownerclause')->where('collection', $collection->id)->get();
         $partition = false;
         $lyrics_html = '';
@@ -102,8 +122,21 @@ class FrontController extends Controller
         return view('song', ['menu' => true, 'lyrics_html' => $lyrics_html, 'song' => $song, 'collection' => $collection, 'partition' => $partition, 'collection_songs' => $this->_getSongsOfCollection($collection->id, $lists), 'collection_lists' => $lists]);
     }
 
-    protected function _getSongsOfCollection($id, $lists)
-    {
+    protected function notionSong($collection, $song) {
+        $partition = false;
+
+        $u = $song . '.html';
+        $songs = self::getSongsOfNotionCollection($collection);
+        foreach ($songs as $song) {
+            if ($song->getUrl() === $u) {
+                break;
+            }
+        }
+        $lyrics_html = $song->getLyrics();
+        return view('notion_song', ['menu' => true, 'notion' => true, 'lyrics_html' => $lyrics_html, 'song' => $song, 'collection' => $collection, 'collection_songs' => $songs]);
+    }
+
+    protected function _getSongsOfCollection($id, $lists) {
         /** @var Song $q */
         $q = Song::withoutGlobalScope('ownerclause')->whereRaw('json_contains(collections, \'["' . $id . '"]\')');
         foreach ($lists as $list) {
@@ -113,8 +146,145 @@ class FrontController extends Controller
 
     }
 
-    public function manifest($collection)
-    {
+    /**
+     * @param $collection Collection
+     * @return \App\Notion\Song[]
+     * @throws \Exception
+     */
+    public static function getSongsOfNotionCollection($collection, $force = false) {
+        $cacheKey = 'songs_notion_' . $collection->notion_database . '_' . $collection->id;
+        $ttl = 900;
+        if ($force) {
+            $v = self::_getSongsOfNotionCollection($collection);
+            cache()->set($cacheKey, $v, $ttl);
+        } else {
+            return cache()->remember($cacheKey, $ttl, function () use ($collection) {
+                return self::_getSongsOfNotionCollection($collection);
+            });
+        }
+    }
+
+
+    protected static function _getSongsOfNotionCollection($collection) {
+
+        $audios = ['mp3', 'm4a', 'wav'];
+        $notion = Notion::create($collection->notion_key);
+        $database = $notion->databases()->find($collection->notion_database);
+        $songs = $notion->databases()->queryAllPages($database);
+
+        $res = [];
+        foreach ($songs as $song) {
+            $pageContents = '';
+            try {
+                $contents = $notion->blocks()->findChildren($song->id);
+                foreach ($contents as $content) {
+                    $pageContents .= self::_blockToHtml($content);
+                }
+            } catch (\Exception $e) {
+
+            }
+
+            $s = [];
+
+            /** @var Title $titleProperty */
+            $titleProperty = $song->getProprety('Titre');
+            /** @var Number $orderProperty */
+            $orderProperty = $song->getProprety('Ordre');
+            /** @var RichTextProperty $lyricsProperty */
+            $lyricsProperty = $song->getProprety('Paroles');
+            /** @var \Notion\Pages\Properties\Files $filesProperty */
+            $filesProperty = $song->getProprety('Files & media');
+
+            $s['id'] = $song->id;
+            $s['order'] = (int)$orderProperty->number;
+            $s['title'] = $titleProperty->toString();
+            $s['lyrics'] = self::_blockToHtml($lyricsProperty);
+            $s['notes'] = $pageContents;
+            $s['notion_url'] = $song->url;
+
+
+            $s['files'] = [];
+            $s['audios'] = [];
+            foreach ($filesProperty->files as $file) {
+                $ext = self::parseExtensionFromAmazonURL($file->url);
+                if (in_array($ext, $audios)) {
+                    $s['audios'][] = ['name' => self::parseFileNameFromAmazonURL($file->url), 'url' => $file->url, 'ext' => $ext];
+                } else {
+                    $s['files'][] = ['name' => self::parseFileNameFromAmazonURL($file->url), 'url' => $file->url, 'ext' => $ext];
+                }
+            }
+
+            $res[$s['order']] = new \App\Notion\Song($s, $collection->notion_database);
+        }
+        ksort($res);
+        return $res;
+
+    }
+
+    /**
+     * @param $block RichTextProperty|BlockInterface
+     * @return string
+     */
+    protected static function _blockToHtml($block) {
+        $start = '';
+        $end = '';
+        if ($block instanceof Paragraph) {
+            $start = '<p>';
+            $end = '</p>';
+        }
+        $res = '';
+        foreach ($block->text as $rt) {
+            $res .= self::_richTextToHtml($rt);
+        }
+        $res = $start . $res . $end;
+        return str_replace('</h3><br />', '</h3>', $res);
+    }
+
+    /**
+     * @param $rt RichText
+     * @return string
+     */
+    protected static function _richTextToHtml($rt) {
+        $start = '';
+        $end = '';
+        if ($rt->annotations->isBold) {
+            $start = '<strong>' . $start;
+            $end = $end . '</strong>';
+        }
+        if ($rt->annotations->isItalic) {
+            $start = '<em>' . $start;
+            $end = $end . '</em>';
+        }
+        if ($rt->annotations->isUnderline) {
+            $start = '<h3>' . $start;
+            $end = $end . '</h3>';
+        }
+        if ($rt->annotations->isCode) {
+            $start = '<blockquote>' . $start;
+            $end = $end . '</blockquote>';
+        }
+        return $start . nl2br($rt->plainText) . $end;
+    }
+
+    public static function parseFileNameFromAmazonURL($url) {
+        $u = parse_url($url);
+        $p = explode('/', $u['path']);
+        $f = array_pop($p);
+        $e = explode('.', $f);
+        array_pop($e);
+        $f = implode('.', $e);
+        return str_replace('_', ' ', $f);
+    }
+
+    public static function parseExtensionFromAmazonURL($url) {
+        $u = parse_url($url);
+        $p = explode('/', $u['path']);
+        $f = array_pop($p);
+        $e = explode('.', $f);
+        return array_pop($e);
+    }
+
+    public function manifest($collection) {
         $collection = Collection::withoutGlobalScope('ownerclause')->where('slug', $collection)->first();
         if (null === $collection) {
             abort(404);
@@ -133,21 +303,20 @@ class FrontController extends Controller
         $icons[count($icons) - 1]['purpose'] = 'maskable';
 
         $res = ['name' => $collection->name,
-            'short_name' => $collection->shortname ?: $collection->name,
-            'description' => '',
-            'display' => 'standalone',
-            'orientation' => 'any',
-            'background_color' => $collection->splashscreen_color,
-            'theme_color' => $collection->theme_color,
-            'start_url' => '/' . $collection->slug,
-            'scope' => '/' . $collection->slug,
-            'icons' => $icons];
+                'short_name' => $collection->shortname ?: $collection->name,
+                'description' => '',
+                'display' => 'standalone',
+                'orientation' => 'any',
+                'background_color' => $collection->splashscreen_color,
+                'theme_color' => $collection->theme_color,
+                'start_url' => '/' . $collection->slug,
+                'scope' => '/' . $collection->slug,
+                'icons' => $icons];
 
         return response(json_encode($res))->header('Content-Type', 'application/manifest+json');
     }
 
-    public function downloadAssets($songId)
-    {
+    public function downloadAssets($songId) {
         /** @var Song $song */
         $song = Song::withoutGlobalScope('ownerclause')->find($songId);
         $fields = ['partition', 'lyrics_doc'];
index 6fcf7453794eddf2fb669b0d6b687924176d7b0f..ad4fc6480201423586b337b6f33744aae0a8c819 100644 (file)
@@ -3,19 +3,13 @@
 namespace App\Jobs;
 
 use App\Models\Song;
+use Cubist\Backpack\Jobs\Base;
 use Cubist\Util\Files\Files;
 use Cubist\Util\PHP;
-use Illuminate\Bus\Queueable;
-use Illuminate\Contracts\Queue\ShouldQueue;
-use Illuminate\Foundation\Bus\Dispatchable;
-use Illuminate\Queue\InteractsWithQueue;
-use Illuminate\Queue\SerializesModels;
 use YoutubeDl\Options;
 use YoutubeDl\YoutubeDl;
 
-class DownloadAudioTracks implements ShouldQueue
-{
-    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+class DownloadAudioTracks extends Base{
 
     public function handle()
     {
index ee56e9e43336399961f83b400cf36fbbf47273ca..26a905ed7059f1de91090c5ea19d2d0868204d75 100644 (file)
@@ -5,10 +5,7 @@ namespace App\Jobs;
 use App\Models\Song;
 use Cubist\Backpack\Jobs\Base;
 use Cubist\Util\CommandLine;
-use Cubist\Util\Files\Files;
 use Cubist\Util\PHP;
-use YoutubeDl\Options;
-use YoutubeDl\YoutubeDl;
 
 class OptimizeMP3 extends Base
 {
index 748818668368c7b19f43f34fb1fc7a435b6028c1..6fee92aa2b6bf3b48ba914a89cbe81e6fdd4fa72 100644 (file)
@@ -3,6 +3,7 @@
 namespace App\Jobs;
 
 use App\Models\Song;
+use Cubist\Backpack\Jobs\Base;
 use Cubist\Util\CommandLine;
 use Cubist\Util\PHP;
 use Illuminate\Bus\Queueable;
@@ -11,14 +12,11 @@ use Illuminate\Foundation\Bus\Dispatchable;
 use Illuminate\Queue\InteractsWithQueue;
 use Illuminate\Queue\SerializesModels;
 
-class PitchShiftAudio implements ShouldQueue
-{
-    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
+class PitchShiftAudio extends Base {
 
     public static $pitches = [1 => '+1', 2 => '+2', 3 => '+3', 4 => '+4', 5 => '+5', 6 => '+6', 7 => '-5', 8 => '-4', 9 => '-3', 10 => '-2', 11 => '-1'];
 
-    public function handle()
-    {
+    public function handle() {
         PHP::neverStop();
 
         DownloadAudioTracks::dispatchSync();
diff --git a/app/Jobs/SyncNotion.php b/app/Jobs/SyncNotion.php
new file mode 100644 (file)
index 0000000..147c2ce
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+namespace App\Jobs;
+
+use App\Http\Controllers\FrontController;
+use App\Models\Collection;
+use Cubist\Backpack\Jobs\Base;
+use Cubist\Util\PHP;
+use Notion\Common\RichText;
+use Notion\Notion;
+use Notion\Pages\Properties\Files;
+use Notion\Pages\Properties\Number;
+use Notion\Pages\Properties\RichTextProperty;
+use Notion\Pages\Properties\Title;
+
+class SyncNotion extends Base {
+
+    /**
+     * @throws \Exception
+     */
+    public function handle() {
+        PHP::neverStop();
+
+        foreach (Collection::withoutGlobalScopes()->get() as $collection) {
+            if ($collection->notion_key && $collection->notion_database) {
+                FrontController::getSongsOfNotionCollection($collection, true);
+            }
+        }
+    }
+}
index 2815a6057193701af42c0ecb56b4249059c40d0b..6270f428fa3446d871e1dcbc329e955d3656b8da 100644 (file)
@@ -11,6 +11,7 @@ use Cubist\Backpack\Magic\Fields\SelectFromModel;
 use Cubist\Backpack\Magic\Fields\Slug;
 use Cubist\Backpack\Magic\Fields\Table;
 use Cubist\Backpack\Magic\Fields\Text;
+use Cubist\Backpack\Magic\Fields\URL;
 use Cubist\Backpack\Magic\Models\CubistMagicAbstractModel;
 use Illuminate\Database\Eloquent\Builder;
 use Illuminate\Support\Facades\Auth;
@@ -47,6 +48,9 @@ class Collection extends CubistMagicAbstractModel {
         $this->addField('agenda', FilesOrURL::class, 'Planning / Agenda', ['default' => false, 'database_default' => false]);
         $this->addField('organisation_name', Text::class, 'Label du lien "Rรฉpartition / organisation"', ['default' => false, 'database_default' => false]);
         $this->addField('organisation', FilesOrURL::class, 'Rรฉpartition / organisation', ['default' => false, 'database_default' => false]);
+        $this->addField('notion_key',Text::class,'Clรฉ Notion');
+        $this->addField('notion_database',Text::class,'Base de donnรฉes Notion');
+        $this->addField('notion_home',URL::class,'Home Notion');
     }
 
     protected function _getFreeFileBaseDirectory() {
diff --git a/app/Notion/Song.php b/app/Notion/Song.php
new file mode 100644 (file)
index 0000000..101fefc
--- /dev/null
@@ -0,0 +1,55 @@
+<?php
+
+namespace App\Notion;
+
+use Cubist\Util\Data;
+use Cubist\Util\Str;
+
+class Song extends Data{
+
+    public function getUrl() {
+        return Str::slug($this->getTitle()) . '.html';
+    }
+
+    public function getArtist() {
+        return '';
+    }
+
+    public function getTitle() {
+        return $this->get('title');
+    }
+
+    public function getLyrics() {
+        return $this->get('lyrics');
+    }
+
+    public function getId() {
+        return $this->get('id');
+    }
+
+    public function getOrder() {
+        return $this->get('order');
+    }
+
+    public function getNotionURL(){
+        return $this->get('notion_url');
+    }
+
+    public function hasSimpleChords(){
+        return false;
+    }
+
+    public function getAudioTracks() {
+        $res = $this->get('audios');
+        foreach ($res as $k=>$v) {
+            $res[$k]['i']=$k;
+            $res[$k]['opturl']=$v['url'];
+        }
+        return $res;
+    }
+
+    public function getFiles(){
+        return $this->get('files');
+    }
+
+}
index 3ed4667c5f44f4e218677fe7ebc175a60ce996f2..5713631285c8c1a9e60628276d217fe9b88a744b 100644 (file)
     ],
     "license": "MIT",
     "require": {
-        "php": ">=7.4",
+        "php": ">=8.1",
+        "ext-dom": "*",
         "ext-json": "*",
+        "ext-libxml": "*",
+        "ext-redis": "*",
         "ext-simplexml": "*",
         "ext-tidy": "*",
         "ext-zip": "*",
-        "ext-libxml": "*",
-        "ext-dom": "*",
-        "ext-redis": "*",
         "cubist/cms-back": "dev-master",
         "fruitcake/laravel-cors": "^2.2",
+        "guzzlehttp/psr7": "^2.0",
         "league/csv": "^9.8",
+        "mariosimao/notion-sdk-php": "^1.0",
         "mxl/laravel-job": "^1.3",
         "norkunas/youtube-dl-php": "dev-master",
         "php-ffmpeg/php-ffmpeg": "^0.18.0",
-        "phpoffice/phpspreadsheet": "^1.23"
+        "phpoffice/phpspreadsheet": "^1.25"
+    },
+    "replace": {
+        "cviebrock/laravel-elasticsearch": "*"
     },
     "require-dev": {
         "barryvdh/laravel-ide-helper": "^2.10",
index 54a9a9d4c1a2ed4c0bff4f707b473b8ac200b4b7..c1e914d9b6b4f9bb88c94086fa8988f025831ea3 100644 (file)
     font-weight: 700
     src: url('fonts/roboto-condensed-700.woff2') format('woff2')
 
+@font-face
+    font-family: 'Dancing Script'
+    font-style: normal
+    font-weight: 400
+    src: url('fonts/dancing-script-v24-latin-regular.woff2') format('woff2')
+
 $slab: 'Roboto Slab', sans-serif
 
 .phpdebugbar
@@ -106,11 +112,15 @@ main
         overflow: hidden
         text-overflow: ellipsis
 
+
         span
             color: #000
             @media (prefers-color-scheme: dark)
                 color: #fff
             font-size: 0.65em
+            &.order
+                font-size: 1em
+                margin-right: 10px
 
     li
         list-style: none
@@ -136,6 +146,17 @@ article.song
                 @media (prefers-color-scheme: dark)
                     color: #fff !important
 
+        &.fromnotion
+            margin: 0 !important
+            font-family: $slab !important
+            border-bottom: 1px solid currentColor
+            padding-bottom: 20px
+
+            &.notes
+                font-family: "Dancing Script", cursive !important
+                padding-top: 20px
+                font-size: 1.25em
+
 
     &.lyrics
         .lyrics
@@ -206,10 +227,27 @@ article.song
             top: -0.25em
             opacity: 0.5
 
+    h2
+        font-size: 20px
+        margin: 20px 0 15px
+
+    ul
+        li
+            list-style: none
+
     h3
         color: var(--theme-color)
         margin: 5px 0
 
+    a.select_audio
+        cursor: pointer
+
+    blockquote
+        border-left: 5px solid var(--theme-color)
+        padding-left: 20px
+        opacity: 0.6
+
+
     .lyrics
         font-family: "Roboto Slab", serif
         font-weight: 400
diff --git a/resources/css/fonts/dancing-script-v24-latin-regular.woff2 b/resources/css/fonts/dancing-script-v24-latin-regular.woff2
new file mode 100644 (file)
index 0000000..a78f79d
Binary files /dev/null and b/resources/css/fonts/dancing-script-v24-latin-regular.woff2 differ
index 2b34144ee78430a29f03e07e934abe2e3d26aabb..f483c67a80d057bb84df6bbd6e91a3cc5b4350ea 100644 (file)
@@ -34,6 +34,13 @@ document.addEventListener("DOMContentLoaded", () => {
     $('body').addClass('init');
 });
 
+setTimeout(function () {
+    $('body').addClass('init');
+}, 2000);
+$(function () {
+    $('body').addClass('init');
+});
+
 $(window).on('beforeunload', function () {
     $('body').removeClass('init');
 });
@@ -103,12 +110,11 @@ window.setOption = function (name, value) {
     $('input[name="' + n + '"]').prop('checked', value == '1');
 }
 
-function updateSelect(select) {
+window.updateSelect = function (select) {
     var sv = $(select).val();
     if (sv === null) {
         return;
     }
-    console.log('Set option from select', $(select).data('name'), sv);
     $(select).closest('.clickselect').find('span').text($(select).find('option[value="' + $(select).val() + '"]').text());
     setOption($(select).data('name'), $(select).val());
     updateSongView();
@@ -124,6 +130,7 @@ $(function () {
         return true;
     });
 
+
     $(document).on('change', '.checkbox-switch', function () {
         var name = $(this).attr('name');
         var checked = $(this).is(':checked') ? '1' : '0';
index 37a9560fbf89ec2a2437ad971fa60b73959ba545..0046519bc534c8665d2e9ee3aea5776d750cf42d 100644 (file)
@@ -9,6 +9,16 @@
         resetPlayers();
     });
 
+    $(document).on('click', '.select_audio', function () {
+        var e = $(this).attr('data-id').split('_');
+        $('select[data-name="audio"]').val(e[1]);
+        updateSelect($('select[data-name="audio"]'));
+        resetPlayers();
+        playAudio();
+        return false;
+    });
+
+
     function resetPlayers() {
         $.each(window.players, function (k, player) {
             player.stop();
         });
     });
     $(document).on('click', '[data-action="play"]', function () {
-        $(this).hide();
+        playAudio();
+        return false;
+    });
+
+    function playAudio() {
+        $('[data-action="play"]').hide();
 
         var audio = window.getOption('audio').toString();
         var t = window.getOption('audio_' + audio + '_tone');
@@ -46,8 +61,7 @@
         var p = window.players[pid];
         $(p.elements.container).show();
         p.play();
-        return false;
-    });
+    }
 
     function changeAudio() {
         $('li[data-audio]').hide();
index 11bf20e8682b8e5a87477d8de9891351998d2f63..43068c73e39aad63aaf91106f3be861f6f660e82 100644 (file)
@@ -1,15 +1,19 @@
+@if(isset($notion) && $notion)
+@include('notion_menu')
+@else
 @include('menu')
-    <!DOCTYPE html>
+@endif
+<!DOCTYPE html>
 <html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
 <head>
     <meta charset="utf-8">
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <title>@yield('title')</title>
     <style>
-        body {
-            --theme-color: {{$collection->theme_color}};
-            --plyr-color-main: {{$collection->theme_color}};
-        }
+               body {
+                       --theme-color: {{$collection->theme_color}};
+                       --plyr-color-main: {{$collection->theme_color}};
+               }
     </style>
     <link href="{{ mix('css/app.css') }}" rel="stylesheet">
     <link rel="manifest" href="/{{$collection->slug}}.webmanifest">
@@ -32,7 +36,7 @@
     <meta name="viewport" content="width=device-width, initial-scale=1">
     <script>var THEME_COLOR = '{{$collection->theme_color}}';
         @if(isset($song))
-        var SONG = {{$song->id}};
+        var SONG = "{{$song->id}}";
         @endif
     </script>
 </head>
diff --git a/resources/views/notion_collection.blade.php b/resources/views/notion_collection.blade.php
new file mode 100644 (file)
index 0000000..ff85e94
--- /dev/null
@@ -0,0 +1,18 @@
+@extends('layout')
+@php
+    $preload=[];
+@endphp
+@section('title', $collection->name)
+
+@section('content')
+    @include('header',['title'=>$collection->name,'subtitle'=>''])
+    <article class="collection">
+        <nav>
+            <ul>
+                @foreach($songs as $csong)
+                    @include('notion_collection_song')
+                @endforeach
+            </ul>
+        </nav>
+    </article>
+@endsection
diff --git a/resources/views/notion_collection_song.blade.php b/resources/views/notion_collection_song.blade.php
new file mode 100644 (file)
index 0000000..6034632
--- /dev/null
@@ -0,0 +1,5 @@
+@php
+    $songurl='/'.$collection->slug.'/'.$csong->getURL();
+@endphp
+<li><a href="{{$songurl}}"><span class="order">{{$csong->getOrder()}}</span> {{$csong->getTitle()}}<span>{{$csong->getArtist()}}</span></a>
+</li>
diff --git a/resources/views/notion_menu.blade.php b/resources/views/notion_menu.blade.php
new file mode 100644 (file)
index 0000000..44c0be5
--- /dev/null
@@ -0,0 +1,144 @@
+@php
+    $tones=\App\Field\Tone::getTones();
+    $fontSizes=[0.5,0.6,0.7,0.8,0.9,1,1.1,1.25,1.5,1.75,2];
+    $prefetch=[];
+@endphp
+
+@section('menu')
+    <nav id="menu">
+        <ul id="panel-menu">
+            <li><a href="/{{$collection->slug}}">๐Ÿ“– {{__('Home')}}</a></li>
+            <li><span>๐ŸŽถ {{__('Songs')}}</span>
+                <ul>
+                    @if(isset($collection_songs))
+                        @foreach($collection_songs as $csong)
+                            @include('notion_menu_song')
+                        @endforeach
+                    @endif
+                </ul>
+            </li>
+            @if(isset($song))
+{{--                @if($song->hasChords())--}}
+{{--                    <li><a href="#" class="noaction">๐ŸŽค {{__('Show lyrics')}} <input type="checkbox"--}}
+{{--                                                                                    class="checkbox-switch"--}}
+{{--                                                                                    name="show_lyrics_{{$song->id}}"--}}
+{{--                                                                                    data-default="1"></a></li>--}}
+{{--                    <li><a href="#" class="noaction">๐ŸŽผ {{__('Show chords')}} <input type="checkbox"--}}
+{{--                                                                                    class="checkbox-switch"--}}
+{{--                                                                                    name="show_chords_{{$song->id}}"--}}
+{{--                                                                                    data-default="1"></a></li>--}}
+{{--                    @if($song->hasSimpleChords())--}}
+{{--                        <li><a href="#" class="noaction">๐Ÿฃ {{__('Show simple chords')}} <input type="checkbox"--}}
+{{--                                                                                               class="checkbox-switch"--}}
+{{--                                                                                               name="show_simplechords_{{$song->id}}"--}}
+{{--                                                                                               data-default="0"></a>--}}
+{{--                        </li>--}}
+{{--                    @endif--}}
+{{--                    @if($collection->transpose)--}}
+{{--                        <li><a href="#" class="clickselect">โ†•๏ธ {{__('Key')}} <select data-name="tone"--}}
+{{--                                                                                     name="tone_{{$song->id}}">--}}
+{{--                                    @for($i=-5;$i<=6;$i++)--}}
+{{--                                        <option value="{{$i}}"--}}
+{{--                                                @if($i===0) selected @endif>{{$tones[(12+$song->key+$i)%12].$song->mode}} @if($i>0)--}}
+{{--                                                (+{{$i}}--}}
+{{--                                                )--}}
+{{--                                            @elseif($i<0)--}}
+{{--                                                ({{$i}})--}}
+{{--                                            @endif </option>--}}
+{{--                                    @endfor--}}
+{{--                                </select><span></span></a></li>--}}
+{{--                    @endif--}}
+{{--                @else--}}
+{{--                    <li class="hidden"><a href="#" class="noaction">{{__('Show chords')}} <input type="checkbox"--}}
+{{--                                                                                                 class="checkbox-switch"--}}
+{{--                                                                                                 name="show_chords_{{$song->id}}"--}}
+{{--                                                                                                 data-default="0"></a>--}}
+{{--                    </li>--}}
+{{--                    <li class="hidden"><a href="#" class="noaction">{{__('Show lyrics')}} <input type="checkbox"--}}
+{{--                                                                                                 class="checkbox-switch"--}}
+{{--                                                                                                 name="show_lyrics_{{$song->id}}"--}}
+{{--                                                                                                 data-default="1"></a>--}}
+{{--                    </li>--}}
+{{--                @endif--}}
+
+                <li><a href="#" class="clickselect">๐Ÿ”  {{__('Lyrics text size')}} <select data-name="size"
+                                                                                         name="size_{{$song->id}}">
+                            @foreach($fontSizes as $s)
+                                <option value="{{$s}}" @if($s===1) selected @endif>{!! round($s*100) !!}%</option>
+                            @endforeach
+                        </select><span></span></a></li>
+
+                @if(count($song->getAudioTracks())>0)
+                    <li><a href="#" class="clickselect">๐Ÿ’ฟ {{__('Audio track')}} <select data-name="audio"
+                                                                                        name="audio_{{$song->id}}">
+                                @foreach($song->getAudioTracks() as $i=>$track)
+                                    <option value="{{$i}}" data-url="{{$track['url']}}">{{$track['name']}}</option>
+                                @endforeach
+                            </select><span></span></a></li>
+                    @foreach($song->getAudioTracks() as $i=>$track)
+                        @if($collection->transpose && isset($track['tone']) && is_numeric($track['tone']))
+                            <li data-audio="{{$i}}"><a href="#" class="clickselect">โ†•๏ธ{{__('Audio key')}} <select
+                                        class="audiotone"
+                                        data-name="audio_{{$i}}_tone"
+                                        name="audio_{{$i}}_tone_{{$song->id}}">
+                                        @for($i=-5;$i<=6;$i++)
+                                            <option value="{{($i+12)%12}}"
+                                                    @if($i===0) selected @endif>{{$tones[(12+$track['tone']+$i)%12].$song->mode}} @if($i>0)
+                                                    (+{{$i}}
+                                                    )
+                                                @elseif($i<0)
+                                                    ({{$i}})
+                                                @endif </option>
+                                        @endfor
+                                    </select><span></span></a></li>
+                        @endif
+                    @endforeach
+                @endif
+{{--                @if($partition)--}}
+{{--                    <li><a target="_blank" href="{{$partition}}">๐ŸŽผ {{__('Partition')}}</a></li>--}}
+{{--                @endif--}}
+{{--                @if($collection->download_assets)--}}
+{{--                    <li><a download="{{$song->title}}.zip" href="/downloadassets/{{$song->id}}">โฌ‡๏ธ &nbsp;{{__('Tรฉlรฉcharger')}}</a></li>--}}
+{{--                @endif--}}
+            @endif
+
+            @if(!isset($song) && $collection->agenda)
+                @php
+                    $planning=\Cubist\Util\Url::isLocal($collection->agenda)?'/collection/'.$collection->id.'/'.$collection->agenda:$collection->agenda;
+                @endphp
+            <li>
+                <span>๐Ÿ—“๏ธ {{__('Planning')}}</span>
+                <ul>
+                    <iframe src="{{$planning}}" style="width: 100%;height:100%;border: 0;"></iframe>
+                </ul>
+            </li>
+            @endif
+
+            @if($collection->organisation_name)
+                <li>
+                    <a target="_blank" href="{{$collection->organisation}}">๐Ÿง‘โ€๐ŸŽค๏ธ {{$collection->organisation_name}}</a>
+                </li>
+            @endif
+
+            <li>
+                <span><img
+                        src="https://api.qrserver.com/v1/create-qr-code/?size=50x50&data={{rawurlencode('https://songbook.enhydra.fr/'.$collection->slug)}}"
+                        style="width: 15px;height:auto;margin:5px 10px 5px 5px;vertical-align: bottom">{{__('Share via QR Code')}}</span>
+                <ul>
+                    <div style="padding: 30px;background-color: #fff;height: 100%"><img
+                            src="https://api.qrserver.com/v1/create-qr-code/?size=300x300&data={{rawurlencode('https://songbook.enhydra.fr/'.$collection->slug)}}"
+                            style="width: 100%;height:auto;"></div>
+                </ul>
+            </li>
+            @if(isset($song))
+                <li><a href="{{$song->getNotionURL()}}">๐ŸงŠ {{__('La chanson sur Notion')}}</a></li>
+            @else
+                <li><a href="{{$collection->notion_home}}">๐ŸงŠ {{__('Les chansons sur Notion')}}</a></li>
+            @endif
+        </ul>
+    </nav>
+@endsection
+
+@section('prefetch')
+    <script>var PRELOAD =@json($prefetch);</script>
+@endsection
diff --git a/resources/views/notion_menu_song.blade.php b/resources/views/notion_menu_song.blade.php
new file mode 100644 (file)
index 0000000..334b59a
--- /dev/null
@@ -0,0 +1,6 @@
+@php
+    $songurl="/$collection->slug/".$csong->getUrl();
+    $prefetch[]=$songurl;
+@endphp
+<li><a rel="prefetch" href="{{$songurl}}">{{trim($csong->getOrder().' - '.$csong->getTitle().' - '.$csong->getArtist(),' -')}}</a>
+</li>
diff --git a/resources/views/notion_song.blade.php b/resources/views/notion_song.blade.php
new file mode 100644 (file)
index 0000000..c3c0117
--- /dev/null
@@ -0,0 +1,51 @@
+@php
+    $audioTracks=$song->getAudioTracks();
+    $simple=$song->hasSimpleChords();
+@endphp
+
+@extends('layout')
+@section('title', $song->title.' - '.$song->artist.' - '. $collection->name)
+@section('content')
+    @include('header',['title'=>$song->title,'subtitle'=>$song->artist])
+    <article class="song" data-tone="{{$song->key}}" data-mode="{{$song->mode}}">
+        <section class="fromnotion">{!! $lyrics_html !!}</section>
+        @if($song->notes)
+            <section class="fromnotion notes">{!! $song->notes !!}</section>
+        @endif
+        <div class="credits">{{$song->credits}}</div>
+        @if(count($audioTracks))
+            <h2>๐Ÿ’ฟ {{__('Audios')}}</h2>
+            <ul class="files">
+                @foreach($audioTracks as $audio)
+                    <li><a class="select_audio" data-id="player_{{$audio['i']}}_0">{{$audio['name']}}</a></li>
+                @endforeach
+            </ul>
+        @endif
+        @if(count($song->getFiles()))
+            <h2>๐Ÿ“„ {{__('Fichiers')}}</h2>
+            <ul class="files">
+                @foreach($song->getFiles() as $file)
+                    <li><a target="_blank" href="{{$file['url']}}">{{$file['name']}}.{{$file['ext']}}</a></li>
+                @endforeach
+            </ul>
+        @endif
+    </article>
+    @if(count($audioTracks))
+        <div id="audioplayers">
+            @foreach($audioTracks as $audio)
+                <audio id="player_{{$audio['i']}}_0" controls loop>
+                    <source src="{{$audio['opturl']}}" type="audio/mp3"/>
+                </audio>
+            @endforeach
+        </div>
+    @endif
+@endsection
+@section('floating')
+    @if(count($audioTracks))
+        <a href="#" data-action="play">
+            <svg x="0" y="0" width="124.512" height="124.512" aria-hidden="true">
+                <use xlink:href="#play"/>
+            </svg>
+        </a>
+    @endif
+@endsection