diff --git a/Bin/MSWin32-x86-multi-thread/faad.exe b/Bin/MSWin32-x86-multi-thread/faad.exe deleted file mode 100755 index 9f3e6ffb776..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/faad.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/flac.exe b/Bin/MSWin32-x86-multi-thread/flac.exe deleted file mode 100755 index a581348df21..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/flac.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/grant.exe b/Bin/MSWin32-x86-multi-thread/grant.exe deleted file mode 100644 index 55e32870fec..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/grant.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/mac.exe b/Bin/MSWin32-x86-multi-thread/mac.exe deleted file mode 100755 index d30a1ee6e26..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/mac.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/mppdec.exe b/Bin/MSWin32-x86-multi-thread/mppdec.exe deleted file mode 100755 index 5ec045d1c86..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/mppdec.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/sls.exe b/Bin/MSWin32-x86-multi-thread/sls.exe deleted file mode 100755 index 2f74c77f3bc..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/sls.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/socketwrapper.exe b/Bin/MSWin32-x86-multi-thread/socketwrapper.exe deleted file mode 100755 index 46759fdca47..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/socketwrapper.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/sox.exe b/Bin/MSWin32-x86-multi-thread/sox.exe deleted file mode 100755 index 689eb35c30e..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/sox.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/wmadec.exe b/Bin/MSWin32-x86-multi-thread/wmadec.exe deleted file mode 100755 index c6cdf07b3da..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/wmadec.exe and /dev/null differ diff --git a/Bin/MSWin32-x86-multi-thread/wvunpack.exe b/Bin/MSWin32-x86-multi-thread/wvunpack.exe deleted file mode 100644 index 1e49a992ae1..00000000000 Binary files a/Bin/MSWin32-x86-multi-thread/wvunpack.exe and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Audio/Scan.pm b/CPAN/arch/5.14/MSWin32-x86-multi-thread/Audio/Scan.pm deleted file mode 100755 index 0dbd6f9156b..00000000000 --- a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Audio/Scan.pm +++ /dev/null @@ -1,938 +0,0 @@ -package Audio::Scan; - -use strict; - -our $VERSION = '1.09'; - -require XSLoader; -XSLoader::load('Audio::Scan', $VERSION); - -use constant FILTER_INFO_ONLY => 1; -use constant FILTER_TAGS_ONLY => 2; - -sub scan_info { - my ( $class, $path, $opts ) = @_; - - $opts ||= {}; - $opts->{filter} = FILTER_INFO_ONLY; - - $class->scan( $path, $opts ); -} - -sub scan_tags { - my ( $class, $path, $opts ) = @_; - - $opts ||= {}; - $opts->{filter} = FILTER_TAGS_ONLY; - - $class->scan( $path, $opts ); -} - -sub scan { - my ( $class, $path, $opts ) = @_; - - my ($filter, $md5_size, $md5_offset); - - open my $fh, '<', $path or do { - warn "Could not open $path for reading: $!\n"; - return; - }; - - binmode $fh; - - my ($suffix) = $path =~ /\.(\w+)$/; - - return if !$suffix; - - if ( defined $opts ) { - if ( !ref $opts ) { - # Back-compat to support filter as normal argument - warn "The Audio::Scan::scan() filter passing method is deprecated, please pass a hashref instead.\n"; - $filter = $opts; - } - else { - $filter = $opts->{filter} || FILTER_INFO_ONLY | FILTER_TAGS_ONLY; - $md5_size = $opts->{md5_size}; - $md5_offset = $opts->{md5_offset}; - } - } - - if ( !defined $filter ) { - $filter = FILTER_INFO_ONLY | FILTER_TAGS_ONLY; - } - - my $ret = $class->_scan( $suffix, $fh, $path, $filter, $md5_size || 0, $md5_offset || 0 ); - - close $fh; - - return $ret; -} - -sub scan_fh { - my ( $class, $suffix, $fh, $opts ) = @_; - - my ($filter, $md5_size, $md5_offset); - - binmode $fh; - - if ( defined $opts ) { - if ( !ref $opts ) { - # Back-compat to support filter as normal argument - warn "The Audio::Scan::scan_fh() filter passing method is deprecated, please pass a hashref instead.\n"; - $filter = $opts; - } - else { - $filter = $opts->{filter} || FILTER_INFO_ONLY | FILTER_TAGS_ONLY; - $md5_size = $opts->{md5_size}; - $md5_offset = $opts->{md5_offset}; - } - } - - if ( !defined $filter ) { - $filter = FILTER_INFO_ONLY | FILTER_TAGS_ONLY; - } - - return $class->_scan( $suffix, $fh, '(filehandle)', $filter, $md5_size || 0, $md5_offset || 0 ); -} - -sub find_frame { - my ( $class, $path, $offset ) = @_; - - open my $fh, '<', $path or do { - warn "Could not open $path for reading: $!\n"; - return; - }; - - binmode $fh; - - my ($suffix) = $path =~ /\.(\w+)$/; - - return -1 if !$suffix; - - my $ret = $class->_find_frame( $suffix, $fh, $path, $offset ); - - close $fh; - - return $ret; -} - -sub find_frame_fh { - my ( $class, $suffix, $fh, $offset ) = @_; - - binmode $fh; - - return $class->_find_frame( $suffix, $fh, '(filehandle)', $offset ); -} - -sub find_frame_return_info { - my ( $class, $path, $offset ) = @_; - - open my $fh, '<', $path or do { - warn "Could not open $path for reading: $!\n"; - return; - }; - - binmode $fh; - - my ($suffix) = $path =~ /\.(\w+)$/; - - return if !$suffix; - - my $ret = $class->_find_frame_return_info( $suffix, $fh, $path, $offset ); - - close $fh; - - return $ret; -} - -sub find_frame_fh_return_info { - my ( $class, $suffix, $fh, $offset ) = @_; - - binmode $fh; - - return $class->_find_frame_return_info( $suffix, $fh, '(filehandle)', $offset ); -} - -1; -__END__ - -=head1 NAME - -Audio::Scan - Fast C metadata and tag reader for all common audio file formats - -=head1 SYNOPSIS - - use Audio::Scan; - - my $data = Audio::Scan->scan('/path/to/file.mp3'); - - # Just file info - my $info = Audio::Scan->scan_info('/path/to/file.mp3'); - - # Just tags - my $tags = Audio::Scan->scan_tags('/path/to/file.mp3'); - - # Scan without reading (possibly large) artwork into memory. - # Instead of binary artwork data, the size of the artwork will be returned instead. - { - local $ENV{AUDIO_SCAN_NO_ARTWORK} = 1; - my $data = Audio::Scan->scan('/path/to/file.mp3'); - } - - # Scan a filehandle - open my $fh, '<', 'my.mp3'; - my $data = Audio::Scan->scan_fh( mp3 => $fh ); - close $fh; - - # Scan and compute an audio MD5 checksum - my $data = Audio::Scan->scan( '/path/to/file.mp3', { md5_size => 100 * 1024 } ); - my $md5 = $data->{info}->{audio_md5}; - -=head1 DESCRIPTION - -Audio::Scan is a C-based scanner for audio file metadata and tag information. It currently -supports MP3, MP4, Ogg Vorbis, FLAC, ASF, WAV, AIFF, Musepack, Monkey's Audio, and WavPack. - -See below for specific details about each file format. - -=head1 METHODS - -=head2 scan( $path, [ \%OPTIONS ] ) - -Scans $path for both metadata and tag information. The type of scan performed is -determined by the file's extension. Supported extensions are: - - MP3: mp3, mp2 - MP4: mp4, m4a, m4b, m4p, m4v, m4r, k3g, skm, 3gp, 3g2, mov - AAC (ADTS): aac - Ogg: ogg, oga - FLAC: flc, flac, fla - ASF: wma, wmv, asf - Musepack: mpc, mpp, mp+ - Monkey's Audio: ape, apl - WAV: wav - AIFF: aiff, aif - WavPack: wv - -This method returns a hashref containing two other hashrefs: info and tags. The -contents of the info and tag hashes vary depending on file format, see below for details. - -An optional hashref may be provided with the following values: - - md5_size => $audio_bytes_to_checksum - -An MD5 will be computed of the first N audio bytes. Any tags in the file are automatically -skipped, so this is a useful way of determining if a file's audio content is the same even -if tags may have been changed. The hex MD5 value is returned in the $info->{audio_md5} -key. This option will reduce performance, so choose a small enough size that works for you, -you should probably avoid using more than 64K for example. - -For FLAC files that already contain an MD5 checksum, this value will be used instead -of calculating a new one. - - md5_offset => $offset - -Begin computing the audio_md5 value starting at $offset. If this value is not specified, -$offset defaults to a point in the middle of the file. - -=head2 scan_info( $path, [ \%OPTIONS ] ) - -If you only need file metadata and don't care about tags, you can use this method. - -=head2 scan_tags( $path, [ \%OPTIONS ] ) - -If you only need the tags and don't care about the metadata, use this method. - -=head2 scan_fh( $type => $fh, [ \%OPTIONS ] ) - -Scans a filehandle. $type is the type of file to scan as, i.e. "mp3" or "ogg". -Note that FLAC does not support reading from a filehandle. - -=head2 find_frame( $path, $timestamp_in_ms ) - -Returns the byte offset to the first audio frame starting from the given timestamp -(in milliseconds). - -=over 4 - -=item MP3, Ogg, FLAC, ASF, MP4 - -The byte offset to the data packet containing this timestamp will be returned. For -file formats that don't provide timestamp information such as MP3, the best estimate for -the location of the timestamp will be returned. This will be more accurate if the -file has a Xing header or is CBR for example. - -=item WAV, AIFF, Musepack, Monkey's Audio, WavPack - -Not yet supported by find_frame. - -=back - -=head2 find_frame_return_info( $mp4_path, $timestamp_in_ms ) - -The header of an MP4 file contains various metadata that refers to the structure of -the audio data, making seeking more difficult to perform. This method will return -the usual $info hash with 2 additional keys: - - seek_offset - The seek offset in bytes - seek_header - A rewritten MP4 header that can be prepended to the audio data - found at seek_offset to construct a valid bitstream. Specifically, - the following boxes are rewritten: stts, stsc, stsz, stco - -For example, to seek 30 seconds into a file and write out a new MP4 file seeked to -this point: - - my $info = Audio::Scan->find_frame_return_info( $file, 30000 ); - - open my $f, '<', $file; - sysseek $f, $info->{seek_offset}, 1; - - open my $fh, '>', 'seeked.m4a'; - print $fh $info->{seek_header}; - - while ( sysread( $f, my $buf, 65536 ) ) { - print $fh $buf; - } - - close $f; - close $fh; - -=head2 find_frame_fh( $type => $fh, $offset ) - -Same as C, but with a filehandle. - -=head2 find_frame_fh_return_info( $type => $fh, $offset ) - -Same as C, but with a filehandle. - -=head2 has_flac() - -Deprecated. Always returns 1 now that FLAC is always enabled. - -=head2 is_supported( $path ) - -Returns 1 if the given path can be scanned by Audio::Scan, or 0 if not. - -=head2 get_types() - -Returns an array of strings of the file types supported by Audio::Scan. - -=head2 extensions_for( $type ) - -Returns an array of strings of the file extensions that are considered to -be the file type I<$type>. - -=head2 type_for( $extension ) - -Returns file type for a given extension. Returns I for unsupported -extensions. - -=head1 SKIPPING ARTWORK - -To save memory while reading tags, you can opt to skip potentially large -embedded artwork. To do this, set the environment variable AUDIO_SCAN_NO_ARTWORK: - - local $ENV{AUDIO_SCAN_NO_ARTWORK} = 1; - my $tags = Audio::Scan->scan_tags($file); - -This will return the length of the embedded artwork instead of the actual image data. -In some cases it will also return a byte offset to the image data, which can be used -to extract the image using more efficient means. Note that the offset is not always -returned so if you want to use this data make sure to check for offset. If offset -is not present, the only way to get the image data is to perform a normal tag scan -without the environment variable set. - -One limitation that currently exists is that memory for embedded images is still -allocated for ASF and Ogg Vorbis files. - -This information is returned in different ways depending on the format: - -ID3 (MP3, AAC, WAV, AIFF): - - $tags->{APIC}->[3]: image length - $tags->{APIC}->[4]: image offset (unless APIC would need unsynchronization) - -MP4: - - $tags->{COVR}: image length - $tags->{COVR_offset}: image offset (always available) - -Ogg Vorbis: - - $tags->{ALLPICTURES}->[0]->{image_data}: image length - Image offset is not supported with Vorbis because the data is always base64-encoded. - -FLAC: - - $tags->{ALLPICTURES}->[0]->{image_data}: image length - $tags->{ALLPICTURES}->[0]->{offset}: image offset (always available) - -ASF: - - $tags->{'WM/Picture'}->{image}: image length - $tags->{'WM/Picture'}->{offset}: image offset (always available) - -APE, Musepack, WavPack, MP3 with APEv2: - - $tags->{'COVER ART (FRONT)'}: image length - $tags->{'COVER ART (FRONT)_offset'}: image offset (always available) - -=head1 MP3 - -=head2 INFO - -The following metadata about a file may be returned: - - id3_version (i.e. "ID3v2.4.0") - id3_was_unsynced (if a v2.2/v2.3 file needed whole-tag unsynchronization) - song_length_ms (duration in milliseconds) - layer (i.e. 3) - stereo - samples_per_frame - padding - audio_size (size of all audio frames) - audio_offset (byte offset to first audio frame) - bitrate (in bps, determined using Xing/LAME/VBRI if possible, or average in the worst case) - samplerate (in kHz) - vbr (1 if file is VBR) - dlna_profile (if file is compliant) - - If a Xing header is found: - xing_frames - xing_bytes - xing_quality - - If a VBRI header is found: - vbri_delay - vbri_frames - vbri_bytes - vbri_quality - - If a LAME header is found: - lame_encoder_version - lame_tag_revision - lame_vbr_method - lame_lowpass - lame_replay_gain_radio - lame_replay_gain_audiophile - lame_encoder_delay - lame_encoder_padding - lame_noise_shaping - lame_stereo_mode - lame_unwise_settings - lame_source_freq - lame_surround - lame_preset - -=head2 TAGS - -Raw tags are returned as found. This means older tags such as ID3v1 and ID3v2.2/v2.3 -are converted to ID3v2.4 tag names. Multiple instances of a tag in a file will be returned -as arrays. Complex tags such as APIC and COMM are returned as arrays. All tag fields are -converted to upper-case. All text is converted to UTF-8. - -Sample tag data: - - tags => { - ALBUMARTISTSORT => "Solar Fields", - APIC => [ "image/jpeg", 3, "", ], - CATALOGNUMBER => "INRE 017", - COMM => ["eng", "", "Amazon.com Song ID: 202981429"], - "MUSICBRAINZ ALBUM ARTIST ID" => "a2af1f31-c9eb-4fff-990c-c4f547a11b75", - "MUSICBRAINZ ALBUM ID" => "282143c9-6191-474d-a31a-1117b8c88cc0", - "MUSICBRAINZ ALBUM RELEASE COUNTRY" => "FR", - "MUSICBRAINZ ALBUM STATUS" => "official", - "MUSICBRAINZ ALBUM TYPE" => "album", - "MUSICBRAINZ ARTIST ID" => "a2af1f31-c9eb-4fff-990c-c4f547a11b75", - "REPLAYGAIN_ALBUM_GAIN" => "-2.96 dB", - "REPLAYGAIN_ALBUM_PEAK" => "1.045736", - "REPLAYGAIN_TRACK_GAIN" => "+3.60 dB", - "REPLAYGAIN_TRACK_PEAK" => "0.892606", - TALB => "Leaving Home", - TCOM => "Magnus Birgersson", - TCON => "Ambient", - TCOP => "2005 ULTIMAE RECORDS", - TDRC => "2004-10", - TIT2 => "Home", - TPE1 => "Solar Fields", - TPE2 => "Solar Fields", - TPOS => "1/1", - TPUB => "Ultimae Records", - TRCK => "1/11", - TSOP => "Solar Fields", - UFID => [ - "http://musicbrainz.org", - "1084278a-2254-4613-a03c-9fed7a8937ca", - ], - }, - - -=head1 MP4 - -=head2 INFO - -The following metadata about a file may be returned: - - audio_offset (byte offset to start of mdat) - audio_size - compatible_brands - file_size - leading_mdat (if file has mdat before moov) - major_brand - minor_version - song_length_ms - timescale - dlna_profile (if file is compliant) - tracks (array of tracks in the file) - Each track may contain: - - audio_type - avg_bitrate - bits_per_sample - channels - duration - encoding - handler_name - handler_type - id - max_bitrate - samplerate - -=head2 TAGS - -Tags are returned in a hash with all keys converted to upper-case. Keys starting with -0xA9 (copyright symbol) will have this character stripped out. Sample tag data: - - tags => { - AART => "Album Artist", - ALB => "Album", - ART => "Artist", - CMT => "Comments", - COVR => , - CPIL => 1, - DAY => 2009, - DESC => "Video Description", - DISK => "1/2", - "ENCODING PARAMS" => "vers\0\0\0\1acbf\0\0\0\2brat\0\1w\0cdcv\0\1\6\5", - GNRE => "Jazz", - GRP => "Grouping", - ITUNNORM => " 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", - ITUNSMPB => " 00000000 00000840 000001E4 00000000000001DC 00000000 00000000 00000000 00000000 00000000 00000000 00000000 00000000", - LYR => "Lyrics", - NAM => "Name", - PGAP => 1, - SOAA => "Sort Album Artist", - SOAL => "Sort Album", - SOAR => "Sort Artist", - SOCO => "Sort Composer", - SONM => "Sort Name", - SOSN => "Sort Show", - TMPO => 120, - TOO => "iTunes 8.1.1, QuickTime 7.6", - TRKN => "1/10", - TVEN => "Episode ID", - TVES => 12, - TVSH => "Show", - TVSN => 12, - WRT => "Composer", - }, - -=head1 AAC (ADTS) - -=head2 INFO - -The following metadata about a file is returned: - - audio_offset - audio_size - bitrate (in bps) - channels - file_size - profile (Main, LC, or SSR) - samplerate (in kHz) - song_length_ms (duration in milliseconds) - dlna_profile (if file is compliant) - -=head1 OGG VORBIS - -=head2 INFO - -The following metadata about a file is returned: - - version - channels - stereo - samplerate (in kHz) - bitrate_average (in bps) - bitrate_upper - bitrate_nominal - bitrate_lower - blocksize_0 - blocksize_1 - audio_offset (byte offset to audio) - audio_size - song_length_ms (duration in milliseconds) - -=head2 TAGS - -Raw Vorbis comments are returned. All comment keys are capitalized. - -=head1 FLAC - -=head2 INFO - -The following metadata about a file is returned: - - channels - samplerate (in kHz) - bitrate (in bps) - file_size - audio_offset (byte offset to first audio frame) - audio_size - song_length_ms (duration in milliseconds) - bits_per_sample - frames - minimum_blocksize - maximum_blocksize - minimum_framesize - maximum_framesize - audio_md5 - total_samples - -=head2 TAGS - -Raw FLAC comments are returned. All comment keys are capitalized. Some data returned is special: - -APPLICATION - - Each application block is returned in the APPLICATION tag keyed by application ID. - -CUESHEET_BLOCK - - The CUESHEET_BLOCK tag is an array containing each line of the cue sheet. - -ALLPICTURES - - Embedded pictures are returned in an ALLPICTURES array. Each picture has the following metadata: - - mime_type - description - width - height - depth - color_index - image_data - picture_type - -=head1 ASF (Windows Media Audio/Video) - -=head2 INFO - -The following metadata about a file may be returned. Reading the ASF spec is encouraged if you -want to find out more about any of these values. - - audio_offset (byte offset to first data packet) - audio_size - broadcast (boolean, whether the file is a live broadcast or not) - codec_list (array of information about codecs used in the file) - creation_date (UNIX timestamp when file was created) - data_packets - drm_key - drm_license_url - drm_protection_type - drm_data - file_id (unique file ID) - file_size - index_blocks - index_entry_interval (in milliseconds) - index_offsets (byte offsets for each second of audio, per stream. Useful for seeking) - index_specifiers (indicates which stream a given index_offset points to) - language_list (array of languages referenced by the file's metadata) - lossless (boolean) - max_bitrate - max_packet_size - min_packet_size - mutex_list (mutually exclusive stream information) - play_duration_ms - preroll - script_commands - script_types - seekable (boolean, whether the file is seekable or not) - send_duration_ms - song_length_ms (the actual length of the audio, in milliseconds) - dlna_profile (if file is compliant) - -STREAMS - -The streams array contains metadata related to an individul stream within the file. -The following metadata may be returned: - - DeviceConformanceTemplate - IsVBR - alt_bitrate - alt_buffer_fullness - alt_buffer_size - avg_bitrate (most accurate bitrate for this stream) - avg_bytes_per_sec (audio only) - bitrate - bits_per_sample (audio only) - block_alignment (audio only) - bpp (video only) - buffer_fullness - buffer_size - channels (audio only) - codec_id (audio only) - compression_id (video only) - encode_options - encrypted (boolean) - error_correction_type - flag_seekable (boolean) - height (video only) - index_type - language_index (offset into language_list array) - max_object_size - samplerate (in kHz) (audio only) - samples_per_block - stream_number - stream_type - super_block_align - time_offset - width (video only) - -=head2 TAGS - -Raw tags are returned. Tags that occur more than once are returned as arrays. -In contrast to the other formats, tag keys are NOT capitalized. There is one special key: - -WM/Picture - -Pictures are returned as a hash with the following keys: - - image_type (numeric type, same as ID3v2 APIC) - mime_type - description - image - -=head1 WAV - -=head2 INFO - -The following metadata about a file may be returned. - - audio_offset - audio_size - bitrate (in bps) - bits_per_sample - block_align - channels - dlna_profile (if file is compliant) - file_size - format (WAV format code, 1 == PCM) - id3_version (if an ID3v2 tag is found) - samplerate (in kHz) - song_length_ms - -=head2 TAGS - -WAV files can contain several different types of tags. "Native" WAV tags -found in a LIST block may include these and others: - - IARL - Archival Location - IART - Artist - ICMS - Commissioned - ICMT - Comment - ICOP - Copyright - ICRD - Creation Date - ICRP - Cropped - IENG - Engineer - IGNR - Genre - IKEY - Keywords - IMED - Medium - INAM - Name (Title) - IPRD - Product (Album) - ISBJ - Subject - ISFT - Software - ISRC - Source - ISRF - Source Form - TORG - Label - LOCA - Location - TVER - Version - TURL - URL - TLEN - Length - ITCH - Technician - TRCK - Track - ITRK - Track - -ID3v2 tags can also be embedded within WAV files. These are returned exactly as for MP3 files. - -=head1 AIFF - -=head2 INFO - -The following metadata about a file may be returned. - - audio_offset - audio_size - bitrate (in bps) - bits_per_sample - block_align - channels - compression_name (if AIFC) - compression_type (if AIFC) - dlna_profile (if file is compliant) - file_size - id3_version (if an ID3v2 tag is found) - samplerate (in kHz) - song_length_ms - -=head2 TAGS - -ID3v2 tags can be embedded within AIFF files. These are returned exactly as for MP3 files. - -=head1 MONKEY'S AUDIO (APE) - -=head2 INFO - -The following metadata about a file may be returned. - - audio_offset - audio_size - bitrate (in bps) - channels - compression - file_size - samplerate (in kHz) - song_length_ms - version - -=head2 TAGS - -APEv2 tags are returned as a hash of key/value pairs. - -=head1 MUSEPACK - -=head2 INFO - -The following metadata about a file may be returned. - - audio_offset - audio_size - bitrate (in bps) - channels - encoder - file_size - profile - samplerate (in kHz) - song_length_ms - -=head2 TAGS - -Musepack uses APEv2 tags. They are returned as a hash of key/value pairs. - -=head1 WAVPACK - -=head2 INFO - -The following metadata about a file may be returned. - - audio_offset - audio_size - bitrate (in bps) - bits_per_sample - channels - encoder_version - file_size - hybrid (1 if file is lossy) (v4 only) - lossless (1 if file is lossless) (v4 only) - samplerate - song_length_ms - total_samples - -=head2 TAGS - -WavPack uses APEv2 tags. They are returned as a hash of key/value pairs. - -=head1 DSF - -=head2 INFO - -The following metadata about a file may be returned. - - audio_offset - audio_size - bits_per_sample - channels - song_length_ms - samplerate - block_size_per_channel - -=head2 TAGS - -ID3v2 tags can be embedded within DSF files. These are returned exactly as for MP3 files. - -=head1 DSDIFF (DFF) - -=head2 INFO - -The following metadata about a file may be returned. - - audio_offset - audio_size - bits_per_sample - channels - song_length_ms - samplerate - tag_diti_title - tag_diar_artist - -=head2 TAGS - -No separate tags are supported by the DSDIFF format. - -=head1 - -=head1 THANKS - -Logitech & Slim Devices, for letting us release so much of our code to the world. -Long live Squeezebox! - -Kimmo Taskinen, Adrian Smith, Clive Messer, and Jurgen Kramer for -DSF/DSDIFF support and various other fixes. - -Some code from the Rockbox project was very helpful in implementing ASF and -MP4 seeking. - -Some of the file format parsing code was derived from the mt-daapd project, -and adapted by Netgear. It has been heavily rewritten to fix bugs and add -more features. - -The source to the original Netgear C scanner for SqueezeCenter is located -at L - -The audio MD5 feature uses an MD5 implementation by L. Peter Deutsch, -Eghost@aladdin.comE. - -=head1 SEE ALSO - -ASF Spec L - -MP4 Info: -L -L - -=head1 AUTHORS - -Andy Grundman, Eandy@hybridized.orgE - -Dan Sully, Edaniel@cpan.orgE - -=head1 COPYRIGHT AND LICENSE - -Copyright (C) 2010-2011 Logitech, Inc. - -This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. - -=cut diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Crypt/Blowfish.pm b/CPAN/arch/5.14/MSWin32-x86-multi-thread/Crypt/Blowfish.pm deleted file mode 100755 index 7cbc118f848..00000000000 --- a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Crypt/Blowfish.pm +++ /dev/null @@ -1,194 +0,0 @@ -package Crypt::Blowfish; - -require Exporter; -require DynaLoader; -use vars qw($VERSION @ISA @EXPORT @EXPORT_OK); - -@ISA = qw(Exporter DynaLoader); -# @ISA = qw(Exporter DynaLoader Crypt::BlockCipher); - -# Items to export into callers namespace by default -@EXPORT = qw(); - -# Other items we are prepared to export if requested -@EXPORT_OK = qw( - blocksize keysize min_keysize max_keysize - new encrypt decrypt -); - -$VERSION = '2.14'; -bootstrap Crypt::Blowfish $VERSION; - -use strict; -use Carp; - -sub usage -{ - my ($package, $filename, $line, $subr) = caller(1); - $Carp::CarpLevel = 2; - croak "Usage: $subr(@_)"; -} - - -sub blocksize { 8; } # /* byte my shiny metal.. */ -sub keysize { 0; } # /* we'll leave this at 8 .. for now. */ -sub min_keysize { 8; } -sub max_keysize { 56; } - -sub new -{ - usage("new Blowfish key") unless @_ == 2; - my $type = shift; my $self = {}; bless $self, $type; - $self->{'ks'} = Crypt::Blowfish::init(shift); - return $self; -} - -sub encrypt -{ - usage("encrypt data[8 bytes]") unless @_ == 2; - my ($self,$data) = @_; - Crypt::Blowfish::crypt($data, $data, $self->{'ks'}, 0); - return $data; -} - -sub decrypt -{ - usage("decrypt data[8 bytes]") unless @_ == 2; - my ($self,$data) = @_; - Crypt::Blowfish::crypt($data, $data, $self->{'ks'}, 1); - return $data; -} - -1; - -__END__ -# -# Parts Copyright (C) 1995, 1996 Systemics Ltd (http://www.systemics.com/) -# New Parts Copyright (C) 1999, 2001 W3Works, LLC (http://www.w3works.com/) -# All rights reserved. -# - -=head1 NAME - -Crypt::Blowfish - Perl Blowfish encryption module - -=head1 SYNOPSIS - - use Crypt::Blowfish; - my $cipher = new Crypt::Blowfish $key; - my $ciphertext = $cipher->encrypt($plaintext); - my $plaintext = $cipher->decrypt($ciphertext); - - You probably want to use this in conjunction with - a block chaining module like Crypt::CBC. - -=head1 DESCRIPTION - -Blowfish is capable of strong encryption and can use key sizes up -to 56 bytes (a 448 bit key). You're encouraged to take advantage -of the full key size to ensure the strongest encryption possible -from this module. - -Crypt::Blowfish has the following methods: - -=over 4 - - blocksize() - keysize() - encrypt() - decrypt() - -=back - -=head1 FUNCTIONS - -=over 4 - -=item blocksize - -Returns the size (in bytes) of the block cipher. - -Crypt::Blowfish doesn't return a key size due to its ability -to use variable-length keys. More accurately, it shouldn't, -but it does anyway to play nicely with others. - -=item new - - my $cipher = new Crypt::Blowfish $key; - -This creates a new Crypt::Blowfish BlockCipher object, using $key, -where $key is a key of C bytes (minimum of eight bytes). - -=item encrypt - - my $cipher = new Crypt::Blowfish $key; - my $ciphertext = $cipher->encrypt($plaintext); - -This function encrypts $plaintext and returns the $ciphertext -where $plaintext and $ciphertext must be of C bytes. -(hint: Blowfish is an 8 byte block cipher) - -=item decrypt - - my $cipher = new Crypt::Blowfish $key; - my $plaintext = $cipher->decrypt($ciphertext); - -This function decrypts $ciphertext and returns the $plaintext -where $plaintext and $ciphertext must be of C bytes. -(hint: see previous hint) - -=back - -=head1 EXAMPLE - - my $key = pack("H16", "0123456789ABCDEF"); # min. 8 bytes - my $cipher = new Crypt::Blowfish $key; - my $ciphertext = $cipher->encrypt("plaintex"); # SEE NOTES - print unpack("H16", $ciphertext), "\n"; - -=head1 PLATFORMS - - Please see the README document for platforms and performance - tests. - -=head1 NOTES - -The module is capable of being used with Crypt::CBC. You're -encouraged to read the perldoc for Crypt::CBC if you intend to -use this module for Cipher Block Chaining modes. In fact, if -you have any intentions of encrypting more than eight bytes of -data with this, or any other block cipher, you're going to need -B type of block chaining help. Crypt::CBC tends to be -very good at this. If you're not going to encrypt more than -eight bytes, your data B be B eight bytes long. -If need be, do your own padding. "\0" as a null byte is perfectly -valid to use for this. - -=head1 SEE ALSO - -Crypt::CBC, -Crypt::DES, -Crypt::IDEA - -Bruce Schneier, I, 1995, Second Edition, -published by John Wiley & Sons, Inc. - -=head1 COPYRIGHT - -The implementation of the Blowfish algorithm was developed by, -and is copyright of, A.M. Kuchling. - -Other parts of the perl extension and module are -copyright of Systemics Ltd ( http://www.systemics.com/ ). - -Code revisions, updates, and standalone release are copyright -1999-2010 W3Works, LLC. - -=head1 AUTHOR - -Original algorithm, Bruce Shneier. Original implementation, A.M. -Kuchling. Original Perl implementation, Systemics Ltd. Current -maintenance by W3Works, LLC. - -Current revision and maintainer: Dave Paris - diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/DBD/SQLite.pm b/CPAN/arch/5.14/MSWin32-x86-multi-thread/DBD/SQLite.pm deleted file mode 100755 index a719c10ea75..00000000000 --- a/CPAN/arch/5.14/MSWin32-x86-multi-thread/DBD/SQLite.pm +++ /dev/null @@ -1,2611 +0,0 @@ -package DBD::SQLite; - -use 5.006; -use strict; -use DBI 1.57 (); -use DynaLoader (); - -our $VERSION = '1.58'; -our @ISA = 'DynaLoader'; - -# sqlite_version cache (set in the XS bootstrap) -our ($sqlite_version, $sqlite_version_number); - -# not sure if we still need these... -our ($err, $errstr); - -__PACKAGE__->bootstrap($VERSION); - -# New or old API? -use constant NEWAPI => ($DBI::VERSION >= 1.608); - -# global registry of collation functions, initialized with 2 builtins -our %COLLATION; -tie %COLLATION, 'DBD::SQLite::_WriteOnceHash'; -$COLLATION{perl} = sub { $_[0] cmp $_[1] }; -$COLLATION{perllocale} = sub { use locale; $_[0] cmp $_[1] }; - -our $drh; -my $methods_are_installed = 0; - -sub driver { - return $drh if $drh; - - if (!$methods_are_installed && DBD::SQLite::NEWAPI ) { - DBI->setup_driver('DBD::SQLite'); - - DBD::SQLite::db->install_method('sqlite_last_insert_rowid'); - DBD::SQLite::db->install_method('sqlite_busy_timeout'); - DBD::SQLite::db->install_method('sqlite_create_function'); - DBD::SQLite::db->install_method('sqlite_create_aggregate'); - DBD::SQLite::db->install_method('sqlite_create_collation'); - DBD::SQLite::db->install_method('sqlite_collation_needed'); - DBD::SQLite::db->install_method('sqlite_progress_handler'); - DBD::SQLite::db->install_method('sqlite_commit_hook'); - DBD::SQLite::db->install_method('sqlite_rollback_hook'); - DBD::SQLite::db->install_method('sqlite_update_hook'); - DBD::SQLite::db->install_method('sqlite_set_authorizer'); - DBD::SQLite::db->install_method('sqlite_backup_from_file'); - DBD::SQLite::db->install_method('sqlite_backup_to_file'); - DBD::SQLite::db->install_method('sqlite_enable_load_extension'); - DBD::SQLite::db->install_method('sqlite_load_extension'); - DBD::SQLite::db->install_method('sqlite_register_fts3_perl_tokenizer'); - DBD::SQLite::db->install_method('sqlite_trace', { O => 0x0004 }); - DBD::SQLite::db->install_method('sqlite_profile', { O => 0x0004 }); - DBD::SQLite::db->install_method('sqlite_table_column_metadata', { O => 0x0004 }); - DBD::SQLite::db->install_method('sqlite_db_filename', { O => 0x0004 }); - DBD::SQLite::db->install_method('sqlite_db_status', { O => 0x0004 }); - DBD::SQLite::st->install_method('sqlite_st_status', { O => 0x0004 }); - DBD::SQLite::db->install_method('sqlite_create_module'); - - $methods_are_installed++; - } - - $drh = DBI::_new_drh( "$_[0]::dr", { - Name => 'SQLite', - Version => $VERSION, - Attribution => 'DBD::SQLite by Matt Sergeant et al', - } ); - - return $drh; -} - -sub CLONE { - undef $drh; -} - - -package # hide from PAUSE - DBD::SQLite::dr; - -sub connect { - my ($drh, $dbname, $user, $auth, $attr) = @_; - - # Default PrintWarn to the value of $^W - # unless ( defined $attr->{PrintWarn} ) { - # $attr->{PrintWarn} = $^W ? 1 : 0; - # } - - my $dbh = DBI::_new_dbh( $drh, { - Name => $dbname, - } ); - - my $real = $dbname; - if ( $dbname =~ /=/ ) { - foreach my $attrib ( split(/;/, $dbname) ) { - my ($key, $value) = split(/=/, $attrib, 2); - if ( $key =~ /^(?:db(?:name)?|database)$/ ) { - $real = $value; - } elsif ( $key eq 'uri' ) { - $real = $value; - $attr->{sqlite_open_flags} |= DBD::SQLite::OPEN_URI(); - } else { - $attr->{$key} = $value; - } - } - } - - if (my $flags = $attr->{sqlite_open_flags}) { - unless ($flags & (DBD::SQLite::OPEN_READONLY() | DBD::SQLite::OPEN_READWRITE())) { - $attr->{sqlite_open_flags} |= DBD::SQLite::OPEN_READWRITE() | DBD::SQLite::OPEN_CREATE(); - } - } - - # To avoid unicode and long file name problems on Windows, - # convert to the shortname if the file (or parent directory) exists. - if ( $^O =~ /MSWin32/ and $real ne ':memory:' and $real ne '' and $real !~ /^file:/ and !-f $real ) { - require File::Basename; - my ($file, $dir, $suffix) = File::Basename::fileparse($real); - # We are creating a new file. - # Does the directory it's in at least exist? - if ( -d $dir ) { - require Win32; - $real = join '', grep { defined } Win32::GetShortPathName($dir), $file, $suffix; - } else { - # SQLite can't do mkpath anyway. - # So let it go through as it and fail. - } - } - - # Hand off to the actual login function - DBD::SQLite::db::_login($dbh, $real, $user, $auth, $attr) or return undef; - - # Register the on-demand collation installer, REGEXP function and - # perl tokenizer - if ( DBD::SQLite::NEWAPI ) { - $dbh->sqlite_collation_needed( \&install_collation ); - $dbh->sqlite_create_function( "REGEXP", 2, \®exp ); - $dbh->sqlite_register_fts3_perl_tokenizer(); - } else { - $dbh->func( \&install_collation, "collation_needed" ); - $dbh->func( "REGEXP", 2, \®exp, "create_function" ); - $dbh->func( "register_fts3_perl_tokenizer" ); - } - - # HACK: Since PrintWarn = 0 doesn't seem to actually prevent warnings - # in DBD::SQLite we set Warn to false if PrintWarn is false. - - # NOTE: According to the explanation by timbunce, - # "Warn is meant to report on bad practices or problems with - # the DBI itself (hence always on by default), while PrintWarn - # is meant to report warnings coming from the database." - # That is, if you want to disable an ineffective rollback warning - # etc (due to bad practices), you should turn off Warn, - # and to silence other warnings, turn off PrintWarn. - # Warn and PrintWarn are independent, and turning off PrintWarn - # does not silence those warnings that should be controlled by - # Warn. - - # unless ( $attr->{PrintWarn} ) { - # $attr->{Warn} = 0; - # } - - return $dbh; -} - -sub install_collation { - my $dbh = shift; - my $name = shift; - my $collation = $DBD::SQLite::COLLATION{$name}; - unless ($collation) { - warn "Can't install unknown collation: $name" if $dbh->{PrintWarn}; - return; - } - if ( DBD::SQLite::NEWAPI ) { - $dbh->sqlite_create_collation( $name => $collation ); - } else { - $dbh->func( $name => $collation, "create_collation" ); - } -} - -# default implementation for sqlite 'REGEXP' infix operator. -# Note : args are reversed, i.e. "a REGEXP b" calls REGEXP(b, a) -# (see http://www.sqlite.org/vtab.html#xfindfunction) -sub regexp { - use locale; - return if !defined $_[0] || !defined $_[1]; - return scalar($_[1] =~ $_[0]); -} - -package # hide from PAUSE - DBD::SQLite::db; - -sub prepare { - my $dbh = shift; - my $sql = shift; - $sql = '' unless defined $sql; - - my $sth = DBI::_new_sth( $dbh, { - Statement => $sql, - } ); - - DBD::SQLite::st::_prepare($sth, $sql, @_) or return undef; - - return $sth; -} - -sub do { - my ($dbh, $statement, $attr, @bind_values) = @_; - - # shortcut - my $allow_multiple_statements = $dbh->FETCH('sqlite_allow_multiple_statements'); - if (defined $statement && !defined $attr && !@bind_values) { - # _do() (i.e. sqlite3_exec()) runs semicolon-separate SQL - # statements, which is handy but insecure sometimes. - # Use this only when it's safe or explicitly allowed. - if (index($statement, ';') == -1 or $allow_multiple_statements) { - return DBD::SQLite::db::_do($dbh, $statement); - } - } - - my @copy = @{[@bind_values]}; - my $rows = 0; - - while ($statement) { - my $sth = $dbh->prepare($statement, $attr) or return undef; - $sth->execute(splice @copy, 0, $sth->{NUM_OF_PARAMS}) or return undef; - $rows += $sth->rows; - # XXX: not sure why but $dbh->{sqlite...} wouldn't work here - last unless $allow_multiple_statements; - $statement = $sth->{sqlite_unprepared_statements}; - } - - # always return true if no error - return ($rows == 0) ? "0E0" : $rows; -} - -sub ping { - my $dbh = shift; - - # $file may be undef (ie. in-memory/temporary database) - my $file = DBD::SQLite::NEWAPI ? $dbh->sqlite_db_filename - : $dbh->func("db_filename"); - - return 0 if $file && !-f $file; - return $dbh->FETCH('Active') ? 1 : 0; -} - -sub _get_version { - return ( DBD::SQLite::db::FETCH($_[0], 'sqlite_version') ); -} - -my %info = ( - 17 => 'SQLite', # SQL_DBMS_NAME - 18 => \&_get_version, # SQL_DBMS_VER - 29 => '"', # SQL_IDENTIFIER_QUOTE_CHAR -); - -sub get_info { - my($dbh, $info_type) = @_; - my $v = $info{int($info_type)}; - $v = $v->($dbh) if ref $v eq 'CODE'; - return $v; -} - -sub _attached_database_list { - my $dbh = shift; - my @attached; - - my $sth_databases = $dbh->prepare( 'PRAGMA database_list' ) or return; - $sth_databases->execute or return; - while ( my $db_info = $sth_databases->fetchrow_hashref ) { - push @attached, $db_info->{name} if $db_info->{seq} >= 2; - } - return @attached; -} - -# SQL/CLI (ISO/IEC JTC 1/SC 32 N 0595), 6.63 Tables -# Based on DBD::Oracle's -# See also http://www.ch-werner.de/sqliteodbc/html/sqlite3odbc_8c.html#a213 -sub table_info { - my ($dbh, $cat_val, $sch_val, $tbl_val, $typ_val, $attr) = @_; - - my @where = (); - my $sql; - if ( defined($cat_val) && $cat_val eq '%' - && defined($sch_val) && $sch_val eq '' - && defined($tbl_val) && $tbl_val eq '') { # Rule 19a - $sql = <<'END_SQL'; -SELECT NULL TABLE_CAT - , NULL TABLE_SCHEM - , NULL TABLE_NAME - , NULL TABLE_TYPE - , NULL REMARKS -END_SQL - } - elsif ( defined($cat_val) && $cat_val eq '' - && defined($sch_val) && $sch_val eq '%' - && defined($tbl_val) && $tbl_val eq '') { # Rule 19b - $sql = <<'END_SQL'; -SELECT NULL TABLE_CAT - , t.tn TABLE_SCHEM - , NULL TABLE_NAME - , NULL TABLE_TYPE - , NULL REMARKS -FROM ( - SELECT 'main' tn - UNION SELECT 'temp' tn -END_SQL - for my $db_name (_attached_database_list($dbh)) { - $sql .= " UNION SELECT '$db_name' tn\n"; - } - $sql .= ") t\n"; - } - elsif ( defined($cat_val) && $cat_val eq '' - && defined($sch_val) && $sch_val eq '' - && defined($tbl_val) && $tbl_val eq '' - && defined($typ_val) && $typ_val eq '%') { # Rule 19c - $sql = <<'END_SQL'; -SELECT NULL TABLE_CAT - , NULL TABLE_SCHEM - , NULL TABLE_NAME - , t.tt TABLE_TYPE - , NULL REMARKS -FROM ( - SELECT 'TABLE' tt UNION - SELECT 'VIEW' tt UNION - SELECT 'LOCAL TEMPORARY' tt UNION - SELECT 'SYSTEM TABLE' tt -) t -ORDER BY TABLE_TYPE -END_SQL - } - else { - $sql = <<'END_SQL'; -SELECT * -FROM -( -SELECT NULL TABLE_CAT - , TABLE_SCHEM - , tbl_name TABLE_NAME - , TABLE_TYPE - , NULL REMARKS - , sql sqlite_sql -FROM ( - SELECT 'main' TABLE_SCHEM, tbl_name, upper(type) TABLE_TYPE, sql - FROM sqlite_master -UNION ALL - SELECT 'temp' TABLE_SCHEM, tbl_name, 'LOCAL TEMPORARY' TABLE_TYPE, sql - FROM sqlite_temp_master -END_SQL - - for my $db_name (_attached_database_list($dbh)) { - $sql .= <<"END_SQL"; -UNION ALL - SELECT '$db_name' TABLE_SCHEM, tbl_name, upper(type) TABLE_TYPE, sql - FROM "$db_name".sqlite_master -END_SQL - } - - $sql .= <<'END_SQL'; -UNION ALL - SELECT 'main' TABLE_SCHEM, 'sqlite_master' tbl_name, 'SYSTEM TABLE' TABLE_TYPE, NULL sql -UNION ALL - SELECT 'temp' TABLE_SCHEM, 'sqlite_temp_master' tbl_name, 'SYSTEM TABLE' TABLE_TYPE, NULL sql -) -) -END_SQL - $attr = {} unless ref $attr eq 'HASH'; - my $escape = defined $attr->{Escape} ? " ESCAPE '$attr->{Escape}'" : ''; - if ( defined $sch_val ) { - push @where, "TABLE_SCHEM LIKE '$sch_val'$escape"; - } - if ( defined $tbl_val ) { - push @where, "TABLE_NAME LIKE '$tbl_val'$escape"; - } - if ( defined $typ_val ) { - my $table_type_list; - $typ_val =~ s/^\s+//; - $typ_val =~ s/\s+$//; - my @ttype_list = split (/\s*,\s*/, $typ_val); - foreach my $table_type (@ttype_list) { - if ($table_type !~ /^'.*'$/) { - $table_type = "'" . $table_type . "'"; - } - } - $table_type_list = join(', ', @ttype_list); - push @where, "TABLE_TYPE IN (\U$table_type_list)" if $table_type_list; - } - $sql .= ' WHERE ' . join("\n AND ", @where ) . "\n" if @where; - $sql .= " ORDER BY TABLE_TYPE, TABLE_SCHEM, TABLE_NAME\n"; - } - my $sth = $dbh->prepare($sql) or return undef; - $sth->execute or return undef; - $sth; -} - -sub primary_key_info { - my ($dbh, $catalog, $schema, $table, $attr) = @_; - - my $databases = $dbh->selectall_arrayref("PRAGMA database_list", {Slice => {}}); - - my @pk_info; - for my $database (@$databases) { - my $dbname = $database->{name}; - next if defined $schema && $schema ne '%' && $schema ne $dbname; - - my $quoted_dbname = $dbh->quote_identifier($dbname); - - my $master_table = - ($dbname eq 'main') ? 'sqlite_master' : - ($dbname eq 'temp') ? 'sqlite_temp_master' : - $quoted_dbname.'.sqlite_master'; - - my $sth = $dbh->prepare("SELECT name, sql FROM $master_table WHERE type = ?") or return; - $sth->execute("table") or return; - while(my $row = $sth->fetchrow_hashref) { - my $tbname = $row->{name}; - next if defined $table && $table ne '%' && $table ne $tbname; - - my $quoted_tbname = $dbh->quote_identifier($tbname); - my $t_sth = $dbh->prepare("PRAGMA $quoted_dbname.table_info($quoted_tbname)") or return; - $t_sth->execute or return; - my @pk; - while(my $col = $t_sth->fetchrow_hashref) { - push @pk, $col->{name} if $col->{pk}; - } - - # If there're multiple primary key columns, we need to - # find their order from one of the auto-generated unique - # indices (note that single column integer primary key - # doesn't create an index). - if (@pk > 1 and $row->{sql} =~ /\bPRIMARY\s+KEY\s*\(\s* - ( - (?: - ( - [a-z_][a-z0-9_]* - | (["'`])(?:\3\3|(?!\3).)+?\3(?!\3) - | \[[^\]]+\] - ) - \s*,\s* - )+ - ( - [a-z_][a-z0-9_]* - | (["'`])(?:\5\5|(?!\5).)+?\5(?!\5) - | \[[^\]]+\] - ) - ) - \s*\)/six) { - my $pk_sql = $1; - @pk = (); - while($pk_sql =~ / - ( - [a-z_][a-z0-9_]* - | (["'`])(?:\2\2|(?!\2).)+?\2(?!\2) - | \[([^\]]+)\] - ) - (?:\s*,\s*|$) - /sixg) { - my($col, $quote, $brack) = ($1, $2, $3); - if ( defined $quote ) { - # Dequote "'` - $col = substr $col, 1, -1; - $col =~ s/$quote$quote/$quote/g; - } elsif ( defined $brack ) { - # Dequote [] - $col = $brack; - } - push @pk, $col; - } - } - - my $key_name = $row->{sql} =~ /\bCONSTRAINT\s+(\S+|"[^"]+")\s+PRIMARY\s+KEY\s*\(/i ? $1 : 'PRIMARY KEY'; - my $key_seq = 0; - foreach my $pk_field (@pk) { - push @pk_info, { - TABLE_SCHEM => $dbname, - TABLE_NAME => $tbname, - COLUMN_NAME => $pk_field, - KEY_SEQ => ++$key_seq, - PK_NAME => $key_name, - }; - } - } - } - - my $sponge = DBI->connect("DBI:Sponge:", '','') - or return $dbh->DBI::set_err($DBI::err, "DBI::Sponge: $DBI::errstr"); - my @names = qw(TABLE_CAT TABLE_SCHEM TABLE_NAME COLUMN_NAME KEY_SEQ PK_NAME); - my $sth = $sponge->prepare( "primary_key_info", { - rows => [ map { [ @{$_}{@names} ] } @pk_info ], - NUM_OF_FIELDS => scalar @names, - NAME => \@names, - }) or return $dbh->DBI::set_err( - $sponge->err, - $sponge->errstr, - ); - return $sth; -} - - -our %DBI_code_for_rule = ( # from DBI doc; curiously, they are not exported - # by the DBI module. - # codes for update/delete constraints - 'CASCADE' => 0, - 'RESTRICT' => 1, - 'SET NULL' => 2, - 'NO ACTION' => 3, - 'SET DEFAULT' => 4, - - # codes for deferrability - 'INITIALLY DEFERRED' => 5, - 'INITIALLY IMMEDIATE' => 6, - 'NOT DEFERRABLE' => 7, - ); - - -my @FOREIGN_KEY_INFO_ODBC = ( - 'PKTABLE_CAT', # The primary (unique) key table catalog identifier. - 'PKTABLE_SCHEM', # The primary (unique) key table schema identifier. - 'PKTABLE_NAME', # The primary (unique) key table identifier. - 'PKCOLUMN_NAME', # The primary (unique) key column identifier. - 'FKTABLE_CAT', # The foreign key table catalog identifier. - 'FKTABLE_SCHEM', # The foreign key table schema identifier. - 'FKTABLE_NAME', # The foreign key table identifier. - 'FKCOLUMN_NAME', # The foreign key column identifier. - 'KEY_SEQ', # The column sequence number (starting with 1). - 'UPDATE_RULE', # The referential action for the UPDATE rule. - 'DELETE_RULE', # The referential action for the DELETE rule. - 'FK_NAME', # The foreign key name. - 'PK_NAME', # The primary (unique) key name. - 'DEFERRABILITY', # The deferrability of the foreign key constraint. - 'UNIQUE_OR_PRIMARY', # qualifies the key referenced by the foreign key -); - -# Column names below are not used, but listed just for completeness's sake. -# Maybe we could add an option so that the user can choose which field -# names will be returned; the DBI spec is not very clear about ODBC vs. CLI. -my @FOREIGN_KEY_INFO_SQL_CLI = qw( - UK_TABLE_CAT - UK_TABLE_SCHEM - UK_TABLE_NAME - UK_COLUMN_NAME - FK_TABLE_CAT - FK_TABLE_SCHEM - FK_TABLE_NAME - FK_COLUMN_NAME - ORDINAL_POSITION - UPDATE_RULE - DELETE_RULE - FK_NAME - UK_NAME - DEFERABILITY - UNIQUE_OR_PRIMARY - ); - -sub foreign_key_info { - my ($dbh, $pk_catalog, $pk_schema, $pk_table, $fk_catalog, $fk_schema, $fk_table) = @_; - - my $databases = $dbh->selectall_arrayref("PRAGMA database_list", {Slice => {}}) or return; - - my @fk_info; - my %table_info; - for my $database (@$databases) { - my $dbname = $database->{name}; - next if defined $fk_schema && $fk_schema ne '%' && $fk_schema ne $dbname; - - my $quoted_dbname = $dbh->quote_identifier($dbname); - my $master_table = - ($dbname eq 'main') ? 'sqlite_master' : - ($dbname eq 'temp') ? 'sqlite_temp_master' : - $quoted_dbname.'.sqlite_master'; - - my $tables = $dbh->selectall_arrayref("SELECT name FROM $master_table WHERE type = ?", undef, "table") or return; - for my $table (@$tables) { - my $tbname = $table->[0]; - next if defined $fk_table && $fk_table ne '%' && $fk_table ne $tbname; - - my $quoted_tbname = $dbh->quote_identifier($tbname); - my $sth = $dbh->prepare("PRAGMA $quoted_dbname.foreign_key_list($quoted_tbname)") or return; - $sth->execute or return; - while(my $row = $sth->fetchrow_hashref) { - next if defined $pk_table && $pk_table ne '%' && $pk_table ne $row->{table}; - - unless ($table_info{$row->{table}}) { - my $quoted_tb = $dbh->quote_identifier($row->{table}); - for my $db (@$databases) { - my $quoted_db = $dbh->quote_identifier($db->{name}); - my $t_sth = $dbh->prepare("PRAGMA $quoted_db.table_info($quoted_tb)") or return; - $t_sth->execute or return; - my $cols = {}; - while(my $r = $t_sth->fetchrow_hashref) { - $cols->{$r->{name}} = $r->{pk}; - } - if (keys %$cols) { - $table_info{$row->{table}} = { - schema => $db->{name}, - columns => $cols, - }; - last; - } - } - } - - next if defined $pk_schema && $pk_schema ne '%' && $pk_schema ne $table_info{$row->{table}}{schema}; - - push @fk_info, { - PKTABLE_CAT => undef, - PKTABLE_SCHEM => $table_info{$row->{table}}{schema}, - PKTABLE_NAME => $row->{table}, - PKCOLUMN_NAME => $row->{to}, - FKTABLE_CAT => undef, - FKTABLE_SCHEM => $dbname, - FKTABLE_NAME => $tbname, - FKCOLUMN_NAME => $row->{from}, - KEY_SEQ => $row->{seq} + 1, - UPDATE_RULE => $DBI_code_for_rule{$row->{on_update}}, - DELETE_RULE => $DBI_code_for_rule{$row->{on_delete}}, - FK_NAME => undef, - PK_NAME => undef, - DEFERRABILITY => undef, - UNIQUE_OR_PRIMARY => $table_info{$row->{table}}{columns}{$row->{to}} ? 'PRIMARY' : 'UNIQUE', - }; - } - } - } - - my $sponge_dbh = DBI->connect("DBI:Sponge:", "", "") - or return $dbh->DBI::set_err($DBI::err, "DBI::Sponge: $DBI::errstr"); - my $sponge_sth = $sponge_dbh->prepare("foreign_key_info", { - NAME => \@FOREIGN_KEY_INFO_ODBC, - rows => [ map { [@{$_}{@FOREIGN_KEY_INFO_ODBC} ] } @fk_info ], - NUM_OF_FIELDS => scalar(@FOREIGN_KEY_INFO_ODBC), - }) or return $dbh->DBI::set_err( - $sponge_dbh->err, - $sponge_dbh->errstr, - ); - return $sponge_sth; -} - -my @STATISTICS_INFO_ODBC = ( - 'TABLE_CAT', # The catalog identifier. - 'TABLE_SCHEM', # The schema identifier. - 'TABLE_NAME', # The table identifier. - 'NON_UNIQUE', # Unique index indicator. - 'INDEX_QUALIFIER', # Index qualifier identifier. - 'INDEX_NAME', # The index identifier. - 'TYPE', # The type of information being returned. - 'ORDINAL_POSITION', # Column sequence number (starting with 1). - 'COLUMN_NAME', # The column identifier. - 'ASC_OR_DESC', # Column sort sequence. - 'CARDINALITY', # Cardinality of the table or index. - 'PAGES', # Number of storage pages used by this table or index. - 'FILTER_CONDITION', # The index filter condition as a string. -); - -sub statistics_info { - my ($dbh, $catalog, $schema, $table, $unique_only, $quick) = @_; - - my $databases = $dbh->selectall_arrayref("PRAGMA database_list", {Slice => {}}) or return; - - my @statistics_info; - for my $database (@$databases) { - my $dbname = $database->{name}; - next if defined $schema && $schema ne '%' && $schema ne $dbname; - - my $quoted_dbname = $dbh->quote_identifier($dbname); - my $master_table = - ($dbname eq 'main') ? 'sqlite_master' : - ($dbname eq 'temp') ? 'sqlite_temp_master' : - $quoted_dbname.'.sqlite_master'; - - my $tables = $dbh->selectall_arrayref("SELECT name FROM $master_table WHERE type = ?", undef, "table") or return; - for my $table_ref (@$tables) { - my $tbname = $table_ref->[0]; - next if defined $table && $table ne '%' && uc($table) ne uc($tbname); - - my $quoted_tbname = $dbh->quote_identifier($tbname); - my $sth = $dbh->prepare("PRAGMA $quoted_dbname.index_list($quoted_tbname)") or return; - $sth->execute or return; - while(my $row = $sth->fetchrow_hashref) { - - next if $unique_only && !$row->{unique}; - my $quoted_idx = $dbh->quote_identifier($row->{name}); - for my $db (@$databases) { - my $quoted_db = $dbh->quote_identifier($db->{name}); - my $i_sth = $dbh->prepare("PRAGMA $quoted_db.index_info($quoted_idx)") or return; - $i_sth->execute or return; - my $cols = {}; - while(my $info = $i_sth->fetchrow_hashref) { - push @statistics_info, { - TABLE_CAT => undef, - TABLE_SCHEM => $db->{name}, - TABLE_NAME => $tbname, - NON_UNIQUE => $row->{unique} ? 0 : 1, - INDEX_QUALIFIER => undef, - INDEX_NAME => $row->{name}, - TYPE => 'btree', # see http://www.sqlite.org/version3.html esp. "Traditional B-trees are still used for indices" - ORDINAL_POSITION => $info->{seqno} + 1, - COLUMN_NAME => $info->{name}, - ASC_OR_DESC => undef, - CARDINALITY => undef, - PAGES => undef, - FILTER_CONDITION => undef, - }; - } - } - } - } - } - - my $sponge_dbh = DBI->connect("DBI:Sponge:", "", "") - or return $dbh->DBI::set_err($DBI::err, "DBI::Sponge: $DBI::errstr"); - my $sponge_sth = $sponge_dbh->prepare("statistics_info", { - NAME => \@STATISTICS_INFO_ODBC, - rows => [ map { [@{$_}{@STATISTICS_INFO_ODBC} ] } @statistics_info ], - NUM_OF_FIELDS => scalar(@STATISTICS_INFO_ODBC), - }) or return $dbh->DBI::set_err( - $sponge_dbh->err, - $sponge_dbh->errstr, - ); - return $sponge_sth; -} - -sub type_info_all { - return; # XXX code just copied from DBD::Oracle, not yet thought about -# return [ -# { -# TYPE_NAME => 0, -# DATA_TYPE => 1, -# COLUMN_SIZE => 2, -# LITERAL_PREFIX => 3, -# LITERAL_SUFFIX => 4, -# CREATE_PARAMS => 5, -# NULLABLE => 6, -# CASE_SENSITIVE => 7, -# SEARCHABLE => 8, -# UNSIGNED_ATTRIBUTE => 9, -# FIXED_PREC_SCALE => 10, -# AUTO_UNIQUE_VALUE => 11, -# LOCAL_TYPE_NAME => 12, -# MINIMUM_SCALE => 13, -# MAXIMUM_SCALE => 14, -# SQL_DATA_TYPE => 15, -# SQL_DATETIME_SUB => 16, -# NUM_PREC_RADIX => 17, -# }, -# [ 'CHAR', 1, 255, '\'', '\'', 'max length', 1, 1, 3, -# undef, '0', '0', undef, undef, undef, 1, undef, undef -# ], -# [ 'NUMBER', 3, 38, undef, undef, 'precision,scale', 1, '0', 3, -# '0', '0', '0', undef, '0', 38, 3, undef, 10 -# ], -# [ 'DOUBLE', 8, 15, undef, undef, undef, 1, '0', 3, -# '0', '0', '0', undef, undef, undef, 8, undef, 10 -# ], -# [ 'DATE', 9, 19, '\'', '\'', undef, 1, '0', 3, -# undef, '0', '0', undef, '0', '0', 11, undef, undef -# ], -# [ 'VARCHAR', 12, 1024*1024, '\'', '\'', 'max length', 1, 1, 3, -# undef, '0', '0', undef, undef, undef, 12, undef, undef -# ] -# ]; -} - -my @COLUMN_INFO = qw( - TABLE_CAT - TABLE_SCHEM - TABLE_NAME - COLUMN_NAME - DATA_TYPE - TYPE_NAME - COLUMN_SIZE - BUFFER_LENGTH - DECIMAL_DIGITS - NUM_PREC_RADIX - NULLABLE - REMARKS - COLUMN_DEF - SQL_DATA_TYPE - SQL_DATETIME_SUB - CHAR_OCTET_LENGTH - ORDINAL_POSITION - IS_NULLABLE -); - -sub column_info { - my ($dbh, $cat_val, $sch_val, $tbl_val, $col_val) = @_; - - if ( defined $col_val and $col_val eq '%' ) { - $col_val = undef; - } - - # Get a list of all tables ordered by TABLE_SCHEM, TABLE_NAME - my $sql = <<'END_SQL'; -SELECT TABLE_SCHEM, tbl_name TABLE_NAME -FROM ( - SELECT 'main' TABLE_SCHEM, tbl_name - FROM sqlite_master - WHERE type IN ('table','view') -UNION ALL - SELECT 'temp' TABLE_SCHEM, tbl_name - FROM sqlite_temp_master - WHERE type IN ('table','view') -END_SQL - - for my $db_name (_attached_database_list($dbh)) { - $sql .= <<"END_SQL"; -UNION ALL - SELECT '$db_name' TABLE_SCHEM, tbl_name - FROM "$db_name".sqlite_master - WHERE type IN ('table','view') -END_SQL - } - - $sql .= <<'END_SQL'; -UNION ALL - SELECT 'main' TABLE_SCHEM, 'sqlite_master' tbl_name -UNION ALL - SELECT 'temp' TABLE_SCHEM, 'sqlite_temp_master' tbl_name -) -END_SQL - - my @where; - if ( defined $sch_val ) { - push @where, "TABLE_SCHEM LIKE '$sch_val'"; - } - if ( defined $tbl_val ) { - push @where, "TABLE_NAME LIKE '$tbl_val'"; - } - $sql .= ' WHERE ' . join("\n AND ", @where ) . "\n" if @where; - $sql .= " ORDER BY TABLE_SCHEM, TABLE_NAME\n"; - my $sth_tables = $dbh->prepare($sql) or return undef; - $sth_tables->execute or return undef; - - # Taken from Fey::Loader::SQLite - my @cols; - while ( my ($schema, $table) = $sth_tables->fetchrow_array ) { - my $sth_columns = $dbh->prepare(qq{PRAGMA "$schema".table_info("$table")}) or return; - $sth_columns->execute or return; - - for ( my $position = 1; my $col_info = $sth_columns->fetchrow_hashref; $position++ ) { - if ( defined $col_val ) { - # This must do a LIKE comparison - my $sth = $dbh->prepare("SELECT '$col_info->{name}' LIKE '$col_val'") or return undef; - $sth->execute or return undef; - # Skip columns that don't match $col_val - next unless ($sth->fetchrow_array)[0]; - } - - my %col = ( - TABLE_SCHEM => $schema, - TABLE_NAME => $table, - COLUMN_NAME => $col_info->{name}, - ORDINAL_POSITION => $position, - ); - - my $type = $col_info->{type}; - if ( $type =~ s/(\w+)\s*\(\s*(\d+)(?:\s*,\s*(\d+))?\s*\)/$1/ ) { - $col{COLUMN_SIZE} = $2; - $col{DECIMAL_DIGITS} = $3; - } - - $col{TYPE_NAME} = $type; - - if ( defined $col_info->{dflt_value} ) { - $col{COLUMN_DEF} = $col_info->{dflt_value} - } - - if ( $col_info->{notnull} ) { - $col{NULLABLE} = 0; - $col{IS_NULLABLE} = 'NO'; - } else { - $col{NULLABLE} = 1; - $col{IS_NULLABLE} = 'YES'; - } - - push @cols, \%col; - } - $sth_columns->finish; - } - $sth_tables->finish; - - my $sponge = DBI->connect("DBI:Sponge:", '','') - or return $dbh->DBI::set_err($DBI::err, "DBI::Sponge: $DBI::errstr"); - $sponge->prepare( "column_info", { - rows => [ map { [ @{$_}{@COLUMN_INFO} ] } @cols ], - NUM_OF_FIELDS => scalar @COLUMN_INFO, - NAME => [ @COLUMN_INFO ], - } ) or return $dbh->DBI::set_err( - $sponge->err, - $sponge->errstr, - ); -} - -#====================================================================== -# An internal tied hash package used for %DBD::SQLite::COLLATION, to -# prevent people from unintentionally overriding globally registered collations. - -package # hide from PAUSE - DBD::SQLite::_WriteOnceHash; - -require Tie::Hash; - -our @ISA = qw(Tie::StdHash); - -sub TIEHASH { - bless {}, $_[0]; -} - -sub STORE { - ! exists $_[0]->{$_[1]} or die "entry $_[1] already registered"; - $_[0]->{$_[1]} = $_[2]; -} - -sub DELETE { - die "deletion of entry $_[1] is forbidden"; -} - -1; - -__END__ - -=pod - -=encoding utf-8 - -=head1 NAME - -DBD::SQLite - Self-contained RDBMS in a DBI Driver - -=head1 SYNOPSIS - - use DBI; - my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","",""); - -=head1 DESCRIPTION - -SQLite is a public domain file-based relational database engine that -you can find at L. - -B is a Perl DBI driver for SQLite, that includes -the entire thing in the distribution. -So in order to get a fast transaction capable RDBMS working for your -perl project you simply have to install this module, and B -else. - -SQLite supports the following features: - -=over 4 - -=item Implements a large subset of SQL92 - -See L for details. - -=item A complete DB in a single disk file - -Everything for your database is stored in a single disk file, making it -easier to move things around than with L. - -=item Atomic commit and rollback - -Yes, B is small and light, but it supports full transactions! - -=item Extensible - -User-defined aggregate or regular functions can be registered with the -SQL parser. - -=back - -There's lots more to it, so please refer to the docs on the SQLite web -page, listed above, for SQL details. Also refer to L for details -on how to use DBI itself. The API works like every DBI module does. -However, currently many statement attributes are not implemented or -are limited by the typeless nature of the SQLite database. - -=head1 SQLITE VERSION - -DBD::SQLite is usually compiled with a bundled SQLite library -(SQLite version S<3.22.0> as of this release) for consistency. -However, a different version of SQLite may sometimes be used for -some reasons like security, or some new experimental features. - -You can look at C<$DBD::SQLite::sqlite_version> (C<3.x.y> format) or -C<$DBD::SQLite::sqlite_version_number> (C<3xxxyyy> format) -to find which version of SQLite is actually used. You can also -check C. - -You can also find how the library is compiled by calling -C (see below). - -=head1 NOTABLE DIFFERENCES FROM OTHER DRIVERS - -=head2 Database Name Is A File Name - -SQLite creates a file per a database. You should pass the C of -the database file (with or without a parent directory) in the DBI -connection string (as a database C): - - my $dbh = DBI->connect("dbi:SQLite:dbname=$dbfile","",""); - -The file is opened in read/write mode, and will be created if -it does not exist yet. - -Although the database is stored in a single file, the directory -containing the database file must be writable by SQLite because the -library will create several temporary files there. - -If the filename C<$dbfile> is ":memory:", then a private, temporary -in-memory database is created for the connection. This in-memory -database will vanish when the database connection is closed. -It is handy for your library tests. - -Note that future versions of SQLite might make use of additional -special filenames that begin with the ":" character. It is recommended -that when a database filename actually does begin with a ":" character -you should prefix the filename with a pathname such as "./" to avoid -ambiguity. - -If the filename C<$dbfile> is an empty string, then a private, -temporary on-disk database will be created. This private database will -be automatically deleted as soon as the database connection is closed. - -As of 1.41_01, you can pass URI filename (see L) -as well for finer control: - - my $dbh = DBI->connect("dbi:SQLite:uri=file:$path_to_dbfile?mode=rwc"); - -Note that this is not for remote SQLite database connection. You can -only connect to a local database. - -=head2 Read-Only Database - -You can set sqlite_open_flags (only) when you connect to a database: - - use DBD::SQLite::Constants qw/:file_open/; - my $dbh = DBI->connect("dbi:SQLite:$dbfile", undef, undef, { - sqlite_open_flags => SQLITE_OPEN_READONLY, - }); - -See L for details. - -As of 1.49_05, you can also make a database read-only by setting -C attribute to true (only) when you connect to a database. -Actually you can set it after you connect, but in that case, it -can't make the database read-only, and you'll see a warning (which -you can hide by turning C off). - -=head2 DBD::SQLite And File::Temp - -When you use L to create a temporary file/directory for -SQLite databases, you need to remember: - -=over 4 - -=item tempfile may be locked exclusively - -You may want to use C to create a temporary database -filename for DBD::SQLite, but as noted in L's POD, -this file may have an exclusive lock under some operating systems -(notably Mac OSX), and result in a "database is locked" error. -To avoid this, set EXLOCK option to false when you call tempfile(). - - ($fh, $filename) = tempfile($template, EXLOCK => 0); - -=item CLEANUP may not work unless a database is disconnected - -When you set CLEANUP option to true when you create a temporary -directory with C or C, you may have to -disconnect databases explicitly before the temporary directory -is gone (notably under MS Windows). - -=back - -(The above is quoted from the pod of File::Temp.) - -If you don't need to keep or share a temporary database, -use ":memory:" database instead. It's much handier and cleaner -for ordinary testing. - -=head2 DBD::SQLite and fork() - -Follow the advice in the SQLite FAQ (L). - -=over 4 - -Under Unix, you should not carry an open SQLite database across -a fork() system call into the child process. Problems will result -if you do. - -=back - -You shouldn't (re)use a database handle you created (probably to -set up a database schema etc) before you fork(). Otherwise, you -might see a database corruption in the worst case. - -If you need to fork(), (re)open a database after you fork(). -You might also want to tweak C and -C (see below), depending -on your needs. - -If you need a higher level of concurrency than SQLite supports, -consider using other client/server database engines. - -=head2 Accessing A Database With Other Tools - -To access the database from the command line, try using C -which comes with the L module. Just type: - - dbish dbi:SQLite:foo.db - -On the command line to access the file F. - -Alternatively you can install SQLite from the link above without -conflicting with B and use the supplied C -command line tool. - -=head2 Blobs - -As of version 1.11, blobs should "just work" in SQLite as text columns. -However this will cause the data to be treated as a string, so SQL -statements such as length(x) will return the length of the column as a NUL -terminated string, rather than the size of the blob in bytes. In order to -store natively as a BLOB use the following code: - - use DBI qw(:sql_types); - my $dbh = DBI->connect("dbi:SQLite:dbfile","",""); - - my $blob = `cat foo.jpg`; - my $sth = $dbh->prepare("INSERT INTO mytable VALUES (1, ?)"); - $sth->bind_param(1, $blob, SQL_BLOB); - $sth->execute(); - -And then retrieval just works: - - $sth = $dbh->prepare("SELECT * FROM mytable WHERE id = 1"); - $sth->execute(); - my $row = $sth->fetch; - my $blobo = $row->[1]; - - # now $blobo == $blob - -=head2 Functions And Bind Parameters - -As of this writing, a SQL that compares a return value of a function -with a numeric bind value like this doesn't work as you might expect. - - my $sth = $dbh->prepare(q{ - SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?; - }); - $sth->execute(5); - -This is because DBD::SQLite assumes that all the bind values are text -(and should be quoted) by default. Thus the above statement becomes -like this while executing: - - SELECT bar FROM foo GROUP BY bar HAVING count(*) > "5"; - -There are three workarounds for this. - -=over 4 - -=item Use bind_param() explicitly - -As shown above in the C section, you can always use -C to tell the type of a bind value. - - use DBI qw(:sql_types); # Don't forget this - - my $sth = $dbh->prepare(q{ - SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?; - }); - $sth->bind_param(1, 5, SQL_INTEGER); - $sth->execute(); - -=item Add zero to make it a number - -This is somewhat weird, but works anyway. - - my $sth = $dbh->prepare(q{ - SELECT bar FROM foo GROUP BY bar HAVING count(*) > (? + 0); - }); - $sth->execute(5); - -=item Set C database handle attribute - -As of version 1.32_02, you can use C -to let DBD::SQLite to see if the bind values are numbers or not. - - $dbh->{sqlite_see_if_its_a_number} = 1; - my $sth = $dbh->prepare(q{ - SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?; - }); - $sth->execute(5); - -You can set it to true when you connect to a database. - - my $dbh = DBI->connect('dbi:SQLite:foo', undef, undef, { - AutoCommit => 1, - RaiseError => 1, - sqlite_see_if_its_a_number => 1, - }); - -This is the most straightforward solution, but as noted above, -existing data in your databases created by DBD::SQLite have not -always been stored as numbers, so this *might* cause other obscure -problems. Use this sparingly when you handle existing databases. -If you handle databases created by other tools like native C -command line tool, this attribute would help you. - -As of 1.41_04, C works only for -bind values with no explicit type. - - my $dbh = DBI->connect('dbi:SQLite:foo', undef, undef, { - AutoCommit => 1, - RaiseError => 1, - sqlite_see_if_its_a_number => 1, - }); - my $sth = $dbh->prepare('INSERT INTO foo VALUES(?)'); - # '1.230' will be inserted as a text, instead of 1.23 as a number, - # even though sqlite_see_if_its_a_number is set. - $sth->bind_param(1, '1.230', SQL_VARCHAR); - $sth->execute; - -=back - -=head2 Placeholders - -SQLite supports several placeholder expressions, including C -and C<:AAAA>. Consult the L and SQLite documentation for -details. - -L - -Note that a question mark actually means a next unused (numbered) -placeholder. You're advised not to use it with other (numbered or -named) placeholders to avoid confusion. - - my $sth = $dbh->prepare( - 'update TABLE set a=?1 where b=?2 and a IS NOT ?1' - ); - $sth->execute(1, 2); - -=head2 Pragma - -SQLite has a set of "Pragma"s to modify its operation or to query -for its internal data. These are specific to SQLite and are not -likely to work with other DBD libraries, but you may find some of -these are quite useful, including: - -=over 4 - -=item journal_mode - -You can use this pragma to change the journal mode for SQLite -databases, maybe for better performance, or for compatibility. - -Its default mode is C, which means SQLite uses a rollback -journal to implement transactions, and the journal is deleted -at the conclusion of each transaction. If you use C -instead of C, the journal will be truncated, which is -usually much faster. - -A C (write-ahead log) mode is introduced as of SQLite 3.7.0. -This mode is persistent, and it stays in effect even after -closing and reopening the database. In other words, once the C -mode is set in an application or in a test script, the database -becomes inaccessible by older clients. This tends to be an issue -when you use a system C executable under a conservative -operating system. - -To fix this, You need to issue C -(or C) beforehand, or install a newer version of -C. - -=item legacy_file_format - -If you happen to need to create a SQLite database that will also -be accessed by a very old SQLite client (prior to 3.3.0 released -in Jan. 2006), you need to set this pragma to ON before you create -a database. - -=item reverse_unordered_selects - -You can set this pragma to ON to reverse the order of results of -SELECT statements without an ORDER BY clause so that you can see -if applications are making invalid assumptions about the result -order. - -Note that SQLite 3.7.15 (bundled with DBD::SQLite 1.38_02) enhanced -its query optimizer and the order of results of a SELECT statement -without an ORDER BY clause may be different from the one of the -previous versions. - -=item synchronous - -You can set set this pragma to OFF to make some of the operations -in SQLite faster with a possible risk of database corruption -in the worst case. See also L section below. - -=back - -See L for more details. - -=head2 Foreign Keys - -SQLite has started supporting foreign key constraints since 3.6.19 -(released on Oct 14, 2009; bundled in DBD::SQLite 1.26_05). -To be exact, SQLite has long been able to parse a schema with foreign -keys, but the constraints has not been enforced. Now you can issue -a C pragma to enable this feature and enforce the -constraints, preferably as soon as you connect to a database and -you're not in a transaction: - - $dbh->do("PRAGMA foreign_keys = ON"); - -And you can explicitly disable the feature whenever you like by -turning the pragma off: - - $dbh->do("PRAGMA foreign_keys = OFF"); - -As of this writing, this feature is disabled by default by the -SQLite team, and by us, to secure backward compatibility, as -this feature may break your applications, and actually broke -some for us. If you have used a schema with foreign key constraints -but haven't cared them much and supposed they're always ignored for -SQLite, be prepared, and please do extensive testing to ensure -that your applications will continue to work when the foreign keys -support is enabled by default. - -See L for details. - -=head2 Transactions - -DBI/DBD::SQLite's transactions may be a bit confusing. They behave -differently according to the status of the C flag: - -=over 4 - -=item When the AutoCommit flag is on - -You're supposed to always use the auto-commit mode, except you -explicitly begin a transaction, and when the transaction ended, -you're supposed to go back to the auto-commit mode. To begin a -transaction, call C method, or issue a C -statement. To end it, call C methods, or issue -the corresponding statements. - - $dbh->{AutoCommit} = 1; - - $dbh->begin_work; # or $dbh->do('BEGIN TRANSACTION'); - - # $dbh->{AutoCommit} is turned off temporarily during a transaction; - - $dbh->commit; # or $dbh->do('COMMIT'); - - # $dbh->{AutoCommit} is turned on again; - -=item When the AutoCommit flag is off - -You're supposed to always use the transactional mode, until you -explicitly turn on the AutoCommit flag. You can explicitly issue -a C statement (only when an actual transaction has not -begun yet) but you're not allowed to call C method -(if you don't issue a C, it will be issued internally). -You can commit or roll it back freely. Another transaction will -automatically begin if you execute another statement. - - $dbh->{AutoCommit} = 0; - - # $dbh->do('BEGIN TRANSACTION') is not necessary, but possible - - ... - - $dbh->commit; # or $dbh->do('COMMIT'); - - # $dbh->{AutoCommit} stays intact; - - $dbh->{AutoCommit} = 1; # ends the transactional mode - -=back - -This C mode is independent from the autocommit mode -of the internal SQLite library, which always begins by a C -statement, and ends by a C or a . - -=head2 Transaction and Database Locking - -The default transaction behavior of SQLite is C, that -means, locks are not acquired until the first read or write -operation, and thus it is possible that another thread or process -could create a separate transaction and write to the database after -the C on the current thread has executed, and eventually -cause a "deadlock". To avoid this, DBD::SQLite internally issues -a C if you begin a transaction by calling -C or by turning off C (since 1.38_01). - -If you really need to turn off this feature for some reasons, -set C database handle attribute -to false, and the default C transaction will be used. - - my $dbh = DBI->connect("dbi:SQLite::memory:", "", "", { - sqlite_use_immediate_transaction => 0, - }); - -Or, issue a C statement explicitly each time you begin -a transaction. - -See L for locking details. - -=head2 C<< $sth->finish >> and Transaction Rollback - -As the L doc says, you almost certainly do B need to -call L method if you fetch all rows (probably in a loop). -However, there are several exceptions to this rule, and rolling-back -of an unfinished C statements in -a transaction (See L for -details). So you need to call C before you issue a rollback. - - $sth = $dbh->prepare("SELECT * FROM t"); - $dbh->begin_work; - eval { - $sth->execute; - $row = $sth->fetch; - ... - die "For some reason"; - ... - }; - if($@) { - $sth->finish; # You need this for SQLite - $dbh->rollback; - } else { - $dbh->commit; - } - -=head2 Processing Multiple Statements At A Time - -L's statement handle is not supposed to process multiple -statements at a time. So if you pass a string that contains multiple -statements (a C) to a statement handle (via C or C), -L only processes the first statement, and discards the -rest. - -If you need to process multiple statements at a time, set -a C attribute of a database handle -to true when you connect to a database, and C method takes care -of the rest (since 1.30_01, and without creating DBI's statement -handles internally since 1.47_01). If you do need to use C -or C (which I don't recommend in this case, because -typically there's no placeholder nor reusable part in a dump), -you can look at << $sth->{sqlite_unprepared_statements} >> to retrieve -what's left, though it usually contains nothing but white spaces. - -=head2 Performance - -SQLite is fast, very fast. Matt processed his 72MB log file with it, -inserting the data (400,000+ rows) by using transactions and only -committing every 1000 rows (otherwise the insertion is quite slow), -and then performing queries on the data. - -Queries like count(*) and avg(bytes) took fractions of a second to -return, but what surprised him most of all was: - - SELECT url, count(*) as count - FROM access_log - GROUP BY url - ORDER BY count desc - LIMIT 20 - -To discover the top 20 hit URLs on the site (L), -and it returned within 2 seconds. He was seriously considering -switching his log analysis code to use this little speed demon! - -Oh yeah, and that was with no indexes on the table, on a 400MHz PIII. - -For best performance be sure to tune your hdparm settings if you -are using linux. Also you might want to set: - - PRAGMA synchronous = OFF - -Which will prevent SQLite from doing fsync's when writing (which -slows down non-transactional writes significantly) at the expense -of some peace of mind. Also try playing with the cache_size pragma. - -The memory usage of SQLite can also be tuned using the cache_size -pragma. - - $dbh->do("PRAGMA cache_size = 800000"); - -The above will allocate 800M for DB cache; the default is 2M. -Your sweet spot probably lies somewhere in between. - -=head1 DRIVER PRIVATE ATTRIBUTES - -=head2 Database Handle Attributes - -=over 4 - -=item sqlite_version - -Returns the version of the SQLite library which B is using, -e.g., "2.8.0". Can only be read. - -=item sqlite_unicode - -If set to a true value, B will turn the UTF-8 flag on for all -text strings coming out of the database (this feature is currently disabled -for perl < 5.8.5). For more details on the UTF-8 flag see -L. The default is for the UTF-8 flag to be turned off. - -Also note that due to some bizarreness in SQLite's type system (see -L), if you want to retain -blob-style behavior for B columns under C<< $dbh->{sqlite_unicode} = 1 ->> (say, to store images in the database), you have to state so -explicitly using the 3-argument form of L when doing -updates: - - use DBI qw(:sql_types); - $dbh->{sqlite_unicode} = 1; - my $sth = $dbh->prepare("INSERT INTO mytable (blobcolumn) VALUES (?)"); - - # Binary_data will be stored as is. - $sth->bind_param(1, $binary_data, SQL_BLOB); - -Defining the column type as C in the DDL is B sufficient. - -This attribute was originally named as C, and renamed to -C for integrity since version 1.26_06. Old C -attribute is still accessible but will be deprecated in the near future. - -=item sqlite_allow_multiple_statements - -If you set this to true, C method will process multiple -statements at one go. This may be handy, but with performance -penalty. See above for details. - -=item sqlite_use_immediate_transaction - -If you set this to true, DBD::SQLite tries to issue a C (instead of C) when -necessary. See above for details. - -As of version 1.38_01, this attribute is set to true by default. -If you really need to use C transactions for some reasons, -set this to false explicitly. - -=item sqlite_see_if_its_a_number - -If you set this to true, DBD::SQLite tries to see if the bind values -are number or not, and does not quote if they are numbers. See above -for details. - -=item sqlite_extended_result_codes - -If set to true, DBD::SQLite uses extended result codes where appropriate -(see L). - -=back - -=head2 Statement Handle Attributes - -=over 4 - -=item sqlite_unprepared_statements - -Returns an unprepared part of the statement you pass to C. -Typically this contains nothing but white spaces after a semicolon. -See above for details. - -=back - -=head1 METHODS - -See also to the L documentation for the details of other common -methods. - -=head2 table_info - - $sth = $dbh->table_info(undef, $schema, $table, $type, \%attr); - -Returns all tables and schemas (databases) as specified in L. -The schema and table arguments will do a C search. You can specify an -ESCAPE character by including an 'Escape' attribute in \%attr. The C<$type> -argument accepts a comma separated list of the following types 'TABLE', -'VIEW', 'LOCAL TEMPORARY' and 'SYSTEM TABLE' (by default all are returned). -Note that a statement handle is returned, and not a direct list of tables. - -The following fields are returned: - -B: Always NULL, as SQLite does not have the concept of catalogs. - -B: The name of the schema (database) that the table or view is -in. The default schema is 'main', temporary tables are in 'temp' and other -databases will be in the name given when the database was attached. - -B: The name of the table or view. - -B: The type of object returned. Will be one of 'TABLE', 'VIEW', -'LOCAL TEMPORARY' or 'SYSTEM TABLE'. - -=head2 primary_key, primary_key_info - - @names = $dbh->primary_key(undef, $schema, $table); - $sth = $dbh->primary_key_info(undef, $schema, $table, \%attr); - -You can retrieve primary key names or more detailed information. -As noted above, SQLite does not have the concept of catalogs, so the -first argument of the methods is usually C, and you'll usually -set C for the second one (unless you want to know the primary -keys of temporary tables). - - -=head2 foreign_key_info - - $sth = $dbh->foreign_key_info(undef, $pk_schema, $pk_table, - undef, $fk_schema, $fk_table); - -Returns information about foreign key constraints, as specified in -L, but with some limitations : - -=over - -=item * - -information in rows returned by the C<$sth> is incomplete with -respect to the L specification. All requested fields -are present, but the content is C for some of them. - -=back - -The following nonempty fields are returned : - -B: -The primary (unique) key table identifier. - -B: -The primary (unique) key column identifier. - -B: -The foreign key table identifier. - -B: -The foreign key column identifier. - -B: -The column sequence number (starting with 1), when -several columns belong to a same constraint. - -B: -The referential action for the UPDATE rule. -The following codes are defined: - - CASCADE 0 - RESTRICT 1 - SET NULL 2 - NO ACTION 3 - SET DEFAULT 4 - -Default is 3 ('NO ACTION'). - -B: -The referential action for the DELETE rule. -The codes are the same as for UPDATE_RULE. - -Unfortunately, the B field is always C; -as a matter of fact, deferrability clauses are supported by SQLite, -but they can't be reported because the C -tells nothing about them. - -B: -Whether the column is primary or unique. - -B: foreign key support in SQLite must be explicitly turned on through -a C command; see L earlier in this manual. - -=head2 statistics_info - - $sth = $dbh->statistics_info(undef, $schema, $table, - $unique_only, $quick); - -Returns information about a table and it's indexes, as specified in -L, but with some limitations : - -=over - -=item * - -information in rows returned by the C<$sth> is incomplete with -respect to the L specification. All requested fields -are present, but the content is C for some of them. - -=back - -The following nonempty fields are returned : - -B: -The name of the schema (database) that the table is in. The default schema is 'main', temporary tables are in 'temp' and other databases will be in the name given when the database was attached. - -B: -The name of the table - -B: -Contains 0 for unique indexes, 1 for non-unique indexes - -B: -The name of the index - -B: -SQLite uses 'btree' for all it's indexes - -B: -Column sequence number (starting with 1). - -B: -The name of the column - -=head2 ping - - my $bool = $dbh->ping; - -returns true if the database file exists (or the database is in-memory), and the database connection is active. - -=head1 DRIVER PRIVATE METHODS - -The following methods can be called via the func() method with a little -tweak, but the use of func() method is now discouraged by the L author -for various reasons (see DBI's document -L -for details). So, if you're using L >= 1.608, use these C -methods. If you need to use an older L, you can call these like this: - - $dbh->func( ..., "(method name without sqlite_ prefix)" ); - -Exception: C should always be called as is, even with C -method (to avoid conflict with DBI's trace() method). - - $dbh->func( ..., "sqlite_trace"); - -=head2 $dbh->sqlite_last_insert_rowid() - -This method returns the last inserted rowid. If you specify an INTEGER PRIMARY -KEY as the first column in your table, that is the column that is returned. -Otherwise, it is the hidden ROWID column. See the SQLite docs for details. - -Generally you should not be using this method. Use the L last_insert_id -method instead. The usage of this is: - - $h->last_insert_id($catalog, $schema, $table_name, $field_name [, \%attr ]) - -Running C<$h-Elast_insert_id("","","","")> is the equivalent of running -C<$dbh-Esqlite_last_insert_rowid()> directly. - -=head2 $dbh->sqlite_db_filename() - -Retrieve the current (main) database filename. If the database is in-memory or temporary, this returns C. - -=head2 $dbh->sqlite_busy_timeout() - -Retrieve the current busy timeout. - -=head2 $dbh->sqlite_busy_timeout( $ms ) - -Set the current busy timeout. The timeout is in milliseconds. - -=head2 $dbh->sqlite_create_function( $name, $argc, $code_ref, $flags ) - -This method will register a new function which will be usable in an SQL -query. The method's parameters are: - -=over - -=item $name - -The name of the function. This is the name of the function as it will -be used from SQL. - -=item $argc - -The number of arguments taken by the function. If this number is -1, -the function can take any number of arguments. - -=item $code_ref - -This should be a reference to the function's implementation. - -=item $flags - -You can optionally pass an extra flag bit to create_function, which then would be ORed with SQLITE_UTF8 (default). As of 1.47_02 (SQLite 3.8.9), only meaning bit is SQLITE_DETERMINISTIC (introduced at SQLite 3.8.3), which can make the function perform better. See C API documentation at L for details. - -=back - -For example, here is how to define a now() function which returns the -current number of seconds since the epoch: - - $dbh->sqlite_create_function( 'now', 0, sub { return time } ); - -After this, it could be used from SQL as: - - INSERT INTO mytable ( now() ); - -=head3 REGEXP function - -SQLite includes syntactic support for an infix operator 'REGEXP', but -without any implementation. The C driver -automatically registers an implementation that performs standard -perl regular expression matching, using current locale. So for example -you can search for words starting with an 'A' with a query like - - SELECT * from table WHERE column REGEXP '\bA\w+' - -If you want case-insensitive searching, use perl regex flags, like this : - - SELECT * from table WHERE column REGEXP '(?i:\bA\w+)' - -The default REGEXP implementation can be overridden through the -C API described above. - -Note that regexp matching will B use SQLite indices, but will iterate -over all rows, so it could be quite costly in terms of performance. - -=head2 $dbh->sqlite_create_collation( $name, $code_ref ) - -This method manually registers a new function which will be usable in an SQL -query as a COLLATE option for sorting. Such functions can also be registered -automatically on demand: see section L below. - -The method's parameters are: - -=over - -=item $name - -The name of the function exposed to SQL. - -=item $code_ref - -Reference to the function's implementation. -The driver will check that this is a proper sorting function. - -=back - -=head2 $dbh->sqlite_collation_needed( $code_ref ) - -This method manually registers a callback function that will -be invoked whenever an undefined collation sequence is required -from an SQL statement. The callback is invoked as - - $code_ref->($dbh, $collation_name) - -and should register the desired collation using -L. - -An initial callback is already registered by C, -so for most common cases it will be simpler to just -add your collation sequences in the C<%DBD::SQLite::COLLATION> -hash (see section L below). - -=head2 $dbh->sqlite_create_aggregate( $name, $argc, $pkg, $flags ) - -This method will register a new aggregate function which can then be used -from SQL. The method's parameters are: - -=over - -=item $name - -The name of the aggregate function, this is the name under which the -function will be available from SQL. - -=item $argc - -This is an integer which tells the SQL parser how many arguments the -function takes. If that number is -1, the function can take any number -of arguments. - -=item $pkg - -This is the package which implements the aggregator interface. - -=item $flags - -You can optionally pass an extra flag bit to create_aggregate, which then would be ORed with SQLITE_UTF8 (default). As of 1.47_02 (SQLite 3.8.9), only meaning bit is SQLITE_DETERMINISTIC (introduced at SQLite 3.8.3), which can make the function perform better. See C API documentation at L for details. - -=back - -The aggregator interface consists of defining three methods: - -=over - -=item new() - -This method will be called once to create an object which should -be used to aggregate the rows in a particular group. The step() and -finalize() methods will be called upon the reference return by -the method. - -=item step(@_) - -This method will be called once for each row in the aggregate. - -=item finalize() - -This method will be called once all rows in the aggregate were -processed and it should return the aggregate function's result. When -there is no rows in the aggregate, finalize() will be called right -after new(). - -=back - -Here is a simple aggregate function which returns the variance -(example adapted from pysqlite): - - package variance; - - sub new { bless [], shift; } - - sub step { - my ( $self, $value ) = @_; - - push @$self, $value; - } - - sub finalize { - my $self = $_[0]; - - my $n = @$self; - - # Variance is NULL unless there is more than one row - return undef unless $n || $n == 1; - - my $mu = 0; - foreach my $v ( @$self ) { - $mu += $v; - } - $mu /= $n; - - my $sigma = 0; - foreach my $v ( @$self ) { - $sigma += ($v - $mu)**2; - } - $sigma = $sigma / ($n - 1); - - return $sigma; - } - - $dbh->sqlite_create_aggregate( "variance", 1, 'variance' ); - -The aggregate function can then be used as: - - SELECT group_name, variance(score) - FROM results - GROUP BY group_name; - -For more examples, see the L. - -=head2 $dbh->sqlite_progress_handler( $n_opcodes, $code_ref ) - -This method registers a handler to be invoked periodically during long -running calls to SQLite. - -An example use for this interface is to keep a GUI updated during a -large query. The parameters are: - -=over - -=item $n_opcodes - -The progress handler is invoked once for every C<$n_opcodes> -virtual machine opcodes in SQLite. - -=item $code_ref - -Reference to the handler subroutine. If the progress handler returns -non-zero, the SQLite operation is interrupted. This feature can be used to -implement a "Cancel" button on a GUI dialog box. - -Set this argument to C if you want to unregister a previous -progress handler. - -=back - -=head2 $dbh->sqlite_commit_hook( $code_ref ) - -This method registers a callback function to be invoked whenever a -transaction is committed. Any callback set by a previous call to -C is overridden. A reference to the previous -callback (if any) is returned. Registering an C disables the -callback. - -When the commit hook callback returns zero, the commit operation is -allowed to continue normally. If the callback returns non-zero, then -the commit is converted into a rollback (in that case, any attempt to -I call C<< $dbh->rollback() >> afterwards would yield an -error). - -=head2 $dbh->sqlite_rollback_hook( $code_ref ) - -This method registers a callback function to be invoked whenever a -transaction is rolled back. Any callback set by a previous call to -C is overridden. A reference to the previous -callback (if any) is returned. Registering an C disables the -callback. - -=head2 $dbh->sqlite_update_hook( $code_ref ) - -This method registers a callback function to be invoked whenever a row -is updated, inserted or deleted. Any callback set by a previous call to -C is overridden. A reference to the previous -callback (if any) is returned. Registering an C disables the -callback. - -The callback will be called as - - $code_ref->($action_code, $database, $table, $rowid) - -where - -=over - -=item $action_code - -is an integer equal to either C, -C or C -(see L); - -=item $database - -is the name of the database containing the affected row; - -=item $table - -is the name of the table containing the affected row; - -=item $rowid - -is the unique 64-bit signed integer key of the affected row within -that table. - -=back - -=head2 $dbh->sqlite_set_authorizer( $code_ref ) - -This method registers an authorizer callback to be invoked whenever -SQL statements are being compiled by the L method. The -authorizer callback should return C to allow the -action, C to disallow the specific action but -allow the SQL statement to continue to be compiled, or -C to cause the entire SQL statement to be rejected -with an error. If the authorizer callback returns any other value, -then C call that triggered the authorizer will fail with -an error message. - -An authorizer is used when preparing SQL statements from an untrusted -source, to ensure that the SQL statements do not try to access data -they are not allowed to see, or that they do not try to execute -malicious statements that damage the database. For example, an -application may allow a user to enter arbitrary SQL queries for -evaluation by a database. But the application does not want the user -to be able to make arbitrary changes to the database. An authorizer -could then be put in place while the user-entered SQL is being -prepared that disallows everything except SELECT statements. - -The callback will be called as - - $code_ref->($action_code, $string1, $string2, $database, $trigger_or_view) - -where - -=over - -=item $action_code - -is an integer that specifies what action is being authorized -(see L). - -=item $string1, $string2 - -are strings that depend on the action code -(see L). - -=item $database - -is the name of the database (C
, C, etc.) if applicable. - -=item $trigger_or_view - -is the name of the inner-most trigger or view that is responsible for -the access attempt, or C if this access attempt is directly from -top-level SQL code. - -=back - -=head2 $dbh->sqlite_backup_from_file( $filename ) - -This method accesses the SQLite Online Backup API, and will take a backup of -the named database file, copying it to, and overwriting, your current database -connection. This can be particularly handy if your current connection is to the -special :memory: database, and you wish to populate it from an existing DB. - -=head2 $dbh->sqlite_backup_to_file( $filename ) - -This method accesses the SQLite Online Backup API, and will take a backup of -the currently connected database, and write it out to the named file. - -=head2 $dbh->sqlite_enable_load_extension( $bool ) - -Calling this method with a true value enables loading (external) -SQLite3 extensions. After the call, you can load extensions like this: - - $dbh->sqlite_enable_load_extension(1); - $sth = $dbh->prepare("select load_extension('libsqlitefunctions.so')") - or die "Cannot prepare: " . $dbh->errstr(); - -=head2 $dbh->sqlite_load_extension( $file, $proc ) - -Loading an extension by a select statement (with the "load_extension" SQLite3 function like above) has some limitations. If you need to, say, create other functions from an extension, use this method. $file (a path to the extension) is mandatory, and $proc (an entry point name) is optional. You need to call C before calling C. - -=head2 $dbh->sqlite_trace( $code_ref ) - -This method registers a trace callback to be invoked whenever -SQL statements are being run. - -The callback will be called as - - $code_ref->($statement) - -where - -=over - -=item $statement - -is a UTF-8 rendering of the SQL statement text as the statement -first begins executing. - -=back - -Additional callbacks might occur as each triggered subprogram is -entered. The callbacks for triggers contain a UTF-8 SQL comment -that identifies the trigger. - -See also L for better tracing options. - -=head2 $dbh->sqlite_profile( $code_ref ) - -This method registers a profile callback to be invoked whenever -a SQL statement finishes. - -The callback will be called as - - $code_ref->($statement, $elapsed_time) - -where - -=over - -=item $statement - -is the original statement text (without bind parameters). - -=item $elapsed_time - -is an estimate of wall-clock time of how long that statement took to run (in milliseconds). - -=back - -This method is considered experimental and is subject to change in future versions of SQLite. - -See also L for better profiling options. - -=head2 $dbh->sqlite_table_column_metadata( $dbname, $tablename, $columnname ) - -is for internal use only. - -=head2 $dbh->sqlite_db_status() - -Returns a hash reference that holds a set of status information of database connection such as cache usage. See L for details. You may also pass 0 as an argument to reset the status. - -=head2 $sth->sqlite_st_status() - -Returns a hash reference that holds a set of status information of SQLite statement handle such as full table scan count. See L for details. Statement status only holds the current value. - - my $status = $sth->sqlite_st_status(); - my $cur = $status->{fullscan_step}; - -You may also pass 0 as an argument to reset the status. - -=head2 $dbh->sqlite_create_module() - -Registers a name for a I. Module names must be -registered before creating a new virtual table using the module and -before using a preexisting virtual table for the module. -Virtual tables are explained in L. - -=head1 DRIVER FUNCTIONS - -=head2 DBD::SQLite::compile_options() - -Returns an array of compile options (available since SQLite 3.6.23, -bundled in DBD::SQLite 1.30_01), or an empty array if the bundled -library is old or compiled with SQLITE_OMIT_COMPILEOPTION_DIAGS. - -=head2 DBD::SQLite::sqlite_status() - -Returns a hash reference that holds a set of status information of SQLite runtime such as memory usage or page cache usage (see L for details). Each of the entry contains the current value and the highwater value. - - my $status = DBD::SQLite::sqlite_status(); - my $cur = $status->{memory_used}{current}; - my $high = $status->{memory_used}{highwater}; - -You may also pass 0 as an argument to reset the status. - -=head2 DBD::SQLite::strlike($pattern, $string, $escape_char), DBD::SQLite::strglob($pattern, $string) - -As of 1.49_05 (SQLite 3.10.0), you can use these two functions to -see if a string matches a pattern. These may be useful when you -create a virtual table or a custom function. -See L and -L for details. - -=head1 DRIVER CONSTANTS - -A subset of SQLite C constants are made available to Perl, -because they may be needed when writing -hooks or authorizer callbacks. For accessing such constants, -the C module must be explicitly Cd at compile -time. For example, an authorizer that forbids any -DELETE operation would be written as follows : - - use DBD::SQLite; - $dbh->sqlite_set_authorizer(sub { - my $action_code = shift; - return $action_code == DBD::SQLite::DELETE ? DBD::SQLite::DENY - : DBD::SQLite::OK; - }); - -The list of constants implemented in C is given -below; more information can be found ad -at L. - -=head2 Authorizer Return Codes - - OK - DENY - IGNORE - -=head2 Action Codes - -The L method registers a callback function that is -invoked to authorize certain SQL statement actions. The first -parameter to the callback is an integer code that specifies what -action is being authorized. The second and third parameters to the -callback are strings, the meaning of which varies according to the -action code. Below is the list of action codes, together with their -associated strings. - - # constant string1 string2 - # ======== ======= ======= - CREATE_INDEX Index Name Table Name - CREATE_TABLE Table Name undef - CREATE_TEMP_INDEX Index Name Table Name - CREATE_TEMP_TABLE Table Name undef - CREATE_TEMP_TRIGGER Trigger Name Table Name - CREATE_TEMP_VIEW View Name undef - CREATE_TRIGGER Trigger Name Table Name - CREATE_VIEW View Name undef - DELETE Table Name undef - DROP_INDEX Index Name Table Name - DROP_TABLE Table Name undef - DROP_TEMP_INDEX Index Name Table Name - DROP_TEMP_TABLE Table Name undef - DROP_TEMP_TRIGGER Trigger Name Table Name - DROP_TEMP_VIEW View Name undef - DROP_TRIGGER Trigger Name Table Name - DROP_VIEW View Name undef - INSERT Table Name undef - PRAGMA Pragma Name 1st arg or undef - READ Table Name Column Name - SELECT undef undef - TRANSACTION Operation undef - UPDATE Table Name Column Name - ATTACH Filename undef - DETACH Database Name undef - ALTER_TABLE Database Name Table Name - REINDEX Index Name undef - ANALYZE Table Name undef - CREATE_VTABLE Table Name Module Name - DROP_VTABLE Table Name Module Name - FUNCTION undef Function Name - SAVEPOINT Operation Savepoint Name - -=head1 COLLATION FUNCTIONS - -=head2 Definition - -SQLite v3 provides the ability for users to supply arbitrary -comparison functions, known as user-defined "collation sequences" or -"collating functions", to be used for comparing two text values. -L -explains how collations are used in various SQL expressions. - -=head2 Builtin collation sequences - -The following collation sequences are builtin within SQLite : - -=over - -=item B - -Compares string data using memcmp(), regardless of text encoding. - -=item B - -The same as binary, except the 26 upper case characters of ASCII are -folded to their lower case equivalents before the comparison is -performed. Note that only ASCII characters are case folded. SQLite -does not attempt to do full UTF case folding due to the size of the -tables required. - -=item B - -The same as binary, except that trailing space characters are ignored. - -=back - -In addition, C automatically installs the -following collation sequences : - -=over - -=item B - -corresponds to the Perl C operator - -=item B - -Perl C operator, in a context where C is activated. - -=back - -=head2 Usage - -You can write for example - - CREATE TABLE foo( - txt1 COLLATE perl, - txt2 COLLATE perllocale, - txt3 COLLATE nocase - ) - -or - - SELECT * FROM foo ORDER BY name COLLATE perllocale - -=head2 Unicode handling - -If the attribute C<< $dbh->{sqlite_unicode} >> is set, strings coming from -the database and passed to the collation function will be properly -tagged with the utf8 flag; but this only works if the -C attribute is set B the first call to -a perl collation sequence . The recommended way to activate unicode -is to set the parameter at connection time : - - my $dbh = DBI->connect( - "dbi:SQLite:dbname=foo", "", "", - { - RaiseError => 1, - sqlite_unicode => 1, - } - ); - -=head2 Adding user-defined collations - -The native SQLite API for adding user-defined collations is -exposed through methods L and -L. - -To avoid calling these functions every time a C<$dbh> handle is -created, C offers a simpler interface through the -C<%DBD::SQLite::COLLATION> hash : just insert your own -collation functions in that hash, and whenever an unknown -collation name is encountered in SQL, the appropriate collation -function will be loaded on demand from the hash. For example, -here is a way to sort text values regardless of their accented -characters : - - use DBD::SQLite; - $DBD::SQLite::COLLATION{no_accents} = sub { - my ( $a, $b ) = map lc, @_; - tr[] - [aaaaaacdeeeeiiiinoooooouuuuy] for $a, $b; - $a cmp $b; - }; - my $dbh = DBI->connect("dbi:SQLite:dbname=dbfile"); - my $sql = "SELECT ... FROM ... ORDER BY ... COLLATE no_accents"); - my $rows = $dbh->selectall_arrayref($sql); - -The builtin C or C collations are predefined -in that same hash. - -The COLLATION hash is a global registry within the current process; -hence there is a risk of undesired side-effects. Therefore, to -prevent action at distance, the hash is implemented as a "write-only" -hash, that will happily accept new entries, but will raise an -exception if any attempt is made to override or delete a existing -entry (including the builtin C and C). - -If you really, really need to change or delete an entry, you can -always grab the tied object underneath C<%DBD::SQLite::COLLATION> --- -but don't do that unless you really know what you are doing. Also -observe that changes in the global hash will not modify existing -collations in existing database handles: it will only affect new -I for collations. In other words, if you want to change -the behaviour of a collation within an existing C<$dbh>, you -need to call the L method directly. - -=head1 FULLTEXT SEARCH - -SQLite is bundled with an extension module for full-text -indexing. Tables with this feature enabled can be efficiently queried -to find rows that contain one or more instances of some specified -words, in any column, even if the table contains many large documents. - -Explanations for using this feature are provided in a separate document: -see L. - - -=head1 R* TREE SUPPORT - -The RTREE extension module within SQLite adds support for creating -a R-Tree, a special index for range and multidimensional queries. This -allows users to create tables that can be loaded with (as an example) -geospatial data such as latitude/longitude coordinates for buildings within -a city : - - CREATE VIRTUAL TABLE city_buildings USING rtree( - id, -- Integer primary key - minLong, maxLong, -- Minimum and maximum longitude - minLat, maxLat -- Minimum and maximum latitude - ); - -then query which buildings overlap or are contained within a specified region: - - # IDs that are contained within query coordinates - my $contained_sql = <<""; - SELECT id FROM city_buildings - WHERE minLong >= ? AND maxLong <= ? - AND minLat >= ? AND maxLat <= ? - - # ... and those that overlap query coordinates - my $overlap_sql = <<""; - SELECT id FROM city_buildings - WHERE maxLong >= ? AND minLong <= ? - AND maxLat >= ? AND minLat <= ? - - my $contained = $dbh->selectcol_arrayref($contained_sql,undef, - $minLong, $maxLong, $minLat, $maxLat); - - my $overlapping = $dbh->selectcol_arrayref($overlap_sql,undef, - $minLong, $maxLong, $minLat, $maxLat); - -For more detail, please see the SQLite R-Tree page -(L). Note that custom R-Tree -queries using callbacks, as mentioned in the prior link, have not been -implemented yet. - -=head1 VIRTUAL TABLES IMPLEMENTED IN PERL - -SQLite has a concept of "virtual tables" which look like regular -tables but are implemented internally through specific functions. -The fulltext or R* tree features described in the previous chapters -are examples of such virtual tables, implemented in C code. - -C also supports virtual tables implemented in I: -see L for using or implementing such -virtual tables. These can have many interesting uses -for joining regular DBMS data with some other kind of data within your -Perl programs. Bundled with the present distribution are : - -=over - -=item * - -L : implements a virtual -column that exposes file contents. This is especially useful -in conjunction with a fulltext index; see L. - -=item * - -L : binds to a Perl array -within the Perl program. This can be used for simple import/export -operations, for debugging purposes, for joining data from different -sources, etc. - -=back - -Other Perl virtual tables may also be published separately on CPAN. - -=head1 FOR DBD::SQLITE EXTENSION AUTHORS - -Since 1.30_01, you can retrieve the bundled SQLite C source and/or -header like this: - - use File::ShareDir 'dist_dir'; - use File::Spec::Functions 'catfile'; - - # the whole sqlite3.h header - my $sqlite3_h = catfile(dist_dir('DBD-SQLite'), 'sqlite3.h'); - - # or only a particular header, amalgamated in sqlite3.c - my $what_i_want = 'parse.h'; - my $sqlite3_c = catfile(dist_dir('DBD-SQLite'), 'sqlite3.c'); - open my $fh, '<', $sqlite3_c or die $!; - my $code = do { local $/; <$fh> }; - my ($parse_h) = $code =~ m{( - /\*+[ ]Begin[ ]file[ ]$what_i_want[ ]\*+ - .+? - /\*+[ ]End[ ]of[ ]$what_i_want[ ]\*+/ - )}sx; - open my $out, '>', $what_i_want or die $!; - print $out $parse_h; - close $out; - -You usually want to use this in your extension's C, -and you may want to add DBD::SQLite to your extension's C -to ensure your extension users use the same C source/header they use -to build DBD::SQLite itself (instead of the ones installed in their -system). - -=head1 TO DO - -The following items remain to be done. - -=head2 Leak Detection - -Implement one or more leak detection tests that only run during -AUTOMATED_TESTING and RELEASE_TESTING and validate that none of the C -code we work with leaks. - -=head2 Stream API for Blobs - -Reading/writing into blobs using C / C. - -=head2 Support for custom callbacks for R-Tree queries - -Custom queries of a R-Tree index using a callback are possible with -the SQLite C API (L), so one could -potentially use a callback that narrowed the result set down based -on a specific need, such as querying for overlapping circles. - -=head1 SUPPORT - -Bugs should be reported via the CPAN bug tracker at - -L - -Note that bugs of bundled SQLite library (i.e. bugs in C) -should be reported to the SQLite developers at sqlite.org via their bug -tracker or via their mailing list. - -The master repository is on GitHub: - -L. - -We also have a mailing list: - -L - -=head1 AUTHORS - -Matt Sergeant Ematt@sergeant.orgE - -Francis J. Lacoste Eflacoste@logreport.orgE - -Wolfgang Sourdeau Ewolfgang@logreport.orgE - -Adam Kennedy Eadamk@cpan.orgE - -Max Maischein Ecorion@cpan.orgE - -Laurent Dami Edami@cpan.orgE - -Kenichi Ishigaki Eishigaki@cpan.orgE - -=head1 COPYRIGHT - -The bundled SQLite code in this distribution is Public Domain. - -DBD::SQLite is copyright 2002 - 2007 Matt Sergeant. - -Some parts copyright 2008 Francis J. Lacoste. - -Some parts copyright 2008 Wolfgang Sourdeau. - -Some parts copyright 2008 - 2013 Adam Kennedy. - -Some parts copyright 2009 - 2013 Kenichi Ishigaki. - -Some parts derived from L -copyright 2008 Audrey Tang. - -This program is free software; you can redistribute -it and/or modify it under the same terms as Perl itself. - -The full text of the license can be found in the -LICENSE file included with this module. - -=cut diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Win32/Locale.pm b/CPAN/arch/5.14/MSWin32-x86-multi-thread/Win32/Locale.pm deleted file mode 100644 index f6cda1d1327..00000000000 --- a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Win32/Locale.pm +++ /dev/null @@ -1,371 +0,0 @@ - -package Win32::Locale; -# Time-stamp: "2004-01-11 18:56:06 AST" -use strict; -use vars qw($VERSION %MSLocale2LangTag); -$VERSION = '0.04'; -%MSLocale2LangTag = ( - - 0x0436 => 'af' , # - 0x041c => 'sq' , # - - 0x0401 => 'ar-sa', # - 0x0801 => 'ar-iq', # - 0x0C01 => 'ar-eg', # - 0x1001 => 'ar-ly', # - 0x1401 => 'ar-dz', # - 0x1801 => 'ar-ma', # - 0x1C01 => 'ar-tn', # - 0x2001 => 'ar-om', # - 0x2401 => 'ar-ye', # - 0x2801 => 'ar-sy', # - 0x2C01 => 'ar-jo', # - 0x3001 => 'ar-lb', # - 0x3401 => 'ar-kw', # - 0x3801 => 'ar-ae', # - 0x3C01 => 'ar-bh', # - 0x4001 => 'ar-qa', # - - 0x042b => 'hy' , # - 0x044d => 'as' , # - 0x042c => 'az-latn', # - 0x082c => 'az-cyrl', # - 0x042D => 'eu' , # - 0x0423 => 'be' , # - 0x0445 => 'bn' , # - 0x0402 => 'bg' , # - 0x0403 => 'ca' , # - - # Chinese is zh, not cn! - 0x0404 => 'zh-tw', # - 0x0804 => 'zh-cn', # - 0x0C04 => 'zh-hk', # - 0x1004 => 'zh-sg', # - 0x1404 => 'zh-mo', # - - 0x041a => 'hr' , # - 0x0405 => 'cs' , # - 0x0406 => 'da' , # - 0x0413 => 'nl-nl', # - 0x0813 => 'nl-be', # - - 0x0409 => 'en-us', # - 0x0809 => 'en-gb', # - 0x0c09 => 'en-au', # - 0x1009 => 'en-ca', # - 0x1409 => 'en-nz', # - 0x1809 => 'en-ie', # - 0x1c09 => 'en-za', # - 0x2009 => 'en-jm', # - 0x2409 => 'en-jm', # # a hack - 0x2809 => 'en-bz', # - 0x2c09 => 'en-tt', # - 0x3009 => 'en-zw', # - 0x3409 => 'en-ph', # - - 0x0425 => 'et' , # - 0x0438 => 'fo' , # - 0x0429 => 'pa' , # # =Persian - 0x040b => 'fi' , # - - 0x040c => 'fr-fr', # - 0x080c => 'fr-be', # - 0x0c0c => 'fr-ca', # - 0x100c => 'fr-ch', # - 0x140c => 'fr-lu', # - 0x180c => 'fr-mc', # - - 0x0437 => 'ka' , # - - 0x0407 => 'de-de', # - 0x0807 => 'de-ch', # - 0x0c07 => 'de-at', # - 0x1007 => 'de-lu', # - 0x1407 => 'de-li', # - - 0x0408 => 'el' , # - 0x0447 => 'gu' , # - 0x040D => 'he' , # # formerly 'iw' - 0x0439 => 'hi' , # - 0x040e => 'hu' , # - 0x040F => 'is' , # - 0x0421 => 'id' , # # formerly 'in' - 0x0410 => 'it-it', # - 0x0810 => 'it-ch', # - 0x0411 => 'ja' , # # not "jp"! - 0x044b => 'kn' , # - 0x0860 => 'ks' , # - 0x043f => 'kk' , # - 0x0457 => 'kok' , # 3-letters! - 0x0412 => 'ko' , # - 0x0812 => 'ko' , # ? - 0x0426 => 'lv' , # # = lettish - 0x0427 => 'lt' , # - 0x0827 => 'lt' , # ? - 0x042f => 'mk' , # - 0x043e => 'ms' , # - 0x083e => 'ms-bn', # - 0x044c => 'ml' , # - 0x044e => 'mr' , # - 0x0461 => 'ne-np', # - 0x0861 => 'ne-in', # - 0x0414 => 'nb' , # #was no-bok - 0x0814 => 'nn' , # #was no-nyn - # note that this leaves nothing using "no" ("Norwegian") - 0x0448 => 'or' , # - 0x0415 => 'pl' , # - 0x0416 => 'pt-br', # - 0x0816 => 'pt-pt', # - 0x0446 => 'pa' , # - 0x0417 => 'rm' , # - 0x0418 => 'ro' , # - 0x0818 => 'ro-md', # - 0x0419 => 'ru' , # - 0x0819 => 'ru-md', # - 0x043b => 'se' , # assuming == "Northern Sami" - 0x044f => 'sa' , # - 0x0c1a => 'sr-cyrl', # - 0x081a => 'sr-latn', # - 0x0459 => 'sd' , # - 0x041b => 'sk' , # - 0x0424 => 'sl' , # - 0x042e => 'wen' , # # !!! 3 letters - - 0x040a => 'es-es', # - 0x080a => 'es-mx', # - 0x0c0a => 'es-es', # - 0x100a => 'es-gt', # - 0x140a => 'es-cr', # - 0x180a => 'es-pa', # - 0x1c0a => 'es-do', # - 0x200a => 'es-ve', # - 0x240a => 'es-co', # - 0x280a => 'es-pe', # - 0x2c0a => 'es-ar', # - 0x300a => 'es-ec', # - 0x340a => 'es-cl', # - 0x380a => 'es-uy', # - 0x3c0a => 'es-py', # - 0x400a => 'es-bo', # - 0x440a => 'es-sv', # - 0x480a => 'es-hn', # - 0x4c0a => 'es-ni', # - 0x500a => 'es-pr', # - - 0x0430 => 'st' , # == soto, sesotho - 0x0441 => 'sw-ke', # - 0x041D => 'sv' , # - 0x081d => 'sv-fi', # - 0x0449 => 'ta' , # - 0x0444 => 'tt' , # - 0x044a => 'te' , # - 0x041E => 'th' , # - 0x0431 => 'ts' , # (not Tonga!) - 0x0432 => 'tn' , # == Setswana - 0x041f => 'tr' , # - 0x0422 => 'uk' , # - 0x0420 => 'ur-pk', # - 0x0820 => 'ur-in', # - 0x0443 => 'uz-latn', # - 0x0843 => 'uz-cyrl', # - 0x0433 => 'ven' , # - 0x042a => 'vi' , # - 0x0434 => 'xh' , # - 0x043d => 'yi' , # # formetly ji - 0x0435 => 'zu' , # -); -#----------------------------------------------------------------------------- - -sub get_ms_locale { - my $locale; - return unless defined do { - # see if there's a W32 registry on this machine, and if so, look in it - local $SIG{"__DIE__"} = ""; - eval ' - use Win32::TieRegistry (); - my $i18n = Win32::TieRegistry->new( - "HKEY_CURRENT_USER/Control Panel/International", - { Delimiter => "/" } - ); - #print "no key!" unless $i18n; - $locale = $i18n->GetValue("Locale") if $i18n; - undef $i18n; - '; - #print "<$@>\n" if $@; - $locale; - }; - return unless $locale =~ m/^[0-9a-fA-F]+$/s; - return hex($locale); -} - -sub get_language { - my $lang = $MSLocale2LangTag{ $_[0] || get_ms_locale() || '' }; - return unless $lang; - return $lang; -} - -sub get_locale { - # I guess this is right. - my $lang = get_language(@_); - return unless $lang and $lang =~ m/^[a-z]{2}(?:-[a-z]{2})?$/s; - - # should we try to turn "fi" into "fi_FI"? - - $lang =~ tr/-/_/; - return $lang; -} -#----------------------------------------------------------------------------- - -# If we're just executed... -unless(caller) { - my $locale = get_ms_locale(); - if($locale) { - printf "Locale 0x%08x (%s => %s) => Lang %s\n", - $locale, $locale, - get_locale($locale) || '?', - get_language($locale) || '?', - } else { - print "Can't get ms-locale\n"; - } -} - -#----------------------------------------------------------------------------- -1; - -__END__ - -=head1 NAME - -Win32::Locale - get the current MSWin locale or language - -=head1 SYNOPSIS - - use Win32::Locale; - my $language = Win32::Locale::get_language(); - if($language eq 'en-us') { - print "Wasaaap homeslice!\n"; - } else { - print "You $language people ain't FROM around here, are ya?\n"; - } - -=head1 DESCRIPTION - -This library provides some simple functions allowing Perl under MSWin -to ask what the current locale/language setting is. (Yes, MSWin -conflates locales and languages, it seems; and the way it's -conflated is even stranger after MSWin98.) - -Note that you should be able to safely use this module under any -OS; the functions just won't be able to access any current -locale value. - -=head1 FUNCTIONS - -Note that these functions are not exported, -nor are they exportable: - -=over - -=item Win32::Locale::get_language() - -Returns the (all-lowercase) RFC3066 language tag corresponding -to the currently currently selected MS locale. - -Returns nothing if the MS locale value isn't accessible -(notably, if you're not running under MSWin!), or if it -corresponds to no known language tag. Example: "en-us". - -In list context, this may in the future be made to return -multiple values. - -=item Win32::Locale::get_locale() - -Returns the (all-lowercase) Unixish locale tag corresponding -to the currently currently selected MS locale. Example: "en_us". - -Returns nothing if the MS locale value isn't accessible -(notably, if you're not running under MSWin!), or if it -corresponds to no locale. - -In list context, this may in the future be made to return -multiple values. - -Note that this function is B, and I greatly welcome -suggestions. - -=item Win32::Locale::get_ms_locale() - -Returns the MS locale ID code for the currently selected MSWindows -locale. For example, returns the number 1033 for "US -English". (You may know the number 1033 better as 0x00000409, -as these numbers are usually given in hex in MS documents). - -Returns nothing if the value isn't accessible (notably, if you're -not running under MSWin!). - -=item Win32::Locale::get_language($msid) - -Returns the (all-lowercase) RFC3066 language tag corresponding -to the given MS locale code, or nothing if none. - -In list context, this may in the future be made to return -multiple values. - -=item Win32::Locale::get_locale($msid) - -Returns the (all-lowercase) Unixish locale tag corresponding -to the given MS locale code, or nothing if none. - -In list context, this may in the future be made to return -multiple values. - -=back - -("Nothing", above, means "in scalar context, undef; in list -context, empty-list".) - -=head1 AND MORE - -This module provides an (unexported) public hash, -%Win32::Locale::MSLocale2LangTag, that maps -from the MS locale ID code to my idea of the single best corresponding -RFC3066 language tag. - -The hash's contents are relatively certain for well-known -languages (US English is "en-us"), but are still experimental -in its finer details (like Konkani being "kok"). - -=head1 SEE ALSO - -L, -L, -L. - -=head1 COPYRIGHT AND DISCLAIMER - -Copyright (c) 2001,2003 Sean M. Burke. All rights reserved. - -This library is free software; you can redistribute it and/or modify -it under the same terms as Perl itself. - -This program is distributed in the hope that it will be useful, but -without any warranty; without even the implied warranty of -merchantability or fitness for a particular purpose. - -I am not affiliated with the Microsoft corporation, nor the ActiveState -corporation. - -Product and company names mentioned in this document may be the -trademarks or service marks of their respective owners. Trademarks -and service marks might not be identified as such, although -this must not be construed as anyone's expression of validity -or invalidity of each trademark or service mark. - -=head1 AUTHOR - -Sean M. Burke C - -=cut - -# No big whoop. - diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Win32/Process/List.pm b/CPAN/arch/5.14/MSWin32-x86-multi-thread/Win32/Process/List.pm deleted file mode 100644 index 53147e936ac..00000000000 --- a/CPAN/arch/5.14/MSWin32-x86-multi-thread/Win32/Process/List.pm +++ /dev/null @@ -1,272 +0,0 @@ -package Win32::Process::List; - -use 5.006; -use strict; -use warnings; -use Carp; -use Data::Dumper; - -require Exporter; -require DynaLoader; -use AutoLoader; - -our @ISA = qw(Exporter DynaLoader); - -# Items to export into callers namespace by default. Note: do not export -# names by default without a very good reason. Use EXPORT_OK instead. -# Do not simply export all your public functions/methods/constants. - -# This allows declaration use Win32::Process::List ':all'; -# If you do not need this, moving things directly into @EXPORT or @EXPORT_OK -# will save memory. -our %EXPORT_TAGS = ( 'all' => [ qw( - -) ] ); - -our @EXPORT_OK = ( @{ $EXPORT_TAGS{'all'} } ); - -our @EXPORT = qw( - -); -our $VERSION = '0.09'; - -#sub AUTOLOAD { - # This AUTOLOAD is used to 'autoload' constants from the constant() - # XS function. If a constant is not found then control is passed - # to the AUTOLOAD in AutoLoader. - -# my $constname; -# our $AUTOLOAD; -# ($constname = $AUTOLOAD) =~ s/.*:://; -# croak "& not defined" if $constname eq 'constant'; -# local $! = 0; -# my $val = constant($constname, @_ ? $_[0] : 0); -# if ($! != 0) { -# if ($! =~ /Invalid/ || $!{EINVAL}) { -# $AutoLoader::AUTOLOAD = $AUTOLOAD; -# goto &AutoLoader::AUTOLOAD; -# } -# else { -# croak "Your vendor has not defined Win32::Process::List macro $constname"; -# } -# } -# { -# no strict 'refs'; - # Fixed between 5.005_53 and 5.005_61 -# if ($] >= 5.00561) { -# *$AUTOLOAD = sub () { $val }; -# } -# else { -# *$AUTOLOAD = sub { $val }; -# } -# } -# goto &$AUTOLOAD; -#} - -bootstrap Win32::Process::List $VERSION; - -# Preloaded methods go here. - -sub new -{ - my $class = shift; - my $self = { - nProcesses=>0, - processes=>[], - isError=>0, - Error=>undef - }; - bless $self, $class; - my $error = undef; - my $err = ListProcesses($error); - if($error) { - $self->{isError} = 1; - $self->{Error} = $error; - } - #my @arr = @{ $err }; - # $self->{processes} = [ @arr ]; - $self->{processes} = [ $err ]; - my %h = %{ $err }; - my $nProcesses = (scalar keys %h); - $self->{nProcesses} = $nProcesses; - return $self; - -} - -sub ProcessAliveNa -{ - my $self = shift; - my $process =shift; - if($process !~ /\.exe$/ ) - { - $process .= '.exe'; - } - - $self->{Error}=""; - $self->{isError}=0; - my $ret =ProcessAliveN($process, $self->{Error}); - if($ret == -1) { $self->{isError}=1; } - return $ret; - - -} - -sub ProcessAlivePid -{ - my $self = shift; - $self->{Error}=""; - $self->{isError}=0; - my $ret = ProcessAliveP(shift,$self->{Error}); - if($ret == -1) { $self->{isError}=1; } - return $ret; - -} - -sub ProcessAliveName -{ - my $self = shift; - my $process=shift; - $process=lc($process); - my @procArr=(); - my $alive = 0; - my %ret; - $self->{isError}=0; - $self->{Error}=""; - if(ref($process) eq "ARRAY") - { - #my $count=0; - #@procArr=@{$process}; - #foreach (@procArr) - #{ - # if($procArr[$count] !~ /\.exe$/ && $usePID == 0) - # { - # $procArr[$count]= $procArr[$count] . '.exe'; - # } - # $count++; - #} - $self->{isError} = 1; - $self->{Error} = "ARRAY of processes not yet supported!"; - return; - } else { - if($process !~ /\.exe$/ ) - { - $process .= '.exe'; - } - push(@procArr, $process); - } - my $error = undef; - my $y = undef; - my $processes=ListProcesses($error); - my %h=%{$processes}; - foreach my $p (keys %h) - { - if(lc($h{$p}) eq $process) { $ret{$process} = 1; $alive=1; } - } - return %ret; -} - -sub GetNProcesses -{ - my $self = shift; - return $self->{nProcesses}; -} - -sub GetProcessPid -{ - my $self = shift; - my $pr = shift; - my %ret; - $pr=lc($pr); - $self->{isError} = 0; - my @a = @{ $self->{processes} }; - my %h = %{ $a[0] }; - my $count = 0; - foreach my $key (keys %h) - { - if(lc($h{$key}) =~ /$pr/) { - #$a[$count] = $key; - $ret{$h{$key}}=$key; - $count++; - } - } - if($count > 0) { - return %ret; - } - $self->{isError} = 1; - $self->{Error} = "Error: no PID found for $pr"; - return; -} - -sub GetProcesses -{ - my $self = shift; - $self->{isError} = 0; - my @tmp = @{ $self->{processes} }; - my %h = %{ $tmp[0] }; - return %h; - -} - -sub IsError -{ - my $self = shift; - return $self->{isError}; -} - -sub GetErrorText -{ - my $self = shift; - if($self->{isError} == 1) - { - return $self->{Error}; - } - return; -} - -DESTROY -{ - my $self = shift; - #print "destroying!\n"; -} - -# Autoload methods go after =cut, and are processed by the autosplit program. - -1; -__END__ -# Below is stub documentation for your module. You better edit it! - -=head1 NAME - -Win32::Process::List - Perl extension to get all processes and thier PID on a Win32 system - -=head1 SYNOPSIS - - use Win32::Process::List; - my $P = Win32::Process::List->new(); constructor - my %list = $P->GetProcesses(); returns the hashes with PID and process name - foreach my $key ( keys %list ) { - # $list{$key} is now the process name and $key is the PID - print sprintf("%30s has PID %15s", $list{$key}, $key) . "\n"; - } - my $PID = $P->GetProcessPid("explorer"); get the PID of process explorer.exe - my $np = $P->GetNProcesses(); returns the number of processes - -=head1 DESCRIPTION - - Win32::Process::List is a module to get the running processes with their PID's from - a Win32 System. Please look at Win32/Process/List/processes.pl. - -=head2 EXPORT - -None by default. - - -=head1 AUTHOR - -Reinhard Pagitsch, Erpirpag@gmx.atE - -=head1 SEE ALSO - -L. - -=cut diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Audio/Scan/Scan.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Audio/Scan/Scan.dll deleted file mode 100755 index 68da4c309ad..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Audio/Scan/Scan.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Class/XSAccessor/XSAccessor.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Class/XSAccessor/XSAccessor.dll deleted file mode 100755 index fd7d34c063c..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Class/XSAccessor/XSAccessor.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Crypt/Blowfish/Blowfish.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Crypt/Blowfish/Blowfish.dll deleted file mode 100644 index a6c11604ee7..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Crypt/Blowfish/Blowfish.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/SQLite.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/SQLite.dll deleted file mode 100755 index 73b8b886d20..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/SQLite.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icudt57.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icudt57.dll deleted file mode 100755 index a9d3fc4448c..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icudt57.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icuin57.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icuin57.dll deleted file mode 100755 index 3f41a5e3b83..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icuin57.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icuuc57.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icuuc57.dll deleted file mode 100755 index b2f67c0c889..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/DBD/SQLite/icuuc57.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/EV/EV.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/EV/EV.dll deleted file mode 100755 index 99a8ef28237..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/EV/EV.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Encode/Detect/Detector/Detector.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Encode/Detect/Detector/Detector.dll deleted file mode 100755 index 62f2693029e..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Encode/Detect/Detector/Detector.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Font/FreeType/FreeType.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Font/FreeType/FreeType.dll deleted file mode 100755 index 6421239dffd..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Font/FreeType/FreeType.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Image/Scale/Scale.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Image/Scale/Scale.dll deleted file mode 100755 index c5c3bfca5e7..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Image/Scale/Scale.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/JSON/XS/XS.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/JSON/XS/XS.dll deleted file mode 100755 index e679a68abd6..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/JSON/XS/XS.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Locale/Hebrew/Hebrew.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Locale/Hebrew/Hebrew.dll deleted file mode 100755 index 8e4407a6ff0..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Locale/Hebrew/Hebrew.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/MP3/Cut/Gapless/Gapless.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/MP3/Cut/Gapless/Gapless.dll deleted file mode 100755 index 6864ab7dee3..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/MP3/Cut/Gapless/Gapless.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Template/Stash/XS/XS.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Template/Stash/XS/XS.dll deleted file mode 100755 index 21411385166..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Template/Stash/XS/XS.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Win32/Process/List/List.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Win32/Process/List/List.dll deleted file mode 100755 index 99995e0acd4..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Win32/Process/List/List.dll and /dev/null differ diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Win32/Process/List/autosplit.ix b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Win32/Process/List/autosplit.ix deleted file mode 100644 index fa14b89287c..00000000000 --- a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/Win32/Process/List/autosplit.ix +++ /dev/null @@ -1,3 +0,0 @@ -# Index created by AutoSplit for blib\lib\Win32\Process\List.pm -# (file acts as timestamp) -1; diff --git a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/XML/Parser/Expat/Expat.dll b/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/XML/Parser/Expat/Expat.dll deleted file mode 100755 index 3034106074c..00000000000 Binary files a/CPAN/arch/5.14/MSWin32-x86-multi-thread/auto/XML/Parser/Expat/Expat.dll and /dev/null differ diff --git a/Changelog9.html b/Changelog9.html index 2c61b3304fb..f29f502c367 100644 --- a/Changelog9.html +++ b/Changelog9.html @@ -18,6 +18,8 @@

Version 9.1.0

  • Platform Support:
    • Make Docker a first class citizan: add Slim::Utils::OS::Docker insted of a Custom.pm
    • +
    • Remove Win32 legacy support files, code, control panels, build pipeline, etc.
    • +
    • Remove legacy Mac installer from build pipeline.

    diff --git a/Slim/GUI/ControlPanel.pm b/Slim/GUI/ControlPanel.pm deleted file mode 100644 index 7e38c59c1a9..00000000000 --- a/Slim/GUI/ControlPanel.pm +++ /dev/null @@ -1,516 +0,0 @@ -package Slim::GUI::ControlPanel::MainFrame; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use strict; -use base 'Wx::Frame'; - -use Slim::Utils::Light; -use File::Spec::Functions; -use File::Slurp; - -use Wx qw(:everything); -use Wx::Event qw(EVT_BUTTON EVT_NOTEBOOK_PAGE_CHANGED); - -use Slim::GUI::ControlPanel::Settings; -use Slim::GUI::ControlPanel::Music; -use Slim::GUI::ControlPanel::Advanced; -use Slim::GUI::ControlPanel::Status; -use Slim::GUI::ControlPanel::Diagnostics; -use Slim::Utils::OSDetect; -use Slim::Utils::ServiceManager; - -use constant PAGE_STATUS => 3; -use constant PAGE_SCAN => 1; - -my $pollTimer; -my $btnOk; - -my $svcMgr = Slim::Utils::ServiceManager->new(); - -sub new { - my $ref = shift; - my $args = shift; - - Slim::Utils::OSDetect::init(); - - # if we're running for the first time, show the SN page - my $initialSetup = $svcMgr->isRunning() && !Slim::GUI::ControlPanel->getPref('wizardDone'); - - my $self = $ref->SUPER::new( - undef, - -1, - $initialSetup ? string('WELCOME_TO_SQUEEZEBOX_SERVER') : string('CONTROLPANEL_TITLE'), - [-1, -1], - main::ISWINDOWS ? [550, 610] : [700, 700], - wxMINIMIZE_BOX | wxMAXIMIZE_BOX | wxCAPTION | wxCLOSE_BOX | wxSYSTEM_MENU | wxRESIZE_BORDER, - 'WELCOME_TO_SQUEEZEBOX_SERVER' - ); - - my $file = $self->_fixIcon('SqueezeCenter.ico'); - if ($file && (my $icon = Wx::Icon->new($file, wxBITMAP_TYPE_ICO)) ) { - $self->SetIcon($icon); - } - - my $panel = Wx::Panel->new($self); - my $mainSizer = Wx::BoxSizer->new(wxVERTICAL); - - $pollTimer = Slim::GUI::ControlPanel::Timer->new(); - - $btnOk = Slim::GUI::ControlPanel::OkButton->new( $panel, wxID_OK, string('OK') ); - EVT_BUTTON( $self, $btnOk, sub { - $btnOk->do($svcMgr->checkServiceState()); - Slim::Utils::OS::Win32->cleanupTempDirs() if main::ISWINDOWS; - $_[0]->Destroy; - } ); - - my $notebook = Wx::Notebook->new($panel); - - EVT_NOTEBOOK_PAGE_CHANGED($self, $notebook, sub { - my ($self, $event) = @_; - - eval { - my $child = $notebook->GetPage($notebook->GetSelection()); - if ($child && $child->can('_update')) { - $child->_update($event); - }; - } - }); - - $notebook->AddPage(Slim::GUI::ControlPanel::Settings->new($notebook, $self), string('CONTROLPANEL_SERVERSTATUS'), 1); - $notebook->AddPage(Slim::GUI::ControlPanel::Music->new($notebook, $self), string('CONTROLPANEL_MUSIC_LIBRARY')); - $notebook->AddPage(Slim::GUI::ControlPanel::Advanced->new($notebook, $self, $args), string('ADVANCED_SETTINGS')); - $notebook->AddPage(Slim::GUI::ControlPanel::Diagnostics->new($notebook, $self, $args), string('CONTROLPANEL_DIAGNOSTICS')); - $notebook->AddPage(Slim::GUI::ControlPanel::Status->new($notebook, $self), string('INFORMATION')); - - $mainSizer->Add($notebook, 1, wxALL | wxGROW, 10); - - my $footerSizer = Wx::BoxSizer->new(wxHORIZONTAL); - - my $btnsizer = Wx::StdDialogButtonSizer->new(); - $btnsizer->AddButton($btnOk); - - if (!$initialSetup) { - my $btnApply = Wx::Button->new( $panel, wxID_APPLY, string('APPLY') ); - EVT_BUTTON( $self, $btnApply, sub { - $btnOk->do($svcMgr->checkServiceState()); - } ); - - $btnsizer->AddButton($btnApply); - } - - my $btnCancel = Wx::Button->new( $panel, wxID_CANCEL, string('CANCEL') ); - - EVT_BUTTON( $self, $btnCancel, sub { - Slim::Utils::OS::Win32->cleanupTempDirs() if main::ISWINDOWS; - $_[0]->Destroy; - } ); - - $btnsizer->AddButton($btnCancel); - - $btnsizer->Realize(); - - my $footerSizer2 = Wx::BoxSizer->new(wxVERTICAL); - $footerSizer2->Add($btnsizer, 0, wxEXPAND); - $footerSizer2->AddSpacer(7); - $footerSizer2->Add(Wx::StaticText->new($panel, -1, string('COPYRIGHT')), 0, wxALIGN_RIGHT | wxRIGHT, 3); - - my ($version) = parseRevision(); - $version = sprintf(string('VERSION'), $version); - $footerSizer2->Add(Wx::StaticText->new($panel, -1, $version), 0, wxALIGN_RIGHT | wxRIGHT, 3); - - $footerSizer->Add($footerSizer2, wxEXPAND); - $mainSizer->Add($footerSizer, 0, wxLEFT | wxRIGHT | wxGROW, 8); - - $panel->SetSizer($mainSizer); - - $pollTimer->Start(5000, wxTIMER_CONTINUOUS); - $pollTimer->Notify(); - - return $self; -} - -sub addApplyHandler { - my $self = shift; - $btnOk->addActionHandler(@_); -} - -sub addStatusListener { - my $self = shift; - $pollTimer->addListener(@_); -} - -sub checkServiceStatus { - $pollTimer->Notify(); -} - -sub _fixIcon { - my $self = shift; - my $iconFile = shift; - - return unless main::ISWINDOWS; - - # bug 12904 - Windows 2000 can't read hires icon file... - return if $iconFile =~ /.ico$/i && Slim::Utils::OSDetect::details->{osName} =~ /Windows 2000/i; - - # set the application icon - my $file = "../platforms/win32/res/$iconFile"; - - if (main::ISACTIVEPERL && defined $PerlApp::VERSION && !-f $file) { - $file = PerlApp::extract_bound_file($iconFile); - } - - else { - $file = $iconFile; - } - - return $file if -f $file; -} - -# stolen from Slim::Utils::Misc -sub parseRevision { - # The revision file may not exist for svn copies. - my $tempBuildInfo = eval { File::Slurp::read_file( - catdir(scalar Slim::Utils::OSDetect::dirsFor('revision'), 'revision.txt') - ) } || "TRUNK\nUNKNOWN"; - - # Once we've read the file, split it up so we have the Revision and Build Date - return split (/\n/, $tempBuildInfo); -} - -1; - - -# Our own timer object, checking for SC availability -package Slim::GUI::ControlPanel::Timer; - -use base 'Wx::Timer'; -use Slim::Utils::ServiceManager; - -my %listeners; - -sub addListener { - my ($self, $item, $callback) = @_; - - # if no callback is given, then enable the element if SC is running, or disable otherwise - $listeners{$item} = $callback || sub { $item->Enable($_[0] == SC_STATE_RUNNING) }; -} - -sub Notify { - my $status = $svcMgr->checkServiceState(); - - foreach my $listener (keys %listeners) { - - if (my $callback = $listeners{$listener}) { - &$callback($status); - } - } -} - -1; - - -# Ok button will apply our changes -package Slim::GUI::ControlPanel::OkButton; - -use base 'Wx::Button'; - -sub new { - my $self = shift; - - $self = $self->SUPER::new(@_); - $self->{actionHandlers} = {}; - $self->SetDefault(); - - return $self; -} - -sub addActionHandler { - my ($self, $item, $callback) = @_; - $self->{actionHandlers}->{$item} = $callback; -} - -sub do { - my ($self, $status) = @_; - - Slim::GUI::ControlPanel->setPref('wizardDone', 1); - - foreach my $actionHandler (keys %{ $self->{actionHandlers} }) { - - if (my $action = $self->{actionHandlers}->{$actionHandler}) { - &$action($status); - } - } -} - -1; - - -# The CleanupGUI main class -package Slim::GUI::ControlPanel; - -use base 'Wx::App'; -use Wx qw(:everything); -use LWP::UserAgent; -use JSON::XS::VersionOneAndTwo; - -use Slim::Utils::ServiceManager; - -my $args; - -my $credentials = {}; -my $needAuthentication; - -sub new { - my $self = shift; - $args = shift; - - $self = $self->SUPER::new(); - - return $self; -} - -sub OnInit { - my $self = shift; - my $frame; - - $frame = Slim::GUI::ControlPanel::MainFrame->new($args); - - $frame->Show( 1 ); -} - -# the following subs are static methods to deliver some commonly used services -my $baseUrl; -sub getBaseUrl { - my $self = shift; - my $update = shift; - - if ($update || !$baseUrl || time() > $baseUrl->{ttl}) { - $baseUrl = { - url => 'http://' . ( - $credentials && $credentials->{username} && $credentials->{password} - ? $credentials->{username} . ':' . $credentials->{password} . '@' - : '' - ) . '127.0.0.1:' . (Slim::Utils::Light::getPref('httpport') || 9000), - ttl => time() + 15, - }; - } - - return $baseUrl->{url}; -} - -sub setPref { - my ($self, $pref, $value) = @_; - - $self->serverRequest('pref', $pref, $value); -} - -sub getPref { - my ($self, $pref, $file) = @_; - $file ||= ''; - - my $value; - - # if SC is running, use the CLI, otherwise read the prefs file from disk - if ($svcMgr->isRunning()) { - - if ($file) { - $file =~ s/\.prefs$//; - $file = "plugin.$file:"; - } - - $value = $self->serverRequest('pref', $file . $pref, '?'); - - if (ref $value eq 'HASH' && $value->{msg} && $value->{msg} =~ /^500/i) { - $value = Slim::Utils::Light::getPref($pref, $file); - } - elsif (ref $value eq 'HASH') { - $value = $value->{'_p2'}; - } - } - - else { - $value = Slim::Utils::Light::getPref($pref, $file); - } - - return $value; -} - -sub string { - my ($self, $stringToken) = @_; - - my $string = Slim::Utils::Light::string($stringToken); - - # if SC is running, use the CLI, otherwise read the prefs file from disk - if ($string eq $stringToken && $svcMgr->isRunning()) { - - my $response = $self->serverRequest('getstring', $stringToken); - - if (ref $response eq 'HASH' && $response->{$stringToken} && $response->{$stringToken} ne $stringToken) { - $string = $response->{$stringToken}; - Slim::Utils::Light::setString($stringToken, $string); - } - } - - return $string; -} - -sub serverRequest { - my $self = shift; - my $postdata; - - return unless $svcMgr->isRunning(); - - eval { $postdata = '{"id":1,"method":"slim.request","params":["",' . to_json(\@_) . ']}' }; - - return if $@ || !$postdata; - - my $baseUrl = $self->getBaseUrl(); - $baseUrl =~ s|^http://||; - - my $req = HTTP::Request->new( - 'POST' => "http://$baseUrl/jsonrpc.js", - ); - $req->header('Content-Type' => 'text/plain'); - - $req->content($postdata); - - my $ua = LWP::UserAgent->new(); - $ua->timeout(2); - - if ($credentials && $credentials->{username} && $credentials->{password}) { - $ua->credentials($baseUrl, Slim::Utils::Light::string('SQUEEZEBOX_SERVER'), $credentials->{username}, $credentials->{password}); - } - - return if $needAuthentication; - - my $response = $ua->request($req); - - # check whether authentication is needed - while ($response->code == 401) { - - $needAuthentication = 1; - - my $loginDialog = Slim::GUI::ControlPanel::LoginDialog->new(); - - if ($loginDialog->ShowModal() == wxID_OK) { - - $credentials = { - username => $loginDialog->username, - password => $loginDialog->password, - }; - - $ua->credentials($baseUrl, Slim::Utils::Light::string('SQUEEZEBOX_SERVER'), $credentials->{username}, $credentials->{password}); - - $response = $ua->request($req); - } - - else { - exit; - } - - $loginDialog->Destroy(); - } - - $needAuthentication = 0; - - my $content; - $content = $response->decoded_content if ($response); - - if ($content) { - eval { - $content = from_json($content); - $content = $content->{result}; - } - } - - return ref $content eq 'HASH' ? $content : { msg => $content }; -} - -1; - - -# Ok button will apply our changes -package Slim::GUI::ControlPanel::LoginDialog; - -use base 'Wx::Dialog'; -use Wx qw(:everything); -use Slim::Utils::Light; - -my ($username, $password); - -sub new { - my $self = shift; - - $self = $self->SUPER::new(undef, -1, string('LOGIN'), [-1, -1], [350, 220], wxDEFAULT_DIALOG_STYLE); - - my $mainSizer = Wx::BoxSizer->new(wxVERTICAL); - - $mainSizer->Add(Wx::StaticText->new($self, -1, string('CONTROLPANEL_AUTHENTICATION_REQUIRED')), 0, wxALL, 10); - - $mainSizer->Add(Wx::StaticText->new($self, -1, string('SETUP_USERNAME') . string('COLON')), 0, wxLEFT | wxRIGHT, 10); - $username = Wx::TextCtrl->new($self, -1, '', [-1, -1], [320, -1]); - $mainSizer->Add($username, 0, wxALL, 10); - - $mainSizer->Add(Wx::StaticText->new($self, -1, string('SETUP_PASSWORD') . string('COLON')), 0, wxLEFT | wxRIGHT, 10); - $password = Wx::TextCtrl->new($self, -1, '', [-1, -1], [320, -1], wxTE_PASSWORD); - $mainSizer->Add($password, 0, wxALL, 10); - - $mainSizer->AddStretchSpacer(); - - my $btnsizer = Wx::StdDialogButtonSizer->new(); - $btnsizer->AddButton(Wx::Button->new($self, wxID_OK, string('OK'))); - $btnsizer->AddButton(Wx::Button->new($self, wxID_CANCEL, string('CANCEL'))); - $btnsizer->Realize(); - $mainSizer->Add($btnsizer, 0, wxALL | wxGROW, 10); - - $self->SetSizer($mainSizer); - - $self->Centre(); - - return $self; -} - -sub username { - return $username->GetValue(); -} - - -sub password { - return $password->GetValue(); -} - -1; - - -package Slim::GUI::WebButton; - -use base 'Wx::Button'; - -use Wx qw(:everything); -use Wx::Event qw(EVT_BUTTON); - -use Slim::GUI::ControlPanel; -use Slim::Utils::Light; - -sub new { - my ($self, $page, $parent, $url, $label, $width) = @_; - - $self = $self->SUPER::new($page, -1, string($label), [-1, -1], [$width || -1, -1]); - - $parent->addStatusListener($self); - - $url = Slim::GUI::ControlPanel->getBaseUrl() . $url; - - EVT_BUTTON( $page, $self, sub { - Wx::LaunchDefaultBrowser($url); - }); - - return $self; -} - -1; diff --git a/Slim/GUI/ControlPanel/Advanced.pm b/Slim/GUI/ControlPanel/Advanced.pm deleted file mode 100644 index c55057968bd..00000000000 --- a/Slim/GUI/ControlPanel/Advanced.pm +++ /dev/null @@ -1,290 +0,0 @@ -package Slim::GUI::ControlPanel::Advanced; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use strict; -use base 'Wx::Panel'; - -use Wx qw(:everything); -use Wx::Event qw(EVT_BUTTON EVT_TIMER); -use File::Spec::Functions qw(catfile); - -use Slim::Utils::Light; -use Slim::Utils::ServiceManager; -use Slim::Utils::OSDetect; - -my $os = Slim::Utils::OSDetect::getOS(); - -if (main::ISWINDOWS) { - require Win32::Process; - - if (0) { - require 'auto/Win32/Process/List/autosplit.ix'; - } -} - -my %checkboxes; - -sub new { - my ($self, $nb, $parent, $args) = @_; - - $self = $self->SUPER::new($nb); - $self->{args} = $args; - - my $mainSizer = Wx::BoxSizer->new(wxVERTICAL); - - if (main::ISWINDOWS) { - - # check for SC updates - my $updateSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('SETUP_CHECKVERSION')), - wxVERTICAL - ); - - my $updateLabel = Wx::StaticText->new($self, -1, ''); - $updateSizer->Add($updateLabel, 0, wxLEFT | wxRIGHT | wxTOP | wxGROW, 10); - - # update button - my $btnUpdate = Wx::Button->new($self, -1, string('CONTROLPANEL_INSTALL_UPDATE')); - - EVT_BUTTON( $self, $btnUpdate, sub { - - if (my $installer = Slim::Utils::Light->checkForUpdate()) { - - Slim::Utils::Light->resetUpdateCheck(); - - my $processObj; - Win32::Process::Create( - $processObj, - $installer, - '', - 0, - Win32::Process::DETACHED_PROCESS() | Win32::Process::CREATE_NO_WINDOW() | Win32::Process::NORMAL_PRIORITY_CLASS(), - '.' - ) && exit; - - } - - }); - - $updateSizer->Add($btnUpdate, 0, wxALL, 10); - - $mainSizer->Add($updateSizer, 0, wxALL | wxGROW, 10); - - my $updateChecker = Wx::Timer->new($self, 1); - EVT_TIMER( $self, 1, sub { - my $ready = Slim::Utils::Light->checkForUpdate(); - $updateLabel->SetLabel( string($ready ? 'CONTROLPANEL_UPDATE_AVAILABLE' : 'CONTROLPANEL_NO_UPDATE_AVAILABLE') ); - $btnUpdate->Enable($ready); - - # check every five minutes - $updateChecker->Start(0.5 * 60 * 1000); - }); - $updateChecker->Start(500); - } - - - my $webSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('CONTROLPANEL_WEB_UI')), - wxVERTICAL - ); - - $webSizer->Add( Slim::GUI::WebButton->new($self, $parent, '/', 'CONTROLPANEL_WEB_CONTROL_DESC', 250) , 0, wxLEFT | wxTOP, 10 ); - $webSizer->Add( Slim::GUI::WebButton->new($self, $parent, '/settings/index.html', 'CONTROLPANEL_ADVANCED_SETTINGS_DESC', 250) , 0, wxALL, 10 ); - - $mainSizer->Add($webSizer, 0, wxALL | wxGROW, 10); - - - my $logSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('CONTROLPANEL_LOGFILES')), - wxVERTICAL - ); - - my $logBtnSizer = Wx::BoxSizer->new(wxHORIZONTAL); - - $logBtnSizer->Add(Slim::GUI::ControlPanel::LogLink->new($self, $parent, 'server.log', 'CONTROLPANEL_SHOW_SERVER_LOG')); - $logBtnSizer->Add(Slim::GUI::ControlPanel::LogLink->new($self, $parent, 'scanner.log', 'CONTROLPANEL_SHOW_SCANNER_LOG'), 0, wxLEFT, 10); - - $logSizer->Add($logBtnSizer, 0, wxALL, 10); - - $logSizer->Add(Slim::GUI::ControlPanel::LogOptions->new($self, $parent), 0, wxLEFT | wxBOTTOM, 10); - - $mainSizer->Add($logSizer, 0, wxALL | wxGROW, 10); - - - my $cleanupSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('CLEANUP')), - wxVERTICAL - ); - - $cleanupSizer->AddSpacer(5); - - foreach (@{ $args->{options} }) { - - # support only wants these three options - next unless $_->{name} =~ /^(?:prefs|cache)$/; - - $checkboxes{$_->{name}} = Wx::CheckBox->new( $self, -1, $_->{title}, $_->{position}); - $cleanupSizer->AddSpacer(5); - $cleanupSizer->Add($checkboxes{$_->{name}}, 0, wxLEFT, 10); - } - - my $btnCleanup = Wx::Button->new( $self, -1, string('CLEANUP_DO') ); - EVT_BUTTON( $self, $btnCleanup, \&doCleanup ); - - $cleanupSizer->Add($btnCleanup, 0, wxALL , 10); - - $mainSizer->Add($cleanupSizer, 0, wxALL | wxGROW, 10); - - $self->SetSizer($mainSizer); - - return $self; -} - -sub doCleanup { - my( $self, $event ) = @_; - - # return if no option was selected - return unless grep { $checkboxes{$_}->GetValue() } keys %checkboxes; - - my $svcMgr = Slim::Utils::ServiceManager->new(); - - if ($svcMgr->checkServiceState() == SC_STATE_RUNNING) { - - my $msg = Wx::MessageDialog->new($self, string('CLEANUP_WANT_TO_STOP_SC'), string('CLEANUP_DO'), wxYES_NO | wxNO_DEFAULT | wxICON_QUESTION); - - if ($msg->ShowModal() == wxID_YES) { - # stop SC before continuing - Slim::GUI::ControlPanel->serverRequest('stopserver'); - - # wait while SC is being shut down - my $wait = 59; - while ($svcMgr->checkServiceState != SC_STATE_STOPPED && $wait > 0) { - sleep 5; - $wait -= 5; - } - } - else { - # don't do anything - return; - } - } - - my $params = {}; - my $selected = 0; - - foreach (@{ $self->{args}->{options} }) { - - next unless $checkboxes{$_->{name}}; - - $params->{$_->{name}} = $checkboxes{$_->{name}}->GetValue(); - $selected ||= $checkboxes{$_->{name}}->GetValue(); - } - - if ($selected) { - Wx::BusyCursor->new(); - - my $folders = $self->{args}->{folderCB}($params); - - $self->{args}->{cleanCB}($folders) if $folders; - } -} - -1; - - -package Slim::GUI::ControlPanel::LogLink; - -use base 'Wx::Button'; - -use Wx qw(:everything); -use Wx::Event qw(EVT_BUTTON); -use File::Spec::Functions qw(catfile); - -use Slim::GUI::ControlPanel; -use Slim::Utils::Light; - -sub new { - my ($self, $page, $parent, $file, $label, $width) = @_; - - $self = $self->SUPER::new($page, -1, string($label), [-1, -1], [$width || -1, -1]); - - EVT_BUTTON( $page, $self, sub { - Wx::LaunchDefaultBrowser('file://' . $os->dirsFor('log') . "/$file"); - }); - - return $self; -} - -1; - - -package Slim::GUI::ControlPanel::LogOptions; - -use base 'Wx::Choice'; - -use Wx qw(:everything); -use File::Spec::Functions qw(catfile); - -use Slim::GUI::ControlPanel; -use Slim::Utils::Light; -use Slim::Utils::Log; -use Slim::Utils::ServiceManager; - -my $logGroups; - -sub new { - my ($self, $page, $parent) = @_; - - $logGroups = Slim::Utils::Log->logGroups(); - - my @logOptions = (string('DEBUG_DEFAULT')); - - my $x = 1; - foreach my $group (keys %$logGroups) { - - $logGroups->{$group}->{index} = $x; - push @logOptions, string($logGroups->{$group}->{label}); - - $x++; - } - - $parent->addApplyHandler($self, sub { - $self->save(@_); - }); - - $self = $self->SUPER::new($page, -1, [-1, -1], [-1, -1], \@logOptions); - - return $self; -} - - -sub save { - my $self = shift; - my $state = shift; - - my $selected = $self->GetSelection(); - my ($group) = grep { $logGroups->{$_}->{index} == $selected } keys %$logGroups; - - $group ||= 'default'; - - if ($state == SC_STATE_RUNNING) { - Slim::GUI::ControlPanel->serverRequest('logging', "group:$group"); - } - else { - Slim::Utils::Log->init({ - 'logconf' => catfile(scalar Slim::Utils::OSDetect::dirsFor('prefs'), 'log.conf'), - 'logtype' => 'server', - }) unless Slim::Utils::Log->isInitialized(); - - Slim::Utils::Log->setLogGroup($group, 1); - - Slim::Utils::Log->writeConfig(); - } -} - -1; \ No newline at end of file diff --git a/Slim/GUI/ControlPanel/Diagnostics.pm b/Slim/GUI/ControlPanel/Diagnostics.pm deleted file mode 100644 index d61daa9d524..00000000000 --- a/Slim/GUI/ControlPanel/Diagnostics.pm +++ /dev/null @@ -1,318 +0,0 @@ -package Slim::GUI::ControlPanel::Diagnostics; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use strict; -use base 'Wx::Panel'; - -use Wx qw(:everything); -use Wx::Event qw(EVT_BUTTON); - -use Net::Ping; -use Socket; -use Symbol; - -use Slim::Utils::Light; -use Slim::Utils::ServiceManager; - -my $svcMgr = Slim::Utils::ServiceManager->new(); - -my @checks; -my $cache; -my $alertBox; - -sub new { - my ($self, $nb) = @_; - - $self = $self->SUPER::new($nb); - - my $mainSizer = Wx::BoxSizer->new(wxVERTICAL); - - $alertBox = Wx::TextCtrl->new($self, -1, '', [-1, -1], [-1, 90], wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH | wxTE_RICH2 | wxTE_AUTO_URL); - - my $scBoxSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('SQUEEZEBOX_SERVER')), - wxVERTICAL - ); - my $scSizer = Wx::FlexGridSizer->new(0, 2, 5, 10); - $scSizer->AddGrowableCol(0, 2); - $scSizer->AddGrowableCol(1, 1); - $scSizer->SetFlexibleDirection(wxHORIZONTAL); - - $self->_addItem($scSizer, string('SQUEEZEBOX_SERVER') . string('COLON'), sub { - $_[0] ? string('RUNNING') : string('STOPPED'); - }); - $self->_addItem($scSizer, string('INFORMATION_SERVER_IP') . string('COLON'), \&getHostIP); - $self->_addItem($scSizer, string('CONTROLPANEL_PORTNO', '', '3483', 'slimproto'), sub { - checkPort(getHostIP(), '3483', $_[0]); - }); - - my $httpPort = Slim::GUI::ControlPanel->getPref('httpport') || 9000; - $self->_addItem($scSizer, string('CONTROLPANEL_PORTNO', '', $httpPort, 'HTTP'), sub { - my $isRunning = shift; - my ($state, $stateString) = checkPort(getHostIP(), $httpPort, 1); - - # check failed - let's try to figure out why - if ($isRunning && !$state) { - $alertBox->AppendText(string('CONTROLPANEL_PORTBLOCKED', '', $httpPort)); - - # server running, but not accessible -> firewall? - if (main::ISWINDOWS && (my $conflicts = $self->getConflictingApp('Firewall'))) { - $alertBox->AppendText(string('CONTROLPANEL_PORTBLOCKED_APPS')); - - foreach (keys %$conflicts) { - my $conflict = $conflicts->{$_}; - - $alertBox->AppendText("\n* " . ($conflict->{ProgramName} || $conflict->{ProgramName})); - $alertBox->AppendText(string('COLON') . ' ' . string('CONTROLPANEL_CONFLICT_' . uc($conflict->{Help}))) if $conflict->{Help}; - } - - $alertBox->AppendText("\n\n"); - } - } - - elsif (!$isRunning && $state) { - $alertBox->AppendText(string('CONTROLPANEL_PORTCONFLICT', '', $httpPort)); - - # server not running, but port open -> other application using it? - if (main::ISWINDOWS && (my $conflicts = $self->getConflictingApp('PortConflict'))) { - - foreach (keys %$conflicts) { - my $conflict = $conflicts->{$_}; - - if ($conflict->{Port} == $httpPort || $conflict->{ServiceName} eq 'Perl') { - $alertBox->AppendText("\n* " . ($conflict->{ProgramName} || $conflict->{ProgramName})); - $alertBox->AppendText(string('COLON') . ' ' . string('CONTROLPANEL_CONFLICT_' . uc($conflict->{Help}))) if $conflict->{Help}; - } - } - - $alertBox->AppendText("\n\n"); - } - - } - - # on Windows we want to look out for other potential offenders... - elsif (main::ISWINDOWS && !$isRunning && (my $conflicts = $self->getConflictingApp('Other'))) { - $alertBox->AppendText(string('CONTROLPANEL_OTHER_ISSUE')); - - foreach (keys %$conflicts) { - my $conflict = $conflicts->{$_}; - - $alertBox->AppendText("\n* " . ($conflict->{ProgramName} || $conflict->{ProgramName})); - $alertBox->AppendText(string('COLON') . ' ' . string('CONTROLPANEL_OTHER_ISSUE_' . uc($conflict->{Help}))) if $conflict->{Help}; - } - - $alertBox->AppendText("\n\n"); - - } - - return $stateString; - }); - - my $cliPort = Slim::GUI::ControlPanel->getPref('cliport', 'cli.prefs') || 9090; - $self->_addItem($scSizer, string('CONTROLPANEL_PORTNO', '', $cliPort, 'CLI'), sub { - checkPort(getHostIP(), $cliPort, $_[0]); - }); - - $scBoxSizer->Add($scSizer, 0, wxALL | wxGROW, 10); - $mainSizer->Add($scBoxSizer, 0, wxALL | wxGROW, 10); - - - my $alertBoxSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('CONTROLPANEL_ALERTS')), - wxVERTICAL - ); - - $alertBoxSizer->Add($alertBox, 0, wxALL | wxGROW, 10); - - $mainSizer->Add($alertBoxSizer, 0, wxALL | wxEXPAND, 10); - - - my $btnRefresh = Wx::Button->new( $self, -1, string('CONTROLPANEL_REFRESH') ); - EVT_BUTTON( $self, $btnRefresh, sub { - $self->_update(); - } ); - - $mainSizer->Add($btnRefresh, 0, wxALL, 10); - - $self->SetSizer($mainSizer); - - return $self; -} - -sub _addItem { - my ($self, $sizer, $label, $checkCB) = @_; - - $sizer->Add(Wx::StaticText->new($self, -1, string($label))); - - my $labelText = Wx::StaticText->new($self, -1, '', [-1, -1], [-1, -1], wxALIGN_RIGHT); - push @checks, { - label => $labelText, - cb => ref $checkCB eq 'CODE' ? $checkCB : sub { $checkCB }, - }; - - $sizer->Add($labelText); -} - -sub _update { - my ($self, $event) = @_; - - $alertBox->SetValue(''); - foreach my $check (@checks) { - - if ($check->{label}) { - $check->{label}->SetLabel(''); - $self->Layout(); - } - } - - $self->Update; - - my $isRunning = $svcMgr->checkServiceState() == SC_STATE_RUNNING; - - foreach my $check (@checks) { - - if (defined $check->{cb} && $check->{cb}) { - eval { - my $val = &{$check->{cb}}($isRunning); - $check->{label}->SetLabel($val || 'n/a') if $check->{label}; - - $self->Layout(); - }; - - print "$@" if $@; - } - } - - $alertBox->ShowPosition(0); - $self->Layout(); -} - -sub getConflictingApp { - my ($self, $type) = @_; - - return unless main::ISWINDOWS; - - require XML::Simple; - require Win32::Service; - require Win32::Process::List; - - my $file = "../platforms/win32/installer/ApplicationData.xml"; - - if (!-f $file && defined $PerlApp::VERSION) { - $file = PerlApp::extract_bound_file('ApplicationData.xml'); - } - - else { - $file = "ApplicationData.xml"; - } - - return if !-f $file; - - my $ref = XML::Simple::XMLin($file); - - return unless $ref->{'d:Culture'}->{'d:process'}; - - # create list of apps of the wanted type - my (%apps, $conflicingApps); - map { $apps{$_->{ServiceName}} = $_ } - grep { $_->{type} eq $type } - @{ $ref->{'d:Culture'}->{'d:process'} }; - - foreach (keys %apps) { - my %status; - if (Win32::Service::GetStatus('.', $_, \%status)) { - $conflicingApps->{$_} = $apps{$_}; - } - } - - my $p = Win32::Process::List->new; - if ($p->IsError != 1) { - my %processes = $p->GetProcesses(); - - foreach my $process ( grep { !$conflicingApps->{$_} } keys %apps ) { - if (grep { $processes{$_} =~ /^$process\b/i } keys %processes) { - $conflicingApps->{$process} = $apps{$process}; - } - } - } - - return $conflicingApps; -} - -sub getHostIP { - return $cache->{SC}->{IP} if $cache->{SC} && $cache->{SC}->{ttl} < time; - - # Thanks to trick from Bill Fenner, trying to use a UDP socket won't - # send any packets out over the network, but will cause the routing - # table to do a lookup, so we can find our address. Don't use a high - # level abstraction like IO::Socket, as it dies when connect() fails. - # - # time.nist.gov - though it doesn't really matter. - my $raddr = '192.43.244.18'; - my $rport = 123; - - my $proto = (getprotobyname('udp'))[2]; - my $pname = (getprotobynumber($proto))[0]; - my $sock = Symbol::gensym(); - - my $iaddr = inet_aton($raddr) || return; - my $paddr = sockaddr_in($rport, $iaddr); - socket($sock, PF_INET, SOCK_DGRAM, $proto) || return; - connect($sock, $paddr) || return; - - # Find my half of the connection - my ($port, $address) = sockaddr_in( (getsockname($sock))[0] ); - - my $scAddress; - $scAddress = inet_ntoa($address) if $address; - - $cache->{SC} = { - ttl => time() + 60, - IP => $scAddress, - } ; - - return $scAddress; -} - -sub checkPort { - my ($raddr, $rport, $serviceState) = @_; - - return (wantarray ? (0, string('CONTROLPANEL_FAILED')) : string('CONTROLPANEL_FAILED')) unless $raddr && $rport && $serviceState; - - my $iaddr = inet_aton($raddr); - my $paddr = sockaddr_in($rport, $iaddr); - - socket(SSERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')); - - if (connect(SSERVER, $paddr)) { - - close(SSERVER); - return wantarray ? (1, string('CONTROLPANEL_OK')) : string('CONTROLPANEL_OK'); - } - - return wantarray ? (0, string('CONTROLPANEL_FAILED')) : string('CONTROLPANEL_FAILED'); -} - -sub checkPing { - my ($host, $port, $serviceState) = @_; - - return (wantarray ? (0, string('CONTROLPANEL_FAILED')) : string('CONTROLPANEL_FAILED')) unless $host && $serviceState; - - my $p = Net::Ping->new('tcp', 2); - - $p->{port_num} = $port if $port; - - my @result = ($p->ping($host) ? 1 : 0); - push @result, string($p->ping($host) ? 'CONTROLPANEL_OK' : 'CONTROLPANEL_FAILED'); - $p->close(); - - return wantarray ? @result : $result[1]; -} - - -1; \ No newline at end of file diff --git a/Slim/GUI/ControlPanel/Music.pm b/Slim/GUI/ControlPanel/Music.pm deleted file mode 100644 index 8a0a842b082..00000000000 --- a/Slim/GUI/ControlPanel/Music.pm +++ /dev/null @@ -1,183 +0,0 @@ -package Slim::GUI::ControlPanel::Music; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use strict; -use base 'Wx::Panel'; - -use Wx qw(:everything); -use Wx::Event qw(EVT_BUTTON EVT_CHOICE); - -use Slim::Utils::Light; -use Slim::Utils::ServiceManager; - -sub new { - my ($self, $nb, $parent) = @_; - - $self = $self->SUPER::new($nb); - - my $svcMgr = Slim::Utils::ServiceManager->new(); - - my $mainSizer = Wx::BoxSizer->new(wxVERTICAL); - - $mainSizer->Add($self->getLibraryName($parent), 0, wxALL | wxGROW, 10); - - my $settingsSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('MEDIASOURCE')), - wxVERTICAL - ); - - # folder selectors - $settingsSizer->Add(Wx::StaticText->new($self, -1, string('SETUP_MEDIADIRS')), 0, wxLEFT | wxTOP, 10); - - my $mediaDirsSizer = Wx::BoxSizer->new(wxVERTICAL); - my $dirsBtnSizer = Wx::BoxSizer->new(wxHORIZONTAL); - - my $dirsList = Wx::ListBox->new($self, -1, wxDefaultPosition, wxDefaultSize, [], wxLB_EXTENDED); - my $mediadirs = Slim::GUI::ControlPanel->getPref('mediadirs'); - if ($mediadirs && ref $mediadirs eq 'ARRAY') { - $dirsList->InsertItems($mediadirs, 0); - } - $mediaDirsSizer->Add($dirsList, 0, wxGROW, 10); - - my $btnAdd = Wx::Button->new($self, -1, string('ADD')); - $parent->addStatusListener($btnAdd); - $dirsBtnSizer->Add($btnAdd, 0); - $dirsBtnSizer->AddSpacer(5); - - my $btnRemove = Wx::Button->new($self, -1, string('DELETE')); - $parent->addStatusListener($btnRemove); - $dirsBtnSizer->Add($btnRemove, 0); - - $mediaDirsSizer->Add($dirsBtnSizer, 0, wxTOP, 5); - $settingsSizer->AddSpacer(5); - $settingsSizer->Add($mediaDirsSizer, 0, wxGROW | wxLEFT | wxRIGHT, 10); - - EVT_BUTTON($self, $btnAdd, sub { - my $dirsSelector = Wx::DirDialog->new($self); - if ($dirsSelector->ShowModal() == wxID_OK) { - if (my $path = $dirsSelector->GetPath()) { - $dirsList->Append($path); - } - } - }); - - EVT_BUTTON($self, $btnRemove, sub { - my @selected = $dirsList->GetSelections(); - foreach (reverse sort @selected) { - $dirsList->Delete($_); - } - }); - - $parent->addApplyHandler($self, sub { - my $running = (shift == SC_STATE_RUNNING); - - my @mediaDirs = $dirsList->GetStrings(); - - if ($running && scalar @mediaDirs) { - Slim::GUI::ControlPanel->setPref('mediadirs', \@mediaDirs); - } - }); - - - $settingsSizer->Add(Wx::StaticText->new($self, -1, string('SETUP_PLAYLISTDIR')), 0, wxLEFT | wxTOP, 10); - $settingsSizer->AddSpacer(5); - $settingsSizer->Add( - Slim::GUI::ControlPanel::DirPicker->new($self, $parent, 'playlistdir', 'SETUP_PLAYLISTDIR'), - 0, wxEXPAND | wxLEFT | wxBOTTOM | wxRIGHT, 10 - ); - - my $iTunes = getPref('iTunes', 'state.prefs'); - my $useItunesStr = ($svcMgr->checkServiceState() == SC_STATE_RUNNING) - ? Slim::GUI::ControlPanel->serverRequest('getstring', 'USE_ITUNES') - : {}; - - if ($useItunesStr && $useItunesStr->{USE_ITUNES} && (!$iTunes || $iTunes !~ /disabled/i)) { - - my $useItunes = Wx::CheckBox->new($self, -1, $useItunesStr->{USE_ITUNES}); - - $settingsSizer->Add($useItunes, 0, wxEXPAND | wxALL, 10); - $parent->addStatusListener($useItunes); - $useItunes->SetValue(Slim::GUI::ControlPanel->getPref('itunes', 'itunes.prefs')); - - $parent->addApplyHandler($useItunes, sub { - if (shift == SC_STATE_RUNNING) { - Slim::GUI::ControlPanel->setPref('plugin.itunes:itunes', $useItunes->IsChecked() ? 1 : 0); - } - }); - } - - $mainSizer->Add($settingsSizer, 0, wxALL | wxEXPAND, 10); - - $self->SetSizer($mainSizer); - - return $self; -} - - -sub getLibraryName { - my ($self, $parent) = @_; - - my $musicLibrarySizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('SETUP_LIBRARY_NAME')), - wxVERTICAL - ); - - $musicLibrarySizer->Add(Wx::StaticText->new($self, -1, string('SETUP_LIBRARY_NAME_DESC')), 0, wxLEFT | wxTOP, 10); - $musicLibrarySizer->AddSpacer(5); - my $libraryname = Wx::TextCtrl->new($self, -1, Slim::GUI::ControlPanel->getPref('libraryname') || '', [-1, -1], [300, -1]); - $musicLibrarySizer->Add($libraryname, 0, wxLEFT | wxBOTTOM | wxRIGHT | wxGROW, 10); - - $parent->addStatusListener($libraryname); - $parent->addApplyHandler($libraryname, sub { - if (shift == SC_STATE_RUNNING) { - Slim::GUI::ControlPanel->setPref('libraryname', $libraryname->GetValue()); - } - }); - - return $musicLibrarySizer; -} - -1; - - -package Slim::GUI::ControlPanel::DirPicker; - -use base 'Wx::DirPickerCtrl'; - -use Wx qw(:everything); - -use Slim::Utils::Light; -use Slim::Utils::OSDetect; -use Slim::Utils::ServiceManager; - -sub new { - my ($self, $page, $parent, $pref, $title) = @_; - - $self = $self->SUPER::new( - $page, - -1, - Slim::GUI::ControlPanel->getPref($pref) || '', - string($title), - wxDefaultPosition, wxDefaultSize, wxPB_USE_TEXTCTRL | wxDIRP_DIR_MUST_EXIST - ); - - $parent->addApplyHandler($self, sub { - my $running = (shift == SC_STATE_RUNNING); - - my $path = $self->GetPath; - if ($running && $path ne Slim::GUI::ControlPanel->getPref($pref)) { - Slim::GUI::ControlPanel->setPref($pref, $path); - } - }); - - $parent->addStatusListener($self); - - return $self; -} - -1; diff --git a/Slim/GUI/ControlPanel/Settings.pm b/Slim/GUI/ControlPanel/Settings.pm deleted file mode 100644 index 1be042d14f4..00000000000 --- a/Slim/GUI/ControlPanel/Settings.pm +++ /dev/null @@ -1,432 +0,0 @@ -package Slim::GUI::ControlPanel::Settings; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use strict; -use base 'Wx::Panel'; - -use Encode; -use Wx qw(:everything); -use Wx::Event qw(EVT_BUTTON EVT_CHOICE EVT_TEXT); - -use Slim::GUI::ControlPanel; -use Slim::Utils::Light; -use Slim::Utils::ServiceManager; - -my ($progressPoll, $btnRescan, $setStartupMode, $setStartupModeHandler); - -sub new { - my ($self, $nb, $parent) = @_; - - $self = $self->SUPER::new($nb); - - my $svcMgr = Slim::Utils::ServiceManager->new(); - - my $mainSizer = Wx::BoxSizer->new(wxVERTICAL); - - my ($noAdminWarning, @startupOptions) = $svcMgr->getStartupOptions(); - - if ($noAdminWarning) { - my $string = string($noAdminWarning); - $string =~ s/\\n/\n/g; - - my $warning = Wx::StaticText->new($self, -1, $string); - $warning->SetForegroundColour(wxRED); - my ($width) = $parent->GetSizeWH(); - $warning->Wrap($width - 70) if $width && $width > 200; - $mainSizer->Add($warning, 0, wxALL, 10); - } - - - my $statusSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('CONTROLPANEL_SERVERSTATUS')), - wxVERTICAL - ); - - my $statusLabel = Wx::StaticText->new($self, -1, ''); - $statusSizer->Add($statusLabel, 0, wxALL, 10); - - $parent->addStatusListener($statusLabel, sub { - my $state = shift; - - if ($state == SC_STATE_STOPPED) { - $statusLabel->SetLabel(string('CONTROLPANEL_STATUS_STOPPED')); - } - elsif ($state == SC_STATE_RUNNING) { - $statusLabel->SetLabel(string('CONTROLPANEL_STATUS_RUNNING')); - } - elsif ($state == SC_STATE_STARTING) { - $statusLabel->SetLabel(string('CONTROLPANEL_STATUS_STARTING')); - } - - }); - - # Start/Stop button - my $btnStartStop = Wx::Button->new($self, -1, string('STOP_SQUEEZEBOX_SERVER')); - - $parent->addStatusListener($btnStartStop, sub { - $btnStartStop->SetLabel($_[0] == SC_STATE_RUNNING ? string('STOP_SQUEEZEBOX_SERVER') : string('START_SQUEEZEBOX_SERVER')); - $btnStartStop->Enable( ($_[0] == SC_STATE_RUNNING || $_[0] == SC_STATE_STOPPED || $_[0] == SC_STATE_UNKNOWN) && ($_[0] == SC_STATE_STOPPED ? $svcMgr->canStart : 1) ); - $btnStartStop->SetSize( $btnStartStop->GetBestSize() ); - }); - $statusSizer->Add($btnStartStop, 0, wxLEFT, 10); - - my $cbStartSafeMode = Wx::CheckBox->new($self, -1, string('RUN_FAILSAFE')); - $parent->addStatusListener($cbStartSafeMode, sub { - $cbStartSafeMode->Enable( $_[0] == SC_STATE_STOPPED ); - }); - $statusSizer->Add($cbStartSafeMode, 0, wxLEFT | wxTOP | wxBOTTOM, 10); - - # check box if server is running in failsafe mode - $cbStartSafeMode->SetValue( $svcMgr->checkServiceState() == SC_STATE_RUNNING && Slim::GUI::ControlPanel->getPref('failsafe') ); - - @startupOptions = map { string($_) } @startupOptions; - my $lbStartupMode = Wx::Choice->new($self, -1, [-1, -1], [-1, -1], \@startupOptions); - - EVT_CHOICE($self, $lbStartupMode, sub { - $setStartupMode = 1; - }); - - EVT_BUTTON( $self, $btnStartStop, sub { - if ($svcMgr->checkServiceState() == SC_STATE_RUNNING) { - Slim::GUI::ControlPanel->serverRequest('stopserver'); - } - - # starting SC is heavily platform dependant - else { - &$setStartupModeHandler() if $setStartupModeHandler; - $svcMgr->start($cbStartSafeMode->IsChecked() ? '--failsafe --debug server=debug,server.plugins=debug --d_startup' : undef); - $parent->checkServiceStatus(); - } - }); - - $mainSizer->Add($statusSizer, 0, wxALL | wxGROW, 10); - - - my $startupSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('CONTROLPANEL_STARTUP_OPTIONS')), - wxVERTICAL - ); - - $lbStartupMode->SetSelection($svcMgr->getStartupType() || 0); - $lbStartupMode->Enable($svcMgr->canSetStartupType()); - - $setStartupModeHandler = sub { - $svcMgr->setStartupType($lbStartupMode->GetSelection()) if $setStartupMode; - $setStartupMode = 0; - }; - - # use dummy listener to allow setting startup mode whether server is running or not - $parent->addStatusListener($lbStartupMode, sub {}); - - $startupSizer->Add($lbStartupMode, 0, wxLEFT | wxRIGHT | wxTOP, 10); - - if (main::ISWINDOWS) { - require Win32::TieRegistry; - $Win32::TieRegistry::Registry->Delimiter('/'); - my $serviceUser = $Win32::TieRegistry::Registry->{'LMachine/SYSTEM/CurrentControlSet/Services/squeezesvc/ObjectName'} || ''; - $serviceUser = '' if $serviceUser =~ /^(?:LocalSystem)$/i; - - my $credentialsSizer = Wx::FlexGridSizer->new(2, 2, 5, 10); - $credentialsSizer->AddGrowableCol(1, 1); - $credentialsSizer->SetFlexibleDirection(wxHORIZONTAL); - - $credentialsSizer->Add(Wx::StaticText->new($self, -1, string('SETUP_USERNAME') . string('COLON'))); - my $username = Wx::TextCtrl->new($self, -1, $serviceUser, [-1, -1], [150, -1]); - $credentialsSizer->Add($username); - EVT_TEXT($self, $username, sub { - $setStartupMode = 1; - }); - - $credentialsSizer->Add(Wx::StaticText->new($self, -1, string('SETUP_PASSWORD') . string('COLON'))); - my $password = Wx::TextCtrl->new($self, -1, '', [-1, -1], [150, -1], wxTE_PASSWORD); - $credentialsSizer->Add($password); - EVT_TEXT($self, $password, sub { - $setStartupMode = 1; - }); - - $startupSizer->Add($credentialsSizer, 0, wxALL, 10); - - my $handler = sub { - $username->Enable($lbStartupMode->GetSelection() == 2); - $password->Enable($lbStartupMode->GetSelection() == 2); - }; - - &$handler(); - EVT_CHOICE($self, $lbStartupMode, sub { - $setStartupMode = 1; - &$handler(); - }); - - # overwrite action handler for startup mode - $setStartupModeHandler = sub { - - if ($setStartupMode) { - - $svcMgr->setStartupType( - $lbStartupMode->GetSelection(), - $username->GetValue(), - $password->GetValue(), - ); - } - - $setStartupMode = 0; - }; - - # doubleclick action for tray icon - my $lbDoubleClickHandler = Wx::Choice->new($self, -1, [-1, -1], [-1, -1], [ string('CONTROLPANEL_TRAY_DOUBLECLICK_CONTROLPANEL'), string('CONTROLPANEL_TRAY_DOUBLECLICK_WEB') ]); - $lbDoubleClickHandler->SetSelection($Win32::TieRegistry::Registry->{'CUser/Software/Logitech/Squeezebox/DefaultToWebUI'} || 0); - - $parent->addApplyHandler($lbDoubleClickHandler, sub { - $Win32::TieRegistry::Registry->{'CUser/Software/Logitech/Squeezebox/DefaultToWebUI'} = $lbDoubleClickHandler->GetSelection() ? '1' : '0'; - }); - $startupSizer->Add($lbDoubleClickHandler, 0, wxLEFT | wxRIGHT | wxBOTTOM, 10); - } - - $parent->addApplyHandler($lbStartupMode, $setStartupModeHandler); - - $mainSizer->Add($startupSizer, 0, wxALL | wxGROW, 10); - - - my $rescanSizer = Wx::StaticBoxSizer->new( - Wx::StaticBox->new($self, -1, string('INFORMATION_MENU_SCAN')), - wxVERTICAL - ); - - my $rescanBtnSizer = Wx::BoxSizer->new(wxHORIZONTAL); - - my $rescanMode = Wx::Choice->new($self, -1, [-1, -1], [-1, -1], [ - string('SETUP_STANDARDRESCAN'), - string('SETUP_WIPEDB'), - string('SETUP_PLAYLISTRESCAN'), - ]); - $rescanMode->SetSelection(0); - $rescanBtnSizer->Add($rescanMode); - $parent->addStatusListener($rescanMode); - - $btnRescan = Wx::Button->new($self, -1, string('SETUP_RESCAN_BUTTON')); - $rescanBtnSizer->Add($btnRescan, 0, wxLEFT, 5); - $parent->addStatusListener($btnRescan); - - EVT_BUTTON($self, $btnRescan, sub { - if ($btnRescan->GetLabel() eq string('ABORT_SCAN')) { - Slim::GUI::ControlPanel->serverRequest('abortscan'); - } - - elsif ($rescanMode->GetSelection == 0) { - Slim::GUI::ControlPanel->serverRequest('rescan'); - } - - elsif ($rescanMode->GetSelection == 1) { - Slim::GUI::ControlPanel->serverRequest('wipecache'); - } - - elsif ($rescanMode->GetSelection == 2) { - Slim::GUI::ControlPanel->serverRequest('rescan', 'playlists'); - } - - $progressPoll->Start(100, wxTIMER_CONTINUOUS, 10) if $progressPoll && $btnRescan->GetLabel() ne string('ABORT_SCAN'); - }); - - $rescanSizer->Add($rescanBtnSizer, 0, wxALL | wxGROW, 10); - - my $progressPanel = Wx::Panel->new($self); - $progressPoll = Slim::GUI::ControlPanel::ScanPoll->new($progressPanel); - $parent->addStatusListener($progressPanel); - - $rescanSizer->Add($progressPanel, 1, wxLEFT | wxRIGHT | wxGROW, 10); - - $mainSizer->Add($rescanSizer, 0, wxALL | wxGROW, 10); - - - $self->SetSizer($mainSizer); - - return $self; -} - -1; - - -package Slim::GUI::ControlPanel::ScanPoll; - -use base 'Wx::Timer'; - -use Wx qw(:everything); - -use Slim::Utils::Light; -use Slim::Utils::ServiceManager; - -my $svcMgr = Slim::Utils::ServiceManager->new(); -my $isScanning = 0; - -my ($parent, $progressBar, $progressTime, $progressLabel, $progressInfo); - -sub new { - my $self = shift; - $parent = shift; - - $self = $self->SUPER::new(); - $self->Start(250); - - my $sizer = Wx::BoxSizer->new(wxVERTICAL); - - $progressLabel = Wx::StaticText->new($parent, -1, ''); - $sizer->Add($progressLabel, 0, wxEXPAND | wxTOP | wxBOTTOM, 5); - - my $progressSizer = Wx::BoxSizer->new(wxHORIZONTAL); - - $progressBar = Wx::Gauge->new($parent, -1, 100, [-1, -1], [-1, main::ISWINDOWS ? 20 : -1]); - $progressSizer->Add($progressBar, 1, wxGROW); - - $progressTime = Wx::StaticText->new($parent, -1, '00:00:00'); - $progressSizer->AddSpacer(10); - $progressSizer->Add($progressTime, 0, wxTOP, 3); - - $sizer->Add($progressSizer, 0, wxEXPAND); - -# re-enable ellipsizing once we're running Wx 2.9.x -# $progressInfo = Wx::StaticText->new($parent, -1, '', [-1, -1], [-1, -1], wxST_ELLIPSIZE_MIDDLE); - $progressInfo = Wx::StaticText->new($parent, -1, ''); - $sizer->Add($progressInfo, 0, wxEXPAND | wxTOP | wxBOTTOM, 5); - - $sizer->AddSpacer(15); - - $parent->SetSizer($sizer); - - return $self; -} - -sub Start { - my ($self, $milliseconds, $oneShot, $scanInit) = @_; - - $isScanning = $scanInit if $scanInit; - - $self->SUPER::Start($milliseconds, $oneShot); -} - -sub Notify { - my $self = shift; - - $progressInfo->SetLabel(''); - - if ($svcMgr->isRunning()) { - - my $progress = Slim::GUI::ControlPanel->serverRequest('rescanprogress'); - - if ($progress && $progress->{rescan}) { - $self->showProgress($progress); - return; - } - - elsif ($progress && $progress->{lastscanfailed}) { - $progressLabel->SetLabel($progress->{lastscanfailed}); - } - - elsif (!$isScanning) { - $self->showStats(); - } - - elsif ($isScanning) { - $progressLabel->SetLabel(''); - } - } - - # don't poll that often when no scan is running - $self->Start(10000, wxTIMER_CONTINUOUS); - - if ($isScanning) { - $progressBar->SetValue(100); - $self->Start(1000, wxTIMER_CONTINUOUS); - - $isScanning--; - } - - $btnRescan->SetLabel(string($isScanning ? 'ABORT_SCAN' : 'SETUP_RESCAN_BUTTON')); - $btnRescan->SetSize( $btnRescan->GetBestSize() ); -} - -sub showProgress { - my $self = shift; - my $progress = shift; - - $isScanning = 1; - - $progressBar->Show(); - $progressLabel->SetLabel(''); - - my @steps = split(/,/, $progress->{steps} || 'directory'); - - if (@steps) { - - my $step = $steps[-1]; - $progressBar->SetValue($progress->{$step}) if $progress->{$steps[-1]}; - $progressLabel->SetLabel( @steps . '. ' . Slim::GUI::ControlPanel->string(uc($step) . '_PROGRESS') ); - $progressTime->SetLabel($progress->{totaltime}); - - } - - if (defined $progress->{info}) { - $progressInfo->SetLabel($progress->{info}); - } - - $btnRescan->SetLabel(string('ABORT_SCAN')); - $btnRescan->SetSize( $btnRescan->GetBestSize() ); - $self->Start(2100, wxTIMER_CONTINUOUS); - $self->Layout(); -} - -sub showStats { - my $self = shift; - - my $libraryStats = Slim::GUI::ControlPanel->serverRequest('systeminfo', 'items', 0, 999); - - if ($libraryStats && $libraryStats->{loop_loop}) { - my $libraryName = string('INFORMATION_MENU_LIBRARY'); - my $x = 0; - - foreach my $item (@{$libraryStats->{loop_loop}}) { - - last if ($item->{name} && $item->{name} eq $libraryName); - - $x++; - - } - - if ($x < scalar @{$libraryStats->{loop_loop}}) { - $libraryStats = Slim::GUI::ControlPanel->serverRequest('systeminfo', 'items', 0, 999, "item_id:$x"); - - if ($libraryStats && $libraryStats->{loop_loop}) { - my $newLabel = ''; - - foreach my $item (@{$libraryStats->{loop_loop}}) { - - if ($item->{name}) { - $newLabel .= $item->{name} . "\n"; - } - - } - - if ($newLabel) { - $progressBar->Hide(); - $progressTime->SetLabel(''); - $progressLabel->SetLabel($newLabel); - } - } - } - } -} - -sub Layout { - my $self = shift; - - my ($width) = $parent->GetSizeWH(); - $progressLabel->Wrap($width); - $parent->Layout(); -} - -1; - diff --git a/Slim/GUI/ControlPanel/Status.pm b/Slim/GUI/ControlPanel/Status.pm deleted file mode 100644 index 090726df16a..00000000000 --- a/Slim/GUI/ControlPanel/Status.pm +++ /dev/null @@ -1,98 +0,0 @@ -package Slim::GUI::ControlPanel::Status; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use strict; -use base 'Wx::Panel'; - -use Encode; -use Wx qw(:everything); -use Wx::Event qw(EVT_CHILD_FOCUS); -use Wx::Html; -use LWP::Simple qw($ua get); - -$ua->timeout(10); - -use Slim::Utils::Light; -use Slim::Utils::ServiceManager; - -sub new { - my ($self, $nb, $parent) = @_; - - $self = $self->SUPER::new($nb); - - $self->{loaded} = 0; - $self->{serviceState} = 0; - - $self->SetAutoLayout(1); - - my $mainSizer = Wx::BoxSizer->new(wxVERTICAL); - - $mainSizer->Add(Wx::HtmlWindow->new( - $self, - -1, - [-1, -1], - [-1, -1], - wxSUNKEN_BORDER - ), 1, wxALL | wxGROW, 10); - - $self->SetSizer($mainSizer); - - - EVT_CHILD_FOCUS($self, sub { - my ($self, $event) = @_; - $self->_update($event); - }); - - - $parent->addStatusListener('statusUpdater', sub { - my $state = shift; - - if ($state != $self->{serviceState}) { - $self->_update(); - } - }); - - - return $self; -} - -sub _update { - my ($self, $event) = @_; - - my $child = $self->GetChildren(); - - if ( $child && $child->isa('Wx::HtmlWindow') && !$self->{loaded} ) { - - my $svcMgr = Slim::Utils::ServiceManager->new(); - - if ($svcMgr->isRunning()) { - - my $status = get(Slim::GUI::ControlPanel->getBaseUrl(1) . '/EN/settings/server/status.html?simple=1'); - $status = decode("utf8", $status) if $status; - - $child->SetPage($status || string('CONTROLPANEL_NO_STATUS')); - $self->{loaded} = 1; - - } - else { - - $child->SetPage(string('CONTROLPANEL_NO_STATUS')); - $self->{loaded} = 1; - - } - - $self->{serviceState} = $svcMgr->getServiceState(); - } - else { - $self->{loaded} = 0; - } - - $event->Skip() if $event; -} - -1; diff --git a/Slim/Utils/Errno.pm b/Slim/Utils/Errno.pm index 9edfcc948aa..fd183fb77e9 100644 --- a/Slim/Utils/Errno.pm +++ b/Slim/Utils/Errno.pm @@ -40,19 +40,11 @@ our @EXPORT = qw(EWOULDBLOCK EINPROGRESS EINTR ECHILD EBADF); BEGIN { if (main::ISWINDOWS) { - if (main::ISACTIVEPERL) { - *EINTR = sub () { 10004 }; - *EBADF = sub () { 10009 }; - *ECHILD = sub () { 10010 }; - *EWOULDBLOCK = sub () { 10035 }; - *EINPROGRESS = sub () { 10036 }; - } else { - *EINTR = sub () { 4 }; - *EBADF = sub () { 9 }; - *ECHILD = sub () { 10 }; - *EWOULDBLOCK = sub () { 140 }; - *EINPROGRESS = sub () { 112 }; - } + *EINTR = sub () { 4 }; + *EBADF = sub () { 9 }; + *ECHILD = sub () { 10 }; + *EWOULDBLOCK = sub () { 140 }; + *EINPROGRESS = sub () { 112 }; } else { require Errno; import Errno qw(EWOULDBLOCK EINPROGRESS EINTR ECHILD EBADF); diff --git a/Slim/Utils/Light.pm b/Slim/Utils/Light.pm index baae1ede5ed..9723e48dc5b 100644 --- a/Slim/Utils/Light.pm +++ b/Slim/Utils/Light.pm @@ -110,22 +110,9 @@ sub loadStrings { my $language = ''; my $stringname = ''; - # server string file - my $file; - - # let's see whether this is a PerlApp/Tray compiled executable - if (defined $PerlApp::VERSION) { - $file = PerlApp::extract_bound_file('strings.txt'); - } - elsif (defined $PerlTray::VERSION) { - $file = PerlTray::extract_bound_file('strings.txt'); - } - # try to find the strings.txt file from our installation - unless ($file && -f $file) { - my $path = $os->dirsFor('strings'); - $file = catdir($path, 'strings.txt'); - } + my $path = $os->dirsFor('strings'); + my $file = catdir($path, 'strings.txt'); open(STRINGS, "<:utf8", $file) || do { warn "Couldn't open file [$file]!"; diff --git a/Slim/Utils/Misc.pm b/Slim/Utils/Misc.pm index c66468b1fb6..e2cf2f21cb6 100644 --- a/Slim/Utils/Misc.pm +++ b/Slim/Utils/Misc.pm @@ -1436,21 +1436,6 @@ sub shouldCacheURL { return 1; } -=head2 runningAsService ( ) - -Returns true if running as a Windows service. - -=cut - -sub runningAsService { if (main::ISACTIVEPERL) { - - if (defined(&PerlSvc::RunningAsService) && PerlSvc::RunningAsService()) { - return 1; - } - - return 0; -} } - =head2 validMacAddress ( ) Returns true if string is in correct form of a mac address diff --git a/Slim/Utils/OS.pm b/Slim/Utils/OS.pm index e8bee5ffd39..70633492e40 100644 --- a/Slim/Utils/OS.pm +++ b/Slim/Utils/OS.pm @@ -264,10 +264,6 @@ sub scanner { return "$Bin/scanner.pl"; } -sub gdresize { - return "$Bin/gdresize.pl"; -} - sub gdresized { return "$Bin/gdresized.pl"; } diff --git a/Slim/Utils/OS/Win32.pm b/Slim/Utils/OS/Win32.pm index c76f1f04031..9b471924363 100644 --- a/Slim/Utils/OS/Win32.pm +++ b/Slim/Utils/OS/Win32.pm @@ -25,12 +25,6 @@ my $driveList = {}; my $driveState = {}; my $writablePath; -sub getFlavor { - return (!main::ISACTIVEPERL && Win32::GetOSDisplayName() =~ /64-bit/i) - ? 'Win64' - : 'Win32'; -} - sub name { return 'win'; } @@ -114,15 +108,6 @@ sub initDetails { # This covers Vista or later $class->{osDetails}->{'isWin6+'} = ($major >= 6); - # some features are Vista only, no longer supported in Windows 7 - $class->{osDetails}->{isVista} = 1 if $class->{osDetails}->{'osName'} =~ /Vista/; - - # let's clean up our temporary folders (pdk* folders) - # only run when using the compiled version - if ($PerlSvc::VERSION && !main::SCANNER) { - $class->cleanupTempDirs(); - } - return $class->{osDetails}; } @@ -288,18 +273,6 @@ sub getFileName { return $path; } -sub scanner { - return -x "$Bin/scanner.exe" ? "$Bin/scanner.exe" : $_[0]->SUPER::scanner(); -} - -sub gdresize { - return -x "$Bin/gdresize.exe" ? "$Bin/gdresize.exe" : $_[0]->SUPER::gdresize(); -} - -sub gdresized { - return -x "$Bin/gdresized.exe" ? "$Bin/gdresized.exe" : $_[0]->SUPER::gdresized(); -} - sub localeDetails { eval { use POSIX qw(LC_TIME); }; require Win32::Locale; @@ -653,116 +626,5 @@ Get the current priority of the server. Disabled on Windows. sub getPriority {} -=head2 cleanupTempDirs( ) - -PDK compiled executables can leave temporary pdk-{username}-{pid} folders behind -if process is crashing. Use this method to clean them up. - -=cut - -sub cleanupTempDirs { - - my $dir = $ENV{TEMP}; - - return unless $dir && -d $dir; - - opendir(DIR, $dir) || return; - - my @folders = readdir(DIR); - close(DIR); - - my %pdkFolders; - for my $entry (@folders) { - if ($entry =~ /^pdk-.*?-(\d+)$/i) { - $pdkFolders{$1} = $entry - } - } - - return unless scalar(keys %pdkFolders); - - require File::Path; - require Win32::Process::List; - my $p = Win32::Process::List->new(); - my %processes = $p->GetProcesses(); - - foreach my $pid (keys %pdkFolders) { - - # don't remove files if process is still running... - next if $processes{$pid}; - - my $path = catdir($dir, $pdkFolders{$pid}); - next unless -d $path; - - eval { File::Path::rmtree($path) }; - } -} - - -sub getUpdateParams { - my ($class, $url) = @_; - - return { - path => $class->dirsFor('updates'), - }; -} - -sub canAutoUpdate { 1 } - -# return file extension filter for installer -sub installerExtension { '(?:exe|msi)' } - -sub installerOS { 'win' } - -sub restartServer { - my $class = shift; - - my $log = Slim::Utils::Log::logger('server.update'); - - - if (!$class->canRestartServer()) { - $log->warn("Lyrion Music Server can't be restarted automatically on Windows if run from the perl source."); - return; - } - - if ($PerlSvc::VERSION && PerlSvc::RunningAsService()) { - - my $svcHelper = Win32::GetShortPathName( catdir( $class->installPath, 'server', 'squeezesvc.exe' ) ); - my $processObj; - - Slim::bootstrap::tryModuleLoad('Win32::Process'); - - if ($@ || !Win32::Process::Create( - $processObj, - $svcHelper, - "$svcHelper --restart", - 0, - Win32::Process::DETACHED_PROCESS() | Win32::Process::CREATE_NO_WINDOW() | Win32::Process::NORMAL_PRIORITY_CLASS(), - ".") - ) { - $log->error("Couldn't restart Lyrion Music Server service (squeezesvc)"); - } - else { - return 1; - } - } - - elsif ($PerlSvc::VERSION) { - - my $restartFlag = catdir( Slim::Utils::Prefs::preferences('server')->get('cachedir') || scalar $class->dirsFor('cache'), 'restart.txt' ); - if (open(RESTART, ">$restartFlag")) { - close RESTART; - main::stopServer(); - return 1; - } - - else { - $log->error("Can't write restart flag ($restartFlag) - don't shut down"); - } - } - - return; -} - -sub canRestartServer { return $PerlSvc::VERSION ? 1 : 0; } 1; diff --git a/Slim/Utils/OS/Win64.pm b/Slim/Utils/OS/Win64.pm index 7ab49e9f7d2..487f5564d09 100644 --- a/Slim/Utils/OS/Win64.pm +++ b/Slim/Utils/OS/Win64.pm @@ -44,14 +44,6 @@ sub initSearchPath { Slim::Utils::Misc::addFindBinPaths(catdir($_[0] || $class->dirsFor('Bin'), $binArch)); } - -sub scanner { "$Bin/scanner.pl" } - -sub gdresize { "$Bin/gdresize.pl" } - -sub gdresized { "$Bin/gdresized.pl" } - - sub runService { if ($main::daemon) { my $class = shift; diff --git a/Slim/Utils/OSDetect.pm b/Slim/Utils/OSDetect.pm index dacbe64fc59..52366ec6d6d 100644 --- a/Slim/Utils/OSDetect.pm +++ b/Slim/Utils/OSDetect.pm @@ -76,14 +76,8 @@ sub init { } elsif ($^O =~ /^m?s?win/i) { - require Slim::Utils::OS::Win32; - if (Slim::Utils::OS::Win32->getFlavor() eq 'Win64') { - require Slim::Utils::OS::Win64; - $os = Slim::Utils::OS::Win64->new(); - } - else { - $os = Slim::Utils::OS::Win32->new(); - } + require Slim::Utils::OS::Win64; + $os = Slim::Utils::OS::Win64->new(); } elsif ($^O =~ /linux/i) { diff --git a/Slim/Utils/Prefs/Migration/README.md b/Slim/Utils/Prefs/Migration/README.md deleted file mode 100644 index 3f7c0618cf4..00000000000 --- a/Slim/Utils/Prefs/Migration/README.md +++ /dev/null @@ -1,6 +0,0 @@ -IMPORTANT -========= - -Whenever you add a new migration module (be it Vx.pm or ClientVx.pm), make sure you add it to -the Windows build file [squeezecenter.perlsvc](https://github.com/LMS-Community/slimserver-platforms/blob/public/8.0/win32/squeezecenter.perlsvc). -Otherwise the Windows build will not include it in the binary and fail to load. \ No newline at end of file diff --git a/Slim/Utils/ServiceManager.pm b/Slim/Utils/ServiceManager.pm deleted file mode 100644 index 9b0bd00a424..00000000000 --- a/Slim/Utils/ServiceManager.pm +++ /dev/null @@ -1,129 +0,0 @@ -package Slim::Utils::ServiceManager; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use Exporter::Lite; -@ISA = qw(Exporter); - -our @EXPORT = qw( - SC_STARTUP_TYPE_LOGIN SC_STARTUP_TYPE_NONE SC_STARTUP_TYPE_SERVICE - SC_STATE_STOPPED SC_STATE_RUNNING SC_STATE_STARTING SC_STATE_STOPPING SC_STATE_UNKNOWN -); - -use File::Spec::Functions qw(catdir); -use Socket; - -use Slim::Utils::OSDetect; -use Slim::Utils::Light; - -use constant SC_STARTUP_TYPE_NONE => 0; -use constant SC_STARTUP_TYPE_LOGIN => 1; -use constant SC_STARTUP_TYPE_SERVICE => 2; - -use constant SC_STATE_STOPPED => 0; -use constant SC_STATE_RUNNING => 1; -use constant SC_STATE_STARTING => -1; -use constant SC_STATE_STOPPING => -2; -use constant SC_STATE_UNKNOWN => -99; - -Slim::Utils::OSDetect::init(); - -sub new { - my $class = shift; - - my $svcMgr; - - if (Slim::Utils::OSDetect::isWindows()) { - - require Slim::Utils::ServiceManager::Win32; - $svcMgr = Slim::Utils::ServiceManager::Win32->init(); - - } - - elsif (Slim::Utils::OSDetect::isMac()) { - - require Slim::Utils::ServiceManager::OSX; - $svcMgr = Slim::Utils::ServiceManager::OSX->init(); - - } - - return $svcMgr || $class->init(); -} - -sub init { - my $class = shift; - - my $self = { - checkHTTP => 0, - status => SC_STATE_UNKNOWN, - }; - - return bless $self, $class; -} - -# Determine how the user wants to start Lyrion Music Server -sub getStartupType { - return SC_STARTUP_TYPE_NONE; -} - -sub canSetStartupType { 0 } -sub setStartupType {} -sub initStartupType {} -sub canStart {} - -sub getStartupOptions { - return ('', 'RUN_NEVER', 'RUN_AT_LOGIN', 'RUN_AT_BOOT'); -} - -sub start {} - -sub checkServiceState { - return SC_STATE_UNKNOWN; -} - -# we're called often - cache results for a second -my %isRunning; -sub isRunning { - - if (!defined $isRunning{state} || $isRunning{ttl} < time()) { - - %isRunning = ( - ttl => time() + 1, - state => $_[0]->checkServiceState() == SC_STATE_RUNNING - ); - - } - - return $isRunning{state}; -} - -sub getServiceState { - return defined $_[0]->{status} ? $_[0]->{status} : SC_STATE_UNKNOWN; -} - -sub checkForHTTP { - my $httpPort = getPref('httpport') || 9000; - - # Use low-level socket code. IO::Socket returns a 'Invalid Descriptor' - # erorr. It also sucks more memory than it should. - my $rport = $httpPort; - - my $iaddr = inet_aton('127.0.0.1'); - my $paddr = sockaddr_in($rport, $iaddr); - - socket(SSERVER, PF_INET, SOCK_STREAM, getprotobyname('tcp')); - - if (connect(SSERVER, $paddr)) { - - close(SSERVER); - return "http://127.0.0.1:$httpPort"; - } - - return 0; -} - -1; diff --git a/Slim/Utils/ServiceManager/OSX.pm b/Slim/Utils/ServiceManager/OSX.pm deleted file mode 100644 index 390a3cbdeec..00000000000 --- a/Slim/Utils/ServiceManager/OSX.pm +++ /dev/null @@ -1,56 +0,0 @@ -package Slim::Utils::ServiceManager::OSX; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use base qw(Slim::Utils::ServiceManager); - -use FindBin qw($Bin); -use File::Spec::Functions qw(catdir); -use Slim::Utils::ServiceManager; - -# re-use the startup-script we already have in place for the PreferencePane -sub canStart { 1 } -sub start { - my ($class, $params) = @_; - - foreach my $path ( - catdir($Bin, '..', 'platforms', 'osx', 'Preference Pane'), - catdir($Bin, '..', 'Resources'), - catdir($ENV{HOME}, '/Library/PreferencePanes/SqueezeCenter.prefPane/Contents/Resources'), - '/Library/PreferencePanes/SqueezeCenter.prefPane/Contents/Resources', - ) { - my $startScript = catdir($path, 'start-server.sh'); - - if (-f $startScript) { - - $startScript =~ s/ /\\ /g; - system( $startScript . ($params ? " $params" : '') ); - - last; - } - } - -} - -sub getStartupOptions { - return ("I'm sorry, we're not quite there yet", 'Whatever is defined in the PrefPane'); -} - -# simple check so far - only check http availability (no starting/stopping states) -sub checkServiceState { - my ($class) = @_; - - $class->{status} = $class->checkForHTTP() ? SC_STATE_RUNNING : SC_STATE_STOPPED; - - return $class->{status}; -} - -# use AppleScript to run some script as admin -# ugly but effective -# system('osascript -e \'do shell script "/run/something" with administrator privileges\''); - -1; \ No newline at end of file diff --git a/Slim/Utils/ServiceManager/Win32.pm b/Slim/Utils/ServiceManager/Win32.pm deleted file mode 100644 index 4628b9f8e49..00000000000 --- a/Slim/Utils/ServiceManager/Win32.pm +++ /dev/null @@ -1,248 +0,0 @@ -package Slim::Utils::ServiceManager::Win32; - -# Logitech Media Server Copyright 2001-2024 Logitech. -# Lyrion Music Server Copyright 2024 Lyrion Community. -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License, -# version 2. - -use base qw(Slim::Utils::ServiceManager); - -use File::Spec::Functions qw(catdir); -use FindBin qw($Bin); -use Win32::Process qw(DETACHED_PROCESS CREATE_NO_WINDOW NORMAL_PRIORITY_CLASS); -use Win32::Process::List; -use Win32::Service; -use Win32::TieRegistry ('Delimiter' => '/'); - -use constant LEGACY_USER_REGISTRY_KEY => 'CUser/Software/Logitech/Squeezebox'; -use constant USER_REGISTRY_KEY => 'CUser/Software/Lyrion/server'; -use constant SC_SERVICE_NAME => 'squeezesvc'; - -use Slim::Utils::OSDetect; -use Slim::Utils::ServiceManager; - -my $os = Slim::Utils::OSDetect::getOS(); -my $svcHelper; - -sub init { - my $class = shift; - $class = $class->SUPER::init(); - $svcHelper = catdir( Win32::GetShortPathName( scalar $os->dirsFor('base') ), 'server', 'squeezesvc.exe' ); - - return $class; -} - -# Determine how the user wants to start Lyrion Music Server -sub getStartupType { - my %services; - - Win32::Service::GetServices('', \%services); - - if (grep {$services{$_} =~ /squeezesvc/} keys %services) { - return SC_STARTUP_TYPE_SERVICE; - } - - if ($Registry->{USER_REGISTRY_KEY . '/StartAtLogin'}) { - return SC_STARTUP_TYPE_LOGIN; - } - - return SC_STARTUP_TYPE_NONE; -} - -sub canSetStartupType { - - # on Vista+ we can elevate privileges - if ($os->get('isVista')) { - return 1; - } - - # on other Windows versions we have to be member of the administrators group to be able to manage the service - # only return true if SC isn't configured to be run as a background service, OR if the user is an admin - else { - - my $isService = (getStartupType() == SC_STARTUP_TYPE_SERVICE); - return ($isService && Win32::IsAdminUser()) || !$isService; - } -} - -sub getStartupOptions { - my $class = shift; - - if (!$os->get('isVista') && !Win32::IsAdminUser()) { - return ('CONTROLPANEL_NEED_ADMINISTRATOR', 'RUN_NEVER', 'RUN_AT_LOGIN'); - } - - return $class->SUPER::getStartupOptions(); -} - -sub setStartupType { - my ($class, $type, $username, $password) = @_; - $username = '' unless defined $username; - - $Registry->{USER_REGISTRY_KEY . '/StartAtLogin'} = ($type == SC_STARTUP_TYPE_LOGIN || 0); - - # enable service mode - if ($type == SC_STARTUP_TYPE_SERVICE) { - my @args; - - push @args, "--username=$username" if $username; - push @args, "--password=$password" if $password; - push @args, '--install'; - - system($svcHelper, @args); - } - else { - system($svcHelper, "--remove"); - } - - return 1; -} - -sub initStartupType { - my $class = shift; - - # preset atLogin if it isn't defined yet - my $atLogin = $Registry->{USER_REGISTRY_KEY . '/StartAtLogin'}; - - if ($atLogin !~ /[01]/) { - - # make sure our Key does exist before we can write to it - if (! (my $regKey = $Registry->{USER_REGISTRY_KEY . ''})) { - $Registry->{'CUser/Software/Lyrion/'} = { - 'server/' => {} - }; - } - - # migrate startup setting - if (defined $Registry->{LEGACY_USER_REGISTRY_KEY . '/StartAtLogin'}) { - $Registry->{USER_REGISTRY_KEY . '/StartAtLogin'} = $Registry->{LEGACY_USER_REGISTRY_KEY . '/StartAtLogin'}; - delete $Registry->{LEGACY_USER_REGISTRY_KEY . '/StartAtLogin'}; - } - - $class->setStartupType(SC_STARTUP_TYPE_LOGIN); - } -} - -sub canStart { - canSetStartupType(); -} - -sub start { - my ($class, $params) = @_; - - if (!$params && $class->getStartupType() == SC_STARTUP_TYPE_SERVICE) { - - `$svcHelper --start`; - } - - else { - - my $appExe = Win32::GetShortPathName( catdir( scalar $os->dirsFor('base'), 'server', 'SqueezeSvr.exe' ) ); - - if ($params) { - $params = "$appExe $params"; - } - else { - $params = ''; - } - - # start as background job - my $processObj; - Win32::Process::Create( - $processObj, - $appExe, - $params, - 0, - DETACHED_PROCESS | CREATE_NO_WINDOW | NORMAL_PRIORITY_CLASS, - '.' - ) if $appExe; - - } - - $class->{checkHTTP} = 1; -} - - -sub checkServiceState { - my $class = shift; - - if ($class->getStartupType() == SC_STARTUP_TYPE_SERVICE) { - - my %status = (); - - Win32::Service::GetStatus('', SC_SERVICE_NAME, \%status); - - if ($status{'CurrentState'} == 0x04) { - - $class->{status} = SC_STATE_RUNNING; - } - - elsif ($status{'CurrentState'} == 0x02) { - - $class->{status} = SC_STATE_STARTING; - } - - elsif ($status{'CurrentState'} == 0x01) { - - $class->{status} = SC_STATE_STOPPED; - - # it could happen SC has been started as an app, even though - # it's configured to be running as a service - if (getProcessID() != -1) { - - $class->{status} = SC_STATE_RUNNING; - } - } - - elsif ($status{'CurrentState'} == 0x03) { - - $class->{status} = SC_STATE_STOPPING; - } - - } else { - - if (getProcessID() != -1) { - - $class->{status} = SC_STATE_RUNNING; - } - - else { - - $class->{status} = SC_STATE_STOPPED; - } - - } - - if ($class->{status} == SC_STATE_RUNNING) { - - if ($class->{checkHTTP} && !$class->checkForHTTP()) { - - $class->{status} = SC_STATE_STARTING; - } - - else { - - $class->{checkHTTP} = 0; - } - } - - return $class->{status}; -} - -sub getProcessID { - - my $p = Win32::Process::List->new; - - if ($p->IsError == 1) { - - return $p->GetErrorText; - } - - # Windows sometimes only displays squeez~1.exe or similar - my $pid = ($p->GetProcessPid(qr/^squeez(esvr|~\d).exe$/i))[1]; - - return $pid || -1; -} - -1; diff --git a/Slim/bootstrap.pm b/Slim/bootstrap.pm index b6630a62a27..6cfc8ec013a 100644 --- a/Slim/bootstrap.pm +++ b/Slim/bootstrap.pm @@ -193,11 +193,7 @@ sub loadModules { print "The following modules failed to load: $failed\n\n"; - if ( main::ISACTIVEPERL ) { - print "To run from source on Windows 32-bit, please install ActivePerl 5.14.\n"; - print "http://downloads.activestate.com/ActivePerl/releases/\n\n"; - } - elsif ( main::ISWINDOWS ) { + if ( main::ISWINDOWS ) { print "To run from source on Windows 64-bit, please install dependencies using Strawberry Perl 5.32.\n"; print "https://strawberryperl.com/releases.html\n\n"; } diff --git a/cleanup.pl b/cleanup.pl index 744f88dcd53..bc62bfc952c 100755 --- a/cleanup.pl +++ b/cleanup.pl @@ -15,25 +15,9 @@ require 5.010; use Config; -use constant SPLASH_LOGO => 'lms_splash.png'; use constant ISWINDOWS => ( $^O =~ /^m?s?win/i ) ? 1 : 0; use constant ISMAC => ( $^O =~ /darwin/i ) ? 1 : 0; -use constant ISACTIVEPERL => ( $Config{cf_email} =~ /ActiveState/i ) ? 1 : 0; - -# don't use Wx, if script is run using perl on OSX, it needs to be run using wxperl -my $splash; -my $useWx = (!ISMAC || $^X =~ /wxPerl/i) && eval { - require Wx; - - showSplashScreen(); - - require Wx::Event; - require Slim::GUI::ControlPanel; - - return 1; -}; - -print "$@\n" if $@ && ISWINDOWS; +use constant ISACTIVEPERL => 0; use strict; use Socket; @@ -63,13 +47,6 @@ our $VERSION = '9.1.0'; -BEGIN { - if (ISWINDOWS) { - eval { require Wx::Perl::Packager; } - } -} - - if (DEBUG && $@) { print "GUI can't be loaded: $@\n"; } @@ -80,7 +57,7 @@ sub main { Slim::Utils::OSDetect::init(); $os = Slim::Utils::OSDetect->getOS(); - if (checkForSC() && !$useWx) { + if (checkForSC()) { print sprintf("\n%s\n\n", Slim::Utils::Light::string('CLEANUP_PLEASE_STOP_SC')); exit; } @@ -107,26 +84,8 @@ sub main { }); unless (scalar @$folders) { - - # show simple GUI if possible - if ($useWx) { - - my $app = Slim::GUI::ControlPanel->new({ - folderCB => \&getFolderList, - cleanCB => \&cleanup, - options => options(), - }); - - $splash->Destroy(); - - $app->MainLoop; - exit; - } - - else { - usage(); - exit; - } + usage(); + exit; } cleanup($folders, $dryrun); @@ -332,12 +291,12 @@ sub cleanup { my ($folders, $dryrun) = @_; for my $item (@$folders) { - print sprintf("\n%s %s...\n", Slim::Utils::Light::string('CLEANUP_DELETING'), $item->{label}) unless $useWx; + print sprintf("\n%s %s...\n", Slim::Utils::Light::string('CLEANUP_DELETING'), $item->{label}); foreach ( @{$item->{folders}} ) { next unless $_; - print "-> $_\n" if (-e $_ && !$useWx); + print "-> $_\n" if -e $_; next if $dryrun; @@ -352,39 +311,6 @@ sub cleanup { } } -sub showSplashScreen { - return unless $^O =~ /win/i; - - my $file; - - if (defined $PerlApp::VERSION) { - $file = PerlApp::extract_bound_file(SPLASH_LOGO); - } - - else { - $file = SPLASH_LOGO; - } - - if (!$file || !-f $file) { - $file = '../platforms/win32/res/' . SPLASH_LOGO; - } - - Wx::Image::AddHandler(Wx::PNGHandler->new()); - - if (my $bitmap = Wx::Bitmap->new($file, Wx::wxBITMAP_TYPE_PNG())) { - - $splash = Wx::SplashScreen->new( - $bitmap, - Wx::wxSPLASH_CENTRE_ON_SCREEN() | Wx::wxSPLASH_NO_TIMEOUT(), - 0, - undef, - -1, [-1, -1], [-1, -1], - Wx::wxSIMPLE_BORDER() | Wx::wxSTAY_ON_TOP() - ); - - } -} - main(); __END__ diff --git a/gdresize.pl b/gdresize.pl deleted file mode 100755 index df2dc13d79e..00000000000 --- a/gdresize.pl +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/perl -# -# Stand-alone interface to GDResizer -# -# TODO: -# Better error handling -# - -use strict; -use FindBin qw($Bin); -use lib $Bin; - -use constant RESIZER => 1; -use constant SLIM_SERVICE => 0; -use constant PERFMON => 0; -use constant SCANNER => 0; -use constant WEBUI => 0; -use constant ISWINDOWS => ( $^O =~ /^m?s?win/i ) ? 1 : 0; -use constant DEBUG => ( grep { /--debug/ } @ARGV ) ? 1 : 0; -use constant LOCALFILE => 0; -use constant NOMYSB => 1; - -BEGIN { - use Slim::bootstrap (); - Slim::bootstrap->loadModules( ['Image::Scale'], [] ); -}; - -use Getopt::Long; - -use Slim::Utils::GDResizer; - -my $help; -our ($file, $url, @spec, $cacheroot, $cachekey, $faster, $debug); - -my $ok = GetOptions( - 'help|?' => \$help, - 'file=s' => \$file, - 'url=s' => \$url, - 'spec=s' => \@spec, - 'cacheroot=s' => \$cacheroot, - 'cachekey=s' => \$cachekey, - 'faster' => \$faster, - 'debug' => \$debug, -); - -if ( !$ok || $help || ( !$file && !$url ) || !@spec ) { - require Pod::Usage; - Pod::Usage::pod2usage(1); -} - -# Download URL to a temp file -my $fh; -if ( $url ) { - require File::Temp; - require LWP::UserAgent; - - $fh = File::Temp->new(); - $file = $fh->filename; - - my $ua = LWP::UserAgent->new( timeout => 5 ); - - $debug && warn "Downloading URL to $file\n"; - - my $res = $ua->get( $url, ':content_file' => $file ); - - if ( !$res->is_success ) { - die "Unable to download $url: " . $res->status_line . "\n"; - } -} - -# Setup cache -my $cache; -if ( $cacheroot && $cachekey ) { - require Cache::FileCache; - - $cache = Cache::FileCache->new( { - namespace => 'Artwork', - cache_root => $cacheroot, - directory_umask => umask(), - } ); -} - -eval { - Slim::Utils::GDResizer->gdresize( - file => $file, - debug => $debug, - faster => $faster, - cache => $cache, - cachekey => $cachekey, - spec => \@spec, - ); -}; - -if ( $@ ) { - die "$@\n"; -} - -exit 0; - - -__END__ - -=head1 NAME - -gdresize.pl - Standalone artwork resizer - -=head1 SYNOPSIS - -Resize normal image file or an audio file's embedded tags: - -Options: - - --file [ /path/to/image.jpg | /path/to/image.mp3 ] - Supported file types: - Images: jpg, jpeg, gif, png, bmp - Audio: see Audio::Scan documentation - - --url http://... - - --spec x_[.ext] ... - Mode is one of: - m: max (default) - p: pad (same as max) - o: original - - Multiple spec arguments may be specified to resize in series. - - --cacheroot [dir] Cache resulting image in a FileCache called - 'Artwork' located in dir - --cachekey [key] Use this key for the cached data. - Note: spec value will be appended to the cachekey - if multiple spec values were supplied. - -=cut diff --git a/scanner.pl b/scanner.pl index d2d010df888..465e9a0463d 100755 --- a/scanner.pl +++ b/scanner.pl @@ -25,7 +25,7 @@ use constant TRANSCODING => 0; use constant PERFMON => 0; use constant ISWINDOWS => ( $^O =~ /^m?s?win/i ) ? 1 : 0; -use constant ISACTIVEPERL => ( $Config{cf_email} =~ /ActiveState/i ) ? 1 : 0; +use constant ISACTIVEPERL => 0; use constant ISMAC => ( $^O =~ /darwin/i ) ? 1 : 0; use constant DEBUGLOG => ( grep { /--nodebuglog/ } @ARGV ) ? 0 : 1; use constant INFOLOG => ( grep { /--noinfolog/ } @ARGV ) ? 0 : 1; @@ -36,18 +36,12 @@ use constant LOCALFILE => 0; use constant NOMYSB => 1; -# Tell PerlApp to bundle these modules -if (0) { - require 'auto/Compress/Raw/Zlib/autosplit.ix'; - require Cache::FileCache; -} - our $REVISION = undef; our $BUILDDATE = undef; BEGIN { # hack a Strawberry Perl specific path into the environment variable - XML::Parser::Expat needs it! - if (ISWINDOWS && !ISACTIVEPERL) { + if (ISWINDOWS) { my $path = File::Basename::dirname($^X); $path =~ s/perl(?=.bin)/c/i; $ENV{PATH} = "$path;" . $ENV{PATH} if -d $path; diff --git a/slimserver.pl b/slimserver.pl index ffe585da656..58b38d9656e 100755 --- a/slimserver.pl +++ b/slimserver.pl @@ -15,28 +15,6 @@ require 5.010; use strict; -# Bug 7491 - bug in PerlSvc: ARGV is not populated when executable is run in service mode. -# Try to work around this limitation by reading the command line from the registry. Ugh... -BEGIN { - if ($PerlSvc::VERSION && $^O =~ /^m?s?win/i && !@ARGV) { - eval { - require Win32::TieRegistry; - my $swKey = $Win32::TieRegistry::Registry->Open( - 'LMachine/System/ControlSet001/services/squeezesvc', - { - Access => Win32::TieRegistry::KEY_READ(), - Delimiter =>'/' - } - ); - - if ($swKey) { - push @ARGV, split(" ", $swKey->{ImagePath}); - shift @ARGV; # remove script name - } - }; - } -} - use constant SCANNER => 0; use constant RESIZER => 0; use constant ISWINDOWS => ( $^O =~ /^m?s?win/i ) ? 1 : 0; @@ -55,96 +33,13 @@ BEGIN # leaving some legacy flags for the moment - unlikely but possibly some 3rd party plugin is referring to it use constant SLIM_SERVICE => 0; use constant NOUPNP => 0; +use constant ISACTIVEPERL => 0; use Config; -use constant ISACTIVEPERL => ( $Config{cf_email} =~ /ActiveState/i ) ? 1 : 0; - my %check_inc; $ENV{PERL5LIB} = join $Config{path_sep}, grep { !$check_inc{$_}++ } @INC; -# This package section is used for the windows service version of the application, -# as built with ActiveState's PerlSvc -if (ISACTIVEPERL && $PerlSvc::VERSION) { - package PerlSvc; - - our %Config = ( - DisplayName => 'Lyrion Music Server', - Description => "Lyrion Music Server - streaming media server", - ServiceName => "squeezesvc", - StartNow => 0, - ); - - sub Startup { - # Tell PerlSvc to bundle these modules - if (0) { - require 'auto/Compress/Raw/Zlib/autosplit.ix'; - require Cache::FileCache; - } - - # added to workaround a problem with 5.8 and perlsvc. - # $SIG{BREAK} = sub {} if RunningAsService(); - main::initOptions(); - main::init(); - - # here's where your startup code will go - while (ContinueRun() && !main::idle()) { } - - main::stopServer(); - } - - sub Install { - - my($Username,$Password); - - use Getopt::Long; - - Getopt::Long::GetOptions( - 'username=s' => \$Username, - 'password=s' => \$Password, - ); - - main::initLogging(); - - if ((defined $Username) && ((defined $Password) && length($Password) != 0)) { - my @infos; - my ($host, $user); - - # use the localhost '.' by default, unless user has defined "domain\username" - if ($Username =~ /(.+)\\(.+)/) { - $host = $1; - $user = $2; - } - else { - $host = '.'; - $user = $Username; - } - - # configure user to be used to run the server - my $grant = PerlSvc::extract_bound_file('grant.exe'); - if ($host && $user && $grant && !`$grant add SeServiceLogonRight $user`) { - $Config{UserName} = "$host\\$user"; - $Config{Password} = $Password; - } - } - } - - sub Interactive { - main::main(); - } - - sub Remove { - # add your additional remove messages or functions here - main::initLogging(); - } - - sub Help { - main::showUsage(); - main::initLogging(); - } -} - - package main; use FindBin qw($Bin); @@ -157,7 +52,7 @@ package main; BEGIN { # hack a Strawberry Perl specific path into the environment variable - XML::Parser::Expat needs it! - if (ISWINDOWS && !ISACTIVEPERL) { + if (ISWINDOWS) { my $path = File::Basename::dirname($^X); $path =~ s/perl(?=.bin)/c/i; $ENV{PATH} = "$path;" . $ENV{PATH} if -d $path; @@ -420,12 +315,7 @@ sub init { $SIG{'HUP'} = \&initSettings; } - if (Slim::Utils::Misc::runningAsService()) { - $SIG{'QUIT'} = \&Slim::bootstrap::ignoresigquit; - } else { - $SIG{'QUIT'} = \&Slim::bootstrap::sigquit; - } - + $SIG{'QUIT'} = \&Slim::bootstrap::sigquit; $SIG{__WARN__} = sub { msg($_[0]) }; # Uncomment to enable crash debugging. @@ -669,7 +559,7 @@ sub main { # all other initialization init(); - if ( ISWINDOWS && !ISACTIVEPERL && $daemon ) { + if ( ISWINDOWS && $daemon ) { Slim::Utils::OSDetect->getOS()->runService(); } else { @@ -1205,15 +1095,12 @@ sub remove_pid_file { sub END { Slim::bootstrap::theEND(); - # tell Windows Service manager to resart - if (ISWINDOWS && !ISACTIVEPERL && $? == Slim::Utils::OS::Win64::RESTART_STATUS) { + # tell Windows Service manager to restart + if (ISWINDOWS && $? == Slim::Utils::OS::Win64::RESTART_STATUS) { POSIX::_exit($?); } } -# start up the server if we're not running as a service. -if (!defined($PerlSvc::VERSION)) { - main() -} +main() __END__ diff --git a/strings.txt b/strings.txt index fc879173475..3f924b976e0 100644 --- a/strings.txt +++ b/strings.txt @@ -24898,280 +24898,6 @@ BACKUP_ALARM RU Резервный будильник SV Reservalarm -CONTROLPANEL_TITLE - CS Ovládací panel Lyrion Music Serveru - DA Kontrolpanel til Lyrion Music Server - DE Lyrion Music Server-Systemsteuerung - EN Lyrion Music Server Control Panel - ES Panel de control de Lyrion Music Server - FI Lyrion Music Serverin ohjauspaneeli - FR Panneau de configuration du Lyrion Music Server - HU Lyrion Music Server vezérlőpult - IT Pannello di controllo di Lyrion Music Server - NL Lyrion Music Server-configuratiescherm - NO Kontrollpanel for Lyrion Music Server - PL Panel sterowania programu Lyrion Music Server - RU Панель управления Lyrion Music Server - SV Kontrollpanelen för Lyrion Music Server - -CONTROLPANEL_SERVERSTATUS - CS Stav - DA Status - DE Status - EN Status - ES Estado - FI Tila - FR Etat - HE מצב - HU Státusz - IT Stato - JA ステータス - NL Status - NO Status - PL Stan - RU Статус - SV Status - -CONTROLPANEL_STATUS_RUNNING - CS Stav: Server je spuštěn - DA Status: Serveren kører - DE Status: Der Server wird ausgeführt - EN Status: The server is running - ES Estado: el servidor está en ejecución - FI Tila: palvelin on käynnissä - FR Etat : le serveur est en cours d'exécution. - HU Állapot: A szerver fut - IT Stato: il server è in esecuzione - NL Status: De server is actief - NO Status: Serveren kjører - PL Stan: Serwer działa - RU Состояние: сервер выполняется - SV Status: Servern körs - -CONTROLPANEL_STATUS_STARTING - CS Stav: Server se spouští - DA Status: Serveren startes - DE Status: Der Server wird gestartet. - EN Status: The server is starting - ES Estado: el servidor está iniciando - FI Tila: palvelin on käynnistymässä - FR Etat : le serveur est en cours de démarrage. - HU Állapot: A szerver elindul - IT Stato: il server si sta avviando - NL Status: De server wordt gestart - NO Status: Serveren starter opp - PL Stan: Trwa uruchamianie serwera - RU Состояние: сервер запускается - SV Status: Servern startar - -CONTROLPANEL_STATUS_STOPPED - CS Stav: Server je zastaven - DA Status: Serveren er stoppet - DE Status: Der Server wurde angehalten. - EN Status: The server is stopped - ES Estado: el servidor está detenido - FI Tila: palvelin on pysäytetty - FR Etat : le serveur est arrêté. - HU Állapot: A szerver leállt - IT Stato: il server è stato arrestato - NL Status: De server is gestopt - NO Status: Serveren er stoppet - PL Stan: Serwer jest zatrzymany - RU Состояние: сервер остановлен - SV Status: Servern har stoppats - -CONTROLPANEL_ACCOUNT - CS Účet - DA Konto - DE Konto - EN Account - ES Cuenta - FI Tili - FR Compte - HU Fiók - IT Account - NL Account - NO Konto - PL Konto - RU Учетная запись - SV Konto - -CONTROLPANEL_STARTUP_OPTIONS - CS Volby při spuštění - DA Indstillinger for systemstart - DE Startoptionen - EN Startup Options - ES Opciones de inicio - FI Käynnistysasetukset - FR Options de démarrage - HU Indítási lehetőségek - IT Opzioni di avvio - NL Opstartopties - NO Oppstartsalternativer - PL Opcje Autostartu - RU Параметры запуска - SV Startalternativ - -CONTROLPANEL_MUSIC_LIBRARY - CS Knihovna - DA Bibliotek - DE Bibliothek - EN Library - ES Biblioteca - FI Kirjasto - FR Bibliothèque - HU Könyvtár - IT Libreria - NL Bibliotheek - NO Bibliotek - PL Biblioteka - RU Медиатека - SV Bibliotek - -CONTROLPANEL_AUTHENTICATION_REQUIRED - CS Pro přístup do Lyrion Music Serveru je vyžadována autentizace - DA Du skal godkendes for at få adgang til Lyrion Music Server - DE Für den Zugriff auf Lyrion Music Server ist eine Authentifizierung erforderlich - EN Authentication is required to access Lyrion Music Server - ES El acceso a Lyrion Music Server requiere autenticación - FI Lyrion Music Serverin käyttö vaatii todennuksen - FR Une authentification est requise pour accéder au Lyrion Music Server - HU A Lyrion Music Server eléréséhez hitelesítés szükséges - IT Per accedere a Lyrion Music Server è necessario eseguire l'autenticazione - NL Verificatie vereist voor toegang tot Lyrion Music Server - NO Det kreves godkjenning for å få tilgang til Lyrion Music Server - PL W celu uzyskania dostępu do programu Lyrion Music Server wymagane jest uwierzytelnienie - RU Для доступа к Lyrion Music Server требуется проверка подлинности - SV Det krävs autentisering för att komma åt Lyrion Music Server - -CONTROLPANEL_WEB_UI - CS Webové rozhraní - DA Webbaseret brugerflade - DE Web-Benutzeroberfläche - EN Web based Interface - ES Interfaz basada en Web - FI Internet-pohjainen käyttöliittymä - FR Interface Web - HU Web alapú felület - IT Interfaccia basata su Web - NL Webinterface - NO Nettbasert grensesnitt - PL Interfejs internetowy - RU Веб-интерфейс - SV Webbaserat gränssnitt - -CONTROLPANEL_WEB_CONTROL_DESC - CS Webové dálkové ovládání - DA Fjernbetjening via browser - DE Fernbedienung - EN Web Remote Control - ES Control remoto por Web - FI Kauko-ohjaus - FR Commande Web - HU Webes távirányító - IT Controllo remoto Web - NL Afstandsbediening voor web - NO Fjernkontroll - PL Pilot zdalnego sterowania - RU Пульт управления по Интернету - SV Fjärrkontroll - -CONTROLPANEL_TRAY_DOUBLECLICK_WEB - CS Webové dálkové ovládání otevřete dvojitým kliknutím na ikonu v oznamovací oblasti - DA Åbn Fjernbetjening via browser ved at dobbeltklikke på ikonet i systembakken - DE Fernbedienung per Doppelklick auf das Symbol in der Taskleiste öffnen - EN Open Web Remote Control on doubleclicking the tray icon - ES Abrir el Control remoto por Web haciendo doble clic en el icono de la bandeja - FI Avaa WWW-etähallinta kaksoisnapsauttamalla ilmaisinalueen kuvaketta - FR Ouvrir la commande Web en cliquant deux fois sur l'icône de la barre d'état - HU Megnyitja a Webes távvezérlőt, ha duplán kattint a tálca ikonjára - IT Aprire Controllo remoto Web facendo doppio clic sull'icona nell'area di notifica - NL Open web-afstandsbediening door te dubbelklikken op het pictogram in het systeemvak - NO Åpne Fjernkontroll ved dobbeltklikk på ikonet i systemstatusfeltet - PL Otwórz Pilot zdalnego sterowania, klikając dwukrotnie ikonę na pasku zadań - RU Открывать пульт управления по Интернету двойным щелчком по значку на панели задач - SV Öppna webbfjärrkontrollen genom att klicka på ikonen i aktivitetsfältet - -CONTROLPANEL_TRAY_DOUBLECLICK_CONTROLPANEL - CS Ovládací panel otevřete dvojitým kliknutím na ikonu v oznamovací oblasti - DA Åbn kontrolpanelet ved at dobbeltklikke på ikonet i systembakken - DE Systemsteuerung per Doppelklick auf das Symbol in der Taskleiste öffnen - EN Open the Control Panel on doubleclicking the tray icon - ES Abrir el Panel de control haciendo doble clic en el icono de la bandeja - FI Avaa Ohjauspaneeli kaksoisnapsauttamalla ilmaisinalueen kuvaketta - FR Ouvrir le panneau de configuration en cliquant deux fois sur l'icône de la barre d'état - HU Megnyitja a Vezérlőpultot, ha duplán kattint a tálca ikonjára - IT Aprire il pannello di controllo facendo doppio clic sull'icona nell'area di notifica - NL Open het configuratiescherm door te dubbelklikken op het pictogram in het systeemvak - NO Åpne kontrollpanelet ved dobbeltklikk på ikonet i systemstatusfeltet - PL Otwórz Panel sterowania, klikając dwukrotnie ikonę na pasku zadań - RU Открывать панель управления двойным щелчком по значку на панели задач - SV Öppna Kontrollpanelen genom att klicka på ikonen i fältet - -CONTROLPANEL_ADVANCED_SETTINGS_DESC - CS Upřesnit nastavení - DA Avancerede indstillinger - DE Erweiterte Einstellungen - EN Advanced Settings - ES Configuración avanzada - FI Lisäasetukset - FR Paramètres avancés - HU Speciális beállítások - IT Impostazioni avanzate - NL Geavanceerde instellingen - NO Avanserte innstillinger - PL Ustawienia zaawansowane - RU Дополнительные настройки - SV Avancerade inställningar - -CONTROLPANEL_LOGFILES - CS Protokolovací soubory - DA Logfiler - DE Protokolldateien - EN Log Files - ES Archivos de registro - FI Lokitiedostot - FR Fichiers journaux - HU Naplófájlok - IT File di registro - NL Logboeken - NO Loggfiler - PL Pliki dziennika - RU Файлы журнала - SV Loggfiler - -CONTROLPANEL_SHOW_SERVER_LOG - CS Zobrazit protokol serveru - DA Vis serverlogfil - DE Serverprotokoll anzeigen - EN Show server log - ES Mostrar registro de servidor - FI Näytä palvelimen loki - FR Afficher le journal du serveur - HU Szervernapló megjelenítése - IT Mostra registro del server - NL Serverlogboek weergeven - NO Vis serverlogg - PL Pokaż dziennik serwera - RU Показать журнал сервера - SV Visa serverlogg - -CONTROLPANEL_SHOW_SCANNER_LOG - CS Zobrazit protokol prohledávání - DA Vis gennemsøgningslogfilen - DE Scannerprotokoll anzeigen - EN Show scanner log - ES Mostrar registro de examen - FI Näytä tarkistuksen loki - FR Afficher le journal de l'analyseur - HU Szkennernapló megjelenítése - IT Mostra registro analisi - NL Scannerlogboek weergeven - NO Vis søkelogg - PL Pokaż dziennik skanera - RU Показать scanner.log - SV Visa loggfilen för sökning - CONTROLPANEL_UPDATE_AVAILABLE CS Aktualizovaná verze Lyrion Music Serveru je k dispozici a připravena k instalaci. DA Der findes en opdateret version af Lyrion Music Server som er klar til at blive installeret. @@ -25220,278 +24946,6 @@ CONTROLPANEL_NO_UPDATE_AVAILABLE RU Нет доступных обновленных версий Lyrion Music Server. SV Det finns ingen uppdaterad version av Lyrion Music Server tillgänglig. -CONTROLPANEL_CHECK_UPDATE - CS Hledat aktualizace - DA Søg efter opdateringer - DE Nach Update suchen - EN Check for update - ES Buscar actualización - FI Etsi päivityksiä - FR Rechercher les mises à jour - HU Frissítések ellenőrzése - IT Verifica disponibilità aggiornamenti - NL Op update controleren - NO Se etter oppdatering - PL Sprawdź dostępność aktualizacji - RU Проверить наличие обновления - SV Sök efter uppdatering - -CONTROLPANEL_DOWNLOAD_UPDATE - CS Stáhnout aktualizaci - DA Hent opdatering - DE Update herunterladen - EN Download update - ES Descargar actualización - FI Lataa päivitys - FR Télécharger la mise à jour - HU Frissítés letöltése - IT Scarica aggiornamento - NL Update downloaden - NO Last ned oppdatering - PL Pobierz aktualizację - RU Загрузить обновление - SV Ladda ner uppdatering - -CONTROLPANEL_INSTALL_UPDATE - CS Instalovat aktualizaci - DA Installer opdatering - DE Update installieren - EN Install update - ES Instalar actualización - FI Asenna päivitys - FR Installer la mise à jour - HU Frissítés telepítése - IT Installa aggiornamento - NL Update installeren - NO Installer oppdatering - PL Zainstaluj aktualizację - RU Установить обновление - SV Installera uppdatering - -CONTROLPANEL_MAINTENANCE - CS Údržba - DA Vedligeholdelse - DE Reinigen der Maus - EN Maintenance - ES Mantenimiento - FI Huolto - FR Entretien - HU Karbantartás - IT Manutenzione - NL Onderhoud - NO Vedlikehold - PL Konserwacja - RU Обслуживание - SV Underhåll - -CONTROLPANEL_DIAGNOSTICS - CS Diagnostika - DA Diagnosticering - DE Diagnose - EN Diagnostics - ES Diagnósticos - FI Diagnostiikka - FR Diagnostic - HU Diagnosztika - IT Diagnostica - NL Diagnose - NO Diagnose - PL Diagnostyka - RU Диагностика - SV Diagnostik - -CONTROLPANEL_PORTNO - CS Port %s (%s): - DA Port %s (%s): - DE Port %s (%s): - EN Port %s (%s): - ES Puerto %s (%s): - FI Portti %s (%s): - FR Port %s (%s) : - HU %s port (%s) : - IT Porta %s (%s): - NL Poort %s (%s): - NO Port %s (%s): - PL Port %s (%s): - RU Порт %s (%s): - SV Port %s (%s): - -CONTROLPANEL_PING - CS Ping: - DA Ping: - DE Ping: - EN Ping: - ES Ping: - FI Ping: - FR Ping : - HU Ping: - IT Ping: - NL Ping: - NO Ping: - PL Ping: - RU Ping: - SV Ping: - -CONTROLPANEL_FAILED - CS Selhání - DA Mislykkedes - DE Fehlgeschlagen - EN Failed - ES Fallo - FI Epäonnistui - FR Echec - HU Sikertelen - IT Non riuscito - NL Mislukt - NO Mislyktes - PL Niepowodzenie - RU Сбой - SV Åtgärden kunde inte genomföras - -CONTROLPANEL_OK - CS OK - DA OK - DE OK - EN OK - ES Correcto - FI OK - FR OK - HU Rendben - IT OK - NL OK - NO OK - PL OK - RU ОК - SV OK - -CONTROLPANEL_ALERTS - CS Výstrahy - DA Advarsler - DE Benachrichtigungen - EN Alerts - ES Alertas - FI Hälytykset - FR Alertes - HU Figyelmeztetések - IT Avvisi - NL Waarschuwingen - NO Varsler - PL Alerty - RU Сигналы - SV Varningar - -CONTROLPANEL_PORTCONFLICT - CS Lyrion Music Server není v provozu, ale nějaká aplikace používá stejný port (%s). - DA Lyrion Music Server kører ikke, men et andet program benytter den samme port (%s). - DE Lyrion Music Server wird nicht ausgeführt. Port (%s) wird von einer anderen Anwendung verwendet. - EN Lyrion Music Server is not running, but some application is using the same port (%s). - ES Lyrion Music Server no está en ejecución, pero alguna aplicación está usando el mismo puerto (%s). - FI Lyrion Music Server ei ole käynnissä, mutta jokin sovellus käyttää samaa porttia (%s). - FR Le Lyrion Music Server n'est pas en cours d'exécution, mais une application utilise actuellement le même port (%s). - HU A Lyrion Music Server nem fut, de néhány alkalmazás ugyanazt a portot (%s) használja. - IT Lyrion Music Server non è in esecuzione ma qualche applicazione sta utilizzando la stessa porta (%s). - NL Lyrion Music Server is niet actief. Poort (%s) wordt door een andere applicatie gebruikt. - NO Lyrion Music Server kjører ikke, men et annet program bruker samme port (%s). - PL Program Lyrion Music Server nie jest uruchomiony, ale jakaś aplikacja używa tego samego portu (%s). - RU Lyrion Music Server не выполняется, но какое-то приложение использует этот же порт (%s). - SV Lyrion Music Server körs inte men något program använder samma port (%s). - -CONTROLPANEL_PORTBLOCKED - CS Lyrion Music Server je v provozu, ale nemůže se spojit s portem %s. - DA Lyrion Music Server kører men kan ikke kontaktes på port %s. - DE Lyrion Music Server wird ausgeführt, kann aber an Port %s nicht erreicht werden. - EN Lyrion Music Server is running but can't be contacted on port %s. - ES Lyrion Music Server está en ejecución pero no se puede contactar con él en el puerto %s. - FI Lyrion Music Server on käynnissä, mutta siihen ei saada yhteyttä portissa %s. - FR Le Lyrion Music Server est en cours d'exécution mais ne peut être contacté sur le port %s. - HU A Lyrion Music Server fut, de nem érhető el a %s porton. - IT Lyrion Music Server è in esecuzione ma non può essere contattato sulla porta %s - NL Lyrion Music Server wordt uitgevoerd maar is niet toegankelijk via poort %s. - NO Lyrion Music Server kjører, men kan ikke kontaktes på port %s - PL Program Lyrion Music Server działa, ale nie można skontaktować się z nim na porcie %s. - RU Lyrion Music Server выполняется, но подключение через порт %s невозможно. - SV Lyrion Music Server körs men går inte att ansluta till port %s. - -CONTROLPANEL_PORTBLOCKED_APPS - CS Vaše spojení mohou blokovat následující aplikace: - DA Følgende programmer blokerer muligvis forbindelsen: - DE Folgende Anwendungen blockieren unter Umständen die Verbindung: - EN The following applications might be blocking your connection: - ES Es posible que las aplicaciones siguientes estén bloqueando la conexión: - FI Seuraavat sovellukset saattavat estää yhteyden: - FR Les applications suivantes sont susceptibles de bloquer votre connexion : - HU Lehetséges, hogy a következő alkalmazások blokkolják a kapcsolatot: - IT Le seguenti applicazioni potrebbero bloccare la connessione: - NL Jouw verbinding wordt mogelijk door de volgende applicaties geblokkeerd: - NO Følgende programmer blokkerer kanskje tilkoplingen: - PL Następujące aplikacje mogą blokować połączenie: - RU Возможно, подключение блокируется следующими приложениями: - SV Följande program kan blockera anslutningen: - -CONTROLPANEL_CONFLICT_CISCOVPNSTATEFULINSPECTION - CS Pokud se vyskytnou problémy s připojením k Lyrion Music Serveru, ujistěte se, že je vypnuta funkce "Stateful Firewall (Always On)" - DA Hvis der er problemer med forbindelsen til og fra Lyrion Music Server, skal du kontrollere at "Stateful Firewall (Always On)" er slået fra - DE Wenn es Verbindungsprobleme mit Lyrion Music Server gibt, vergewissern Sie sich, dass die Option "Statusbehaftete Firewall (immer aktiv)" deaktiviert ist. - EN If you encounter connectivity issues with Lyrion Music Server, please make sure "Stateful Firewall (Always On)" is turned off - ES Si surgen problemas de conectividad con Lyrion Music Server, asegúrese de que la opción "Stateful Firewall (Always On)" está desactivada - FI Jos Lyrion Music Serverin kanssa on yhteysongelmia, varmista, että Tilallinen palomuuri (aina käytössä) -valinta ei ole valittuna. - FR Si vous rencontrez des problèmes de connectivité avec le Lyrion Music Server, vérifiez que l'option "Pare-feu stateful (toujours activé)" est désactivée. - HU Ha kapcsolódási problémákat tapasztal a Lyrion Music Serverrel, kérjük, győződjön meg arról, hogy az „Állapotfüggő tűzfal (mindig bekapcsolva)” ki van kapcsolva - IT In caso di problemi di connessione con Lyrion Music Server, verificare che il firewall con stato sia disattivato. - NL Ondervind je verbindingsproblemen met Lyrion Music Server, zorg dan dat 'Stateful Firewall (Altijd aan)' is uitgeschakeld - NO Hvis du har tilkoplingsproblemer med Lyrion Music Server, må du sørge for at "Tilstandsbevisst brannmur (Alltid på)" er slått av - PL W przypadku wystąpienia problemów z łącznością w programie Squeezebox, upewnij się, że opcja „Zapora stanowa (zawsze włączona)” jest wyłączona - RU При возникновении проблем с подключением к Lyrion Music Server убедитесь, что параметр "Брандмауэр с отслеживанием состояния (Всегда включено)" отключен - SV Om det uppstår anslutningsproblem med Lyrion Music Server bör du kontrollera att alternativet Tillståndskänslig brandvägg (alltid på) är avaktiverat - -CONTROLPANEL_CONFLICT_SCPERL - CS Pokud provozujete Lyrion Music Server s použitím verze Perlu, pak je to v pořádku a očekáváno. - DA Hvis du kører Lyrion Music Server i Perl-versionen, er det OK og forventet. - DE Das Ausführen von Lyrion Music Server mithilfe der Perl-Version wird akzeptiert und erwartet. - EN If you're running Lyrion Music Server using the perl version, then this is ok and expected. - ES Si ejecuta Lyrion Music Server con la versión perl, es correcto y está previsto. - FI Jos Lyrion Music Server on käynnissä ja käytät Perl-versiota, tämä on odotettavissa eikä aiheuta ongelmia. - FR Si vous exécutez Lyrion Music Server à l'aide de la version perl, cet événement est attendu. - HU Ha a Lyrion Music Servert perl verzióval fut, akkor ez rendben van. - IT Se è in esecuzione la versione Perl di Lyrion Music Server, il problema non sussiste. - NL Als je Lyrion Music Server met de perl-versie uitvoert, is dit normaal gedrag. - NO Hvis du kjører Lyrion Music Server med perl-versjonen, er dette greit og forventet. - PL Jeśli używasz programu Lyrion Music Server w wersji perl, jest to poprawne i oczekiwane zachowanie. - RU При выполнении Lyrion Music Server с версией perl данное поведение ожидаемо и нормально. - SV Om du kör du perlversionen av Lyrion Music Server är detta inget fel, utan OK och förväntat. - -CONTROLPANEL_OTHER_ISSUE - CS Nalezen možný konflikt softwaru - DA Der er fundet en mulig softwarekonflikt - DE Möglicher Software-Konflikt gefunden - EN Possible software conflict found - ES Encontrado posible conflicto de software - FI Löytyi mahdollinen ohjelmiston ristiriita - FR Conflit logiciel possible détecté - HU Lehetséges szoftverütközés található - IT Possibile conflitto software rilevato - NL Mogelijk softwareconflict gevonden - NO Mulig programvarekonflikt oppdaget - PL Znaleziono potencjalny konflikt oprogramowania - RU Обнаружен возможный конфликт ПО - SV Eventuellt programvarukonflikt upptäcktes - -CONTROLPANEL_OTHER_ISSUE_ESETPORTFILTERING - CS ESET Antivirus nebo Smart Security může při spuštění Lyrion Music Serveru způsobovat problémy. Pokud dojde k chybě při spuštění Lyrion Music Serveru, ujistěte se, že jste zrušili zaškrtnutí filtrování portů pro SqueezeboxSvr.exe v Pokročilém nastavení ESET / Antivirus a antispyware / Ochrana webového přístupu / HTTP, HTTPS / Webové prohlížeče. - DA ESET Antivirus eller Smart Security kan skabe problemer når du starter Lyrion Music Server. Hvis du ikke kan starte Lyrion Music Server, skal du sørge for at porten som bruges af SqueezeSvr.exe, ikke er lukket i ESET Advanced Settings/Antivirus og antispyware/Web access protection/HTTP, HTTPS/Web browsers. - DE ESET Antivirus oder ESET Smart Security können beim Starten von Lyrion Music Server Probleme verursachen. Wenn beim Starten von Lyrion Music Server Fehler auftreten, sollten Sie prüfen, ob Sie unter ESET Advanced Settings/Antivirus and antispyware/Web access protection/HTTP, HTTPS/Web browsers die Portfilterung für 'SqueezeSvr.exe' deaktiviert haben. - EN ESET Antivirus or Smart Security can cause problems starting Lyrion Music Server. If you experience failure starting Lyrion Music Server, then make sure you have unchecked port filtering for SqueezeSvr.exe in ESET Advanced Settings/Antivirus and antispyware/Web access protection/HTTP, HTTPS/Web browsers. - ES ESET Antivirus o Smart Security pueden producir problemas a la hora de iniciar Lyrion Music Server. Si no puede iniciar Lyrion Music Server, asegúrese de no tener seleccionada la opción de filtrado de puertos para SqueezeSvr.exe en ESET: Configuración avanzada/Antivirus y antiespía/Protección del tráfico de Internet/HTTP, HTTPS/Navegadores de Internet. - FI ESET Antivirus tai Smart Security saattavat aiheuttaa ongelmia Lyrion Music Serverin käynnistyksessä. Jos Lyrion Music Serverin käynnistys ei onnistu, varmista, että olet poistanut portinsuodatuksen valinnan SqueezeboxSvr.exe-tiedostolle kohteessa ESET Advanced Settings/Antivirus and antispyware/Web access protection/HTTP, HTTPS/Web browsers. - FR L'antivirus ESET ou Smart Security peut empêcher le démarrage du Lyrion Music Server. En cas d'échec du démarrage du Lyrion Music Server, vérifiez que le filtrage des ports n'est pas activé pour SqueezeSvr.exe sous ESET Advanced Settings/Antivirus et antispyware/Web access protection/HTTP, HTTPS/Web browsers. - HU Az ESET Antivirus vagy a Smart Security problémákat okozhat a Lyrion Music Server indításakor. Ha a Lyrion Music Server indításakor hiba lép fel, ellenőrizze, hogy nincs-e bejelölve a SqueezeSvr.exe portszűrése az ESET Speciális beállítások/Vírusirtó és kémprogram-elhárító/Webhozzáférés-védelem/HTTP, HTTPS/Webböngészők részben. - IT L'antivirus ESET o Smart Security possono causare problemi di avvio di Lyrion Music Server. Se Lyrion Music Server non si avvia, deselezionare il filtraggio delle porte per SqueezeSvr.exe in Impostazioni avanzate/Antivirus e antispyware/Protezione accesso Web/HTTP di ESET e nei browser HTTPS/Web. - NL ESET Antivirus of Smart Security kan problemen veroorzaken bij het opstarten van Lyrion Music Server. Controleer in dit geval of je het filteren van poorten hebt uitgeschakeld voor SqueezeSvr.exe in ESET Advanced Settings/Antivirus and antispyware/Web access protection/HTTP, HTTPS/Web browsers. - NO ESET Antivirus og Smart Security kan skape problemer med oppstarten av Lyrion Music Server. Hvis du ikke får til å starte Lyrion Music Server, må du sikre at du ikke har merket av for portfiltrering for SqueezeSvr.exe i ESET Advanced Settings/Antivirus and antispyware/Web access protection/HTTP, HTTPS/Web browsers. - PL Program ESET Antivirus lub Smart Security może powodować problemy z uruchomieniem programu Lyrion Music Server. W przypadku napotkania problemu z uruchomieniem programu Lyrion Music Server należy sprawdzić, czy wyłączono opcję filtrowania portów dla programu SqueezeSvr.exe w ustawieniach zaawansowanych funkcji antywirusowych i anty-spyware programu ESET, a także w ustawieniach zabezpieczeń dostępu do sieci Web oraz protokołów HTTP/HTTPS przeglądarki internetowej. - RU Антивирусная программа ESET или Smart Security может привести к неполадкам при запуске Lyrion Music Server. Если возникают ошибки при запуске Lyrion Music Server, убедитесь, что для SqueezeSvr.exe отключена фильтрация портов в разделе ESET Advanced Settings/Antivirus and antispyware/Web access protection/HTTP, HTTPS/Web browsers. - SV Om ESET Antivirus och Smart Security är installerade kan det uppstå problem när Lyrion Music Server ska startas. Vid eventuella problem bör du kontrollera att du har avmarkerat portfiltrering för SqueezeboxSvr.exe i ESET under Avancerade inställningar/Skydd mot virus och spionprogram/Webbåtkomstskydd/HTTP, HTTPS/Webbläsare. - CONTROLPANEL_REFRESH CS Obnovit DA Opdater @@ -25765,38 +25219,6 @@ CLEANUP_DELETING RU Удаление SV Raderar -CONTROLPANEL_NO_STATUS - CS Nejsou dostupné žádné informace o stavu. Vezměte na vědomí, že pro zobrazení informací o stavu musí být Lyrion Music Server aktivní a v provozu. - DA Der er ingen statusoplysninger. Husk at Lyrion Music Server skal køre for at du kan se statusoplysninger. - DE Keine Statusinformationen verfügbar. Lyrion Music Server muss eingerichtet und ausgeführt werden, damit die Statusinformationen angezeigt werden können. - EN No status information available. Please note that Lyrion Music Server has to be up and running in order to display its status information. - ES No hay información de estado disponible. Tenga en cuenta que Lyrion Music Server debe estar en ejecución para mostrar su información de estado. - FI Tilatietoja ei ole saatavilla. Huomaa, että Lyrion Music Serverin on oltava käynnissä, jotta sen tilatiedot voitaisiin näyttää. - FR Aucune information sur l'état n'est disponible. Notez que le Lyrion Music Server doit être en cours d'utilisation pour afficher ces informations. - HU Nem áll rendelkezésre állapotinformáció. Kérjük, vegye figyelembe, hogy a Lyrion Music Servernek működnie kell az állapotinformációk megjelenítéséhez. - IT Non sono disponibili informazioni sullo stato. Per visualizzare le informazioni sullo stato è necessario che Lyrion Music Server sia in esecuzione. - NL Geen statusinformatie beschikbaar. Lyrion Music Server moet actief zijn om statusinformatie te kunnen weergeven. - NO Ingen statusinformasjon er tilgjengelig. Lyrion Music Server må kjøre for at den skal kunne vise statusinformasjon. - PL Brak dostępnych informacji o stanie. Aby możliwe było wyświetlenie informacji o stanie programu Lyrion Music Server, musi on być uruchomiony. - RU Сведения о состоянии недоступны. Сведения о состоянии выводятся только в том случае, если Lyrion Music Server выполняется. - SV Det finns ingen statusinformation. Tänk på att statusinformationen inte kan visas när Lyrion Music Server inte körs. - -CONTROLPANEL_NEED_ADMINISTRATOR - CS Nemáte práva instalovat nebo spouštět/zastavovat procesy Lyrion Music Serveru na pozadí. Spusťte ovládací panel z nabídky Start systému Windows prostřednictvím kontextové nabídky vyvolané pravým klepnutím tlačítka, a klikněte na možnost "Spustit jako správce". - DA Du har ikke rettigheder til at installere eller starte/stoppe baggrundstjenesten Lyrion Music Server. Start kontrolpanelet fra Startmenuen i Windows – via højrekliksmenuen klikker du på "Kør som administrator". - DE Sie sind nicht dazu berechtigt, den Lyrion Music Server-Hintergrunddienst zu installieren oder zu starten bzw. anzuhalten. Öffnen Sie die Systemsteuerung im Windows-Startmenü über das Kontextmenü und wählen Sie 'Als Administrator ausführen'. - EN You don't have privileges to install or start/stop the Lyrion Music Server background service. Please start the control panel from the Windows Start Menu, via the right click context menu, and click "Run as Administrator". - ES No tiene privilegios para instalar o iniciar/detener el servicio en segundo plano Lyrion Music Server. Inicie el Panel de control desde el menú Inicio de Windows, mediante el menú contextual de botón derecho y haga clic en "Ejecutar como administrador". - FI Sinulla ei ole tarvittavia oikeuksia asentaa, käynnistää tai pysäyttää Lyrion Music Serverin taustapalvelua. Avaa Windowsin Käynnistä-valikosta palvelimen ohjauspaneeli napsauttamalla kakkospainiketta ja valitse pikavalikosta Suorita järjestelmänvalvojana. - FR Vous ne disposez pas des droits pour installer ou arrêter/démarrer le service d'arrière-plan Lyrion Music Server. Démarrez le Panneau de configuration en cliquant dessus à l'aide du bouton droit dans le menu Démarrer de Windows et en sélectionnant Exécuter en tant qu'administrateur. - HU Nincs jogosultsága a Lyrion Music Server háttérszolgáltatás telepítéséhez, elindításához/leállításához. Kérjük, indítsa el a vezérlőpultot a Windows Start menüjéből, a jobb gombbal a helyi menüből, majd kattintson a "Futtatás rendszergazdaként" elemre. - IT Non si dispone dei privilegi per installare o avviare/arrestare il servizio in background di Lyrion Music Server. Aprire il Pannello di controllo dal menu Start di Windows utilizzando il menu di scelta rapida visualizzabile facendo clic con il pulsante destro del mouse, quindi fare clic su "Esegui come amministratore". - NL Je hebt geen rechten om de achtergrondprocessen van Lyrion Music Server te installeren of te starten/stoppen. Start het Configuratiescherm vanuit het menu Start in Windows via de rechtermuisknop en klik in het snelmenu op 'Als administrator uitvoeren'. - NO Du har ikke rettighetene som trengs for å installere eller starte/stoppe bakgrunnstjenesten Lyrion Music Server. Start kontrollpanelet fra Start-menyen i Windows ved å høyreklikke og velge Kjør som administrator. - PL Brak uprawnień do uruchomienia lub zatrzymania działającej w tle usługi Lyrion Music Server. Kliknij menu Start, ustaw kursor myszy nad Panelem sterowania, kliknij prawym przyciskiem myszy i wybierz polecenie Uruchom jako administrator. - RU У вас нет прав на установку и запуск/остановку фоновой службы Lyrion Music Server. Откройте панель управления с помощью меню "Пуск" Windows и, открыв щелчком правой кнопки мыши контекстное меню, выберите в нем пункт "Запуск от имени администратора". - SV Du har inte behörighet att installera eller starta/stoppa Lyrion Music Server-bakgrundstjänsten. Starta kontrollpanelen från Start-menyn i Windows via den snabbmeny som visas när du högerklickar och klicka på Kör som administratör. - RUN_AT_BOOT CS Spustit automaticky při startu systému DA Kør automatisk ved systemstart