Fix trailing whitespaces in files

This commit is contained in:
jo 2021-05-27 16:33:20 +02:00
parent 1af089219f
commit d8195f0fd8
46 changed files with 240 additions and 241 deletions

88
CREDITS
View File

@ -92,7 +92,7 @@ Martin Konecny (martin.konecny@sourcefabric.org)
James Moon (james.moon@sourcefabric.org) James Moon (james.moon@sourcefabric.org)
Role: Software Developer Role: Software Developer
Denise Rigato (denise.rigato@sourcefabric.org) Denise Rigato (denise.rigato@sourcefabric.org)
Role: Software Developer Role: Software Developer
@ -124,7 +124,7 @@ Martin Konecny (martin.konecny@sourcefabric.org)
James Moon (james.moon@sourcefabric.org) James Moon (james.moon@sourcefabric.org)
Role: Software Developer Role: Software Developer
Denise Rigato (denise.rigato@sourcefabric.org) Denise Rigato (denise.rigato@sourcefabric.org)
Role: Software Developer Role: Software Developer
@ -147,7 +147,7 @@ Naomi Aro (naomi.aro@sourcefabric.org)
James Moon (james.moon@sourcefabric.org) James Moon (james.moon@sourcefabric.org)
Role: Software Developer Role: Software Developer
Denise Rigato (denise.rigato@sourcefabric.org) Denise Rigato (denise.rigato@sourcefabric.org)
Role: Software Developer Role: Software Developer
@ -198,7 +198,7 @@ Naomi Aro (naomi.aro@sourcefabric.org)
James Moon (james.moon@sourcefabric.org) James Moon (james.moon@sourcefabric.org)
Role: Software Developer Role: Software Developer
Denise Rigato (denise.rigato@sourcefabric.org) Denise Rigato (denise.rigato@sourcefabric.org)
Role: Software Developer Role: Software Developer
@ -267,7 +267,7 @@ Martin Konecny (martin.konecny@sourcefabric.org)
James Moon (james.moon@sourcefabric.org) James Moon (james.moon@sourcefabric.org)
Role: Software Developer Role: Software Developer
Yuchen Wang (yuchen.wang@sourcefabric.org) Yuchen Wang (yuchen.wang@sourcefabric.org)
Role: Software Developer Role: Software Developer
@ -350,10 +350,10 @@ Version 1.6.1
------------- -------------
Same as previous version. Same as previous version.
Version 1.6.0 Version 1.6.0
------------- -------------
This version marks a major change to the project, completely replacing the This version marks a major change to the project, completely replacing the
custom audio player with liquidsoap, dropping the custom desktop GUI, and custom audio player with liquidsoap, dropping the custom desktop GUI, and
completely rewriting the web interface. The project has also been renamed completely rewriting the web interface. The project has also been renamed
from "Campcaster" to "Airtime" for this release. from "Campcaster" to "Airtime" for this release.
@ -361,11 +361,11 @@ Paul Baranowski (paul.baranowski@sourcefabric.org)
Role: Project Lead / Software Developer Role: Project Lead / Software Developer
Highlights: Highlights:
- Integration and development of liquidsoap scheduler - Integration and development of liquidsoap scheduler
- Separation of playlists from the scheduler - Separation of playlists from the scheduler
Naomi Aro (naomi.aro@sourcefabric.org) Naomi Aro (naomi.aro@sourcefabric.org)
Role: Software Developer Role: Software Developer
Highlights: Highlights:
- New User Interface - New User Interface
- Conversion to Propel DB backend - Conversion to Propel DB backend
@ -397,44 +397,44 @@ generated radio station based in Basel, Switzerland powered by Campcaster. We ar
very grateful for their contributions, and specifically to Thomas Gilgen, Dirk Claes, very grateful for their contributions, and specifically to Thomas Gilgen, Dirk Claes,
Rigzen Latshang and Fabiano Sidler. Rigzen Latshang and Fabiano Sidler.
Douglas Arellanes Douglas Arellanes
- Tester and user feedback - Tester and user feedback
Robin Gareus Robin Gareus
- Packaging - Packaging
Ferenc Gerlits Ferenc Gerlits
- Studio GUI - Studio GUI
Sebastian Göbel Sebastian Göbel
- Web interface, storage server - Web interface, storage server
Nebojsa Grujic Nebojsa Grujic
- Scheduler, XML-RPC interface, Gstreamer plugins - Scheduler, XML-RPC interface, Gstreamer plugins
Tomáš Hlava Tomáš Hlava
- Bug fixes - Bug fixes
Sava Tatić Sava Tatić
- Manager - Manager
Version 1.3.0 - "Dakar" Version 1.3.0 - "Dakar"
----------------------- -----------------------
Douglas Arellanes Douglas Arellanes
- Tester and user feedback - Tester and user feedback
Ferenc Gerlits Ferenc Gerlits
- Studio GUI, scheduler, packaging - Studio GUI, scheduler, packaging
Sebastian Göbel Sebastian Göbel
- Web interface - Web interface
Tomáš Hlava Tomáš Hlava
- Bug fixes - Bug fixes
Sava Tatić Sava Tatić
- Manager - Manager
@ -442,19 +442,19 @@ Version 1.2.0 - "Kotor"
----------------------- -----------------------
In alphabetical order: In alphabetical order:
Douglas Arellanes Douglas Arellanes
- Tester and user feedback - Tester and user feedback
Paul Baranowski Paul Baranowski
- Project manager, HTML UI, storage server - Project manager, HTML UI, storage server
Ferenc Gerlits Ferenc Gerlits
- Studio GUI, scheduler, packaging - Studio GUI, scheduler, packaging
Tomáš Hlava Tomáš Hlava
- Bug fixes - Bug fixes
Robert Klajn Robert Klajn
- Superuser feedback - Superuser feedback
Mark Kretschmann Mark Kretschmann
- Audio player - Audio player
Sava Tatić Sava Tatić
- Manager - Manager
@ -462,40 +462,40 @@ Version 1.1.X - "Freetown"
-------------------------- --------------------------
In alphabetical order: In alphabetical order:
Douglas Arellanes Douglas Arellanes
- Tester and user feedback - Tester and user feedback
Paul Baranowski Paul Baranowski
- Project manager, HTML UI, storage server, scheduler - Project manager, HTML UI, storage server, scheduler
János Csikós János Csikós
- HTML UI - HTML UI
Ferenc Gerlits Ferenc Gerlits
- Studio GUI, scheduler, packaging - Studio GUI, scheduler, packaging
Tomáš Hlava Tomáš Hlava
- Storage server, network hub - Storage server, network hub
Mark Kretschmann Mark Kretschmann
- Audio player - Audio player
Ákos Maróy Ákos Maróy
- Architecture design, scheduler, audio player - Architecture design, scheduler, audio player
Sava Tatić Sava Tatić
- Manager - Manager
Version 1.0 Version 1.0
----------- -----------
The original Campcaster (LiveSupport) concept was drafted by Micz Flor. It was The original Campcaster (LiveSupport) concept was drafted by Micz Flor. It was
fully developed by Robert Klajn, Douglas Arellanes, Ákos Maróy, and Sava Tatić. fully developed by Robert Klajn, Douglas Arellanes, Ákos Maróy, and Sava Tatić.
The user interface has been designed by Charles Truett, based on the initial work The user interface has been designed by Charles Truett, based on the initial work
done by a team of his then-fellow Parsons School of Design students Turi McKinley, done by a team of his then-fellow Parsons School of Design students Turi McKinley,
Catalin Lazia and Sangita Shah. The team was led by then-head of the school's Catalin Lazia and Sangita Shah. The team was led by then-head of the school's
Department of Digital Design Colleen Macklin, assisted by Kunal Jain. Department of Digital Design Colleen Macklin, assisted by Kunal Jain.
In alphabetical order: In alphabetical order:
Douglas Arellanes Douglas Arellanes
Michael Aschauer Michael Aschauer
Micz Flor Micz Flor
Ferenc Gerlits Ferenc Gerlits
Sebastian Göbel Sebastian Göbel
Tomáš Hlava Tomáš Hlava
Nadine Kokot Nadine Kokot
Ákos Maróy Ákos Maróy
Sava Tatić Sava Tatić
Charles Truett Charles Truett

View File

@ -49,14 +49,14 @@
* Much faster library import (Silan analyzer runs in background) * Much faster library import (Silan analyzer runs in background)
* Fixed zombie process sometimes being created * Fixed zombie process sometimes being created
* Other * Other
* Upgrade to Mutagen (tag reader) 1.21 * Upgrade to Mutagen (tag reader) 1.21
2.3.0 - Jan 21st, 2013 2.3.0 - Jan 21st, 2013
* New features * New features
* Localization (Chinese, Czech, English, French, German, Italian, Korean, * Localization (Chinese, Czech, English, French, German, Italian, Korean,
Portuguese, Russian, Spanish) Portuguese, Russian, Spanish)
* User management page for non-admin users * User management page for non-admin users
* Listener statistics (Icecast/Shoutcast) * Listener statistics (Icecast/Shoutcast)
* Airtime no longer requires Apache document root * Airtime no longer requires Apache document root
* Replay Gain offset in real-time * Replay Gain offset in real-time
* Enable/disable replay gain * Enable/disable replay gain
@ -113,7 +113,7 @@
* Playlist Builder should remember your position instead of resetting to the first page every time an operation was performed * Playlist Builder should remember your position instead of resetting to the first page every time an operation was performed
* If Master or Live input source is disconnected, Airtime will no longer automatically switch off that source. This should allow the source to * If Master or Live input source is disconnected, Airtime will no longer automatically switch off that source. This should allow the source to
reconnect and continue playback. reconnect and continue playback.
* Bug fixes * Bug fixes
* Fixed playout engine sometimes not receiving new schedule which could result in dead air * Fixed playout engine sometimes not receiving new schedule which could result in dead air
* Fixed script timeout which caused Apache to become unresponsive * Fixed script timeout which caused Apache to become unresponsive
@ -174,7 +174,7 @@
* Fixed Airtime could stop automatically recording after 2 hours if the web interface isn't used. * Fixed Airtime could stop automatically recording after 2 hours if the web interface isn't used.
* Fixed upgrading from 1.8.2 when the stor directory was a symlink would cause filenames to not be preserved. * Fixed upgrading from 1.8.2 when the stor directory was a symlink would cause filenames to not be preserved.
* Fixed Day View in the Now Playing tab showed some items on incorrect days. * Fixed Day View in the Now Playing tab showed some items on incorrect days.
* Fixed problems with having an equal '=' sign as an icecast password * Fixed problems with having an equal '=' sign as an icecast password
* Other * Other
* Various optimizations to make Airtime feel snappier in the browser. Various views should * Various optimizations to make Airtime feel snappier in the browser. Various views should
load much quicker. load much quicker.
@ -295,11 +295,11 @@
- Fixed pypo hanging if web server is unavailable - Fixed pypo hanging if web server is unavailable
- Fixed items that were being dragged and dropped in the Playlist Builder - Fixed items that were being dragged and dropped in the Playlist Builder
being obscured by other UI elements. being obscured by other UI elements.
1.9.3 - August 26th, 2011 1.9.3 - August 26th, 2011
* Improvements * Improvements
- It is now possible to upgrade your system while a show is playing. - It is now possible to upgrade your system while a show is playing.
Playout will be temporarily interrupted for about 5-10 seconds and then Playout will be temporarily interrupted for about 5-10 seconds and then
playout will resume. Previously playout would not resume until the next playout will resume. Previously playout would not resume until the next
scheduled show. scheduled show.
* Fixes * Fixes
@ -324,7 +324,7 @@
- Prevent users from doing a manual install of Airtime if they already have - Prevent users from doing a manual install of Airtime if they already have
the Debian package version installed the Debian package version installed
* Changes * Changes
- Support Settings moved to a separate page accessible by Admin user only. - Support Settings moved to a separate page accessible by Admin user only.
1.9.0 - August 9, 2011 1.9.0 - August 9, 2011
@ -333,20 +333,20 @@ The cool stuff:
- Human-readable file structure. The directory structure and file names on - Human-readable file structure. The directory structure and file names on
disk are now human-readable. This means you can easily find files using disk are now human-readable. This means you can easily find files using
your file browser on your server. your file browser on your server.
- Magic file synchronization. Edits to your files are automatically - Magic file synchronization. Edits to your files are automatically
noticed by Airtime. If you edit any files on disk, such as trimming the noticed by Airtime. If you edit any files on disk, such as trimming the
length of a track, Airtime will automatically notice this and adjust the length of a track, Airtime will automatically notice this and adjust the
playlist lengths and shows for that audio file. playlist lengths and shows for that audio file.
- Auto-import and multiple-directory support. You can set any number of - Auto-import and multiple-directory support. You can set any number of
directories to be watched by Airtime. Any new files you add to watched directories to be watched by Airtime. Any new files you add to watched
directories will be automatically imported into Airtime, and any deleted directories will be automatically imported into Airtime, and any deleted
files will be automatically removed. files will be automatically removed.
- The "airtime-import" command line tool can now set watched directories - The "airtime-import" command line tool can now set watched directories
and change the storage directory. and change the storage directory.
- Graceful recovery from reboot. If the playout engine starts up and - Graceful recovery from reboot. If the playout engine starts up and
detects that a show should be playing at the current time, it will skip detects that a show should be playing at the current time, it will skip
to the right point in the track and start playing. Previously, Airtime to the right point in the track and start playing. Previously, Airtime
would not play anything until the next show started. This also fixes a would not play anything until the next show started. This also fixes a
problem where the metadata on the stream was lost when a file had problem where the metadata on the stream was lost when a file had
cue-in/out values set. Thanks to the Liquidsoap developers for cue-in/out values set. Thanks to the Liquidsoap developers for
implementing the ability to do all of this! implementing the ability to do all of this!
@ -354,28 +354,28 @@ The cool stuff:
- A new "Program Manager" role. A program manager can create shows but - A new "Program Manager" role. A program manager can create shows but
can't change the preferences or modify users. can't change the preferences or modify users.
- No more rebooting after install! Airtime now uses standard SystemV initd - No more rebooting after install! Airtime now uses standard SystemV initd
scripts instead of non-standard daemontools. This also makes for a much scripts instead of non-standard daemontools. This also makes for a much
faster install. faster install.
- Frontend widgets are much easier to use and their theme can be modified - Frontend widgets are much easier to use and their theme can be modified
with CSS (Click here for more info and installation instructions). with CSS (Click here for more info and installation instructions).
- Improved installation - only one command to install on Ubuntu! - Improved installation - only one command to install on Ubuntu!
* Improvements: * Improvements:
- Cumulative time shown on playlists. The Playlist Builder now shows the - Cumulative time shown on playlists. The Playlist Builder now shows the
total time since the beginning of the playlist for each song. total time since the beginning of the playlist for each song.
- "End Time" instead of "Duration". In the Add/Edit Show dialog, we - "End Time" instead of "Duration". In the Add/Edit Show dialog, we
replaced the "Duration" field with "End Time". Users reported that this replaced the "Duration" field with "End Time". Users reported that this
was a much more intuitive way to schedule the show. Duration is still was a much more intuitive way to schedule the show. Duration is still
shown as a read-only field. shown as a read-only field.
- Feedback & promotion system. Airtime now includes a way to send feedback - Feedback & promotion system. Airtime now includes a way to send feedback
and promote your site on the Sourcefabric web page. This will greatly and promote your site on the Sourcefabric web page. This will greatly
enhance our ability to understand who is using the software, which in enhance our ability to understand who is using the software, which in
turn will allow us to make appropriate features and receive grant turn will allow us to make appropriate features and receive grant
funding. funding.
- The show recorder can now instantly cancel a show thanks to the use of - The show recorder can now instantly cancel a show thanks to the use of
RabbitMQ. RabbitMQ.
- Only admins have the ability to delete files now. - Only admins have the ability to delete files now.
- The playout engine now runs with a higher priority. This should help - The playout engine now runs with a higher priority. This should help
prevent any problems with audio skipping. prevent any problems with audio skipping.
- Airtime has been contained. It is now easier to run other apps on the - Airtime has been contained. It is now easier to run other apps on the
same system with Airtime because it no longer messes with the system-wide same system with Airtime because it no longer messes with the system-wide
@ -386,12 +386,12 @@ The cool stuff:
page( above the search box). page( above the search box).
* Bug fixes: * Bug fixes:
- Fixed bug where you couldn't import a file with a name longer than 255 - Fixed bug where you couldn't import a file with a name longer than 255
characters. characters.
- Fixed bug where searching an audio archive of 15K+ files was slow. - Fixed bug where searching an audio archive of 15K+ files was slow.
- Fixed bug where upgrading from more than one version back - Fixed bug where upgrading from more than one version back
(e.g. 1.8.0 -> 1.9.0) did not work. (e.g. 1.8.0 -> 1.9.0) did not work.
- Fixed bug where the wrong file length was reported for very large CBR - Fixed bug where the wrong file length was reported for very large CBR
mp3 files (thanks to mutagen developers for the patch!) mp3 files (thanks to mutagen developers for the patch!)
1.8.2 - June 8, 2011 1.8.2 - June 8, 2011
@ -456,30 +456,30 @@ Highlights:
1.8.0 - April 19, 2011 1.8.0 - April 19, 2011
* The biggest feature of this release is the ability to edit shows. You can * The biggest feature of this release is the ability to edit shows. You can
change everything from Name, Description, and URL, to repeat and change everything from Name, Description, and URL, to repeat and
rebroadcast days. Show instances will be dynamically created or removed as rebroadcast days. Show instances will be dynamically created or removed as
needed. Radio stations will be pleased to know they can now have up to needed. Radio stations will be pleased to know they can now have up to
ten rebroadcast shows too. ten rebroadcast shows too.
* Airtimes calendar now looks, feels and performs better than ever. Loading * Airtimes calendar now looks, feels and performs better than ever. Loading
a station schedule is now five to eight times faster. In our tests of 1.7, a station schedule is now five to eight times faster. In our tests of 1.7,
if the month calendar had shows scheduled for every hour of every day, it if the month calendar had shows scheduled for every hour of every day, it
used to take 16 seconds to load. Now in 1.8 it takes two seconds. used to take 16 seconds to load. Now in 1.8 it takes two seconds.
* It is possible to have up to ten rebroadcast shows now, in 1.7 it was only * It is possible to have up to ten rebroadcast shows now, in 1.7 it was only
up to five. up to five.
* Airtimes new installation script has two options for increased install * Airtimes new installation script has two options for increased install
flexibility: --preserve to keep your existing config files, or --overwrite flexibility: --preserve to keep your existing config files, or --overwrite
to replace your existing config files with new ones. Uninstall no longer to replace your existing config files with new ones. Uninstall no longer
removes Airtime config files or the music storage directory. removes Airtime config files or the music storage directory.
* New improved look & feel of the calendar (thanks to the "FullCalendar" * New improved look & feel of the calendar (thanks to the "FullCalendar"
jQuery project). jQuery project).
* Installation now puts files in standard locations in the Linux file * Installation now puts files in standard locations in the Linux file
hierarchy, which prepares the project to be accepted into Ubuntu and Debian. hierarchy, which prepares the project to be accepted into Ubuntu and Debian.
Also because of our wish to be part of those projects, the default output Also because of our wish to be part of those projects, the default output
stream type is now OGG instead of MP3 -- due to MP3 licensing issues. stream type is now OGG instead of MP3 -- due to MP3 licensing issues.
This configuration can be changed in "/etc/airtime/liquidsoap.conf". This configuration can be changed in "/etc/airtime/liquidsoap.conf".
* You now have the ability to start and stop pypo and the show recorder from * You now have the ability to start and stop pypo and the show recorder from
the command line with the commands "airtime-pypo-start", the command line with the commands "airtime-pypo-start",
"airtime-pypo-stop", "airtime-show-recorder-start", and "airtime-pypo-stop", "airtime-show-recorder-start", and
"airtime-show-recorder-stop". "airtime-show-recorder-stop".
* Bug fixes: * Bug fixes:
- CC-2192 Schedule sent to pypo is not sorted by start time. - CC-2192 Schedule sent to pypo is not sorted by start time.
@ -520,7 +520,7 @@ Highlights:
* Bug fixes: * Bug fixes:
- CC-2082 OGG stream dies after every song when using MPlayer - CC-2082 OGG stream dies after every song when using MPlayer
- CC-1894 Warn users about time zone differences or clock drift problems on - CC-1894 Warn users about time zone differences or clock drift problems on
the server the server
- CC-2058 Utilities are not in the system $PATH - CC-2058 Utilities are not in the system $PATH
- CC-2051 Unable to change user password - CC-2051 Unable to change user password
- CC-2030 Icon needed for Cue In/Out - CC-2030 Icon needed for Cue In/Out
@ -531,7 +531,7 @@ Bug fixes:
* CC-1973 Liquidsoap crashes after multi-day playout * CC-1973 Liquidsoap crashes after multi-day playout
* CC-1970 API key fix (Security fix) - Each time you run the install scripts, * CC-1970 API key fix (Security fix) - Each time you run the install scripts,
a new API key is now generated. a new API key is now generated.
* CC-1992 Editing metadata goes blank on 'submit' * CC-1992 Editing metadata goes blank on 'submit'
* CC-1993 ui start time and song time unsynchronized * CC-1993 ui start time and song time unsynchronized
1.6.0 - Feb 14, 2011 1.6.0 - Feb 14, 2011

View File

@ -7,5 +7,5 @@ To update the Airtime translations:
- Commit the updated files. - Commit the updated files.
- Push to GitHub. - Push to GitHub.
- Transifex will then pick up the updated files in about 24 hours, and they'll be available for translation there. - Transifex will then pick up the updated files in about 24 hours, and they'll be available for translation there.
- After translators have updated strings, they'll be automatically downloaded and committed to our git repo by - After translators have updated strings, they'll be automatically downloaded and committed to our git repo by
a script running here at Sourcefabric (contact Andrey). a script running here at Sourcefabric (contact Andrey).

View File

@ -1,13 +1,13 @@
<?PHP <?PHP
/* /*
The purpose of this script is to take a file from cc_files table, and insert it into The purpose of this script is to take a file from cc_files table, and insert it into
the schedule table. DB columns at the time of writing are the schedule table. DB columns at the time of writing are
starts | ends | file_id | clip_length | fade_in | fade_out | cue_in | cue_out | media_item_played | instance_id starts | ends | file_id | clip_length | fade_in | fade_out | cue_in | cue_out | media_item_played | instance_id
an example of data in this row is: an example of data in this row is:
"9" | "2012-02-29 17:10:00" | "2012-02-29 17:15:05.037166" | 1 | "00:05:05.037166" | "00:00:00" | "00:00:00" | "00:00:00" | "00:05:05.037166" | FALSE | 5 "9" | "2012-02-29 17:10:00" | "2012-02-29 17:15:05.037166" | 1 | "00:05:05.037166" | "00:00:00" | "00:00:00" | "00:00:00" | "00:05:05.037166" | FALSE | 5
@ -19,25 +19,25 @@ function query($conn, $query){
echo "Error executing query $query.\n"; echo "Error executing query $query.\n";
exit(1); exit(1);
} }
return $result; return $result;
} }
function getFileFromCcFiles($conn){ function getFileFromCcFiles($conn){
$query = "SELECT * from cc_files LIMIT 2"; $query = "SELECT * from cc_files LIMIT 2";
$result = query($conn, $query); $result = query($conn, $query);
$files = array(); $files = array();
while ($row = pg_fetch_array($result)) { while ($row = pg_fetch_array($result)) {
$files[] = $row; $files[] = $row;
} }
if (count($files) == 0){ if (count($files) == 0){
echo "Library is empty. Could not choose random file."; echo "Library is empty. Could not choose random file.";
exit(1); exit(1);
} }
return $files; return $files;
} }
@ -60,7 +60,7 @@ function insertIntoCcShow($conn){
while ($row = pg_fetch_array($result)) { while ($row = pg_fetch_array($result)) {
$show_id = $row["currval"]; $show_id = $row["currval"];
} }
return $show_id; return $show_id;
} }
@ -70,7 +70,7 @@ function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $files){
* Column values: * Column values:
* starts | ends | show_id | record | rebroadcast | instance_id | file_id | time_filled | last_scheduled | modified_instance * starts | ends | show_id | record | rebroadcast | instance_id | file_id | time_filled | last_scheduled | modified_instance
* */ * */
$nowDateTime = new DateTime("now", new DateTimeZone("UTC")); $nowDateTime = new DateTime("now", new DateTimeZone("UTC"));
$now = $nowDateTime->format("Y-m-d H:i:s"); $now = $nowDateTime->format("Y-m-d H:i:s");
@ -79,7 +79,7 @@ function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $files){
$values = "('$starts', '$ends', $show_id, 0, 0, NULL, NULL, TIMESTAMP '$ends' - TIMESTAMP '$starts', '$now', 'f')"; $values = "('$starts', '$ends', $show_id, 0, 0, NULL, NULL, TIMESTAMP '$ends' - TIMESTAMP '$starts', '$now', 'f')";
$query = "INSERT INTO cc_show_instances $columns values $values "; $query = "INSERT INTO cc_show_instances $columns values $values ";
echo $query.PHP_EOL; echo $query.PHP_EOL;
$result = query($conn, $query); $result = query($conn, $query);
$query = "SELECT currval('cc_show_instances_id_seq');"; $query = "SELECT currval('cc_show_instances_id_seq');";
@ -92,7 +92,7 @@ function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $files){
while ($row = pg_fetch_array($result)) { while ($row = pg_fetch_array($result)) {
$show_instance_id = $row["currval"]; $show_instance_id = $row["currval"];
} }
return $show_instance_id; return $show_instance_id;
} }
@ -102,9 +102,9 @@ function insertIntoCcShowInstances($conn, $show_id, $starts, $ends, $files){
*/ */
function insertIntoCcSchedule($conn, $files, $show_instance_id, $p_starts, $p_ends){ function insertIntoCcSchedule($conn, $files, $show_instance_id, $p_starts, $p_ends){
$columns = "(starts, ends, file_id, clip_length, fade_in, fade_out, cue_in, cue_out, media_item_played, instance_id)"; $columns = "(starts, ends, file_id, clip_length, fade_in, fade_out, cue_in, cue_out, media_item_played, instance_id)";
$starts = $p_starts; $starts = $p_starts;
foreach($files as $file){ foreach($files as $file){
$endsDateTime = new DateTime($starts, new DateTimeZone("UTC")); $endsDateTime = new DateTime($starts, new DateTimeZone("UTC"));
@ -115,9 +115,9 @@ function insertIntoCcSchedule($conn, $files, $show_instance_id, $p_starts, $p_en
$values = "('$starts', '$ends', $file[id], '$file[length]', '00:00:00', '00:00:00', '00:00:00', '$file[length]', 'f', $show_instance_id)"; $values = "('$starts', '$ends', $file[id], '$file[length]', '00:00:00', '00:00:00', '00:00:00', '$file[length]', 'f', $show_instance_id)";
$query = "INSERT INTO cc_schedule $columns VALUES $values"; $query = "INSERT INTO cc_schedule $columns VALUES $values";
echo $query.PHP_EOL; echo $query.PHP_EOL;
$starts = $ends; $starts = $ends;
$result = query($conn, $query); $result = query($conn, $query);
} }
} }
@ -131,7 +131,7 @@ function getEndTime($startDateTime, $p_files){
foreach ($p_files as $file){ foreach ($p_files as $file){
$startDateTime->add(getDateInterval($file['length'])); $startDateTime->add(getDateInterval($file['length']));
} }
return $startDateTime; return $startDateTime;
} }
@ -142,7 +142,7 @@ function rabbitMqNotify(){
echo "Contacting $url".PHP_EOL; echo "Contacting $url".PHP_EOL;
$ch = curl_init($url); $ch = curl_init($url);
curl_exec($ch); curl_exec($ch);
curl_close($ch); curl_close($ch);
} }
$conn = pg_connect("host=localhost port=5432 dbname=airtime user=airtime password=airtime"); $conn = pg_connect("host=localhost port=5432 dbname=airtime user=airtime password=airtime");
@ -152,9 +152,9 @@ if (!$conn) {
} }
if (count($argv) > 1){ if (count($argv) > 1){
if ($argv[1] == "--clean"){ if ($argv[1] == "--clean"){
$tables = array("cc_schedule", "cc_show_instances", "cc_show"); $tables = array("cc_schedule", "cc_show_instances", "cc_show");
foreach($tables as $table){ foreach($tables as $table){
$query = "DELETE FROM $table"; $query = "DELETE FROM $table";
echo $query.PHP_EOL; echo $query.PHP_EOL;
@ -162,9 +162,9 @@ if (count($argv) > 1){
} }
rabbitMqNotify(); rabbitMqNotify();
exit(0); exit(0);
} else { } else {
$str = <<<EOD $str = <<<EOD
This script schedules a file to play 30 seconds in the future. It This script schedules a file to play 30 seconds in the future. It
modifies the database tables cc_schedule, cc_show_instances and cc_show. modifies the database tables cc_schedule, cc_show_instances and cc_show.
You can clean up these tables using the --clean option. You can clean up these tables using the --clean option.
EOD; EOD;
@ -178,7 +178,7 @@ $startDateTime = new DateTime("now + 30sec", new DateTimeZone("UTC"));
$starts = $startDateTime->format("Y-m-d H:i:s"); $starts = $startDateTime->format("Y-m-d H:i:s");
//$ends = $endDateTime->format("Y-m-d H:i:s"); //$ends = $endDateTime->format("Y-m-d H:i:s");
$files = getFileFromCcFiles($conn); $files = getFileFromCcFiles($conn);
$show_id = insertIntoCcShow($conn); $show_id = insertIntoCcShow($conn);
$endDateTime = getEndTime(clone $startDateTime, $files); $endDateTime = getEndTime(clone $startDateTime, $files);

View File

@ -30,7 +30,7 @@ class AirtimeMediaMonitorBootstrap:
config = ConfigObj("/etc/airtime/airtime.conf") config = ConfigObj("/etc/airtime/airtime.conf")
self.api_client = apc.api_client_factory(config) self.api_client = apc.api_client_factory(config)
""" """
try: try:
logging.config.fileConfig("logging.cfg") logging.config.fileConfig("logging.cfg")
except Exception, e: except Exception, e:

View File

@ -90,7 +90,7 @@ fi
rm -rf liquidsoap-full rm -rf liquidsoap-full
git clone https://github.com/savonet/liquidsoap-full git clone https://github.com/savonet/liquidsoap-full
cd liquidsoap-full cd liquidsoap-full
git checkout master git checkout master
make init make init
make update make update

View File

@ -26,7 +26,7 @@ build_env () {
echo "Please use -u to assign sudo username before build environments." echo "Please use -u to assign sudo username before build environments."
exit 1 exit 1
fi fi
echo "build_env $1" echo "build_env $1"
#exec > >(tee ./liquidsoap_compile_logs/build_env_$1.log) #exec > >(tee ./liquidsoap_compile_logs/build_env_$1.log)
os=`echo $1 | awk '/(debian)/'` os=`echo $1 | awk '/(debian)/'`
@ -40,7 +40,7 @@ build_env () {
useradd tmp useradd tmp
echo "User tmp is created." echo "User tmp is created."
fi fi
apt-get update apt-get update
apt-get --force-yes -y install debootstrap dchroot apt-get --force-yes -y install debootstrap dchroot
echo [$1] > /etc/schroot/chroot.d/$1.conf echo [$1] > /etc/schroot/chroot.d/$1.conf
@ -87,7 +87,7 @@ compile_liq () {
else else
mv ./liquidsoap-compile_logs/compile_liq_$1.log ./liquidsoap-compile_logs/fail_to_compile_liq_$1.log mv ./liquidsoap-compile_logs/compile_liq_$1.log ./liquidsoap-compile_logs/fail_to_compile_liq_$1.log
fi fi
} }
os_versions=("ubuntu_lucid_32" "ubuntu_lucid_64" "ubuntu_precise_32" "ubuntu_precise_64" "ubuntu_quantal_32" "ubuntu_quantal_64" "ubuntu_raring_32" "ubuntu_raring_64" "debian_squeeze_32" "debian_squeeze_64" "debian_wheezy_32" "debian_wheezy_64") os_versions=("ubuntu_lucid_32" "ubuntu_lucid_64" "ubuntu_precise_32" "ubuntu_precise_64" "ubuntu_quantal_32" "ubuntu_quantal_64" "ubuntu_raring_32" "ubuntu_raring_64" "debian_squeeze_32" "debian_squeeze_64" "debian_wheezy_32" "debian_wheezy_64")
@ -147,7 +147,7 @@ do
compile_liq ${os_versions[$i]} | tee ./liquidsoap-compile_logs/compile_liq_${os_versions[$i]}.log compile_liq ${os_versions[$i]} | tee ./liquidsoap-compile_logs/compile_liq_${os_versions[$i]}.log
flag=0 flag=0
fi fi
done done
if [ $flag = 1 ];then if [ $flag = 1 ];then
echo "Unsupported Platform from:" echo "Unsupported Platform from:"
for k in "${os_versions[@]}" for k in "${os_versions[@]}"

View File

@ -74,7 +74,7 @@ tar -czf $target_file \
--exclude dev_tools \ --exclude dev_tools \
--exclude vendor/phing \ --exclude vendor/phing \
--exclude vendor/simplepie/simplepie/tests \ --exclude vendor/simplepie/simplepie/tests \
libretime-${suffix} libretime-${suffix}
echo " Done" echo " Done"
popd popd

View File

@ -1,5 +1,5 @@
[merge "pofile"] [merge "pofile"]
name = Gettext merge driver name = Gettext merge driver
driver = git merge-po %O %A %B driver = git merge-po %O %A %B

View File

@ -1,6 +1,6 @@
#!/bin/sh #!/bin/sh
# #
# https://gist.github.com/mezis/1605647 # https://gist.github.com/mezis/1605647
# by Julien Letessier (mezis) # by Julien Letessier (mezis)
# #
# Custom Git merge driver - merges PO files using msgcat(1) # Custom Git merge driver - merges PO files using msgcat(1)
@ -8,15 +8,15 @@
# - Install gettext # - Install gettext
# #
# - Place this script in your PATH # - Place this script in your PATH
# #
# - Add this to your .git/config : # - Add this to your .git/config :
# #
# [merge "pofile"] # [merge "pofile"]
# name = Gettext merge driver # name = Gettext merge driver
# driver = git merge-po %O %A %B # driver = git merge-po %O %A %B
# #
# - Add this to .gitattributes : # - Add this to .gitattributes :
# #
# *.po merge=pofile # *.po merge=pofile
# *.pot merge=pofile # *.pot merge=pofile
# #

View File

@ -5,7 +5,7 @@ if [[ $EUID -ne 0 ]]; then
fi fi
usage () { usage () {
echo "Use --enable <user> or --disable flag. Enable is to set up environment" echo "Use --enable <user> or --disable flag. Enable is to set up environment"
echo "for specified user. --disable is to reset it back to pypo user" echo "for specified user. --disable is to reset it back to pypo user"
} }
@ -28,7 +28,7 @@ elif [ "$1" = "--disable" ]; then
echo "Changing ownership to user $1" echo "Changing ownership to user $1"
chmod 644 /etc/airtime/airtime.conf chmod 644 /etc/airtime/airtime.conf
chown -Rv $user:$user /var/tmp/airtime/pypo/ chown -Rv $user:$user /var/tmp/airtime/pypo/
chmod -v a+r /etc/airtime/api_client.cfg chmod -v a+r /etc/airtime/api_client.cfg
/etc/init.d/airtime-playout stop-liquidsoap /etc/init.d/airtime-playout stop-liquidsoap

View File

@ -4,13 +4,13 @@
<!-- Bootstrap CSS --> <!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous"> <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/css/bootstrap.min.css" integrity="sha384-9aIt2nRpC12Uk9gS9baDl411NQApFmC26EwAOH8WgZl5MYYxFfc+NcPb1dKGj7Sk" crossorigin="anonymous">
<!-- Custom fonts, icons for this template --> <!-- Custom fonts, icons for this template -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" rel="stylesheet" type="text/css"> <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Merriweather:400,300,300italic,400italic,700,700italic,900,900italic' rel='stylesheet' type='text/css'> <link href='https://fonts.googleapis.com/css?family=Merriweather:400,300,300italic,400italic,700,700italic,900,900italic' rel='stylesheet' type='text/css'>
<!-- Custom styles for this template --> <!-- Custom styles for this template -->
<link href="/css/creative.min.css" rel="stylesheet"> <link href="/css/creative.min.css" rel="stylesheet">
<title>{{ site.title }} - {{ page.title }}</title> <title>{{ site.title }} - {{ page.title }}</title>

View File

@ -1,6 +1,6 @@
<nav class="navbar navbar-expand-lg navbar-light fixed-top navbar-shrink" id="mainNav"> <nav class="navbar navbar-expand-lg navbar-light fixed-top navbar-shrink" id="mainNav">
<div class="container"> <div class="container">
<a class="navbar-brand js-scroll-trigger" href="/index"> <a class="navbar-brand js-scroll-trigger" href="/index">
{{ site.title }} </a> {{ site.title }} </a>
<button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"> <button class="navbar-toggler navbar-toggler-right" type="button" data-toggle="collapse" data-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span> <span class="navbar-toggler-icon"></span>

View File

@ -8,11 +8,11 @@
<script> <script>
// Set a variable for our button element. // Set a variable for our button element.
const scrollToTopButton = document.getElementById('js-top'); const scrollToTopButton = document.getElementById('js-top');
const scrollFunc = () => { const scrollFunc = () => {
// Get the current scroll value // Get the current scroll value
let y = window.scrollY; let y = window.scrollY;
// If the scroll value is greater than the window height, let's add a class to the scroll-to-top button to show it! // If the scroll value is greater than the window height, let's add a class to the scroll-to-top button to show it!
if (y > 0) { if (y > 0) {
scrollToTopButton.className = "top-link show"; scrollToTopButton.className = "top-link show";
@ -24,7 +24,7 @@
const scrollToTop = () => { const scrollToTop = () => {
// Let's set a variable for the number of pixels we are from the top of the document. // Let's set a variable for the number of pixels we are from the top of the document.
const c = document.documentElement.scrollTop || document.body.scrollTop; const c = document.documentElement.scrollTop || document.body.scrollTop;
// If that number is greater than 0, we'll scroll back to 0, or the top of the document. // If that number is greater than 0, we'll scroll back to 0, or the top of the document.
// We'll also animate that scroll with requestAnimationFrame: // We'll also animate that scroll with requestAnimationFrame:
// https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame // https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame
@ -41,4 +41,3 @@
scrollToTop(); scrollToTop();
} }
</script> </script>

View File

@ -1,14 +1,14 @@
--- ---
layout: default layout: default
--- ---
<!-- Promo Section --> <!-- Promo Section -->
<section class="bg-primary"> <section class="bg-primary">
<div class="container"> <div class="container">
<div class="d-flex mh-25rem pt-11 py-6"> <div class="d-flex mh-25rem pt-11 py-6">
<div class="align-self-center"> <div class="align-self-center">
<h1 class="text-white font-weight-light mb-3">{{ page.title }}</h1> <h1 class="text-white font-weight-light mb-3">{{ page.title }}</h1>
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb breadcrumb-light"> <ol class="breadcrumb breadcrumb-light">
<li class="breadcrumb-item"><a href="/">Home</a></li> <li class="breadcrumb-item"><a href="/">Home</a></li>
@ -20,7 +20,7 @@ layout: default
</div> </div>
</div> </div>
</div> </div>
<!-- SVG BG --> <!-- SVG BG -->
<svg class="position-absolute bottom-0 left-0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1920 323" enable-background="new 0 0 1920 323" xml:space="preserve"> <svg class="position-absolute bottom-0 left-0" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 1920 323" enable-background="new 0 0 1920 323" xml:space="preserve">
<polygon fill="#ffffff" style="fill-opacity: .05;" points="-0.5,322.5 -0.5,121.5 658.3,212.3 "></polygon> <polygon fill="#ffffff" style="fill-opacity: .05;" points="-0.5,322.5 -0.5,121.5 658.3,212.3 "></polygon>

View File

@ -2,13 +2,13 @@
<html lang="en"> <html lang="en">
<head> <head>
{% include head.html %} {% include head.html %}
</head> </head>
<body id="page-top"> <body id="page-top">
<!-- Navigation --> <!-- Navigation -->
{% include navbar.html %} {% include navbar.html %}
<!-- Scroll to Top link --> <!-- Scroll to Top link -->
<a class="top-link hide" href="" id="js-top"> <a class="top-link hide" href="" id="js-top">
<svg class="bi bi-arrow-up-circle-fill" width="4em" height="4em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg"> <svg class="bi bi-arrow-up-circle-fill" width="4em" height="4em" viewBox="0 0 16 16" fill="currentColor" xmlns="http://www.w3.org/2000/svg">
@ -16,9 +16,9 @@
</svg> </svg>
<span class="screen-reader-text">Back to top</span> <span class="screen-reader-text">Back to top</span>
</a> </a>
{{content}} {{content}}
{% include footer.html %} {% include footer.html %}
{% include scripts.html %} {% include scripts.html %}

View File

@ -1,7 +1,7 @@
--- ---
layout: default layout: default
--- ---
<style> <style>
header.masthead { header.masthead {
padding-top: 10rem; padding-top: 10rem;
@ -27,7 +27,7 @@ layout: default
</div> </div>
</div> </div>
</header> </header>
<!-- Features Block --> <!-- Features Block -->
<section id="features"> <section id="features">
<div class="container"> <div class="container">
@ -150,7 +150,7 @@ layout: default
</div> </div>
</div> </div>
</section> </section>
<!-- "Our Biggest Fans" Section --> <!-- "Our Biggest Fans" Section -->
<section class="" id="biggest-fans"> <section class="" id="biggest-fans">
<div class="container text-center"> <div class="container text-center">

View File

@ -1,40 +1,40 @@
/*! /*!
* Start Bootstrap - Libretime v1.0.0 () * Start Bootstrap - Libretime v1.0.0 ()
* Copyright 2013-2018 * Copyright 2013-2018
* Licensed under MIT (https://github.com/BlackrockDigital/libretime-website/blob/master/LICENSE) * Licensed under MIT (https://github.com/BlackrockDigital/libretime-website/blob/master/LICENSE)
*/ */
body,html{ body,html{
width:100%;height:100% width:100%;height:100%
} }
body{ body{
font-family:Merriweather,'Helvetica Neue',Arial,sans-serif; font-family:Merriweather,'Helvetica Neue',Arial,sans-serif;
padding-top: 57px; padding-top: 57px;
} }
hr{ hr{
max-width:auto;border-width:2px;border-color:#f05f40 max-width:auto;border-width:2px;border-color:#f05f40
} }
hr.light{ hr.light{
border-color:#fff border-color:#fff
} }
img{ img{
width:100%; width:100%;
max-width: 600px; max-width: 600px;
} }
a{ a{
color:#f05f40; color:#f05f40;
-webkit-transition:all .2s; -webkit-transition:all .2s;
transition:all .2s; transition:all .2s;
} }
a:hover{ a:hover{
color:#f05f40 color:#f05f40
} }
h1,h2,h3,h4,h5,h6{ h1,h2,h3,h4,h5,h6{
font-family:'Open Sans','Helvetica Neue',Arial,sans-serif; font-family:'Open Sans','Helvetica Neue',Arial,sans-serif;
} }
@ -58,34 +58,34 @@ th{
text-align: center; text-align: center;
color: white; color: white;
} }
tr, td{ tr, td{
padding: 5px; padding: 5px;
text-align: left; text-align: left;
border: 2px solid #f05f40 border: 2px solid #f05f40
} }
/* Theme Colors */ /* Theme Colors */
.bg-primary{ .bg-primary{
background-color:#f05f40!important background-color:#f05f40!important
} }
.bg-dark{ .bg-dark{
background-color:#212529!important background-color:#212529!important
} }
.footer-dark{ .footer-dark{
background-color:#212529!important; background-color:#212529!important;
padding:2rem 0 padding:2rem 0
} }
.text-faded{ .text-faded{
color:rgba(255,255,255,.9) color:rgba(255,255,255,.9)
} }
div.text-footer{ div.text-footer{
text-align: center; text-align: center;
} }
/* Changed padding */ /* Changed padding */
section{padding:2rem 0} section{padding:2rem 0}
@ -98,7 +98,7 @@ img::-moz-selection{color:#fff;background:0 0}
#mainNav{ #mainNav{
border-bottom:1px solid rgba(33,37,41,.1);background-color:#fff;font-family:'Open Sans','Helvetica Neue',Arial,sans-serif;-webkit-transition:all .2s;transition:all .2s border-bottom:1px solid rgba(33,37,41,.1);background-color:#fff;font-family:'Open Sans','Helvetica Neue',Arial,sans-serif;-webkit-transition:all .2s;transition:all .2s
} }
#mainNav .navbar-brand{ #mainNav .navbar-brand{
font-weight:700; font-weight:700;
@ -106,7 +106,7 @@ img::-moz-selection{color:#fff;background:0 0}
color:#f05f40; color:#f05f40;
font-family:'Open Sans','Helvetica Neue',Arial,sans-serif font-family:'Open Sans','Helvetica Neue',Arial,sans-serif
} }
#mainNav .navbar-brand:focus, #mainNav .navbar-brand:focus,
#mainNav .navbar-brand:hover{color:#f05f40} #mainNav .navbar-brand:hover{color:#f05f40}
#mainNav .navbar-nav>li.nav-item>a.nav-link, #mainNav .navbar-nav>li.nav-item>a.nav-link,
@ -123,7 +123,7 @@ img::-moz-selection{color:#fff;background:0 0}
@media (min-width:992px){ @media (min-width:992px){
#mainNav{border-color:transparent;background-color:transparent #mainNav{border-color:transparent;background-color:transparent
} }
#mainNav .navbar-brand{color:rgba(255,255,255,.7)} #mainNav .navbar-brand{color:rgba(255,255,255,.7)}
#mainNav .navbar-brand:focus,#mainNav .navbar-brand:hover{color:#fff} #mainNav .navbar-brand:focus,#mainNav .navbar-brand:hover{color:#fff}
#mainNav .navbar-nav>li.nav-item>a.nav-link{padding:.5rem 1rem} #mainNav .navbar-nav>li.nav-item>a.nav-link{padding:.5rem 1rem}
@ -204,7 +204,7 @@ header.masthead p{font-weight:300}
.btn-primary:active,.btn-primary:focus{ .btn-primary:active,.btn-primary:focus{
-webkit-box-shadow:0 0 0 .2rem rgba(240,95,64,.5)!important;box-shadow:0 0 0 .2rem rgba(240,95,64,.5)!important -webkit-box-shadow:0 0 0 .2rem rgba(240,95,64,.5)!important;box-shadow:0 0 0 .2rem rgba(240,95,64,.5)!important
} }
.btn-outline-full-width{border:1px solid #888;margin:5px;width:100%} .btn-outline-full-width{border:1px solid #888;margin:5px;width:100%}
/* Blockquotes */ /* Blockquotes */
@ -215,12 +215,12 @@ font-size: .9rem;
margin: 10px; margin: 10px;
padding: 10px 20px; padding: 10px 20px;
} }
blockquote p { blockquote p {
margin: 0; margin: 0;
line-height: 25px; line-height: 25px;
} }
blockquote .small { blockquote .small {
display: block; display: block;
font-size: 80%; font-size: 80%;
@ -250,7 +250,7 @@ padding: 10px 20px;
bottom: 0; bottom: 0;
right: 0; right: 0;
display: inline-flex; display: inline-flex;
cursor: pointer; cursor: pointer;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
@ -266,7 +266,7 @@ padding: 10px 20px;
visibility: visible; visibility: visible;
opacity: 1; opacity: 1;
} }
.hide { .hide {
visibility: hidden; visibility: hidden;
opacity: 0; opacity: 0;
@ -283,12 +283,12 @@ padding: 10px 20px;
overflow: hidden; overflow: hidden;
word-wrap: normal !important; word-wrap: normal !important;
clip: rect(1px, 1px, 1px, 1px); clip: rect(1px, 1px, 1px, 1px);
&:focus { &:focus {
display: block; display: block;
top: 5px; top: 5px;
left: 5px; left: 5px;
z-index: 100000; z-index: 100000;
clip-path: none; clip-path: none;
background-color: #eee; background-color: #eee;
padding: 15px 23px 14px; padding: 15px 23px 14px;

View File

@ -139,4 +139,4 @@ title: Docs
</div> </div>
</section> </section>
</main> </main>

View File

@ -8,7 +8,7 @@ title: Search
<div class="d-flex mh-25rem pt-11 py-6"> <div class="d-flex mh-25rem pt-11 py-6">
<div class="align-self-center"> <div class="align-self-center">
<h1 class="text-white font-weight-light mb-3">{{ page.title }}</h1> <h1 class="text-white font-weight-light mb-3">{{ page.title }}</h1>
<nav aria-label="breadcrumb"> <nav aria-label="breadcrumb">
<ol class="breadcrumb breadcrumb-light"> <ol class="breadcrumb breadcrumb-light">
<li class="breadcrumb-item"><a href="/">Home</a></li> <li class="breadcrumb-item"><a href="/">Home</a></li>

View File

@ -22,7 +22,7 @@ echo "...Done"
set -e set -e
### ###
# ! NOTE: If you run into errors resolving the archives when running apt-get update, # ! NOTE: If you run into errors resolving the archives when running apt-get update,
# clear your /var/cache/lxc directory and retry. # clear your /var/cache/lxc directory and retry.
### ###

View File

@ -31,7 +31,7 @@ patch -f /var/lib/pgsql/data/pg_hba.conf << EOD
--- pg_hba.conf.orig 2020-12-19 13:10:46.828960307 +0000 --- pg_hba.conf.orig 2020-12-19 13:10:46.828960307 +0000
+++ pg_hba.conf 2020-12-19 13:11:37.356290128 +0000 +++ pg_hba.conf 2020-12-19 13:11:37.356290128 +0000
@@ -78,10 +78,11 @@ @@ -78,10 +78,11 @@
# "local" is for Unix domain socket connections only # "local" is for Unix domain socket connections only
local all all peer local all all peer
+local all all md5 +local all all md5
@ -153,7 +153,7 @@ echo 'date.timezone=Europe/Zurich' >> /etc/php.d/timezone.ini
systemctl restart httpd systemctl restart httpd
# icecast needs to be available to everyone # icecast needs to be available to everyone
sed -i -e 's@<bind-address>127.0.0.1</bind-address>@<bind-address>0.0.0.0</bind-address>@' /etc/icecast.xml sed -i -e 's@<bind-address>127.0.0.1</bind-address>@<bind-address>0.0.0.0</bind-address>@' /etc/icecast.xml
systemctl enable --now icecast systemctl enable --now icecast
# let em use alsa # let em use alsa

View File

@ -21,9 +21,9 @@ endobj
endobj endobj
7 0 obj 7 0 obj
<< <<
/AIMetaData 9 0 R /AIPrivateData1 10 0 R /AIPrivateData2 8 0 R /CreatorVersion 15 /AIMetaData 9 0 R /AIPrivateData1 10 0 R /AIPrivateData2 8 0 R /CreatorVersion 15
/ContainerVersion 9 /ContainerVersion 9
/RoundtripVersion 15 /RoundtripVersion 15
/NumBlock 2 >> /NumBlock 2 >>
endobj endobj
9 0 obj 9 0 obj
@ -43,7 +43,7 @@ stream
%AI3_TileBox:0 0 246 -68 %AI3_TileBox:0 0 246 -68
%AI3_TemplateBox:123 -34 123 -34 %AI3_TemplateBox:123 -34 123 -34
%AI3_DocumentPreview: None %AI3_DocumentPreview: None
%AI5_ArtSize: 246 68 %AI5_ArtSize: 246 68
%AI5_NumLayers: 1 %AI5_NumLayers: 1
%AI5_FileFormat 2.0 %AI5_FileFormat 2.0
%AI9_ColorModel: 2 %AI9_ColorModel: 2

View File

@ -19,36 +19,36 @@ QUEUE = "airtime-uploads"
""" A message listener class that waits for messages from Airtime through RabbitMQ """ A message listener class that waits for messages from Airtime through RabbitMQ
notifying us about new uploads. notifying us about new uploads.
This is probably the most important class in this application. It connects This is probably the most important class in this application. It connects
to RabbitMQ (or an AMQP server) and listens for messages that notify us to RabbitMQ (or an AMQP server) and listens for messages that notify us
when a user uploads a new file to Airtime, either through the web interface when a user uploads a new file to Airtime, either through the web interface
or via FTP (on Airtime Pro). When we get a notification, we spawn a child or via FTP (on Airtime Pro). When we get a notification, we spawn a child
process that extracts the uploaded audio file's metadata and moves it into process that extracts the uploaded audio file's metadata and moves it into
Airtime's music library directory. Lastly, the extracted metadata is Airtime's music library directory. Lastly, the extracted metadata is
reported back to the Airtime web application. reported back to the Airtime web application.
There's a couple of Very Important technical details and constraints that you There's a couple of Very Important technical details and constraints that you
need to know if you're going to work on this code: need to know if you're going to work on this code:
1) airtime_analyzer is designed so it doesn't have to run on the same 1) airtime_analyzer is designed so it doesn't have to run on the same
computer as the web server. It just needs access to your Airtime library computer as the web server. It just needs access to your Airtime library
folder (stor). folder (stor).
2) airtime_analyzer is multi-tenant - One process can be used for many 2) airtime_analyzer is multi-tenant - One process can be used for many
Airtime instances. It's designed NOT to know about whether it's running Airtime instances. It's designed NOT to know about whether it's running
in a single tenant or multi-tenant environment. All the information it in a single tenant or multi-tenant environment. All the information it
needs to import a file into an Airtime instance is passed in via those needs to import a file into an Airtime instance is passed in via those
RabbitMQ messages. RabbitMQ messages.
3) We're using a "topic exchange" for the new upload notification RabbitMQ 3) We're using a "topic exchange" for the new upload notification RabbitMQ
messages. This means if we run several airtime_analyzer processes on messages. This means if we run several airtime_analyzer processes on
different computers, RabbitMQ will do round-robin dispatching of the different computers, RabbitMQ will do round-robin dispatching of the
file notification. This is cheap, easy load balancing and file notification. This is cheap, easy load balancing and
redundancy for us. You can even run multiple airtime_analyzer processes redundancy for us. You can even run multiple airtime_analyzer processes
on one machine if you want. on one machine if you want.
4) We run the actual work (metadata analysis and file moving) in a separate 4) We run the actual work (metadata analysis and file moving) in a separate
child process so that if it crashes, we can stop RabbitMQ from resending child process so that if it crashes, we can stop RabbitMQ from resending
the file notification message to another airtime_analyzer process (NACK), the file notification message to another airtime_analyzer process (NACK),
which would otherwise cause cascading failure. We also do this so that we which would otherwise cause cascading failure. We also do this so that we
can report the problem file to the Airtime web interface ("import failed"). can report the problem file to the Airtime web interface ("import failed").
So that is a quick overview of the design constraints for this application, and So that is a quick overview of the design constraints for this application, and
@ -164,10 +164,10 @@ class MessageListener:
api_key = "" api_key = ""
file_prefix = "" file_prefix = ""
""" Spin up a worker process. We use the multiprocessing module and multiprocessing.Queue """ Spin up a worker process. We use the multiprocessing module and multiprocessing.Queue
to pass objects between the processes so that if the analyzer process crashes, it does not to pass objects between the processes so that if the analyzer process crashes, it does not
take down the rest of the daemon and we NACK that message so that it doesn't get take down the rest of the daemon and we NACK that message so that it doesn't get
propagated to other airtime_analyzer daemons (eg. running on other servers). propagated to other airtime_analyzer daemons (eg. running on other servers).
We avoid cascading failure this way. We avoid cascading failure this way.
""" """
try: try:
@ -208,8 +208,8 @@ class MessageListener:
except Exception as e: except Exception as e:
logging.exception(e) logging.exception(e)
""" If ANY exception happens while processing a file, we're going to NACK to the """ If ANY exception happens while processing a file, we're going to NACK to the
messaging server and tell it to remove the message from the queue. messaging server and tell it to remove the message from the queue.
(NACK is a negative acknowledgement. We could use ACK instead, but this might come (NACK is a negative acknowledgement. We could use ACK instead, but this might come
in handy in the future.) in handy in the future.)
Exceptions in this context are unexpected, unhandled errors. We try to recover Exceptions in this context are unexpected, unhandled errors. We try to recover

View File

@ -216,7 +216,7 @@ class StatusReporter:
# r = requests.Request(method='PUT', url=callback_url, data=put_payload, # r = requests.Request(method='PUT', url=callback_url, data=put_payload,
# auth=requests.auth.HTTPBasicAuth(api_key, '')) # auth=requests.auth.HTTPBasicAuth(api_key, ''))
""" """
r = requests.Request(method='PUT', url=callback_url, data=put_payload, r = requests.Request(method='PUT', url=callback_url, data=put_payload,
auth=requests.auth.HTTPBasicAuth(api_key, '')) auth=requests.auth.HTTPBasicAuth(api_key, ''))
StatusReporter._send_http_request(r) StatusReporter._send_http_request(r)
@ -235,11 +235,11 @@ class StatusReporter:
StatusReporter._ipc_queue.put(r.prepare()) StatusReporter._ipc_queue.put(r.prepare())
""" """
""" """
# Encode the audio metadata as json and post it back to the callback_url # Encode the audio metadata as json and post it back to the callback_url
put_payload = json.dumps(audio_metadata) put_payload = json.dumps(audio_metadata)
logging.debug("sending http put with payload: " + put_payload) logging.debug("sending http put with payload: " + put_payload)
r = requests.put(callback_url, data=put_payload, r = requests.put(callback_url, data=put_payload,
auth=requests.auth.HTTPBasicAuth(api_key, ''), auth=requests.auth.HTTPBasicAuth(api_key, ''),
timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) timeout=StatusReporter._HTTP_REQUEST_TIMEOUT)
logging.debug("HTTP request returned status: " + str(r.status_code)) logging.debug("HTTP request returned status: " + str(r.status_code))
@ -266,7 +266,7 @@ class StatusReporter:
put_payload = json.dumps(audio_metadata) put_payload = json.dumps(audio_metadata)
# logging.debug("sending http put with payload: " + put_payload) # logging.debug("sending http put with payload: " + put_payload)
""" """
r = requests.put(callback_url, data=put_payload, r = requests.put(callback_url, data=put_payload,
auth=requests.auth.HTTPBasicAuth(api_key, ''), auth=requests.auth.HTTPBasicAuth(api_key, ''),
timeout=StatusReporter._HTTP_REQUEST_TIMEOUT) timeout=StatusReporter._HTTP_REQUEST_TIMEOUT)
""" """

View File

@ -16,27 +16,27 @@ post_file() {
mv "${file_path}" "${stripped_file_path}" mv "${file_path}" "${stripped_file_path}"
file_path="${stripped_file_path}" file_path="${stripped_file_path}"
filename="${file_path##*/}" filename="${file_path##*/}"
airtime_conf_path=/etc/airtime/airtime.conf airtime_conf_path=/etc/airtime/airtime.conf
#instance_path will look like 1/1384, for example #instance_path will look like 1/1384, for example
http_path=$(grep base_url ${airtime_conf_path} | awk '{print $3;}' ) http_path=$(grep base_url ${airtime_conf_path} | awk '{print $3;}' )
http_port=$(grep base_port ${airtime_conf_path} | awk '{print $3;}' ) http_port=$(grep base_port ${airtime_conf_path} | awk '{print $3;}' )
#post request url - http://bananas.airtime.pro/rest/media, for example #post request url - http://bananas.airtime.pro/rest/media, for example
url=http:// url=http://
url+=$http_path url+=$http_path
url+=: url+=:
url+=$http_port url+=$http_port
url+=/rest/media url+=/rest/media
api_key=$(grep api_key ${airtime_conf_path} | awk '{print $3;}' ) api_key=$(grep api_key ${airtime_conf_path} | awk '{print $3;}' )
# -f is needed to make curl fail if there's an HTTP error code # -f is needed to make curl fail if there's an HTTP error code
# -L is needed to follow redirects! (just in case) # -L is needed to follow redirects! (just in case)
until curl -fL --max-time 30 $url -u $api_key":" -X POST -F "file=@${file_path}" until curl -fL --max-time 30 $url -u $api_key":" -X POST -F "file=@${file_path}"
do do
retry_count=$[$retry_count+1] retry_count=$[$retry_count+1]
if [ $retry_count -ge $max_retry ]; then if [ $retry_count -ge $max_retry ]; then

View File

@ -21,8 +21,8 @@ if ($argc <= 1)
exit(); exit();
} }
$message = $argv[1]; $message = $argv[1];
$connection = new AMQPConnection(HOST, PORT, USER, PASS, VHOST); $connection = new AMQPConnection(HOST, PORT, USER, PASS, VHOST);
if (!isset($connection)) if (!isset($connection))
{ {
@ -31,10 +31,10 @@ if (!isset($connection))
} }
$channel = $connection->channel(); $channel = $connection->channel();
// declare/create the queue // declare/create the queue
$channel->queue_declare($queue, false, true, false, false); $channel->queue_declare($queue, false, true, false, false);
// declare/create the exchange as a topic exchange. // declare/create the exchange as a topic exchange.
$channel->exchange_declare($exchange, $exchangeType, false, true, false); $channel->exchange_declare($exchange, $exchangeType, false, true, false);

View File

@ -3,7 +3,7 @@
post_file() { post_file() {
file_path=${1} file_path=${1}
filename="${file_path##*/}" filename="${file_path##*/}"
#kill process after 30 minutes (360*5=30 minutes) #kill process after 30 minutes (360*5=30 minutes)
max_retry=10 max_retry=10
retry_count=0 retry_count=0

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source)) ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source))
elsif bitrate == 32 then elsif bitrate == 32 then
ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source)) ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source))

View File

@ -16,7 +16,7 @@ def notify_stream(m)
#escaping the apostrophe, and then starting a new string right after it. This is why we use 3 apostrophes. #escaping the apostrophe, and then starting a new string right after it. This is why we use 3 apostrophes.
json_str = string.replace(pattern="'",(fun (s) -> "'\''"), json_str) json_str = string.replace(pattern="'",(fun (s) -> "'\''"), json_str)
command = "timeout --signal=KILL 45 pyponotify --webstream='#{json_str}' --media-id=#{!current_dyn_id} &" command = "timeout --signal=KILL 45 pyponotify --webstream='#{json_str}' --media-id=#{!current_dyn_id} &"
if !current_dyn_id != "-1" then if !current_dyn_id != "-1" then
log(command) log(command)
system(command) system(command)
@ -24,7 +24,7 @@ def notify_stream(m)
end end
# A function applied to each metadata chunk # A function applied to each metadata chunk
def append_title(m) = def append_title(m) =
log("Using stream_format #{!stream_metadata_type}") log("Using stream_format #{!stream_metadata_type}")
if list.mem_assoc("mapped", m) then if list.mem_assoc("mapped", m) then
@ -82,9 +82,9 @@ end
# Define a transition that fades out the # Define a transition that fades out the
# old source, adds a single, and then # old source, adds a single, and then
# plays the new source # plays the new source
def to_live(old,new) = def to_live(old,new) =
# Fade out old source # Fade out old source
old = fade.final(old) old = fade.final(old)
# Compose this in sequence with # Compose this in sequence with
@ -233,7 +233,7 @@ def clear_queue(s)
end end
def set_dynamic_source_id(id) = def set_dynamic_source_id(id) =
current_dyn_id := id current_dyn_id := id
string_of(!current_dyn_id) string_of(!current_dyn_id)
end end

View File

@ -47,7 +47,7 @@ end
# cue cut fix for liquidsoap <1.2.2 # cue cut fix for liquidsoap <1.2.2
# #
# This was most likely broken on 1.1.1 (debian) as well. # This was most likely broken on 1.1.1 (debian) as well.
# #
# adapted from https://github.com/savonet/liquidsoap/issues/390#issuecomment-277562081 # adapted from https://github.com/savonet/liquidsoap/issues/390#issuecomment-277562081
# #
def fix_cue_in(~cue_in_metadata='liq_cue_in', m) = def fix_cue_in(~cue_in_metadata='liq_cue_in', m) =
@ -80,9 +80,9 @@ def create_source()
sources := list.append([l], !sources) sources := list.append([l], !sources)
server.register(namespace="queues", server.register(namespace="queues",
"s#{!source_id}_skip", "s#{!source_id}_skip",
fun (s) -> begin log("queues.s#{!source_id}_skip") fun (s) -> begin log("queues.s#{!source_id}_skip")
clear_queue(l) clear_queue(l)
"Done" "Done"
end) end)
source_id := !source_id + 1 source_id := !source_id + 1
end end

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
if stereo then if stereo then
ignore(output_stereo(%mp3(bitrate = 24, stereo = true), !source)) ignore(output_stereo(%mp3(bitrate = 24, stereo = true), !source))
else else

View File

@ -2,7 +2,7 @@
source := add(normalize=false, [amplify(0.00001, noise()), !source]) source := add(normalize=false, [amplify(0.00001, noise()), !source])
end end
if bitrate == 24 or bitrate == 32 or bitrate == 48 then if bitrate == 24 or bitrate == 32 or bitrate == 48 then
if stereo then if stereo then
ignore(output_stereo(%vorbis(quality=-0.1, channels = 2), !source)) ignore(output_stereo(%vorbis(quality=-0.1, channels = 2), !source))
else else

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
if stereo then if stereo then
ignore(output_stereo(%opus(bitrate = 24, channels = 2, signal="music", application="audio", complexity=10, vbr="constrained"), !source)) ignore(output_stereo(%opus(bitrate = 24, channels = 2, signal="music", application="audio", complexity=10, vbr="constrained"), !source))
else else

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source)) ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source))
elsif bitrate == 32 then elsif bitrate == 32 then
ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source)) ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source))

View File

@ -16,7 +16,7 @@ def notify_stream(m)
#escaping the apostrophe, and then starting a new string right after it. This is why we use 3 apostrophes. #escaping the apostrophe, and then starting a new string right after it. This is why we use 3 apostrophes.
json_str = string.replace(pattern="'",(fun (s) -> "'\''"), json_str) json_str = string.replace(pattern="'",(fun (s) -> "'\''"), json_str)
command = "timeout --signal=KILL 45 pyponotify --webstream='#{json_str}' --media-id=#{!current_dyn_id} &" command = "timeout --signal=KILL 45 pyponotify --webstream='#{json_str}' --media-id=#{!current_dyn_id} &"
if !current_dyn_id != "-1" then if !current_dyn_id != "-1" then
log(command) log(command)
system(command) system(command)
@ -24,7 +24,7 @@ def notify_stream(m)
end end
# A function applied to each metadata chunk # A function applied to each metadata chunk
def append_title(m) = def append_title(m) =
log("Using stream_format #{!stream_metadata_type}") log("Using stream_format #{!stream_metadata_type}")
if list.mem_assoc("mapped", m) then if list.mem_assoc("mapped", m) then
@ -82,9 +82,9 @@ end
# Define a transition that fades out the # Define a transition that fades out the
# old source, adds a single, and then # old source, adds a single, and then
# plays the new source # plays the new source
def to_live(old,new) = def to_live(old,new) =
# Fade out old source # Fade out old source
old = fade.final(old) old = fade.final(old)
# Compose this in sequence with # Compose this in sequence with
@ -233,7 +233,7 @@ def clear_queue(s)
end end
def set_dynamic_source_id(id) = def set_dynamic_source_id(id) =
current_dyn_id := id current_dyn_id := id
string_of(!current_dyn_id) string_of(!current_dyn_id)
end end

View File

@ -47,7 +47,7 @@ end
# cue cut fix for liquidsoap <1.2.2 # cue cut fix for liquidsoap <1.2.2
# #
# This was most likely broken on 1.1.1 (debian) as well. # This was most likely broken on 1.1.1 (debian) as well.
# #
# adapted from https://github.com/savonet/liquidsoap/issues/390#issuecomment-277562081 # adapted from https://github.com/savonet/liquidsoap/issues/390#issuecomment-277562081
# #
def fix_cue_in(~cue_in_metadata='liq_cue_in', m) = def fix_cue_in(~cue_in_metadata='liq_cue_in', m) =
@ -80,9 +80,9 @@ def create_source()
sources := list.append([l], !sources) sources := list.append([l], !sources)
server.register(namespace="queues", server.register(namespace="queues",
"s#{!source_id}_skip", "s#{!source_id}_skip",
fun (s) -> begin log("queues.s#{!source_id}_skip") fun (s) -> begin log("queues.s#{!source_id}_skip")
clear_queue(l) clear_queue(l)
"Done" "Done"
end) end)
source_id := !source_id + 1 source_id := !source_id + 1
end end

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
if stereo then if stereo then
ignore(output_stereo(%mp3(bitrate = 24, stereo = true), !source)) ignore(output_stereo(%mp3(bitrate = 24, stereo = true), !source))
else else

View File

@ -2,7 +2,7 @@
source := add(normalize=false, [amplify(0.00001, noise()), !source]) source := add(normalize=false, [amplify(0.00001, noise()), !source])
end end
if bitrate == 24 or bitrate == 32 or bitrate == 48 then if bitrate == 24 or bitrate == 32 or bitrate == 48 then
if stereo then if stereo then
ignore(output_stereo(%vorbis(quality=-0.1, channels = 2), !source)) ignore(output_stereo(%vorbis(quality=-0.1, channels = 2), !source))
else else

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
if stereo then if stereo then
ignore(output_stereo(%opus(bitrate = 24, channels = 2, signal="music", application="audio", complexity=10, vbr="constrained"), !source)) ignore(output_stereo(%opus(bitrate = 24, channels = 2, signal="music", application="audio", complexity=10, vbr="constrained"), !source))
else else

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source)) ignore(output_stereo(%fdkaac(bitrate = 24, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source))
elsif bitrate == 32 then elsif bitrate == 32 then
ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source)) ignore(output_stereo(%fdkaac(bitrate = 32, aot="mpeg4_he_aac_v2", afterburner=false, sbr_mode=true), !source))

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
if stereo then if stereo then
ignore(output_stereo(%mp3(bitrate = 24, stereo = true), !source)) ignore(output_stereo(%mp3(bitrate = 24, stereo = true), !source))
else else

View File

@ -2,7 +2,7 @@
source := add(normalize=false, [amplify(0.00001, noise()), !source]) source := add(normalize=false, [amplify(0.00001, noise()), !source])
end end
if bitrate == 24 or bitrate == 32 or bitrate == 48 then if bitrate == 24 or bitrate == 32 or bitrate == 48 then
if stereo then if stereo then
ignore(output_stereo(%vorbis(quality=-0.1, channels = 2), !source)) ignore(output_stereo(%vorbis(quality=-0.1, channels = 2), !source))
else else

View File

@ -1,4 +1,4 @@
if bitrate == 24 then if bitrate == 24 then
if stereo then if stereo then
ignore(output_stereo(%opus(bitrate = 24, channels = 2, signal="music", application="audio", complexity=10, vbr="constrained"), !source)) ignore(output_stereo(%opus(bitrate = 24, channels = 2, signal="music", application="audio", complexity=10, vbr="constrained"), !source))
else else

View File

@ -41,7 +41,7 @@ function exitIfNotRoot()
function printUsage($userMsg = "") function printUsage($userMsg = "")
{ {
global $opts; global $opts;
$msg = $opts->getUsageMessage(); $msg = $opts->getUsageMessage();
if (strlen($userMsg)>0) if (strlen($userMsg)>0)
echo $userMsg; echo $userMsg;
@ -64,11 +64,11 @@ function viewSpecificLog($key){
} else printUsage(); } else printUsage();
} }
function dumpAllLogs(){ function dumpAllLogs(){
$dateStr = gmdate("Y-m-d-H-i-s"); $dateStr = gmdate("Y-m-d-H-i-s");
$dir = getcwd(); $dir = getcwd();
$filename = "$dir/airtime-log-all-$dateStr.tgz"; $filename = "$dir/airtime-log-all-$dateStr.tgz";
echo "Creating Airtime logs tgz file at $filename"; echo "Creating Airtime logs tgz file at $filename";
$command = "tar cfz $filename /var/log/airtime 2>/dev/null"; $command = "tar cfz $filename /var/log/airtime 2>/dev/null";
@ -82,7 +82,7 @@ function dumpSpecificLog($key){
$dateStr = gmdate("Y-m-d-H-i-s"); $dateStr = gmdate("Y-m-d-H-i-s");
$dir = getcwd(); $dir = getcwd();
$filename = "$dir/airtime-log-$key-$dateStr.tgz"; $filename = "$dir/airtime-log-$key-$dateStr.tgz";
echo "Creating Airtime logs tgz file at $filename"; echo "Creating Airtime logs tgz file at $filename";
$dir = dirname($log_files[$key]); $dir = dirname($log_files[$key]);
@ -104,7 +104,7 @@ function tailSpecificLog($key){
if (isKeyValid($key)){ if (isKeyValid($key)){
echo "Tail $key log"; echo "Tail $key log";
pcntl_exec(exec("which tail"), array("-F", $log_files[$key])); pcntl_exec(exec("which tail"), array("-F", $log_files[$key]));
pcntl_wait($status); pcntl_wait($status);
} else printUsage(); } else printUsage();
} }

View File

@ -4,7 +4,7 @@
# database and set appropriate tags to each MP3 file. # database and set appropriate tags to each MP3 file.
# Notes: # Notes:
# 1 - Rivendell store files in .wav format, airtime uses .mp3 format # 1 - Rivendell store files in .wav format, airtime uses .mp3 format
# 2 - WAV does not have Meta-tag support so all meta-tags need to be fetched from Rivendell database. # 2 - WAV does not have Meta-tag support so all meta-tags need to be fetched from Rivendell database.